diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 4fdf1115a..000000000 --- a/.babelrc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presets": [["@babel/preset-env", { - "targets": { - "chrome": 32, - "ie": 9, - "firefox": 27, - "safari": 8 - } - }]] -} diff --git a/.browserslistrc b/.browserslistrc new file mode 100644 index 000000000..0664125b8 --- /dev/null +++ b/.browserslistrc @@ -0,0 +1,5 @@ +chrome >= 72, +ie >= 11, +edge >= 79, +firefox >= 78, +safari >= 9.1, diff --git a/.bundlemonrc.json b/.bundlemonrc.json new file mode 100644 index 000000000..61a914d94 --- /dev/null +++ b/.bundlemonrc.json @@ -0,0 +1,35 @@ +{ + "files": [ + { + "path": "./trackers/browser-tracker/dist/index.module.js", + "maxSize": "5kb", + "maxPercentIncrease": 10 + }, + { + "path": "./trackers/browser-tracker/dist/index.umd.min.js", + "maxSize": "20kb", + "maxPercentIncrease": 10 + }, + { + "path": "./trackers/javascript-tracker/dist/sp.js", + "maxSize": "30kb", + "maxPercentIncrease": 10 + }, + { + "path": "./trackers/javascript-tracker/dist/sp.lite.js", + "maxSize": "20kb", + "maxPercentIncrease": 10 + }, + { + "path": "./libraries/browser-tracker-core/dist/index.module.js", + "maxSize": "26.5kb", + "maxPercentIncrease": 10 + }, + { + "path": "./libraries/tracker-core/dist/index.module.js", + "maxSize": "20kb", + "maxPercentIncrease": 10 + } + ], + "reportOutput": [] +} diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 93f136199..000000000 --- a/.dockerignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -npm-debug.log diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..537b7fae4 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,6 @@ +# don't ever lint node_modules +node_modules +# don't lint build output (make sure it's set to your correct build folder name) +dist +# don't lint nyc coverage output +coverage diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..b31ad6679 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,6 @@ +/* eslint-disable no-undef */ +module.exports = { + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint'], + extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], +}; diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..e2aabb869 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,14 @@ +# Don't allow people to merge changes to these generated files, because the result +# may be invalid. You need to run "rush update" again. +pnpm-lock.yaml merge=binary +shrinkwrap.yaml merge=binary +npm-shrinkwrap.json merge=binary +yarn.lock merge=binary + +# Rush's JSON config files use JavaScript-style code comments. The rule below prevents pedantic +# syntax highlighters such as GitHub's from highlighting these comments as errors. Your text editor +# may also require a special configuration to allow comments in JSON. +# +# For more information, see this issue: https://github.com/microsoft/rushstack/issues/1088 +# +*.json linguist-language=JSON-with-Comments diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..60eb9392b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,34 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: type:defect +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior or code snippets that produce the issue. + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..36db55952 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: type:enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/RELEASE.md b/.github/RELEASE.md new file mode 100644 index 000000000..c4f8ad361 --- /dev/null +++ b/.github/RELEASE.md @@ -0,0 +1,92 @@ +# Preparing a release + +The `Prepare release PR` workflow (`.github/workflows/prepare-release.yml`) +automates the "Prepare for X.Y.Z release" commit and the release PR that +maintainers used to write by hand. + +Note: the JS tracker is a Rush monorepo. Per-package version bumps and per- +package `CHANGELOG.md` entries are produced by `rush version --bump` and +`rush publish --apply` during `publish.yml`, **not** by the prepare-release +workflow. The prepare-release step only sets the `nextBump` field in +`common/config/rush/version-policies.json` so Rush bumps to the right target +on publish. + +## How a release works now + +1. Create the release branch from `master` and merge feature/bug-fix PRs into + it as usual: + ```bash + git checkout master && git pull + git checkout -b release/4.9.0 + git push -u origin release/4.9.0 + ``` +2. When the branch is ready to ship, go to **Actions → Prepare release PR → + Run workflow** and fill in: + - `release_branch`: `release/4.9.0` + - `dry_run`: leave unchecked for a real run; check it for a preview. +3. The workflow computes the correct `nextBump` (`patch` / `minor` / `major`) + from the current version in `version-policies.json` vs the target version + parsed from the branch name, then updates the single line in + `common/config/rush/version-policies.json`. +4. Commits as `Prepare for X.Y.Z release` and pushes to the release branch. +5. Asks Claude to draft the PR body from the commits on the branch (using the + previous release PR as a style example) — flat bullets for 1–2 changes, + `**New features** / **Enhancements** / **Bug fixes**` groups for 3+, with + `thanks to @user` attribution for external contributors only. +6. Opens (or updates) a PR titled `Release/X.Y.Z` against `master`. + +Review the PR, edit the PR body in place if needed, then merge. After +merging, run **Actions → Deploy Tracker** with the version string as the +input. `publish.yml` runs `rush version --bump` (which performs the actual +per-package version bumps and generates the per-package CHANGELOGs from the +`rush change` files under `common/changes/`), cross-validates the resulting +tracker version against your input, builds, tests, publishes to npm, tags +`X.Y.Z`, and creates the GitHub release with `sp.js` / `sp.lite.js` and the +plugins zip attached. + +## Re-running on the same branch + +If you push a small fix to the release branch after the workflow ran, re-run +the workflow. It detects that `HEAD` is already a `Prepare for X.Y.Z release` +commit and skips the bump+commit — it only refreshes the PR body. + +If you need the bump re-done from scratch, drop the prepare commit locally +(`git reset --hard HEAD~1 && git push --force-with-lease`) and re-run the +workflow. + +## Dry-run mode + +`dry_run: true` runs everything up to (but not including) the push and the PR +write. The full `git diff` and the generated PR body are printed to the +workflow log. Use this the first time you exercise the workflow on a real +release branch. + +## Inputs that will make the workflow fail loudly + +- A `release_branch` that doesn't match `release/X.Y.Z`. +- A `release_branch` that doesn't exist on origin. +- A target version that isn't a valid next semver bump from the current + version in `version-policies.json` (e.g. you're on `4.8.1` and you ask + for `5.1.0`; the script only accepts the next patch, the next minor, or + the next major). +- A previous release tag that can't be found on `master` (the workflow needs + one to compute the commit list). + +## Notes on the commit filter + +`commits-raw.txt` is built by filtering out commits the JS publish pipeline +creates automatically, so they don't end up in the release notes: + +- `Prepare for ...` +- `Bump versions [skip ci]` (from `rush version --bump`) +- `Update changelogs [skip ci]` (from `rush publish --apply`) +- `Applying documentation updates.` (api-docs commit during publish) + +If the publish pipeline ever changes its commit subjects, update the +`grep -v -E` line in `prepare-release.yml` to match. + +## Requirements + +- `ANTHROPIC_API_KEY` secret must be set on the repository. +- `GITHUB_TOKEN` (provided automatically) needs `contents: write` and + `pull-requests: write`, which the workflow declares. diff --git a/.github/scripts/classify-commits.sh b/.github/scripts/classify-commits.sh new file mode 100755 index 000000000..62e87ae72 --- /dev/null +++ b/.github/scripts/classify-commits.sh @@ -0,0 +1,179 @@ +#!/usr/bin/env bash +# +# Classify release commits into categories for CHANGELOG entries and PR bodies. +# +# Reads annotated commit lines on stdin, one per line, in the format produced by +# the "Annotate commits with author + external flag" workflow step: +# +# -- author= external= +# +# Writes TSV to stdout, one line per included commit: +# +# \t\t\t\t +# +# where is one of: breaking, feature, fix, improvement, enhancement +# and is either "#NNN" or empty. +# +# Chore-type commits (chore/ci/docs/test/build/style, version-bump and +# release-automation commits) are dropped entirely. +# +# Classification order: +# 1. Conventional-commit prefix (feat:, fix:, perf:, ...). A "!" before the +# colon, or a "BREAKING CHANGE" marker, promotes the commit to breaking. +# 2. Leading imperative verb, for the many historical commits in these repos +# that predate conventional commits. +# 3. Anything left over becomes "enhancement". + +set -euo pipefail + +# Subjects matching these patterns are release-automation noise, never user-facing. +readonly SKIP_SUBJECT_RE='^(Prepare for |Bump versions|Update changelogs|Applying documentation updates|Merge (branch|pull request|remote-tracking)|Release/|Run rush change|Initial (commit|release)|Resync )' + +# Conventional-commit types that never appear in release notes. +readonly SKIP_TYPE_RE='^(chore|ci|docs|test|tests|build|style|revert)$' + +# Bare-subject chore detection, for the many commits predating conventional +# commits. Deliberately narrow: it requires a chore *object* (CI, README, API +# docs, the test suite, a linter) so that user-facing changes which merely +# mention a version or a dependency are still included. Verified against the +# existing hand-written CHANGELOGs, which omit exactly these. +readonly SKIP_BARE_RE='(^|[[:space:]])(ci|CI)([[:space:]]|$)|[Ll]inting|[Ll]int issues|(unit|integration|flaky)[[:space:]]+tests?|tests?[[:space:]]+(in|on)[[:space:]]+CI|README|API docs|api docs|[Dd]ocumentation (build|updates|page)|docs\.snowplow\.io|API ref|[Cc]hangelog|GitHub [Aa]ction|publish action|prepare-release|\[skip ci\]|[Cc]laude|CLAUDE\.md|[Aa]gent pipeline|instrumentation|jest tests|[Ss]igning config for demo|[Bb]undlemon|[Cc]overalls|[Dd]ependabot|[Aa]ddress (PR )?review|[Aa]ddress review comments|[Ff]ix(up)? review|[Aa]pply review|[Ss]elf-review|[Rr]ebase|[Mm]erge conflict|[Tt]ypo in (test|CI)' + +while IFS= read -r line; do + [[ -z "$line" ]] && continue + + # Split the trailing "-- author=... external=..." metadata off the subject. + # The separator is optional: dry runs and manual testing pipe bare + # " " lines, and treating those as metadata would leak the + # parsed fields into the description. + if [[ "$line" == *" -- author="* ]]; then + meta="${line##*" -- "}" + head="${line%" -- "*}" + else + meta="" + head="$line" + fi + + # The leading short sha is dropped; only the subject drives classification. + subject="${head#* }" + [[ "$subject" == "$head" ]] && subject="" + [[ -z "$subject" ]] && continue + + login="" + external="false" + if [[ -n "$meta" ]]; then + if [[ "$meta" =~ author=([^[:space:]]*) ]]; then + login="${BASH_REMATCH[1]}" + fi + if [[ "$meta" =~ external=([^[:space:]]*) ]]; then + external="${BASH_REMATCH[1]}" + fi + fi + + # Drop release-automation commits. + if [[ "$subject" =~ $SKIP_SUBJECT_RE ]]; then + continue + fi + + breaking="false" + # "BREAKING CHANGE" / "BREAKING-CHANGE" anywhere in the subject is a strong signal. + if [[ "$subject" == *"BREAKING CHANGE"* || "$subject" == *"BREAKING-CHANGE"* ]]; then + breaking="true" + fi + + category="" + description="$subject" + + # --- Rule 1: conventional-commit prefix --------------------------------- + # Matches "type: ", "type(scope): ", and the breaking "type!: " / "type(scope)!: ". + if [[ "$subject" =~ ^([a-zA-Z]+)(\(([^\)]*)\))?(!)?:[[:space:]]+(.*)$ ]]; then + type="$(printf '%s' "${BASH_REMATCH[1]}" | tr '[:upper:]' '[:lower:]')" + bang="${BASH_REMATCH[4]}" + rest="${BASH_REMATCH[5]}" + + if [[ "$type" =~ $SKIP_TYPE_RE ]]; then + continue + fi + + [[ -n "$bang" ]] && breaking="true" + + case "$type" in + feat|feature) category="feature" ;; + fix|bugfix) category="fix" ;; + perf|refactor) category="improvement" ;; + *) category="" ;; # unknown type: fall through to the verb rule + esac + + if [[ -n "$category" ]]; then + # Drop the scope. It duplicates information already obvious from the + # description in these repos (e.g. "emitter: wake emitter on signal"), + # and keeping it forces an awkward capitalisation of the scope token. + description="$rest" + fi + fi + + # --- Rule 2: leading imperative verb ----------------------------------- + # Covers the bare-subject style used throughout these repos' history. + if [[ -z "$category" ]]; then + # Bare chore commits (CI, docs, lint, test-suite upkeep) are not + # user-facing. Only applied here: an explicit "feat:"/"fix:" prefix in + # rule 1 always wins, so a genuine fix mentioning CI is never dropped. + if [[ "$subject" =~ $SKIP_BARE_RE ]]; then + continue + fi + + verb="$(printf '%s' "$subject" | awk '{print tolower($1)}')" + case "$verb" in + fix|fixes|fixed|resolve|resolves|correct|corrects|prevent|prevents|address|addresses|avoid|avoids|handle|handles|guard) + category="fix" ;; + add|adds|added|introduce|introduces|support|supports|expose|exposes|implement|implements|allow|allows|enable|enables|create|creates) + category="feature" ;; + improve|improves|update|updates|upgrade|upgrades|refactor|refactors|change|changes|make|makes|migrate|migrates|remove|removes|strip|strips|filter|filters|rename|renames|switch|switches|reduce|reduces|optimise|optimize|simplify|declare|deprecate|deprecates|move|moves|replace|replaces|drop|drops|adjust|adjusts|annotate|clean|unify|tidy|undeprecate|reintroduce) + category="improvement" ;; + *) + category="enhancement" ;; + esac + fi + + [[ "$breaking" == "true" ]] && category="breaking" + + # Extract a PR/issue reference to preserve at the end of the line. + # + # Subjects may carry two references: a trailing "(#NNN)" squash-merge marker + # added by GitHub, and an inline "(close #NNN)" issue link written by the + # author. Prefer the inline issue reference (it names the user-visible issue) + # and strip both markers so the formatters re-append exactly one. + pr_ref="" + if [[ "$description" =~ \((close[sd]?|fix(e[sd])?|resolve[sd]?)[[:space:]]+\#([0-9]+)\) ]]; then + # Preserve the "close" keyword: the existing CHANGELOGs write "(close #720)", + # and it keeps GitHub's issue-closing semantics visible in the notes. + pr_ref="${BASH_REMATCH[1]} #${BASH_REMATCH[3]}" + description="$(printf '%s' "$description" \ + | sed -E 's/[[:space:]]*\((close[sd]?|fix(e[sd])?|resolve[sd]?)[[:space:]]+#[0-9]+\)//I')" + # Drop a redundant trailing squash marker, e.g. "... (close #720) (#720)". + description="$(printf '%s' "$description" | sed -E 's/[[:space:]]*\(#[0-9]+\)[[:space:]]*$//')" + elif [[ "$description" =~ \(\#([0-9]+)\)[[:space:]]*$ ]]; then + pr_ref="#${BASH_REMATCH[1]}" + description="$(printf '%s' "$description" | sed -E 's/[[:space:]]*\(#[0-9]+\)[[:space:]]*$//')" + elif [[ "$description" =~ \#([0-9]+) ]]; then + pr_ref="#${BASH_REMATCH[1]}" + fi + + # Strip an inline BREAKING CHANGE marker; the category already conveys it. + description="$(printf '%s' "$description" \ + | sed -E 's/^BREAKING[ -]CHANGE:?[[:space:]]*//; s/[[:space:]]*BREAKING[ -]CHANGE:?[[:space:]]*/ /')" + + # Tidy whitespace and drop a trailing period for consistent list formatting. + description="$(printf '%s' "$description" | sed -E 's/[[:space:]]+/ /g; s/^ //; s/ $//; s/\.$//')" + [[ -z "$description" ]] && continue + + # Capitalise the first letter so bare conventional-commit bodies read as list items. + first="$(printf '%s' "${description:0:1}" | tr '[:lower:]' '[:upper:]')" + description="${first}${description:1}" + + # Empty fields are written as "-": bash's word splitting collapses runs of + # tabs, so a genuinely empty column would shift every later field left. + # The formatters translate "-" back to an empty string. + printf '%s\t%s\t%s\t%s\t%s\n' \ + "$category" "$description" "${pr_ref:--}" "${login:--}" "$external" +done diff --git a/.github/scripts/format-pr-body.sh b/.github/scripts/format-pr-body.sh new file mode 100755 index 000000000..016689db9 --- /dev/null +++ b/.github/scripts/format-pr-body.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# +# Format classified commits into a release PR body. +# +# Reads the TSV produced by classify-commits.sh on stdin and writes +# GitHub-flavoured markdown to stdout: bullets grouped under bold headers, +# with external contributors credited. +# +# Groups with no entries are omitted. If nothing at all is classifiable the +# script emits a short placeholder rather than an empty body, so the PR is +# never opened with a blank description. + +set -euo pipefail + +work="$(mktemp -d)" +trap 'rm -rf "$work"' EXIT + +# Bucket the incoming rows by category. +while IFS=$'\t' read -r category description pr_ref login external; do + [[ -z "${category:-}" ]] && continue + # classify-commits.sh writes "-" for empty columns; see the note there. + [[ "$pr_ref" == "-" ]] && pr_ref="" + [[ "$login" == "-" ]] && login="" + + line="- ${description}" + [[ -n "$pr_ref" ]] && line="${line} (${pr_ref})" + # Credit external contributors only; team members are not called out. + if [[ "$external" == "true" && -n "$login" ]]; then + line="${line} thanks to @${login}" + fi + printf '%s\n' "$line" >> "$work/$category" +done + +emit_group() { + local file="$1" header="$2" + [[ -s "$work/$file" ]] || return 0 + printf '%s\n' "$header" + cat "$work/$file" + printf '\n' +} + +{ + emit_group breaking '**Breaking changes:**' + emit_group feature '**New features:**' + emit_group improvement '**Improvements:**' + emit_group fix '**Bug fixes:**' + emit_group enhancement '**Enhancements:**' +} > "$work/body.md" + +if [[ -s "$work/body.md" ]]; then + # Trim the trailing blank line left by the last group. + awk 'NF || NR < prev_nonblank' prev_nonblank="$(awk 'NF{n=NR}END{print n}' "$work/body.md")" "$work/body.md" +else + printf '%s\n' 'No user-facing changes in this release.' +fi diff --git a/.github/scripts/prepare-release.js b/.github/scripts/prepare-release.js new file mode 100755 index 000000000..4cafe45e9 --- /dev/null +++ b/.github/scripts/prepare-release.js @@ -0,0 +1,76 @@ +#!/usr/bin/env node +/** + * Prepare for X.Y.Z release: set the `nextBump` field in + * common/config/rush/version-policies.json so that Rush will bump from the + * current version to the target version on the next publish. + * + * Usage: node .github/scripts/prepare-release.js + * + * The file uses JSON-with-comments, so we don't JSON.parse it — we read the + * current `version` with a regex and rewrite the `nextBump` line in place. + */ +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +const target = process.argv[2]; +if (!target || !/^\d+\.\d+\.\d+$/.test(target)) { + console.error(`Usage: ${process.argv[1]} `); + process.exit(2); +} + +const repoRoot = path.resolve(__dirname, '..', '..'); +const policyPath = path.join(repoRoot, 'common/config/rush/version-policies.json'); +const original = fs.readFileSync(policyPath, 'utf8'); + +const versionMatch = original.match(/"version"\s*:\s*"(\d+\.\d+\.\d+)"/); +if (!versionMatch) { + console.error('Could not find "version" field in version-policies.json'); + process.exit(1); +} +const current = versionMatch[1]; +console.log(`Current version: ${current}`); +console.log(`Target version: ${target}`); + +if (current === target) { + console.error(`Current version is already ${target}; nothing to do.`); + process.exit(1); +} + +const [cMaj, cMin, cPatch] = current.split('.').map(Number); +const [tMaj, tMin, tPatch] = target.split('.').map(Number); + +let nextBump; +if (tMaj > cMaj && tMin === 0 && tPatch === 0) { + nextBump = 'major'; +} else if (tMaj === cMaj && tMin > cMin && tPatch === 0) { + nextBump = 'minor'; +} else if (tMaj === cMaj && tMin === cMin && tPatch > cPatch) { + nextBump = 'patch'; +} else { + console.error( + `Target ${target} is not a valid next semver bump from ${current}. ` + + `Expected one of: ${cMaj}.${cMin}.${cPatch + 1} (patch), ` + + `${cMaj}.${cMin + 1}.0 (minor), or ${cMaj + 1}.0.0 (major).` + ); + process.exit(1); +} +console.log(`Computed nextBump: ${nextBump}`); + +// Rewrite the "nextBump" line in place. Preserve indentation and trailing +// whitespace/newline exactly so the diff is the single intended change. +const nextBumpRegex = /(^\s*"nextBump"\s*:\s*")(prerelease|release|patch|minor|major)(")/m; +if (!nextBumpRegex.test(original)) { + console.error('Could not find "nextBump" field in version-policies.json'); + process.exit(1); +} +const updated = original.replace(nextBumpRegex, `$1${nextBump}$3`); + +if (updated === original) { + console.log(`nextBump is already "${nextBump}"; no change needed.`); + process.exit(0); +} + +fs.writeFileSync(policyPath, updated); +console.log(`Updated nextBump to "${nextBump}" in ${policyPath}`); diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..1d17917f9 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,90 @@ +name: Build + +on: + push: + branches: + - '**' # Prevents builds on tag + +jobs: + build: + runs-on: ubuntu-latest + + env: + SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }} + SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }} + BROWSERSLIST_IGNORE_OLD_DATA: true + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Use Node.js 18 + uses: actions/setup-node@v3 + with: + node-version: 22.x + + - name: pnpm cache + uses: actions/cache@v3 + with: + path: ./common/temp/pnpm-store + key: ${{ runner.os }}-pnpm-${{ hashFiles('common/config/rush/pnpm-lock.yaml') }} + restore-keys: ${{ runner.os }}-pnpm- + + - name: Install + run: node common/scripts/install-run-rush.js install + + - name: Build + run: node common/scripts/install-run-rush.js rebuild --verbose + + - name: Test + run: node common/scripts/install-run-rush.js test --verbose + + - name: Block Concurrent Executions of E2E Tests + if: ${{ env.SAUCE_ACCESS_KEY != '' }} + uses: softprops/turnstyle@v1 + with: + poll-interval-seconds: 20 + same-branch-only: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Add Host for Saucelabs Tunnel + if: ${{ env.SAUCE_ACCESS_KEY != '' }} + run: echo "127.0.0.1 snowplow-js-tracker.local" | sudo tee -a /etc/hosts + + - name: Run End to End Tests + if: ${{ env.SAUCE_ACCESS_KEY != '' }} + working-directory: ./trackers/javascript-tracker + run: node ../../common/scripts/install-run-rushx.js test:e2e:sauce + + - name: Pack + run: node common/scripts/install-run-rush.js publish -p --pack --include-all + + - name: Upload packages + uses: actions/upload-artifact@v4 + with: + name: packages + path: | + ./common/temp/artifacts/packages/* + + - name: Upload sp.js artifact + uses: actions/upload-artifact@v4 + with: + name: sp.js + path: trackers/javascript-tracker/dist/sp.js + + - name: Upload sp.lite.js artifact + uses: actions/upload-artifact@v4 + with: + name: sp.lite.js + path: trackers/javascript-tracker/dist/sp.lite.js + + - name: Upload plugins + uses: actions/upload-artifact@v4 + with: + name: plugins.umd + path: | + ./plugins/*/dist/*.umd.js + ./plugins/*/dist/*.umd.js.map + ./plugins/*/dist/*.umd.min.js + ./plugins/*/dist/*.umd.min.js.map diff --git a/.github/workflows/change_check.yml b/.github/workflows/change_check.yml new file mode 100644 index 000000000..d4bda6f73 --- /dev/null +++ b/.github/workflows/change_check.yml @@ -0,0 +1,69 @@ +name: Pull Request Check + +on: pull_request + +jobs: + check: + runs-on: ubuntu-latest + + permissions: + contents: read + pull-requests: write + checks: write + + env: + BROWSERSLIST_IGNORE_OLD_DATA: true + + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Use Node.js 18 + uses: actions/setup-node@v3 + with: + node-version: 22.x + + - name: pnpm cache + uses: actions/cache@v3 + with: + path: ./common/temp/pnpm-store + key: ${{ runner.os }}-pnpm-${{ hashFiles('common/config/rush/pnpm-lock.yaml') }} + restore-keys: ${{ runner.os }}-pnpm- + + - name: Install + run: node common/scripts/install-run-rush.js install + + - name: Check dependencies + run: node common/scripts/install-run-rush.js check + + - name: Verify change files + run: node common/scripts/install-run-rush.js change --verify + + - name: Rush Build + run: node common/scripts/install-run-rush.js rebuild --verbose + + - name: Install API Extractor + run: npm install -g @microsoft/api-extractor@7.18.4 + + - name: Check for API changes to @snowplow/browser-tracker + working-directory: ./trackers/browser-tracker + run: api-extractor run + + - name: Check for API changes to @snowplow/node-tracker + working-directory: ./trackers/node-tracker + run: api-extractor run + + - name: Check for API changes to @snowplow/react-native-tracker + working-directory: ./trackers/react-native-tracker + run: api-extractor run + + - name: Check bundle size using bundlemon + if: github.event.pull_request.head.repo.full_name == github.repository + run: npx bundlemon@3 + env: + BUNDLEMON_PROJECT_ID: 69e5e44cf67d5035af9fd1c0 + BUNDLEMON_PROJECT_APIKEY: ${{ secrets.BUNDLEMON_PROJECT_APIKEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha || github.sha }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000..35b78acf4 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,31 @@ +name: Deploy to GitHub Pages + +on: + workflow_run: + workflows: ['Deploy Tracker'] + types: + - completed +permissions: + contents: write + +jobs: + deploy: + name: Deploy to GitHub Pages + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 22 + + - name: Install dependencies + working-directory: ./api-docs + run: npm install + - name: Build website + working-directory: ./api-docs + run: npm run build + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./api-docs/build diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml new file mode 100644 index 000000000..4fd04babf --- /dev/null +++ b/.github/workflows/prepare-release.yml @@ -0,0 +1,186 @@ +name: Prepare release PR + +on: + workflow_dispatch: + inputs: + release_branch: + description: 'Release branch (must already exist, format: release/X.Y.Z)' + required: true + type: string + dry_run: + description: 'Print the planned commit and PR body without pushing or opening a PR' + required: false + type: boolean + default: false + +permissions: + contents: write + pull-requests: write + +jobs: + prepare: + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BASE_BRANCH: master + # Workflow inputs are exposed as environment variables and referenced as + # "$RELEASE_BRANCH" in run: blocks, never interpolated as ${{ }} into an + # inline script. Direct interpolation splices the raw value into the shell + # before it runs, which is a script-injection sink (see ST-482). + RELEASE_BRANCH: ${{ inputs.release_branch }} + DRY_RUN: ${{ inputs.dry_run }} + steps: + - name: Validate inputs + id: validate + run: | + set -euo pipefail + if [[ ! "$RELEASE_BRANCH" =~ ^release/([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then + echo "::error::release_branch must match 'release/X.Y.Z' (got: $RELEASE_BRANCH)" + exit 1 + fi + version="${BASH_REMATCH[1]}" + echo "version=$version" >> "$GITHUB_OUTPUT" + echo "release_date=$(date -u +%Y-%m-%d)" >> "$GITHUB_OUTPUT" + + - name: Checkout release branch + uses: actions/checkout@v4 + with: + ref: ${{ inputs.release_branch }} + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Use Node.js 22 + uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: Configure git + run: | + git config user.name 'snowplow-ci' + git config user.email 'ci@snowplowanalytics.com' + + - name: Verify branch state + id: state + env: + VERSION: ${{ steps.validate.outputs.version }} + run: | + set -euo pipefail + git fetch origin "$BASE_BRANCH" + + # Idempotent re-run: if HEAD is already "Prepare for X.Y.Z release", + # skip the bump+commit and only refresh the PR body. + head_subject="$(git log -1 --pretty=%s)" + if [[ "$head_subject" == "Prepare for $VERSION release" ]]; then + echo "Branch HEAD is already the prepare-release commit; will skip bump+commit and only refresh the PR." + echo "already_prepared=true" >> "$GITHUB_OUTPUT" + else + echo "already_prepared=false" >> "$GITHUB_OUTPUT" + fi + + - name: Collect commits since previous release + id: commits + run: | + set -euo pipefail + # Previous tag = highest semver tag reachable from BASE_BRANCH. + prev_tag="$(git tag --merged "origin/$BASE_BRANCH" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -1 || true)" + if [[ -z "$prev_tag" ]]; then + echo "::error::Could not determine previous release tag" + exit 1 + fi + echo "prev_tag=$prev_tag" >> "$GITHUB_OUTPUT" + + # Commits on the release branch since prev_tag. classify-commits.sh + # drops the commits the JS publish pipeline creates automatically + # ("Bump versions [skip ci]", "Update changelogs [skip ci]", + # "Applying documentation updates.") along with other chores. + git log --no-merges "$prev_tag..HEAD" --pretty='%h %s' > commits-raw.txt || true + git log --merges "$prev_tag..HEAD" --pretty='%h %s' >> commits-raw.txt || true + + # De-dup by short sha, preserve order + awk '!seen[$1]++' commits-raw.txt > commits.txt + echo "Commits since $prev_tag:" + cat commits.txt + + - name: Annotate commits with author + external flag + env: + REPOSITORY: ${{ github.repository }} + run: | + set -euo pipefail + : > commits-annotated.txt + while read -r line; do + [[ -z "$line" ]] && continue + sha="$(echo "$line" | awk '{print $1}')" + subject="$(echo "$line" | cut -d' ' -f2-)" + pr_num="$(echo "$subject" | grep -oE '#[0-9]+' | head -1 | tr -d '#' || true)" + login="" + external="false" + if [[ -n "$pr_num" ]]; then + if json="$(gh api "repos/$REPOSITORY/pulls/$pr_num" 2>/dev/null)"; then + login="$(echo "$json" | jq -r '.user.login // ""')" + assoc="$(echo "$json" | jq -r '.author_association // ""')" + case "$assoc" in + MEMBER|OWNER|COLLABORATOR) external="false" ;; + *) external="true" ;; + esac + fi + fi + echo "$sha $subject -- author=$login external=$external" >> commits-annotated.txt + done < commits.txt + echo "Annotated commits:" + cat commits-annotated.txt + + - name: Set nextBump in version-policies.json + if: steps.state.outputs.already_prepared == 'false' + env: + VERSION: ${{ steps.validate.outputs.version }} + run: node .github/scripts/prepare-release.js "$VERSION" + + - name: Commit "Prepare for release" + if: steps.state.outputs.already_prepared == 'false' && inputs.dry_run == false + env: + VERSION: ${{ steps.validate.outputs.version }} + run: | + set -euo pipefail + git add common/config/rush/version-policies.json + # If the script was a no-op (nextBump already correct), skip the commit. + if git diff --cached --quiet; then + echo "No staged changes; nextBump was already set correctly. Skipping commit." + else + git commit -m "Prepare for $VERSION release" + git push origin "$RELEASE_BRANCH" + fi + + - name: Show planned changes (dry run) + if: inputs.dry_run == true + run: | + echo "=== Diff that would be committed ===" + git --no-pager diff + echo "====================================" + + - name: Generate PR body + run: | + set -euo pipefail + ./.github/scripts/classify-commits.sh < commits-annotated.txt > classified.tsv + ./.github/scripts/format-pr-body.sh < classified.tsv > pr-body.md + + echo "=== Generated PR body ===" + cat pr-body.md + echo "=========================" + + - name: Open or update release PR + if: inputs.dry_run == false + env: + VERSION: ${{ steps.validate.outputs.version }} + run: | + set -euo pipefail + existing="$(gh pr list --head "$RELEASE_BRANCH" --base "$BASE_BRANCH" --state open --json number --jq '.[0].number' || true)" + if [[ -n "$existing" ]]; then + gh pr edit "$existing" --title "Release/$VERSION" --body-file pr-body.md + echo "Updated existing PR #$existing" + else + gh pr create \ + --base "$BASE_BRANCH" \ + --head "$RELEASE_BRANCH" \ + --title "Release/$VERSION" \ + --body-file pr-body.md + fi diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 000000000..26ec022ab --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,126 @@ +name: Deploy Tracker + +on: + workflow_dispatch: + inputs: + version: + description: 'The release tag' + required: true + +jobs: + deploy: + runs-on: ubuntu-latest + + env: + NPM_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} + BROWSERSLIST_IGNORE_OLD_DATA: true + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Use Node.js 18 + uses: actions/setup-node@v3 + with: + node-version: 22 + + - name: pnpm cache + uses: actions/cache@v3 + with: + path: ./common/temp/pnpm-store + key: ${{ runner.os }}-pnpm-${{ hashFiles('common/config/rush/pnpm-lock.yaml') }} + restore-keys: ${{ runner.os }}-pnpm- + + - name: Rush Install + run: node common/scripts/install-run-rush.js install + + - name: Setup git + uses: oleksiyrudenko/gha-git-credentials@v2.1.1 + with: + token: '${{ secrets.GITHUB_TOKEN }}' + name: github-actions[bot] + email: 41898282+github-actions[bot]@users.noreply.github.com + + - name: Rush Version + run: node common/scripts/install-run-rush.js version --bump --target-branch master --ignore-git-hooks + + - name: Get version + id: version + run: echo "TRACKER_VERSION=$(node -p "require('./trackers/javascript-tracker/package.json').version")" >> $GITHUB_OUTPUT + + - name: Fail if version mismatch + if: ${{ github.event.inputs.version != steps.version.outputs.TRACKER_VERSION }} + run: | + echo "Input version (${{ github.event.inputs.version }}) doesn't match version in project (${{ steps.version.outputs.TRACKER_VERSION }})" + exit 1 + + - name: Rush Build + run: node common/scripts/install-run-rush.js rebuild --verbose + + - name: Rush Test + run: node common/scripts/install-run-rush.js test --verbose + + - name: Install API Extractor & Documenter + run: npm install -g @microsoft/api-extractor@7.18.4 @microsoft/api-documenter@7.13.34 + + - name: Create API documentation for @snowplow/browser-tracker + working-directory: ./trackers/browser-tracker + run: | + api-extractor run + api-documenter markdown --input-folder temp --output-folder ../../api-docs/docs/browser-tracker/markdown + + - name: Create API documentation for @snowplow/node-tracker + working-directory: ./trackers/node-tracker + run: | + api-extractor run + api-documenter markdown --input-folder temp --output-folder ../../api-docs/docs/node-tracker/markdown + + - name: Create API documentation for @snowplow/react-native-tracker + working-directory: ./trackers/react-native-tracker + run: | + api-extractor run + api-documenter markdown --input-folder temp --output-folder ../../api-docs/docs/react-native-tracker/markdown + + - name: Apply API documentation updates + run: | + git add api-docs/docs/browser-tracker + git add api-docs/docs/node-tracker + git add api-docs/docs/react-native-tracker + git commit --no-verify --allow-empty -m "Applying documentation updates." + git push + + - name: Rush Publish + run: node common/scripts/install-run-rush.js publish --apply --include-all --publish --target-branch master --set-access-level public --ignore-git-hooks + + - name: Generate Release Information + id: tag_version + uses: mathieudutour/github-tag-action@v6.1 + with: + dry_run: true + github_token: ${{ secrets.GITHUB_TOKEN }} + tag_prefix: '' + default_bump: false + custom_tag: ${{ github.event.inputs.version }} + + - name: Tag release + run: | + git tag -a ${{ steps.tag_version.outputs.new_tag }} -m "Version ${{ steps.tag_version.outputs.new_tag }}" + git push --tags + + - name: Zip plugins + run: zip -r plugins.umd.zip ./plugins/*/dist/*.umd*.js* + + - name: Publish Release + uses: softprops/action-gh-release@v1 + with: + name: Version ${{ steps.tag_version.outputs.new_tag }} + tag_name: ${{ steps.tag_version.outputs.new_tag }} + body: ${{ steps.tag_version.outputs.changelog }} + files: | + ./trackers/javascript-tracker/dist/sp.js + ./trackers/javascript-tracker/dist/sp.js.map + ./trackers/javascript-tracker/dist/sp.lite.js + ./trackers/javascript-tracker/dist/sp.lite.js.map + ./plugins.umd.zip + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/publish_branch.yml b/.github/workflows/publish_branch.yml new file mode 100644 index 000000000..09af511d7 --- /dev/null +++ b/.github/workflows/publish_branch.yml @@ -0,0 +1,64 @@ +name: Deploy Branch + +on: workflow_dispatch + +jobs: + deploy: + runs-on: ubuntu-latest + + env: + NPM_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} + BROWSERSLIST_IGNORE_OLD_DATA: true + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Use Node.js 18 + uses: actions/setup-node@v3 + with: + node-version: 22 + + - name: Get dist-tag from branch name + env: + BRANCH: ${{ github.ref_name }} + id: split + run: echo "branchDescription=${BRANCH##*/}" >> "$GITHUB_OUTPUT" + + - name: Fail if no proper branch name + run: | + if test -z "${{ steps.split.outputs.branchDescription }}"; then + echo "Failed as no proper branch name was provided. Please use the format of prefix/branch-description." + exit 1 + fi + + - name: pnpm cache + uses: actions/cache@v3 + with: + path: ./common/temp/pnpm-store + key: ${{ runner.os }}-pnpm-${{ hashFiles('common/config/rush/pnpm-lock.yaml') }} + restore-keys: ${{ runner.os }}-pnpm- + + - name: Rush Install + run: node common/scripts/install-run-rush.js install + + - name: Setup git + uses: oleksiyrudenko/gha-git-credentials@v2.1.1 + with: + token: '${{ secrets.GITHUB_TOKEN }}' + name: github-actions[bot] + email: 41898282+github-actions[bot]@users.noreply.github.com + + - name: Rush Version + run: node common/scripts/install-run-rush.js version --bump --ignore-git-hooks --override-prerelease-id dev --override-bump prerelease + + - name: Rush Build + run: node common/scripts/install-run-rush.js rebuild --verbose + + - name: Rush Test + run: node common/scripts/install-run-rush.js test --verbose + + - name: Rush Publish + env: + BRANCH_DESCRIPTION: ${{ steps.split.outputs.branchDescription }} + run: node common/scripts/install-run-rush.js publish --apply --include-all --publish --tag $BRANCH_DESCRIPTION --set-access-level public --ignore-git-hooks diff --git a/.github/workflows/publish_prerelease.yml b/.github/workflows/publish_prerelease.yml new file mode 100644 index 000000000..5f238358c --- /dev/null +++ b/.github/workflows/publish_prerelease.yml @@ -0,0 +1,119 @@ +name: Deploy Tracker Prerelease + +on: + workflow_dispatch: + inputs: + version: + description: 'The prerelease tag' + required: true + +jobs: + deploy: + runs-on: ubuntu-latest + + env: + NPM_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} + BROWSERSLIST_IGNORE_OLD_DATA: true + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Use Node.js 18 + uses: actions/setup-node@v3 + with: + node-version: 22 + + - name: pnpm cache + uses: actions/cache@v3 + with: + path: ./common/temp/pnpm-store + key: ${{ runner.os }}-pnpm-${{ hashFiles('common/config/rush/pnpm-lock.yaml') }} + restore-keys: ${{ runner.os }}-pnpm- + + - name: Rush Install + run: node common/scripts/install-run-rush.js install + + - name: Setup git + uses: oleksiyrudenko/gha-git-credentials@v2.1.1 + with: + token: '${{ secrets.GITHUB_TOKEN }}' + name: github-actions[bot] + email: 41898282+github-actions[bot]@users.noreply.github.com + + - name: Rush Version + run: node common/scripts/install-run-rush.js version --bump --ignore-git-hooks + + - name: Get version + id: version + run: echo "TRACKER_VERSION=$(node -p "require('./trackers/javascript-tracker/package.json').version")" >> $GITHUB_OUTPUT + + - name: Fail if version mismatch + if: ${{ github.event.inputs.version != steps.version.outputs.TRACKER_VERSION }} + run: | + echo "Input version (${{ github.event.inputs.version }}) doesn't match version in project (${{ steps.version.outputs.TRACKER_VERSION }})" + exit 1 + + - name: Rush Build + run: node common/scripts/install-run-rush.js rebuild --verbose + + - name: Rush Test + run: node common/scripts/install-run-rush.js test --verbose + + - name: Install API Extractor & Documenter + run: npm install -g @microsoft/api-extractor@^7.18.4 @microsoft/api-documenter@^7.13.34 + + - name: Create API documentation for @snowplow/browser-tracker + working-directory: ./trackers/browser-tracker + run: | + api-extractor run + api-documenter markdown --input-folder temp --output-folder docs/markdown + + - name: Create API documentation for @snowplow/node-tracker + working-directory: ./trackers/node-tracker + run: | + api-extractor run + api-documenter markdown --input-folder temp --output-folder docs/markdown + + - name: Create API documentation for @snowplow/react-native-tracker + working-directory: ./trackers/react-native-tracker + run: | + api-extractor run + api-documenter markdown --input-folder temp --output-folder docs/markdown + + - name: Rush Publish + run: node common/scripts/install-run-rush.js publish --apply --include-all --publish --tag next --set-access-level public --ignore-git-hooks + + - name: Generate Release Information + id: tag_version + uses: mathieudutour/github-tag-action@v6.1 + with: + dry_run: true + github_token: ${{ secrets.GITHUB_TOKEN }} + tag_prefix: '' + default_bump: false + custom_tag: ${{ github.event.inputs.version }} + + - name: Tag release + run: | + git tag -a ${{ steps.tag_version.outputs.new_tag }} -m "Version ${{ steps.tag_version.outputs.new_tag }}" + git push --tags + + - name: Zip plugins + run: zip -r plugins.umd.zip ./plugins/*/dist/*.umd*.js* + + - name: Release + uses: softprops/action-gh-release@v1 + with: + name: Version ${{ steps.tag_version.outputs.new_tag }} + tag_name: ${{ steps.tag_version.outputs.new_tag }} + body: ${{ steps.tag_version.outputs.changelog }} + prerelease: true + files: | + ./trackers/javascript-tracker/dist/sp.js + ./trackers/javascript-tracker/dist/sp.js.map + ./trackers/javascript-tracker/dist/sp.lite.js + ./trackers/javascript-tracker/dist/sp.lite.js.map + ./plugins.umd.zip + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/snyk.yml b/.github/workflows/snyk.yml new file mode 100644 index 000000000..753187e98 --- /dev/null +++ b/.github/workflows/snyk.yml @@ -0,0 +1,31 @@ +name: Snyk +on: + push: + branches: [master] +jobs: + security: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Use Node.js 18 + uses: actions/setup-node@v3 + with: + node-version: 22 + + - name: pnpm cache + uses: actions/cache@v3 + with: + path: ./common/temp/pnpm-store + key: ${{ runner.os }}-pnpm-${{ hashFiles('common/config/rush/pnpm-lock.yaml') }} + restore-keys: ${{ runner.os }}-pnpm- + + - name: Install + run: node common/scripts/install-run-rush.js install + + - name: Run Snyk to check for vulnerabilities + uses: snyk/actions/node@master + with: + command: monitor + args: --all-projects --exclude=common + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} diff --git a/.gitignore b/.gitignore index 99db4b572..a0bdc3180 100644 --- a/.gitignore +++ b/.gitignore @@ -1,35 +1,84 @@ -# Tests suite -ngrok - -# node.js -lib-cov -*.seed -*.log -*.csv -*.dat -*.out -*.pid -*.gz - -pids -logs -results - -npm-debug.log -node_modules - -**/lodash.js -tests/pages/*.js -tests/local/serve/ -tags/tag.min.js - -# creds for Grunt -aws.json - -# Vagrant -.vagrant -VERSION - -src/js/lib_managed - -.idea/ +# Logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# next.js build output +.next + +# OS X temporary files +.DS_Store + +# Rush temporary files +common/deploy/ +common/temp/ +common/autoinstallers/*/.npmrc +**/.rush/temp/ + +# API Extractor +trackers/browser-tracker/temp/ +trackers/node-tracker/temp/ +trackers/react-native-tracker/temp/ + +# Distribution files +dist + +# Test files +trackers/javascript-tracker/test/pages/*.js +trackers/javascript-tracker/test/local/serve/ + +# IDE files +.idea/ +.DS_Store + +# gitleaks file +findings.json diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 000000000..2bd5a0a98 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +22 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..293c1615e --- /dev/null +++ b/.prettierignore @@ -0,0 +1,106 @@ +#------------------------------------------------------------------------------------------------------------------- +# Keep this section in sync with .gitignore +#------------------------------------------------------------------------------------------------------------------- + +# Logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# next.js build output +.next + +# OS X temporary files +.DS_Store + +# Rush temporary files +common/deploy/ +common/temp/ +common/autoinstallers/*/.npmrc +**/.rush/temp/ + +# Test files +trackers/browser-tracker/test/pages/*.js +trackers/browser-tracker/test/local/serve/ + +# Generated tag +trackers/browser-tracker/tags/tag.min.js + +# IDE files +.idea/ +.DS_Store + +#------------------------------------------------------------------------------------------------------------------- +# Prettier-specific overrides +#------------------------------------------------------------------------------------------------------------------- + +# Rush files +common/changes/ +common/scripts/ +common/config/ +CHANGELOG.* + +# Package manager files +pnpm-lock.yaml +yarn.lock +package-lock.json +shrinkwrap.json + +# Build outputs +dist +lib +tags + +sp.js + +# Prettier reformats code blocks inside Markdown, which affects rendered output +*.md \ No newline at end of file diff --git a/.prettierrc b/.prettierrc index fa51da29e..3bb548593 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,6 +1,7 @@ { "trailingComma": "es5", "tabWidth": 2, - "semi": false, - "singleQuote": true + "singleQuote": true, + "printWidth": 120, + "endOfLine": "auto" } diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index af74d0571..000000000 --- a/.travis.yml +++ /dev/null @@ -1,66 +0,0 @@ -addons: - hosts: - - snowplow-js-tracker.local -node_js: -- 8.12.0 -language: node_js -install: -- npm install -g npm@6.4.1 -- npm install -g grunt-cli - -# install packages and build core -- cd core -- rm -rf node_modules -- npm install -- grunt ts -- grunt dtsGenerator - -# install packages for tracker -- cd .. -- rm -rf node_modules -- npm install - -before_script: -script: -- cd core && grunt intern && cd .. -- grunt travis && npm run test:unit && npm run test:e2e:sauce -before_deploy: -- grunt default -deploy: -- provider: script - skip_cleanup: true - script: ./.travis/deploy.py - on: - condition: '"$(.travis/is_correct_core_release_tag.sh $TRAVIS_TAG)" == "" && $? == 0' - tags: true -# - provider: script -# skip_cleanup: true -# script: ./.travis/deploy.py -# on: -# condition: '"$(.travis/is_tracker_release_tag.sh $TRAVIS_TAG)" == "" && $? == 0' -# tags: true -- provider: releases - skip_cleanup: true - api_key: - secure: juUw//XdoRAb494NvxNTghZC7TBJLBx8WdAZsrSGp+6Sf7yPZ6skDt/+qU2VgrG/4RBWUwl3lnAWobiY6ZQQSD95lQDyVM9IdC9JHchhVav1nHBrcJWubEKN/R0Ri/3XjLFJ/LFlkdOteYYPVZR6MGehRR9Gsnazavk9+0x6c1A= - file: $TRAVIS_BUILD_DIR/dist/sp.js - on: - condition: '"$(.travis/is_correct_tracker_release_tag.sh $TRAVIS_TAG)" == "" && $? == 0' - tags: true -env: - global: - # SAUCE_USERNAME - - secure: S/6Ild1n9SmW8xYqarjkigDqmyFgWS4Hi0M07e/ryPeS1MNQdiS5+WuSmlSTevM/wU/oSCvzXnKhO9W/1tvz4qj/BMQYxYWFjwWAXJrkjJPvWoa5ogYkR3ETSYrqdhkT+8LVof8iLPlpHjS1y2fozyJbYf1YNSkcVCLxMdIwnk0= - # SAUCE_ACCESS_KEY - - secure: bkmtL2PXFGdOB6YNfWw6thEyVAbX/l7Q99pfT2jHmfzhTDf4/FT1CprsAacf0JeYkwMg5UQDMqAcZSojjO6GeAY8rhC94Tor5hKoEwCL4wg5NatXBUUI+WWaoBSg2KWYG2MfkPxtGJyNk1LPQoV+nUUzwEGejV8lJvaHVxkBsqA= - # NGROK_AUTH - - secure: JwP5MuqZ6k8FlHg8AnzYTrCZByJLnlu0to2srEwfVOhW1efGTEmtWf/SLlplYHcdelsFakdiSbD3BkZyEqpe/2/AIb56KLAqtE2Ng3WS8Vz/80yknxII0xcSPzAZdhZYRUJlbIrA1Ua3XGgirBenjn7ILFXNX/qLgvwJ1uLKCPo= - # AWS_ACCESS_KEY - - secure: AEvIKW1H/DPU5yPKfRPHY9XpBCjXGtwVqpQERx0wYGwV8j9mzz8EMMrx6yPMaLOkeBMcaH/db3aXEePHWAlnxrTuUuhwwr9A7sihaaAwZ9GllUlUEJzfXeBcCM9rhsooY2roMzJM3Ener1W+yKHThagYxUZ4PyZrPJCMMzbc0qw= - # AWS_SECRET_KEY - - secure: C+PTon3PsELG2bFlAZ5qfinWVih8XxlZV45Gk2W5i2CK1AROJ60lnfhgYZM4YidIRcA/V/zbm8tDgZbA8i/MVKcO5f1qbD5Skyo2fEFRlXoSWhtwaScViihN338U/SsEviKThIGSSLgdfsQ0CW7TYxvetFSwXFyZPPrYrenF3dk= - # NPM_AUTH_TOKEN - - secure: PwIU7BHXhpHUhFh/sxRO1o9awiTKJ5PNrSgeTytp2CcE22q0yx/q5cKJp/gPWiY0l0sKSrNjcV/s0hifg3d8q4YcTa3JEK6Ap71ehOsCIJQD897cgTMqgawkdspeyZL8OPPAs0hMwHFAASm7RDTe4zz1rYMFs2+DYLbIKu0Ki8I= - - AWS_S3_BUCKET=snowplow-static-js - - AWS_REGION=eu-west-1 - - AWS_CF_DISTRIBUTION=E1RICD7QD0F2KE diff --git a/.travis/deploy.py b/.travis/deploy.py deleted file mode 100755 index 97619b0ea..000000000 --- a/.travis/deploy.py +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/env python - -""" -Script responsible for deploying both snowplow-tracker-core and snowplow-tracker -Need to be executed in Travis CI environment by tag (core/x.y.z OR x.y.z) -Publish core locally, build tracker using locally publiched core and then -publish altogether -""" - -from contextlib import contextmanager -import os -import sys -import subprocess - - -# Initial setup - -if 'TRAVIS_TAG' in os.environ: - TRAVIS_TAG = os.environ.get('TRAVIS_TAG') -else: - sys.exit("Environment variable TRAVIS_TAG is unavailable") - -if 'TRAVIS_BUILD_DIR' in os.environ: - TRAVIS_BUILD_DIR = os.environ.get('TRAVIS_BUILD_DIR') -else: - sys.exit("Environment variable TRAVIS_BUILD_DIR is unavailable") - -if 'NPM_AUTH_TOKEN' in os.environ: - NPM_AUTH_TOKEN = os.environ.get('NPM_AUTH_TOKEN') -else: - sys.exit("Environment variable NPM_AUTH_TOKEN is unavailable") - -if TRAVIS_TAG.startswith('core/'): - PROJECT = 'core' - VERSION = TRAVIS_TAG[5:] -else: - PROJECT = 'tracker' - VERSION = TRAVIS_TAG - - if 'AWS_ACCESS_KEY' in os.environ: - AWS_ACCESS_KEY = os.environ.get('AWS_ACCESS_KEY') - else: - sys.exit("Environment variable AWS_ACCESS_KEY is unavailable (required for tracker publishing)") - - if 'AWS_SECRET_KEY' in os.environ: - AWS_SECRET_KEY = os.environ.get('AWS_SECRET_KEY') - else: - sys.exit("Environment variable AWS_SECRET_KEY is unavailable (required for tracker publishing)") - - if 'AWS_S3_BUCKET' in os.environ: - AWS_S3_BUCKET = os.environ.get('AWS_S3_BUCKET') - else: - sys.exit("Environment variable AWS_S3_BUCKET is unavailable (required for tracker publishing)") - - if 'AWS_REGION' in os.environ: - AWS_REGION = os.environ.get('AWS_REGION') - else: - sys.exit("Environment variable AWS_REGION is unavailable (required for tracker publishing)") - - if 'AWS_CF_DISTRIBUTION' in os.environ: - AWS_CF_DISTRIBUTION = os.environ.get('AWS_CF_DISTRIBUTION') - else: - sys.exit("Environment variable AWS_CF_DISTRIBUTION is unavailable (required for tracker publishing)") - - -# Helper functions - -def output_if_error(sbt_output): - """Callback to print stderr and fail deploy if exit status not successful""" - (stdout, stderr) = sbt_output.communicate() - if sbt_output.returncode != 0: - print("Process has been failed.\n" + stdout) - sys.exit(stderr) - - -def execute(command, callback=output_if_error): - """Execute shell command with optional callback""" - formatted_command = " ".join(command) if (type(command) == list) else command - print("Executing [{0}]".format(formatted_command)) - output = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - if hasattr(callback, '__call__'): - return callback(output) - else: - return output - - -def check_version(): - """Fail deploy if tag version doesn't match SBT version""" - if PROJECT == 'core': - get_version = """var fs=require('fs'); fs.readFile('./core/package.json', 'utf8', function(e,d) { console.log(JSON.parse(d)['version']) });""" - elif PROJECT == 'tracker': - get_version = """var fs=require('fs'); fs.readFile('./package.json', 'utf8', function(e,d) { console.log(JSON.parse(d)['version']) });""" - else: - sys.exit("Unknown project " + str(PROJECT)) - - node_output = execute(['node', '-e', get_version], None) - print(node_output.stderr.read()) - for line in node_output.stdout.read().split("\n"): - print(line) - if line: - if line != VERSION: - sys.exit("Version extracted from TRAVIS_TAG [{0}] doesn't conform declared in package.json [{1}]".format(VERSION, line)) - else: - return - - sys.exit("Cannot find version in core output:\n" + str(node_output)) - - -@contextmanager -def npm_credentials(): - """Context manager allowing to use different credentials and delete them after use""" - npmrc = os.path.expanduser("~/.npmrc") - - if os.path.isfile(npmrc): - os.remove(npmrc) - print("WARNING! ~/.npmrc already exists. It should be deleted after each use") - print("Overwriting existing ~/.npmrc") - else: - print("Creating ~/.npmrc") - - with open(npmrc, 'a') as f: - f.write("registry=https://registry.npmjs.org/\n//registry.npmjs.org/:_authToken=" + NPM_AUTH_TOKEN) - - yield - - print("Deleting ~/.npmrc") - os.remove(npmrc) - - -@contextmanager -def aws_credentials(): - """Context manager allowing to use different credentials and delete them after use""" - awsjson = os.path.join(TRAVIS_BUILD_DIR, "aws.json") - - if os.path.isfile(awsjson): - sys.exit("aws.json already exists. It should be deleted after each use") - else: - print("Creating aws.json") - with open(awsjson, 'a') as f: - f.write( - '{"key":"%(key)s","secret":"%(secret)s","bucket":"%(bucket)s","region":"%(region)s", "distribution":"%(distribution)s"}' % \ - {'key': AWS_ACCESS_KEY, 'secret': AWS_SECRET_KEY, 'bucket': AWS_S3_BUCKET, 'distribution': AWS_CF_DISTRIBUTION, 'region': AWS_REGION} - ) - - yield - - print("Deleting aws.json") - os.remove(awsjson) - - -def publish_core(): - os.chdir(os.path.join(TRAVIS_BUILD_DIR, "core")) - with npm_credentials(): - execute(['npm', 'publish']) - - -def publish_tracker(): - os.chdir(TRAVIS_BUILD_DIR) - with aws_credentials(): - execute(['grunt', 'publish']) - - -def publish(): - if PROJECT == 'core': - publish_core() - elif PROJECT == 'tracker': - publish_tracker() - else: - sys.exit("Unknown project " + str(PROJECT)) - -if __name__ == "__main__": - # Publish locally all dependencies - check_version() - publish() diff --git a/.travis/is_core_release_tag.sh b/.travis/is_core_release_tag.sh deleted file mode 100755 index 7fac811a3..000000000 --- a/.travis/is_core_release_tag.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -tag=$1 -cicd=${tag:0:4} -release=${tag:5} - -if [ "${cicd}" == "core" ]; then - if [ "${release}" == "" ]; then - echo "Warning! No release specified! Ignoring." - exit 2 - fi - exit 0 -else - exit 1 -fi \ No newline at end of file diff --git a/.travis/is_correct_core_release_tag.sh b/.travis/is_correct_core_release_tag.sh deleted file mode 100755 index befbb1bf3..000000000 --- a/.travis/is_correct_core_release_tag.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -tag=$1 -cicd=${tag:0:4} -release=${tag:5} -coreVersion=$(node -e 'const {version} = require("./core/package.json"); console.log(`${version}`);') - -if [ "${cicd}" == "core" ]; then - if [ "${release}" == "" ]; then - echo "Warning! No release specified! Ignoring." - exit 2 - elif [ "${release}" != "${coreVersion}" ]; then - echo "Tagged version ${release} does not equal core package version ${coreVersion}" - exit 1 - fi - exit 0 -else - exit 1 -fi diff --git a/.travis/is_correct_tracker_release_tag.sh b/.travis/is_correct_tracker_release_tag.sh deleted file mode 100755 index 771522f74..000000000 --- a/.travis/is_correct_tracker_release_tag.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -tag=$1 -release=$tag -trackerVersion=$(node -e 'const {version} = require("./package.json"); console.log(`${version}`);') - -if [ "${release}" == "" ]; then - echo "Warning! No release specified! Ignoring." - exit 2 -else - if [ "${release:0:4}" == "core" ]; then - echo "Core relase, not tracker" -elif [ "${release}" != "${trackerVersion}" ]; then - echo "Tagged version ${release} does not equal tracker package version ${trackerVersion}" - fi -fi -exit 0 diff --git a/.travis/is_tracker_release_tag.sh b/.travis/is_tracker_release_tag.sh deleted file mode 100755 index 2c7c43507..000000000 --- a/.travis/is_tracker_release_tag.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -tag=$1 -release=$tag - -if [ "${release}" == "" ]; then - echo "Warning! No release specified! Ignoring." - exit 2 -else - if [ "${release:0:4}" == "core" ]; then - echo "Core relase, not tracker" - fi -fi -exit 0 diff --git a/CHANGELOG b/CHANGELOG deleted file mode 100644 index afec7099e..000000000 --- a/CHANGELOG +++ /dev/null @@ -1,598 +0,0 @@ -Version 2.14.0 (2020-02-28) ---------------------------- - Fix SameSite cookie warning for storage Cookies (#795) - -Version 2.13.0 (2020-02-07) ---------------------------- -Add activity tracking callback mechanism (#774) -Reset activity on page view (#750) -Update beacon support to handle "gotchas" (#716) -Remove user_fingerprint (#549) -Change setup process to use Docker (#782) -Handle errors in tracker callback (#784) -Fix al.optimizely.get is not a function error (#619) -Further harden the Optimizely integrations (#654) -Use local sp.js for example pages (#790) -Change deprecation strings to constants and reuse (close #791) - -Version 2.12.0 (2019-10-31) ---------------------------- -Core: Add function to allow setting Useragent (#744) -Fix OptimizelyX context collecting (#730) -Fix osx+safari testing setup issues (#760) -Fix tracker continuing to insert events up to max Local Storage quota (#764) -Fix dynamic context callbacks sometimes returning null (#743) -Fix stateStorageStrategy localStorage not increasing session counters (#718) -Update packages and test harness (#756) -Add Snowplow Micro tests (#755) - -Version 2.11.0 (2019-08-28) ---------------------------- -Core: Send focus_form 'type' field as 'elementType' (#731) -Update Sauce Connect version (#735) -Add GDPR context (#645) -Rotate npm token (#737) -Deploy tracker asset directly to Github Tagged release rather than cloudfront (#741) -Ensure that the intended version is deployed (#739) - -Version 2.10.2 (2019-02-07) ---------------------------- -Update integration template to set eventMethod arg to get (#713) -Make POST default instead of Beacon API (#712) -Fix Beacon tracking to flush to OutQueue (#708) -Add method to disallow braces in URL (#711) - -Version 2.10.1 (2019-02-01) ---------------------------- -Catch Beacon safelist exception for Chrome (#706) -Add flag for disabling stm event parameter (#705) -Remove chromeFirstPaint from PerformanceTiming context (#635) - -Version 2.10.0 (2019-01-17) ---------------------------- -Transpile helpers.js and detectors.js (#693) -Allow dynamic context callbacks for link and form tracking (#585) -Fix default configOptOutCookie value (#672) -Remove outdated addClickListener method (#667) -Error-handling for tracker methods (#675) -Beacon API option for sending events to collector (#674) -Tracking click events on forms (#579) -Update tracker script banner (#684) -Add new local testing workflow (#686) -Clean up indentation of integration test template (#691) -Update outdated dependencies (#685) -Fix typo in sesname variable (#671) -Add global contexts features (#405) -Add Babel to build process (#665) -Replace YUI Compressor with UglifyJS (#687) -Fix log output for failed integration tests (#689) -Use modularized imports for lodash (#502) -Update npm steps in .travis.yml (#690) -Consolidate request method API (#700) -Fix Beacon API support (#702) - -Version 2.9.3 (2019-01-09) --------------------------- -Add option to set a custom POST request path (#696) -Refresh npm authentication token (#688) - -Version 2.9.2 (2018-07-24) --------------------------- -Remove wheel and passive event listener feature flags (#661) - -Version 2.9.1 (2018-06-20) --------------------------- -Keep node type definitions at version 9.6.7 (#649) -Update page ping context on every call to trackPageView (#612) -Core: fix type incompatibility in consent methods (#652) -Added src/js/lib_managed to .gitignore (#650) -Use passive event listeners for mouse wheel event (#478) -Check if browser has full support of Performance Timing API (#539) -Add Java 10 to Ansible playbooks (#657) - -Version 2.9.0 (2018-02-27) --------------------------- -Add ability to change field content before sending form tracking (#465) -Add a method to start a new session (#515) -Make newDocumentTitle variable local (#580) -Enforce that geolocation.timestamp is an integer (#602) -Remove respectOptOutCookie from the Tracker function comments (#605) -Add jsDelivr hits badge (#611) -Add identifyUser as alias for setUserId (#621) -Add trackConsentGranted method (#623) -Add trackConsentWithdrawn method (#624) -Bump semver to 4.3.2 (#625) -LocalStorage domain user ID is not persisted properly (#627) -Core: add trackConsentGranted method (#629) -Core: add trackConsentWithdrawn method (#630) -Update OS X test targets for Saucelabs (#632) -Install dependencies and update shrinkwrap before deployment (#633) - -Version 2.8.2 (2017-08-21) --------------------------- -Fix opt-out cookie check (#604) - -Version 2.8.1 (2017-07-26) --------------------------- -Use trackCallback for all events (#589) -Fix grunt ts in CI/CD (#598) -Fix tech docs icon (#596) -Fix string ids in Optimizely Summary context (#591) -Fix race condition with pageViewId creation (#592) - -Version 2.8.0 (2017-05-18) --------------------------- -Add support for users opting out of state tracking using cookie or localStorage (#459) -Add support for recording state in localStorage rather than cookies (#506) -Exclude password fields from form tracking (#521) -Add Parrable context (#525) -Add support for OptimizelyX context (#551) -Update README markdown in according with CommonMark (#561) -Add support for not recording any state (#563) -Deprecate useCookies (#565) -Deprecate useLocalStorage (#566) -Prevent multiple setInterval from being created (#571) -Guard against non-integer values for minimumVisitLength and heartBeatDelay (#572) -Provide read-only access to domainSessionIndex (#573) -Provide read-only access to cookieName (#574) -Provide read-only access to pageViewId (#575) - -Version 2.7.2 (2017-03-07) --------------------------- -Add defensive check for window.optimizely.data in getOptimizelyStateContexts (#555) - -Version 2.7.1 (2017-03-06) --------------------------- -Add defensive check for window.optimizely.data (#553) - -Version 2.7.0 (2017-01-09) --------------------------- -Add CI/CD (#529) -Add ngrok credentials (#527) -Add Sauce Labs credentials (#528) -Add npm credentials to .travis.yml (#536) -Add AWS credentials to .travis.yml (#537) -Remove random upload path (#538) -Add an option to change life of the visitor cookie, or disable, on tracker creation (#504) -Make tracker Content Security Policy (CSP) compliant (#490) -Add Optimizely summary context (#466) -Add the option to regenerate the page view ID with each page view event (#436) -Add automatic & manual tracking of JS errors to JavaScript tracker (#16) -Get Code Climate badge to green (#152) -Add ability to set true timestamp (#484) -Add timestamp argument for tracking methods (#532) -Remove deprecated visibility state check (#470) -Update Selenium version to 2.48.0 (#487) -Add date for release 2.6.2 to CHANGELOG (#520) -Add trackSelfDescribingEvent method (#471) -Fix integration tests suite (#523) -Bump Core version to 0.5.0 (#301) -Restrict package versions (#522) -Core: only send custom contexts if non-empty array (#540) -Core: add support of true timestamp (#531) -Core: add trackSelfDescribing method (#533) -Core: port to TypeScript (#526) - -Version 2.6.2 (2016-07-14) --------------------------- -Add date for release 2.6.1 to CHANGELOG (#495) -Don't send invalid viewport dimensions (#488) -Check whether elements of navigator.plugins array are undefined (#492) -Only call navigator.javaEnabled on instances of Navigator (#491) -Stop using String.startsWith (#493) -Ensure page view ID is passed to synchronous tracker (#485) - -Version 2.6.1 (2016-04-14) --------------------------- -Prevent CSS class listing from failing for elements with no CSS classes (#473) -Explicitly set suites field in Intern config (#475) - -Version 2.6.0 (2016-03-03) --------------------------- -Bumped ngrok version used in CI to 2.x (#460) -Allowed random upload path in grunt task (#461) -Ensured that PerformanceTiming context doesn't contain properties inherited from Object.prototype (#458) -Added `forceUnsecureTracker` Tracker argument, thanks @bloodyowl! (#374) -Added subset of Augur data as a new context (#386) -Added deprecation warning to setSessionCookieTimeout (#394) -Added setting to automatically use top-level domain for duid (#409) -Added Optimizely contexts (#448) -Added trackEnhancedEcommerceAction() method (#452) -Added addEnhancedEcommerceActionContext() method (#453) -Added addEnhancedEcommerceImpressionContext() method (#454) -Added addEnhancedEcommerceProductContext() method (#455) -Added addEnhancedEcommercePromoContext() method (#456) -Made domainUserId a UUID (#274) -Attached device sent timestamp (stm) to events at last possible moment (#355) -Attempting to create a new tracker using an existing namespace should do nothing (#411) -Using a different library to publish to S3 (#422) -Prevented error running grunt-cloudfront (#426) -Respected doNotTrack in IE 11 and Safari 7.1.3+, thanks @grzegorzewald! (#440) - -Version 2.5.3 (2015-11-10) --------------------------- -Bumped Node version to 4.1.2 in .travis.yml (#420) -Bumped Intern version to 3.0.6 (#370) -Bumped version of temporary to 0.0.8 (#425) -Bumped grunt-yui-compressor to 0.4.0 (#424) -Bumped grunt-browserify to 3.28.1 (#427) -Fixed jstimezonedetect version at 1.0.5 (#429) -Removed Browserify from devDependencies (#428) -Made extraction of DOM element classes compatible with IE9 (#418) -Stopped dereferencing undefined nodes when setting up form tracking (#423) - -Version 2.5.2 (2015-08-13) --------------------------- -Prevented the tracker from setting cookies on initialization if "useCookies" is disabled (#403) -Remove tests for unsupported environments (#406) - -Version 2.5.1 (2015-07-27) --------------------------- -Fixed prerender detection (#391) -Made page title tracking dynamic (#392) -Added warning about using a file URL to example pages (#397) - -Version 2.5.0 (2015-07-22) --------------------------- -Generated a unique session ID for each new session (#347) -Added a page view UUID (#369) -Maintained visit count when cookies are disabled (#388) -Bumped payload_data schema to 1-0-3 (#385) -Added Grunt task to build the tracker skipping the lodash and minification tasks (#382) -Added ability to configure the session cookie timeout in the argmap (#383) -Removed deprecated performanceTiming argument to trackPageView (#375) -Added ability to pass a context-generating function to trackPageView (#372) -Removed configWriteCookies setting (#390) -Updated browser feature detection tests (#378) - -Version 2.4.3 (2015-04-15) --------------------------- -Added License button to README (#357) -Set the ID cookie as soon as the tracker loads (#358) -Updated the session count as soon as the tracker loads (#361) -Made single events exceeding the maximum POST request size attempt to fire exactly once (#359) -Fixed querystring decoration for links with inner elements (#360) - -Version 2.4.2 (2015-04-07) --------------------------- -Set a maximum size for POST requests (#353) -Fixed QuotaExceededError bug (#352) - -Version 2.4.1 (2015-03-27) --------------------------- -Counted any 2xx or 3xx collector response to a POST request as successful (#343) -Counted any 4xx or 5xx collector response to a POST request as failed (#344) -Prevented the localStorage event buffer from being flushed more than once simultaneously (#345) -Cancelled the XMLHttpRequest timeout callback when the request fails (#348) -Stopped adding null PerformanceTiming context (#354) - -Version 2.4.0 (2015-03-16) --------------------------- -Added ability to modify links allowing cross-domain tracking (#109) -Added timing event (#320) -Increased safety of document size detection (#334) -Started randomly generating ngrok subdomain in integration tests (#333) -Fixed Vagrant setup to use latest Peru version (#336) -Stopped caching page URL and referrer URL (#337) -Stopped caching PerformanceTiming context (#339) -Added common contexts to link_click, change_form, and submit_form events (#340) - -Version 2.3.0 (2015-03-03) -------------------------- -Added support for sending events via POST (#168) -Removed dependency on fblundun fork of grunt-yui-compressor (#172) -Added support for batching events (#186) -Started sending PerformanceTiming context with all events (#317) -Added ability to send geolocation context with all events (#191) -Added ability to send context containing all GA cookies with all events (#253) -Improved document height detection (#236) -Added integration tests (#154) -Added functional tests for document size detection and browser features (#270) -Added ability to whitelist or blacklist specific forms and specific form fields (#287) -Added dedicated Vagrant setup (#312) -Added Vagrant "push core" to build and publish Tracker Core (#315) -Added Vagrant "push tracker" to build and deploy JavaScript Tracker (#313) -Renamed deploy to dist (#319) -Stopped sending NaN for page scroll offsets (#324) - -Version 2.2.2 (2015-03-03) --------------------------- -Corrected time at which minimum and maximum scroll offsets are reset (#325) - -Version 2.2.1 (2015-01-28) --------------------------- -Fixed QuotaExceededError bug with localStorage in Safari (#308) -Stopped sending empty PerformanceTiming context (#306) -Prevented PerformanceTiming context being sent multiple times (#309) -Stopped automatically setting Cloudfront URL in synchronous tracker, thanks @vassilevsky! (#311) -Fixed lodash-cli version at 2.4.2 (#314) -Prevented accidental publication of snowplow-tracker to npm (#300) -Added missing tid ticket to CHANGELOG under 2.1.0 (#302) - -Version 2.2.0 (2014-12-15) --------------------------- -Made trackerDictionary object available in onload callbacks, thanks @murphybob! (#294) -Ensured all page offsets are integers (#291) -Added public method to get duid (#289) -Added public method to get user fingerprint (#288) -Added bundle.js to deploy/.gitignore (#281) -Started using grunt-cloudfront for cache invalidation (#276) -Added ability to disable use of localStorage (#181) -Added ability to disable cookies (#140) -URL encoded custom contexts if base 64 encoding is disabled (#299) - -Version 2.1.2 (2014-11-15) --------------------------- -Removed requestEnd field from PerformanceTiming context (#285) - -Version 2.1.1 (2014-11-06) --------------------------- -Rounded chromeFirstPaint field to an integer (#282) - -Version 2.1.0 (2014-11-05) --------------------------- -Added automated form submission tracking (#252) -Stopped outbound queue from triggering multiple times per event (#251) -Added PerformanceTiming context using HTML5 Web Performance API (#248) -Added ability to execute a custom callback once sp.js is loaded (#246) -Added internal site search event (#241) -Started using grunt-cloudfront-clear for CloudFront cache invalidation (#230) -Renamed /dist to /deploy (#216) -Moved context querystring to end of JS-generated beacons (#204) -Added guard to wait until outbound queue is empty before unloading (#202) -Added event_id generation (#190) -Stopped sending tid (#218) -Added content field to link click events (#187) -Replaced "Getting started" with Vagrant-using "Contributing quickstart" (#169) -Added async-large.html (#162) -Improved F rating for tracker.js in CodeClimate (#150) -Added trackAddToCart and trackRemoveFromCart events (#97) -Added further Intern unit tests (#76) -Added social tracking features (#12) -Improved efficiency of enableLinkClickTracking (#254) -Integrated the Tracker Core (#255) -Removed deprecated trackImpression method (#256) -Added forceSecureTracker boolean option to the argmap, thanks @kujo4pmZ! (#247) -Moved link click tracking into its own file (#266) -Made IP address regex more strict (#267) -Updated expected browser fingerprints in functional detectors test (#275) -Added check to ensure outQueue is an array, thanks @kevinsimper! (#277) - -Version 2.0.2 (2014-10-20) --------------------------- -Changed default configCookiePath to "/" (#250) - -Version 2.0.1 (2014-10-12) --------------------------- -Made error logging compatible with Internet Explorer (#264) -Fixed SauceLabs red status (#235) - -Version 2.0.0 (2014-07-03) --------------------------- -Moved fixUpUrl into its own file, called lib/proxies.js (#112) -Fixed duplication of querystring parameter lookup (#111) -Added tests for helpers.js (#96) -Added tests for detectors.js (#95) -Replaced cookie.js with browser-cookie-lite (#88) -Added ad conversion tracking (#60) -Added ad click tracking (#59) -Added initial localStorage support for intermittent offline beacons, thanks @rcs! (#24) -Added new trackAdImpression, mapping to unstructured event (#13) -Removed references to referral cookie (#118) -Implemented enableLinkTracking support (#51) -Replaced hard-coded version with template value (#120) -Added Sauce Labs small button at top of README (#123) -Added Sauce full test summary widget (long bar) at bottom of README (#124) -Added support for namespacing (#4) -Passed tracker namespace through to collector in Tracker Protocol (#126) -Moved to argmap-style tracker creation with 'newTracker' (#132) -Added support for cookie namespacing (#131) -Added new tag which allows queue to be renamed (#130) -Started rigorously checking whether a page is cached by Yahoo (#142) -Upgraded Intern to 1.5.0 (#119) -Fixed link to code climate button in README.md (#149) -Added examples of tracker namespacing (#159) -Split async.html into async-small.html, async-medium.html (#160) -Linked the Technical Docs and Setup Guide images to the appropriate pages (#164) -Made JS invocation tag part of the build process (#158) -Fixed warnings generated by the Closure Compiler, thanks @steve-gh! (#170) -Added untracked files which should be ignored to .gitignore (#173) -Removed ads/sync.html (#182) -Updated ads/async.html (#183) -Added pageUnloadTimer option to argmap (#171) -Removed type hints from unstructured events and custom contexts (#163) -Added hardcoded schema to custom context arrays (#199) -Added hardcoded schema to unstructured events (#196) -Changed trackUnstructEvent to take a JSON containing schema and data fields (#197) - -Version 1.0.3 (2014-06-27) --------------------------- -Changed Base64 encoding function to prevent character encoding errors, thanks @shermozle! (#231) - -Version 1.0.2 (2014-06-24) --------------------------- -Added guard to prevent document size field from being set as "NaNxNaN" (#220) -Fixed Grunt publish tasks to build sp.js as well as upload it to S3 (#224) -Added cache control to Grunt upload for full semantic version (#225) - -Version 1.0.1 (2014-04-09) --------------------------- -Fixed lodash.js to work in the presence of AMD modules (#165) -Added missing variable declarations (#166) - -Version 1.0.0 (2014-03-27) --------------------------- -Added extra meta-data to package.json (#83) -Moved part of banner.js into Gruntfile with grunt-concat's banner option so its values are based on package.json (#82) -Started using Browserify for modules (#74) -Replaced some/all of lib/.js with modules (#7) -Added user fingerprinting on/off switch and configurable hash seed (#7) -Deprecated trackImpression (#66) -Removed attachUserId as fully deprecated now (#64) -Removed setSiteId as fully deprecated now (#63) -Removed getVisitor-Id, -Info as fully deprecated now (#62) -Removed trackEvent as fully deprecated now (#61) -Tightened public API for SnowPlow (#29) -Renamed SnowPlow everywhere to Snowplow (#69) -Prepended window. or SnowPlow.windowAlias. onto _snaq everywhere (#39) -Removed legacy Piwik plugin framework (#56) -Moved hasSessionStorage and hasLocalStorage into detectors.js (#91) -Wrote tests for AsyncQueueProxy (#100) -Added Travis CI to the project (#103) -Added a built with Grunt button to the README (#102) -Added codeclimate button to README (#137) -Added named Grunt tasks (#86) -Added Intern unit tests for payload.js (#5) -Replaced all functions in identifiers.js which are directly available from lodash (#85) -Moved functions from identifers.js into payload.js and wrote Intern tests for them (#108) -Added getting started info for developers to README, thanks @pkallos! (#129) - -Version 0.14.1 (2014-03-12) ---------------------------- -Fixed bug where fromQuerystring was matching fragments instead of just the querystring (#116) - -Version 0.14.0 (2014-02-12) ---------------------------- -Bumped version to 0.14.0 -Removed all DEBUG blocks from codebase (#65) -Renamed requestStringBuilder to payloadBuilder and moved it into its own file, payload.js (#55) -Introduced gzipped sp.js library (#48) -Updated grunt and intern dependencies (#54) -Replaced snowpak.sh with Grunt and grunt-yui-compressor (#53) -Added setUserIdFromReferrer and setUserIdFromLocation (#57) -Added ability to pass a referrer to Snowplow from an IFRAME (#1) -Tested setDoNotTrack and renamed it to respectDoNotTrack (#28) -Moved detect...() functions into new file context.js (#37) -Moved cookie-related functionality into new file cookie.js (#77) -Removed getLegacyCookieName as no longer needed for migrating cookie IDs (#50) -Switched deployment to use Grunt (#58) -Added setUserIdFromCookie (#78) - -Version 0.13.1 (2014-01-28) ---------------------------- -Fixed bug where non-String values are not being added to our payload (#71) - -Version 0.13.0 (2014-01-26) ---------------------------- -Added fully retrospective CHANGELOG (#20) -Added setPlatform support, thanks @rcs! (#25) -Added currency field to ecommerce transactions (#34) -Added custom unstructured contexts (#49) -Added base64decode to Tracker (#36) -Added null check to requestStringBuilder() (#40) -Added array helpers (#41) -Fixed (harmless) bug in base64.js (#35) -Update .gitignore to be node-friendly .gitignore (#52) -Switched to Semantic versioning & only put MAJOR version in hosted path to snowplow.js (#47) -Added package.json (#38) -Added retrospective tags back in (#22) -Restructured folders (#21) - -Version 0.12.0 (2013-07-07) ---------------------------- -Fixed document reference to use documentAlias (#247) -Fixed bug with setCustomUrl (#267) -Changed ev_ to se_ for structured events (#197) -Fixed Firefox failure when "Always ask" set for cookies (#163) -Fixed bug in page ping functionality detected in IE 8 (#260) -Replaced forEach as not supported in IE 6-8 (#295) - -Version 0.11.2 (2013-05-14) ---------------------------- -Added unstructured events, thanks @rgabo, @tarsolya, @lackac (#198) -Remove leading ampersand in querystring (#188) - -Version 0.11.1 (2013-02-25) ---------------------------- -Fixed bug with cookie secure flag killing user ID cookies (#181) - -Version 0.11.0 (2013-02-22) ---------------------------- -Introduced setAppId() and deprecated setSiteId() (#168) -1st party user ID now transmitted as duid (domain uid) (part of #150) -Now sends dtm - the client timestamp (#149) -Deprecated and disabled attachUserId() -Deprecated getVisitorId() and getVisitorInfo() - use getDomainUserId() and getDomainUserInfo() instead -Added setUserId which sets the uid field (#167) -Snowplow cookies no longer tied to site ID (#148) - -Version 0.10.0 (2013-02-15) ---------------------------- -Updated copyright notices -Removed deprecated setAccount(), setTracker(), setHeartBeatTimer() - BREAKING CHANGE (#86) -Added document charset to querystring (#138) -Page ping no longer killed by 1 heartbeat w/o activity (#132) -Added document & viewport dimensions (#94) -Introduced trackStructEvent and deprecated trackEvent (#143) -Cleaned up getRequest code to use improved requestStringBuilder -Fixed logImpression (was using wrong argument names) (#162) -Added scroll offsets to page ping (#127) - -Version 0.9.1 (2013-01-29) --------------------------- -Fixed bug where secure flag not being set on cookies sent via HTTPS - -Version 0.9.0 (2012-12-26) --------------------------- -Each event now sent with an event type `e` (#63) -Refactoring of event definition code -Added attachUserId(boolean) method (#92) -Removed configCustomData from logImpression (#115) -Cleaned up activity tracking (page pings) -Added a combine only option to snowpak.sh - -Version 0.8.2 (2012-12-18) --------------------------- -Fixed regressions from splitting JS into multiple files (#103) - -Version 0.8.1 (2012-11-29) --------------------------- -Fixed bug with trailing comma (#102) -Removed console.log when not debugging (#101) -Removed minified sp.js from version control (added .gitignore to keep it out) - -Version 0.8.0 (2012-11-28) --------------------------- -Rename ice.png to i - BREAKING CHANGE (#29) -Added setCollectorCf() and deprecated setAccount() (#32) -Tracker constructor now supports Cf or Url (part of #44) -getTrackerCf() and -Url() added, getTracker() deprecated (part of #44) -Added tracker version (`tv`) to querystring (#41) -Added color depth tracking (part of #69) -Added timezone tracking (part of #69) -Added user fingerprinting (#70) -Broke out .js into multiple files (#55) - -Version 0.7.0 (2012-10-01) --------------------------- -Renamed said to aid for application ID - -Version 0.6 (2012-09-05) ------------------------- -Added setSiteId functionality -Added ecommerce tracking - -Version 0.5 (2012-08-18) --------------------------- -Changed header comments from Doxygen format to JsDoc -Added support for specifying collectorUrl directly -Added versioning into header comment (so survives minification) -Took f_ off res and cookie; added url onto end, renamed rdm to tid - -Version 0.4 (2012-05-30) ------------------------- -Improved names of querystring params -Added page-url to querystring as fallback - -Version 0.3 (2012-05-18) ------------------------- -Updated to prepend f_ to browser features -Revised the querystring name-value pairs to make them more user-friendly - -Version 0.2 (2012-05-08) ------------------------- -Formalised minification process - -Version 0.1 (2012-03-21) ------------------------- -Initial release diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..a04310f6b --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,554 @@ +# Snowplow JavaScript Tracker - CLAUDE.md + +## Project Overview + +The Snowplow JavaScript Tracker is a comprehensive analytics tracking library for web, browser, and React Native applications. It provides event tracking capabilities for sending data to Snowplow collectors. The project uses a monorepo structure managed by Rush.js with TypeScript as the primary language. + +### Key Technologies +- **Language**: TypeScript/JavaScript +- **Build System**: Rush.js (monorepo) + Rollup +- **Package Manager**: pnpm (v9.7.1) +- **Testing**: Jest with jsdom +- **Target Environments**: Browser, Node.js, React Native + +## Development Commands + +```bash +# Install dependencies and build all packages +rush install +rush build + +# Run tests +rush test # Run all tests +rush test:unit # Unit tests only +rush test:e2e # E2E tests + +# Build specific package +cd trackers/browser-tracker && rushx build + +# Quality checks +rush lint # ESLint +rush format # Prettier +``` + +## Architecture + +### System Design +The tracker follows a **layered plugin architecture** with core libraries providing fundamental tracking capabilities and plugins extending functionality for specific use cases. + +``` +┌─────────────────────────────────────────┐ +│ Trackers Layer │ +│ (browser, javascript, node, react-native) │ +├─────────────────────────────────────────┤ +│ Plugins Layer │ +│ (30+ browser plugins for features) │ +├─────────────────────────────────────────┤ +│ Core Libraries Layer │ +│ (tracker-core, browser-tracker-core) │ +└─────────────────────────────────────────┘ +``` + +### Module Organization +- **libraries/**: Core tracking functionality + - `tracker-core`: Platform-agnostic tracking logic + - `browser-tracker-core`: Browser-specific core features +- **trackers/**: Platform-specific tracker implementations +- **plugins/**: Feature-specific plugins (ad tracking, media, ecommerce, etc.) +- **common/**: Shared Rush.js configuration and scripts + +## Core Architectural Principles + +### 1. Plugin-Based Architecture +```typescript +// ✅ Correct: Plugin pattern with activation lifecycle +export function MyPlugin(): BrowserPlugin { + return { + activateBrowserPlugin: (tracker) => { + _trackers[tracker.id] = tracker; + } + }; +} + +// ❌ Wrong: Direct tracker manipulation +export function myFeature(tracker) { + tracker.someMethod(); // Breaks encapsulation +} +``` + +### 2. Event Builder Pattern +```typescript +// ✅ Correct: Use builder functions for events +import { buildSelfDescribingEvent } from '@snowplow/tracker-core'; +const event = buildSelfDescribingEvent({ schema, data }); + +// ❌ Wrong: Manual event construction +const event = { e: 'ue', ue_pr: {...} }; // Don't construct manually +``` + +### 3. Type-Safe Self-Describing JSON +```typescript +// ✅ Correct: Typed SelfDescribingJson +export type MyEventData = { + field: string; + value: number; +}; +const event: SelfDescribingJson = { + schema: 'iglu:com.example/event/jsonschema/1-0-0', + data: { field: 'test', value: 42 } +}; + +// ❌ Wrong: Untyped data objects +const event = { schema: '...', data: someData }; +``` + +### 4. Workspace Dependencies +```typescript +// ✅ Correct: Use workspace protocol for internal deps +"dependencies": { + "@snowplow/tracker-core": "workspace:*" +} + +// ❌ Wrong: Version-specific internal dependencies +"dependencies": { + "@snowplow/tracker-core": "^3.0.0" +} +``` + +## Layer Organization & Responsibilities + +### Core Libraries (`libraries/`) +- **tracker-core**: Event building, payload construction, emitter logic +- **browser-tracker-core**: Browser APIs, storage, cookies, DOM helpers + +### Trackers (`trackers/`) +- **browser-tracker**: Modern browser tracking API +- **javascript-tracker**: Legacy SP.js compatible tracker +- **node-tracker**: Server-side Node.js tracking +- **react-native-tracker**: Mobile app tracking + +### Plugins (`plugins/`) +Each plugin follows the standard structure: +``` +browser-plugin-*/ +├── src/ +│ ├── index.ts # Plugin export & registration +│ ├── api.ts # Public API functions +│ ├── types.ts # TypeScript definitions +│ └── schemata.ts # Event schemas +├── test/ +├── package.json +└── rollup.config.js +``` + +## Critical Import Patterns + +### 1. Core Imports +```typescript +// ✅ Correct: Import from package roots +import { BrowserPlugin } from '@snowplow/browser-tracker-core'; +import { buildSelfDescribingEvent } from '@snowplow/tracker-core'; + +// ❌ Wrong: Deep imports into src +import { something } from '@snowplow/browser-tracker-core/src/helpers'; +``` + +### 2. Plugin Registration +```typescript +// ✅ Correct: Plugin initialization pattern +import { AdTrackingPlugin } from '@snowplow/browser-plugin-ad-tracking'; + +newTracker('sp', 'collector.example.com', { + plugins: [AdTrackingPlugin()] +}); + +// ❌ Wrong: Direct plugin function calls +AdTrackingPlugin.trackAdClick(); // Plugins need registration +``` + +### 3. Type Exports +```typescript +// ✅ Correct: Re-export types with functions +export { AdClickEvent, trackAdClick } from './api'; + +// ❌ Wrong: Forget to export event types +export { trackAdClick } from './api'; // Missing type export +``` + +## Essential Library Patterns + +### Event Tracking Pattern +```typescript +// Standard event tracking with context +export function trackMyEvent( + event: MyEvent & CommonEventProperties, + trackers: Array = Object.keys(_trackers) +) { + dispatchToTrackersInCollection(trackers, _trackers, (t) => { + t.core.track(buildMyEvent(event), event.context, event.timestamp); + }); +} +``` + +### Plugin State Management +```typescript +// Plugin-scoped tracker registry +const _trackers: Record = {}; + +export function MyPlugin(): BrowserPlugin { + return { + activateBrowserPlugin: (tracker) => { + _trackers[tracker.id] = tracker; + } + }; +} +``` + +### Schema Definition Pattern +```typescript +// schemata.ts - Centralized schema constants +export const MY_SCHEMA = 'iglu:com.snowplowanalytics.snowplow/my_event/jsonschema/1-0-0'; + +// Usage in event builders +const event: SelfDescribingJson = { + schema: MY_SCHEMA, + data: eventData +}; +``` + +## Model Organization Pattern + +### Event Type Definitions +```typescript +// types.ts - Event data interfaces +export interface MediaPlayerEvent { + currentTime: number; + duration?: number; + ended: boolean; + loop: boolean; + // ... other fields +} + +// Composite types for API +export type MediaTrackEvent = MediaPlayerEvent & { + eventType: MediaEventType; + label?: string; +}; +``` + +### Context Builders +```typescript +// Context creation pattern +export function buildMediaContext(player: MediaPlayer): SelfDescribingJson { + return { + schema: MEDIA_PLAYER_SCHEMA, + data: { + currentTime: player.currentTime, + duration: player.duration, + // ... map player state + } + }; +} +``` + +## Common Pitfalls & Solutions + +### 1. Forgetting Plugin Registration +```typescript +// ❌ Wrong: Using plugin API without registration +import { trackAdClick } from '@snowplow/browser-plugin-ad-tracking'; +trackAdClick(event); // Error: _trackers is empty + +// ✅ Correct: Register plugin first +import { AdTrackingPlugin, trackAdClick } from '@snowplow/browser-plugin-ad-tracking'; +newTracker('sp', 'collector.example.com', { + plugins: [AdTrackingPlugin()] +}); +trackAdClick(event); // Works correctly +``` + +### 2. Incorrect Timestamp Types +```typescript +// ❌ Wrong: String timestamps +event.timestamp = '2024-01-01T00:00:00Z'; + +// ✅ Correct: Use Timestamp ADT +event.timestamp = { type: 'ttm', value: Date.now() }; +// or just number for device timestamp +event.timestamp = Date.now(); +``` + +### 3. Manual Payload Construction +```typescript +// ❌ Wrong: Building payloads manually +const payload = { + e: 'se', + se_ca: 'category', + se_ac: 'action' +}; + +// ✅ Correct: Use builder functions +const payload = buildStructEvent({ + category: 'category', + action: 'action' +}); +``` + +## File Structure Template + +### New Plugin Structure +``` +plugins/browser-plugin-[feature]/ +├── src/ +│ ├── index.ts # Plugin export +│ ├── api.ts # Public tracking functions +│ ├── types.ts # TypeScript interfaces +│ ├── schemata.ts # Schema constants +│ └── contexts.ts # Context builders +├── test/ +│ └── [feature].test.ts # Jest tests +├── package.json # Workspace package +├── tsconfig.json # TypeScript config +├── rollup.config.js # Build configuration +└── README.md # Documentation +``` + +## Testing Patterns + +### Test Directory Structure +Each package maintains its own `test/` directory with TypeScript test files: +``` +package/ +├── test/ +│ ├── *.test.ts # Unit tests +│ ├── integration/ # Integration tests +│ ├── functional/ # E2E/browser tests +│ └── __snapshots__/ # Jest snapshots +``` + +### Test File Naming Conventions +```typescript +// ✅ Correct: Descriptive test file names +events.test.ts // Testing event functions +contexts.test.ts // Testing context builders +browser_props.test.ts // Testing browser properties + +// ❌ Wrong: Generic or unclear names +test.test.ts // Too generic +unit.test.ts // Not descriptive +``` + +### Test Suite Structure +```typescript +// ✅ Correct: Nested describe blocks with clear naming +describe('AdTrackingPlugin', () => { + describe('#trackAdClick', () => { + it('tracks click event with correct schema', () => {}); + it('includes required fields in payload', () => {}); + }); +}); + +// ❌ Wrong: Flat structure without context +describe('tests', () => { + it('test1', () => {}); + it('test2', () => {}); +}); +``` + +### Common Test Utilities +```typescript +// Using lodash/fp for test data extraction +import F from 'lodash/fp'; + +const getUEEvents = F.compose(F.filter(F.compose(F.eq('ue'), F.get('e')))); +const extractEventProperties = F.map(F.compose( + F.get('data'), + (cx: string) => JSON.parse(cx), + F.get('ue_pr') +)); +``` + +### Mock Setup Pattern +```typescript +// Standard mock configuration in tests +beforeAll(() => { + jest.spyOn(document, 'title', 'get').mockReturnValue('Test Title'); +}); + +beforeEach(() => { + jest.clearAllMocks(); + // Reset tracker state between tests +}); +``` + +### Snapshot Testing +```typescript +// ✅ Correct: Snapshot for complex objects +expect(buildMediaContext(player)).toMatchSnapshot(); + +// ❌ Wrong: Snapshot for simple values +expect(event.id).toMatchSnapshot(); // Use toBe() instead +``` + +### Test Categories & Best Practices + +#### 1. Unit Tests +Test individual functions and modules in isolation: +```typescript +// ✅ Correct: Testing pure functions +it('makeDimension correctly floors dimension type values', () => { + expect(makeDimension(800.5)).toBe(800); + expect(makeDimension('not-a-number')).toBe(0); +}); +``` + +#### 2. Integration Tests +Test multi-component interactions: +```typescript +// ✅ Correct: Testing plugin integration with tracker +it('registers plugin and tracks events', () => { + const tracker = createTracker({ plugins: [MyPlugin()] }); + trackMyEvent({ data: 'test' }); + expect(eventStore.getEvents()).toHaveLength(1); +}); +``` + +#### 3. Functional/E2E Tests +Browser automation tests for full tracker behavior: +```typescript +// Located in test/functional/ +it('persists session across page reloads', async () => { + await browser.url('/test-page'); + const sessionId = await browser.execute(() => tracker.getSessionId()); + await browser.refresh(); + const newSessionId = await browser.execute(() => tracker.getSessionId()); + expect(sessionId).toBe(newSessionId); +}); +``` + +### Testing Configuration + +#### Jest Configuration Pattern +```javascript +// jest.config.js - Standard config for packages +module.exports = { + preset: 'ts-jest', + testEnvironment: 'jsdom', + setupFilesAfterEnv: ['../../setupTestGlobals.ts'], + reporters: ['jest-standard-reporter'] +}; +``` + +#### Global Test Setup +```typescript +// setupTestGlobals.ts - Shared test utilities +import 'whatwg-fetch'; +global.crypto = { + getRandomValues: (buffer) => nodeCrypto.randomFillSync(buffer) +}; +``` + +### Event Store Testing Pattern +```typescript +// ✅ Correct: Using in-memory event store for tests +import { newInMemoryEventStore } from '@snowplow/tracker-core'; + +const eventStore = newInMemoryEventStore(); +const tracker = createTracker({ eventStore }); +// Verify events: eventStore.getEvents() +``` + +### Testing Async Behavior +```typescript +// ✅ Correct: Testing timer-based functionality +it('sends ping event after interval', async () => { + jest.useFakeTimers(); + startPingInterval(player, 30); + jest.advanceTimersByTime(30000); + await Promise.resolve(); // Allow async operations + expect(trackMediaPing).toHaveBeenCalled(); + jest.useRealTimers(); +}); +``` + +## Quick Reference + +### Import Checklist +- [ ] Import from package root, not `/src` +- [ ] Include type exports with functions +- [ ] Use `workspace:*` for internal dependencies +- [ ] Import builders from `@snowplow/tracker-core` +- [ ] Import browser utils from `@snowplow/browser-tracker-core` + +### Common Tasks + +```typescript +// Create new tracker +import { newTracker } from '@snowplow/browser-tracker'; +newTracker('sp', 'collector.example.com', { + appId: 'my-app', + plugins: [/* plugins */] +}); + +// Track custom event +import { trackSelfDescribingEvent } from '@snowplow/browser-tracker'; +trackSelfDescribingEvent({ + event: { + schema: 'iglu:com.example/event/jsonschema/1-0-0', + data: { /* event data */ } + } +}); + +// Add global context +import { addGlobalContexts } from '@snowplow/browser-tracker'; +addGlobalContexts([{ + schema: 'iglu:com.example/context/jsonschema/1-0-0', + data: { /* context data */ } +}]); + +// Test a tracker with in-memory event store +import { createTracker } from '../helpers'; +import { newInMemoryEventStore } from '@snowplow/tracker-core'; +const eventStore = newInMemoryEventStore(); +const tracker = createTracker({ eventStore }); +``` + +## Contributing to CLAUDE.md + +When adding or updating content in this document, please follow these guidelines: + +### File Size Limit +- **CLAUDE.md must not exceed 40KB** (currently ~11KB) +- Check file size after updates: `wc -c CLAUDE.md` +- Remove outdated content if approaching the limit + +### Code Examples +- Keep all code examples **4 lines or fewer** +- Focus on the essential pattern, not complete implementations +- Use `// ❌` and `// ✅` to clearly show wrong vs right approaches + +### Content Organization +- Add new patterns to existing sections when possible +- Create new sections sparingly to maintain structure +- Update the architectural principles section for major changes +- Ensure examples follow current codebase conventions + +### Quality Standards +- Test any new patterns in actual code before documenting +- Verify imports and syntax are correct for the codebase +- Keep language concise and actionable +- Focus on "what" and "how", minimize "why" explanations + +### Multiple CLAUDE.md Files +- **Directory-specific CLAUDE.md files** can be created for specialized modules +- Follow the same structure and guidelines as this root CLAUDE.md +- Keep them focused on directory-specific patterns and conventions +- Maximum 20KB per directory-specific CLAUDE.md file + +### Instructions for LLMs +When editing files in this repository, **always check for CLAUDE.md guidance**: + +1. **Look for CLAUDE.md in the same directory** as the file being edited +2. **If not found, check parent directories** recursively up to project root +3. **Follow the patterns and conventions** described in the applicable CLAUDE.md +4. **Prioritize directory-specific guidance** over root-level guidance when conflicts exist \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..7804ea950 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,80 @@ +# Contributing + +The Snowplow JavaScript Tracker is maintained by the Engineering team at Snowplow Analytics. We welcome suggestions for improvements and bug fixes to all Snowplow Trackers. + +We are extremely grateful for all contributions we receive, whether that is reporting an issue or a change to the code which can be made in the form of a pull request. + +For support requests, please use our community support Discourse forum: https://discourse.snowplowanalytics.com/. + +## Setting up an Environment + +Instructions on how to build and run tests are available in the [README.md](README.md). The README will also list any requirements that you will need to install first before being able to build and run the tests. + +You should ensure you are comfortable building and testing the existing release before adding new functionality or fixing issues. + +## Issues + +### Creating an issue + +The project contains an issue template which should help guiding you through the process. However, please keep in mind that support requests should go to our Discourse forum: https://discourse.snowplowanalytics.com/ and not GitHub issues. + +It's also a good idea to log an issue before starting to work on a pull request to discuss it with the maintainers. A pull request is just one solution to a problem and it is often a good idea to talk about the problem with the maintainers first. + +### Working on an issue + +If you see an issue you would like to work on, please let us know in the issue! That will help us in terms of scheduling and +not doubling the amount of work. + +If you don't know where to start contributing, you can look at +[the issues labeled `good first issue`](https://github.com/snowplow/snowplow-javascript-tracker/labels/category%3Agood_first_issue). + +## Pull requests + +These are a few guidelines to keep in mind when opening pull requests. + +### Guidelines + +Please supply a good PR description. These are very helpful and help the maintainers to understand _why_ the change has been made, not just _what_ changes have been made. + +Please try and keep your PR to a single feature of fix. This might mean breaking up a feature into multiple PRs but this makes it easier for the maintainers to review and also reduces the risk in each change. + +Please review your own PR as you would do it you were a reviewer first. This is a great way to spot any mistakes you made when writing the change. Additionally, ensure your code compiles and all tests pass. + +### Commit hygiene + +We keep a strict 1-to-1 correspondance between commits and issues, as such our commit messages are formatted in the following +fashion: + +`Issue Description (closes #1234)` + +for example: + +`Fix Issue with Tracker (closes #1234)` + +### Writing tests + +Whenever necessary, it's good practice to add the corresponding tests to whichever feature you are working on. +Any non-trivial PR must have tests and will not be accepted without them. + +### Feedback cycle + +Reviews should happen fairly quickly during weekdays. +If you feel your pull request has been forgotten, please ping one or more maintainers in the pull request. + +### Getting your pull request merged + +If your pull request is fairly chunky, there might be a non-trivial delay between the moment the pull request is approved and the moment it gets merged. This is because your pull request will have been scheduled for a specific milestone which might or might not be actively worked on by a maintainer at the moment. + +### Contributor license agreement + +We require outside contributors to sign a Contributor license agreement (or CLA) before we can merge their pull requests. +You can find more information on the topic in [the dedicated wiki page](https://github.com/snowplow/snowplow/wiki/CLA). +The @snowplowcla bot will guide you through the process. + +## Getting in touch + +### Community support requests + +Please do not log an issue if you are asking for support, all of our community support requests go through our Discourse forum: https://discourse.snowplowanalytics.com/. + +Posting your problem there ensures more people will see it and you should get support faster than creating a new issue on GitHub. Please do create a new issue on GitHub if you think you've found a bug though! \ No newline at end of file diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 18ffea04e..000000000 --- a/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM node:8.12.0-alpine - -RUN apk add git -RUN npm install -g grunt-cli - -WORKDIR /usr/src/app - -COPY package.json ./ -RUN npm install - -COPY . . diff --git a/Gruntfile.js b/Gruntfile.js deleted file mode 100644 index f494a002a..000000000 --- a/Gruntfile.js +++ /dev/null @@ -1,227 +0,0 @@ -/* -* JavaScript tracker for Snowplow: Gruntfile.js -* -* Significant portions copyright 2010 Anthon Pang. Remainder copyright -* 2012-2014 Snowplow Analytics Ltd. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are -* met: -* -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* -* * Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the -* names of their contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -var semver = require('semver'); - -/*global module:false*/ -module.exports = function(grunt) { - - var pkg = grunt.file.readJSON('package.json'); - var semVer = semver.parse(pkg.version); - pkg.pinnedVersion = semVer.major; - var banner = "/*\n" + - " * Snowplow - The world's most powerful web analytics platform\n" + - " *\n" + - " * @description <%= pkg.description %>\n" + - " * @version <%= pkg.version %>\n" + - " * @author " + pkg.contributors.join(', ') +"\n" + - " * @copyright Anthon Pang, Snowplow Analytics Ltd\n" + - " * @license <%= pkg.license %>\n" + - " *\n" + - " * For technical documentation:\n" + - " * https://github.com/snowplow/snowplow/wiki/javascript-tracker\n" + - " *\n" + - " * For the setup guide:\n" + - " * https://github.com/snowplow/snowplow/wiki/javascript-tracker-setup\n" + - " *\n" + - " * Minimum supported browsers:\n" + - " * - Firefox 27 \n" + - " * - Chrome 32 \n" + - " * - IE 9 \n" + - " * - Safari 8 \n" + - " */\n"; - - grunt.initConfig({ - - banner: banner, - - pkg: pkg, - - subdomain: process.env.SUBDOMAIN, - - browserify: { - main: { - files: { - 'dist/bundle.js': ['src/js/init.js'] - } - }, - test: { - files: { - 'tests/pages/helpers.bundle.js': ['tests/scripts/helpers.js'], - 'tests/pages/detectors.bundle.js': ['tests/scripts/detectors.js'], - 'tests/pages/bundle.js': ['src/js/init.js'] - } - } - }, - - babel: { - options: { - presets: ['@babel/preset-env'] - }, - dist: { - files: { - 'dist/bundle-postbabel.js': 'dist/bundle.js' - } - }, - test: { - files: { - 'tests/pages/helpers.js': 'tests/pages/helpers.bundle.js', - 'tests/pages/detectors.js': 'tests/pages/detectors.bundle.js', - 'tests/pages/snowplow.js': 'tests/pages/bundle.js' - } - }, - local: { - files: { - 'tests/local/serve/snowplow.js': 'tests/pages/bundle.js' - } - } - }, - - concat: { - deploy: { - options: { - 'report': 'gzip', - 'process': true - }, - src: ['dist/bundle-postbabel.js'], - dest: 'dist/snowplow.js' - }, - tag: { - options: { - banner: ';' - }, - src: ['tags/tag.min.js'], - dest: 'tags/tag.min.js' - } - }, - - uglify: { - deploy: { - options: { - 'banner': '<%= banner %>' - }, - files: { - 'dist/sp.js': ['dist/snowplow.js'] - } - }, - tag: { - files: { - 'tags/tag.min.js': ['tags/tag.js'] - } - } - } - }); - - grunt.loadNpmTasks('grunt-contrib-concat'); - grunt.loadNpmTasks('grunt-aws'); - grunt.loadNpmTasks('grunt-browserify'); - grunt.loadNpmTasks('grunt-contrib-uglify'); - grunt.loadNpmTasks('grunt-babel'); - - grunt.registerTask('upload_setup', 'Read aws.json and configure upload tasks', function() { - var aws = grunt.file.readJSON('aws.json'); - - grunt.config('aws', aws); - - grunt.config('s3', { - options: { - accessKeyId: '<%= aws.key %>', - secretAccessKey: '<%= aws.secret %>', - bucket: '<%= aws.bucket %>', - access: 'public-read', - region: '<%= aws.region %>', - gzip: true, - cache: false - }, - not_pinned: { - options: { - headers: { - CacheControl: "max-age=315360000" - } - }, - files: [ - { - src: ["dist/sp.js"], - dest: "<%= pkg.version %>/sp.js" - } - ] - }, - pinned: { - options: { - headers: { - CacheControl: "max-age=3600" - } - }, - files: [ - { - src: ["dist/sp.js"], - dest: "<%= pkg.pinnedVersion %>/sp.js" - } - ] - } - }); - - grunt.config('cloudfront', { - options: { - accessKeyId: '<%= aws.key %>', - secretAccessKey: '<%= aws.secret %>', - distributionId: '<%= aws.distribution %>' - }, - not_pinned: { - options: { - invalidations: [ - '/<%= pkg.version %>/sp.js' - ] - } - }, - pinned: { - options: { - invalidations: [ - '/<%= pkg.pinnedVersion %>/sp.js' - ] - } - } - }); - }); - - grunt.registerTask('default', 'Build Browserify, add banner, and minify', ['browserify:main', 'babel:dist', 'concat:deploy', 'uglify:deploy']); - grunt.registerTask('publish', 'Upload to S3 and invalidate Cloudfront (full semantic version only)', ['upload_setup', 'browserify:main', 'babel:dist', 'concat:deploy', 'uglify:deploy', 's3:not_pinned', 'cloudfront:not_pinned']); - grunt.registerTask('publish-pinned', 'Upload to S3 and invalidate Cloudfront (full semantic version and semantic major version)', ['upload_setup', 'browserify:main', 'babel:dist', 'concat:deploy', 'uglify:deploy', 's3', 'cloudfront']); - grunt.registerTask('quick', 'Build snowplow.js, skipping building and minifying', ['browserify:main', 'babel:dist', 'concat:deploy']); - grunt.registerTask('test', 'Intern tests', ['browserify:test', 'babel:test']); - grunt.registerTask('travis', 'Intern tests for Travis CI', ['browserify:test', 'babel:test']); - grunt.registerTask('tags', 'Minifiy the Snowplow invocation tag', ['uglify:tag', 'concat:tag']); - grunt.registerTask('local', 'Builds and places files read to serve and test locally', ['browserify:test', 'babel:test', - 'babel:local', 'concat:local']); -}; diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..74e6299ae --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index 1a6b140d7..000000000 --- a/LICENSE.txt +++ /dev/null @@ -1,29 +0,0 @@ -Significant portions copyright 2010 Anthon Pang. Remainder copyright -2012 Snowplow Analytics Ltd. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -* Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -* Neither the name of Anthon Pang nor Snowplow Analytics Ltd nor the - names of their contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index c1b25374a..b9813e4ee 100644 --- a/README.md +++ b/README.md @@ -1,86 +1,131 @@ -# JavaScript web analytics for Snowplow +# Browser and Node.js analytics for Snowplow -[![Build Status][travis-image]][travis] -[![Selenium Test Status][saucelabs-button-image]][saucelabs] -[![Code Climate][codeclimate-image]][codeclimate] -[![License][license-image]][bsd] -[![jsDelivr Hits](https://data.jsdelivr.com/v1/package/gh/snowplow/snowplow-javascript-tracker/badge?style=rounded)](https://www.jsdelivr.com/package/gh/snowplow/snowplow-javascript-tracker) +[![actively-maintained]][tracker-classificiation] +[![Release][release-image]][releases] +[![License][license-image]](LICENSE) +[![Build Status][gh-actions-image]][gh-actions] +[![Saucelabs Test Status][saucelabs-button-image]][saucelabs] -## Overview +![snowplow-logo](common/media/snowplow_logo.png) -Add analytics to your websites and web apps with the [Snowplow][snowplow] event tracker for -JavaScript. +Snowplow is a scalable open-source platform for rich, high quality, low-latency data collection. It is designed to collect high quality, complete behavioral data for enterprise business. -With this tracker you can collect user event data (page views, e-commerce transactions etc) from the -client-side tier of your websites and web apps. +**To find out more, please check out the [Snowplow website][website] and our [documentation][docs].** -## Find out more +## Snowplow JavaScript Trackers Overview -| Technical Docs | Setup Guide | Roadmap & Contributing | -|-------------------------------------|------------------------------|--------------------------------------| -| [![i1][techdocs-image]][tech-docs] | [ ![i2][setup-image]][setup] | ![i3][roadmap-image] | -| [Technical Docs][tech-docs] | [Setup Guide][setup] | _coming soon_ | +The Snowplow JavaScript Trackers allow you to add analytics to your websites, web apps and Node.js applications when using a [Snowplow][snowplow] pipeline. +With these trackers you can collect user event data (page views, e-commerce transactions etc) from the +client-side and server-side tiers of your websites and web apps. -## Developers +**Technical documentation can be found for each tracker in our [Documentation][javascript-docs].** -### Contributing quickstart +### @snowplow/browser-tracker (npm) -Assuming git and [Docker][docker-install] installed: +| Technical Docs | Setup Guide | +|---------------------------------------------|--------------------------------------| +| [![i1][techdocs-image]][tech-docs-browser] | [![i2][setup-image]][setup-browser] | +| [Technical Docs][tech-docs-browser] | [Setup Guide][setup-browser] | +### @snowplow/javascript-tracker (tag based) + +| Technical Docs | Setup Guide | +|----------------------------------------|---------------------------------| +| [![i3][techdocs-image]][tech-docs-js] | [![i4][setup-image]][setup-js] | +| [Technical Docs][tech-docs-js] | [Setup Guide][setup-js] | + +### @snowplow/node-tracker (npm) + +| Technical Docs | Setup Guide | +|------------------------------------------|-----------------------------------| +| [![i5][techdocs-image]][tech-docs-node] | [![i6][setup-image]][setup-node] | +| [Technical Docs][tech-docs-node] | [Setup Guide][setup-node] | + +## Maintainers + +| Contributing | +|--------------------------------------| +| ![i7][contributing-image] | +| [Contributing](CONTRIBUTING.md) | + +### Maintainer quick start + +Assuming [git](https://git-scm.com/downloads), [Node.js 18 - 20](https://nodejs.org/en/download/releases/) are installed. + +#### Clone repository + +```bash +git clone https://github.com/snowplow/snowplow-javascript-tracker.git ``` - host$ git clone https://github.com/snowplow/snowplow-javascript-tracker.git - host$ cd snowplow-javascript-tracker - host$ docker build -t tracker . - host$ docker run tracker grunt - host$ cd core - host$ docker build -t core . - host$ docker run core grunt -``` -Set up an `./aws.json` file using the example `./aws.sample.json`. If you just want to concat + -minify without uploading then you don't need to fill out the `aws.json` file with valid credentials. +#### Install gitleaks + +To commit with safety in the repository, preventing sensitive key leakage, we use [gitleaks](https://github.com/gitleaks/gitleaks). Gitleaks runs as a pre-commit hook making sure it can prevent accidental committing of sensitive data. + +To install gitleaks, you can follow the [getting started](https://github.com/gitleaks/gitleaks) section on the repository. + +_For open source users before the update, you might need to re-run `rush install` to update your git hooks from source._ -Build the package (default task concatenates and minifies) using `grunt`. +:warning: To disable gitleaks check, you can run your commit command with the `SKIP=gitleaks` variable. e.g. `SKIP=gitleaks git commit -m "Unsafe commit"`. + +#### Building + +```bash +npm install -g @microsoft/rush +rush update +rush build +``` ## Testing -[![Selenium Test Status][saucelabs-matrix-image]][saucelabs] +To run unit tests: -## Copyright and license +```bash +rush test +``` + +To run e2e browser tests (locally): -The Snowplow JavaScript Tracker is based on Anthon Pang's [`piwik.js`][piwikjs], the JavaScript -tracker for the open-source [Piwik][piwik] project, and is distributed under the same license -([Simplified BSD][bsd]). +- Add `127.0.0.1 snowplow-js-tracker.local` to your `hosts` file: -Significant portions of the Snowplow JavaScript Tracker copyright 2010 Anthon Pang. Remainder -copyright 2012-14 Snowplow Analytics Ltd. +```bash +cd trackers/javascript-tracker/ +rushx test:e2e:local +``` -Licensed under the [Simplified BSD][bsd] license. +[![Sauce Labs Test Status][saucelabs-matrix-image]][saucelabs] -[snowplow]: http://snowplowanalytics.com/ +## Copyright and license -[docker-install]: https://docs.docker.com/install/ +Licensed and distributed under the [BSD 3-Clause License](LICENSE) ([An OSI Approved License][osi]). -[piwik]: http://piwik.org/ -[piwikjs]: https://github.com/piwik/piwik/blob/master/js/piwik.js -[piwikphp]: https://github.com/piwik/piwik/blob/master/piwik.php -[bsd]: http://www.opensource.org/licenses/bsd-license.php -[integrating]: /snowplow/snowplow/blob/master/docs/03_integrating_snowplowjs.md -[selfhosting]: /snowplow/snowplow/blob/master/docs/04_selfhosting_snowplow.md -[setup]: https://github.com/snowplow/snowplow/wiki/javascript-tracker-setup -[integrating-js-on-website]: https://github.com/snowplow/snowplow/wiki/integrating-javascript-tags-onto-your-website -[tech-docs]: https://github.com/snowplow/snowplow/wiki/javascript-tracker +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang. + +All rights reserved. + +[website]: https://snowplowanalytics.com +[snowplow]: https://github.com/snowplow/snowplow +[docs]: https://docs.snowplowanalytics.com/ +[docker-install]: https://docs.docker.com/install/ +[javascript-docs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-trackers/ +[tech-docs-browser]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-trackers/browser-tracker/browser-tracker-v3-reference/ +[setup-browser]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-trackers/browser-tracker/quick-start-guide/ +[tech-docs-js]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-trackers/javascript-tracker/javascript-tracker-v3/ +[setup-js]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-trackers/javascript-tracker/web-quick-start-guide/ +[tech-docs-node]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-trackers/node-js-tracker/node-js-tracker-v3/ +[setup-node]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-trackers/node-js-tracker/node-js-tracker-v3/setup/ [techdocs-image]: https://d3i6fms1cm1j0i.cloudfront.net/github/images/techdocs.png [setup-image]: https://d3i6fms1cm1j0i.cloudfront.net/github/images/setup.png -[roadmap-image]: https://d3i6fms1cm1j0i.cloudfront.net/github/images/roadmap.png -[grunt-image]: https://cdn.gruntjs.com/builtwith.png -[grunt]: http://gruntjs.com/ -[travis-image]: https://travis-ci.org/snowplow/snowplow-javascript-tracker.png?branch=master -[travis]: http://travis-ci.org/snowplow/snowplow-javascript-tracker -[codeclimate-image]: https://codeclimate.com/github/snowplow/snowplow-javascript-tracker.png -[codeclimate]: https://codeclimate.com/github/snowplow/snowplow-javascript-tracker +[contributing-image]: https://d3i6fms1cm1j0i.cloudfront.net/github/images/contributing.png +[release-image]: https://img.shields.io/github/v/release/snowplow/snowplow-javascript-tracker?sort=semver +[releases]: https://github.com/snowplow/snowplow-javascript-tracker/releases +[gh-actions]: https://github.com/snowplow/snowplow-javascript-tracker/actions +[gh-actions-image]: https://github.com/snowplow/snowplow-javascript-tracker/workflows/Build/badge.svg [saucelabs]: https://saucelabs.com/u/snowplow -[saucelabs-button-image]: https://saucelabs.com/buildstatus/snowplow -[saucelabs-matrix-image]: https://saucelabs.com/browser-matrix/snowplow.svg -[license-image]: http://img.shields.io/badge/license-simplified--bsd-blue.svg?style=flat +[saucelabs-button-image]: https://img.shields.io/static/v1?style=flat&label=Sauce%20Labs&message=Tested&color=e2231a&logo=sauce-labs +[saucelabs-matrix-image]: https://app.saucelabs.com/browser-matrix/snowplow.svg +[osi]: https://opensource.org/licenses/BSD-3-Clause +[license-image]: https://img.shields.io/npm/l/@snowplow/javascript-tracker +[tracker-classificiation]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/tracker-maintenance-classification/ +[actively-maintained]: https://img.shields.io/static/v1?style=flat&label=Snowplow&message=Actively%20Maintained&color=6638b8&labelColor=9ba0aa&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAeFBMVEVMaXGXANeYANeXANZbAJmXANeUANSQAM+XANeMAMpaAJhZAJeZANiXANaXANaOAM2WANVnAKWXANZ9ALtmAKVaAJmXANZaAJlXAJZdAJxaAJlZAJdbAJlbAJmQAM+UANKZANhhAJ+EAL+BAL9oAKZnAKVjAKF1ALNBd8J1AAAAKHRSTlMAa1hWXyteBTQJIEwRgUh2JjJon21wcBgNfmc+JlOBQjwezWF2l5dXzkW3/wAAAHpJREFUeNokhQOCA1EAxTL85hi7dXv/E5YPCYBq5DeN4pcqV1XbtW/xTVMIMAZE0cBHEaZhBmIQwCFofeprPUHqjmD/+7peztd62dWQRkvrQayXkn01f/gWp2CrxfjY7rcZ5V7DEMDQgmEozFpZqLUYDsNwOqbnMLwPAJEwCopZxKttAAAAAElFTkSuQmCC diff --git a/api-docs/.gitignore b/api-docs/.gitignore new file mode 100644 index 000000000..b2d6de306 --- /dev/null +++ b/api-docs/.gitignore @@ -0,0 +1,20 @@ +# Dependencies +/node_modules + +# Production +/build + +# Generated files +.docusaurus +.cache-loader + +# Misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/api-docs/babel.config.js b/api-docs/babel.config.js new file mode 100644 index 000000000..e00595dae --- /dev/null +++ b/api-docs/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: [require.resolve('@docusaurus/core/lib/babel/preset')], +}; diff --git a/api-docs/docs/browser-tracker/browser-tracker.api.md b/api-docs/docs/browser-tracker/browser-tracker.api.md new file mode 100644 index 000000000..00e3908cd --- /dev/null +++ b/api-docs/docs/browser-tracker/browser-tracker.api.md @@ -0,0 +1,614 @@ +## API Report File for "@snowplow/browser-tracker" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public +export type ActivityCallback = (data: ActivityCallbackData) => void; + +// @public +export type ActivityCallbackData = { + context: Array; + pageViewId: string; + minXOffset: number; + minYOffset: number; + maxXOffset: number; + maxYOffset: number; + activityMetrics?: ActivityMetrics; +}; + +// @public +export type ActivityMetrics = { + mouseDistance: number; + scrollDistance: number; + keyPresses: number; + clicks: number; + touches: number; +}; + +// @public +export interface ActivityTrackingConfiguration { + activityMetrics?: boolean; + heartbeatDelay: number; + minimumVisitLength: number; +} + +// @public +export interface ActivityTrackingConfigurationCallback { + callback: ActivityCallback; +} + +// @public +export function addGlobalContexts(contexts: Array | Record, trackers?: Array): void; + +// @public +export function addPlugin(configuration: BrowserPluginConfiguration, trackers?: Array): void; + +// @public (undocumented) +export type AnonymousTrackingOptions = boolean | { + withSessionTracking?: boolean; + withServerAnonymisation?: boolean; +}; + +// @public +export interface BrowserPlugin extends CorePlugin { + activateBrowserPlugin?: (tracker: BrowserTracker) => void; +} + +// @public +export interface BrowserPluginConfiguration extends CorePluginConfiguration { + /* The plugin to add */ + // (undocumented) + plugin: BrowserPlugin; +} + +// @public +export interface BrowserTracker { + addPlugin: (configuration: BrowserPluginConfiguration) => void; + clearUserData: (configuration?: ClearUserDataConfiguration) => void; + core: TrackerCore; + crossDomainLinker: (crossDomainLinkerCriterion: (elt: HTMLAnchorElement | HTMLAreaElement) => boolean) => void; + disableActivityTracking: () => void; + disableActivityTrackingCallback: () => void; + disableAnonymousTracking: (configuration?: DisableAnonymousTrackingConfiguration) => void; + discardBrace: (enableFilter: boolean) => void; + discardHashTag: (enableFilter: boolean) => void; + enableActivityTracking: (configuration: ActivityTrackingConfiguration) => void; + enableActivityTrackingCallback: (configuration: ActivityTrackingConfiguration & ActivityTrackingConfigurationCallback) => void; + enableAnonymousTracking: (configuration?: EnableAnonymousTrackingConfiguration) => void; + flushBuffer: (configuration?: FlushBufferConfiguration) => void; + getCookieName: (basename: string) => string; + getDomainSessionId: () => string; + getDomainSessionIndex: () => number; + getDomainUserId: () => string; + getDomainUserInfo: () => ParsedIdCookie; + getPageViewId: () => string; + getTabId: () => string | null; + getUserId: () => string | null | undefined; + id: string; + namespace: string; + newSession: () => void; + preservePageViewId: () => void; + preservePageViewIdForUrl: (preserve: PreservePageViewIdForUrl) => void; + setBufferSize: (newBufferSize: number) => void; + setCollectorUrl: (collectorUrl: string) => void; + setCookiePath: (path: string) => void; + setCustomUrl: (url: string) => void; + setDocumentTitle: (title: string) => void; + setOptOutCookie: (name?: string | null) => void; + setReferrerUrl: (url: string) => void; + setUserId: (userId?: string | null) => void; + setUserIdFromCookie: (cookieName: string) => void; + setUserIdFromLocation: (querystringField: string) => void; + setUserIdFromReferrer: (querystringField: string) => void; + setVisitorCookieTimeout: (timeout: number) => void; + sharedState: SharedState; + trackPageView: (event?: PageViewEvent & CommonEventProperties) => void; + updatePageActivity: () => void; +} + +// Warning: (ae-forgotten-export) The symbol "RequireAtLeastOne" needs to be exported by the entry point index.module.d.ts +// +// @public (undocumented) +export type BuiltInContexts = RequireAtLeastOne<{ + /* Toggles the web_page context */ + webPage: boolean; + /* Toggles the session context */ + session: boolean; + /* Toggles the browser context */ + browser: boolean; +}> | Record; + +// @public +export function clearGlobalContexts(trackers?: Array): void; + +// @public +export function clearUserData(configuration?: ClearUserDataConfiguration, trackers?: Array): void; + +// @public +export interface ClearUserDataConfiguration { + /* Store session information in memory for subsequent events */ + // (undocumented) + preserveSession: boolean; + /* Store user information in memory for subsequent events */ + // (undocumented) + preserveUser: boolean; +} + +// @public +export interface ClientSession extends Record { + eventIndex: number; + firstEventId: string | null; + firstEventTimestamp: string | null; + previousSessionId: string | null; + sessionId: string; + sessionIndex: number; + storageMechanism: string; + userId: string; +} + +// @public +export interface CommonEventProperties> { + context?: Array> | null; + timestamp?: Timestamp | null; +} + +// @public +export type ConditionalContextProvider = FilterProvider | RuleSetProvider; + +// @public +export interface ContextEvent { + event: Payload; + eventSchema: string; + eventType: string; +} + +// @public +export type ContextFilter = (args?: ContextEvent) => boolean; + +// @public +export type ContextGenerator = (args?: ContextEvent) => SelfDescribingJson | SelfDescribingJson[] | undefined; + +// @public +export type ContextPrimitive = SelfDescribingJson | ContextGenerator; + +// @public (undocumented) +export type CookieSameSite = "None" | "Lax" | "Strict"; + +// @public +export interface CorePlugin { + activateCorePlugin?: (core: TrackerCore) => void; + afterTrack?: (payload: Payload) => void; + beforeTrack?: (payloadBuilder: PayloadBuilder) => void; + contexts?: () => SelfDescribingJson[]; + deactivatePlugin?: (core: TrackerCore) => void; + filter?: (payload: Payload) => boolean; + logger?: (logger: Logger) => void; +} + +// @public +export interface CorePluginConfiguration { + /* The plugin to add */ + // (undocumented) + plugin: CorePlugin; +} + +// @public +export function crossDomainLinker(crossDomainLinkerCriterion: (elt: HTMLAnchorElement | HTMLAreaElement) => boolean, trackers?: Array): void; + +// @public +export interface DeviceTimestamp { + // (undocumented) + readonly type: "dtm"; + // (undocumented) + readonly value: number; +} + +// @public +export function disableActivityTracking(trackers?: Array): void; + +// @public +export function disableActivityTrackingCallback(trackers?: Array): void; + +// @public +export function disableAnonymousTracking(configuration?: DisableAnonymousTrackingConfiguration, trackers?: Array): void; + +// @public +export interface DisableAnonymousTrackingConfiguration { + /* Available configurations for different storage strategies */ + // (undocumented) + stateStorageStrategy?: StateStorageStrategy; +} + +// @public +export function discardBrace(enable: boolean, trackers?: Array): void; + +// @public +export function discardHashTag(enable: boolean, trackers?: Array): void; + +// @public (undocumented) +export interface EmitterConfigurationBase { + bufferSize?: number; + connectionTimeout?: number; + cookieExtensionService?: string; + credentials?: "omit" | "same-origin" | "include"; + customFetch?: (input: Request, options?: RequestInit) => Promise; + customHeaders?: Record; + dontRetryStatusCodes?: number[]; + eventMethod?: EventMethod; + eventStore?: EventStore; + // @deprecated (undocumented) + idService?: string; + keepalive?: boolean; + maxGetBytes?: number; + maxPostBytes?: number; + onRequestFailure?: (data: RequestFailure, response?: Response) => void; + onRequestSuccess?: (data: EventBatch, response: Response) => void; + postPath?: string; + retryFailedRequests?: boolean; + retryStatusCodes?: number[]; + useStm?: boolean; +} + +// @public +export function enableActivityTracking(configuration: ActivityTrackingConfiguration, trackers?: Array): void; + +// @public +export function enableActivityTrackingCallback(configuration: ActivityTrackingConfiguration & ActivityTrackingConfigurationCallback, trackers?: Array): void; + +// @public +export function enableAnonymousTracking(configuration?: EnableAnonymousTrackingConfiguration, trackers?: Array): void; + +// @public +export interface EnableAnonymousTrackingConfiguration { + /* Configuration for Anonymous Tracking */ + // (undocumented) + options?: AnonymousTrackingOptions; + /* Available configurations for different storage strategies */ + // (undocumented) + stateStorageStrategy?: StateStorageStrategy; +} + +// @public +export type EventBatch = Payload[]; + +// Warning: (ae-forgotten-export) The symbol "EventJsonWithKeys" needs to be exported by the entry point index.module.d.ts +// +// @public +export type EventJson = Array; + +// @public (undocumented) +export type EventMethod = "post" | "get"; + +// @public +export interface EventPayloadAndContext { + context: Array; + event: PayloadBuilder; +} + +// @public +export interface EventStore { + add: (payload: EventStorePayload) => Promise; + count: () => Promise; + getAll: () => Promise; + getAllPayloads: () => Promise; + iterator: () => EventStoreIterator; + removeHead: (count: number) => Promise; +} + +// @public (undocumented) +export interface EventStoreConfiguration { + maxSize?: number; +} + +// @public +export interface EventStoreIterator { + // Warning: (ae-forgotten-export) The symbol "EventStoreIteratorNextResult" needs to be exported by the entry point index.module.d.ts + next: () => Promise; +} + +// @public (undocumented) +export interface EventStorePayload { + payload: Payload; + svrAnon?: boolean; +} + +// @public (undocumented) +export type ExtendedCrossDomainLinkerAttributes = { + userId?: boolean; + sessionId?: boolean; + sourceId?: boolean; + sourcePlatform?: boolean; + reason?: boolean | ((evt: Event) => string); +}; + +// @public (undocumented) +export type ExtendedCrossDomainLinkerOptions = boolean | ExtendedCrossDomainLinkerAttributes; + +// @public +export type FilterProvider = [ +ContextFilter, +Array | ContextPrimitive +]; + +// @public +export function flushBuffer(configuration?: FlushBufferConfiguration, trackers?: Array): void; + +// @public +export interface FlushBufferConfiguration { + /* The size of the buffer after this flush */ + // (undocumented) + newBufferSize?: number; +} + +// @public +export function getDomainSessionId(trackerId?: string): string | undefined; + +// @public +export type JsonProcessor = (payloadBuilder: PayloadBuilder, jsonForProcessing: EventJson, contextEntitiesForProcessing: SelfDescribingJson[]) => void; + +// @public (undocumented) +export interface LocalStorageEventStoreConfigurationBase extends EventStoreConfiguration { + maxLocalStorageQueueSize?: number; + useLocalStorage?: boolean; +} + +// @public (undocumented) +export interface Logger { + // (undocumented) + debug: (message: string, ...extraParams: unknown[]) => void; + // (undocumented) + error: (message: string, error?: unknown, ...extraParams: unknown[]) => void; + // (undocumented) + info: (message: string, ...extraParams: unknown[]) => void; + // Warning: (ae-forgotten-export) The symbol "LOG_LEVEL" needs to be exported by the entry point index.module.d.ts + // + // (undocumented) + setLogLevel: (level: LOG_LEVEL) => void; + // (undocumented) + warn: (message: string, error?: unknown, ...extraParams: unknown[]) => void; +} + +// @public +export function newSession(trackers?: Array): void; + +// @public +export function newTracker(trackerId: string, endpoint: string, configuration?: TrackerConfiguration): BrowserTracker | null | undefined; + +// @public +export interface PageViewEvent { + contextCallback?: (() => Array) | null; + title?: string | null; +} + +// @public +export type ParsedIdCookie = [ +cookieDisabled: string, +domainUserId: string, +cookieCreateTs: number, +visitCount: number, +nowTs: number, +lastVisitTs: number | undefined, +sessionId: string, +previousSessionId: string, +firstEventId: string, +firstEventTs: number | undefined, +eventIndex: number +]; + +// @public +export type Payload = Record; + +// @public +export interface PayloadBuilder { + add: (key: string, value: unknown) => void; + addContextEntity: (entity: SelfDescribingJson) => void; + addDict: (dict: Payload) => void; + addJson: (keyIfEncoded: string, keyIfNotEncoded: string, json: Record) => void; + build: () => Payload; + getJson: () => EventJson; + getPayload: () => Payload; + withJsonProcessor: (jsonProcessor: JsonProcessor) => void; +} + +// @public (undocumented) +export type Platform = "web" | "mob" | "pc" | "srv" | "app" | "tv" | "cnsl" | "iot"; + +// @public +export function preservePageViewId(trackers?: Array): void; + +// @public (undocumented) +export type PreservePageViewIdForUrl = boolean | "full" | "pathname" | "pathnameAndSearch"; + +// @public +export function removeGlobalContexts(contexts: Array, trackers?: Array): void; + +// @public +export type RequestFailure = { + events: EventBatch; + status?: number; + message?: string; + willRetry: boolean; +}; + +// @public +export interface RuleSet { + // (undocumented) + accept?: Array | string; + // (undocumented) + reject?: Array | string; +} + +// @public +export type RuleSetProvider = [ +RuleSet, +Array | ContextPrimitive +]; + +// @public +export interface SelfDescribingEvent> { + event: SelfDescribingJson; +} + +// @public +export type SelfDescribingJson> = { + schema: string; + data: T extends any[] ? never : T extends {} ? T : never; +}; + +// @public +export function setBufferSize(newBufferSize: number, trackers?: Array): void; + +// @public +export function setCollectorUrl(collectorUrl: string, trackers?: Array): void; + +// @public +export function setCookiePath(path: string, trackers?: Array): void; + +// @public +export function setCustomUrl(url: string, trackers?: Array): void; + +// @public +export function setDocumentTitle(title: string, trackers?: Array): void; + +// @public +export function setOptOutCookie(name?: string | null, trackers?: Array): void; + +// @public +export function setReferrerUrl(url: string, trackers?: Array): void; + +// @public +export function setUserId(userId?: string | null, trackers?: Array): void; + +// @public +export function setUserIdFromCookie(cookieName: string, trackers?: Array): void; + +// @public +export function setUserIdFromLocation(querystringField: string, trackers?: Array): void; + +// @public +export function setUserIdFromReferrer(querystringField: string, trackers?: Array): void; + +// @public +export function setVisitorCookieTimeout(timeout: number, trackers?: Array): void; + +// @public +export class SharedState { + // (undocumented) + bufferFlushers: Array<(sync: boolean) => void>; + /* DOM Ready */ + // (undocumented) + hasLoaded: boolean; + /* DOM Ready */ + // (undocumented) + pageViewId?: string; + /* DOM Ready */ + // (undocumented) + pageViewUrl?: string; + /* DOM Ready */ + // (undocumented) + registeredOnLoadHandlers: Array<() => void>; +} + +// @public (undocumented) +export type StateStorageStrategy = "cookieAndLocalStorage" | "cookie" | "localStorage" | "none"; + +// @public +export interface StructuredEvent { + // (undocumented) + action: string; + // (undocumented) + category: string; + // (undocumented) + label?: string; + // (undocumented) + property?: string; + // (undocumented) + value?: number; +} + +// @public +export type Timestamp = TrueTimestamp | DeviceTimestamp | number; + +// @public +export type TrackerConfiguration = { + encodeBase64?: boolean; + cookieDomain?: string; + cookieName?: string; + cookieSameSite?: CookieSameSite; + cookieSecure?: boolean; + cookieLifetime?: number; + sessionCookieTimeout?: number; + appId?: string; + appVersion?: string; + platform?: Platform; + respectDoNotTrack?: boolean; + crossDomainLinker?: (elt: HTMLAnchorElement | HTMLAreaElement) => boolean; + useExtendedCrossDomainLinker?: ExtendedCrossDomainLinkerOptions; + discoverRootDomain?: boolean; + stateStorageStrategy?: StateStorageStrategy; + resetActivityTrackingOnPageView?: boolean; + anonymousTracking?: AnonymousTrackingOptions; + contexts?: BuiltInContexts; + plugins?: Array; + onSessionUpdateCallback?: (updatedSession: ClientSession) => void; + preservePageViewIdForUrl?: PreservePageViewIdForUrl; + preserveOriginalReferrer?: boolean; + synchronousCookieWrite?: boolean; + disableSessionContextWithinWebView?: boolean; +} & EmitterConfigurationBase & LocalStorageEventStoreConfigurationBase; + +// @public +export interface TrackerCore { + addGlobalContexts(contexts: Array | Record): void; + addPayloadDict(dict: Payload): void; + addPayloadPair: (key: string, value: unknown) => void; + addPlugin(configuration: CorePluginConfiguration): void; + clearGlobalContexts(): void; + deactivate(): void; + getBase64Encoding(): boolean; + removeGlobalContexts(contexts: Array): void; + resetPayloadPairs(dict: Payload): void; + setAppId(appId: string): void; + setBase64Encoding(encode: boolean): void; + setColorDepth(depth: string): void; + setIpAddress(ip: string): void; + setLang(lang: string): void; + setPlatform(value: string): void; + setScreenResolution(width: string, height: string): void; + setTimezone(timezone: string): void; + setTrackerNamespace(name: string): void; + setTrackerVersion(version: string): void; + setUseragent(useragent: string): void; + setUserId(userId: string): void; + setViewport(width: string, height: string): void; + track: (pb: PayloadBuilder, context?: Array | null, timestamp?: Timestamp | null) => Payload | undefined; +} + +// @public +export function trackPageView(event?: PageViewEvent & CommonEventProperties, trackers?: Array): void; + +// @public +export function trackSelfDescribingEvent>(event: SelfDescribingEvent & CommonEventProperties, trackers?: Array): void; + +// @public +export function trackStructEvent(event: StructuredEvent & CommonEventProperties, trackers?: Array): void; + +// @public +export interface TrueTimestamp { + // (undocumented) + readonly type: "ttm"; + // (undocumented) + readonly value: number; +} + +// @public +export function updatePageActivity(trackers?: Array): void; + +// @public (undocumented) +export const version: string; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.activitycallback.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.activitycallback.md new file mode 100644 index 000000000..08a749ed8 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.activitycallback.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ActivityCallback](./browser-tracker.activitycallback.md) + +## ActivityCallback type + +The callback for enableActivityTrackingCallback + +Signature: + +```typescript +type ActivityCallback = (data: ActivityCallbackData) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.activitycallbackdata.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.activitycallbackdata.md new file mode 100644 index 000000000..b146d8477 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.activitycallbackdata.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ActivityCallbackData](./browser-tracker.activitycallbackdata.md) + +## ActivityCallbackData type + +The data which is passed to the Activity Tracking callback + +Signature: + +```typescript +type ActivityCallbackData = { + context: Array; + pageViewId: string; + minXOffset: number; + minYOffset: number; + maxXOffset: number; + maxYOffset: number; + activityMetrics?: ActivityMetrics; +}; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.activitymetrics.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.activitymetrics.md new file mode 100644 index 000000000..6f461105c --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.activitymetrics.md @@ -0,0 +1,19 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ActivityMetrics](./browser-tracker.activitymetrics.md) + +## ActivityMetrics type + +Quantitative activity metrics accumulated between page pings. Attached as a context entity when activityMetrics is enabled. + +Signature: + +```typescript +type ActivityMetrics = { + mouseDistance: number; + scrollDistance: number; + keyPresses: number; + clicks: number; + touches: number; +}; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.activitytrackingconfiguration.activitymetrics.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.activitytrackingconfiguration.activitymetrics.md new file mode 100644 index 000000000..af2a96371 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.activitytrackingconfiguration.activitymetrics.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ActivityTrackingConfiguration](./browser-tracker.activitytrackingconfiguration.md) > [activityMetrics](./browser-tracker.activitytrackingconfiguration.activitymetrics.md) + +## ActivityTrackingConfiguration.activityMetrics property + +Enable activity metrics to attach an activity\_metrics entity to each page ping + +Signature: + +```typescript +activityMetrics?: boolean; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.activitytrackingconfiguration.heartbeatdelay.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.activitytrackingconfiguration.heartbeatdelay.md new file mode 100644 index 000000000..ca281d710 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.activitytrackingconfiguration.heartbeatdelay.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ActivityTrackingConfiguration](./browser-tracker.activitytrackingconfiguration.md) > [heartbeatDelay](./browser-tracker.activitytrackingconfiguration.heartbeatdelay.md) + +## ActivityTrackingConfiguration.heartbeatDelay property + +The interval at which the callback will be fired + +Signature: + +```typescript +heartbeatDelay: number; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.activitytrackingconfiguration.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.activitytrackingconfiguration.md new file mode 100644 index 000000000..cb4cf5be3 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.activitytrackingconfiguration.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ActivityTrackingConfiguration](./browser-tracker.activitytrackingconfiguration.md) + +## ActivityTrackingConfiguration interface + +The base configuration for activity tracking + +Signature: + +```typescript +interface ActivityTrackingConfiguration +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [activityMetrics?](./browser-tracker.activitytrackingconfiguration.activitymetrics.md) | boolean | (Optional) Enable activity metrics to attach an activity\_metrics entity to each page ping | +| [heartbeatDelay](./browser-tracker.activitytrackingconfiguration.heartbeatdelay.md) | number | The interval at which the callback will be fired | +| [minimumVisitLength](./browser-tracker.activitytrackingconfiguration.minimumvisitlength.md) | number | The minimum time that must have elapsed before first heartbeat | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.activitytrackingconfiguration.minimumvisitlength.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.activitytrackingconfiguration.minimumvisitlength.md new file mode 100644 index 000000000..b2fa6f03a --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.activitytrackingconfiguration.minimumvisitlength.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ActivityTrackingConfiguration](./browser-tracker.activitytrackingconfiguration.md) > [minimumVisitLength](./browser-tracker.activitytrackingconfiguration.minimumvisitlength.md) + +## ActivityTrackingConfiguration.minimumVisitLength property + +The minimum time that must have elapsed before first heartbeat + +Signature: + +```typescript +minimumVisitLength: number; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.activitytrackingconfigurationcallback.callback.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.activitytrackingconfigurationcallback.callback.md new file mode 100644 index 000000000..aa792752d --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.activitytrackingconfigurationcallback.callback.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ActivityTrackingConfigurationCallback](./browser-tracker.activitytrackingconfigurationcallback.md) > [callback](./browser-tracker.activitytrackingconfigurationcallback.callback.md) + +## ActivityTrackingConfigurationCallback.callback property + +The callback to fire based on heart beat + +Signature: + +```typescript +callback: ActivityCallback; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.activitytrackingconfigurationcallback.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.activitytrackingconfigurationcallback.md new file mode 100644 index 000000000..74558dc9e --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.activitytrackingconfigurationcallback.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ActivityTrackingConfigurationCallback](./browser-tracker.activitytrackingconfigurationcallback.md) + +## ActivityTrackingConfigurationCallback interface + +The callback for enableActivityTrackingCallback + +Signature: + +```typescript +interface ActivityTrackingConfigurationCallback +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [callback](./browser-tracker.activitytrackingconfigurationcallback.callback.md) | ActivityCallback | The callback to fire based on heart beat | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.addglobalcontexts.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.addglobalcontexts.md new file mode 100644 index 000000000..d77b7c3ae --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.addglobalcontexts.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [addGlobalContexts](./browser-tracker.addglobalcontexts.md) + +## addGlobalContexts() function + +All provided contexts will be sent with every event + +Signature: + +```typescript +declare function addGlobalContexts(contexts: Array | Record, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| contexts | Array<ConditionalContextProvider \| ContextPrimitive> \| Record<string, ConditionalContextProvider \| ContextPrimitive> | An array of contexts or conditional contexts | +| trackers | Array<string> | The tracker identifiers which the global contexts will be added to | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.addplugin.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.addplugin.md new file mode 100644 index 000000000..8f808e3e9 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.addplugin.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [addPlugin](./browser-tracker.addplugin.md) + +## addPlugin() function + +Add a plugin into the plugin collection after trackers have already been initialised + +Signature: + +```typescript +declare function addPlugin(configuration: BrowserPluginConfiguration, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| configuration | BrowserPluginConfiguration | The plugin to add | +| trackers | Array<string> | The tracker identifiers which the plugin will be added to | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.anonymoustrackingoptions.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.anonymoustrackingoptions.md new file mode 100644 index 000000000..a59581472 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.anonymoustrackingoptions.md @@ -0,0 +1,14 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [AnonymousTrackingOptions](./browser-tracker.anonymoustrackingoptions.md) + +## AnonymousTrackingOptions type + +Signature: + +```typescript +type AnonymousTrackingOptions = boolean | { + withSessionTracking?: boolean; + withServerAnonymisation?: boolean; +}; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browserplugin.activatebrowserplugin.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browserplugin.activatebrowserplugin.md new file mode 100644 index 000000000..f90d51a13 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browserplugin.activatebrowserplugin.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserPlugin](./browser-tracker.browserplugin.md) > [activateBrowserPlugin](./browser-tracker.browserplugin.activatebrowserplugin.md) + +## BrowserPlugin.activateBrowserPlugin property + +Called when the plugin is initialised during the Tracker construction + +Signature: + +```typescript +activateBrowserPlugin?: (tracker: BrowserTracker) => void; +``` + +## Remarks + +Use to capture the specific Tracker instance for each instance of a Browser Plugin + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browserplugin.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browserplugin.md new file mode 100644 index 000000000..6dcf88576 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browserplugin.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserPlugin](./browser-tracker.browserplugin.md) + +## BrowserPlugin interface + +Interface which defines Core Plugins + +Signature: + +```typescript +interface BrowserPlugin extends CorePlugin +``` +Extends: CorePlugin + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [activateBrowserPlugin?](./browser-tracker.browserplugin.activatebrowserplugin.md) | (tracker: BrowserTracker) => void | (Optional) Called when the plugin is initialised during the Tracker construction | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browserpluginconfiguration.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browserpluginconfiguration.md new file mode 100644 index 000000000..16f7248ca --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browserpluginconfiguration.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserPluginConfiguration](./browser-tracker.browserpluginconfiguration.md) + +## BrowserPluginConfiguration interface + +The configuration of the plugin to add + +Signature: + +```typescript +interface BrowserPluginConfiguration extends CorePluginConfiguration +``` +Extends: CorePluginConfiguration + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [plugin](./browser-tracker.browserpluginconfiguration.plugin.md) | BrowserPlugin | | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browserpluginconfiguration.plugin.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browserpluginconfiguration.plugin.md new file mode 100644 index 000000000..53cf2a197 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browserpluginconfiguration.plugin.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserPluginConfiguration](./browser-tracker.browserpluginconfiguration.md) > [plugin](./browser-tracker.browserpluginconfiguration.plugin.md) + +## BrowserPluginConfiguration.plugin property + +Signature: + +```typescript +plugin: BrowserPlugin; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.addplugin.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.addplugin.md new file mode 100644 index 000000000..0c7680250 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.addplugin.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [addPlugin](./browser-tracker.browsertracker.addplugin.md) + +## BrowserTracker.addPlugin property + +Add a plugin into the plugin collection after Tracker has already been initialised + +Signature: + +```typescript +addPlugin: (configuration: BrowserPluginConfiguration) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.clearuserdata.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.clearuserdata.md new file mode 100644 index 000000000..9dbf168ce --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.clearuserdata.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [clearUserData](./browser-tracker.browsertracker.clearuserdata.md) + +## BrowserTracker.clearUserData property + +Clears all cookies and local storage containing user and session identifiers + +Signature: + +```typescript +clearUserData: (configuration?: ClearUserDataConfiguration) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.core.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.core.md new file mode 100644 index 000000000..13f74346b --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.core.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [core](./browser-tracker.browsertracker.core.md) + +## BrowserTracker.core property + +The instance of the core library which this tracker has initialised + +Signature: + +```typescript +core: TrackerCore; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.crossdomainlinker.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.crossdomainlinker.md new file mode 100644 index 000000000..2789a65a9 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.crossdomainlinker.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [crossDomainLinker](./browser-tracker.browsertracker.crossdomainlinker.md) + +## BrowserTracker.crossDomainLinker property + +Enable querystring decoration for links passing a filter + +Signature: + +```typescript +crossDomainLinker: (crossDomainLinkerCriterion: (elt: HTMLAnchorElement | HTMLAreaElement) => boolean) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.disableactivitytracking.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.disableactivitytracking.md new file mode 100644 index 000000000..6b80aec01 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.disableactivitytracking.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [disableActivityTracking](./browser-tracker.browsertracker.disableactivitytracking.md) + +## BrowserTracker.disableActivityTracking property + +Disables page activity tracking. + +Signature: + +```typescript +disableActivityTracking: () => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.disableactivitytrackingcallback.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.disableactivitytrackingcallback.md new file mode 100644 index 000000000..056a79fb0 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.disableactivitytrackingcallback.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [disableActivityTrackingCallback](./browser-tracker.browsertracker.disableactivitytrackingcallback.md) + +## BrowserTracker.disableActivityTrackingCallback property + +Disables page activity tracking callback. + +Signature: + +```typescript +disableActivityTrackingCallback: () => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.disableanonymoustracking.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.disableanonymoustracking.md new file mode 100644 index 000000000..fa892743f --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.disableanonymoustracking.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [disableAnonymousTracking](./browser-tracker.browsertracker.disableanonymoustracking.md) + +## BrowserTracker.disableAnonymousTracking property + +Disables anonymous tracking if active (ie. tracker initialized with `anonymousTracking`) For stateStorageStrategy override, uses supplied value first, falls back to one defined in initial config, otherwise uses cookieAndLocalStorage. + +Signature: + +```typescript +disableAnonymousTracking: (configuration?: DisableAnonymousTrackingConfiguration) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.discardbrace.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.discardbrace.md new file mode 100644 index 000000000..8e56cf4a2 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.discardbrace.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [discardBrace](./browser-tracker.browsertracker.discardbrace.md) + +## BrowserTracker.discardBrace property + +Strip braces from URL + +Signature: + +```typescript +discardBrace: (enableFilter: boolean) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.discardhashtag.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.discardhashtag.md new file mode 100644 index 000000000..ee558bc81 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.discardhashtag.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [discardHashTag](./browser-tracker.browsertracker.discardhashtag.md) + +## BrowserTracker.discardHashTag property + +Strip hash tag (or anchor) from URL + +Signature: + +```typescript +discardHashTag: (enableFilter: boolean) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.enableactivitytracking.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.enableactivitytracking.md new file mode 100644 index 000000000..4ab54b6f7 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.enableactivitytracking.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [enableActivityTracking](./browser-tracker.browsertracker.enableactivitytracking.md) + +## BrowserTracker.enableActivityTracking property + +Enables page activity tracking (sends page pings to the Collector regularly). + +Signature: + +```typescript +enableActivityTracking: (configuration: ActivityTrackingConfiguration) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.enableactivitytrackingcallback.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.enableactivitytrackingcallback.md new file mode 100644 index 000000000..ae737e9c3 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.enableactivitytrackingcallback.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [enableActivityTrackingCallback](./browser-tracker.browsertracker.enableactivitytrackingcallback.md) + +## BrowserTracker.enableActivityTrackingCallback property + +Enables page activity tracking (replaces collector ping with callback). + +Signature: + +```typescript +enableActivityTrackingCallback: (configuration: ActivityTrackingConfiguration & ActivityTrackingConfigurationCallback) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.enableanonymoustracking.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.enableanonymoustracking.md new file mode 100644 index 000000000..0a0f8d972 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.enableanonymoustracking.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [enableAnonymousTracking](./browser-tracker.browsertracker.enableanonymoustracking.md) + +## BrowserTracker.enableAnonymousTracking property + +Enables anonymous tracking (ie. tracker initialized without `anonymousTracking`) + +Signature: + +```typescript +enableAnonymousTracking: (configuration?: EnableAnonymousTrackingConfiguration) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.flushbuffer.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.flushbuffer.md new file mode 100644 index 000000000..480e8ad3a --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.flushbuffer.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [flushBuffer](./browser-tracker.browsertracker.flushbuffer.md) + +## BrowserTracker.flushBuffer property + +Send all events in the outQueue Only need to use this when sending events with a bufferSize of at least 2 + +Signature: + +```typescript +flushBuffer: (configuration?: FlushBufferConfiguration) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.getcookiename.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.getcookiename.md new file mode 100644 index 000000000..a7fc42852 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.getcookiename.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [getCookieName](./browser-tracker.browsertracker.getcookiename.md) + +## BrowserTracker.getCookieName property + +Get the cookie name as cookieNamePrefix + basename + . + domain. + +Signature: + +```typescript +getCookieName: (basename: string) => string; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.getdomainsessionid.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.getdomainsessionid.md new file mode 100644 index 000000000..0ba75df76 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.getdomainsessionid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [getDomainSessionId](./browser-tracker.browsertracker.getdomainsessionid.md) + +## BrowserTracker.getDomainSessionId property + +Get the current domain session ID (from first party cookie) + +Signature: + +```typescript +getDomainSessionId: () => string; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.getdomainsessionindex.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.getdomainsessionindex.md new file mode 100644 index 000000000..da89d162b --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.getdomainsessionindex.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [getDomainSessionIndex](./browser-tracker.browsertracker.getdomainsessionindex.md) + +## BrowserTracker.getDomainSessionIndex property + +Get the domain session index also known as current memorized visit count. + +Signature: + +```typescript +getDomainSessionIndex: () => number; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.getdomainuserid.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.getdomainuserid.md new file mode 100644 index 000000000..e5f63239f --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.getdomainuserid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [getDomainUserId](./browser-tracker.browsertracker.getdomainuserid.md) + +## BrowserTracker.getDomainUserId property + +Get visitor ID (from first party cookie) + +Signature: + +```typescript +getDomainUserId: () => string; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.getdomainuserinfo.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.getdomainuserinfo.md new file mode 100644 index 000000000..2b2830b3a --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.getdomainuserinfo.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [getDomainUserInfo](./browser-tracker.browsertracker.getdomainuserinfo.md) + +## BrowserTracker.getDomainUserInfo property + +Get the visitor information (from first party cookie) + +Signature: + +```typescript +getDomainUserInfo: () => ParsedIdCookie; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.getpageviewid.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.getpageviewid.md new file mode 100644 index 000000000..025419897 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.getpageviewid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [getPageViewId](./browser-tracker.browsertracker.getpageviewid.md) + +## BrowserTracker.getPageViewId property + +Get the current page view ID + +Signature: + +```typescript +getPageViewId: () => string; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.gettabid.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.gettabid.md new file mode 100644 index 000000000..07addefcc --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.gettabid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [getTabId](./browser-tracker.browsertracker.gettabid.md) + +## BrowserTracker.getTabId property + +Get the current browser tab ID + +Signature: + +```typescript +getTabId: () => string | null; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.getuserid.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.getuserid.md new file mode 100644 index 000000000..768528327 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.getuserid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [getUserId](./browser-tracker.browsertracker.getuserid.md) + +## BrowserTracker.getUserId property + +Get the current user ID (as set previously with setUserId()). + +Signature: + +```typescript +getUserId: () => string | null | undefined; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.id.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.id.md new file mode 100644 index 000000000..a4ae7f5c4 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.id.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [id](./browser-tracker.browsertracker.id.md) + +## BrowserTracker.id property + +The unique identifier of this tracker + +Signature: + +```typescript +id: string; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.md new file mode 100644 index 000000000..a08c031d1 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.md @@ -0,0 +1,60 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) + +## BrowserTracker interface + +The Browser Tracker + +Signature: + +```typescript +interface BrowserTracker +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [addPlugin](./browser-tracker.browsertracker.addplugin.md) | (configuration: BrowserPluginConfiguration) => void | Add a plugin into the plugin collection after Tracker has already been initialised | +| [clearUserData](./browser-tracker.browsertracker.clearuserdata.md) | (configuration?: ClearUserDataConfiguration) => void | Clears all cookies and local storage containing user and session identifiers | +| [core](./browser-tracker.browsertracker.core.md) | TrackerCore | The instance of the core library which this tracker has initialised | +| [crossDomainLinker](./browser-tracker.browsertracker.crossdomainlinker.md) | (crossDomainLinkerCriterion: (elt: HTMLAnchorElement \| HTMLAreaElement) => boolean) => void | Enable querystring decoration for links passing a filter | +| [disableActivityTracking](./browser-tracker.browsertracker.disableactivitytracking.md) | () => void | Disables page activity tracking. | +| [disableActivityTrackingCallback](./browser-tracker.browsertracker.disableactivitytrackingcallback.md) | () => void | Disables page activity tracking callback. | +| [disableAnonymousTracking](./browser-tracker.browsertracker.disableanonymoustracking.md) | (configuration?: DisableAnonymousTrackingConfiguration) => void | Disables anonymous tracking if active (ie. tracker initialized with anonymousTracking) For stateStorageStrategy override, uses supplied value first, falls back to one defined in initial config, otherwise uses cookieAndLocalStorage. | +| [discardBrace](./browser-tracker.browsertracker.discardbrace.md) | (enableFilter: boolean) => void | Strip braces from URL | +| [discardHashTag](./browser-tracker.browsertracker.discardhashtag.md) | (enableFilter: boolean) => void | Strip hash tag (or anchor) from URL | +| [enableActivityTracking](./browser-tracker.browsertracker.enableactivitytracking.md) | (configuration: ActivityTrackingConfiguration) => void | Enables page activity tracking (sends page pings to the Collector regularly). | +| [enableActivityTrackingCallback](./browser-tracker.browsertracker.enableactivitytrackingcallback.md) | (configuration: ActivityTrackingConfiguration & ActivityTrackingConfigurationCallback) => void | Enables page activity tracking (replaces collector ping with callback). | +| [enableAnonymousTracking](./browser-tracker.browsertracker.enableanonymoustracking.md) | (configuration?: EnableAnonymousTrackingConfiguration) => void | Enables anonymous tracking (ie. tracker initialized without anonymousTracking) | +| [flushBuffer](./browser-tracker.browsertracker.flushbuffer.md) | (configuration?: FlushBufferConfiguration) => void | Send all events in the outQueue Only need to use this when sending events with a bufferSize of at least 2 | +| [getCookieName](./browser-tracker.browsertracker.getcookiename.md) | (basename: string) => string | Get the cookie name as cookieNamePrefix + basename + . + domain. | +| [getDomainSessionId](./browser-tracker.browsertracker.getdomainsessionid.md) | () => string | Get the current domain session ID (from first party cookie) | +| [getDomainSessionIndex](./browser-tracker.browsertracker.getdomainsessionindex.md) | () => number | Get the domain session index also known as current memorized visit count. | +| [getDomainUserId](./browser-tracker.browsertracker.getdomainuserid.md) | () => string | Get visitor ID (from first party cookie) | +| [getDomainUserInfo](./browser-tracker.browsertracker.getdomainuserinfo.md) | () => ParsedIdCookie | Get the visitor information (from first party cookie) | +| [getPageViewId](./browser-tracker.browsertracker.getpageviewid.md) | () => string | Get the current page view ID | +| [getTabId](./browser-tracker.browsertracker.gettabid.md) | () => string \| null | Get the current browser tab ID | +| [getUserId](./browser-tracker.browsertracker.getuserid.md) | () => string \| null \| undefined | Get the current user ID (as set previously with setUserId()). | +| [id](./browser-tracker.browsertracker.id.md) | string | The unique identifier of this tracker | +| [namespace](./browser-tracker.browsertracker.namespace.md) | string | The tracker namespace | +| [newSession](./browser-tracker.browsertracker.newsession.md) | () => void | Expires current session and starts a new session. | +| [preservePageViewId](./browser-tracker.browsertracker.preservepageviewid.md) | () => void | Stop regenerating pageViewId (available from web_page context) | +| [preservePageViewIdForUrl](./browser-tracker.browsertracker.preservepageviewidforurl.md) | (preserve: PreservePageViewIdForUrl) => void | Decide how the pageViewId should be preserved based on the URL. If set to false, the pageViewId will be regenerated on the second and each following page view event (first page view doesn't change the page view ID since tracker initialization). If set to true or 'full', the pageViewId will be kept the same for all page views with that exact URL (even for events tracked before the page view event). If set to 'pathname', the pageViewId will be kept the same for all page views with the same pathname (search params or fragment may change). If set to 'pathnameAndSearch', the pageViewId will be kept the same for all page views with the same pathname and search params (fragment may change). If preservePageViewId is enabled, the preservePageViewIdForUrl setting is ignored. Defaults to false. | +| [setBufferSize](./browser-tracker.browsertracker.setbuffersize.md) | (newBufferSize: number) => void | Alter buffer size Can be useful if you want to stop batching requests to ensure events start sending closer to event creation | +| [setCollectorUrl](./browser-tracker.browsertracker.setcollectorurl.md) | (collectorUrl: string) => void | Specify the Snowplow collector URL. Specific http or https to force it or leave it off to match the website protocol. | +| [setCookiePath](./browser-tracker.browsertracker.setcookiepath.md) | (path: string) => void | Set first-party cookie path | +| [setCustomUrl](./browser-tracker.browsertracker.setcustomurl.md) | (url: string) => void | Override url | +| [setDocumentTitle](./browser-tracker.browsertracker.setdocumenttitle.md) | (title: string) => void | Override document.title | +| [setOptOutCookie](./browser-tracker.browsertracker.setoptoutcookie.md) | (name?: string \| null) => void | Sets the opt out cookie. | +| [setReferrerUrl](./browser-tracker.browsertracker.setreferrerurl.md) | (url: string) => void | Override referrer | +| [setUserId](./browser-tracker.browsertracker.setuserid.md) | (userId?: string \| null) => void | Set the business-defined user ID for this user. | +| [setUserIdFromCookie](./browser-tracker.browsertracker.setuseridfromcookie.md) | (cookieName: string) => void | Set the business-defined user ID for this user to the value of a cookie. | +| [setUserIdFromLocation](./browser-tracker.browsertracker.setuseridfromlocation.md) | (querystringField: string) => void | Set the business-defined user ID for this user using the location querystring. | +| [setUserIdFromReferrer](./browser-tracker.browsertracker.setuseridfromreferrer.md) | (querystringField: string) => void | Set the business-defined user ID for this user using the referrer querystring. | +| [setVisitorCookieTimeout](./browser-tracker.browsertracker.setvisitorcookietimeout.md) | (timeout: number) => void | Set visitor cookie timeout (in seconds) | +| [sharedState](./browser-tracker.browsertracker.sharedstate.md) | SharedState | The instance of shared state this tracker is using | +| [trackPageView](./browser-tracker.browsertracker.trackpageview.md) | (event?: PageViewEvent & CommonEventProperties) => void | Log visit to this page | +| [updatePageActivity](./browser-tracker.browsertracker.updatepageactivity.md) | () => void | Triggers the activityHandler manually to allow external user defined activity. i.e. While watching a video | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.namespace.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.namespace.md new file mode 100644 index 000000000..54b45ae81 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.namespace.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [namespace](./browser-tracker.browsertracker.namespace.md) + +## BrowserTracker.namespace property + +The tracker namespace + +Signature: + +```typescript +namespace: string; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.newsession.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.newsession.md new file mode 100644 index 000000000..21b3cf171 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.newsession.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [newSession](./browser-tracker.browsertracker.newsession.md) + +## BrowserTracker.newSession property + +Expires current session and starts a new session. + +Signature: + +```typescript +newSession: () => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.preservepageviewid.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.preservepageviewid.md new file mode 100644 index 000000000..9a27e24c2 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.preservepageviewid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [preservePageViewId](./browser-tracker.browsertracker.preservepageviewid.md) + +## BrowserTracker.preservePageViewId property + +Stop regenerating `pageViewId` (available from `web_page` context) + +Signature: + +```typescript +preservePageViewId: () => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.preservepageviewidforurl.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.preservepageviewidforurl.md new file mode 100644 index 000000000..701b238b7 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.preservepageviewidforurl.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [preservePageViewIdForUrl](./browser-tracker.browsertracker.preservepageviewidforurl.md) + +## BrowserTracker.preservePageViewIdForUrl property + +Decide how the `pageViewId` should be preserved based on the URL. If set to `false`, the `pageViewId` will be regenerated on the second and each following page view event (first page view doesn't change the page view ID since tracker initialization). If set to `true` or `'full'`, the `pageViewId` will be kept the same for all page views with that exact URL (even for events tracked before the page view event). If set to `'pathname'`, the `pageViewId` will be kept the same for all page views with the same pathname (search params or fragment may change). If set to `'pathnameAndSearch'`, the `pageViewId` will be kept the same for all page views with the same pathname and search params (fragment may change). If `preservePageViewId` is enabled, the `preservePageViewIdForUrl` setting is ignored. Defaults to `false`. + +Signature: + +```typescript +preservePageViewIdForUrl: (preserve: PreservePageViewIdForUrl) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setbuffersize.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setbuffersize.md new file mode 100644 index 000000000..abdf8e516 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setbuffersize.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [setBufferSize](./browser-tracker.browsertracker.setbuffersize.md) + +## BrowserTracker.setBufferSize property + +Alter buffer size Can be useful if you want to stop batching requests to ensure events start sending closer to event creation + +Signature: + +```typescript +setBufferSize: (newBufferSize: number) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setcollectorurl.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setcollectorurl.md new file mode 100644 index 000000000..9b650e49c --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setcollectorurl.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [setCollectorUrl](./browser-tracker.browsertracker.setcollectorurl.md) + +## BrowserTracker.setCollectorUrl property + +Specify the Snowplow collector URL. Specific http or https to force it or leave it off to match the website protocol. + +Signature: + +```typescript +setCollectorUrl: (collectorUrl: string) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setcookiepath.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setcookiepath.md new file mode 100644 index 000000000..6a3c800f7 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setcookiepath.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [setCookiePath](./browser-tracker.browsertracker.setcookiepath.md) + +## BrowserTracker.setCookiePath property + +Set first-party cookie path + +Signature: + +```typescript +setCookiePath: (path: string) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setcustomurl.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setcustomurl.md new file mode 100644 index 000000000..f478f0fa9 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setcustomurl.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [setCustomUrl](./browser-tracker.browsertracker.setcustomurl.md) + +## BrowserTracker.setCustomUrl property + +Override url + +Signature: + +```typescript +setCustomUrl: (url: string) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setdocumenttitle.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setdocumenttitle.md new file mode 100644 index 000000000..9b6b5e2f7 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setdocumenttitle.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [setDocumentTitle](./browser-tracker.browsertracker.setdocumenttitle.md) + +## BrowserTracker.setDocumentTitle property + +Override document.title + +Signature: + +```typescript +setDocumentTitle: (title: string) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setoptoutcookie.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setoptoutcookie.md new file mode 100644 index 000000000..fba5b9aa6 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setoptoutcookie.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [setOptOutCookie](./browser-tracker.browsertracker.setoptoutcookie.md) + +## BrowserTracker.setOptOutCookie property + +Sets the opt out cookie. + +Signature: + +```typescript +setOptOutCookie: (name?: string | null) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setreferrerurl.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setreferrerurl.md new file mode 100644 index 000000000..6b2b06958 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setreferrerurl.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [setReferrerUrl](./browser-tracker.browsertracker.setreferrerurl.md) + +## BrowserTracker.setReferrerUrl property + +Override referrer + +Signature: + +```typescript +setReferrerUrl: (url: string) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setuserid.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setuserid.md new file mode 100644 index 000000000..020656273 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setuserid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [setUserId](./browser-tracker.browsertracker.setuserid.md) + +## BrowserTracker.setUserId property + +Set the business-defined user ID for this user. + +Signature: + +```typescript +setUserId: (userId?: string | null) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setuseridfromcookie.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setuseridfromcookie.md new file mode 100644 index 000000000..09d2bab52 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setuseridfromcookie.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [setUserIdFromCookie](./browser-tracker.browsertracker.setuseridfromcookie.md) + +## BrowserTracker.setUserIdFromCookie property + +Set the business-defined user ID for this user to the value of a cookie. + +Signature: + +```typescript +setUserIdFromCookie: (cookieName: string) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setuseridfromlocation.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setuseridfromlocation.md new file mode 100644 index 000000000..780ba562c --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setuseridfromlocation.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [setUserIdFromLocation](./browser-tracker.browsertracker.setuseridfromlocation.md) + +## BrowserTracker.setUserIdFromLocation property + +Set the business-defined user ID for this user using the location querystring. + +Signature: + +```typescript +setUserIdFromLocation: (querystringField: string) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setuseridfromreferrer.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setuseridfromreferrer.md new file mode 100644 index 000000000..ed720b6ba --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setuseridfromreferrer.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [setUserIdFromReferrer](./browser-tracker.browsertracker.setuseridfromreferrer.md) + +## BrowserTracker.setUserIdFromReferrer property + +Set the business-defined user ID for this user using the referrer querystring. + +Signature: + +```typescript +setUserIdFromReferrer: (querystringField: string) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setvisitorcookietimeout.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setvisitorcookietimeout.md new file mode 100644 index 000000000..f0f513cb4 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.setvisitorcookietimeout.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [setVisitorCookieTimeout](./browser-tracker.browsertracker.setvisitorcookietimeout.md) + +## BrowserTracker.setVisitorCookieTimeout property + +Set visitor cookie timeout (in seconds) + +Signature: + +```typescript +setVisitorCookieTimeout: (timeout: number) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.sharedstate.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.sharedstate.md new file mode 100644 index 000000000..b5d9a9cf6 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.sharedstate.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [sharedState](./browser-tracker.browsertracker.sharedstate.md) + +## BrowserTracker.sharedState property + +The instance of shared state this tracker is using + +Signature: + +```typescript +sharedState: SharedState; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.trackpageview.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.trackpageview.md new file mode 100644 index 000000000..eab57ea67 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.trackpageview.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [trackPageView](./browser-tracker.browsertracker.trackpageview.md) + +## BrowserTracker.trackPageView property + +Log visit to this page + +Signature: + +```typescript +trackPageView: (event?: PageViewEvent & CommonEventProperties) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.updatepageactivity.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.updatepageactivity.md new file mode 100644 index 000000000..daf44f828 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.browsertracker.updatepageactivity.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BrowserTracker](./browser-tracker.browsertracker.md) > [updatePageActivity](./browser-tracker.browsertracker.updatepageactivity.md) + +## BrowserTracker.updatePageActivity property + +Triggers the activityHandler manually to allow external user defined activity. i.e. While watching a video + +Signature: + +```typescript +updatePageActivity: () => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.builtincontexts.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.builtincontexts.md new file mode 100644 index 000000000..2d59a6c8b --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.builtincontexts.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [BuiltInContexts](./browser-tracker.builtincontexts.md) + +## BuiltInContexts type + +Signature: + +```typescript +type BuiltInContexts = RequireAtLeastOne<{ + /* Toggles the web_page context */ + webPage: boolean; + /* Toggles the session context */ + session: boolean; + /* Toggles the browser context */ + browser: boolean; +}> | Record; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.clearglobalcontexts.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.clearglobalcontexts.md new file mode 100644 index 000000000..350d12d8f --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.clearglobalcontexts.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [clearGlobalContexts](./browser-tracker.clearglobalcontexts.md) + +## clearGlobalContexts() function + +Clear all global contexts that are sent with events + +Signature: + +```typescript +declare function clearGlobalContexts(trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| trackers | Array<string> | The tracker identifiers which the global contexts will be cleared from | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.clearuserdata.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.clearuserdata.md new file mode 100644 index 000000000..940d63735 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.clearuserdata.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [clearUserData](./browser-tracker.clearuserdata.md) + +## clearUserData() function + +Clears all cookies and local storage containing user and session identifiers + +Signature: + +```typescript +declare function clearUserData(configuration?: ClearUserDataConfiguration, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| configuration | ClearUserDataConfiguration | | +| trackers | Array<string> | The tracker identifiers which the event will be sent to | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.clearuserdataconfiguration.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.clearuserdataconfiguration.md new file mode 100644 index 000000000..8a8663c61 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.clearuserdataconfiguration.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ClearUserDataConfiguration](./browser-tracker.clearuserdataconfiguration.md) + +## ClearUserDataConfiguration interface + +The configuration that can be changed when enabling anonymous tracking + +Signature: + +```typescript +interface ClearUserDataConfiguration +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [preserveSession](./browser-tracker.clearuserdataconfiguration.preservesession.md) | boolean | | +| [preserveUser](./browser-tracker.clearuserdataconfiguration.preserveuser.md) | boolean | | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.clearuserdataconfiguration.preservesession.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.clearuserdataconfiguration.preservesession.md new file mode 100644 index 000000000..ab798699d --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.clearuserdataconfiguration.preservesession.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ClearUserDataConfiguration](./browser-tracker.clearuserdataconfiguration.md) > [preserveSession](./browser-tracker.clearuserdataconfiguration.preservesession.md) + +## ClearUserDataConfiguration.preserveSession property + +Signature: + +```typescript +preserveSession: boolean; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.clearuserdataconfiguration.preserveuser.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.clearuserdataconfiguration.preserveuser.md new file mode 100644 index 000000000..0920602b2 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.clearuserdataconfiguration.preserveuser.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ClearUserDataConfiguration](./browser-tracker.clearuserdataconfiguration.md) > [preserveUser](./browser-tracker.clearuserdataconfiguration.preserveuser.md) + +## ClearUserDataConfiguration.preserveUser property + +Signature: + +```typescript +preserveUser: boolean; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.eventindex.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.eventindex.md new file mode 100644 index 000000000..e2e336de3 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.eventindex.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ClientSession](./browser-tracker.clientsession.md) > [eventIndex](./browser-tracker.clientsession.eventindex.md) + +## ClientSession.eventIndex property + +Index of the current event in the session + +Signature: + +```typescript +eventIndex: number; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.firsteventid.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.firsteventid.md new file mode 100644 index 000000000..8c34c93c2 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.firsteventid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ClientSession](./browser-tracker.clientsession.md) > [firstEventId](./browser-tracker.clientsession.firsteventid.md) + +## ClientSession.firstEventId property + +Identifier of the first event for this session + +Signature: + +```typescript +firstEventId: string | null; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.firsteventtimestamp.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.firsteventtimestamp.md new file mode 100644 index 000000000..78c6ad599 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.firsteventtimestamp.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ClientSession](./browser-tracker.clientsession.md) > [firstEventTimestamp](./browser-tracker.clientsession.firsteventtimestamp.md) + +## ClientSession.firstEventTimestamp property + +Date-time timestamp of when the first event in the session was tracked + +Signature: + +```typescript +firstEventTimestamp: string | null; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.md new file mode 100644 index 000000000..bbec2182b --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.md @@ -0,0 +1,28 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ClientSession](./browser-tracker.clientsession.md) + +## ClientSession interface + +Schema for client client session context entity + +Signature: + +```typescript +interface ClientSession extends Record +``` +Extends: Record<string, unknown> + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [eventIndex](./browser-tracker.clientsession.eventindex.md) | number | Index of the current event in the session | +| [firstEventId](./browser-tracker.clientsession.firsteventid.md) | string \| null | Identifier of the first event for this session | +| [firstEventTimestamp](./browser-tracker.clientsession.firsteventtimestamp.md) | string \| null | Date-time timestamp of when the first event in the session was tracked | +| [previousSessionId](./browser-tracker.clientsession.previoussessionid.md) | string \| null | The previous session identifier for this user | +| [sessionId](./browser-tracker.clientsession.sessionid.md) | string | An identifier for the session (same as domain\_sessionid) | +| [sessionIndex](./browser-tracker.clientsession.sessionindex.md) | number | The index of the current session for this user (same as domain\_sessionidx) | +| [storageMechanism](./browser-tracker.clientsession.storagemechanism.md) | string | The mechanism that the session information has been stored on the device | +| [userId](./browser-tracker.clientsession.userid.md) | string | An identifier for the user of the session (same as domain\_userid) | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.previoussessionid.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.previoussessionid.md new file mode 100644 index 000000000..594b71530 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.previoussessionid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ClientSession](./browser-tracker.clientsession.md) > [previousSessionId](./browser-tracker.clientsession.previoussessionid.md) + +## ClientSession.previousSessionId property + +The previous session identifier for this user + +Signature: + +```typescript +previousSessionId: string | null; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.sessionid.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.sessionid.md new file mode 100644 index 000000000..51707d88d --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.sessionid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ClientSession](./browser-tracker.clientsession.md) > [sessionId](./browser-tracker.clientsession.sessionid.md) + +## ClientSession.sessionId property + +An identifier for the session (same as domain\_sessionid) + +Signature: + +```typescript +sessionId: string; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.sessionindex.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.sessionindex.md new file mode 100644 index 000000000..cc40d5458 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.sessionindex.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ClientSession](./browser-tracker.clientsession.md) > [sessionIndex](./browser-tracker.clientsession.sessionindex.md) + +## ClientSession.sessionIndex property + +The index of the current session for this user (same as domain\_sessionidx) + +Signature: + +```typescript +sessionIndex: number; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.storagemechanism.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.storagemechanism.md new file mode 100644 index 000000000..5dfd14eaa --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.storagemechanism.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ClientSession](./browser-tracker.clientsession.md) > [storageMechanism](./browser-tracker.clientsession.storagemechanism.md) + +## ClientSession.storageMechanism property + +The mechanism that the session information has been stored on the device + +Signature: + +```typescript +storageMechanism: string; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.userid.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.userid.md new file mode 100644 index 000000000..3df2405e0 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.clientsession.userid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ClientSession](./browser-tracker.clientsession.md) > [userId](./browser-tracker.clientsession.userid.md) + +## ClientSession.userId property + +An identifier for the user of the session (same as domain\_userid) + +Signature: + +```typescript +userId: string; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.commoneventproperties.context.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.commoneventproperties.context.md new file mode 100644 index 000000000..22877ecc2 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.commoneventproperties.context.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [CommonEventProperties](./browser-tracker.commoneventproperties.md) > [context](./browser-tracker.commoneventproperties.context.md) + +## CommonEventProperties.context property + +Add context to an event by setting an Array of Self Describing JSON + +Signature: + +```typescript +context?: Array> | null; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.commoneventproperties.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.commoneventproperties.md new file mode 100644 index 000000000..491fd5645 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.commoneventproperties.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [CommonEventProperties](./browser-tracker.commoneventproperties.md) + +## CommonEventProperties interface + +Additional data points to set when tracking an event + +Signature: + +```typescript +interface CommonEventProperties> +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [context?](./browser-tracker.commoneventproperties.context.md) | Array<SelfDescribingJson<T>> \| null | (Optional) Add context to an event by setting an Array of Self Describing JSON | +| [timestamp?](./browser-tracker.commoneventproperties.timestamp.md) | Timestamp \| null | (Optional) Set the true timestamp or overwrite the device sent timestamp on an event | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.commoneventproperties.timestamp.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.commoneventproperties.timestamp.md new file mode 100644 index 000000000..083fec1a5 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.commoneventproperties.timestamp.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [CommonEventProperties](./browser-tracker.commoneventproperties.md) > [timestamp](./browser-tracker.commoneventproperties.timestamp.md) + +## CommonEventProperties.timestamp property + +Set the true timestamp or overwrite the device sent timestamp on an event + +Signature: + +```typescript +timestamp?: Timestamp | null; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.conditionalcontextprovider.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.conditionalcontextprovider.md new file mode 100644 index 000000000..daa9c8f2f --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.conditionalcontextprovider.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ConditionalContextProvider](./browser-tracker.conditionalcontextprovider.md) + +## ConditionalContextProvider type + +Conditional context providers are two element arrays used to decide when to attach contexts, where: - the first element is some conditional criterion - the second element is any number of context primitives + +Signature: + +```typescript +type ConditionalContextProvider = FilterProvider | RuleSetProvider; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.contextevent.event.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.contextevent.event.md new file mode 100644 index 000000000..15e2fb795 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.contextevent.event.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ContextEvent](./browser-tracker.contextevent.md) > [event](./browser-tracker.contextevent.event.md) + +## ContextEvent.event property + +The event payload + +Signature: + +```typescript +event: Payload; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.contextevent.eventschema.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.contextevent.eventschema.md new file mode 100644 index 000000000..5538afb51 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.contextevent.eventschema.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ContextEvent](./browser-tracker.contextevent.md) > [eventSchema](./browser-tracker.contextevent.eventschema.md) + +## ContextEvent.eventSchema property + +The event schema where one is available, or empty string + +Signature: + +```typescript +eventSchema: string; +``` + +## Example + +'iglu:com.snowplowanalytics.snowplow/ad\_impression/jsonschema/1-0-0' + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.contextevent.eventtype.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.contextevent.eventtype.md new file mode 100644 index 000000000..bffc498d3 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.contextevent.eventtype.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ContextEvent](./browser-tracker.contextevent.md) > [eventType](./browser-tracker.contextevent.eventtype.md) + +## ContextEvent.eventType property + +The event type + +Signature: + +```typescript +eventType: string; +``` + +## Example + +'page\_view' + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.contextevent.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.contextevent.md new file mode 100644 index 000000000..48f7d228d --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.contextevent.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ContextEvent](./browser-tracker.contextevent.md) + +## ContextEvent interface + +Argument for [ContextGenerator](./browser-tracker.contextgenerator.md) and [ContextFilter](./browser-tracker.contextfilter.md) callback + +Signature: + +```typescript +interface ContextEvent +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [event](./browser-tracker.contextevent.event.md) | Payload | The event payload | +| [eventSchema](./browser-tracker.contextevent.eventschema.md) | string | The event schema where one is available, or empty string | +| [eventType](./browser-tracker.contextevent.eventtype.md) | string | The event type | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.contextfilter.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.contextfilter.md new file mode 100644 index 000000000..372d95274 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.contextfilter.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ContextFilter](./browser-tracker.contextfilter.md) + +## ContextFilter type + +A context filter is a user-supplied callback that is evaluated for each event to determine if the context associated with the filter should be attached to the event + +Signature: + +```typescript +type ContextFilter = (args?: ContextEvent) => boolean; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.contextgenerator.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.contextgenerator.md new file mode 100644 index 000000000..2fb65af74 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.contextgenerator.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ContextGenerator](./browser-tracker.contextgenerator.md) + +## ContextGenerator type + +A context generator is a user-supplied callback that is evaluated for each event to allow an additional context to be dynamically attached to the event + +Signature: + +```typescript +type ContextGenerator = (args?: ContextEvent) => SelfDescribingJson | SelfDescribingJson[] | undefined; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.contextprimitive.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.contextprimitive.md new file mode 100644 index 000000000..6d3f109dd --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.contextprimitive.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ContextPrimitive](./browser-tracker.contextprimitive.md) + +## ContextPrimitive type + +A context primitive is either a self-describing JSON or a context generator + +Signature: + +```typescript +type ContextPrimitive = SelfDescribingJson | ContextGenerator; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.cookiesamesite.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.cookiesamesite.md new file mode 100644 index 000000000..946fb40e6 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.cookiesamesite.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [CookieSameSite](./browser-tracker.cookiesamesite.md) + +## CookieSameSite type + +Signature: + +```typescript +type CookieSameSite = "None" | "Lax" | "Strict"; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.activatecoreplugin.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.activatecoreplugin.md new file mode 100644 index 000000000..42da09758 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.activatecoreplugin.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [CorePlugin](./browser-tracker.coreplugin.md) > [activateCorePlugin](./browser-tracker.coreplugin.activatecoreplugin.md) + +## CorePlugin.activateCorePlugin property + +Called when the plugin is initialised during the trackerCore construction + +Signature: + +```typescript +activateCorePlugin?: (core: TrackerCore) => void; +``` + +## Remarks + +Use to capture the specific core instance for each instance of a core plugin + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.aftertrack.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.aftertrack.md new file mode 100644 index 000000000..407869150 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.aftertrack.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [CorePlugin](./browser-tracker.coreplugin.md) > [afterTrack](./browser-tracker.coreplugin.aftertrack.md) + +## CorePlugin.afterTrack property + +Called just after the trackerCore callback fires + +Signature: + +```typescript +afterTrack?: (payload: Payload) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.beforetrack.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.beforetrack.md new file mode 100644 index 000000000..16ca1c014 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.beforetrack.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [CorePlugin](./browser-tracker.coreplugin.md) > [beforeTrack](./browser-tracker.coreplugin.beforetrack.md) + +## CorePlugin.beforeTrack property + +Called before the `filter` method is called and before the trackerCore callback fires (if the filter passes) + +Signature: + +```typescript +beforeTrack?: (payloadBuilder: PayloadBuilder) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.contexts.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.contexts.md new file mode 100644 index 000000000..fbb5738b0 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.contexts.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [CorePlugin](./browser-tracker.coreplugin.md) > [contexts](./browser-tracker.coreplugin.contexts.md) + +## CorePlugin.contexts property + +Called when constructing the context for each event Useful for adding additional context to events + +Signature: + +```typescript +contexts?: () => SelfDescribingJson[]; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.deactivateplugin.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.deactivateplugin.md new file mode 100644 index 000000000..bf29e5d18 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.deactivateplugin.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [CorePlugin](./browser-tracker.coreplugin.md) > [deactivatePlugin](./browser-tracker.coreplugin.deactivateplugin.md) + +## CorePlugin.deactivatePlugin property + +Called when the tracker is being destroyed. Should be used to clean up any resources or listeners that the plugin has created. + +Signature: + +```typescript +deactivatePlugin?: (core: TrackerCore) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.filter.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.filter.md new file mode 100644 index 000000000..9782c9593 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.filter.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [CorePlugin](./browser-tracker.coreplugin.md) > [filter](./browser-tracker.coreplugin.filter.md) + +## CorePlugin.filter property + +Called before the payload is sent to the callback to decide whether to send the payload or skip it + +Signature: + +```typescript +filter?: (payload: Payload) => boolean; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.logger.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.logger.md new file mode 100644 index 000000000..316f3e126 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.logger.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [CorePlugin](./browser-tracker.coreplugin.md) > [logger](./browser-tracker.coreplugin.logger.md) + +## CorePlugin.logger property + +Passed a logger instance which can be used to send log information to the active logger + +Signature: + +```typescript +logger?: (logger: Logger) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.md new file mode 100644 index 000000000..a224db7cc --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.coreplugin.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [CorePlugin](./browser-tracker.coreplugin.md) + +## CorePlugin interface + +Interface which defines Core Plugins + +Signature: + +```typescript +interface CorePlugin +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [activateCorePlugin?](./browser-tracker.coreplugin.activatecoreplugin.md) | (core: TrackerCore) => void | (Optional) Called when the plugin is initialised during the trackerCore construction | +| [afterTrack?](./browser-tracker.coreplugin.aftertrack.md) | (payload: Payload) => void | (Optional) Called just after the trackerCore callback fires | +| [beforeTrack?](./browser-tracker.coreplugin.beforetrack.md) | (payloadBuilder: PayloadBuilder) => void | (Optional) Called before the filter method is called and before the trackerCore callback fires (if the filter passes) | +| [contexts?](./browser-tracker.coreplugin.contexts.md) | () => SelfDescribingJson\[\] | (Optional) Called when constructing the context for each event Useful for adding additional context to events | +| [deactivatePlugin?](./browser-tracker.coreplugin.deactivateplugin.md) | (core: TrackerCore) => void | (Optional) Called when the tracker is being destroyed. Should be used to clean up any resources or listeners that the plugin has created. | +| [filter?](./browser-tracker.coreplugin.filter.md) | (payload: Payload) => boolean | (Optional) Called before the payload is sent to the callback to decide whether to send the payload or skip it | +| [logger?](./browser-tracker.coreplugin.logger.md) | (logger: Logger) => void | (Optional) Passed a logger instance which can be used to send log information to the active logger | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.corepluginconfiguration.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.corepluginconfiguration.md new file mode 100644 index 000000000..54e42ba1f --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.corepluginconfiguration.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [CorePluginConfiguration](./browser-tracker.corepluginconfiguration.md) + +## CorePluginConfiguration interface + +The configuration of the plugin to add + +Signature: + +```typescript +interface CorePluginConfiguration +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [plugin](./browser-tracker.corepluginconfiguration.plugin.md) | CorePlugin | | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.corepluginconfiguration.plugin.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.corepluginconfiguration.plugin.md new file mode 100644 index 000000000..855e99fc2 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.corepluginconfiguration.plugin.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [CorePluginConfiguration](./browser-tracker.corepluginconfiguration.md) > [plugin](./browser-tracker.corepluginconfiguration.plugin.md) + +## CorePluginConfiguration.plugin property + +Signature: + +```typescript +plugin: CorePlugin; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.crossdomainlinker.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.crossdomainlinker.md new file mode 100644 index 000000000..7a6ef74d4 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.crossdomainlinker.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [crossDomainLinker](./browser-tracker.crossdomainlinker.md) + +## crossDomainLinker() function + +Enable querystring decoration for links passing a filter + +Signature: + +```typescript +declare function crossDomainLinker(crossDomainLinkerCriterion: (elt: HTMLAnchorElement | HTMLAreaElement) => boolean, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| crossDomainLinkerCriterion | (elt: HTMLAnchorElement \| HTMLAreaElement) => boolean | | +| trackers | Array<string> | The tracker identifiers which will be configured | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.devicetimestamp.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.devicetimestamp.md new file mode 100644 index 000000000..4180de7eb --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.devicetimestamp.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [DeviceTimestamp](./browser-tracker.devicetimestamp.md) + +## DeviceTimestamp interface + +A representation of a Device Timestamp (dtm) + +Signature: + +```typescript +interface DeviceTimestamp +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [type](./browser-tracker.devicetimestamp.type.md) | "dtm" | | +| [value](./browser-tracker.devicetimestamp.value.md) | number | | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.devicetimestamp.type.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.devicetimestamp.type.md new file mode 100644 index 000000000..1ad337f8c --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.devicetimestamp.type.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [DeviceTimestamp](./browser-tracker.devicetimestamp.md) > [type](./browser-tracker.devicetimestamp.type.md) + +## DeviceTimestamp.type property + +Signature: + +```typescript +readonly type: "dtm"; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.devicetimestamp.value.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.devicetimestamp.value.md new file mode 100644 index 000000000..7a9e4add3 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.devicetimestamp.value.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [DeviceTimestamp](./browser-tracker.devicetimestamp.md) > [value](./browser-tracker.devicetimestamp.value.md) + +## DeviceTimestamp.value property + +Signature: + +```typescript +readonly value: number; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.disableactivitytracking.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.disableactivitytracking.md new file mode 100644 index 000000000..be17fdb57 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.disableactivitytracking.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [disableActivityTracking](./browser-tracker.disableactivitytracking.md) + +## disableActivityTracking() function + +Disables page activity tracking. + +Signature: + +```typescript +declare function disableActivityTracking(trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| trackers | Array<string> | The tracker identifiers the activity tracking will be disabled. | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.disableactivitytrackingcallback.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.disableactivitytrackingcallback.md new file mode 100644 index 000000000..9b15963b1 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.disableactivitytrackingcallback.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [disableActivityTrackingCallback](./browser-tracker.disableactivitytrackingcallback.md) + +## disableActivityTrackingCallback() function + +Disables page activity tracking callback. + +Signature: + +```typescript +declare function disableActivityTrackingCallback(trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| trackers | Array<string> | The tracker identifiers the activity tracking callback will be disabled. | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.disableanonymoustracking.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.disableanonymoustracking.md new file mode 100644 index 000000000..6a06c91f2 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.disableanonymoustracking.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [disableAnonymousTracking](./browser-tracker.disableanonymoustracking.md) + +## disableAnonymousTracking() function + +Disables anonymous tracking if active (ie. tracker initialized with `anonymousTracking`) For stateStorageStrategy override, uses supplied value first, falls back to one defined in initial config, otherwise uses cookieAndLocalStorage. + +Signature: + +```typescript +declare function disableAnonymousTracking(configuration?: DisableAnonymousTrackingConfiguration, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| configuration | DisableAnonymousTrackingConfiguration | The configuration for disabling anonymous tracking | +| trackers | Array<string> | The tracker identifiers which the event will be sent to | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.disableanonymoustrackingconfiguration.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.disableanonymoustrackingconfiguration.md new file mode 100644 index 000000000..8845e67b3 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.disableanonymoustrackingconfiguration.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [DisableAnonymousTrackingConfiguration](./browser-tracker.disableanonymoustrackingconfiguration.md) + +## DisableAnonymousTrackingConfiguration interface + +The configuration that can be changed when disabling anonymous tracking + +Signature: + +```typescript +interface DisableAnonymousTrackingConfiguration +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [stateStorageStrategy?](./browser-tracker.disableanonymoustrackingconfiguration.statestoragestrategy.md) | StateStorageStrategy | (Optional) | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.disableanonymoustrackingconfiguration.statestoragestrategy.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.disableanonymoustrackingconfiguration.statestoragestrategy.md new file mode 100644 index 000000000..e7b3c4665 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.disableanonymoustrackingconfiguration.statestoragestrategy.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [DisableAnonymousTrackingConfiguration](./browser-tracker.disableanonymoustrackingconfiguration.md) > [stateStorageStrategy](./browser-tracker.disableanonymoustrackingconfiguration.statestoragestrategy.md) + +## DisableAnonymousTrackingConfiguration.stateStorageStrategy property + +Signature: + +```typescript +stateStorageStrategy?: StateStorageStrategy; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.discardbrace.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.discardbrace.md new file mode 100644 index 000000000..2e6ce2087 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.discardbrace.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [discardBrace](./browser-tracker.discardbrace.md) + +## discardBrace() function + +Strip braces from URL + +Signature: + +```typescript +declare function discardBrace(enable: boolean, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| enable | boolean | Whther to enable stripping of braces | +| trackers | Array<string> | The tracker identifiers which will be configured | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.discardhashtag.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.discardhashtag.md new file mode 100644 index 000000000..a856d108b --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.discardhashtag.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [discardHashTag](./browser-tracker.discardhashtag.md) + +## discardHashTag() function + +Strip hash tag (or anchor) from URL + +Signature: + +```typescript +declare function discardHashTag(enable: boolean, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| enable | boolean | Whether to enable stripping of hash | +| trackers | Array<string> | The tracker identifiers which will be configured | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.buffersize.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.buffersize.md new file mode 100644 index 000000000..8016a035d --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.buffersize.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EmitterConfigurationBase](./browser-tracker.emitterconfigurationbase.md) > [bufferSize](./browser-tracker.emitterconfigurationbase.buffersize.md) + +## EmitterConfigurationBase.bufferSize property + +The amount of events that should be buffered before sending Recommended to leave as 1 to reduce change of losing events + +Signature: + +```typescript +bufferSize?: number; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.connectiontimeout.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.connectiontimeout.md new file mode 100644 index 000000000..959c8b97d --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.connectiontimeout.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EmitterConfigurationBase](./browser-tracker.emitterconfigurationbase.md) > [connectionTimeout](./browser-tracker.emitterconfigurationbase.connectiontimeout.md) + +## EmitterConfigurationBase.connectionTimeout property + +How long to wait before aborting requests to the collector + +Signature: + +```typescript +connectionTimeout?: number; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.cookieextensionservice.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.cookieextensionservice.md new file mode 100644 index 000000000..2bb4f496c --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.cookieextensionservice.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EmitterConfigurationBase](./browser-tracker.emitterconfigurationbase.md) > [cookieExtensionService](./browser-tracker.emitterconfigurationbase.cookieextensionservice.md) + +## EmitterConfigurationBase.cookieExtensionService property + +Cookie extension service full URL. This URL will be added to the queue and will be called using a GET method. This option is there to allow the service URL to be called in order to set any required identifiers e.g. extra cookies. + +The request respects the `anonymousTracking` option, including the SP-Anonymous header if needed, and any additional custom headers from the customHeaders option. + +Signature: + +```typescript +cookieExtensionService?: string; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.credentials.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.credentials.md new file mode 100644 index 000000000..ac6c4ab2c --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.credentials.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EmitterConfigurationBase](./browser-tracker.emitterconfigurationbase.md) > [credentials](./browser-tracker.emitterconfigurationbase.credentials.md) + +## EmitterConfigurationBase.credentials property + +Controls whether or not the browser sends credentials (defaults to 'include') + +Signature: + +```typescript +credentials?: "omit" | "same-origin" | "include"; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.customfetch.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.customfetch.md new file mode 100644 index 000000000..26e3fbe87 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.customfetch.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EmitterConfigurationBase](./browser-tracker.emitterconfigurationbase.md) > [customFetch](./browser-tracker.emitterconfigurationbase.customfetch.md) + +## EmitterConfigurationBase.customFetch property + +Enables overriding the default fetch function with a custom implementation. + +Signature: + +```typescript +customFetch?: (input: Request, options?: RequestInit) => Promise; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.customheaders.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.customheaders.md new file mode 100644 index 000000000..4653a77d9 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.customheaders.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EmitterConfigurationBase](./browser-tracker.emitterconfigurationbase.md) > [customHeaders](./browser-tracker.emitterconfigurationbase.customheaders.md) + +## EmitterConfigurationBase.customHeaders property + +An object of key value pairs which represent headers to attach when sending a POST request, only works for POST + +Signature: + +```typescript +customHeaders?: Record; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.dontretrystatuscodes.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.dontretrystatuscodes.md new file mode 100644 index 000000000..fbe2fe686 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.dontretrystatuscodes.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EmitterConfigurationBase](./browser-tracker.emitterconfigurationbase.md) > [dontRetryStatusCodes](./browser-tracker.emitterconfigurationbase.dontretrystatuscodes.md) + +## EmitterConfigurationBase.dontRetryStatusCodes property + +List of HTTP response status codes for which events sent to Collector should not be retried in future request. Only non-success status codes are considered (greater or equal to 300). The don't retry codes are only considered for GET and POST requests. By default, the tracker retries on all non-success status codes except for 400, 401, 403, 410, and 422 (these don't retry codes will remain even if you set your own `dontRetryStatusCodes` but can be changed using the `retryStatusCodes`). + +Signature: + +```typescript +dontRetryStatusCodes?: number[]; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.eventmethod.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.eventmethod.md new file mode 100644 index 000000000..272ccd18b --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.eventmethod.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EmitterConfigurationBase](./browser-tracker.emitterconfigurationbase.md) > [eventMethod](./browser-tracker.emitterconfigurationbase.eventmethod.md) + +## EmitterConfigurationBase.eventMethod property + +The preferred technique to use to send events + +Signature: + +```typescript +eventMethod?: EventMethod; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.eventstore.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.eventstore.md new file mode 100644 index 000000000..27e347507 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.eventstore.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EmitterConfigurationBase](./browser-tracker.emitterconfigurationbase.md) > [eventStore](./browser-tracker.emitterconfigurationbase.eventstore.md) + +## EmitterConfigurationBase.eventStore property + +Enables providing a custom EventStore implementation to store events before sending them to the collector. + +Signature: + +```typescript +eventStore?: EventStore; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.idservice.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.idservice.md new file mode 100644 index 000000000..699c4a7e6 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.idservice.md @@ -0,0 +1,16 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EmitterConfigurationBase](./browser-tracker.emitterconfigurationbase.md) > [idService](./browser-tracker.emitterconfigurationbase.idservice.md) + +## EmitterConfigurationBase.idService property + +> Warning: This API is now obsolete. +> +> Use `cookieExtensionService` instead. +> + +Signature: + +```typescript +idService?: string; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.keepalive.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.keepalive.md new file mode 100644 index 000000000..1fa539492 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.keepalive.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EmitterConfigurationBase](./browser-tracker.emitterconfigurationbase.md) > [keepalive](./browser-tracker.emitterconfigurationbase.keepalive.md) + +## EmitterConfigurationBase.keepalive property + +Indicates that the request should be allowed to outlive the webpage that initiated it. Enables collector requests to complete even if the page is closed or navigated away from. Note: Browsers put a limit on keepalive requests of 64KB. In case of multiple keepalive requests in parallel (may happen in case of multiple trackers), the limit is shared. + +Signature: + +```typescript +keepalive?: boolean; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.maxgetbytes.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.maxgetbytes.md new file mode 100644 index 000000000..b925892c5 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.maxgetbytes.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EmitterConfigurationBase](./browser-tracker.emitterconfigurationbase.md) > [maxGetBytes](./browser-tracker.emitterconfigurationbase.maxgetbytes.md) + +## EmitterConfigurationBase.maxGetBytes property + +The max size a GET request (its complete URL) can be. Requests over this size will be tried as a POST request. + +Signature: + +```typescript +maxGetBytes?: number; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.maxpostbytes.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.maxpostbytes.md new file mode 100644 index 000000000..f4545ea62 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.maxpostbytes.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EmitterConfigurationBase](./browser-tracker.emitterconfigurationbase.md) > [maxPostBytes](./browser-tracker.emitterconfigurationbase.maxpostbytes.md) + +## EmitterConfigurationBase.maxPostBytes property + +The max size a POST request can be before the tracker will force send it Also dictates the max size of a POST request before a batch of events is split into multiple requests + +Signature: + +```typescript +maxPostBytes?: number; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.md new file mode 100644 index 000000000..8ec405334 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.md @@ -0,0 +1,36 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EmitterConfigurationBase](./browser-tracker.emitterconfigurationbase.md) + +## EmitterConfigurationBase interface + +Signature: + +```typescript +interface EmitterConfigurationBase +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [bufferSize?](./browser-tracker.emitterconfigurationbase.buffersize.md) | number | (Optional) The amount of events that should be buffered before sending Recommended to leave as 1 to reduce change of losing events | +| [connectionTimeout?](./browser-tracker.emitterconfigurationbase.connectiontimeout.md) | number | (Optional) How long to wait before aborting requests to the collector | +| [cookieExtensionService?](./browser-tracker.emitterconfigurationbase.cookieextensionservice.md) | string | (Optional) Cookie extension service full URL. This URL will be added to the queue and will be called using a GET method. This option is there to allow the service URL to be called in order to set any required identifiers e.g. extra cookies.The request respects the anonymousTracking option, including the SP-Anonymous header if needed, and any additional custom headers from the customHeaders option. | +| [credentials?](./browser-tracker.emitterconfigurationbase.credentials.md) | "omit" \| "same-origin" \| "include" | (Optional) Controls whether or not the browser sends credentials (defaults to 'include') | +| [customFetch?](./browser-tracker.emitterconfigurationbase.customfetch.md) | (input: Request, options?: RequestInit) => Promise<Response> | (Optional) Enables overriding the default fetch function with a custom implementation. | +| [customHeaders?](./browser-tracker.emitterconfigurationbase.customheaders.md) | Record<string, string> | (Optional) An object of key value pairs which represent headers to attach when sending a POST request, only works for POST | +| [dontRetryStatusCodes?](./browser-tracker.emitterconfigurationbase.dontretrystatuscodes.md) | number\[\] | (Optional) List of HTTP response status codes for which events sent to Collector should not be retried in future request. Only non-success status codes are considered (greater or equal to 300). The don't retry codes are only considered for GET and POST requests. By default, the tracker retries on all non-success status codes except for 400, 401, 403, 410, and 422 (these don't retry codes will remain even if you set your own dontRetryStatusCodes but can be changed using the retryStatusCodes). | +| [eventMethod?](./browser-tracker.emitterconfigurationbase.eventmethod.md) | EventMethod | (Optional) The preferred technique to use to send events | +| [eventStore?](./browser-tracker.emitterconfigurationbase.eventstore.md) | EventStore | (Optional) Enables providing a custom EventStore implementation to store events before sending them to the collector. | +| [idService?](./browser-tracker.emitterconfigurationbase.idservice.md) | string | (Optional) | +| [keepalive?](./browser-tracker.emitterconfigurationbase.keepalive.md) | boolean | (Optional) Indicates that the request should be allowed to outlive the webpage that initiated it. Enables collector requests to complete even if the page is closed or navigated away from. Note: Browsers put a limit on keepalive requests of 64KB. In case of multiple keepalive requests in parallel (may happen in case of multiple trackers), the limit is shared. | +| [maxGetBytes?](./browser-tracker.emitterconfigurationbase.maxgetbytes.md) | number | (Optional) The max size a GET request (its complete URL) can be. Requests over this size will be tried as a POST request. | +| [maxPostBytes?](./browser-tracker.emitterconfigurationbase.maxpostbytes.md) | number | (Optional) The max size a POST request can be before the tracker will force send it Also dictates the max size of a POST request before a batch of events is split into multiple requests | +| [onRequestFailure?](./browser-tracker.emitterconfigurationbase.onrequestfailure.md) | (data: RequestFailure, response?: Response) => void | (Optional) A callback function to be executed whenever a request fails to be sent to the collector. This is the inverse of the onRequestSuccess callback, so any non 2xx status code will trigger this callback. | +| [onRequestSuccess?](./browser-tracker.emitterconfigurationbase.onrequestsuccess.md) | (data: EventBatch, response: Response) => void | (Optional) A callback function to be executed whenever a request is successfully sent to the collector. In practice this means any request which returns a 2xx status code will trigger this callback. | +| [postPath?](./browser-tracker.emitterconfigurationbase.postpath.md) | string | (Optional) The post path which events will be sent to. Ensure your collector is configured to accept events on this post path | +| [retryFailedRequests?](./browser-tracker.emitterconfigurationbase.retryfailedrequests.md) | boolean | (Optional) Whether to retry failed requests to the collector.Failed requests are requests that failed due to \[timeouts\](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/timeout\_event), \[network errors\](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/error\_event), and \[abort events\](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/abort\_event).Takes precedent over retryStatusCodes and dontRetryStatusCodes. | +| [retryStatusCodes?](./browser-tracker.emitterconfigurationbase.retrystatuscodes.md) | number\[\] | (Optional) List of HTTP response status codes for which events sent to Collector should be retried in future requests. Only non-success status codes are considered (greater or equal to 300). The retry codes are only considered for GET and POST requests. They take priority over the dontRetryStatusCodes option. By default, the tracker retries on all non-success status codes except for 400, 401, 403, 410, and 422. | +| [useStm?](./browser-tracker.emitterconfigurationbase.usestm.md) | boolean | (Optional) Should the Sent Timestamp be attached to events. Only applies for GET events. | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.onrequestfailure.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.onrequestfailure.md new file mode 100644 index 000000000..c2bcfef71 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.onrequestfailure.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EmitterConfigurationBase](./browser-tracker.emitterconfigurationbase.md) > [onRequestFailure](./browser-tracker.emitterconfigurationbase.onrequestfailure.md) + +## EmitterConfigurationBase.onRequestFailure property + +A callback function to be executed whenever a request fails to be sent to the collector. This is the inverse of the onRequestSuccess callback, so any non 2xx status code will trigger this callback. + +Signature: + +```typescript +onRequestFailure?: (data: RequestFailure, response?: Response) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.onrequestsuccess.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.onrequestsuccess.md new file mode 100644 index 000000000..ef53a7091 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.onrequestsuccess.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EmitterConfigurationBase](./browser-tracker.emitterconfigurationbase.md) > [onRequestSuccess](./browser-tracker.emitterconfigurationbase.onrequestsuccess.md) + +## EmitterConfigurationBase.onRequestSuccess property + +A callback function to be executed whenever a request is successfully sent to the collector. In practice this means any request which returns a 2xx status code will trigger this callback. + +Signature: + +```typescript +onRequestSuccess?: (data: EventBatch, response: Response) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.postpath.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.postpath.md new file mode 100644 index 000000000..ca2bc0606 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.postpath.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EmitterConfigurationBase](./browser-tracker.emitterconfigurationbase.md) > [postPath](./browser-tracker.emitterconfigurationbase.postpath.md) + +## EmitterConfigurationBase.postPath property + +The post path which events will be sent to. Ensure your collector is configured to accept events on this post path + +Signature: + +```typescript +postPath?: string; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.retryfailedrequests.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.retryfailedrequests.md new file mode 100644 index 000000000..46363698b --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.retryfailedrequests.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EmitterConfigurationBase](./browser-tracker.emitterconfigurationbase.md) > [retryFailedRequests](./browser-tracker.emitterconfigurationbase.retryfailedrequests.md) + +## EmitterConfigurationBase.retryFailedRequests property + +Whether to retry failed requests to the collector. + +Failed requests are requests that failed due to \[timeouts\](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/timeout\_event), \[network errors\](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/error\_event), and \[abort events\](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/abort\_event). + +Takes precedent over `retryStatusCodes` and `dontRetryStatusCodes`. + +Signature: + +```typescript +retryFailedRequests?: boolean; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.retrystatuscodes.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.retrystatuscodes.md new file mode 100644 index 000000000..b005b2014 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.retrystatuscodes.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EmitterConfigurationBase](./browser-tracker.emitterconfigurationbase.md) > [retryStatusCodes](./browser-tracker.emitterconfigurationbase.retrystatuscodes.md) + +## EmitterConfigurationBase.retryStatusCodes property + +List of HTTP response status codes for which events sent to Collector should be retried in future requests. Only non-success status codes are considered (greater or equal to 300). The retry codes are only considered for GET and POST requests. They take priority over the `dontRetryStatusCodes` option. By default, the tracker retries on all non-success status codes except for 400, 401, 403, 410, and 422. + +Signature: + +```typescript +retryStatusCodes?: number[]; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.usestm.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.usestm.md new file mode 100644 index 000000000..294d8f284 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.emitterconfigurationbase.usestm.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EmitterConfigurationBase](./browser-tracker.emitterconfigurationbase.md) > [useStm](./browser-tracker.emitterconfigurationbase.usestm.md) + +## EmitterConfigurationBase.useStm property + +Should the Sent Timestamp be attached to events. Only applies for GET events. + +Signature: + +```typescript +useStm?: boolean; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.enableactivitytracking.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.enableactivitytracking.md new file mode 100644 index 000000000..106a503e1 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.enableactivitytracking.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [enableActivityTracking](./browser-tracker.enableactivitytracking.md) + +## enableActivityTracking() function + +Enables page activity tracking (sends page pings to the Collector regularly). + +Signature: + +```typescript +declare function enableActivityTracking(configuration: ActivityTrackingConfiguration, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| configuration | ActivityTrackingConfiguration | The activity tracking configuration | +| trackers | Array<string> | The tracker identifiers which will be configured | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.enableactivitytrackingcallback.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.enableactivitytrackingcallback.md new file mode 100644 index 000000000..22a099ac3 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.enableactivitytrackingcallback.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [enableActivityTrackingCallback](./browser-tracker.enableactivitytrackingcallback.md) + +## enableActivityTrackingCallback() function + +Enables page activity tracking (replaces collector ping with callback). + +Signature: + +```typescript +declare function enableActivityTrackingCallback(configuration: ActivityTrackingConfiguration & ActivityTrackingConfigurationCallback, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| configuration | ActivityTrackingConfiguration & ActivityTrackingConfigurationCallback | The activity tracking callback configuration | +| trackers | Array<string> | The tracker identifiers which will be configured | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.enableanonymoustracking.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.enableanonymoustracking.md new file mode 100644 index 000000000..07cf432e2 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.enableanonymoustracking.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [enableAnonymousTracking](./browser-tracker.enableanonymoustracking.md) + +## enableAnonymousTracking() function + +Enables anonymous tracking (ie. tracker initialized without `anonymousTracking`) + +Signature: + +```typescript +declare function enableAnonymousTracking(configuration?: EnableAnonymousTrackingConfiguration, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| configuration | EnableAnonymousTrackingConfiguration | The configuration for enabling anonymous tracking | +| trackers | Array<string> | The tracker identifiers which the event will be sent to | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.enableanonymoustrackingconfiguration.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.enableanonymoustrackingconfiguration.md new file mode 100644 index 000000000..e9205986b --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.enableanonymoustrackingconfiguration.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EnableAnonymousTrackingConfiguration](./browser-tracker.enableanonymoustrackingconfiguration.md) + +## EnableAnonymousTrackingConfiguration interface + +The configuration that can be changed when enabling anonymous tracking + +Signature: + +```typescript +interface EnableAnonymousTrackingConfiguration +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [options?](./browser-tracker.enableanonymoustrackingconfiguration.options.md) | AnonymousTrackingOptions | (Optional) | +| [stateStorageStrategy?](./browser-tracker.enableanonymoustrackingconfiguration.statestoragestrategy.md) | StateStorageStrategy | (Optional) | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.enableanonymoustrackingconfiguration.options.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.enableanonymoustrackingconfiguration.options.md new file mode 100644 index 000000000..2a4a3da12 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.enableanonymoustrackingconfiguration.options.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EnableAnonymousTrackingConfiguration](./browser-tracker.enableanonymoustrackingconfiguration.md) > [options](./browser-tracker.enableanonymoustrackingconfiguration.options.md) + +## EnableAnonymousTrackingConfiguration.options property + +Signature: + +```typescript +options?: AnonymousTrackingOptions; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.enableanonymoustrackingconfiguration.statestoragestrategy.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.enableanonymoustrackingconfiguration.statestoragestrategy.md new file mode 100644 index 000000000..346abcf49 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.enableanonymoustrackingconfiguration.statestoragestrategy.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EnableAnonymousTrackingConfiguration](./browser-tracker.enableanonymoustrackingconfiguration.md) > [stateStorageStrategy](./browser-tracker.enableanonymoustrackingconfiguration.statestoragestrategy.md) + +## EnableAnonymousTrackingConfiguration.stateStorageStrategy property + +Signature: + +```typescript +stateStorageStrategy?: StateStorageStrategy; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.eventbatch.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventbatch.md new file mode 100644 index 000000000..e5b3b7460 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventbatch.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EventBatch](./browser-tracker.eventbatch.md) + +## EventBatch type + +A collection of event payloads which are sent to the collector. + +Signature: + +```typescript +type EventBatch = Payload[]; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.eventjson.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventjson.md new file mode 100644 index 000000000..e03b563b5 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventjson.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EventJson](./browser-tracker.eventjson.md) + +## EventJson type + +An array of tuples which represents the unprocessed JSON to be added to the Payload + +Signature: + +```typescript +type EventJson = Array; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.eventmethod.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventmethod.md new file mode 100644 index 000000000..283adbbeb --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventmethod.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EventMethod](./browser-tracker.eventmethod.md) + +## EventMethod type + +Signature: + +```typescript +type EventMethod = "post" | "get"; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.eventpayloadandcontext.context.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventpayloadandcontext.context.md new file mode 100644 index 000000000..9f950fa9f --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventpayloadandcontext.context.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EventPayloadAndContext](./browser-tracker.eventpayloadandcontext.md) > [context](./browser-tracker.eventpayloadandcontext.context.md) + +## EventPayloadAndContext.context property + +List of context entities to track along with the event + +Signature: + +```typescript +context: Array; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.eventpayloadandcontext.event.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventpayloadandcontext.event.md new file mode 100644 index 000000000..3a977651c --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventpayloadandcontext.event.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EventPayloadAndContext](./browser-tracker.eventpayloadandcontext.md) > [event](./browser-tracker.eventpayloadandcontext.event.md) + +## EventPayloadAndContext.event property + +Tracker payload for the event data + +Signature: + +```typescript +event: PayloadBuilder; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.eventpayloadandcontext.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventpayloadandcontext.md new file mode 100644 index 000000000..7b13345a5 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventpayloadandcontext.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EventPayloadAndContext](./browser-tracker.eventpayloadandcontext.md) + +## EventPayloadAndContext interface + +Interface for returning a built event (PayloadBuilder) and context (Array of SelfDescribingJson). + +Signature: + +```typescript +interface EventPayloadAndContext +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [context](./browser-tracker.eventpayloadandcontext.context.md) | Array<SelfDescribingJson> | List of context entities to track along with the event | +| [event](./browser-tracker.eventpayloadandcontext.event.md) | PayloadBuilder | Tracker payload for the event data | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstore.add.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstore.add.md new file mode 100644 index 000000000..5da726296 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstore.add.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EventStore](./browser-tracker.eventstore.md) > [add](./browser-tracker.eventstore.add.md) + +## EventStore.add property + +Add an event to the store + +Signature: + +```typescript +add: (payload: EventStorePayload) => Promise; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstore.count.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstore.count.md new file mode 100644 index 000000000..02c5789c5 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstore.count.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EventStore](./browser-tracker.eventstore.md) > [count](./browser-tracker.eventstore.count.md) + +## EventStore.count property + +Count all events in the store + +Signature: + +```typescript +count: () => Promise; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstore.getall.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstore.getall.md new file mode 100644 index 000000000..b8ae370fd --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstore.getall.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EventStore](./browser-tracker.eventstore.md) > [getAll](./browser-tracker.eventstore.getall.md) + +## EventStore.getAll property + +Retrieve all payloads including their meta configuration in the store + +Signature: + +```typescript +getAll: () => Promise; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstore.getallpayloads.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstore.getallpayloads.md new file mode 100644 index 000000000..9b16ebd79 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstore.getallpayloads.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EventStore](./browser-tracker.eventstore.md) > [getAllPayloads](./browser-tracker.eventstore.getallpayloads.md) + +## EventStore.getAllPayloads property + +Retrieve all pure payloads in the store + +Signature: + +```typescript +getAllPayloads: () => Promise; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstore.iterator.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstore.iterator.md new file mode 100644 index 000000000..77522d3d8 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstore.iterator.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EventStore](./browser-tracker.eventstore.md) > [iterator](./browser-tracker.eventstore.iterator.md) + +## EventStore.iterator property + +Get an iterator over all events in the store + +Signature: + +```typescript +iterator: () => EventStoreIterator; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstore.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstore.md new file mode 100644 index 000000000..45055c443 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstore.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EventStore](./browser-tracker.eventstore.md) + +## EventStore interface + +EventStore allows storing and retrieving events before they are sent to the collector + +Signature: + +```typescript +interface EventStore +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [add](./browser-tracker.eventstore.add.md) | (payload: EventStorePayload) => Promise<number> | Add an event to the store | +| [count](./browser-tracker.eventstore.count.md) | () => Promise<number> | Count all events in the store | +| [getAll](./browser-tracker.eventstore.getall.md) | () => Promise<readonly EventStorePayload\[\]> | Retrieve all payloads including their meta configuration in the store | +| [getAllPayloads](./browser-tracker.eventstore.getallpayloads.md) | () => Promise<readonly Payload\[\]> | Retrieve all pure payloads in the store | +| [iterator](./browser-tracker.eventstore.iterator.md) | () => EventStoreIterator | Get an iterator over all events in the store | +| [removeHead](./browser-tracker.eventstore.removehead.md) | (count: number) => Promise<void> | Remove the first count events from the store | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstore.removehead.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstore.removehead.md new file mode 100644 index 000000000..7242bc72f --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstore.removehead.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EventStore](./browser-tracker.eventstore.md) > [removeHead](./browser-tracker.eventstore.removehead.md) + +## EventStore.removeHead property + +Remove the first `count` events from the store + +Signature: + +```typescript +removeHead: (count: number) => Promise; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstoreconfiguration.maxsize.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstoreconfiguration.maxsize.md new file mode 100644 index 000000000..d333d6bdc --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstoreconfiguration.maxsize.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EventStoreConfiguration](./browser-tracker.eventstoreconfiguration.md) > [maxSize](./browser-tracker.eventstoreconfiguration.maxsize.md) + +## EventStoreConfiguration.maxSize property + +The maximum amount of events that will be buffered in the event store + +This is useful to ensure the Tracker doesn't fill the 5MB or 10MB available to each website should the collector be unavailable due to lost connectivity. Will drop old events once the limit is hit + +Signature: + +```typescript +maxSize?: number; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstoreconfiguration.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstoreconfiguration.md new file mode 100644 index 000000000..71b51d4e3 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstoreconfiguration.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EventStoreConfiguration](./browser-tracker.eventstoreconfiguration.md) + +## EventStoreConfiguration interface + +Signature: + +```typescript +interface EventStoreConfiguration +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [maxSize?](./browser-tracker.eventstoreconfiguration.maxsize.md) | number | (Optional) The maximum amount of events that will be buffered in the event storeThis is useful to ensure the Tracker doesn't fill the 5MB or 10MB available to each website should the collector be unavailable due to lost connectivity. Will drop old events once the limit is hit | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstoreiterator.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstoreiterator.md new file mode 100644 index 000000000..5bd04cb68 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstoreiterator.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EventStoreIterator](./browser-tracker.eventstoreiterator.md) + +## EventStoreIterator interface + +EventStoreIterator allows iterating over all events in the store. + +Signature: + +```typescript +interface EventStoreIterator +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [next](./browser-tracker.eventstoreiterator.next.md) | () => Promise<EventStoreIteratorNextResult> | Retrieve the next event in the store | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstoreiterator.next.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstoreiterator.next.md new file mode 100644 index 000000000..6160964eb --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstoreiterator.next.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EventStoreIterator](./browser-tracker.eventstoreiterator.md) > [next](./browser-tracker.eventstoreiterator.next.md) + +## EventStoreIterator.next property + +Retrieve the next event in the store + +Signature: + +```typescript +next: () => Promise; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstorepayload.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstorepayload.md new file mode 100644 index 000000000..0435dd4c5 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstorepayload.md @@ -0,0 +1,19 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EventStorePayload](./browser-tracker.eventstorepayload.md) + +## EventStorePayload interface + +Signature: + +```typescript +interface EventStorePayload +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [payload](./browser-tracker.eventstorepayload.payload.md) | Payload | The event payload to be stored | +| [svrAnon?](./browser-tracker.eventstorepayload.svranon.md) | boolean | (Optional) If the request should undergo server anonymization. | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstorepayload.payload.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstorepayload.payload.md new file mode 100644 index 000000000..a1c54ab01 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstorepayload.payload.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EventStorePayload](./browser-tracker.eventstorepayload.md) > [payload](./browser-tracker.eventstorepayload.payload.md) + +## EventStorePayload.payload property + +The event payload to be stored + +Signature: + +```typescript +payload: Payload; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstorepayload.svranon.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstorepayload.svranon.md new file mode 100644 index 000000000..2ca4d6294 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.eventstorepayload.svranon.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [EventStorePayload](./browser-tracker.eventstorepayload.md) > [svrAnon](./browser-tracker.eventstorepayload.svranon.md) + +## EventStorePayload.svrAnon property + +If the request should undergo server anonymization. + +Signature: + +```typescript +svrAnon?: boolean; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.extendedcrossdomainlinkerattributes.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.extendedcrossdomainlinkerattributes.md new file mode 100644 index 000000000..6f228ab28 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.extendedcrossdomainlinkerattributes.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ExtendedCrossDomainLinkerAttributes](./browser-tracker.extendedcrossdomainlinkerattributes.md) + +## ExtendedCrossDomainLinkerAttributes type + +Signature: + +```typescript +type ExtendedCrossDomainLinkerAttributes = { + userId?: boolean; + sessionId?: boolean; + sourceId?: boolean; + sourcePlatform?: boolean; + reason?: boolean | ((evt: Event) => string); +}; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.extendedcrossdomainlinkeroptions.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.extendedcrossdomainlinkeroptions.md new file mode 100644 index 000000000..55c2a0732 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.extendedcrossdomainlinkeroptions.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ExtendedCrossDomainLinkerOptions](./browser-tracker.extendedcrossdomainlinkeroptions.md) + +## ExtendedCrossDomainLinkerOptions type + +Signature: + +```typescript +type ExtendedCrossDomainLinkerOptions = boolean | ExtendedCrossDomainLinkerAttributes; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.filterprovider.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.filterprovider.md new file mode 100644 index 000000000..015f42f22 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.filterprovider.md @@ -0,0 +1,16 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [FilterProvider](./browser-tracker.filterprovider.md) + +## FilterProvider type + +A filter provider is a tuple that has two parts: a context filter and the context primitive(s) If the context filter evaluates to true, the tracker will attach the context primitive(s) + +Signature: + +```typescript +type FilterProvider = [ + ContextFilter, + Array | ContextPrimitive +]; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.flushbuffer.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.flushbuffer.md new file mode 100644 index 000000000..27ab8f848 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.flushbuffer.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [flushBuffer](./browser-tracker.flushbuffer.md) + +## flushBuffer() function + +Send all events in the outQueue Only need to use this when sending events with a bufferSize of at least 2 + +Signature: + +```typescript +declare function flushBuffer(configuration?: FlushBufferConfiguration, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| configuration | FlushBufferConfiguration | The configuration to use following flushing the buffer | +| trackers | Array<string> | The tracker identifiers which will be flushed | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.flushbufferconfiguration.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.flushbufferconfiguration.md new file mode 100644 index 000000000..d2f73779f --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.flushbufferconfiguration.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [FlushBufferConfiguration](./browser-tracker.flushbufferconfiguration.md) + +## FlushBufferConfiguration interface + +The configuration that can be changed when flushing the buffer + +Signature: + +```typescript +interface FlushBufferConfiguration +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [newBufferSize?](./browser-tracker.flushbufferconfiguration.newbuffersize.md) | number | (Optional) | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.flushbufferconfiguration.newbuffersize.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.flushbufferconfiguration.newbuffersize.md new file mode 100644 index 000000000..1607d9d32 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.flushbufferconfiguration.newbuffersize.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [FlushBufferConfiguration](./browser-tracker.flushbufferconfiguration.md) > [newBufferSize](./browser-tracker.flushbufferconfiguration.newbuffersize.md) + +## FlushBufferConfiguration.newBufferSize property + +Signature: + +```typescript +newBufferSize?: number; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.getdomainsessionid.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.getdomainsessionid.md new file mode 100644 index 000000000..bb8adc275 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.getdomainsessionid.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [getDomainSessionId](./browser-tracker.getdomainsessionid.md) + +## getDomainSessionId() function + +Get the domain session ID (from the first-party cookie) for a tracker. + +Signature: + +```typescript +declare function getDomainSessionId(trackerId?: string): string | undefined; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| trackerId | string | The tracker identifier which the domain session ID will be retrieved from. Defaults to the first initialised tracker. | + +Returns: + +string \| undefined + +The domain session ID, or undefined if no matching tracker is found + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.jsonprocessor.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.jsonprocessor.md new file mode 100644 index 000000000..52059b32b --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.jsonprocessor.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [JsonProcessor](./browser-tracker.jsonprocessor.md) + +## JsonProcessor type + +A function which will processor the Json onto the injected PayloadBuilder + +Signature: + +```typescript +type JsonProcessor = (payloadBuilder: PayloadBuilder, jsonForProcessing: EventJson, contextEntitiesForProcessing: SelfDescribingJson[]) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.localstorageeventstoreconfigurationbase.maxlocalstoragequeuesize.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.localstorageeventstoreconfigurationbase.maxlocalstoragequeuesize.md new file mode 100644 index 000000000..7d475b29a --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.localstorageeventstoreconfigurationbase.maxlocalstoragequeuesize.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [LocalStorageEventStoreConfigurationBase](./browser-tracker.localstorageeventstoreconfigurationbase.md) > [maxLocalStorageQueueSize](./browser-tracker.localstorageeventstoreconfigurationbase.maxlocalstoragequeuesize.md) + +## LocalStorageEventStoreConfigurationBase.maxLocalStorageQueueSize property + +The maximum amount of events that will be buffered in local storage + +This is useful to ensure the Tracker doesn't fill the 5MB or 10MB available to each website should the collector be unavailable due to lost connectivity. Will drop events once the limit is hit + +Signature: + +```typescript +maxLocalStorageQueueSize?: number; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.localstorageeventstoreconfigurationbase.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.localstorageeventstoreconfigurationbase.md new file mode 100644 index 000000000..72c5b9f3f --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.localstorageeventstoreconfigurationbase.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [LocalStorageEventStoreConfigurationBase](./browser-tracker.localstorageeventstoreconfigurationbase.md) + +## LocalStorageEventStoreConfigurationBase interface + +Signature: + +```typescript +interface LocalStorageEventStoreConfigurationBase extends EventStoreConfiguration +``` +Extends: EventStoreConfiguration + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [maxLocalStorageQueueSize?](./browser-tracker.localstorageeventstoreconfigurationbase.maxlocalstoragequeuesize.md) | number | (Optional) The maximum amount of events that will be buffered in local storageThis is useful to ensure the Tracker doesn't fill the 5MB or 10MB available to each website should the collector be unavailable due to lost connectivity. Will drop events once the limit is hit | +| [useLocalStorage?](./browser-tracker.localstorageeventstoreconfigurationbase.uselocalstorage.md) | boolean | (Optional) Whether to use localStorage at all Default is true | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.localstorageeventstoreconfigurationbase.uselocalstorage.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.localstorageeventstoreconfigurationbase.uselocalstorage.md new file mode 100644 index 000000000..896eb5819 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.localstorageeventstoreconfigurationbase.uselocalstorage.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [LocalStorageEventStoreConfigurationBase](./browser-tracker.localstorageeventstoreconfigurationbase.md) > [useLocalStorage](./browser-tracker.localstorageeventstoreconfigurationbase.uselocalstorage.md) + +## LocalStorageEventStoreConfigurationBase.useLocalStorage property + +Whether to use localStorage at all Default is true + +Signature: + +```typescript +useLocalStorage?: boolean; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.logger.debug.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.logger.debug.md new file mode 100644 index 000000000..0cfbe9015 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.logger.debug.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [Logger](./browser-tracker.logger.md) > [debug](./browser-tracker.logger.debug.md) + +## Logger.debug property + +Signature: + +```typescript +debug: (message: string, ...extraParams: unknown[]) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.logger.error.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.logger.error.md new file mode 100644 index 000000000..9b3a2ecf4 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.logger.error.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [Logger](./browser-tracker.logger.md) > [error](./browser-tracker.logger.error.md) + +## Logger.error property + +Signature: + +```typescript +error: (message: string, error?: unknown, ...extraParams: unknown[]) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.logger.info.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.logger.info.md new file mode 100644 index 000000000..25f51b5ea --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.logger.info.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [Logger](./browser-tracker.logger.md) > [info](./browser-tracker.logger.info.md) + +## Logger.info property + +Signature: + +```typescript +info: (message: string, ...extraParams: unknown[]) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.logger.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.logger.md new file mode 100644 index 000000000..7a5166863 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.logger.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [Logger](./browser-tracker.logger.md) + +## Logger interface + +Signature: + +```typescript +interface Logger +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [debug](./browser-tracker.logger.debug.md) | (message: string, ...extraParams: unknown\[\]) => void | | +| [error](./browser-tracker.logger.error.md) | (message: string, error?: unknown, ...extraParams: unknown\[\]) => void | | +| [info](./browser-tracker.logger.info.md) | (message: string, ...extraParams: unknown\[\]) => void | | +| [setLogLevel](./browser-tracker.logger.setloglevel.md) | (level: LOG\_LEVEL) => void | | +| [warn](./browser-tracker.logger.warn.md) | (message: string, error?: unknown, ...extraParams: unknown\[\]) => void | | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.logger.setloglevel.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.logger.setloglevel.md new file mode 100644 index 000000000..f9dec09c7 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.logger.setloglevel.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [Logger](./browser-tracker.logger.md) > [setLogLevel](./browser-tracker.logger.setloglevel.md) + +## Logger.setLogLevel property + +Signature: + +```typescript +setLogLevel: (level: LOG_LEVEL) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.logger.warn.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.logger.warn.md new file mode 100644 index 000000000..747cffca2 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.logger.warn.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [Logger](./browser-tracker.logger.md) > [warn](./browser-tracker.logger.warn.md) + +## Logger.warn property + +Signature: + +```typescript +warn: (message: string, error?: unknown, ...extraParams: unknown[]) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.md new file mode 100644 index 000000000..71c0e88b7 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.md @@ -0,0 +1,125 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) + +## browser-tracker package + +## Classes + +| Class | Description | +| --- | --- | +| [SharedState](./browser-tracker.sharedstate.md) | A set of variables which are shared among all initialised trackers | + +## Functions + +| Function | Description | +| --- | --- | +| [addGlobalContexts(contexts, trackers)](./browser-tracker.addglobalcontexts.md) | All provided contexts will be sent with every event | +| [addPlugin(configuration, trackers)](./browser-tracker.addplugin.md) | Add a plugin into the plugin collection after trackers have already been initialised | +| [clearGlobalContexts(trackers)](./browser-tracker.clearglobalcontexts.md) | Clear all global contexts that are sent with events | +| [clearUserData(configuration, trackers)](./browser-tracker.clearuserdata.md) | Clears all cookies and local storage containing user and session identifiers | +| [crossDomainLinker(crossDomainLinkerCriterion, trackers)](./browser-tracker.crossdomainlinker.md) | Enable querystring decoration for links passing a filter | +| [disableActivityTracking(trackers)](./browser-tracker.disableactivitytracking.md) | Disables page activity tracking. | +| [disableActivityTrackingCallback(trackers)](./browser-tracker.disableactivitytrackingcallback.md) | Disables page activity tracking callback. | +| [disableAnonymousTracking(configuration, trackers)](./browser-tracker.disableanonymoustracking.md) | Disables anonymous tracking if active (ie. tracker initialized with anonymousTracking) For stateStorageStrategy override, uses supplied value first, falls back to one defined in initial config, otherwise uses cookieAndLocalStorage. | +| [discardBrace(enable, trackers)](./browser-tracker.discardbrace.md) | Strip braces from URL | +| [discardHashTag(enable, trackers)](./browser-tracker.discardhashtag.md) | Strip hash tag (or anchor) from URL | +| [enableActivityTracking(configuration, trackers)](./browser-tracker.enableactivitytracking.md) | Enables page activity tracking (sends page pings to the Collector regularly). | +| [enableActivityTrackingCallback(configuration, trackers)](./browser-tracker.enableactivitytrackingcallback.md) | Enables page activity tracking (replaces collector ping with callback). | +| [enableAnonymousTracking(configuration, trackers)](./browser-tracker.enableanonymoustracking.md) | Enables anonymous tracking (ie. tracker initialized without anonymousTracking) | +| [flushBuffer(configuration, trackers)](./browser-tracker.flushbuffer.md) | Send all events in the outQueue Only need to use this when sending events with a bufferSize of at least 2 | +| [getDomainSessionId(trackerId)](./browser-tracker.getdomainsessionid.md) | Get the domain session ID (from the first-party cookie) for a tracker. | +| [newSession(trackers)](./browser-tracker.newsession.md) | Expires current session and starts a new session. | +| [newTracker(trackerId, endpoint, configuration)](./browser-tracker.newtracker.md) | Initialise a new tracker | +| [preservePageViewId(trackers)](./browser-tracker.preservepageviewid.md) | Stop regenerating pageViewId (available from web_page context) | +| [removeGlobalContexts(contexts, trackers)](./browser-tracker.removeglobalcontexts.md) | All provided contexts will no longer be sent with every event | +| [setBufferSize(newBufferSize, trackers)](./browser-tracker.setbuffersize.md) | Set the buffer size Can be useful if you want to stop batching requests to ensure events start sending closer to event creation | +| [setCollectorUrl(collectorUrl, trackers)](./browser-tracker.setcollectorurl.md) | Specify the Snowplow collector URL. Specific http or https to force it or leave it off to match the website protocol. | +| [setCookiePath(path, trackers)](./browser-tracker.setcookiepath.md) | Set first-party cookie path | +| [setCustomUrl(url, trackers)](./browser-tracker.setcustomurl.md) | Override url | +| [setDocumentTitle(title, trackers)](./browser-tracker.setdocumenttitle.md) | Override document.title | +| [setOptOutCookie(name, trackers)](./browser-tracker.setoptoutcookie.md) | Sets the opt out cookie. | +| [setReferrerUrl(url, trackers)](./browser-tracker.setreferrerurl.md) | Override referrer | +| [setUserId(userId, trackers)](./browser-tracker.setuserid.md) | Set the business-defined user ID for this user. | +| [setUserIdFromCookie(cookieName, trackers)](./browser-tracker.setuseridfromcookie.md) | Set the business-defined user ID for this user to the value of a cookie. | +| [setUserIdFromLocation(querystringField, trackers)](./browser-tracker.setuseridfromlocation.md) | Set the business-defined user ID for this user using the location querystring. | +| [setUserIdFromReferrer(querystringField, trackers)](./browser-tracker.setuseridfromreferrer.md) | Set the business-defined user ID for this user using the referrer querystring. | +| [setVisitorCookieTimeout(timeout, trackers)](./browser-tracker.setvisitorcookietimeout.md) | Set visitor cookie timeout (in seconds) | +| [trackPageView(event, trackers)](./browser-tracker.trackpageview.md) | Track a visit to a web page | +| [trackSelfDescribingEvent(event, trackers)](./browser-tracker.trackselfdescribingevent.md) | Track a self-describing event happening on this page. A custom event type, allowing for an event to be tracked using your own custom schema and a data object which conforms to the supplied schema | +| [trackStructEvent(event, trackers)](./browser-tracker.trackstructevent.md) | Track a structured event A classic style of event tracking, allows for easier movement between analytics systems. A loosely typed event, creating a Self Describing event is preferred, but useful for interoperability. | +| [updatePageActivity(trackers)](./browser-tracker.updatepageactivity.md) | Triggers the activityHandler manually to allow external user defined activity. i.e. While watching a video | + +## Interfaces + +| Interface | Description | +| --- | --- | +| [ActivityTrackingConfiguration](./browser-tracker.activitytrackingconfiguration.md) | The base configuration for activity tracking | +| [ActivityTrackingConfigurationCallback](./browser-tracker.activitytrackingconfigurationcallback.md) | The callback for enableActivityTrackingCallback | +| [BrowserPlugin](./browser-tracker.browserplugin.md) | Interface which defines Core Plugins | +| [BrowserPluginConfiguration](./browser-tracker.browserpluginconfiguration.md) | The configuration of the plugin to add | +| [BrowserTracker](./browser-tracker.browsertracker.md) | The Browser Tracker | +| [ClearUserDataConfiguration](./browser-tracker.clearuserdataconfiguration.md) | The configuration that can be changed when enabling anonymous tracking | +| [ClientSession](./browser-tracker.clientsession.md) | Schema for client client session context entity | +| [CommonEventProperties](./browser-tracker.commoneventproperties.md) | Additional data points to set when tracking an event | +| [ContextEvent](./browser-tracker.contextevent.md) | Argument for [ContextGenerator](./browser-tracker.contextgenerator.md) and [ContextFilter](./browser-tracker.contextfilter.md) callback | +| [CorePlugin](./browser-tracker.coreplugin.md) | Interface which defines Core Plugins | +| [CorePluginConfiguration](./browser-tracker.corepluginconfiguration.md) | The configuration of the plugin to add | +| [DeviceTimestamp](./browser-tracker.devicetimestamp.md) | A representation of a Device Timestamp (dtm) | +| [DisableAnonymousTrackingConfiguration](./browser-tracker.disableanonymoustrackingconfiguration.md) | The configuration that can be changed when disabling anonymous tracking | +| [EmitterConfigurationBase](./browser-tracker.emitterconfigurationbase.md) | | +| [EnableAnonymousTrackingConfiguration](./browser-tracker.enableanonymoustrackingconfiguration.md) | The configuration that can be changed when enabling anonymous tracking | +| [EventPayloadAndContext](./browser-tracker.eventpayloadandcontext.md) | Interface for returning a built event (PayloadBuilder) and context (Array of SelfDescribingJson). | +| [EventStore](./browser-tracker.eventstore.md) | EventStore allows storing and retrieving events before they are sent to the collector | +| [EventStoreConfiguration](./browser-tracker.eventstoreconfiguration.md) | | +| [EventStoreIterator](./browser-tracker.eventstoreiterator.md) | EventStoreIterator allows iterating over all events in the store. | +| [EventStorePayload](./browser-tracker.eventstorepayload.md) | | +| [FlushBufferConfiguration](./browser-tracker.flushbufferconfiguration.md) | The configuration that can be changed when flushing the buffer | +| [LocalStorageEventStoreConfigurationBase](./browser-tracker.localstorageeventstoreconfigurationbase.md) | | +| [Logger](./browser-tracker.logger.md) | | +| [PageViewEvent](./browser-tracker.pageviewevent.md) | A Page View event Used for tracking a page view | +| [PayloadBuilder](./browser-tracker.payloadbuilder.md) | Interface for mutable object encapsulating tracker payload | +| [RuleSet](./browser-tracker.ruleset.md) | A ruleset has accept or reject properties that contain rules for matching Iglu schema URIs | +| [SelfDescribingEvent](./browser-tracker.selfdescribingevent.md) | A Self Describing Event A custom event type, allowing for an event to be tracked using your own custom schema and a data object which conforms to the supplied schema | +| [StructuredEvent](./browser-tracker.structuredevent.md) | A Structured Event A classic style of event tracking, allows for easier movement between analytics systems. A loosely typed event, creating a Self Describing event is preferred, but useful for interoperability. | +| [TrackerCore](./browser-tracker.trackercore.md) | Export interface containing all Core functions | +| [TrueTimestamp](./browser-tracker.truetimestamp.md) | A representation of a True Timestamp (ttm) | + +## Variables + +| Variable | Description | +| --- | --- | +| [version](./browser-tracker.version.md) | | + +## Type Aliases + +| Type Alias | Description | +| --- | --- | +| [ActivityCallback](./browser-tracker.activitycallback.md) | The callback for enableActivityTrackingCallback | +| [ActivityCallbackData](./browser-tracker.activitycallbackdata.md) | The data which is passed to the Activity Tracking callback | +| [ActivityMetrics](./browser-tracker.activitymetrics.md) | Quantitative activity metrics accumulated between page pings. Attached as a context entity when activityMetrics is enabled. | +| [AnonymousTrackingOptions](./browser-tracker.anonymoustrackingoptions.md) | | +| [BuiltInContexts](./browser-tracker.builtincontexts.md) | | +| [ConditionalContextProvider](./browser-tracker.conditionalcontextprovider.md) | Conditional context providers are two element arrays used to decide when to attach contexts, where: - the first element is some conditional criterion - the second element is any number of context primitives | +| [ContextFilter](./browser-tracker.contextfilter.md) | A context filter is a user-supplied callback that is evaluated for each event to determine if the context associated with the filter should be attached to the event | +| [ContextGenerator](./browser-tracker.contextgenerator.md) | A context generator is a user-supplied callback that is evaluated for each event to allow an additional context to be dynamically attached to the event | +| [ContextPrimitive](./browser-tracker.contextprimitive.md) | A context primitive is either a self-describing JSON or a context generator | +| [CookieSameSite](./browser-tracker.cookiesamesite.md) | | +| [EventBatch](./browser-tracker.eventbatch.md) | A collection of event payloads which are sent to the collector. | +| [EventJson](./browser-tracker.eventjson.md) | An array of tuples which represents the unprocessed JSON to be added to the Payload | +| [EventMethod](./browser-tracker.eventmethod.md) | | +| [ExtendedCrossDomainLinkerAttributes](./browser-tracker.extendedcrossdomainlinkerattributes.md) | | +| [ExtendedCrossDomainLinkerOptions](./browser-tracker.extendedcrossdomainlinkeroptions.md) | | +| [FilterProvider](./browser-tracker.filterprovider.md) | A filter provider is a tuple that has two parts: a context filter and the context primitive(s) If the context filter evaluates to true, the tracker will attach the context primitive(s) | +| [JsonProcessor](./browser-tracker.jsonprocessor.md) | A function which will processor the Json onto the injected PayloadBuilder | +| [ParsedIdCookie](./browser-tracker.parsedidcookie.md) | The format of state elements stored in the id cookie. | +| [Payload](./browser-tracker.payload.md) | Type for a Payload dictionary | +| [Platform](./browser-tracker.platform.md) | | +| [PreservePageViewIdForUrl](./browser-tracker.preservepageviewidforurl.md) | | +| [RequestFailure](./browser-tracker.requestfailure.md) | The data that will be available to the onRequestFailure callback | +| [RuleSetProvider](./browser-tracker.rulesetprovider.md) | A ruleset provider is aa tuple that has two parts: a ruleset and the context primitive(s) If the ruleset allows the current event schema URI, the tracker will attach the context primitive(s) | +| [SelfDescribingJson](./browser-tracker.selfdescribingjson.md) | Export interface for any Self-Describing JSON such as context or Self Describing events | +| [StateStorageStrategy](./browser-tracker.statestoragestrategy.md) | | +| [Timestamp](./browser-tracker.timestamp.md) | Algebraic datatype representing possible timestamp type choice | +| [TrackerConfiguration](./browser-tracker.trackerconfiguration.md) | The configuration object for initialising the tracker | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.newsession.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.newsession.md new file mode 100644 index 000000000..c742a4f1d --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.newsession.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [newSession](./browser-tracker.newsession.md) + +## newSession() function + +Expires current session and starts a new session. + +Signature: + +```typescript +declare function newSession(trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| trackers | Array<string> | The tracker identifiers which will have their session refreshed | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.newtracker.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.newtracker.md new file mode 100644 index 000000000..23d477b89 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.newtracker.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [newTracker](./browser-tracker.newtracker.md) + +## newTracker() function + +Initialise a new tracker + +Signature: + +```typescript +declare function newTracker(trackerId: string, endpoint: string, configuration?: TrackerConfiguration): BrowserTracker | null | undefined; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| trackerId | string | The tracker id - also known as tracker namespace | +| endpoint | string | Collector endpoint in the form collector.mysite.com | +| configuration | TrackerConfiguration | The initialisation options of the tracker | + +Returns: + +BrowserTracker \| null \| undefined + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.pageviewevent.contextcallback.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.pageviewevent.contextcallback.md new file mode 100644 index 000000000..2da5fd1c0 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.pageviewevent.contextcallback.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [PageViewEvent](./browser-tracker.pageviewevent.md) > [contextCallback](./browser-tracker.pageviewevent.contextcallback.md) + +## PageViewEvent.contextCallback property + +A callback which will fire on the page view and each subsequent activity tracking event for this page view + +Signature: + +```typescript +contextCallback?: (() => Array) | null; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.pageviewevent.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.pageviewevent.md new file mode 100644 index 000000000..e000ce1c6 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.pageviewevent.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [PageViewEvent](./browser-tracker.pageviewevent.md) + +## PageViewEvent interface + +A Page View event Used for tracking a page view + +Signature: + +```typescript +interface PageViewEvent +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [contextCallback?](./browser-tracker.pageviewevent.contextcallback.md) | (() => Array<SelfDescribingJson>) \| null | (Optional) A callback which will fire on the page view and each subsequent activity tracking event for this page view | +| [title?](./browser-tracker.pageviewevent.title.md) | string \| null | (Optional) Override the page title | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.pageviewevent.title.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.pageviewevent.title.md new file mode 100644 index 000000000..0f42ddf6f --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.pageviewevent.title.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [PageViewEvent](./browser-tracker.pageviewevent.md) > [title](./browser-tracker.pageviewevent.title.md) + +## PageViewEvent.title property + +Override the page title + +Signature: + +```typescript +title?: string | null; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.parsedidcookie.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.parsedidcookie.md new file mode 100644 index 000000000..b3db25344 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.parsedidcookie.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [ParsedIdCookie](./browser-tracker.parsedidcookie.md) + +## ParsedIdCookie type + +The format of state elements stored in the `id` cookie. + +Signature: + +```typescript +type ParsedIdCookie = [ + cookieDisabled: string, + domainUserId: string, + cookieCreateTs: number, + visitCount: number, + nowTs: number, + lastVisitTs: number | undefined, + sessionId: string, + previousSessionId: string, + firstEventId: string, + firstEventTs: number | undefined, + eventIndex: number +]; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.payload.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.payload.md new file mode 100644 index 000000000..4945523b0 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.payload.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [Payload](./browser-tracker.payload.md) + +## Payload type + +Type for a Payload dictionary + +Signature: + +```typescript +type Payload = Record; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.add.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.add.md new file mode 100644 index 000000000..ce00b3ff6 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.add.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [PayloadBuilder](./browser-tracker.payloadbuilder.md) > [add](./browser-tracker.payloadbuilder.add.md) + +## PayloadBuilder.add property + +Adds an entry to the Payload + +Signature: + +```typescript +add: (key: string, value: unknown) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.addcontextentity.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.addcontextentity.md new file mode 100644 index 000000000..fc1f01521 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.addcontextentity.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [PayloadBuilder](./browser-tracker.payloadbuilder.md) > [addContextEntity](./browser-tracker.payloadbuilder.addcontextentity.md) + +## PayloadBuilder.addContextEntity property + +Caches a context entity to be added to payload on build + +Signature: + +```typescript +addContextEntity: (entity: SelfDescribingJson) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.adddict.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.adddict.md new file mode 100644 index 000000000..6ed310f3c --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.adddict.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [PayloadBuilder](./browser-tracker.payloadbuilder.md) > [addDict](./browser-tracker.payloadbuilder.adddict.md) + +## PayloadBuilder.addDict property + +Merges a payload into the existing payload + +Signature: + +```typescript +addDict: (dict: Payload) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.addjson.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.addjson.md new file mode 100644 index 000000000..c2cf712ef --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.addjson.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [PayloadBuilder](./browser-tracker.payloadbuilder.md) > [addJson](./browser-tracker.payloadbuilder.addjson.md) + +## PayloadBuilder.addJson property + +Caches a JSON object to be added to payload on build + +Signature: + +```typescript +addJson: (keyIfEncoded: string, keyIfNotEncoded: string, json: Record) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.build.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.build.md new file mode 100644 index 000000000..91752ffbb --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.build.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [PayloadBuilder](./browser-tracker.payloadbuilder.md) > [build](./browser-tracker.payloadbuilder.build.md) + +## PayloadBuilder.build property + +Builds and returns the Payload + +Signature: + +```typescript +build: () => Payload; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.getjson.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.getjson.md new file mode 100644 index 000000000..6431cbc03 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.getjson.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [PayloadBuilder](./browser-tracker.payloadbuilder.md) > [getJson](./browser-tracker.payloadbuilder.getjson.md) + +## PayloadBuilder.getJson property + +Gets all JSON objects added to payload + +Signature: + +```typescript +getJson: () => EventJson; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.getpayload.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.getpayload.md new file mode 100644 index 000000000..ca2e661da --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.getpayload.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [PayloadBuilder](./browser-tracker.payloadbuilder.md) > [getPayload](./browser-tracker.payloadbuilder.getpayload.md) + +## PayloadBuilder.getPayload property + +Gets the current payload, before cached JSON is processed + +Signature: + +```typescript +getPayload: () => Payload; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.md new file mode 100644 index 000000000..7c2106667 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.md @@ -0,0 +1,27 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [PayloadBuilder](./browser-tracker.payloadbuilder.md) + +## PayloadBuilder interface + +Interface for mutable object encapsulating tracker payload + +Signature: + +```typescript +interface PayloadBuilder +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [add](./browser-tracker.payloadbuilder.add.md) | (key: string, value: unknown) => void | Adds an entry to the Payload | +| [addContextEntity](./browser-tracker.payloadbuilder.addcontextentity.md) | (entity: SelfDescribingJson) => void | Caches a context entity to be added to payload on build | +| [addDict](./browser-tracker.payloadbuilder.adddict.md) | (dict: Payload) => void | Merges a payload into the existing payload | +| [addJson](./browser-tracker.payloadbuilder.addjson.md) | (keyIfEncoded: string, keyIfNotEncoded: string, json: Record<string, unknown>) => void | Caches a JSON object to be added to payload on build | +| [build](./browser-tracker.payloadbuilder.build.md) | () => Payload | Builds and returns the Payload | +| [getJson](./browser-tracker.payloadbuilder.getjson.md) | () => EventJson | Gets all JSON objects added to payload | +| [getPayload](./browser-tracker.payloadbuilder.getpayload.md) | () => Payload | Gets the current payload, before cached JSON is processed | +| [withJsonProcessor](./browser-tracker.payloadbuilder.withjsonprocessor.md) | (jsonProcessor: JsonProcessor) => void | Adds a function which will be executed when building the payload to process the JSON which has been added to this payload | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.withjsonprocessor.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.withjsonprocessor.md new file mode 100644 index 000000000..22fe2cd6f --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.payloadbuilder.withjsonprocessor.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [PayloadBuilder](./browser-tracker.payloadbuilder.md) > [withJsonProcessor](./browser-tracker.payloadbuilder.withjsonprocessor.md) + +## PayloadBuilder.withJsonProcessor property + +Adds a function which will be executed when building the payload to process the JSON which has been added to this payload + +Signature: + +```typescript +withJsonProcessor: (jsonProcessor: JsonProcessor) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.platform.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.platform.md new file mode 100644 index 000000000..505fdfb6b --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.platform.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [Platform](./browser-tracker.platform.md) + +## Platform type + +Signature: + +```typescript +type Platform = "web" | "mob" | "pc" | "srv" | "app" | "tv" | "cnsl" | "iot"; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.preservepageviewid.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.preservepageviewid.md new file mode 100644 index 000000000..decb1ef37 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.preservepageviewid.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [preservePageViewId](./browser-tracker.preservepageviewid.md) + +## preservePageViewId() function + +Stop regenerating `pageViewId` (available from `web_page` context) + +Signature: + +```typescript +declare function preservePageViewId(trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| trackers | Array<string> | The tracker identifiers which the event will preserve their Page View Ids | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.preservepageviewidforurl.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.preservepageviewidforurl.md new file mode 100644 index 000000000..d9acb5f32 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.preservepageviewidforurl.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [PreservePageViewIdForUrl](./browser-tracker.preservepageviewidforurl.md) + +## PreservePageViewIdForUrl type + +Signature: + +```typescript +type PreservePageViewIdForUrl = boolean | "full" | "pathname" | "pathnameAndSearch"; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.removeglobalcontexts.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.removeglobalcontexts.md new file mode 100644 index 000000000..508e042fd --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.removeglobalcontexts.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [removeGlobalContexts](./browser-tracker.removeglobalcontexts.md) + +## removeGlobalContexts() function + +All provided contexts will no longer be sent with every event + +Signature: + +```typescript +declare function removeGlobalContexts(contexts: Array, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| contexts | Array<ConditionalContextProvider \| ContextPrimitive \| string> | An array of contexts or conditional contexts | +| trackers | Array<string> | The tracker identifiers which the global contexts will be remove from | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.requestfailure.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.requestfailure.md new file mode 100644 index 000000000..17e23fa54 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.requestfailure.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [RequestFailure](./browser-tracker.requestfailure.md) + +## RequestFailure type + +The data that will be available to the `onRequestFailure` callback + +Signature: + +```typescript +type RequestFailure = { + events: EventBatch; + status?: number; + message?: string; + willRetry: boolean; +}; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.ruleset.accept.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.ruleset.accept.md new file mode 100644 index 000000000..28abb38b1 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.ruleset.accept.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [RuleSet](./browser-tracker.ruleset.md) > [accept](./browser-tracker.ruleset.accept.md) + +## RuleSet.accept property + +Signature: + +```typescript +accept?: Array | string; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.ruleset.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.ruleset.md new file mode 100644 index 000000000..8f2c10dae --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.ruleset.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [RuleSet](./browser-tracker.ruleset.md) + +## RuleSet interface + +A ruleset has accept or reject properties that contain rules for matching Iglu schema URIs + +Signature: + +```typescript +interface RuleSet +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [accept?](./browser-tracker.ruleset.accept.md) | Array<string> \| string | (Optional) | +| [reject?](./browser-tracker.ruleset.reject.md) | Array<string> \| string | (Optional) | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.ruleset.reject.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.ruleset.reject.md new file mode 100644 index 000000000..9e2266217 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.ruleset.reject.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [RuleSet](./browser-tracker.ruleset.md) > [reject](./browser-tracker.ruleset.reject.md) + +## RuleSet.reject property + +Signature: + +```typescript +reject?: Array | string; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.rulesetprovider.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.rulesetprovider.md new file mode 100644 index 000000000..e7d01aa97 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.rulesetprovider.md @@ -0,0 +1,16 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [RuleSetProvider](./browser-tracker.rulesetprovider.md) + +## RuleSetProvider type + +A ruleset provider is aa tuple that has two parts: a ruleset and the context primitive(s) If the ruleset allows the current event schema URI, the tracker will attach the context primitive(s) + +Signature: + +```typescript +type RuleSetProvider = [ + RuleSet, + Array | ContextPrimitive +]; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.selfdescribingevent.event.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.selfdescribingevent.event.md new file mode 100644 index 000000000..6c39ebd8b --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.selfdescribingevent.event.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [SelfDescribingEvent](./browser-tracker.selfdescribingevent.md) > [event](./browser-tracker.selfdescribingevent.event.md) + +## SelfDescribingEvent.event property + +The Self Describing JSON which describes the event + +Signature: + +```typescript +event: SelfDescribingJson; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.selfdescribingevent.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.selfdescribingevent.md new file mode 100644 index 000000000..32a77cd49 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.selfdescribingevent.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [SelfDescribingEvent](./browser-tracker.selfdescribingevent.md) + +## SelfDescribingEvent interface + +A Self Describing Event A custom event type, allowing for an event to be tracked using your own custom schema and a data object which conforms to the supplied schema + +Signature: + +```typescript +interface SelfDescribingEvent> +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [event](./browser-tracker.selfdescribingevent.event.md) | SelfDescribingJson<T> | The Self Describing JSON which describes the event | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.selfdescribingjson.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.selfdescribingjson.md new file mode 100644 index 000000000..6033c9791 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.selfdescribingjson.md @@ -0,0 +1,16 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [SelfDescribingJson](./browser-tracker.selfdescribingjson.md) + +## SelfDescribingJson type + +Export interface for any Self-Describing JSON such as context or Self Describing events + +Signature: + +```typescript +type SelfDescribingJson> = { + schema: string; + data: T extends any[] ? never : T extends {} ? T : never; +}; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.setbuffersize.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.setbuffersize.md new file mode 100644 index 000000000..d83956412 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.setbuffersize.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [setBufferSize](./browser-tracker.setbuffersize.md) + +## setBufferSize() function + +Set the buffer size Can be useful if you want to stop batching requests to ensure events start sending closer to event creation + +Signature: + +```typescript +declare function setBufferSize(newBufferSize: number, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| newBufferSize | number | The value with which to update the bufferSize to | +| trackers | Array<string> | The tracker identifiers which will be flushed | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.setcollectorurl.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.setcollectorurl.md new file mode 100644 index 000000000..6dd51922b --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.setcollectorurl.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [setCollectorUrl](./browser-tracker.setcollectorurl.md) + +## setCollectorUrl() function + +Specify the Snowplow collector URL. Specific http or https to force it or leave it off to match the website protocol. + +Signature: + +```typescript +declare function setCollectorUrl(collectorUrl: string, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| collectorUrl | string | The collector URL, with or without protocol | +| trackers | Array<string> | The tracker identifiers which will be configured | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.setcookiepath.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.setcookiepath.md new file mode 100644 index 000000000..b0b31007f --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.setcookiepath.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [setCookiePath](./browser-tracker.setcookiepath.md) + +## setCookiePath() function + +Set first-party cookie path + +Signature: + +```typescript +declare function setCookiePath(path: string, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| path | string | The path which will be used when setting cookies | +| trackers | Array<string> | The tracker identifiers which will be configured | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.setcustomurl.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.setcustomurl.md new file mode 100644 index 000000000..719371053 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.setcustomurl.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [setCustomUrl](./browser-tracker.setcustomurl.md) + +## setCustomUrl() function + +Override url + +Signature: + +```typescript +declare function setCustomUrl(url: string, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| url | string | Custom URL which will be used as override | +| trackers | Array<string> | The tracker identifiers which will be configured | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.setdocumenttitle.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.setdocumenttitle.md new file mode 100644 index 000000000..cda9b483b --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.setdocumenttitle.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [setDocumentTitle](./browser-tracker.setdocumenttitle.md) + +## setDocumentTitle() function + +Override document.title + +Signature: + +```typescript +declare function setDocumentTitle(title: string, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| title | string | Document title which will be used as override | +| trackers | Array<string> | The tracker identifiers which will be configured | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.setoptoutcookie.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.setoptoutcookie.md new file mode 100644 index 000000000..8b1e2487e --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.setoptoutcookie.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [setOptOutCookie](./browser-tracker.setoptoutcookie.md) + +## setOptOutCookie() function + +Sets the opt out cookie. + +Signature: + +```typescript +declare function setOptOutCookie(name?: string | null, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| name | string \| null | of the opt out cookie | +| trackers | Array<string> | The tracker identifiers which will be configured | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.setreferrerurl.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.setreferrerurl.md new file mode 100644 index 000000000..977d62641 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.setreferrerurl.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [setReferrerUrl](./browser-tracker.setreferrerurl.md) + +## setReferrerUrl() function + +Override referrer + +Signature: + +```typescript +declare function setReferrerUrl(url: string, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| url | string | Custom Referrer which will be used as override | +| trackers | Array<string> | The tracker identifiers which will be configured | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.setuserid.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.setuserid.md new file mode 100644 index 000000000..1125648b8 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.setuserid.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [setUserId](./browser-tracker.setuserid.md) + +## setUserId() function + +Set the business-defined user ID for this user. + +Signature: + +```typescript +declare function setUserId(userId?: string | null, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| userId | string \| null | The business-defined user ID | +| trackers | Array<string> | The tracker identifiers which will be configured | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.setuseridfromcookie.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.setuseridfromcookie.md new file mode 100644 index 000000000..4488feb9b --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.setuseridfromcookie.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [setUserIdFromCookie](./browser-tracker.setuseridfromcookie.md) + +## setUserIdFromCookie() function + +Set the business-defined user ID for this user to the value of a cookie. + +Signature: + +```typescript +declare function setUserIdFromCookie(cookieName: string, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| cookieName | string | Name of the cookie whose value will be assigned to businessUserId | +| trackers | Array<string> | The tracker identifiers which will be configured | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.setuseridfromlocation.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.setuseridfromlocation.md new file mode 100644 index 000000000..6c20f2593 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.setuseridfromlocation.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [setUserIdFromLocation](./browser-tracker.setuseridfromlocation.md) + +## setUserIdFromLocation() function + +Set the business-defined user ID for this user using the location querystring. + +Signature: + +```typescript +declare function setUserIdFromLocation(querystringField: string, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| querystringField | string | Name of a querystring name-value pair | +| trackers | Array<string> | The tracker identifiers which will be configured | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.setuseridfromreferrer.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.setuseridfromreferrer.md new file mode 100644 index 000000000..153aac1fa --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.setuseridfromreferrer.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [setUserIdFromReferrer](./browser-tracker.setuseridfromreferrer.md) + +## setUserIdFromReferrer() function + +Set the business-defined user ID for this user using the referrer querystring. + +Signature: + +```typescript +declare function setUserIdFromReferrer(querystringField: string, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| querystringField | string | Name of a querystring name-value pair | +| trackers | Array<string> | The tracker identifiers which will be configured | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.setvisitorcookietimeout.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.setvisitorcookietimeout.md new file mode 100644 index 000000000..ecc8211e0 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.setvisitorcookietimeout.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [setVisitorCookieTimeout](./browser-tracker.setvisitorcookietimeout.md) + +## setVisitorCookieTimeout() function + +Set visitor cookie timeout (in seconds) + +Signature: + +```typescript +declare function setVisitorCookieTimeout(timeout: number, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| timeout | number | The timeout until cookies will expire | +| trackers | Array<string> | The tracker identifiers which will be configured | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.sharedstate.bufferflushers.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.sharedstate.bufferflushers.md new file mode 100644 index 000000000..b5cb1d746 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.sharedstate.bufferflushers.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [SharedState](./browser-tracker.sharedstate.md) > [bufferFlushers](./browser-tracker.sharedstate.bufferflushers.md) + +## SharedState.bufferFlushers property + +Signature: + +```typescript +bufferFlushers: Array<(sync: boolean) => void>; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.sharedstate.hasloaded.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.sharedstate.hasloaded.md new file mode 100644 index 000000000..966754796 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.sharedstate.hasloaded.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [SharedState](./browser-tracker.sharedstate.md) > [hasLoaded](./browser-tracker.sharedstate.hasloaded.md) + +## SharedState.hasLoaded property + +Signature: + +```typescript +hasLoaded: boolean; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.sharedstate.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.sharedstate.md new file mode 100644 index 000000000..540c8e6d7 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.sharedstate.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [SharedState](./browser-tracker.sharedstate.md) + +## SharedState class + +A set of variables which are shared among all initialised trackers + +Signature: + +```typescript +declare class SharedState +``` + +## Properties + +| Property | Modifiers | Type | Description | +| --- | --- | --- | --- | +| [bufferFlushers](./browser-tracker.sharedstate.bufferflushers.md) | | Array<(sync: boolean) => void> | | +| [hasLoaded](./browser-tracker.sharedstate.hasloaded.md) | | boolean | | +| [pageViewId?](./browser-tracker.sharedstate.pageviewid.md) | | string | (Optional) | +| [pageViewUrl?](./browser-tracker.sharedstate.pageviewurl.md) | | string | (Optional) | +| [registeredOnLoadHandlers](./browser-tracker.sharedstate.registeredonloadhandlers.md) | | Array<() => void> | | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.sharedstate.pageviewid.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.sharedstate.pageviewid.md new file mode 100644 index 000000000..135e47ba4 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.sharedstate.pageviewid.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [SharedState](./browser-tracker.sharedstate.md) > [pageViewId](./browser-tracker.sharedstate.pageviewid.md) + +## SharedState.pageViewId property + +Signature: + +```typescript +pageViewId?: string; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.sharedstate.pageviewurl.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.sharedstate.pageviewurl.md new file mode 100644 index 000000000..c0981fed8 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.sharedstate.pageviewurl.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [SharedState](./browser-tracker.sharedstate.md) > [pageViewUrl](./browser-tracker.sharedstate.pageviewurl.md) + +## SharedState.pageViewUrl property + +Signature: + +```typescript +pageViewUrl?: string; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.sharedstate.registeredonloadhandlers.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.sharedstate.registeredonloadhandlers.md new file mode 100644 index 000000000..ae39bf4d2 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.sharedstate.registeredonloadhandlers.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [SharedState](./browser-tracker.sharedstate.md) > [registeredOnLoadHandlers](./browser-tracker.sharedstate.registeredonloadhandlers.md) + +## SharedState.registeredOnLoadHandlers property + +Signature: + +```typescript +registeredOnLoadHandlers: Array<() => void>; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.statestoragestrategy.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.statestoragestrategy.md new file mode 100644 index 000000000..9c0de57d0 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.statestoragestrategy.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [StateStorageStrategy](./browser-tracker.statestoragestrategy.md) + +## StateStorageStrategy type + +Signature: + +```typescript +type StateStorageStrategy = "cookieAndLocalStorage" | "cookie" | "localStorage" | "none"; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.structuredevent.action.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.structuredevent.action.md new file mode 100644 index 000000000..8193e5457 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.structuredevent.action.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [StructuredEvent](./browser-tracker.structuredevent.md) > [action](./browser-tracker.structuredevent.action.md) + +## StructuredEvent.action property + +Signature: + +```typescript +action: string; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.structuredevent.category.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.structuredevent.category.md new file mode 100644 index 000000000..d1866c275 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.structuredevent.category.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [StructuredEvent](./browser-tracker.structuredevent.md) > [category](./browser-tracker.structuredevent.category.md) + +## StructuredEvent.category property + +Signature: + +```typescript +category: string; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.structuredevent.label.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.structuredevent.label.md new file mode 100644 index 000000000..c11495ba8 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.structuredevent.label.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [StructuredEvent](./browser-tracker.structuredevent.md) > [label](./browser-tracker.structuredevent.label.md) + +## StructuredEvent.label property + +Signature: + +```typescript +label?: string; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.structuredevent.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.structuredevent.md new file mode 100644 index 000000000..3dcec4e55 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.structuredevent.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [StructuredEvent](./browser-tracker.structuredevent.md) + +## StructuredEvent interface + +A Structured Event A classic style of event tracking, allows for easier movement between analytics systems. A loosely typed event, creating a Self Describing event is preferred, but useful for interoperability. + +Signature: + +```typescript +interface StructuredEvent +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [action](./browser-tracker.structuredevent.action.md) | string | | +| [category](./browser-tracker.structuredevent.category.md) | string | | +| [label?](./browser-tracker.structuredevent.label.md) | string | (Optional) | +| [property?](./browser-tracker.structuredevent.property.md) | string | (Optional) | +| [value?](./browser-tracker.structuredevent.value.md) | number | (Optional) | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.structuredevent.property.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.structuredevent.property.md new file mode 100644 index 000000000..699772914 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.structuredevent.property.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [StructuredEvent](./browser-tracker.structuredevent.md) > [property](./browser-tracker.structuredevent.property.md) + +## StructuredEvent.property property + +Signature: + +```typescript +property?: string; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.structuredevent.value.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.structuredevent.value.md new file mode 100644 index 000000000..e9a0e1c78 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.structuredevent.value.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [StructuredEvent](./browser-tracker.structuredevent.md) > [value](./browser-tracker.structuredevent.value.md) + +## StructuredEvent.value property + +Signature: + +```typescript +value?: number; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.timestamp.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.timestamp.md new file mode 100644 index 000000000..efdf4bb5f --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.timestamp.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [Timestamp](./browser-tracker.timestamp.md) + +## Timestamp type + +Algebraic datatype representing possible timestamp type choice + +Signature: + +```typescript +type Timestamp = TrueTimestamp | DeviceTimestamp | number; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackerconfiguration.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackerconfiguration.md new file mode 100644 index 000000000..1bd565422 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackerconfiguration.md @@ -0,0 +1,52 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerConfiguration](./browser-tracker.trackerconfiguration.md) + +## TrackerConfiguration type + +The configuration object for initialising the tracker + +Signature: + +```typescript +type TrackerConfiguration = { + encodeBase64?: boolean; + cookieDomain?: string; + cookieName?: string; + cookieSameSite?: CookieSameSite; + cookieSecure?: boolean; + cookieLifetime?: number; + sessionCookieTimeout?: number; + appId?: string; + appVersion?: string; + platform?: Platform; + respectDoNotTrack?: boolean; + crossDomainLinker?: (elt: HTMLAnchorElement | HTMLAreaElement) => boolean; + useExtendedCrossDomainLinker?: ExtendedCrossDomainLinkerOptions; + discoverRootDomain?: boolean; + stateStorageStrategy?: StateStorageStrategy; + resetActivityTrackingOnPageView?: boolean; + anonymousTracking?: AnonymousTrackingOptions; + contexts?: BuiltInContexts; + plugins?: Array; + onSessionUpdateCallback?: (updatedSession: ClientSession) => void; + preservePageViewIdForUrl?: PreservePageViewIdForUrl; + preserveOriginalReferrer?: boolean; + synchronousCookieWrite?: boolean; + disableSessionContextWithinWebView?: boolean; +} & EmitterConfigurationBase & LocalStorageEventStoreConfigurationBase; +``` + +## Example + + +``` +newTracker('sp1', 'collector.my-website.com', { + appId: 'my-app-id', + platform: 'web', + plugins: [ PerformanceTimingPlugin(), AdTrackingPlugin() ], + stateStorageStrategy: 'cookieAndLocalStorage' +}); + +``` + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.addglobalcontexts.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.addglobalcontexts.md new file mode 100644 index 000000000..925862d4b --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.addglobalcontexts.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [addGlobalContexts](./browser-tracker.trackercore.addglobalcontexts.md) + +## TrackerCore.addGlobalContexts() method + +Adds contexts globally, contexts added here will be attached to all applicable events + +Signature: + +```typescript +addGlobalContexts(contexts: Array | Record): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| contexts | Array<ConditionalContextProvider \| ContextPrimitive> \| Record<string, ConditionalContextProvider \| ContextPrimitive> | An array containing either contexts or a conditional contexts | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.addpayloaddict.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.addpayloaddict.md new file mode 100644 index 000000000..563fac4d2 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.addpayloaddict.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [addPayloadDict](./browser-tracker.trackercore.addpayloaddict.md) + +## TrackerCore.addPayloadDict() method + +Merges a dictionary into payloadPairs + +Signature: + +```typescript +addPayloadDict(dict: Payload): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| dict | Payload | Adds a new payload dictionary to the existing one | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.addpayloadpair.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.addpayloadpair.md new file mode 100644 index 000000000..9fc6dcbac --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.addpayloadpair.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [addPayloadPair](./browser-tracker.trackercore.addpayloadpair.md) + +## TrackerCore.addPayloadPair property + +Set a persistent key-value pair to be added to every payload + +Signature: + +```typescript +addPayloadPair: (key: string, value: unknown) => void; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.addplugin.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.addplugin.md new file mode 100644 index 000000000..2de06867a --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.addplugin.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [addPlugin](./browser-tracker.trackercore.addplugin.md) + +## TrackerCore.addPlugin() method + +Add a plugin into the plugin collection after Core has already been initialised + +Signature: + +```typescript +addPlugin(configuration: CorePluginConfiguration): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| configuration | CorePluginConfiguration | The plugin to add | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.clearglobalcontexts.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.clearglobalcontexts.md new file mode 100644 index 000000000..bd9b8343a --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.clearglobalcontexts.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [clearGlobalContexts](./browser-tracker.trackercore.clearglobalcontexts.md) + +## TrackerCore.clearGlobalContexts() method + +Removes all global contexts + +Signature: + +```typescript +clearGlobalContexts(): void; +``` +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.deactivate.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.deactivate.md new file mode 100644 index 000000000..3a86b5b43 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.deactivate.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [deactivate](./browser-tracker.trackercore.deactivate.md) + +## TrackerCore.deactivate() method + +Deactivate tracker core including all plugins. This is useful for cleaning up resources or listeners that have been created. Once deactivated, the tracker won't be able to track any events. + +Signature: + +```typescript +deactivate(): void; +``` +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.getbase64encoding.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.getbase64encoding.md new file mode 100644 index 000000000..770ad00f3 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.getbase64encoding.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [getBase64Encoding](./browser-tracker.trackercore.getbase64encoding.md) + +## TrackerCore.getBase64Encoding() method + +Get current base64 encoding state + +Signature: + +```typescript +getBase64Encoding(): boolean; +``` +Returns: + +boolean + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.md new file mode 100644 index 000000000..f61d52fb9 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.md @@ -0,0 +1,47 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) + +## TrackerCore interface + +Export interface containing all Core functions + +Signature: + +```typescript +interface TrackerCore +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [addPayloadPair](./browser-tracker.trackercore.addpayloadpair.md) | (key: string, value: unknown) => void | Set a persistent key-value pair to be added to every payload | +| [track](./browser-tracker.trackercore.track.md) | (pb: PayloadBuilder, context?: Array<SelfDescribingJson> \| null, timestamp?: Timestamp \| null) => Payload \| undefined | Call with a payload from a buildX function Adds context and payloadPairs name-value pairs to the payload Applies the callback to the built payload | + +## Methods + +| Method | Description | +| --- | --- | +| [addGlobalContexts(contexts)](./browser-tracker.trackercore.addglobalcontexts.md) | Adds contexts globally, contexts added here will be attached to all applicable events | +| [addPayloadDict(dict)](./browser-tracker.trackercore.addpayloaddict.md) | Merges a dictionary into payloadPairs | +| [addPlugin(configuration)](./browser-tracker.trackercore.addplugin.md) | Add a plugin into the plugin collection after Core has already been initialised | +| [clearGlobalContexts()](./browser-tracker.trackercore.clearglobalcontexts.md) | Removes all global contexts | +| [deactivate()](./browser-tracker.trackercore.deactivate.md) | Deactivate tracker core including all plugins. This is useful for cleaning up resources or listeners that have been created. Once deactivated, the tracker won't be able to track any events. | +| [getBase64Encoding()](./browser-tracker.trackercore.getbase64encoding.md) | Get current base64 encoding state | +| [removeGlobalContexts(contexts)](./browser-tracker.trackercore.removeglobalcontexts.md) | Removes previously added global context, performs a deep comparison of the contexts or conditional contexts | +| [resetPayloadPairs(dict)](./browser-tracker.trackercore.resetpayloadpairs.md) | Replace payloadPairs with a new dictionary | +| [setAppId(appId)](./browser-tracker.trackercore.setappid.md) | Set the application ID | +| [setBase64Encoding(encode)](./browser-tracker.trackercore.setbase64encoding.md) | Turn base 64 encoding on or off | +| [setColorDepth(depth)](./browser-tracker.trackercore.setcolordepth.md) | Set the color depth | +| [setIpAddress(ip)](./browser-tracker.trackercore.setipaddress.md) | Set the IP address | +| [setLang(lang)](./browser-tracker.trackercore.setlang.md) | Set the language | +| [setPlatform(value)](./browser-tracker.trackercore.setplatform.md) | Set the platform | +| [setScreenResolution(width, height)](./browser-tracker.trackercore.setscreenresolution.md) | Set the screen resolution | +| [setTimezone(timezone)](./browser-tracker.trackercore.settimezone.md) | Set the timezone | +| [setTrackerNamespace(name)](./browser-tracker.trackercore.settrackernamespace.md) | Set the tracker namespace | +| [setTrackerVersion(version)](./browser-tracker.trackercore.settrackerversion.md) | Set the tracker version | +| [setUseragent(useragent)](./browser-tracker.trackercore.setuseragent.md) | Set the Useragent | +| [setUserId(userId)](./browser-tracker.trackercore.setuserid.md) | Set the user ID | +| [setViewport(width, height)](./browser-tracker.trackercore.setviewport.md) | Set the viewport dimensions | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.removeglobalcontexts.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.removeglobalcontexts.md new file mode 100644 index 000000000..c51dfc875 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.removeglobalcontexts.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [removeGlobalContexts](./browser-tracker.trackercore.removeglobalcontexts.md) + +## TrackerCore.removeGlobalContexts() method + +Removes previously added global context, performs a deep comparison of the contexts or conditional contexts + +Signature: + +```typescript +removeGlobalContexts(contexts: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| contexts | Array<ConditionalContextProvider \| ContextPrimitive \| string> | An array containing either contexts or a conditional contexts | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.resetpayloadpairs.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.resetpayloadpairs.md new file mode 100644 index 000000000..38cdb2aa0 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.resetpayloadpairs.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [resetPayloadPairs](./browser-tracker.trackercore.resetpayloadpairs.md) + +## TrackerCore.resetPayloadPairs() method + +Replace payloadPairs with a new dictionary + +Signature: + +```typescript +resetPayloadPairs(dict: Payload): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| dict | Payload | Resets all current payload pairs with a new dictionary of pairs | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setappid.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setappid.md new file mode 100644 index 000000000..48d91b448 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setappid.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [setAppId](./browser-tracker.trackercore.setappid.md) + +## TrackerCore.setAppId() method + +Set the application ID + +Signature: + +```typescript +setAppId(appId: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| appId | string | An application ID which identifies the current application | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setbase64encoding.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setbase64encoding.md new file mode 100644 index 000000000..e5cf71c7b --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setbase64encoding.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [setBase64Encoding](./browser-tracker.trackercore.setbase64encoding.md) + +## TrackerCore.setBase64Encoding() method + +Turn base 64 encoding on or off + +Signature: + +```typescript +setBase64Encoding(encode: boolean): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| encode | boolean | Whether to encode payload | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setcolordepth.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setcolordepth.md new file mode 100644 index 000000000..59579afc5 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setcolordepth.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [setColorDepth](./browser-tracker.trackercore.setcolordepth.md) + +## TrackerCore.setColorDepth() method + +Set the color depth + +Signature: + +```typescript +setColorDepth(depth: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| depth | string | A color depth value as string | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setipaddress.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setipaddress.md new file mode 100644 index 000000000..9b672d638 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setipaddress.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [setIpAddress](./browser-tracker.trackercore.setipaddress.md) + +## TrackerCore.setIpAddress() method + +Set the IP address + +Signature: + +```typescript +setIpAddress(ip: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| ip | string | An IP Address string | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setlang.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setlang.md new file mode 100644 index 000000000..83c102c68 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setlang.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [setLang](./browser-tracker.trackercore.setlang.md) + +## TrackerCore.setLang() method + +Set the language + +Signature: + +```typescript +setLang(lang: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| lang | string | A language string e.g. 'en-UK' | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setplatform.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setplatform.md new file mode 100644 index 000000000..0735af3eb --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setplatform.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [setPlatform](./browser-tracker.trackercore.setplatform.md) + +## TrackerCore.setPlatform() method + +Set the platform + +Signature: + +```typescript +setPlatform(value: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| value | string | A valid Snowplow platform value | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setscreenresolution.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setscreenresolution.md new file mode 100644 index 000000000..241e3a87e --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setscreenresolution.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [setScreenResolution](./browser-tracker.trackercore.setscreenresolution.md) + +## TrackerCore.setScreenResolution() method + +Set the screen resolution + +Signature: + +```typescript +setScreenResolution(width: string, height: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| width | string | screen resolution width | +| height | string | screen resolution height | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.settimezone.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.settimezone.md new file mode 100644 index 000000000..9e640137a --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.settimezone.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [setTimezone](./browser-tracker.trackercore.settimezone.md) + +## TrackerCore.setTimezone() method + +Set the timezone + +Signature: + +```typescript +setTimezone(timezone: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| timezone | string | A timezone string | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.settrackernamespace.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.settrackernamespace.md new file mode 100644 index 000000000..4e80c2925 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.settrackernamespace.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [setTrackerNamespace](./browser-tracker.trackercore.settrackernamespace.md) + +## TrackerCore.setTrackerNamespace() method + +Set the tracker namespace + +Signature: + +```typescript +setTrackerNamespace(name: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| name | string | The trackers namespace | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.settrackerversion.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.settrackerversion.md new file mode 100644 index 000000000..9ce4ebfef --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.settrackerversion.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [setTrackerVersion](./browser-tracker.trackercore.settrackerversion.md) + +## TrackerCore.setTrackerVersion() method + +Set the tracker version + +Signature: + +```typescript +setTrackerVersion(version: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| version | string | The version of the current tracker | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setuseragent.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setuseragent.md new file mode 100644 index 000000000..16fdf6146 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setuseragent.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [setUseragent](./browser-tracker.trackercore.setuseragent.md) + +## TrackerCore.setUseragent() method + +Set the Useragent + +Signature: + +```typescript +setUseragent(useragent: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| useragent | string | A useragent string | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setuserid.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setuserid.md new file mode 100644 index 000000000..09839a2b2 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setuserid.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [setUserId](./browser-tracker.trackercore.setuserid.md) + +## TrackerCore.setUserId() method + +Set the user ID + +Signature: + +```typescript +setUserId(userId: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| userId | string | The custom user id | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setviewport.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setviewport.md new file mode 100644 index 000000000..c0e0a6715 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.setviewport.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [setViewport](./browser-tracker.trackercore.setviewport.md) + +## TrackerCore.setViewport() method + +Set the viewport dimensions + +Signature: + +```typescript +setViewport(width: string, height: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| width | string | viewport width | +| height | string | viewport height | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.track.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.track.md new file mode 100644 index 000000000..1005c4f57 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackercore.track.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrackerCore](./browser-tracker.trackercore.md) > [track](./browser-tracker.trackercore.track.md) + +## TrackerCore.track property + +Call with a payload from a buildX function Adds context and payloadPairs name-value pairs to the payload Applies the callback to the built payload + +Signature: + +```typescript +track: (pb: PayloadBuilder, context?: Array | null, timestamp?: Timestamp | null) => Payload | undefined; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackpageview.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackpageview.md new file mode 100644 index 000000000..51118d1ee --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackpageview.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [trackPageView](./browser-tracker.trackpageview.md) + +## trackPageView() function + +Track a visit to a web page + +Signature: + +```typescript +declare function trackPageView(event?: PageViewEvent & CommonEventProperties, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | PageViewEvent & CommonEventProperties | The Page View Event properties | +| trackers | Array<string> | The tracker identifiers which the event will be sent to | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackselfdescribingevent.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackselfdescribingevent.md new file mode 100644 index 000000000..2a28d3206 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackselfdescribingevent.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [trackSelfDescribingEvent](./browser-tracker.trackselfdescribingevent.md) + +## trackSelfDescribingEvent() function + +Track a self-describing event happening on this page. A custom event type, allowing for an event to be tracked using your own custom schema and a data object which conforms to the supplied schema + +Signature: + +```typescript +declare function trackSelfDescribingEvent>(event: SelfDescribingEvent & CommonEventProperties, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | SelfDescribingEvent<T> & CommonEventProperties | The event information | +| trackers | Array<string> | The tracker identifiers which the event will be sent to | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.trackstructevent.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackstructevent.md new file mode 100644 index 000000000..78aa6efc3 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.trackstructevent.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [trackStructEvent](./browser-tracker.trackstructevent.md) + +## trackStructEvent() function + +Track a structured event A classic style of event tracking, allows for easier movement between analytics systems. A loosely typed event, creating a Self Describing event is preferred, but useful for interoperability. + +Signature: + +```typescript +declare function trackStructEvent(event: StructuredEvent & CommonEventProperties, trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | StructuredEvent & CommonEventProperties | The Structured Event properties | +| trackers | Array<string> | The tracker identifiers which the event will be sent to | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.truetimestamp.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.truetimestamp.md new file mode 100644 index 000000000..1618b6a01 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.truetimestamp.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrueTimestamp](./browser-tracker.truetimestamp.md) + +## TrueTimestamp interface + +A representation of a True Timestamp (ttm) + +Signature: + +```typescript +interface TrueTimestamp +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [type](./browser-tracker.truetimestamp.type.md) | "ttm" | | +| [value](./browser-tracker.truetimestamp.value.md) | number | | + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.truetimestamp.type.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.truetimestamp.type.md new file mode 100644 index 000000000..e5580ddad --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.truetimestamp.type.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrueTimestamp](./browser-tracker.truetimestamp.md) > [type](./browser-tracker.truetimestamp.type.md) + +## TrueTimestamp.type property + +Signature: + +```typescript +readonly type: "ttm"; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.truetimestamp.value.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.truetimestamp.value.md new file mode 100644 index 000000000..e795bb61a --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.truetimestamp.value.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [TrueTimestamp](./browser-tracker.truetimestamp.md) > [value](./browser-tracker.truetimestamp.value.md) + +## TrueTimestamp.value property + +Signature: + +```typescript +readonly value: number; +``` diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.updatepageactivity.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.updatepageactivity.md new file mode 100644 index 000000000..35145f5e7 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.updatepageactivity.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [updatePageActivity](./browser-tracker.updatepageactivity.md) + +## updatePageActivity() function + +Triggers the activityHandler manually to allow external user defined activity. i.e. While watching a video + +Signature: + +```typescript +declare function updatePageActivity(trackers?: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| trackers | Array<string> | The tracker identifiers which will be updated | + +Returns: + +void + diff --git a/api-docs/docs/browser-tracker/markdown/browser-tracker.version.md b/api-docs/docs/browser-tracker/markdown/browser-tracker.version.md new file mode 100644 index 000000000..b5a5925d0 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/browser-tracker.version.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/browser-tracker](./browser-tracker.md) > [version](./browser-tracker.version.md) + +## version variable + +Signature: + +```typescript +version: string +``` diff --git a/api-docs/docs/browser-tracker/markdown/index.md b/api-docs/docs/browser-tracker/markdown/index.md new file mode 100644 index 000000000..491a423d2 --- /dev/null +++ b/api-docs/docs/browser-tracker/markdown/index.md @@ -0,0 +1,12 @@ + + +[Home](./index.md) + +## API Reference + +## Packages + +| Package | Description | +| --- | --- | +| [@snowplow/browser-tracker](./browser-tracker.md) | | + diff --git a/api-docs/docs/index.md b/api-docs/docs/index.md new file mode 100644 index 000000000..8bf9f9e93 --- /dev/null +++ b/api-docs/docs/index.md @@ -0,0 +1,26 @@ +--- +sidebar_position: 1 +--- + +# JavaScript trackers +The Snowplow JavaScript trackers support being used in a number of environments. + +## Web tracking +We have two flavours of web tracker: JavaScript and Browser. + +- JavaScript tracker (v2, v3, and v4) for loading via tags, by adding code snippets to your website or Tag Manager solution. +- Browser tracker (v3 and v4) for installation into web apps via npm. Popular when natively integrating tracking into React, Angular and Vue applications. + +From v3 onwards, the JavaScript tracker is implemented as a wrapper around the Browser tracker. + +Find high-level documentation for both in the [Web trackers](https://docs.snowplow.io/docs/sources/trackers/web-trackers/) section. + +## Server-side tracking +Track events in server-side Node.js environments using the Node.js tracker (v3 and v4). Used via npm. + +Find high-level documentation in the [Node.js tracker](https://docs.snowplow.io/docs/sources/trackers/node-js-tracker/) section. + +## App tracking +Track events in React Native environments including mobile applications with the React Native tracker. + +Find high-level documentation in the [React Native tracker](https://docs.snowplow.io/docs/sources/trackers/react-native-tracker/) section. diff --git a/api-docs/docs/node-tracker/markdown/index.md b/api-docs/docs/node-tracker/markdown/index.md new file mode 100644 index 000000000..87f8bb7e7 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/index.md @@ -0,0 +1,12 @@ + + +[Home](./index.md) + +## API Reference + +## Packages + +| Package | Description | +| --- | --- | +| [@snowplow/node-tracker](./node-tracker.md) | | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.advertiserid.md b/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.advertiserid.md new file mode 100644 index 000000000..3e5e1c1f2 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.advertiserid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdClickEvent](./node-tracker.adclickevent.md) > [advertiserId](./node-tracker.adclickevent.advertiserid.md) + +## AdClickEvent.advertiserId property + +Identifier for the advertiser which the campaign belongs to + +Signature: + +```typescript +advertiserId?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.bannerid.md b/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.bannerid.md new file mode 100644 index 000000000..79afd60f4 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.bannerid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdClickEvent](./node-tracker.adclickevent.md) > [bannerId](./node-tracker.adclickevent.bannerid.md) + +## AdClickEvent.bannerId property + +Identifier for the ad banner being displayed + +Signature: + +```typescript +bannerId?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.campaignid.md b/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.campaignid.md new file mode 100644 index 000000000..4a067d9d9 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.campaignid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdClickEvent](./node-tracker.adclickevent.md) > [campaignId](./node-tracker.adclickevent.campaignid.md) + +## AdClickEvent.campaignId property + +Identifier for the advertiser which the campaign belongs to + +Signature: + +```typescript +campaignId?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.clickid.md b/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.clickid.md new file mode 100644 index 000000000..85816030e --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.clickid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdClickEvent](./node-tracker.adclickevent.md) > [clickId](./node-tracker.adclickevent.clickid.md) + +## AdClickEvent.clickId property + +Identifier for the particular click instance + +Signature: + +```typescript +clickId?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.cost.md b/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.cost.md new file mode 100644 index 000000000..18c8f7a07 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.cost.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdClickEvent](./node-tracker.adclickevent.md) > [cost](./node-tracker.adclickevent.cost.md) + +## AdClickEvent.cost property + +Advertisement cost + +Signature: + +```typescript +cost?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.costmodel.md b/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.costmodel.md new file mode 100644 index 000000000..d568b747c --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.costmodel.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdClickEvent](./node-tracker.adclickevent.md) > [costModel](./node-tracker.adclickevent.costmodel.md) + +## AdClickEvent.costModel property + +The cost model for the campaign + +Signature: + +```typescript +costModel?: "cpa" | "cpc" | "cpm"; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.impressionid.md b/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.impressionid.md new file mode 100644 index 000000000..8af82e525 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.impressionid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdClickEvent](./node-tracker.adclickevent.md) > [impressionId](./node-tracker.adclickevent.impressionid.md) + +## AdClickEvent.impressionId property + +Identifier for the particular impression instance + +Signature: + +```typescript +impressionId?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.md new file mode 100644 index 000000000..f7b092d92 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.md @@ -0,0 +1,32 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdClickEvent](./node-tracker.adclickevent.md) + +## AdClickEvent interface + +An Ad Click Event Used to track an advertisement click + +Signature: + +```typescript +interface AdClickEvent +``` + +## Remarks + +If you provide the cost field, you must also provide one of 'cpa', 'cpc', and 'cpm' for the costModel field. + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [advertiserId?](./node-tracker.adclickevent.advertiserid.md) | string | (Optional) Identifier for the advertiser which the campaign belongs to | +| [bannerId?](./node-tracker.adclickevent.bannerid.md) | string | (Optional) Identifier for the ad banner being displayed | +| [campaignId?](./node-tracker.adclickevent.campaignid.md) | string | (Optional) Identifier for the advertiser which the campaign belongs to | +| [clickId?](./node-tracker.adclickevent.clickid.md) | string | (Optional) Identifier for the particular click instance | +| [cost?](./node-tracker.adclickevent.cost.md) | number | (Optional) Advertisement cost | +| [costModel?](./node-tracker.adclickevent.costmodel.md) | "cpa" \| "cpc" \| "cpm" | (Optional) The cost model for the campaign | +| [impressionId?](./node-tracker.adclickevent.impressionid.md) | string | (Optional) Identifier for the particular impression instance | +| [targetUrl](./node-tracker.adclickevent.targeturl.md) | string | The destination URL of the advertisement | +| [zoneId?](./node-tracker.adclickevent.zoneid.md) | string | (Optional) Identifier for the zone where the ad banner is located | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.targeturl.md b/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.targeturl.md new file mode 100644 index 000000000..7da8c1ed8 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.targeturl.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdClickEvent](./node-tracker.adclickevent.md) > [targetUrl](./node-tracker.adclickevent.targeturl.md) + +## AdClickEvent.targetUrl property + +The destination URL of the advertisement + +Signature: + +```typescript +targetUrl: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.zoneid.md b/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.zoneid.md new file mode 100644 index 000000000..678870cf5 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adclickevent.zoneid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdClickEvent](./node-tracker.adclickevent.md) > [zoneId](./node-tracker.adclickevent.zoneid.md) + +## AdClickEvent.zoneId property + +Identifier for the zone where the ad banner is located + +Signature: + +```typescript +zoneId?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.action.md b/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.action.md new file mode 100644 index 000000000..7a4372493 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.action.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdConversionEvent](./node-tracker.adconversionevent.md) > [action](./node-tracker.adconversionevent.action.md) + +## AdConversionEvent.action property + +The type of user interaction e.g. 'purchase' + +Signature: + +```typescript +action?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.advertiserid.md b/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.advertiserid.md new file mode 100644 index 000000000..442ca64d4 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.advertiserid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdConversionEvent](./node-tracker.adconversionevent.md) > [advertiserId](./node-tracker.adconversionevent.advertiserid.md) + +## AdConversionEvent.advertiserId property + +Identifier for the advertiser which the campaign belongs to + +Signature: + +```typescript +advertiserId?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.campaignid.md b/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.campaignid.md new file mode 100644 index 000000000..052760288 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.campaignid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdConversionEvent](./node-tracker.adconversionevent.md) > [campaignId](./node-tracker.adconversionevent.campaignid.md) + +## AdConversionEvent.campaignId property + +Identifier for the advertiser which the campaign belongs to + +Signature: + +```typescript +campaignId?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.category.md b/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.category.md new file mode 100644 index 000000000..993a9384b --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.category.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdConversionEvent](./node-tracker.adconversionevent.md) > [category](./node-tracker.adconversionevent.category.md) + +## AdConversionEvent.category property + +Conversion category + +Signature: + +```typescript +category?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.conversionid.md b/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.conversionid.md new file mode 100644 index 000000000..714874194 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.conversionid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdConversionEvent](./node-tracker.adconversionevent.md) > [conversionId](./node-tracker.adconversionevent.conversionid.md) + +## AdConversionEvent.conversionId property + +Identifier for the particular conversion instance + +Signature: + +```typescript +conversionId?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.cost.md b/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.cost.md new file mode 100644 index 000000000..1745c1116 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.cost.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdConversionEvent](./node-tracker.adconversionevent.md) > [cost](./node-tracker.adconversionevent.cost.md) + +## AdConversionEvent.cost property + +Advertisement cost + +Signature: + +```typescript +cost?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.costmodel.md b/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.costmodel.md new file mode 100644 index 000000000..60ad5c84f --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.costmodel.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdConversionEvent](./node-tracker.adconversionevent.md) > [costModel](./node-tracker.adconversionevent.costmodel.md) + +## AdConversionEvent.costModel property + +The cost model for the campaign + +Signature: + +```typescript +costModel?: "cpa" | "cpc" | "cpm"; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.initialvalue.md b/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.initialvalue.md new file mode 100644 index 000000000..fc4d27d82 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.initialvalue.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdConversionEvent](./node-tracker.adconversionevent.md) > [initialValue](./node-tracker.adconversionevent.initialvalue.md) + +## AdConversionEvent.initialValue property + +How much the conversion is initially worth + +Signature: + +```typescript +initialValue?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.md new file mode 100644 index 000000000..c9fb83e7c --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.md @@ -0,0 +1,32 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdConversionEvent](./node-tracker.adconversionevent.md) + +## AdConversionEvent interface + +An Ad Conversion Event Used to track an advertisement click + +Signature: + +```typescript +interface AdConversionEvent +``` + +## Remarks + +If you provide the cost field, you must also provide one of 'cpa', 'cpc', and 'cpm' for the costModel field. + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [action?](./node-tracker.adconversionevent.action.md) | string | (Optional) The type of user interaction e.g. 'purchase' | +| [advertiserId?](./node-tracker.adconversionevent.advertiserid.md) | string | (Optional) Identifier for the advertiser which the campaign belongs to | +| [campaignId?](./node-tracker.adconversionevent.campaignid.md) | string | (Optional) Identifier for the advertiser which the campaign belongs to | +| [category?](./node-tracker.adconversionevent.category.md) | string | (Optional) Conversion category | +| [conversionId?](./node-tracker.adconversionevent.conversionid.md) | string | (Optional) Identifier for the particular conversion instance | +| [cost?](./node-tracker.adconversionevent.cost.md) | number | (Optional) Advertisement cost | +| [costModel?](./node-tracker.adconversionevent.costmodel.md) | "cpa" \| "cpc" \| "cpm" | (Optional) The cost model for the campaign | +| [initialValue?](./node-tracker.adconversionevent.initialvalue.md) | number | (Optional) How much the conversion is initially worth | +| [property?](./node-tracker.adconversionevent.property.md) | string | (Optional) Describes the object of the conversion | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.property.md b/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.property.md new file mode 100644 index 000000000..620fbd221 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adconversionevent.property.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdConversionEvent](./node-tracker.adconversionevent.md) > [property](./node-tracker.adconversionevent.property.md) + +## AdConversionEvent.property property + +Describes the object of the conversion + +Signature: + +```typescript +property?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.addtocartevent.category.md b/api-docs/docs/node-tracker/markdown/node-tracker.addtocartevent.category.md new file mode 100644 index 000000000..c673cc6da --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.addtocartevent.category.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AddToCartEvent](./node-tracker.addtocartevent.md) > [category](./node-tracker.addtocartevent.category.md) + +## AddToCartEvent.category property + +The category of the product + +Signature: + +```typescript +category?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.addtocartevent.currency.md b/api-docs/docs/node-tracker/markdown/node-tracker.addtocartevent.currency.md new file mode 100644 index 000000000..e039e4930 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.addtocartevent.currency.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AddToCartEvent](./node-tracker.addtocartevent.md) > [currency](./node-tracker.addtocartevent.currency.md) + +## AddToCartEvent.currency property + +The currency of the product + +Signature: + +```typescript +currency?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.addtocartevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.addtocartevent.md new file mode 100644 index 000000000..db24e8413 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.addtocartevent.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AddToCartEvent](./node-tracker.addtocartevent.md) + +## AddToCartEvent interface + +An Add To Cart Event For tracking users adding items from a cart on an ecommerce site. + +Signature: + +```typescript +interface AddToCartEvent +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [category?](./node-tracker.addtocartevent.category.md) | string | (Optional) The category of the product | +| [currency?](./node-tracker.addtocartevent.currency.md) | string | (Optional) The currency of the product | +| [name?](./node-tracker.addtocartevent.name.md) | string | (Optional) The name of the product | +| [quantity](./node-tracker.addtocartevent.quantity.md) | number | The number added to the cart | +| [sku](./node-tracker.addtocartevent.sku.md) | string | A Product Stock Keeping Unit (SKU) | +| [unitPrice?](./node-tracker.addtocartevent.unitprice.md) | number | (Optional) The price of the product | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.addtocartevent.name.md b/api-docs/docs/node-tracker/markdown/node-tracker.addtocartevent.name.md new file mode 100644 index 000000000..ee05beaa6 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.addtocartevent.name.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AddToCartEvent](./node-tracker.addtocartevent.md) > [name](./node-tracker.addtocartevent.name.md) + +## AddToCartEvent.name property + +The name of the product + +Signature: + +```typescript +name?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.addtocartevent.quantity.md b/api-docs/docs/node-tracker/markdown/node-tracker.addtocartevent.quantity.md new file mode 100644 index 000000000..faa389463 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.addtocartevent.quantity.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AddToCartEvent](./node-tracker.addtocartevent.md) > [quantity](./node-tracker.addtocartevent.quantity.md) + +## AddToCartEvent.quantity property + +The number added to the cart + +Signature: + +```typescript +quantity: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.addtocartevent.sku.md b/api-docs/docs/node-tracker/markdown/node-tracker.addtocartevent.sku.md new file mode 100644 index 000000000..7812ee51e --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.addtocartevent.sku.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AddToCartEvent](./node-tracker.addtocartevent.md) > [sku](./node-tracker.addtocartevent.sku.md) + +## AddToCartEvent.sku property + +A Product Stock Keeping Unit (SKU) + +Signature: + +```typescript +sku: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.addtocartevent.unitprice.md b/api-docs/docs/node-tracker/markdown/node-tracker.addtocartevent.unitprice.md new file mode 100644 index 000000000..1004e0b41 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.addtocartevent.unitprice.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AddToCartEvent](./node-tracker.addtocartevent.md) > [unitPrice](./node-tracker.addtocartevent.unitprice.md) + +## AddToCartEvent.unitPrice property + +The price of the product + +Signature: + +```typescript +unitPrice?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.advertiserid.md b/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.advertiserid.md new file mode 100644 index 000000000..714669fd1 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.advertiserid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdImpressionEvent](./node-tracker.adimpressionevent.md) > [advertiserId](./node-tracker.adimpressionevent.advertiserid.md) + +## AdImpressionEvent.advertiserId property + +Identifier for the advertiser which the campaign belongs to + +Signature: + +```typescript +advertiserId?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.bannerid.md b/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.bannerid.md new file mode 100644 index 000000000..6abc38e9c --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.bannerid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdImpressionEvent](./node-tracker.adimpressionevent.md) > [bannerId](./node-tracker.adimpressionevent.bannerid.md) + +## AdImpressionEvent.bannerId property + +Identifier for the ad banner being displayed + +Signature: + +```typescript +bannerId?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.campaignid.md b/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.campaignid.md new file mode 100644 index 000000000..295fd04d9 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.campaignid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdImpressionEvent](./node-tracker.adimpressionevent.md) > [campaignId](./node-tracker.adimpressionevent.campaignid.md) + +## AdImpressionEvent.campaignId property + +Identifier for the advertiser which the campaign belongs to + +Signature: + +```typescript +campaignId?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.cost.md b/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.cost.md new file mode 100644 index 000000000..a44fd3ac0 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.cost.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdImpressionEvent](./node-tracker.adimpressionevent.md) > [cost](./node-tracker.adimpressionevent.cost.md) + +## AdImpressionEvent.cost property + +Advertisement cost + +Signature: + +```typescript +cost?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.costmodel.md b/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.costmodel.md new file mode 100644 index 000000000..976c9370a --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.costmodel.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdImpressionEvent](./node-tracker.adimpressionevent.md) > [costModel](./node-tracker.adimpressionevent.costmodel.md) + +## AdImpressionEvent.costModel property + +The cost model for the campaign + +Signature: + +```typescript +costModel?: "cpa" | "cpc" | "cpm"; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.impressionid.md b/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.impressionid.md new file mode 100644 index 000000000..1085dc7f1 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.impressionid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdImpressionEvent](./node-tracker.adimpressionevent.md) > [impressionId](./node-tracker.adimpressionevent.impressionid.md) + +## AdImpressionEvent.impressionId property + +Identifier for the particular impression instance + +Signature: + +```typescript +impressionId?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.md new file mode 100644 index 000000000..b1e09a8c9 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.md @@ -0,0 +1,31 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdImpressionEvent](./node-tracker.adimpressionevent.md) + +## AdImpressionEvent interface + +An Ad Impression Event Used to track an advertisement impression + +Signature: + +```typescript +interface AdImpressionEvent +``` + +## Remarks + +If you provide the cost field, you must also provide one of 'cpa', 'cpc', and 'cpm' for the costModel field. + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [advertiserId?](./node-tracker.adimpressionevent.advertiserid.md) | string | (Optional) Identifier for the advertiser which the campaign belongs to | +| [bannerId?](./node-tracker.adimpressionevent.bannerid.md) | string | (Optional) Identifier for the ad banner being displayed | +| [campaignId?](./node-tracker.adimpressionevent.campaignid.md) | string | (Optional) Identifier for the advertiser which the campaign belongs to | +| [cost?](./node-tracker.adimpressionevent.cost.md) | number | (Optional) Advertisement cost | +| [costModel?](./node-tracker.adimpressionevent.costmodel.md) | "cpa" \| "cpc" \| "cpm" | (Optional) The cost model for the campaign | +| [impressionId?](./node-tracker.adimpressionevent.impressionid.md) | string | (Optional) Identifier for the particular impression instance | +| [targetUrl?](./node-tracker.adimpressionevent.targeturl.md) | string | (Optional) The destination URL of the advertisement | +| [zoneId?](./node-tracker.adimpressionevent.zoneid.md) | string | (Optional) Identifier for the zone where the ad banner is located | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.targeturl.md b/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.targeturl.md new file mode 100644 index 000000000..969998014 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.targeturl.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdImpressionEvent](./node-tracker.adimpressionevent.md) > [targetUrl](./node-tracker.adimpressionevent.targeturl.md) + +## AdImpressionEvent.targetUrl property + +The destination URL of the advertisement + +Signature: + +```typescript +targetUrl?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.zoneid.md b/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.zoneid.md new file mode 100644 index 000000000..5a0f779e0 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.adimpressionevent.zoneid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [AdImpressionEvent](./node-tracker.adimpressionevent.md) > [zoneId](./node-tracker.adimpressionevent.zoneid.md) + +## AdImpressionEvent.zoneId property + +Identifier for the zone where the ad banner is located + +Signature: + +```typescript +zoneId?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.buildadclick.md b/api-docs/docs/node-tracker/markdown/node-tracker.buildadclick.md new file mode 100644 index 000000000..785a252c5 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.buildadclick.md @@ -0,0 +1,30 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [buildAdClick](./node-tracker.buildadclick.md) + +## buildAdClick() function + +Build a Ad Click Event Used to track an advertisement click + +Signature: + +```typescript +declare function buildAdClick(event: AdClickEvent): PayloadBuilder; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | AdClickEvent | Contains the properties for the Ad Click event | + +Returns: + +PayloadBuilder + +PayloadBuilder to be sent to + +## Remarks + +If you provide the cost field, you must also provide one of 'cpa', 'cpc', and 'cpm' for the costModel field. + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.buildadconversion.md b/api-docs/docs/node-tracker/markdown/node-tracker.buildadconversion.md new file mode 100644 index 000000000..03f7a9eff --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.buildadconversion.md @@ -0,0 +1,30 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [buildAdConversion](./node-tracker.buildadconversion.md) + +## buildAdConversion() function + +Build a Ad Conversion Event Used to track an advertisement click + +Signature: + +```typescript +declare function buildAdConversion(event: AdConversionEvent): PayloadBuilder; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | AdConversionEvent | Contains the properties for the Ad Conversion event | + +Returns: + +PayloadBuilder + +PayloadBuilder to be sent to + +## Remarks + +If you provide the cost field, you must also provide one of 'cpa', 'cpc', and 'cpm' for the costModel field. + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.buildaddtocart.md b/api-docs/docs/node-tracker/markdown/node-tracker.buildaddtocart.md new file mode 100644 index 000000000..d03b5d54f --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.buildaddtocart.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [buildAddToCart](./node-tracker.buildaddtocart.md) + +## buildAddToCart() function + +Build a Add To Cart Event For tracking users adding items from a cart on an ecommerce site. + +Signature: + +```typescript +declare function buildAddToCart(event: AddToCartEvent): PayloadBuilder; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | AddToCartEvent | Contains the properties for the Add To Cart event | + +Returns: + +PayloadBuilder + +PayloadBuilder to be sent to + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.buildadimpression.md b/api-docs/docs/node-tracker/markdown/node-tracker.buildadimpression.md new file mode 100644 index 000000000..69913bd47 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.buildadimpression.md @@ -0,0 +1,30 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [buildAdImpression](./node-tracker.buildadimpression.md) + +## buildAdImpression() function + +Build a Ad Impression Event Used to track an advertisement impression + +Signature: + +```typescript +declare function buildAdImpression(event: AdImpressionEvent): PayloadBuilder; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | AdImpressionEvent | Contains the properties for the Ad Impression event | + +Returns: + +PayloadBuilder + +PayloadBuilder to be sent to + +## Remarks + +If you provide the cost field, you must also provide one of 'cpa', 'cpc', and 'cpm' for the costModel field. + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.buildconsentgranted.md b/api-docs/docs/node-tracker/markdown/node-tracker.buildconsentgranted.md new file mode 100644 index 000000000..8ed40e118 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.buildconsentgranted.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [buildConsentGranted](./node-tracker.buildconsentgranted.md) + +## buildConsentGranted() function + +Build a Consent Granted Event Used for tracking when a user grants their consent + +Signature: + +```typescript +declare function buildConsentGranted(event: ConsentGrantedEvent): EventPayloadAndContext; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | ConsentGrantedEvent | Contains the properties for the Consent Granted event | + +Returns: + +EventPayloadAndContext + +An object containing the PayloadBuilder to be sent to and a 'consent\_document' context + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.buildconsentwithdrawn.md b/api-docs/docs/node-tracker/markdown/node-tracker.buildconsentwithdrawn.md new file mode 100644 index 000000000..1c1daff46 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.buildconsentwithdrawn.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [buildConsentWithdrawn](./node-tracker.buildconsentwithdrawn.md) + +## buildConsentWithdrawn() function + +Build a Consent Withdrawn Event Used for tracking when a user withdraws their consent + +Signature: + +```typescript +declare function buildConsentWithdrawn(event: ConsentWithdrawnEvent): EventPayloadAndContext; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | ConsentWithdrawnEvent | Contains the properties for the Consent Withdrawn event | + +Returns: + +EventPayloadAndContext + +An object containing the PayloadBuilder to be sent to and a 'consent\_document' context + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.buildecommercetransaction.md b/api-docs/docs/node-tracker/markdown/node-tracker.buildecommercetransaction.md new file mode 100644 index 000000000..3710ec68c --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.buildecommercetransaction.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [buildEcommerceTransaction](./node-tracker.buildecommercetransaction.md) + +## buildEcommerceTransaction() function + +Build an Ecommerce Transaction Event Allows for tracking common ecommerce events, this event is usually used when a consumer completes a transaction. + +Signature: + +```typescript +declare function buildEcommerceTransaction(event: EcommerceTransactionEvent): PayloadBuilder; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | EcommerceTransactionEvent | Contains the properties for the Ecommerce Transactoion event | + +Returns: + +PayloadBuilder + +PayloadBuilder to be sent to + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.buildecommercetransactionitem.md b/api-docs/docs/node-tracker/markdown/node-tracker.buildecommercetransactionitem.md new file mode 100644 index 000000000..6454fe481 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.buildecommercetransactionitem.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [buildEcommerceTransactionItem](./node-tracker.buildecommercetransactionitem.md) + +## buildEcommerceTransactionItem() function + +Build an Ecommerce Transaction Item Event Related to the [buildEcommerceTransaction()](./node-tracker.buildecommercetransaction.md) Each Ecommerce Transaction may contain one or more EcommerceTransactionItem events + +Signature: + +```typescript +declare function buildEcommerceTransactionItem(event: EcommerceTransactionItemEvent): PayloadBuilder; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | EcommerceTransactionItemEvent | Contains the properties for the Ecommerce Transaction Item event | + +Returns: + +PayloadBuilder + +PayloadBuilder to be sent to + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.buildformfocusorchange.md b/api-docs/docs/node-tracker/markdown/node-tracker.buildformfocusorchange.md new file mode 100644 index 000000000..2e85d8821 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.buildformfocusorchange.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [buildFormFocusOrChange](./node-tracker.buildformfocusorchange.md) + +## buildFormFocusOrChange() function + +Build a Form Focus or Change Form Event based on schema property When a user focuses on a form element or when a user makes a change to a form element. + +Signature: + +```typescript +declare function buildFormFocusOrChange(event: FormFocusOrChangeEvent): PayloadBuilder; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | FormFocusOrChangeEvent | Contains the properties for the Form Focus or Change Form event | + +Returns: + +PayloadBuilder + +PayloadBuilder to be sent to + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.buildformsubmission.md b/api-docs/docs/node-tracker/markdown/node-tracker.buildformsubmission.md new file mode 100644 index 000000000..7f25820d9 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.buildformsubmission.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [buildFormSubmission](./node-tracker.buildformsubmission.md) + +## buildFormSubmission() function + +Build a Form Submission Event Used to track when a user submits a form + +Signature: + +```typescript +declare function buildFormSubmission(event: FormSubmissionEvent): PayloadBuilder; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | FormSubmissionEvent | Contains the properties for the Form Submission event | + +Returns: + +PayloadBuilder + +PayloadBuilder to be sent to + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.buildlinkclick.md b/api-docs/docs/node-tracker/markdown/node-tracker.buildlinkclick.md new file mode 100644 index 000000000..0d93ee880 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.buildlinkclick.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [buildLinkClick](./node-tracker.buildlinkclick.md) + +## buildLinkClick() function + +Build a Link Click Event Used when a user clicks on a link on a webpage, typically an anchor tag `` + +Signature: + +```typescript +declare function buildLinkClick(event: LinkClickEvent): PayloadBuilder; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | LinkClickEvent | Contains the properties for the Link Click event | + +Returns: + +PayloadBuilder + +PayloadBuilder to be sent to + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.buildpageping.md b/api-docs/docs/node-tracker/markdown/node-tracker.buildpageping.md new file mode 100644 index 000000000..f72b55146 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.buildpageping.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [buildPagePing](./node-tracker.buildpageping.md) + +## buildPagePing() function + +Build a Page Ping Event Fires when activity tracking is enabled in the browser. Tracks same information as the last tracked Page View and includes scroll information from the current page view + +Signature: + +```typescript +declare function buildPagePing(event: PagePingEvent): PayloadBuilder; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | PagePingEvent | Contains the properties for the Page Ping event | + +Returns: + +PayloadBuilder + +PayloadBuilder to be sent to + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.buildpageview.md b/api-docs/docs/node-tracker/markdown/node-tracker.buildpageview.md new file mode 100644 index 000000000..25a198ad1 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.buildpageview.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [buildPageView](./node-tracker.buildpageview.md) + +## buildPageView() function + +Build a Page View Event Represents a Page View, which is typically fired as soon as possible when a web page is loaded within the users browser. Often also fired on "virtual page views" within Single Page Applications (SPA). + +Signature: + +```typescript +declare function buildPageView(event: PageViewEvent): PayloadBuilder; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | PageViewEvent | Contains the properties for the Page View event | + +Returns: + +PayloadBuilder + +PayloadBuilder to be sent to + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.buildremovefromcart.md b/api-docs/docs/node-tracker/markdown/node-tracker.buildremovefromcart.md new file mode 100644 index 000000000..d9aa28129 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.buildremovefromcart.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [buildRemoveFromCart](./node-tracker.buildremovefromcart.md) + +## buildRemoveFromCart() function + +Build a Remove From Cart Event For tracking users removing items from a cart on an ecommerce site. + +Signature: + +```typescript +declare function buildRemoveFromCart(event: RemoveFromCartEvent): PayloadBuilder; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | RemoveFromCartEvent | Contains the properties for the Remove From Cart event | + +Returns: + +PayloadBuilder + +PayloadBuilder to be sent to + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.buildscreenview.md b/api-docs/docs/node-tracker/markdown/node-tracker.buildscreenview.md new file mode 100644 index 000000000..8ead82eac --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.buildscreenview.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [buildScreenView](./node-tracker.buildscreenview.md) + +## buildScreenView() function + +Build a Scren View Event Similar to a Page View but less focused on typical web properties Often used for mobile applications as the user is presented with new views as they performance navigation events + +Signature: + +```typescript +declare function buildScreenView(event: ScreenViewEvent): PayloadBuilder; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | ScreenViewEvent | Contains the properties for the Screen View event. One or more properties must be included. | + +Returns: + +PayloadBuilder + +PayloadBuilder to be sent to + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.buildselfdescribingevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.buildselfdescribingevent.md new file mode 100644 index 000000000..4f293a24a --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.buildselfdescribingevent.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [buildSelfDescribingEvent](./node-tracker.buildselfdescribingevent.md) + +## buildSelfDescribingEvent() function + +Build a self-describing event A custom event type, allowing for an event to be tracked using your own custom schema and a data object which conforms to the supplied schema + +Signature: + +```typescript +declare function buildSelfDescribingEvent>(event: SelfDescribingEvent): PayloadBuilder; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | SelfDescribingEvent<T> | Contains the properties and schema location for the event | + +Returns: + +PayloadBuilder + +PayloadBuilder to be sent to + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.buildsitesearch.md b/api-docs/docs/node-tracker/markdown/node-tracker.buildsitesearch.md new file mode 100644 index 000000000..d974da411 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.buildsitesearch.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [buildSiteSearch](./node-tracker.buildsitesearch.md) + +## buildSiteSearch() function + +Build a Site Search Event Used when a user performs a search action on a page + +Signature: + +```typescript +declare function buildSiteSearch(event: SiteSearchEvent): PayloadBuilder; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | SiteSearchEvent | Contains the properties for the Site Search event | + +Returns: + +PayloadBuilder + +PayloadBuilder to be sent to + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.buildsocialinteraction.md b/api-docs/docs/node-tracker/markdown/node-tracker.buildsocialinteraction.md new file mode 100644 index 000000000..1fe5f8d23 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.buildsocialinteraction.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [buildSocialInteraction](./node-tracker.buildsocialinteraction.md) + +## buildSocialInteraction() function + +Build a Social Interaction Event Social tracking will be used to track the way users interact with Facebook, Twitter and Google + widgets e.g. to capture “like this” or “tweet this” events. + +Signature: + +```typescript +declare function buildSocialInteraction(event: SocialInteractionEvent): PayloadBuilder; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | SocialInteractionEvent | Contains the properties for the Social Interaction event | + +Returns: + +PayloadBuilder + +PayloadBuilder to be sent to + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.buildstructevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.buildstructevent.md new file mode 100644 index 000000000..a7d5ce436 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.buildstructevent.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [buildStructEvent](./node-tracker.buildstructevent.md) + +## buildStructEvent() function + +Build a Structured Event A classic style of event tracking, allows for easier movement between analytics systems. A loosely typed event, creating a Self Describing event is preferred, but useful for interoperability. + +Signature: + +```typescript +declare function buildStructEvent(event: StructuredEvent): PayloadBuilder; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| event | StructuredEvent | Contains the properties for the Structured event | + +Returns: + +PayloadBuilder + +PayloadBuilder to be sent to + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.conditionalcontextprovider.md b/api-docs/docs/node-tracker/markdown/node-tracker.conditionalcontextprovider.md new file mode 100644 index 000000000..4fea54096 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.conditionalcontextprovider.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ConditionalContextProvider](./node-tracker.conditionalcontextprovider.md) + +## ConditionalContextProvider type + +Conditional context providers are two element arrays used to decide when to attach contexts, where: - the first element is some conditional criterion - the second element is any number of context primitives + +Signature: + +```typescript +type ConditionalContextProvider = FilterProvider | RuleSetProvider; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.consentgrantedevent.description.md b/api-docs/docs/node-tracker/markdown/node-tracker.consentgrantedevent.description.md new file mode 100644 index 000000000..5a2897ce7 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.consentgrantedevent.description.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ConsentGrantedEvent](./node-tracker.consentgrantedevent.md) > [description](./node-tracker.consentgrantedevent.description.md) + +## ConsentGrantedEvent.description property + +Description of the document granting consent + +Signature: + +```typescript +description?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.consentgrantedevent.expiry.md b/api-docs/docs/node-tracker/markdown/node-tracker.consentgrantedevent.expiry.md new file mode 100644 index 000000000..7980124c9 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.consentgrantedevent.expiry.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ConsentGrantedEvent](./node-tracker.consentgrantedevent.md) > [expiry](./node-tracker.consentgrantedevent.expiry.md) + +## ConsentGrantedEvent.expiry property + +When the consent expires + +Signature: + +```typescript +expiry?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.consentgrantedevent.id.md b/api-docs/docs/node-tracker/markdown/node-tracker.consentgrantedevent.id.md new file mode 100644 index 000000000..e97adbf21 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.consentgrantedevent.id.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ConsentGrantedEvent](./node-tracker.consentgrantedevent.md) > [id](./node-tracker.consentgrantedevent.id.md) + +## ConsentGrantedEvent.id property + +Identifier for the document granting consent + +Signature: + +```typescript +id: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.consentgrantedevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.consentgrantedevent.md new file mode 100644 index 000000000..9a8ca92aa --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.consentgrantedevent.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ConsentGrantedEvent](./node-tracker.consentgrantedevent.md) + +## ConsentGrantedEvent interface + +A Consent Granted Event Used for tracking when a user grants their consent + +Signature: + +```typescript +interface ConsentGrantedEvent +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [description?](./node-tracker.consentgrantedevent.description.md) | string | (Optional) Description of the document granting consent | +| [expiry?](./node-tracker.consentgrantedevent.expiry.md) | string | (Optional) When the consent expires | +| [id](./node-tracker.consentgrantedevent.id.md) | string | Identifier for the document granting consent | +| [name?](./node-tracker.consentgrantedevent.name.md) | string | (Optional) Name of the document granting consent | +| [version](./node-tracker.consentgrantedevent.version.md) | string | Version of the document granting consent | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.consentgrantedevent.name.md b/api-docs/docs/node-tracker/markdown/node-tracker.consentgrantedevent.name.md new file mode 100644 index 000000000..2f5c1717c --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.consentgrantedevent.name.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ConsentGrantedEvent](./node-tracker.consentgrantedevent.md) > [name](./node-tracker.consentgrantedevent.name.md) + +## ConsentGrantedEvent.name property + +Name of the document granting consent + +Signature: + +```typescript +name?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.consentgrantedevent.version.md b/api-docs/docs/node-tracker/markdown/node-tracker.consentgrantedevent.version.md new file mode 100644 index 000000000..f09fa300e --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.consentgrantedevent.version.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ConsentGrantedEvent](./node-tracker.consentgrantedevent.md) > [version](./node-tracker.consentgrantedevent.version.md) + +## ConsentGrantedEvent.version property + +Version of the document granting consent + +Signature: + +```typescript +version: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.consentwithdrawnevent.all.md b/api-docs/docs/node-tracker/markdown/node-tracker.consentwithdrawnevent.all.md new file mode 100644 index 000000000..214968a3a --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.consentwithdrawnevent.all.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ConsentWithdrawnEvent](./node-tracker.consentwithdrawnevent.md) > [all](./node-tracker.consentwithdrawnevent.all.md) + +## ConsentWithdrawnEvent.all property + +Specifies whether all consent should be withdrawn + +Signature: + +```typescript +all: boolean; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.consentwithdrawnevent.description.md b/api-docs/docs/node-tracker/markdown/node-tracker.consentwithdrawnevent.description.md new file mode 100644 index 000000000..721fd25f3 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.consentwithdrawnevent.description.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ConsentWithdrawnEvent](./node-tracker.consentwithdrawnevent.md) > [description](./node-tracker.consentwithdrawnevent.description.md) + +## ConsentWithdrawnEvent.description property + +Description of the document withdrawing consent + +Signature: + +```typescript +description?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.consentwithdrawnevent.id.md b/api-docs/docs/node-tracker/markdown/node-tracker.consentwithdrawnevent.id.md new file mode 100644 index 000000000..55ce74932 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.consentwithdrawnevent.id.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ConsentWithdrawnEvent](./node-tracker.consentwithdrawnevent.md) > [id](./node-tracker.consentwithdrawnevent.id.md) + +## ConsentWithdrawnEvent.id property + +Identifier for the document withdrawing consent + +Signature: + +```typescript +id?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.consentwithdrawnevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.consentwithdrawnevent.md new file mode 100644 index 000000000..83ea1e980 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.consentwithdrawnevent.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ConsentWithdrawnEvent](./node-tracker.consentwithdrawnevent.md) + +## ConsentWithdrawnEvent interface + +A Consent Withdrawn Event Used for tracking when a user withdraws their consent + +Signature: + +```typescript +interface ConsentWithdrawnEvent +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [all](./node-tracker.consentwithdrawnevent.all.md) | boolean | Specifies whether all consent should be withdrawn | +| [description?](./node-tracker.consentwithdrawnevent.description.md) | string | (Optional) Description of the document withdrawing consent | +| [id?](./node-tracker.consentwithdrawnevent.id.md) | string | (Optional) Identifier for the document withdrawing consent | +| [name?](./node-tracker.consentwithdrawnevent.name.md) | string | (Optional) Name of the document withdrawing consent | +| [version?](./node-tracker.consentwithdrawnevent.version.md) | string | (Optional) Version of the document withdrawing consent | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.consentwithdrawnevent.name.md b/api-docs/docs/node-tracker/markdown/node-tracker.consentwithdrawnevent.name.md new file mode 100644 index 000000000..eb924a795 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.consentwithdrawnevent.name.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ConsentWithdrawnEvent](./node-tracker.consentwithdrawnevent.md) > [name](./node-tracker.consentwithdrawnevent.name.md) + +## ConsentWithdrawnEvent.name property + +Name of the document withdrawing consent + +Signature: + +```typescript +name?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.consentwithdrawnevent.version.md b/api-docs/docs/node-tracker/markdown/node-tracker.consentwithdrawnevent.version.md new file mode 100644 index 000000000..557356eca --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.consentwithdrawnevent.version.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ConsentWithdrawnEvent](./node-tracker.consentwithdrawnevent.md) > [version](./node-tracker.consentwithdrawnevent.version.md) + +## ConsentWithdrawnEvent.version property + +Version of the document withdrawing consent + +Signature: + +```typescript +version?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.contextevent.event.md b/api-docs/docs/node-tracker/markdown/node-tracker.contextevent.event.md new file mode 100644 index 000000000..e7e6dacb8 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.contextevent.event.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ContextEvent](./node-tracker.contextevent.md) > [event](./node-tracker.contextevent.event.md) + +## ContextEvent.event property + +The event payload + +Signature: + +```typescript +event: Payload; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.contextevent.eventschema.md b/api-docs/docs/node-tracker/markdown/node-tracker.contextevent.eventschema.md new file mode 100644 index 000000000..6dfc354d8 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.contextevent.eventschema.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ContextEvent](./node-tracker.contextevent.md) > [eventSchema](./node-tracker.contextevent.eventschema.md) + +## ContextEvent.eventSchema property + +The event schema where one is available, or empty string + +Signature: + +```typescript +eventSchema: string; +``` + +## Example + +'iglu:com.snowplowanalytics.snowplow/ad\_impression/jsonschema/1-0-0' + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.contextevent.eventtype.md b/api-docs/docs/node-tracker/markdown/node-tracker.contextevent.eventtype.md new file mode 100644 index 000000000..ba6cc94cd --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.contextevent.eventtype.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ContextEvent](./node-tracker.contextevent.md) > [eventType](./node-tracker.contextevent.eventtype.md) + +## ContextEvent.eventType property + +The event type + +Signature: + +```typescript +eventType: string; +``` + +## Example + +'page\_view' + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.contextevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.contextevent.md new file mode 100644 index 000000000..1c30d7d74 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.contextevent.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ContextEvent](./node-tracker.contextevent.md) + +## ContextEvent interface + +Argument for [ContextGenerator](./node-tracker.contextgenerator.md) and [ContextFilter](./node-tracker.contextfilter.md) callback + +Signature: + +```typescript +interface ContextEvent +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [event](./node-tracker.contextevent.event.md) | Payload | The event payload | +| [eventSchema](./node-tracker.contextevent.eventschema.md) | string | The event schema where one is available, or empty string | +| [eventType](./node-tracker.contextevent.eventtype.md) | string | The event type | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.contextfilter.md b/api-docs/docs/node-tracker/markdown/node-tracker.contextfilter.md new file mode 100644 index 000000000..6285a22da --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.contextfilter.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ContextFilter](./node-tracker.contextfilter.md) + +## ContextFilter type + +A context filter is a user-supplied callback that is evaluated for each event to determine if the context associated with the filter should be attached to the event + +Signature: + +```typescript +type ContextFilter = (args?: ContextEvent) => boolean; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.contextgenerator.md b/api-docs/docs/node-tracker/markdown/node-tracker.contextgenerator.md new file mode 100644 index 000000000..1e2764916 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.contextgenerator.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ContextGenerator](./node-tracker.contextgenerator.md) + +## ContextGenerator type + +A context generator is a user-supplied callback that is evaluated for each event to allow an additional context to be dynamically attached to the event + +Signature: + +```typescript +type ContextGenerator = (args?: ContextEvent) => SelfDescribingJson | SelfDescribingJson[] | undefined; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.contextprimitive.md b/api-docs/docs/node-tracker/markdown/node-tracker.contextprimitive.md new file mode 100644 index 000000000..95819e7f0 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.contextprimitive.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ContextPrimitive](./node-tracker.contextprimitive.md) + +## ContextPrimitive type + +A context primitive is either a self-describing JSON or a context generator + +Signature: + +```typescript +type ContextPrimitive = SelfDescribingJson | ContextGenerator; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.coreconfiguration.base64.md b/api-docs/docs/node-tracker/markdown/node-tracker.coreconfiguration.base64.md new file mode 100644 index 000000000..fe7094e46 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.coreconfiguration.base64.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [CoreConfiguration](./node-tracker.coreconfiguration.md) > [base64](./node-tracker.coreconfiguration.base64.md) + +## CoreConfiguration.base64 property + +Signature: + +```typescript +base64?: boolean; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.coreconfiguration.callback.md b/api-docs/docs/node-tracker/markdown/node-tracker.coreconfiguration.callback.md new file mode 100644 index 000000000..56c5a063a --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.coreconfiguration.callback.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [CoreConfiguration](./node-tracker.coreconfiguration.md) > [callback](./node-tracker.coreconfiguration.callback.md) + +## CoreConfiguration.callback property + +Signature: + +```typescript +callback?: (PayloadData: PayloadBuilder) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.coreconfiguration.coreplugins.md b/api-docs/docs/node-tracker/markdown/node-tracker.coreconfiguration.coreplugins.md new file mode 100644 index 000000000..99bbd569d --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.coreconfiguration.coreplugins.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [CoreConfiguration](./node-tracker.coreconfiguration.md) > [corePlugins](./node-tracker.coreconfiguration.coreplugins.md) + +## CoreConfiguration.corePlugins property + +Signature: + +```typescript +corePlugins?: Array; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.coreconfiguration.md b/api-docs/docs/node-tracker/markdown/node-tracker.coreconfiguration.md new file mode 100644 index 000000000..1db83da79 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.coreconfiguration.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [CoreConfiguration](./node-tracker.coreconfiguration.md) + +## CoreConfiguration interface + +The configuration object for the tracker core library + +Signature: + +```typescript +interface CoreConfiguration +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [base64?](./node-tracker.coreconfiguration.base64.md) | boolean | (Optional) | +| [callback?](./node-tracker.coreconfiguration.callback.md) | (PayloadData: PayloadBuilder) => void | (Optional) | +| [corePlugins?](./node-tracker.coreconfiguration.coreplugins.md) | Array<CorePlugin> | (Optional) | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.activatecoreplugin.md b/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.activatecoreplugin.md new file mode 100644 index 000000000..0af3894f6 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.activatecoreplugin.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [CorePlugin](./node-tracker.coreplugin.md) > [activateCorePlugin](./node-tracker.coreplugin.activatecoreplugin.md) + +## CorePlugin.activateCorePlugin property + +Called when the plugin is initialised during the trackerCore construction + +Signature: + +```typescript +activateCorePlugin?: (core: TrackerCore) => void; +``` + +## Remarks + +Use to capture the specific core instance for each instance of a core plugin + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.aftertrack.md b/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.aftertrack.md new file mode 100644 index 000000000..e379642e3 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.aftertrack.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [CorePlugin](./node-tracker.coreplugin.md) > [afterTrack](./node-tracker.coreplugin.aftertrack.md) + +## CorePlugin.afterTrack property + +Called just after the trackerCore callback fires + +Signature: + +```typescript +afterTrack?: (payload: Payload) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.beforetrack.md b/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.beforetrack.md new file mode 100644 index 000000000..fb031028f --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.beforetrack.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [CorePlugin](./node-tracker.coreplugin.md) > [beforeTrack](./node-tracker.coreplugin.beforetrack.md) + +## CorePlugin.beforeTrack property + +Called before the `filter` method is called and before the trackerCore callback fires (if the filter passes) + +Signature: + +```typescript +beforeTrack?: (payloadBuilder: PayloadBuilder) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.contexts.md b/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.contexts.md new file mode 100644 index 000000000..9ae49b41e --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.contexts.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [CorePlugin](./node-tracker.coreplugin.md) > [contexts](./node-tracker.coreplugin.contexts.md) + +## CorePlugin.contexts property + +Called when constructing the context for each event Useful for adding additional context to events + +Signature: + +```typescript +contexts?: () => SelfDescribingJson[]; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.deactivateplugin.md b/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.deactivateplugin.md new file mode 100644 index 000000000..ea93f1c66 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.deactivateplugin.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [CorePlugin](./node-tracker.coreplugin.md) > [deactivatePlugin](./node-tracker.coreplugin.deactivateplugin.md) + +## CorePlugin.deactivatePlugin property + +Called when the tracker is being destroyed. Should be used to clean up any resources or listeners that the plugin has created. + +Signature: + +```typescript +deactivatePlugin?: (core: TrackerCore) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.filter.md b/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.filter.md new file mode 100644 index 000000000..4ce80a4f4 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.filter.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [CorePlugin](./node-tracker.coreplugin.md) > [filter](./node-tracker.coreplugin.filter.md) + +## CorePlugin.filter property + +Called before the payload is sent to the callback to decide whether to send the payload or skip it + +Signature: + +```typescript +filter?: (payload: Payload) => boolean; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.logger.md b/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.logger.md new file mode 100644 index 000000000..d2430b4c0 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.logger.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [CorePlugin](./node-tracker.coreplugin.md) > [logger](./node-tracker.coreplugin.logger.md) + +## CorePlugin.logger property + +Passed a logger instance which can be used to send log information to the active logger + +Signature: + +```typescript +logger?: (logger: Logger) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.md b/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.md new file mode 100644 index 000000000..65e4f9ae4 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.coreplugin.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [CorePlugin](./node-tracker.coreplugin.md) + +## CorePlugin interface + +Interface which defines Core Plugins + +Signature: + +```typescript +interface CorePlugin +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [activateCorePlugin?](./node-tracker.coreplugin.activatecoreplugin.md) | (core: TrackerCore) => void | (Optional) Called when the plugin is initialised during the trackerCore construction | +| [afterTrack?](./node-tracker.coreplugin.aftertrack.md) | (payload: Payload) => void | (Optional) Called just after the trackerCore callback fires | +| [beforeTrack?](./node-tracker.coreplugin.beforetrack.md) | (payloadBuilder: PayloadBuilder) => void | (Optional) Called before the filter method is called and before the trackerCore callback fires (if the filter passes) | +| [contexts?](./node-tracker.coreplugin.contexts.md) | () => SelfDescribingJson\[\] | (Optional) Called when constructing the context for each event Useful for adding additional context to events | +| [deactivatePlugin?](./node-tracker.coreplugin.deactivateplugin.md) | (core: TrackerCore) => void | (Optional) Called when the tracker is being destroyed. Should be used to clean up any resources or listeners that the plugin has created. | +| [filter?](./node-tracker.coreplugin.filter.md) | (payload: Payload) => boolean | (Optional) Called before the payload is sent to the callback to decide whether to send the payload or skip it | +| [logger?](./node-tracker.coreplugin.logger.md) | (logger: Logger) => void | (Optional) Passed a logger instance which can be used to send log information to the active logger | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.corepluginconfiguration.md b/api-docs/docs/node-tracker/markdown/node-tracker.corepluginconfiguration.md new file mode 100644 index 000000000..a224d4cc0 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.corepluginconfiguration.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [CorePluginConfiguration](./node-tracker.corepluginconfiguration.md) + +## CorePluginConfiguration interface + +The configuration of the plugin to add + +Signature: + +```typescript +interface CorePluginConfiguration +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [plugin](./node-tracker.corepluginconfiguration.plugin.md) | CorePlugin | | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.corepluginconfiguration.plugin.md b/api-docs/docs/node-tracker/markdown/node-tracker.corepluginconfiguration.plugin.md new file mode 100644 index 000000000..2aaa9bf92 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.corepluginconfiguration.plugin.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [CorePluginConfiguration](./node-tracker.corepluginconfiguration.md) > [plugin](./node-tracker.corepluginconfiguration.plugin.md) + +## CorePluginConfiguration.plugin property + +Signature: + +```typescript +plugin: CorePlugin; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.customemitter.md b/api-docs/docs/node-tracker/markdown/node-tracker.customemitter.md new file mode 100644 index 000000000..2d4fa82f9 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.customemitter.md @@ -0,0 +1,14 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [CustomEmitter](./node-tracker.customemitter.md) + +## CustomEmitter type + +Signature: + +```typescript +type CustomEmitter = { + /* Function returning custom Emitter or Emitter[] to be used. If set, other options are irrelevant */ + customEmitter: () => Emitter | Array; +}; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.devicetimestamp.md b/api-docs/docs/node-tracker/markdown/node-tracker.devicetimestamp.md new file mode 100644 index 000000000..f0a53829d --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.devicetimestamp.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [DeviceTimestamp](./node-tracker.devicetimestamp.md) + +## DeviceTimestamp interface + +A representation of a Device Timestamp (dtm) + +Signature: + +```typescript +interface DeviceTimestamp +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [type](./node-tracker.devicetimestamp.type.md) | "dtm" | | +| [value](./node-tracker.devicetimestamp.value.md) | number | | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.devicetimestamp.type.md b/api-docs/docs/node-tracker/markdown/node-tracker.devicetimestamp.type.md new file mode 100644 index 000000000..8e307ef38 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.devicetimestamp.type.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [DeviceTimestamp](./node-tracker.devicetimestamp.md) > [type](./node-tracker.devicetimestamp.type.md) + +## DeviceTimestamp.type property + +Signature: + +```typescript +readonly type: "dtm"; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.devicetimestamp.value.md b/api-docs/docs/node-tracker/markdown/node-tracker.devicetimestamp.value.md new file mode 100644 index 000000000..573fa64f2 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.devicetimestamp.value.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [DeviceTimestamp](./node-tracker.devicetimestamp.md) > [value](./node-tracker.devicetimestamp.value.md) + +## DeviceTimestamp.value property + +Signature: + +```typescript +readonly value: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.affiliation.md b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.affiliation.md new file mode 100644 index 000000000..d994df3ee --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.affiliation.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EcommerceTransactionEvent](./node-tracker.ecommercetransactionevent.md) > [affiliation](./node-tracker.ecommercetransactionevent.affiliation.md) + +## EcommerceTransactionEvent.affiliation property + +Transaction affiliation (e.g. store where sale took place) + +Signature: + +```typescript +affiliation?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.city.md b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.city.md new file mode 100644 index 000000000..b8782e255 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.city.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EcommerceTransactionEvent](./node-tracker.ecommercetransactionevent.md) > [city](./node-tracker.ecommercetransactionevent.city.md) + +## EcommerceTransactionEvent.city property + +Delivery address, city + +Signature: + +```typescript +city?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.country.md b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.country.md new file mode 100644 index 000000000..cadfddea4 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.country.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EcommerceTransactionEvent](./node-tracker.ecommercetransactionevent.md) > [country](./node-tracker.ecommercetransactionevent.country.md) + +## EcommerceTransactionEvent.country property + +Delivery address, country + +Signature: + +```typescript +country?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.currency.md b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.currency.md new file mode 100644 index 000000000..dc6658910 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.currency.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EcommerceTransactionEvent](./node-tracker.ecommercetransactionevent.md) > [currency](./node-tracker.ecommercetransactionevent.currency.md) + +## EcommerceTransactionEvent.currency property + +Currency of the transaction + +Signature: + +```typescript +currency?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.md new file mode 100644 index 000000000..4ad6238cc --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.md @@ -0,0 +1,28 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EcommerceTransactionEvent](./node-tracker.ecommercetransactionevent.md) + +## EcommerceTransactionEvent interface + +An Ecommerce Transaction Event Allows for tracking common ecommerce events, this event is usually used when a customer completes a transaction. + +Signature: + +```typescript +interface EcommerceTransactionEvent +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [affiliation?](./node-tracker.ecommercetransactionevent.affiliation.md) | string | (Optional) Transaction affiliation (e.g. store where sale took place) | +| [city?](./node-tracker.ecommercetransactionevent.city.md) | string | (Optional) Delivery address, city | +| [country?](./node-tracker.ecommercetransactionevent.country.md) | string | (Optional) Delivery address, country | +| [currency?](./node-tracker.ecommercetransactionevent.currency.md) | string | (Optional) Currency of the transaction | +| [orderId](./node-tracker.ecommercetransactionevent.orderid.md) | string | An identifier for the order | +| [shipping?](./node-tracker.ecommercetransactionevent.shipping.md) | number | (Optional) The amount of shipping costs for this transaction | +| [state?](./node-tracker.ecommercetransactionevent.state.md) | string | (Optional) Delivery address, state | +| [tax?](./node-tracker.ecommercetransactionevent.tax.md) | number | (Optional) The amount of tax on the transaction | +| [total](./node-tracker.ecommercetransactionevent.total.md) | number | The total value of the order | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.orderid.md b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.orderid.md new file mode 100644 index 000000000..d18cc0704 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.orderid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EcommerceTransactionEvent](./node-tracker.ecommercetransactionevent.md) > [orderId](./node-tracker.ecommercetransactionevent.orderid.md) + +## EcommerceTransactionEvent.orderId property + +An identifier for the order + +Signature: + +```typescript +orderId: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.shipping.md b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.shipping.md new file mode 100644 index 000000000..2c15dbec8 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.shipping.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EcommerceTransactionEvent](./node-tracker.ecommercetransactionevent.md) > [shipping](./node-tracker.ecommercetransactionevent.shipping.md) + +## EcommerceTransactionEvent.shipping property + +The amount of shipping costs for this transaction + +Signature: + +```typescript +shipping?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.state.md b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.state.md new file mode 100644 index 000000000..ab136f265 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.state.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EcommerceTransactionEvent](./node-tracker.ecommercetransactionevent.md) > [state](./node-tracker.ecommercetransactionevent.state.md) + +## EcommerceTransactionEvent.state property + +Delivery address, state + +Signature: + +```typescript +state?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.tax.md b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.tax.md new file mode 100644 index 000000000..59d0f6c6f --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.tax.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EcommerceTransactionEvent](./node-tracker.ecommercetransactionevent.md) > [tax](./node-tracker.ecommercetransactionevent.tax.md) + +## EcommerceTransactionEvent.tax property + +The amount of tax on the transaction + +Signature: + +```typescript +tax?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.total.md b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.total.md new file mode 100644 index 000000000..eec8b36bb --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionevent.total.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EcommerceTransactionEvent](./node-tracker.ecommercetransactionevent.md) > [total](./node-tracker.ecommercetransactionevent.total.md) + +## EcommerceTransactionEvent.total property + +The total value of the order + +Signature: + +```typescript +total: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.category.md b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.category.md new file mode 100644 index 000000000..565961252 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.category.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EcommerceTransactionItemEvent](./node-tracker.ecommercetransactionitemevent.md) > [category](./node-tracker.ecommercetransactionitemevent.category.md) + +## EcommerceTransactionItemEvent.category property + +The category the product belongs to + +Signature: + +```typescript +category?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.currency.md b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.currency.md new file mode 100644 index 000000000..9054c2e57 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.currency.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EcommerceTransactionItemEvent](./node-tracker.ecommercetransactionitemevent.md) > [currency](./node-tracker.ecommercetransactionitemevent.currency.md) + +## EcommerceTransactionItemEvent.currency property + +The currency of the product for the transaction + +Signature: + +```typescript +currency?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.md new file mode 100644 index 000000000..726b48866 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EcommerceTransactionItemEvent](./node-tracker.ecommercetransactionitemevent.md) + +## EcommerceTransactionItemEvent interface + +An Ecommerce Transaction Item Related to the [EcommerceTransactionEvent](./node-tracker.ecommercetransactionevent.md) Each Ecommerce Transaction may contain one or more EcommerceTransactionItem events + +Signature: + +```typescript +interface EcommerceTransactionItemEvent +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [category?](./node-tracker.ecommercetransactionitemevent.category.md) | string | (Optional) The category the product belongs to | +| [currency?](./node-tracker.ecommercetransactionitemevent.currency.md) | string | (Optional) The currency of the product for the transaction | +| [name?](./node-tracker.ecommercetransactionitemevent.name.md) | string | (Optional) The name of the product | +| [orderId](./node-tracker.ecommercetransactionitemevent.orderid.md) | string | An identifier for the order | +| [price](./node-tracker.ecommercetransactionitemevent.price.md) | number | The price of the product | +| [quantity?](./node-tracker.ecommercetransactionitemevent.quantity.md) | number | (Optional) The quanity of this product within the transaction | +| [sku](./node-tracker.ecommercetransactionitemevent.sku.md) | string | A Product Stock Keeping Unit (SKU) | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.name.md b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.name.md new file mode 100644 index 000000000..ea68d4a77 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.name.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EcommerceTransactionItemEvent](./node-tracker.ecommercetransactionitemevent.md) > [name](./node-tracker.ecommercetransactionitemevent.name.md) + +## EcommerceTransactionItemEvent.name property + +The name of the product + +Signature: + +```typescript +name?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.orderid.md b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.orderid.md new file mode 100644 index 000000000..e20a39c00 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.orderid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EcommerceTransactionItemEvent](./node-tracker.ecommercetransactionitemevent.md) > [orderId](./node-tracker.ecommercetransactionitemevent.orderid.md) + +## EcommerceTransactionItemEvent.orderId property + +An identifier for the order + +Signature: + +```typescript +orderId: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.price.md b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.price.md new file mode 100644 index 000000000..9cf674c15 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.price.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EcommerceTransactionItemEvent](./node-tracker.ecommercetransactionitemevent.md) > [price](./node-tracker.ecommercetransactionitemevent.price.md) + +## EcommerceTransactionItemEvent.price property + +The price of the product + +Signature: + +```typescript +price: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.quantity.md b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.quantity.md new file mode 100644 index 000000000..433b60092 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.quantity.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EcommerceTransactionItemEvent](./node-tracker.ecommercetransactionitemevent.md) > [quantity](./node-tracker.ecommercetransactionitemevent.quantity.md) + +## EcommerceTransactionItemEvent.quantity property + +The quanity of this product within the transaction + +Signature: + +```typescript +quantity?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.sku.md b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.sku.md new file mode 100644 index 000000000..3178268ed --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.ecommercetransactionitemevent.sku.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EcommerceTransactionItemEvent](./node-tracker.ecommercetransactionitemevent.md) > [sku](./node-tracker.ecommercetransactionitemevent.sku.md) + +## EcommerceTransactionItemEvent.sku property + +A Product Stock Keeping Unit (SKU) + +Signature: + +```typescript +sku: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitter.flush.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitter.flush.md new file mode 100644 index 000000000..a64176e70 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitter.flush.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [Emitter](./node-tracker.emitter.md) > [flush](./node-tracker.emitter.flush.md) + +## Emitter.flush property + +Forces the emitter to send all events in the event store to the collector. + +Signature: + +```typescript +flush: () => Promise; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitter.input.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitter.input.md new file mode 100644 index 000000000..562cf2ccf --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitter.input.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [Emitter](./node-tracker.emitter.md) > [input](./node-tracker.emitter.input.md) + +## Emitter.input property + +Adds a payload to the event store or sends it to the collector. + +Signature: + +```typescript +input: (payload: Payload) => Promise; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitter.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitter.md new file mode 100644 index 000000000..b09554040 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitter.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [Emitter](./node-tracker.emitter.md) + +## Emitter interface + +Emitter is responsible for sending events to the collector. It manages the event queue and sends events in batches depending on configuration. + +Signature: + +```typescript +interface Emitter +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [flush](./node-tracker.emitter.flush.md) | () => Promise<void> | Forces the emitter to send all events in the event store to the collector. | +| [input](./node-tracker.emitter.input.md) | (payload: Payload) => Promise<void> | Adds a payload to the event store or sends it to the collector. | +| [setAnonymousTracking](./node-tracker.emitter.setanonymoustracking.md) | (anonymous: boolean) => void | Sets the server anonymization flag. | +| [setBufferSize](./node-tracker.emitter.setbuffersize.md) | (bufferSize: number) => void | Updates the buffer size of the emitter. | +| [setCollectorUrl](./node-tracker.emitter.setcollectorurl.md) | (url: string) => void | Updates the collector URL to which events will be sent. | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitter.setanonymoustracking.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitter.setanonymoustracking.md new file mode 100644 index 000000000..bcaf2bafe --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitter.setanonymoustracking.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [Emitter](./node-tracker.emitter.md) > [setAnonymousTracking](./node-tracker.emitter.setanonymoustracking.md) + +## Emitter.setAnonymousTracking property + +Sets the server anonymization flag. + +Signature: + +```typescript +setAnonymousTracking: (anonymous: boolean) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitter.setbuffersize.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitter.setbuffersize.md new file mode 100644 index 000000000..8cee1c8fd --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitter.setbuffersize.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [Emitter](./node-tracker.emitter.md) > [setBufferSize](./node-tracker.emitter.setbuffersize.md) + +## Emitter.setBufferSize property + +Updates the buffer size of the emitter. + +Signature: + +```typescript +setBufferSize: (bufferSize: number) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitter.setcollectorurl.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitter.setcollectorurl.md new file mode 100644 index 000000000..ba73c3063 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitter.setcollectorurl.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [Emitter](./node-tracker.emitter.md) > [setCollectorUrl](./node-tracker.emitter.setcollectorurl.md) + +## Emitter.setCollectorUrl property + +Updates the collector URL to which events will be sent. + +Signature: + +```typescript +setCollectorUrl: (url: string) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfiguration.endpoint.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfiguration.endpoint.md new file mode 100644 index 000000000..45a7d2da4 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfiguration.endpoint.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfiguration](./node-tracker.emitterconfiguration.md) > [endpoint](./node-tracker.emitterconfiguration.endpoint.md) + +## EmitterConfiguration.endpoint property + +Signature: + +```typescript +endpoint: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfiguration.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfiguration.md new file mode 100644 index 000000000..44081c050 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfiguration.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfiguration](./node-tracker.emitterconfiguration.md) + +## EmitterConfiguration interface + +Signature: + +```typescript +interface EmitterConfiguration extends EmitterConfigurationBase +``` +Extends: EmitterConfigurationBase + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [endpoint](./node-tracker.emitterconfiguration.endpoint.md) | string | | +| [port?](./node-tracker.emitterconfiguration.port.md) | number | (Optional) | +| [protocol?](./node-tracker.emitterconfiguration.protocol.md) | "http" \| "https" | (Optional) | +| [serverAnonymization?](./node-tracker.emitterconfiguration.serveranonymization.md) | boolean | (Optional) | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfiguration.port.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfiguration.port.md new file mode 100644 index 000000000..0b9115e49 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfiguration.port.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfiguration](./node-tracker.emitterconfiguration.md) > [port](./node-tracker.emitterconfiguration.port.md) + +## EmitterConfiguration.port property + +Signature: + +```typescript +port?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfiguration.protocol.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfiguration.protocol.md new file mode 100644 index 000000000..53ddd4abb --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfiguration.protocol.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfiguration](./node-tracker.emitterconfiguration.md) > [protocol](./node-tracker.emitterconfiguration.protocol.md) + +## EmitterConfiguration.protocol property + +Signature: + +```typescript +protocol?: "http" | "https"; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfiguration.serveranonymization.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfiguration.serveranonymization.md new file mode 100644 index 000000000..99c586940 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfiguration.serveranonymization.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfiguration](./node-tracker.emitterconfiguration.md) > [serverAnonymization](./node-tracker.emitterconfiguration.serveranonymization.md) + +## EmitterConfiguration.serverAnonymization property + +Signature: + +```typescript +serverAnonymization?: boolean; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.buffersize.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.buffersize.md new file mode 100644 index 000000000..ddb5aa747 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.buffersize.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfigurationBase](./node-tracker.emitterconfigurationbase.md) > [bufferSize](./node-tracker.emitterconfigurationbase.buffersize.md) + +## EmitterConfigurationBase.bufferSize property + +The amount of events that should be buffered before sending Recommended to leave as 1 to reduce change of losing events + +Signature: + +```typescript +bufferSize?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.connectiontimeout.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.connectiontimeout.md new file mode 100644 index 000000000..3177ccdd8 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.connectiontimeout.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfigurationBase](./node-tracker.emitterconfigurationbase.md) > [connectionTimeout](./node-tracker.emitterconfigurationbase.connectiontimeout.md) + +## EmitterConfigurationBase.connectionTimeout property + +How long to wait before aborting requests to the collector + +Signature: + +```typescript +connectionTimeout?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.cookieextensionservice.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.cookieextensionservice.md new file mode 100644 index 000000000..4031cdaa4 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.cookieextensionservice.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfigurationBase](./node-tracker.emitterconfigurationbase.md) > [cookieExtensionService](./node-tracker.emitterconfigurationbase.cookieextensionservice.md) + +## EmitterConfigurationBase.cookieExtensionService property + +Cookie extension service full URL. This URL will be added to the queue and will be called using a GET method. This option is there to allow the service URL to be called in order to set any required identifiers e.g. extra cookies. + +The request respects the `anonymousTracking` option, including the SP-Anonymous header if needed, and any additional custom headers from the customHeaders option. + +Signature: + +```typescript +cookieExtensionService?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.credentials.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.credentials.md new file mode 100644 index 000000000..5535ee412 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.credentials.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfigurationBase](./node-tracker.emitterconfigurationbase.md) > [credentials](./node-tracker.emitterconfigurationbase.credentials.md) + +## EmitterConfigurationBase.credentials property + +Controls whether or not the browser sends credentials (defaults to 'include') + +Signature: + +```typescript +credentials?: "omit" | "same-origin" | "include"; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.customfetch.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.customfetch.md new file mode 100644 index 000000000..568ece696 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.customfetch.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfigurationBase](./node-tracker.emitterconfigurationbase.md) > [customFetch](./node-tracker.emitterconfigurationbase.customfetch.md) + +## EmitterConfigurationBase.customFetch property + +Enables overriding the default fetch function with a custom implementation. + +Signature: + +```typescript +customFetch?: (input: Request, options?: RequestInit) => Promise; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.customheaders.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.customheaders.md new file mode 100644 index 000000000..a143554d3 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.customheaders.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfigurationBase](./node-tracker.emitterconfigurationbase.md) > [customHeaders](./node-tracker.emitterconfigurationbase.customheaders.md) + +## EmitterConfigurationBase.customHeaders property + +An object of key value pairs which represent headers to attach when sending a POST request, only works for POST + +Signature: + +```typescript +customHeaders?: Record; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.dontretrystatuscodes.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.dontretrystatuscodes.md new file mode 100644 index 000000000..ffc915ec3 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.dontretrystatuscodes.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfigurationBase](./node-tracker.emitterconfigurationbase.md) > [dontRetryStatusCodes](./node-tracker.emitterconfigurationbase.dontretrystatuscodes.md) + +## EmitterConfigurationBase.dontRetryStatusCodes property + +List of HTTP response status codes for which events sent to Collector should not be retried in future request. Only non-success status codes are considered (greater or equal to 300). The don't retry codes are only considered for GET and POST requests. By default, the tracker retries on all non-success status codes except for 400, 401, 403, 410, and 422 (these don't retry codes will remain even if you set your own `dontRetryStatusCodes` but can be changed using the `retryStatusCodes`). + +Signature: + +```typescript +dontRetryStatusCodes?: number[]; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.eventmethod.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.eventmethod.md new file mode 100644 index 000000000..cd30544bf --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.eventmethod.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfigurationBase](./node-tracker.emitterconfigurationbase.md) > [eventMethod](./node-tracker.emitterconfigurationbase.eventmethod.md) + +## EmitterConfigurationBase.eventMethod property + +The preferred technique to use to send events + +Signature: + +```typescript +eventMethod?: EventMethod; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.eventstore.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.eventstore.md new file mode 100644 index 000000000..eb6fbfaba --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.eventstore.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfigurationBase](./node-tracker.emitterconfigurationbase.md) > [eventStore](./node-tracker.emitterconfigurationbase.eventstore.md) + +## EmitterConfigurationBase.eventStore property + +Enables providing a custom EventStore implementation to store events before sending them to the collector. + +Signature: + +```typescript +eventStore?: EventStore; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.idservice.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.idservice.md new file mode 100644 index 000000000..8eee6aa69 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.idservice.md @@ -0,0 +1,16 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfigurationBase](./node-tracker.emitterconfigurationbase.md) > [idService](./node-tracker.emitterconfigurationbase.idservice.md) + +## EmitterConfigurationBase.idService property + +> Warning: This API is now obsolete. +> +> Use `cookieExtensionService` instead. +> + +Signature: + +```typescript +idService?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.keepalive.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.keepalive.md new file mode 100644 index 000000000..480135076 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.keepalive.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfigurationBase](./node-tracker.emitterconfigurationbase.md) > [keepalive](./node-tracker.emitterconfigurationbase.keepalive.md) + +## EmitterConfigurationBase.keepalive property + +Indicates that the request should be allowed to outlive the webpage that initiated it. Enables collector requests to complete even if the page is closed or navigated away from. Note: Browsers put a limit on keepalive requests of 64KB. In case of multiple keepalive requests in parallel (may happen in case of multiple trackers), the limit is shared. + +Signature: + +```typescript +keepalive?: boolean; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.maxgetbytes.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.maxgetbytes.md new file mode 100644 index 000000000..cba914977 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.maxgetbytes.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfigurationBase](./node-tracker.emitterconfigurationbase.md) > [maxGetBytes](./node-tracker.emitterconfigurationbase.maxgetbytes.md) + +## EmitterConfigurationBase.maxGetBytes property + +The max size a GET request (its complete URL) can be. Requests over this size will be tried as a POST request. + +Signature: + +```typescript +maxGetBytes?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.maxpostbytes.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.maxpostbytes.md new file mode 100644 index 000000000..8cdcf05b5 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.maxpostbytes.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfigurationBase](./node-tracker.emitterconfigurationbase.md) > [maxPostBytes](./node-tracker.emitterconfigurationbase.maxpostbytes.md) + +## EmitterConfigurationBase.maxPostBytes property + +The max size a POST request can be before the tracker will force send it Also dictates the max size of a POST request before a batch of events is split into multiple requests + +Signature: + +```typescript +maxPostBytes?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.md new file mode 100644 index 000000000..637112285 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.md @@ -0,0 +1,36 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfigurationBase](./node-tracker.emitterconfigurationbase.md) + +## EmitterConfigurationBase interface + +Signature: + +```typescript +interface EmitterConfigurationBase +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [bufferSize?](./node-tracker.emitterconfigurationbase.buffersize.md) | number | (Optional) The amount of events that should be buffered before sending Recommended to leave as 1 to reduce change of losing events | +| [connectionTimeout?](./node-tracker.emitterconfigurationbase.connectiontimeout.md) | number | (Optional) How long to wait before aborting requests to the collector | +| [cookieExtensionService?](./node-tracker.emitterconfigurationbase.cookieextensionservice.md) | string | (Optional) Cookie extension service full URL. This URL will be added to the queue and will be called using a GET method. This option is there to allow the service URL to be called in order to set any required identifiers e.g. extra cookies.The request respects the anonymousTracking option, including the SP-Anonymous header if needed, and any additional custom headers from the customHeaders option. | +| [credentials?](./node-tracker.emitterconfigurationbase.credentials.md) | "omit" \| "same-origin" \| "include" | (Optional) Controls whether or not the browser sends credentials (defaults to 'include') | +| [customFetch?](./node-tracker.emitterconfigurationbase.customfetch.md) | (input: Request, options?: RequestInit) => Promise<Response> | (Optional) Enables overriding the default fetch function with a custom implementation. | +| [customHeaders?](./node-tracker.emitterconfigurationbase.customheaders.md) | Record<string, string> | (Optional) An object of key value pairs which represent headers to attach when sending a POST request, only works for POST | +| [dontRetryStatusCodes?](./node-tracker.emitterconfigurationbase.dontretrystatuscodes.md) | number\[\] | (Optional) List of HTTP response status codes for which events sent to Collector should not be retried in future request. Only non-success status codes are considered (greater or equal to 300). The don't retry codes are only considered for GET and POST requests. By default, the tracker retries on all non-success status codes except for 400, 401, 403, 410, and 422 (these don't retry codes will remain even if you set your own dontRetryStatusCodes but can be changed using the retryStatusCodes). | +| [eventMethod?](./node-tracker.emitterconfigurationbase.eventmethod.md) | EventMethod | (Optional) The preferred technique to use to send events | +| [eventStore?](./node-tracker.emitterconfigurationbase.eventstore.md) | EventStore | (Optional) Enables providing a custom EventStore implementation to store events before sending them to the collector. | +| [idService?](./node-tracker.emitterconfigurationbase.idservice.md) | string | (Optional) | +| [keepalive?](./node-tracker.emitterconfigurationbase.keepalive.md) | boolean | (Optional) Indicates that the request should be allowed to outlive the webpage that initiated it. Enables collector requests to complete even if the page is closed or navigated away from. Note: Browsers put a limit on keepalive requests of 64KB. In case of multiple keepalive requests in parallel (may happen in case of multiple trackers), the limit is shared. | +| [maxGetBytes?](./node-tracker.emitterconfigurationbase.maxgetbytes.md) | number | (Optional) The max size a GET request (its complete URL) can be. Requests over this size will be tried as a POST request. | +| [maxPostBytes?](./node-tracker.emitterconfigurationbase.maxpostbytes.md) | number | (Optional) The max size a POST request can be before the tracker will force send it Also dictates the max size of a POST request before a batch of events is split into multiple requests | +| [onRequestFailure?](./node-tracker.emitterconfigurationbase.onrequestfailure.md) | (data: RequestFailure, response?: Response) => void | (Optional) A callback function to be executed whenever a request fails to be sent to the collector. This is the inverse of the onRequestSuccess callback, so any non 2xx status code will trigger this callback. | +| [onRequestSuccess?](./node-tracker.emitterconfigurationbase.onrequestsuccess.md) | (data: EventBatch, response: Response) => void | (Optional) A callback function to be executed whenever a request is successfully sent to the collector. In practice this means any request which returns a 2xx status code will trigger this callback. | +| [postPath?](./node-tracker.emitterconfigurationbase.postpath.md) | string | (Optional) The post path which events will be sent to. Ensure your collector is configured to accept events on this post path | +| [retryFailedRequests?](./node-tracker.emitterconfigurationbase.retryfailedrequests.md) | boolean | (Optional) Whether to retry failed requests to the collector.Failed requests are requests that failed due to \[timeouts\](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/timeout\_event), \[network errors\](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/error\_event), and \[abort events\](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/abort\_event).Takes precedent over retryStatusCodes and dontRetryStatusCodes. | +| [retryStatusCodes?](./node-tracker.emitterconfigurationbase.retrystatuscodes.md) | number\[\] | (Optional) List of HTTP response status codes for which events sent to Collector should be retried in future requests. Only non-success status codes are considered (greater or equal to 300). The retry codes are only considered for GET and POST requests. They take priority over the dontRetryStatusCodes option. By default, the tracker retries on all non-success status codes except for 400, 401, 403, 410, and 422. | +| [useStm?](./node-tracker.emitterconfigurationbase.usestm.md) | boolean | (Optional) Should the Sent Timestamp be attached to events. Only applies for GET events. | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.onrequestfailure.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.onrequestfailure.md new file mode 100644 index 000000000..2ded72a24 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.onrequestfailure.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfigurationBase](./node-tracker.emitterconfigurationbase.md) > [onRequestFailure](./node-tracker.emitterconfigurationbase.onrequestfailure.md) + +## EmitterConfigurationBase.onRequestFailure property + +A callback function to be executed whenever a request fails to be sent to the collector. This is the inverse of the onRequestSuccess callback, so any non 2xx status code will trigger this callback. + +Signature: + +```typescript +onRequestFailure?: (data: RequestFailure, response?: Response) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.onrequestsuccess.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.onrequestsuccess.md new file mode 100644 index 000000000..6f117725e --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.onrequestsuccess.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfigurationBase](./node-tracker.emitterconfigurationbase.md) > [onRequestSuccess](./node-tracker.emitterconfigurationbase.onrequestsuccess.md) + +## EmitterConfigurationBase.onRequestSuccess property + +A callback function to be executed whenever a request is successfully sent to the collector. In practice this means any request which returns a 2xx status code will trigger this callback. + +Signature: + +```typescript +onRequestSuccess?: (data: EventBatch, response: Response) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.postpath.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.postpath.md new file mode 100644 index 000000000..58fc97c56 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.postpath.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfigurationBase](./node-tracker.emitterconfigurationbase.md) > [postPath](./node-tracker.emitterconfigurationbase.postpath.md) + +## EmitterConfigurationBase.postPath property + +The post path which events will be sent to. Ensure your collector is configured to accept events on this post path + +Signature: + +```typescript +postPath?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.retryfailedrequests.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.retryfailedrequests.md new file mode 100644 index 000000000..7a32a9f98 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.retryfailedrequests.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfigurationBase](./node-tracker.emitterconfigurationbase.md) > [retryFailedRequests](./node-tracker.emitterconfigurationbase.retryfailedrequests.md) + +## EmitterConfigurationBase.retryFailedRequests property + +Whether to retry failed requests to the collector. + +Failed requests are requests that failed due to \[timeouts\](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/timeout\_event), \[network errors\](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/error\_event), and \[abort events\](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/abort\_event). + +Takes precedent over `retryStatusCodes` and `dontRetryStatusCodes`. + +Signature: + +```typescript +retryFailedRequests?: boolean; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.retrystatuscodes.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.retrystatuscodes.md new file mode 100644 index 000000000..06dac5047 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.retrystatuscodes.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfigurationBase](./node-tracker.emitterconfigurationbase.md) > [retryStatusCodes](./node-tracker.emitterconfigurationbase.retrystatuscodes.md) + +## EmitterConfigurationBase.retryStatusCodes property + +List of HTTP response status codes for which events sent to Collector should be retried in future requests. Only non-success status codes are considered (greater or equal to 300). The retry codes are only considered for GET and POST requests. They take priority over the `dontRetryStatusCodes` option. By default, the tracker retries on all non-success status codes except for 400, 401, 403, 410, and 422. + +Signature: + +```typescript +retryStatusCodes?: number[]; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.usestm.md b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.usestm.md new file mode 100644 index 000000000..be353a69e --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.emitterconfigurationbase.usestm.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EmitterConfigurationBase](./node-tracker.emitterconfigurationbase.md) > [useStm](./node-tracker.emitterconfigurationbase.usestm.md) + +## EmitterConfigurationBase.useStm property + +Should the Sent Timestamp be attached to events. Only applies for GET events. + +Signature: + +```typescript +useStm?: boolean; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.eventbatch.md b/api-docs/docs/node-tracker/markdown/node-tracker.eventbatch.md new file mode 100644 index 000000000..c5d63edf2 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.eventbatch.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EventBatch](./node-tracker.eventbatch.md) + +## EventBatch type + +A collection of event payloads which are sent to the collector. + +Signature: + +```typescript +type EventBatch = Payload[]; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.eventjson.md b/api-docs/docs/node-tracker/markdown/node-tracker.eventjson.md new file mode 100644 index 000000000..573a64802 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.eventjson.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EventJson](./node-tracker.eventjson.md) + +## EventJson type + +An array of tuples which represents the unprocessed JSON to be added to the Payload + +Signature: + +```typescript +type EventJson = Array; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.eventjsonwithkeys.md b/api-docs/docs/node-tracker/markdown/node-tracker.eventjsonwithkeys.md new file mode 100644 index 000000000..39bfe8d8b --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.eventjsonwithkeys.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EventJsonWithKeys](./node-tracker.eventjsonwithkeys.md) + +## EventJsonWithKeys type + +A tuple which represents the unprocessed JSON to be added to the Payload + +Signature: + +```typescript +type EventJsonWithKeys = { + keyIfEncoded: string; + keyIfNotEncoded: string; + json: Record; +}; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.eventmethod.md b/api-docs/docs/node-tracker/markdown/node-tracker.eventmethod.md new file mode 100644 index 000000000..56f45e628 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.eventmethod.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EventMethod](./node-tracker.eventmethod.md) + +## EventMethod type + +Signature: + +```typescript +type EventMethod = "post" | "get"; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.eventpayloadandcontext.context.md b/api-docs/docs/node-tracker/markdown/node-tracker.eventpayloadandcontext.context.md new file mode 100644 index 000000000..450dac748 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.eventpayloadandcontext.context.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EventPayloadAndContext](./node-tracker.eventpayloadandcontext.md) > [context](./node-tracker.eventpayloadandcontext.context.md) + +## EventPayloadAndContext.context property + +List of context entities to track along with the event + +Signature: + +```typescript +context: Array; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.eventpayloadandcontext.event.md b/api-docs/docs/node-tracker/markdown/node-tracker.eventpayloadandcontext.event.md new file mode 100644 index 000000000..75e3aad07 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.eventpayloadandcontext.event.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EventPayloadAndContext](./node-tracker.eventpayloadandcontext.md) > [event](./node-tracker.eventpayloadandcontext.event.md) + +## EventPayloadAndContext.event property + +Tracker payload for the event data + +Signature: + +```typescript +event: PayloadBuilder; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.eventpayloadandcontext.md b/api-docs/docs/node-tracker/markdown/node-tracker.eventpayloadandcontext.md new file mode 100644 index 000000000..3f94b70a3 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.eventpayloadandcontext.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EventPayloadAndContext](./node-tracker.eventpayloadandcontext.md) + +## EventPayloadAndContext interface + +Interface for returning a built event (PayloadBuilder) and context (Array of SelfDescribingJson). + +Signature: + +```typescript +interface EventPayloadAndContext +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [context](./node-tracker.eventpayloadandcontext.context.md) | Array<SelfDescribingJson> | List of context entities to track along with the event | +| [event](./node-tracker.eventpayloadandcontext.event.md) | PayloadBuilder | Tracker payload for the event data | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.eventstore.add.md b/api-docs/docs/node-tracker/markdown/node-tracker.eventstore.add.md new file mode 100644 index 000000000..b63a8d256 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.eventstore.add.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EventStore](./node-tracker.eventstore.md) > [add](./node-tracker.eventstore.add.md) + +## EventStore.add property + +Add an event to the store + +Signature: + +```typescript +add: (payload: EventStorePayload) => Promise; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.eventstore.count.md b/api-docs/docs/node-tracker/markdown/node-tracker.eventstore.count.md new file mode 100644 index 000000000..cd321fb5a --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.eventstore.count.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EventStore](./node-tracker.eventstore.md) > [count](./node-tracker.eventstore.count.md) + +## EventStore.count property + +Count all events in the store + +Signature: + +```typescript +count: () => Promise; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.eventstore.getall.md b/api-docs/docs/node-tracker/markdown/node-tracker.eventstore.getall.md new file mode 100644 index 000000000..353635c20 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.eventstore.getall.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EventStore](./node-tracker.eventstore.md) > [getAll](./node-tracker.eventstore.getall.md) + +## EventStore.getAll property + +Retrieve all payloads including their meta configuration in the store + +Signature: + +```typescript +getAll: () => Promise; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.eventstore.getallpayloads.md b/api-docs/docs/node-tracker/markdown/node-tracker.eventstore.getallpayloads.md new file mode 100644 index 000000000..43bc85fb6 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.eventstore.getallpayloads.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EventStore](./node-tracker.eventstore.md) > [getAllPayloads](./node-tracker.eventstore.getallpayloads.md) + +## EventStore.getAllPayloads property + +Retrieve all pure payloads in the store + +Signature: + +```typescript +getAllPayloads: () => Promise; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.eventstore.iterator.md b/api-docs/docs/node-tracker/markdown/node-tracker.eventstore.iterator.md new file mode 100644 index 000000000..0eace0e1c --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.eventstore.iterator.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EventStore](./node-tracker.eventstore.md) > [iterator](./node-tracker.eventstore.iterator.md) + +## EventStore.iterator property + +Get an iterator over all events in the store + +Signature: + +```typescript +iterator: () => EventStoreIterator; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.eventstore.md b/api-docs/docs/node-tracker/markdown/node-tracker.eventstore.md new file mode 100644 index 000000000..88b86e7c4 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.eventstore.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EventStore](./node-tracker.eventstore.md) + +## EventStore interface + +EventStore allows storing and retrieving events before they are sent to the collector + +Signature: + +```typescript +interface EventStore +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [add](./node-tracker.eventstore.add.md) | (payload: EventStorePayload) => Promise<number> | Add an event to the store | +| [count](./node-tracker.eventstore.count.md) | () => Promise<number> | Count all events in the store | +| [getAll](./node-tracker.eventstore.getall.md) | () => Promise<readonly EventStorePayload\[\]> | Retrieve all payloads including their meta configuration in the store | +| [getAllPayloads](./node-tracker.eventstore.getallpayloads.md) | () => Promise<readonly Payload\[\]> | Retrieve all pure payloads in the store | +| [iterator](./node-tracker.eventstore.iterator.md) | () => EventStoreIterator | Get an iterator over all events in the store | +| [removeHead](./node-tracker.eventstore.removehead.md) | (count: number) => Promise<void> | Remove the first count events from the store | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.eventstore.removehead.md b/api-docs/docs/node-tracker/markdown/node-tracker.eventstore.removehead.md new file mode 100644 index 000000000..8bfe8ad87 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.eventstore.removehead.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EventStore](./node-tracker.eventstore.md) > [removeHead](./node-tracker.eventstore.removehead.md) + +## EventStore.removeHead property + +Remove the first `count` events from the store + +Signature: + +```typescript +removeHead: (count: number) => Promise; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.eventstoreconfiguration.maxsize.md b/api-docs/docs/node-tracker/markdown/node-tracker.eventstoreconfiguration.maxsize.md new file mode 100644 index 000000000..52aaa8357 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.eventstoreconfiguration.maxsize.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EventStoreConfiguration](./node-tracker.eventstoreconfiguration.md) > [maxSize](./node-tracker.eventstoreconfiguration.maxsize.md) + +## EventStoreConfiguration.maxSize property + +The maximum amount of events that will be buffered in the event store + +This is useful to ensure the Tracker doesn't fill the 5MB or 10MB available to each website should the collector be unavailable due to lost connectivity. Will drop old events once the limit is hit + +Signature: + +```typescript +maxSize?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.eventstoreconfiguration.md b/api-docs/docs/node-tracker/markdown/node-tracker.eventstoreconfiguration.md new file mode 100644 index 000000000..96bc0bee7 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.eventstoreconfiguration.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EventStoreConfiguration](./node-tracker.eventstoreconfiguration.md) + +## EventStoreConfiguration interface + +Signature: + +```typescript +interface EventStoreConfiguration +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [maxSize?](./node-tracker.eventstoreconfiguration.maxsize.md) | number | (Optional) The maximum amount of events that will be buffered in the event storeThis is useful to ensure the Tracker doesn't fill the 5MB or 10MB available to each website should the collector be unavailable due to lost connectivity. Will drop old events once the limit is hit | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.eventstoreiterator.md b/api-docs/docs/node-tracker/markdown/node-tracker.eventstoreiterator.md new file mode 100644 index 000000000..944e7f666 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.eventstoreiterator.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EventStoreIterator](./node-tracker.eventstoreiterator.md) + +## EventStoreIterator interface + +EventStoreIterator allows iterating over all events in the store. + +Signature: + +```typescript +interface EventStoreIterator +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [next](./node-tracker.eventstoreiterator.next.md) | () => Promise<EventStoreIteratorNextResult> | Retrieve the next event in the store | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.eventstoreiterator.next.md b/api-docs/docs/node-tracker/markdown/node-tracker.eventstoreiterator.next.md new file mode 100644 index 000000000..d1cd8e14e --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.eventstoreiterator.next.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EventStoreIterator](./node-tracker.eventstoreiterator.md) > [next](./node-tracker.eventstoreiterator.next.md) + +## EventStoreIterator.next property + +Retrieve the next event in the store + +Signature: + +```typescript +next: () => Promise; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.eventstorepayload.md b/api-docs/docs/node-tracker/markdown/node-tracker.eventstorepayload.md new file mode 100644 index 000000000..df0cbeeae --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.eventstorepayload.md @@ -0,0 +1,19 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EventStorePayload](./node-tracker.eventstorepayload.md) + +## EventStorePayload interface + +Signature: + +```typescript +interface EventStorePayload +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [payload](./node-tracker.eventstorepayload.payload.md) | Payload | The event payload to be stored | +| [svrAnon?](./node-tracker.eventstorepayload.svranon.md) | boolean | (Optional) If the request should undergo server anonymization. | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.eventstorepayload.payload.md b/api-docs/docs/node-tracker/markdown/node-tracker.eventstorepayload.payload.md new file mode 100644 index 000000000..208ebd71f --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.eventstorepayload.payload.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EventStorePayload](./node-tracker.eventstorepayload.md) > [payload](./node-tracker.eventstorepayload.payload.md) + +## EventStorePayload.payload property + +The event payload to be stored + +Signature: + +```typescript +payload: Payload; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.eventstorepayload.svranon.md b/api-docs/docs/node-tracker/markdown/node-tracker.eventstorepayload.svranon.md new file mode 100644 index 000000000..f35fbcff4 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.eventstorepayload.svranon.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [EventStorePayload](./node-tracker.eventstorepayload.md) > [svrAnon](./node-tracker.eventstorepayload.svranon.md) + +## EventStorePayload.svrAnon property + +If the request should undergo server anonymization. + +Signature: + +```typescript +svrAnon?: boolean; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.filterprovider.md b/api-docs/docs/node-tracker/markdown/node-tracker.filterprovider.md new file mode 100644 index 000000000..20ce14b69 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.filterprovider.md @@ -0,0 +1,16 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [FilterProvider](./node-tracker.filterprovider.md) + +## FilterProvider type + +A filter provider is a tuple that has two parts: a context filter and the context primitive(s) If the context filter evaluates to true, the tracker will attach the context primitive(s) + +Signature: + +```typescript +type FilterProvider = [ + ContextFilter, + Array | ContextPrimitive +]; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.formelement.md b/api-docs/docs/node-tracker/markdown/node-tracker.formelement.md new file mode 100644 index 000000000..1e8793c31 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.formelement.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [FormElement](./node-tracker.formelement.md) + +## FormElement type + +A representation of an element within a form + +Signature: + +```typescript +type FormElement = { + name: string; + value: string | null; + nodeName: string; + type?: string | null; +}; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.elementclasses.md b/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.elementclasses.md new file mode 100644 index 000000000..1a14e2505 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.elementclasses.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [FormFocusOrChangeEvent](./node-tracker.formfocusorchangeevent.md) > [elementClasses](./node-tracker.formfocusorchangeevent.elementclasses.md) + +## FormFocusOrChangeEvent.elementClasses property + +The class names on the element + +Signature: + +```typescript +elementClasses?: Array | null; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.elementid.md b/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.elementid.md new file mode 100644 index 000000000..17e6a12c2 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.elementid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [FormFocusOrChangeEvent](./node-tracker.formfocusorchangeevent.md) > [elementId](./node-tracker.formfocusorchangeevent.elementid.md) + +## FormFocusOrChangeEvent.elementId property + +The element ID which the user is interacting with + +Signature: + +```typescript +elementId: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.formid.md b/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.formid.md new file mode 100644 index 000000000..bd2f9d9b3 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.formid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [FormFocusOrChangeEvent](./node-tracker.formfocusorchangeevent.md) > [formId](./node-tracker.formfocusorchangeevent.formid.md) + +## FormFocusOrChangeEvent.formId property + +The ID of the form which the element belongs to + +Signature: + +```typescript +formId: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.md new file mode 100644 index 000000000..af684f575 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [FormFocusOrChangeEvent](./node-tracker.formfocusorchangeevent.md) + +## FormFocusOrChangeEvent interface + +Represents either a Form Focus or Form Change event When a user focuses on a form element or when a user makes a change to a form element. + +Signature: + +```typescript +interface FormFocusOrChangeEvent +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [elementClasses?](./node-tracker.formfocusorchangeevent.elementclasses.md) | Array<string> \| null | (Optional) The class names on the element | +| [elementId](./node-tracker.formfocusorchangeevent.elementid.md) | string | The element ID which the user is interacting with | +| [formId](./node-tracker.formfocusorchangeevent.formid.md) | string | The ID of the form which the element belongs to | +| [nodeName](./node-tracker.formfocusorchangeevent.nodename.md) | string | The name of the node ("INPUT", "TEXTAREA", "SELECT") | +| [schema](./node-tracker.formfocusorchangeevent.schema.md) | "change\_form" \| "focus\_form" | The schema which will be used for the event | +| [type?](./node-tracker.formfocusorchangeevent.type.md) | string \| null | (Optional) The type of element (e.g. "datetime", "text", "radio", etc.) | +| [value](./node-tracker.formfocusorchangeevent.value.md) | string \| null | The value of the element at the time of the event firing | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.nodename.md b/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.nodename.md new file mode 100644 index 000000000..74a541da3 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.nodename.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [FormFocusOrChangeEvent](./node-tracker.formfocusorchangeevent.md) > [nodeName](./node-tracker.formfocusorchangeevent.nodename.md) + +## FormFocusOrChangeEvent.nodeName property + +The name of the node ("INPUT", "TEXTAREA", "SELECT") + +Signature: + +```typescript +nodeName: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.schema.md b/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.schema.md new file mode 100644 index 000000000..247eb8ead --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.schema.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [FormFocusOrChangeEvent](./node-tracker.formfocusorchangeevent.md) > [schema](./node-tracker.formfocusorchangeevent.schema.md) + +## FormFocusOrChangeEvent.schema property + +The schema which will be used for the event + +Signature: + +```typescript +schema: "change_form" | "focus_form"; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.type.md b/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.type.md new file mode 100644 index 000000000..cc6feca41 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.type.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [FormFocusOrChangeEvent](./node-tracker.formfocusorchangeevent.md) > [type](./node-tracker.formfocusorchangeevent.type.md) + +## FormFocusOrChangeEvent.type property + +The type of element (e.g. "datetime", "text", "radio", etc.) + +Signature: + +```typescript +type?: string | null; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.value.md b/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.value.md new file mode 100644 index 000000000..a7f34f175 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.formfocusorchangeevent.value.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [FormFocusOrChangeEvent](./node-tracker.formfocusorchangeevent.md) > [value](./node-tracker.formfocusorchangeevent.value.md) + +## FormFocusOrChangeEvent.value property + +The value of the element at the time of the event firing + +Signature: + +```typescript +value: string | null; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.formsubmissionevent.elements.md b/api-docs/docs/node-tracker/markdown/node-tracker.formsubmissionevent.elements.md new file mode 100644 index 000000000..b8b5badaf --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.formsubmissionevent.elements.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [FormSubmissionEvent](./node-tracker.formsubmissionevent.md) > [elements](./node-tracker.formsubmissionevent.elements.md) + +## FormSubmissionEvent.elements property + +The elements contained within the form + +Signature: + +```typescript +elements?: Array; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.formsubmissionevent.formclasses.md b/api-docs/docs/node-tracker/markdown/node-tracker.formsubmissionevent.formclasses.md new file mode 100644 index 000000000..52bc3040a --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.formsubmissionevent.formclasses.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [FormSubmissionEvent](./node-tracker.formsubmissionevent.md) > [formClasses](./node-tracker.formsubmissionevent.formclasses.md) + +## FormSubmissionEvent.formClasses property + +The class names on the form + +Signature: + +```typescript +formClasses?: Array; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.formsubmissionevent.formid.md b/api-docs/docs/node-tracker/markdown/node-tracker.formsubmissionevent.formid.md new file mode 100644 index 000000000..c87c64433 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.formsubmissionevent.formid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [FormSubmissionEvent](./node-tracker.formsubmissionevent.md) > [formId](./node-tracker.formsubmissionevent.formid.md) + +## FormSubmissionEvent.formId property + +The ID of the form + +Signature: + +```typescript +formId: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.formsubmissionevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.formsubmissionevent.md new file mode 100644 index 000000000..10a9b5f82 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.formsubmissionevent.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [FormSubmissionEvent](./node-tracker.formsubmissionevent.md) + +## FormSubmissionEvent interface + +A Form Submission Event Used to track when a user submits a form + +Signature: + +```typescript +interface FormSubmissionEvent +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [elements?](./node-tracker.formsubmissionevent.elements.md) | Array<FormElement> | (Optional) The elements contained within the form | +| [formClasses?](./node-tracker.formsubmissionevent.formclasses.md) | Array<string> | (Optional) The class names on the form | +| [formId](./node-tracker.formsubmissionevent.formid.md) | string | The ID of the form | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.jsonprocessor.md b/api-docs/docs/node-tracker/markdown/node-tracker.jsonprocessor.md new file mode 100644 index 000000000..cc2f190c2 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.jsonprocessor.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [JsonProcessor](./node-tracker.jsonprocessor.md) + +## JsonProcessor type + +A function which will processor the Json onto the injected PayloadBuilder + +Signature: + +```typescript +type JsonProcessor = (payloadBuilder: PayloadBuilder, jsonForProcessing: EventJson, contextEntitiesForProcessing: SelfDescribingJson[]) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.linkclickevent.elementclasses.md b/api-docs/docs/node-tracker/markdown/node-tracker.linkclickevent.elementclasses.md new file mode 100644 index 000000000..1e6e5c891 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.linkclickevent.elementclasses.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [LinkClickEvent](./node-tracker.linkclickevent.md) > [elementClasses](./node-tracker.linkclickevent.elementclasses.md) + +## LinkClickEvent.elementClasses property + +An array of class names from the element clicked + +Signature: + +```typescript +elementClasses?: Array; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.linkclickevent.elementcontent.md b/api-docs/docs/node-tracker/markdown/node-tracker.linkclickevent.elementcontent.md new file mode 100644 index 000000000..3612c2946 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.linkclickevent.elementcontent.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [LinkClickEvent](./node-tracker.linkclickevent.md) > [elementContent](./node-tracker.linkclickevent.elementcontent.md) + +## LinkClickEvent.elementContent property + +The content of the element if present and enabled + +Signature: + +```typescript +elementContent?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.linkclickevent.elementid.md b/api-docs/docs/node-tracker/markdown/node-tracker.linkclickevent.elementid.md new file mode 100644 index 000000000..b755d563e --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.linkclickevent.elementid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [LinkClickEvent](./node-tracker.linkclickevent.md) > [elementId](./node-tracker.linkclickevent.elementid.md) + +## LinkClickEvent.elementId property + +The ID of the element clicked if present + +Signature: + +```typescript +elementId?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.linkclickevent.elementtarget.md b/api-docs/docs/node-tracker/markdown/node-tracker.linkclickevent.elementtarget.md new file mode 100644 index 000000000..8a3f1e7be --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.linkclickevent.elementtarget.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [LinkClickEvent](./node-tracker.linkclickevent.md) > [elementTarget](./node-tracker.linkclickevent.elementtarget.md) + +## LinkClickEvent.elementTarget property + +The target value of the element if present + +Signature: + +```typescript +elementTarget?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.linkclickevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.linkclickevent.md new file mode 100644 index 000000000..4ec30914a --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.linkclickevent.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [LinkClickEvent](./node-tracker.linkclickevent.md) + +## LinkClickEvent interface + +A Link Click Event Used when a user clicks on a link on a webpage, typically an anchor tag `` + +Signature: + +```typescript +interface LinkClickEvent +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [elementClasses?](./node-tracker.linkclickevent.elementclasses.md) | Array<string> | (Optional) An array of class names from the element clicked | +| [elementContent?](./node-tracker.linkclickevent.elementcontent.md) | string | (Optional) The content of the element if present and enabled | +| [elementId?](./node-tracker.linkclickevent.elementid.md) | string | (Optional) The ID of the element clicked if present | +| [elementTarget?](./node-tracker.linkclickevent.elementtarget.md) | string | (Optional) The target value of the element if present | +| [targetUrl](./node-tracker.linkclickevent.targeturl.md) | string | The target URL of the link | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.linkclickevent.targeturl.md b/api-docs/docs/node-tracker/markdown/node-tracker.linkclickevent.targeturl.md new file mode 100644 index 000000000..f31b90e57 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.linkclickevent.targeturl.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [LinkClickEvent](./node-tracker.linkclickevent.md) > [targetUrl](./node-tracker.linkclickevent.targeturl.md) + +## LinkClickEvent.targetUrl property + +The target URL of the link + +Signature: + +```typescript +targetUrl: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.log_level.md b/api-docs/docs/node-tracker/markdown/node-tracker.log_level.md new file mode 100644 index 000000000..745f621c1 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.log_level.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [LOG\_LEVEL](./node-tracker.log_level.md) + +## LOG\_LEVEL enum + +Signature: + +```typescript +declare enum LOG_LEVEL +``` + +## Enumeration Members + +| Member | Value | Description | +| --- | --- | --- | +| debug | 3 | | +| error | 1 | | +| info | 4 | | +| none | 0 | | +| warn | 2 | | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.logger.debug.md b/api-docs/docs/node-tracker/markdown/node-tracker.logger.debug.md new file mode 100644 index 000000000..f4617e1b8 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.logger.debug.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [Logger](./node-tracker.logger.md) > [debug](./node-tracker.logger.debug.md) + +## Logger.debug property + +Signature: + +```typescript +debug: (message: string, ...extraParams: unknown[]) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.logger.error.md b/api-docs/docs/node-tracker/markdown/node-tracker.logger.error.md new file mode 100644 index 000000000..baec2704d --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.logger.error.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [Logger](./node-tracker.logger.md) > [error](./node-tracker.logger.error.md) + +## Logger.error property + +Signature: + +```typescript +error: (message: string, error?: unknown, ...extraParams: unknown[]) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.logger.info.md b/api-docs/docs/node-tracker/markdown/node-tracker.logger.info.md new file mode 100644 index 000000000..ea9410890 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.logger.info.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [Logger](./node-tracker.logger.md) > [info](./node-tracker.logger.info.md) + +## Logger.info property + +Signature: + +```typescript +info: (message: string, ...extraParams: unknown[]) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.logger.md b/api-docs/docs/node-tracker/markdown/node-tracker.logger.md new file mode 100644 index 000000000..9a8937ca1 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.logger.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [Logger](./node-tracker.logger.md) + +## Logger interface + +Signature: + +```typescript +interface Logger +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [debug](./node-tracker.logger.debug.md) | (message: string, ...extraParams: unknown\[\]) => void | | +| [error](./node-tracker.logger.error.md) | (message: string, error?: unknown, ...extraParams: unknown\[\]) => void | | +| [info](./node-tracker.logger.info.md) | (message: string, ...extraParams: unknown\[\]) => void | | +| [setLogLevel](./node-tracker.logger.setloglevel.md) | (level: LOG\_LEVEL) => void | | +| [warn](./node-tracker.logger.warn.md) | (message: string, error?: unknown, ...extraParams: unknown\[\]) => void | | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.logger.setloglevel.md b/api-docs/docs/node-tracker/markdown/node-tracker.logger.setloglevel.md new file mode 100644 index 000000000..b08ef823c --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.logger.setloglevel.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [Logger](./node-tracker.logger.md) > [setLogLevel](./node-tracker.logger.setloglevel.md) + +## Logger.setLogLevel property + +Signature: + +```typescript +setLogLevel: (level: LOG_LEVEL) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.logger.warn.md b/api-docs/docs/node-tracker/markdown/node-tracker.logger.warn.md new file mode 100644 index 000000000..deb16cc0f --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.logger.warn.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [Logger](./node-tracker.logger.md) > [warn](./node-tracker.logger.warn.md) + +## Logger.warn property + +Signature: + +```typescript +warn: (message: string, error?: unknown, ...extraParams: unknown[]) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.md b/api-docs/docs/node-tracker/markdown/node-tracker.md new file mode 100644 index 000000000..c93bdbcac --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.md @@ -0,0 +1,110 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) + +## node-tracker package + +## Enumerations + +| Enumeration | Description | +| --- | --- | +| [LOG\_LEVEL](./node-tracker.log_level.md) | | + +## Functions + +| Function | Description | +| --- | --- | +| [buildAdClick(event)](./node-tracker.buildadclick.md) | Build a Ad Click Event Used to track an advertisement click | +| [buildAdConversion(event)](./node-tracker.buildadconversion.md) | Build a Ad Conversion Event Used to track an advertisement click | +| [buildAddToCart(event)](./node-tracker.buildaddtocart.md) | Build a Add To Cart Event For tracking users adding items from a cart on an ecommerce site. | +| [buildAdImpression(event)](./node-tracker.buildadimpression.md) | Build a Ad Impression Event Used to track an advertisement impression | +| [buildConsentGranted(event)](./node-tracker.buildconsentgranted.md) | Build a Consent Granted Event Used for tracking when a user grants their consent | +| [buildConsentWithdrawn(event)](./node-tracker.buildconsentwithdrawn.md) | Build a Consent Withdrawn Event Used for tracking when a user withdraws their consent | +| [buildEcommerceTransaction(event)](./node-tracker.buildecommercetransaction.md) | Build an Ecommerce Transaction Event Allows for tracking common ecommerce events, this event is usually used when a consumer completes a transaction. | +| [buildEcommerceTransactionItem(event)](./node-tracker.buildecommercetransactionitem.md) | Build an Ecommerce Transaction Item Event Related to the [buildEcommerceTransaction()](./node-tracker.buildecommercetransaction.md) Each Ecommerce Transaction may contain one or more EcommerceTransactionItem events | +| [buildFormFocusOrChange(event)](./node-tracker.buildformfocusorchange.md) | Build a Form Focus or Change Form Event based on schema property When a user focuses on a form element or when a user makes a change to a form element. | +| [buildFormSubmission(event)](./node-tracker.buildformsubmission.md) | Build a Form Submission Event Used to track when a user submits a form | +| [buildLinkClick(event)](./node-tracker.buildlinkclick.md) | Build a Link Click Event Used when a user clicks on a link on a webpage, typically an anchor tag <a> | +| [buildPagePing(event)](./node-tracker.buildpageping.md) | Build a Page Ping Event Fires when activity tracking is enabled in the browser. Tracks same information as the last tracked Page View and includes scroll information from the current page view | +| [buildPageView(event)](./node-tracker.buildpageview.md) | Build a Page View Event Represents a Page View, which is typically fired as soon as possible when a web page is loaded within the users browser. Often also fired on "virtual page views" within Single Page Applications (SPA). | +| [buildRemoveFromCart(event)](./node-tracker.buildremovefromcart.md) | Build a Remove From Cart Event For tracking users removing items from a cart on an ecommerce site. | +| [buildScreenView(event)](./node-tracker.buildscreenview.md) | Build a Scren View Event Similar to a Page View but less focused on typical web properties Often used for mobile applications as the user is presented with new views as they performance navigation events | +| [buildSelfDescribingEvent(event)](./node-tracker.buildselfdescribingevent.md) | Build a self-describing event A custom event type, allowing for an event to be tracked using your own custom schema and a data object which conforms to the supplied schema | +| [buildSiteSearch(event)](./node-tracker.buildsitesearch.md) | Build a Site Search Event Used when a user performs a search action on a page | +| [buildSocialInteraction(event)](./node-tracker.buildsocialinteraction.md) | Build a Social Interaction Event Social tracking will be used to track the way users interact with Facebook, Twitter and Google + widgets e.g. to capture “like this” or “tweet this” events. | +| [buildStructEvent(event)](./node-tracker.buildstructevent.md) | Build a Structured Event A classic style of event tracking, allows for easier movement between analytics systems. A loosely typed event, creating a Self Describing event is preferred, but useful for interoperability. | +| [newTracker(trackerConfiguration, emitterConfiguration)](./node-tracker.newtracker.md) | | + +## Interfaces + +| Interface | Description | +| --- | --- | +| [AdClickEvent](./node-tracker.adclickevent.md) | An Ad Click Event Used to track an advertisement click | +| [AdConversionEvent](./node-tracker.adconversionevent.md) | An Ad Conversion Event Used to track an advertisement click | +| [AddToCartEvent](./node-tracker.addtocartevent.md) | An Add To Cart Event For tracking users adding items from a cart on an ecommerce site. | +| [AdImpressionEvent](./node-tracker.adimpressionevent.md) | An Ad Impression Event Used to track an advertisement impression | +| [ConsentGrantedEvent](./node-tracker.consentgrantedevent.md) | A Consent Granted Event Used for tracking when a user grants their consent | +| [ConsentWithdrawnEvent](./node-tracker.consentwithdrawnevent.md) | A Consent Withdrawn Event Used for tracking when a user withdraws their consent | +| [ContextEvent](./node-tracker.contextevent.md) | Argument for [ContextGenerator](./node-tracker.contextgenerator.md) and [ContextFilter](./node-tracker.contextfilter.md) callback | +| [CoreConfiguration](./node-tracker.coreconfiguration.md) | The configuration object for the tracker core library | +| [CorePlugin](./node-tracker.coreplugin.md) | Interface which defines Core Plugins | +| [CorePluginConfiguration](./node-tracker.corepluginconfiguration.md) | The configuration of the plugin to add | +| [DeviceTimestamp](./node-tracker.devicetimestamp.md) | A representation of a Device Timestamp (dtm) | +| [EcommerceTransactionEvent](./node-tracker.ecommercetransactionevent.md) | An Ecommerce Transaction Event Allows for tracking common ecommerce events, this event is usually used when a customer completes a transaction. | +| [EcommerceTransactionItemEvent](./node-tracker.ecommercetransactionitemevent.md) | An Ecommerce Transaction Item Related to the [EcommerceTransactionEvent](./node-tracker.ecommercetransactionevent.md) Each Ecommerce Transaction may contain one or more EcommerceTransactionItem events | +| [Emitter](./node-tracker.emitter.md) | Emitter is responsible for sending events to the collector. It manages the event queue and sends events in batches depending on configuration. | +| [EmitterConfiguration](./node-tracker.emitterconfiguration.md) | | +| [EmitterConfigurationBase](./node-tracker.emitterconfigurationbase.md) | | +| [EventPayloadAndContext](./node-tracker.eventpayloadandcontext.md) | Interface for returning a built event (PayloadBuilder) and context (Array of SelfDescribingJson). | +| [EventStore](./node-tracker.eventstore.md) | EventStore allows storing and retrieving events before they are sent to the collector | +| [EventStoreConfiguration](./node-tracker.eventstoreconfiguration.md) | | +| [EventStoreIterator](./node-tracker.eventstoreiterator.md) | EventStoreIterator allows iterating over all events in the store. | +| [EventStorePayload](./node-tracker.eventstorepayload.md) | | +| [FormFocusOrChangeEvent](./node-tracker.formfocusorchangeevent.md) | Represents either a Form Focus or Form Change event When a user focuses on a form element or when a user makes a change to a form element. | +| [FormSubmissionEvent](./node-tracker.formsubmissionevent.md) | A Form Submission Event Used to track when a user submits a form | +| [LinkClickEvent](./node-tracker.linkclickevent.md) | A Link Click Event Used when a user clicks on a link on a webpage, typically an anchor tag <a> | +| [Logger](./node-tracker.logger.md) | | +| [PagePingEvent](./node-tracker.pagepingevent.md) | A Page Ping Event Fires when activity tracking is enabled in the browser. Tracks same information as the last tracked Page View and includes scroll information from the current page view | +| [PageViewEvent](./node-tracker.pageviewevent.md) | A Page View Event Represents a Page View, which is typically fired as soon as possible when a web page is loaded within the users browser. Often also fired on "virtual page views" within Single Page Applications (SPA). | +| [PayloadBuilder](./node-tracker.payloadbuilder.md) | Interface for mutable object encapsulating tracker payload | +| [RemoveFromCartEvent](./node-tracker.removefromcartevent.md) | An Remove To Cart Event For tracking users removing items from a cart on an ecommerce site. | +| [RuleSet](./node-tracker.ruleset.md) | A ruleset has accept or reject properties that contain rules for matching Iglu schema URIs | +| [ScreenViewEvent](./node-tracker.screenviewevent.md) | A Screen View Event Similar to a Page View but less focused on typical web properties Often used for mobile applications as the user is presented with new views as they performance navigation events | +| [SelfDescribingEvent](./node-tracker.selfdescribingevent.md) | A Self Describing Event A custom event type, allowing for an event to be tracked using your own custom schema and a data object which conforms to the supplied schema | +| [SiteSearchEvent](./node-tracker.sitesearchevent.md) | A Site Search Event Used when a user performs a search action on a page | +| [SocialInteractionEvent](./node-tracker.socialinteractionevent.md) | A Social Interaction Event Social tracking will be used to track the way users interact with Facebook, Twitter and Google + widgets e.g. to capture “like this” or “tweet this” events. | +| [StructuredEvent](./node-tracker.structuredevent.md) | A Structured Event A classic style of event tracking, allows for easier movement between analytics systems. A loosely typed event, creating a Self Describing event is preferred, but useful for interoperability. | +| [Tracker](./node-tracker.tracker.md) | | +| [TrackerConfiguration](./node-tracker.trackerconfiguration.md) | | +| [TrackerCore](./node-tracker.trackercore.md) | Export interface containing all Core functions | +| [TrueTimestamp](./node-tracker.truetimestamp.md) | A representation of a True Timestamp (ttm) | + +## Variables + +| Variable | Description | +| --- | --- | +| [version](./node-tracker.version.md) | | + +## Type Aliases + +| Type Alias | Description | +| --- | --- | +| [ConditionalContextProvider](./node-tracker.conditionalcontextprovider.md) | Conditional context providers are two element arrays used to decide when to attach contexts, where: - the first element is some conditional criterion - the second element is any number of context primitives | +| [ContextFilter](./node-tracker.contextfilter.md) | A context filter is a user-supplied callback that is evaluated for each event to determine if the context associated with the filter should be attached to the event | +| [ContextGenerator](./node-tracker.contextgenerator.md) | A context generator is a user-supplied callback that is evaluated for each event to allow an additional context to be dynamically attached to the event | +| [ContextPrimitive](./node-tracker.contextprimitive.md) | A context primitive is either a self-describing JSON or a context generator | +| [CustomEmitter](./node-tracker.customemitter.md) | | +| [EventBatch](./node-tracker.eventbatch.md) | A collection of event payloads which are sent to the collector. | +| [EventJson](./node-tracker.eventjson.md) | An array of tuples which represents the unprocessed JSON to be added to the Payload | +| [EventJsonWithKeys](./node-tracker.eventjsonwithkeys.md) | A tuple which represents the unprocessed JSON to be added to the Payload | +| [EventMethod](./node-tracker.eventmethod.md) | | +| [FilterProvider](./node-tracker.filterprovider.md) | A filter provider is a tuple that has two parts: a context filter and the context primitive(s) If the context filter evaluates to true, the tracker will attach the context primitive(s) | +| [FormElement](./node-tracker.formelement.md) | A representation of an element within a form | +| [JsonProcessor](./node-tracker.jsonprocessor.md) | A function which will processor the Json onto the injected PayloadBuilder | +| [NodeEmitterConfiguration](./node-tracker.nodeemitterconfiguration.md) | | +| [Payload](./node-tracker.payload.md) | Type for a Payload dictionary | +| [RequestFailure](./node-tracker.requestfailure.md) | The data that will be available to the onRequestFailure callback | +| [RuleSetProvider](./node-tracker.rulesetprovider.md) | A ruleset provider is aa tuple that has two parts: a ruleset and the context primitive(s) If the ruleset allows the current event schema URI, the tracker will attach the context primitive(s) | +| [SelfDescribingJson](./node-tracker.selfdescribingjson.md) | Export interface for any Self-Describing JSON such as context or Self Describing events | +| [Timestamp](./node-tracker.timestamp.md) | Algebraic datatype representing possible timestamp type choice | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.newtracker.md b/api-docs/docs/node-tracker/markdown/node-tracker.newtracker.md new file mode 100644 index 000000000..380cb6c16 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.newtracker.md @@ -0,0 +1,23 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [newTracker](./node-tracker.newtracker.md) + +## newTracker() function + +Signature: + +```typescript +declare function newTracker(trackerConfiguration: TrackerConfiguration, emitterConfiguration: NodeEmitterConfiguration | NodeEmitterConfiguration[]): Tracker; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| trackerConfiguration | TrackerConfiguration | | +| emitterConfiguration | NodeEmitterConfiguration \| NodeEmitterConfiguration\[\] | | + +Returns: + +Tracker + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.nodeemitterconfiguration.md b/api-docs/docs/node-tracker/markdown/node-tracker.nodeemitterconfiguration.md new file mode 100644 index 000000000..258018399 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.nodeemitterconfiguration.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [NodeEmitterConfiguration](./node-tracker.nodeemitterconfiguration.md) + +## NodeEmitterConfiguration type + +Signature: + +```typescript +type NodeEmitterConfiguration = CustomEmitter | EmitterConfiguration; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.pagepingevent.maxxoffset.md b/api-docs/docs/node-tracker/markdown/node-tracker.pagepingevent.maxxoffset.md new file mode 100644 index 000000000..d34b5f1ed --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.pagepingevent.maxxoffset.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [PagePingEvent](./node-tracker.pagepingevent.md) > [maxXOffset](./node-tracker.pagepingevent.maxxoffset.md) + +## PagePingEvent.maxXOffset property + +The maximum X scroll position for the current page view + +Signature: + +```typescript +maxXOffset?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.pagepingevent.maxyoffset.md b/api-docs/docs/node-tracker/markdown/node-tracker.pagepingevent.maxyoffset.md new file mode 100644 index 000000000..06ccfd1fa --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.pagepingevent.maxyoffset.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [PagePingEvent](./node-tracker.pagepingevent.md) > [maxYOffset](./node-tracker.pagepingevent.maxyoffset.md) + +## PagePingEvent.maxYOffset property + +The maximum Y scroll position for the current page view + +Signature: + +```typescript +maxYOffset?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.pagepingevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.pagepingevent.md new file mode 100644 index 000000000..70195df4e --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.pagepingevent.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [PagePingEvent](./node-tracker.pagepingevent.md) + +## PagePingEvent interface + +A Page Ping Event Fires when activity tracking is enabled in the browser. Tracks same information as the last tracked Page View and includes scroll information from the current page view + +Signature: + +```typescript +interface PagePingEvent extends PageViewEvent +``` +Extends: PageViewEvent + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [maxXOffset?](./node-tracker.pagepingevent.maxxoffset.md) | number | (Optional) The maximum X scroll position for the current page view | +| [maxYOffset?](./node-tracker.pagepingevent.maxyoffset.md) | number | (Optional) The maximum Y scroll position for the current page view | +| [minXOffset?](./node-tracker.pagepingevent.minxoffset.md) | number | (Optional) The minimum X scroll position for the current page view | +| [minYOffset?](./node-tracker.pagepingevent.minyoffset.md) | number | (Optional) The minimum Y scroll position for the current page view | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.pagepingevent.minxoffset.md b/api-docs/docs/node-tracker/markdown/node-tracker.pagepingevent.minxoffset.md new file mode 100644 index 000000000..5b54313d6 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.pagepingevent.minxoffset.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [PagePingEvent](./node-tracker.pagepingevent.md) > [minXOffset](./node-tracker.pagepingevent.minxoffset.md) + +## PagePingEvent.minXOffset property + +The minimum X scroll position for the current page view + +Signature: + +```typescript +minXOffset?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.pagepingevent.minyoffset.md b/api-docs/docs/node-tracker/markdown/node-tracker.pagepingevent.minyoffset.md new file mode 100644 index 000000000..ea3e5a487 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.pagepingevent.minyoffset.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [PagePingEvent](./node-tracker.pagepingevent.md) > [minYOffset](./node-tracker.pagepingevent.minyoffset.md) + +## PagePingEvent.minYOffset property + +The minimum Y scroll position for the current page view + +Signature: + +```typescript +minYOffset?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.pageviewevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.pageviewevent.md new file mode 100644 index 000000000..68379fae6 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.pageviewevent.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [PageViewEvent](./node-tracker.pageviewevent.md) + +## PageViewEvent interface + +A Page View Event Represents a Page View, which is typically fired as soon as possible when a web page is loaded within the users browser. Often also fired on "virtual page views" within Single Page Applications (SPA). + +Signature: + +```typescript +interface PageViewEvent +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [pageTitle?](./node-tracker.pageviewevent.pagetitle.md) | string \| null | (Optional) The current page title in the users browser | +| [pageUrl?](./node-tracker.pageviewevent.pageurl.md) | string \| null | (Optional) The current URL visible in the users browser | +| [referrer?](./node-tracker.pageviewevent.referrer.md) | string \| null | (Optional) The URL of the referring page | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.pageviewevent.pagetitle.md b/api-docs/docs/node-tracker/markdown/node-tracker.pageviewevent.pagetitle.md new file mode 100644 index 000000000..45d440241 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.pageviewevent.pagetitle.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [PageViewEvent](./node-tracker.pageviewevent.md) > [pageTitle](./node-tracker.pageviewevent.pagetitle.md) + +## PageViewEvent.pageTitle property + +The current page title in the users browser + +Signature: + +```typescript +pageTitle?: string | null; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.pageviewevent.pageurl.md b/api-docs/docs/node-tracker/markdown/node-tracker.pageviewevent.pageurl.md new file mode 100644 index 000000000..dff6ff16f --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.pageviewevent.pageurl.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [PageViewEvent](./node-tracker.pageviewevent.md) > [pageUrl](./node-tracker.pageviewevent.pageurl.md) + +## PageViewEvent.pageUrl property + +The current URL visible in the users browser + +Signature: + +```typescript +pageUrl?: string | null; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.pageviewevent.referrer.md b/api-docs/docs/node-tracker/markdown/node-tracker.pageviewevent.referrer.md new file mode 100644 index 000000000..510d0ba44 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.pageviewevent.referrer.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [PageViewEvent](./node-tracker.pageviewevent.md) > [referrer](./node-tracker.pageviewevent.referrer.md) + +## PageViewEvent.referrer property + +The URL of the referring page + +Signature: + +```typescript +referrer?: string | null; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.payload.md b/api-docs/docs/node-tracker/markdown/node-tracker.payload.md new file mode 100644 index 000000000..69b929d26 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.payload.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [Payload](./node-tracker.payload.md) + +## Payload type + +Type for a Payload dictionary + +Signature: + +```typescript +type Payload = Record; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.add.md b/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.add.md new file mode 100644 index 000000000..979815d0b --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.add.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [PayloadBuilder](./node-tracker.payloadbuilder.md) > [add](./node-tracker.payloadbuilder.add.md) + +## PayloadBuilder.add property + +Adds an entry to the Payload + +Signature: + +```typescript +add: (key: string, value: unknown) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.addcontextentity.md b/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.addcontextentity.md new file mode 100644 index 000000000..84929af64 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.addcontextentity.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [PayloadBuilder](./node-tracker.payloadbuilder.md) > [addContextEntity](./node-tracker.payloadbuilder.addcontextentity.md) + +## PayloadBuilder.addContextEntity property + +Caches a context entity to be added to payload on build + +Signature: + +```typescript +addContextEntity: (entity: SelfDescribingJson) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.adddict.md b/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.adddict.md new file mode 100644 index 000000000..a4fa7da8a --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.adddict.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [PayloadBuilder](./node-tracker.payloadbuilder.md) > [addDict](./node-tracker.payloadbuilder.adddict.md) + +## PayloadBuilder.addDict property + +Merges a payload into the existing payload + +Signature: + +```typescript +addDict: (dict: Payload) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.addjson.md b/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.addjson.md new file mode 100644 index 000000000..0e572fb3c --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.addjson.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [PayloadBuilder](./node-tracker.payloadbuilder.md) > [addJson](./node-tracker.payloadbuilder.addjson.md) + +## PayloadBuilder.addJson property + +Caches a JSON object to be added to payload on build + +Signature: + +```typescript +addJson: (keyIfEncoded: string, keyIfNotEncoded: string, json: Record) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.build.md b/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.build.md new file mode 100644 index 000000000..da0bc05e3 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.build.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [PayloadBuilder](./node-tracker.payloadbuilder.md) > [build](./node-tracker.payloadbuilder.build.md) + +## PayloadBuilder.build property + +Builds and returns the Payload + +Signature: + +```typescript +build: () => Payload; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.getjson.md b/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.getjson.md new file mode 100644 index 000000000..515efac39 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.getjson.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [PayloadBuilder](./node-tracker.payloadbuilder.md) > [getJson](./node-tracker.payloadbuilder.getjson.md) + +## PayloadBuilder.getJson property + +Gets all JSON objects added to payload + +Signature: + +```typescript +getJson: () => EventJson; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.getpayload.md b/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.getpayload.md new file mode 100644 index 000000000..0c704fd6b --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.getpayload.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [PayloadBuilder](./node-tracker.payloadbuilder.md) > [getPayload](./node-tracker.payloadbuilder.getpayload.md) + +## PayloadBuilder.getPayload property + +Gets the current payload, before cached JSON is processed + +Signature: + +```typescript +getPayload: () => Payload; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.md b/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.md new file mode 100644 index 000000000..ecda8875f --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.md @@ -0,0 +1,27 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [PayloadBuilder](./node-tracker.payloadbuilder.md) + +## PayloadBuilder interface + +Interface for mutable object encapsulating tracker payload + +Signature: + +```typescript +interface PayloadBuilder +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [add](./node-tracker.payloadbuilder.add.md) | (key: string, value: unknown) => void | Adds an entry to the Payload | +| [addContextEntity](./node-tracker.payloadbuilder.addcontextentity.md) | (entity: SelfDescribingJson) => void | Caches a context entity to be added to payload on build | +| [addDict](./node-tracker.payloadbuilder.adddict.md) | (dict: Payload) => void | Merges a payload into the existing payload | +| [addJson](./node-tracker.payloadbuilder.addjson.md) | (keyIfEncoded: string, keyIfNotEncoded: string, json: Record<string, unknown>) => void | Caches a JSON object to be added to payload on build | +| [build](./node-tracker.payloadbuilder.build.md) | () => Payload | Builds and returns the Payload | +| [getJson](./node-tracker.payloadbuilder.getjson.md) | () => EventJson | Gets all JSON objects added to payload | +| [getPayload](./node-tracker.payloadbuilder.getpayload.md) | () => Payload | Gets the current payload, before cached JSON is processed | +| [withJsonProcessor](./node-tracker.payloadbuilder.withjsonprocessor.md) | (jsonProcessor: JsonProcessor) => void | Adds a function which will be executed when building the payload to process the JSON which has been added to this payload | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.withjsonprocessor.md b/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.withjsonprocessor.md new file mode 100644 index 000000000..993c4d7af --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.payloadbuilder.withjsonprocessor.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [PayloadBuilder](./node-tracker.payloadbuilder.md) > [withJsonProcessor](./node-tracker.payloadbuilder.withjsonprocessor.md) + +## PayloadBuilder.withJsonProcessor property + +Adds a function which will be executed when building the payload to process the JSON which has been added to this payload + +Signature: + +```typescript +withJsonProcessor: (jsonProcessor: JsonProcessor) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.removefromcartevent.category.md b/api-docs/docs/node-tracker/markdown/node-tracker.removefromcartevent.category.md new file mode 100644 index 000000000..78fd85461 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.removefromcartevent.category.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [RemoveFromCartEvent](./node-tracker.removefromcartevent.md) > [category](./node-tracker.removefromcartevent.category.md) + +## RemoveFromCartEvent.category property + +The category of the product + +Signature: + +```typescript +category?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.removefromcartevent.currency.md b/api-docs/docs/node-tracker/markdown/node-tracker.removefromcartevent.currency.md new file mode 100644 index 000000000..49749c5dc --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.removefromcartevent.currency.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [RemoveFromCartEvent](./node-tracker.removefromcartevent.md) > [currency](./node-tracker.removefromcartevent.currency.md) + +## RemoveFromCartEvent.currency property + +The currency of the product + +Signature: + +```typescript +currency?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.removefromcartevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.removefromcartevent.md new file mode 100644 index 000000000..2ce7163be --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.removefromcartevent.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [RemoveFromCartEvent](./node-tracker.removefromcartevent.md) + +## RemoveFromCartEvent interface + +An Remove To Cart Event For tracking users removing items from a cart on an ecommerce site. + +Signature: + +```typescript +interface RemoveFromCartEvent +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [category?](./node-tracker.removefromcartevent.category.md) | string | (Optional) The category of the product | +| [currency?](./node-tracker.removefromcartevent.currency.md) | string | (Optional) The currency of the product | +| [name?](./node-tracker.removefromcartevent.name.md) | string | (Optional) The name of the product | +| [quantity](./node-tracker.removefromcartevent.quantity.md) | number | The number removed from the cart | +| [sku](./node-tracker.removefromcartevent.sku.md) | string | A Product Stock Keeping Unit (SKU) | +| [unitPrice?](./node-tracker.removefromcartevent.unitprice.md) | number | (Optional) The price of the product | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.removefromcartevent.name.md b/api-docs/docs/node-tracker/markdown/node-tracker.removefromcartevent.name.md new file mode 100644 index 000000000..f7fb450b1 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.removefromcartevent.name.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [RemoveFromCartEvent](./node-tracker.removefromcartevent.md) > [name](./node-tracker.removefromcartevent.name.md) + +## RemoveFromCartEvent.name property + +The name of the product + +Signature: + +```typescript +name?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.removefromcartevent.quantity.md b/api-docs/docs/node-tracker/markdown/node-tracker.removefromcartevent.quantity.md new file mode 100644 index 000000000..718048c88 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.removefromcartevent.quantity.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [RemoveFromCartEvent](./node-tracker.removefromcartevent.md) > [quantity](./node-tracker.removefromcartevent.quantity.md) + +## RemoveFromCartEvent.quantity property + +The number removed from the cart + +Signature: + +```typescript +quantity: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.removefromcartevent.sku.md b/api-docs/docs/node-tracker/markdown/node-tracker.removefromcartevent.sku.md new file mode 100644 index 000000000..f8314446e --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.removefromcartevent.sku.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [RemoveFromCartEvent](./node-tracker.removefromcartevent.md) > [sku](./node-tracker.removefromcartevent.sku.md) + +## RemoveFromCartEvent.sku property + +A Product Stock Keeping Unit (SKU) + +Signature: + +```typescript +sku: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.removefromcartevent.unitprice.md b/api-docs/docs/node-tracker/markdown/node-tracker.removefromcartevent.unitprice.md new file mode 100644 index 000000000..db5c2bf06 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.removefromcartevent.unitprice.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [RemoveFromCartEvent](./node-tracker.removefromcartevent.md) > [unitPrice](./node-tracker.removefromcartevent.unitprice.md) + +## RemoveFromCartEvent.unitPrice property + +The price of the product + +Signature: + +```typescript +unitPrice?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.requestfailure.md b/api-docs/docs/node-tracker/markdown/node-tracker.requestfailure.md new file mode 100644 index 000000000..63f977207 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.requestfailure.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [RequestFailure](./node-tracker.requestfailure.md) + +## RequestFailure type + +The data that will be available to the `onRequestFailure` callback + +Signature: + +```typescript +type RequestFailure = { + events: EventBatch; + status?: number; + message?: string; + willRetry: boolean; +}; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.ruleset.accept.md b/api-docs/docs/node-tracker/markdown/node-tracker.ruleset.accept.md new file mode 100644 index 000000000..2c29e5003 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.ruleset.accept.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [RuleSet](./node-tracker.ruleset.md) > [accept](./node-tracker.ruleset.accept.md) + +## RuleSet.accept property + +Signature: + +```typescript +accept?: Array | string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.ruleset.md b/api-docs/docs/node-tracker/markdown/node-tracker.ruleset.md new file mode 100644 index 000000000..451a5a5dd --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.ruleset.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [RuleSet](./node-tracker.ruleset.md) + +## RuleSet interface + +A ruleset has accept or reject properties that contain rules for matching Iglu schema URIs + +Signature: + +```typescript +interface RuleSet +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [accept?](./node-tracker.ruleset.accept.md) | Array<string> \| string | (Optional) | +| [reject?](./node-tracker.ruleset.reject.md) | Array<string> \| string | (Optional) | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.ruleset.reject.md b/api-docs/docs/node-tracker/markdown/node-tracker.ruleset.reject.md new file mode 100644 index 000000000..393a8b016 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.ruleset.reject.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [RuleSet](./node-tracker.ruleset.md) > [reject](./node-tracker.ruleset.reject.md) + +## RuleSet.reject property + +Signature: + +```typescript +reject?: Array | string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.rulesetprovider.md b/api-docs/docs/node-tracker/markdown/node-tracker.rulesetprovider.md new file mode 100644 index 000000000..41a471fb7 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.rulesetprovider.md @@ -0,0 +1,16 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [RuleSetProvider](./node-tracker.rulesetprovider.md) + +## RuleSetProvider type + +A ruleset provider is aa tuple that has two parts: a ruleset and the context primitive(s) If the ruleset allows the current event schema URI, the tracker will attach the context primitive(s) + +Signature: + +```typescript +type RuleSetProvider = [ + RuleSet, + Array | ContextPrimitive +]; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.screenviewevent.id.md b/api-docs/docs/node-tracker/markdown/node-tracker.screenviewevent.id.md new file mode 100644 index 000000000..5d48b9793 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.screenviewevent.id.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ScreenViewEvent](./node-tracker.screenviewevent.md) > [id](./node-tracker.screenviewevent.id.md) + +## ScreenViewEvent.id property + +The identifier of the screen + +Signature: + +```typescript +id?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.screenviewevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.screenviewevent.md new file mode 100644 index 000000000..7ae8e119f --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.screenviewevent.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ScreenViewEvent](./node-tracker.screenviewevent.md) + +## ScreenViewEvent interface + +A Screen View Event Similar to a Page View but less focused on typical web properties Often used for mobile applications as the user is presented with new views as they performance navigation events + +Signature: + +```typescript +interface ScreenViewEvent +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [id?](./node-tracker.screenviewevent.id.md) | string | (Optional) The identifier of the screen | +| [name?](./node-tracker.screenviewevent.name.md) | string | (Optional) The name of the screen | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.screenviewevent.name.md b/api-docs/docs/node-tracker/markdown/node-tracker.screenviewevent.name.md new file mode 100644 index 000000000..698ad7b77 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.screenviewevent.name.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [ScreenViewEvent](./node-tracker.screenviewevent.md) > [name](./node-tracker.screenviewevent.name.md) + +## ScreenViewEvent.name property + +The name of the screen + +Signature: + +```typescript +name?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.selfdescribingevent.event.md b/api-docs/docs/node-tracker/markdown/node-tracker.selfdescribingevent.event.md new file mode 100644 index 000000000..d66b67808 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.selfdescribingevent.event.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [SelfDescribingEvent](./node-tracker.selfdescribingevent.md) > [event](./node-tracker.selfdescribingevent.event.md) + +## SelfDescribingEvent.event property + +The Self Describing JSON which describes the event + +Signature: + +```typescript +event: SelfDescribingJson; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.selfdescribingevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.selfdescribingevent.md new file mode 100644 index 000000000..47653d298 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.selfdescribingevent.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [SelfDescribingEvent](./node-tracker.selfdescribingevent.md) + +## SelfDescribingEvent interface + +A Self Describing Event A custom event type, allowing for an event to be tracked using your own custom schema and a data object which conforms to the supplied schema + +Signature: + +```typescript +interface SelfDescribingEvent> +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [event](./node-tracker.selfdescribingevent.event.md) | SelfDescribingJson<T> | The Self Describing JSON which describes the event | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.selfdescribingjson.md b/api-docs/docs/node-tracker/markdown/node-tracker.selfdescribingjson.md new file mode 100644 index 000000000..14c5d7379 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.selfdescribingjson.md @@ -0,0 +1,16 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [SelfDescribingJson](./node-tracker.selfdescribingjson.md) + +## SelfDescribingJson type + +Export interface for any Self-Describing JSON such as context or Self Describing events + +Signature: + +```typescript +type SelfDescribingJson> = { + schema: string; + data: T extends any[] ? never : T extends {} ? T : never; +}; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.sitesearchevent.filters.md b/api-docs/docs/node-tracker/markdown/node-tracker.sitesearchevent.filters.md new file mode 100644 index 000000000..e963f101d --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.sitesearchevent.filters.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [SiteSearchEvent](./node-tracker.sitesearchevent.md) > [filters](./node-tracker.sitesearchevent.filters.md) + +## SiteSearchEvent.filters property + +Any filters which have been applied to the search + +Signature: + +```typescript +filters?: Record; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.sitesearchevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.sitesearchevent.md new file mode 100644 index 000000000..b412bbd27 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.sitesearchevent.md @@ -0,0 +1,23 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [SiteSearchEvent](./node-tracker.sitesearchevent.md) + +## SiteSearchEvent interface + +A Site Search Event Used when a user performs a search action on a page + +Signature: + +```typescript +interface SiteSearchEvent +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [filters?](./node-tracker.sitesearchevent.filters.md) | Record<string, string \| boolean> | (Optional) Any filters which have been applied to the search | +| [pageResults?](./node-tracker.sitesearchevent.pageresults.md) | number | (Optional) The number of visible results on the page | +| [terms](./node-tracker.sitesearchevent.terms.md) | Array<string> | The terms of the search | +| [totalResults?](./node-tracker.sitesearchevent.totalresults.md) | number | (Optional) The total number of results for this search | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.sitesearchevent.pageresults.md b/api-docs/docs/node-tracker/markdown/node-tracker.sitesearchevent.pageresults.md new file mode 100644 index 000000000..a30c5d6ed --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.sitesearchevent.pageresults.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [SiteSearchEvent](./node-tracker.sitesearchevent.md) > [pageResults](./node-tracker.sitesearchevent.pageresults.md) + +## SiteSearchEvent.pageResults property + +The number of visible results on the page + +Signature: + +```typescript +pageResults?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.sitesearchevent.terms.md b/api-docs/docs/node-tracker/markdown/node-tracker.sitesearchevent.terms.md new file mode 100644 index 000000000..6f4a45ceb --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.sitesearchevent.terms.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [SiteSearchEvent](./node-tracker.sitesearchevent.md) > [terms](./node-tracker.sitesearchevent.terms.md) + +## SiteSearchEvent.terms property + +The terms of the search + +Signature: + +```typescript +terms: Array; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.sitesearchevent.totalresults.md b/api-docs/docs/node-tracker/markdown/node-tracker.sitesearchevent.totalresults.md new file mode 100644 index 000000000..7b79bd694 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.sitesearchevent.totalresults.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [SiteSearchEvent](./node-tracker.sitesearchevent.md) > [totalResults](./node-tracker.sitesearchevent.totalresults.md) + +## SiteSearchEvent.totalResults property + +The total number of results for this search + +Signature: + +```typescript +totalResults?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.socialinteractionevent.action.md b/api-docs/docs/node-tracker/markdown/node-tracker.socialinteractionevent.action.md new file mode 100644 index 000000000..b0f8c0975 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.socialinteractionevent.action.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [SocialInteractionEvent](./node-tracker.socialinteractionevent.md) > [action](./node-tracker.socialinteractionevent.action.md) + +## SocialInteractionEvent.action property + +Social action performed + +Signature: + +```typescript +action: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.socialinteractionevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.socialinteractionevent.md new file mode 100644 index 000000000..b079030fa --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.socialinteractionevent.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [SocialInteractionEvent](./node-tracker.socialinteractionevent.md) + +## SocialInteractionEvent interface + +A Social Interaction Event Social tracking will be used to track the way users interact with Facebook, Twitter and Google + widgets e.g. to capture “like this” or “tweet this” events. + +Signature: + +```typescript +interface SocialInteractionEvent +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [action](./node-tracker.socialinteractionevent.action.md) | string | Social action performed | +| [network](./node-tracker.socialinteractionevent.network.md) | string | Social network | +| [target?](./node-tracker.socialinteractionevent.target.md) | string | (Optional) Object social action is performed on | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.socialinteractionevent.network.md b/api-docs/docs/node-tracker/markdown/node-tracker.socialinteractionevent.network.md new file mode 100644 index 000000000..a5301b629 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.socialinteractionevent.network.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [SocialInteractionEvent](./node-tracker.socialinteractionevent.md) > [network](./node-tracker.socialinteractionevent.network.md) + +## SocialInteractionEvent.network property + +Social network + +Signature: + +```typescript +network: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.socialinteractionevent.target.md b/api-docs/docs/node-tracker/markdown/node-tracker.socialinteractionevent.target.md new file mode 100644 index 000000000..a809bc4bb --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.socialinteractionevent.target.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [SocialInteractionEvent](./node-tracker.socialinteractionevent.md) > [target](./node-tracker.socialinteractionevent.target.md) + +## SocialInteractionEvent.target property + +Object social action is performed on + +Signature: + +```typescript +target?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.structuredevent.action.md b/api-docs/docs/node-tracker/markdown/node-tracker.structuredevent.action.md new file mode 100644 index 000000000..7ecfbb207 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.structuredevent.action.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [StructuredEvent](./node-tracker.structuredevent.md) > [action](./node-tracker.structuredevent.action.md) + +## StructuredEvent.action property + +Signature: + +```typescript +action: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.structuredevent.category.md b/api-docs/docs/node-tracker/markdown/node-tracker.structuredevent.category.md new file mode 100644 index 000000000..663b2514c --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.structuredevent.category.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [StructuredEvent](./node-tracker.structuredevent.md) > [category](./node-tracker.structuredevent.category.md) + +## StructuredEvent.category property + +Signature: + +```typescript +category: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.structuredevent.label.md b/api-docs/docs/node-tracker/markdown/node-tracker.structuredevent.label.md new file mode 100644 index 000000000..c92653178 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.structuredevent.label.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [StructuredEvent](./node-tracker.structuredevent.md) > [label](./node-tracker.structuredevent.label.md) + +## StructuredEvent.label property + +Signature: + +```typescript +label?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.structuredevent.md b/api-docs/docs/node-tracker/markdown/node-tracker.structuredevent.md new file mode 100644 index 000000000..f42afa8ac --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.structuredevent.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [StructuredEvent](./node-tracker.structuredevent.md) + +## StructuredEvent interface + +A Structured Event A classic style of event tracking, allows for easier movement between analytics systems. A loosely typed event, creating a Self Describing event is preferred, but useful for interoperability. + +Signature: + +```typescript +interface StructuredEvent +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [action](./node-tracker.structuredevent.action.md) | string | | +| [category](./node-tracker.structuredevent.category.md) | string | | +| [label?](./node-tracker.structuredevent.label.md) | string | (Optional) | +| [property?](./node-tracker.structuredevent.property.md) | string | (Optional) | +| [value?](./node-tracker.structuredevent.value.md) | number | (Optional) | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.structuredevent.property.md b/api-docs/docs/node-tracker/markdown/node-tracker.structuredevent.property.md new file mode 100644 index 000000000..3cf1a6ba1 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.structuredevent.property.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [StructuredEvent](./node-tracker.structuredevent.md) > [property](./node-tracker.structuredevent.property.md) + +## StructuredEvent.property property + +Signature: + +```typescript +property?: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.structuredevent.value.md b/api-docs/docs/node-tracker/markdown/node-tracker.structuredevent.value.md new file mode 100644 index 000000000..e1d1d056d --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.structuredevent.value.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [StructuredEvent](./node-tracker.structuredevent.md) > [value](./node-tracker.structuredevent.value.md) + +## StructuredEvent.value property + +Signature: + +```typescript +value?: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.timestamp.md b/api-docs/docs/node-tracker/markdown/node-tracker.timestamp.md new file mode 100644 index 000000000..0092ffdc2 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.timestamp.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [Timestamp](./node-tracker.timestamp.md) + +## Timestamp type + +Algebraic datatype representing possible timestamp type choice + +Signature: + +```typescript +type Timestamp = TrueTimestamp | DeviceTimestamp | number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.tracker.flush.md b/api-docs/docs/node-tracker/markdown/node-tracker.tracker.flush.md new file mode 100644 index 000000000..44a151f1b --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.tracker.flush.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [Tracker](./node-tracker.tracker.md) > [flush](./node-tracker.tracker.flush.md) + +## Tracker.flush property + +Calls flush on all emitters in order to send all queued events to the collector + +Signature: + +```typescript +flush: () => Promise; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.tracker.md b/api-docs/docs/node-tracker/markdown/node-tracker.tracker.md new file mode 100644 index 000000000..04f6d564b --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.tracker.md @@ -0,0 +1,23 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [Tracker](./node-tracker.tracker.md) + +## Tracker interface + +Signature: + +```typescript +interface Tracker extends TrackerCore +``` +Extends: TrackerCore + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [flush](./node-tracker.tracker.flush.md) | () => Promise<void> | Calls flush on all emitters in order to send all queued events to the collector | +| [setDomainUserId](./node-tracker.tracker.setdomainuserid.md) | (userId: string) => void | Set the domain user ID | +| [setNetworkUserId](./node-tracker.tracker.setnetworkuserid.md) | (userId: string) => void | Set the network user ID | +| [setSessionId](./node-tracker.tracker.setsessionid.md) | (sessionId: string) => void | Set the session ID (domain_sessionid in the atomic events) | +| [setSessionIndex](./node-tracker.tracker.setsessionindex.md) | (sessionIndex: string \| number) => void | Set the session index (domain_sessionidx in the atomic events) | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.tracker.setdomainuserid.md b/api-docs/docs/node-tracker/markdown/node-tracker.tracker.setdomainuserid.md new file mode 100644 index 000000000..afa5bbeca --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.tracker.setdomainuserid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [Tracker](./node-tracker.tracker.md) > [setDomainUserId](./node-tracker.tracker.setdomainuserid.md) + +## Tracker.setDomainUserId property + +Set the domain user ID + +Signature: + +```typescript +setDomainUserId: (userId: string) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.tracker.setnetworkuserid.md b/api-docs/docs/node-tracker/markdown/node-tracker.tracker.setnetworkuserid.md new file mode 100644 index 000000000..ae7ff4348 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.tracker.setnetworkuserid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [Tracker](./node-tracker.tracker.md) > [setNetworkUserId](./node-tracker.tracker.setnetworkuserid.md) + +## Tracker.setNetworkUserId property + +Set the network user ID + +Signature: + +```typescript +setNetworkUserId: (userId: string) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.tracker.setsessionid.md b/api-docs/docs/node-tracker/markdown/node-tracker.tracker.setsessionid.md new file mode 100644 index 000000000..24cc52945 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.tracker.setsessionid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [Tracker](./node-tracker.tracker.md) > [setSessionId](./node-tracker.tracker.setsessionid.md) + +## Tracker.setSessionId property + +Set the session ID (`domain_sessionid` in the atomic events) + +Signature: + +```typescript +setSessionId: (sessionId: string) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.tracker.setsessionindex.md b/api-docs/docs/node-tracker/markdown/node-tracker.tracker.setsessionindex.md new file mode 100644 index 000000000..0432007c2 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.tracker.setsessionindex.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [Tracker](./node-tracker.tracker.md) > [setSessionIndex](./node-tracker.tracker.setsessionindex.md) + +## Tracker.setSessionIndex property + +Set the session index (`domain_sessionidx` in the atomic events) + +Signature: + +```typescript +setSessionIndex: (sessionIndex: string | number) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackerconfiguration.appid.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackerconfiguration.appid.md new file mode 100644 index 000000000..2db6fb611 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackerconfiguration.appid.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerConfiguration](./node-tracker.trackerconfiguration.md) > [appId](./node-tracker.trackerconfiguration.appid.md) + +## TrackerConfiguration.appId property + +Signature: + +```typescript +appId: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackerconfiguration.encodebase64.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackerconfiguration.encodebase64.md new file mode 100644 index 000000000..185fa5a9b --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackerconfiguration.encodebase64.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerConfiguration](./node-tracker.trackerconfiguration.md) > [encodeBase64](./node-tracker.trackerconfiguration.encodebase64.md) + +## TrackerConfiguration.encodeBase64 property + +Whether unstructured events and custom contexts should be base64 encoded. + +Signature: + +```typescript +encodeBase64?: boolean; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackerconfiguration.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackerconfiguration.md new file mode 100644 index 000000000..a75af36b9 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackerconfiguration.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerConfiguration](./node-tracker.trackerconfiguration.md) + +## TrackerConfiguration interface + +Signature: + +```typescript +interface TrackerConfiguration +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [appId](./node-tracker.trackerconfiguration.appid.md) | string | | +| [encodeBase64?](./node-tracker.trackerconfiguration.encodebase64.md) | boolean | (Optional) Whether unstructured events and custom contexts should be base64 encoded. | +| [namespace](./node-tracker.trackerconfiguration.namespace.md) | string | | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackerconfiguration.namespace.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackerconfiguration.namespace.md new file mode 100644 index 000000000..fefc411bb --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackerconfiguration.namespace.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerConfiguration](./node-tracker.trackerconfiguration.md) > [namespace](./node-tracker.trackerconfiguration.namespace.md) + +## TrackerConfiguration.namespace property + +Signature: + +```typescript +namespace: string; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.addglobalcontexts.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.addglobalcontexts.md new file mode 100644 index 000000000..3ba235436 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.addglobalcontexts.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [addGlobalContexts](./node-tracker.trackercore.addglobalcontexts.md) + +## TrackerCore.addGlobalContexts() method + +Adds contexts globally, contexts added here will be attached to all applicable events + +Signature: + +```typescript +addGlobalContexts(contexts: Array | Record): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| contexts | Array<ConditionalContextProvider \| ContextPrimitive> \| Record<string, ConditionalContextProvider \| ContextPrimitive> | An array containing either contexts or a conditional contexts | + +Returns: + +void + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.addpayloaddict.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.addpayloaddict.md new file mode 100644 index 000000000..e57e6f3bd --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.addpayloaddict.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [addPayloadDict](./node-tracker.trackercore.addpayloaddict.md) + +## TrackerCore.addPayloadDict() method + +Merges a dictionary into payloadPairs + +Signature: + +```typescript +addPayloadDict(dict: Payload): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| dict | Payload | Adds a new payload dictionary to the existing one | + +Returns: + +void + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.addpayloadpair.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.addpayloadpair.md new file mode 100644 index 000000000..801ba6a44 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.addpayloadpair.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [addPayloadPair](./node-tracker.trackercore.addpayloadpair.md) + +## TrackerCore.addPayloadPair property + +Set a persistent key-value pair to be added to every payload + +Signature: + +```typescript +addPayloadPair: (key: string, value: unknown) => void; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.addplugin.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.addplugin.md new file mode 100644 index 000000000..fc585d9cf --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.addplugin.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [addPlugin](./node-tracker.trackercore.addplugin.md) + +## TrackerCore.addPlugin() method + +Add a plugin into the plugin collection after Core has already been initialised + +Signature: + +```typescript +addPlugin(configuration: CorePluginConfiguration): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| configuration | CorePluginConfiguration | The plugin to add | + +Returns: + +void + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.clearglobalcontexts.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.clearglobalcontexts.md new file mode 100644 index 000000000..76592d2d7 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.clearglobalcontexts.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [clearGlobalContexts](./node-tracker.trackercore.clearglobalcontexts.md) + +## TrackerCore.clearGlobalContexts() method + +Removes all global contexts + +Signature: + +```typescript +clearGlobalContexts(): void; +``` +Returns: + +void + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.deactivate.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.deactivate.md new file mode 100644 index 000000000..2d2babccd --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.deactivate.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [deactivate](./node-tracker.trackercore.deactivate.md) + +## TrackerCore.deactivate() method + +Deactivate tracker core including all plugins. This is useful for cleaning up resources or listeners that have been created. Once deactivated, the tracker won't be able to track any events. + +Signature: + +```typescript +deactivate(): void; +``` +Returns: + +void + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.getbase64encoding.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.getbase64encoding.md new file mode 100644 index 000000000..7b42a4140 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.getbase64encoding.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [getBase64Encoding](./node-tracker.trackercore.getbase64encoding.md) + +## TrackerCore.getBase64Encoding() method + +Get current base64 encoding state + +Signature: + +```typescript +getBase64Encoding(): boolean; +``` +Returns: + +boolean + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.md new file mode 100644 index 000000000..d63fc8419 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.md @@ -0,0 +1,47 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) + +## TrackerCore interface + +Export interface containing all Core functions + +Signature: + +```typescript +interface TrackerCore +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [addPayloadPair](./node-tracker.trackercore.addpayloadpair.md) | (key: string, value: unknown) => void | Set a persistent key-value pair to be added to every payload | +| [track](./node-tracker.trackercore.track.md) | (pb: PayloadBuilder, context?: Array<SelfDescribingJson> \| null, timestamp?: Timestamp \| null) => Payload \| undefined | Call with a payload from a buildX function Adds context and payloadPairs name-value pairs to the payload Applies the callback to the built payload | + +## Methods + +| Method | Description | +| --- | --- | +| [addGlobalContexts(contexts)](./node-tracker.trackercore.addglobalcontexts.md) | Adds contexts globally, contexts added here will be attached to all applicable events | +| [addPayloadDict(dict)](./node-tracker.trackercore.addpayloaddict.md) | Merges a dictionary into payloadPairs | +| [addPlugin(configuration)](./node-tracker.trackercore.addplugin.md) | Add a plugin into the plugin collection after Core has already been initialised | +| [clearGlobalContexts()](./node-tracker.trackercore.clearglobalcontexts.md) | Removes all global contexts | +| [deactivate()](./node-tracker.trackercore.deactivate.md) | Deactivate tracker core including all plugins. This is useful for cleaning up resources or listeners that have been created. Once deactivated, the tracker won't be able to track any events. | +| [getBase64Encoding()](./node-tracker.trackercore.getbase64encoding.md) | Get current base64 encoding state | +| [removeGlobalContexts(contexts)](./node-tracker.trackercore.removeglobalcontexts.md) | Removes previously added global context, performs a deep comparison of the contexts or conditional contexts | +| [resetPayloadPairs(dict)](./node-tracker.trackercore.resetpayloadpairs.md) | Replace payloadPairs with a new dictionary | +| [setAppId(appId)](./node-tracker.trackercore.setappid.md) | Set the application ID | +| [setBase64Encoding(encode)](./node-tracker.trackercore.setbase64encoding.md) | Turn base 64 encoding on or off | +| [setColorDepth(depth)](./node-tracker.trackercore.setcolordepth.md) | Set the color depth | +| [setIpAddress(ip)](./node-tracker.trackercore.setipaddress.md) | Set the IP address | +| [setLang(lang)](./node-tracker.trackercore.setlang.md) | Set the language | +| [setPlatform(value)](./node-tracker.trackercore.setplatform.md) | Set the platform | +| [setScreenResolution(width, height)](./node-tracker.trackercore.setscreenresolution.md) | Set the screen resolution | +| [setTimezone(timezone)](./node-tracker.trackercore.settimezone.md) | Set the timezone | +| [setTrackerNamespace(name)](./node-tracker.trackercore.settrackernamespace.md) | Set the tracker namespace | +| [setTrackerVersion(version)](./node-tracker.trackercore.settrackerversion.md) | Set the tracker version | +| [setUseragent(useragent)](./node-tracker.trackercore.setuseragent.md) | Set the Useragent | +| [setUserId(userId)](./node-tracker.trackercore.setuserid.md) | Set the user ID | +| [setViewport(width, height)](./node-tracker.trackercore.setviewport.md) | Set the viewport dimensions | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.removeglobalcontexts.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.removeglobalcontexts.md new file mode 100644 index 000000000..774aef674 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.removeglobalcontexts.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [removeGlobalContexts](./node-tracker.trackercore.removeglobalcontexts.md) + +## TrackerCore.removeGlobalContexts() method + +Removes previously added global context, performs a deep comparison of the contexts or conditional contexts + +Signature: + +```typescript +removeGlobalContexts(contexts: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| contexts | Array<ConditionalContextProvider \| ContextPrimitive \| string> | An array containing either contexts or a conditional contexts | + +Returns: + +void + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.resetpayloadpairs.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.resetpayloadpairs.md new file mode 100644 index 000000000..8113180dd --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.resetpayloadpairs.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [resetPayloadPairs](./node-tracker.trackercore.resetpayloadpairs.md) + +## TrackerCore.resetPayloadPairs() method + +Replace payloadPairs with a new dictionary + +Signature: + +```typescript +resetPayloadPairs(dict: Payload): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| dict | Payload | Resets all current payload pairs with a new dictionary of pairs | + +Returns: + +void + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setappid.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setappid.md new file mode 100644 index 000000000..e25c39c44 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setappid.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [setAppId](./node-tracker.trackercore.setappid.md) + +## TrackerCore.setAppId() method + +Set the application ID + +Signature: + +```typescript +setAppId(appId: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| appId | string | An application ID which identifies the current application | + +Returns: + +void + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setbase64encoding.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setbase64encoding.md new file mode 100644 index 000000000..7a6317ef0 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setbase64encoding.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [setBase64Encoding](./node-tracker.trackercore.setbase64encoding.md) + +## TrackerCore.setBase64Encoding() method + +Turn base 64 encoding on or off + +Signature: + +```typescript +setBase64Encoding(encode: boolean): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| encode | boolean | Whether to encode payload | + +Returns: + +void + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setcolordepth.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setcolordepth.md new file mode 100644 index 000000000..b63a709dd --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setcolordepth.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [setColorDepth](./node-tracker.trackercore.setcolordepth.md) + +## TrackerCore.setColorDepth() method + +Set the color depth + +Signature: + +```typescript +setColorDepth(depth: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| depth | string | A color depth value as string | + +Returns: + +void + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setipaddress.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setipaddress.md new file mode 100644 index 000000000..3b67872fb --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setipaddress.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [setIpAddress](./node-tracker.trackercore.setipaddress.md) + +## TrackerCore.setIpAddress() method + +Set the IP address + +Signature: + +```typescript +setIpAddress(ip: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| ip | string | An IP Address string | + +Returns: + +void + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setlang.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setlang.md new file mode 100644 index 000000000..899bca60d --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setlang.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [setLang](./node-tracker.trackercore.setlang.md) + +## TrackerCore.setLang() method + +Set the language + +Signature: + +```typescript +setLang(lang: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| lang | string | A language string e.g. 'en-UK' | + +Returns: + +void + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setplatform.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setplatform.md new file mode 100644 index 000000000..88e822f73 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setplatform.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [setPlatform](./node-tracker.trackercore.setplatform.md) + +## TrackerCore.setPlatform() method + +Set the platform + +Signature: + +```typescript +setPlatform(value: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| value | string | A valid Snowplow platform value | + +Returns: + +void + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setscreenresolution.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setscreenresolution.md new file mode 100644 index 000000000..a911fd57c --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setscreenresolution.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [setScreenResolution](./node-tracker.trackercore.setscreenresolution.md) + +## TrackerCore.setScreenResolution() method + +Set the screen resolution + +Signature: + +```typescript +setScreenResolution(width: string, height: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| width | string | screen resolution width | +| height | string | screen resolution height | + +Returns: + +void + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.settimezone.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.settimezone.md new file mode 100644 index 000000000..ae1538649 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.settimezone.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [setTimezone](./node-tracker.trackercore.settimezone.md) + +## TrackerCore.setTimezone() method + +Set the timezone + +Signature: + +```typescript +setTimezone(timezone: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| timezone | string | A timezone string | + +Returns: + +void + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.settrackernamespace.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.settrackernamespace.md new file mode 100644 index 000000000..58263903b --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.settrackernamespace.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [setTrackerNamespace](./node-tracker.trackercore.settrackernamespace.md) + +## TrackerCore.setTrackerNamespace() method + +Set the tracker namespace + +Signature: + +```typescript +setTrackerNamespace(name: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| name | string | The trackers namespace | + +Returns: + +void + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.settrackerversion.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.settrackerversion.md new file mode 100644 index 000000000..1b8824e87 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.settrackerversion.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [setTrackerVersion](./node-tracker.trackercore.settrackerversion.md) + +## TrackerCore.setTrackerVersion() method + +Set the tracker version + +Signature: + +```typescript +setTrackerVersion(version: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| version | string | The version of the current tracker | + +Returns: + +void + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setuseragent.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setuseragent.md new file mode 100644 index 000000000..ca24eafb3 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setuseragent.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [setUseragent](./node-tracker.trackercore.setuseragent.md) + +## TrackerCore.setUseragent() method + +Set the Useragent + +Signature: + +```typescript +setUseragent(useragent: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| useragent | string | A useragent string | + +Returns: + +void + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setuserid.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setuserid.md new file mode 100644 index 000000000..4fe139f63 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setuserid.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [setUserId](./node-tracker.trackercore.setuserid.md) + +## TrackerCore.setUserId() method + +Set the user ID + +Signature: + +```typescript +setUserId(userId: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| userId | string | The custom user id | + +Returns: + +void + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setviewport.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setviewport.md new file mode 100644 index 000000000..ef6eff820 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.setviewport.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [setViewport](./node-tracker.trackercore.setviewport.md) + +## TrackerCore.setViewport() method + +Set the viewport dimensions + +Signature: + +```typescript +setViewport(width: string, height: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| width | string | viewport width | +| height | string | viewport height | + +Returns: + +void + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.track.md b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.track.md new file mode 100644 index 000000000..30162bf17 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.trackercore.track.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrackerCore](./node-tracker.trackercore.md) > [track](./node-tracker.trackercore.track.md) + +## TrackerCore.track property + +Call with a payload from a buildX function Adds context and payloadPairs name-value pairs to the payload Applies the callback to the built payload + +Signature: + +```typescript +track: (pb: PayloadBuilder, context?: Array | null, timestamp?: Timestamp | null) => Payload | undefined; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.truetimestamp.md b/api-docs/docs/node-tracker/markdown/node-tracker.truetimestamp.md new file mode 100644 index 000000000..d4b2ad656 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.truetimestamp.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrueTimestamp](./node-tracker.truetimestamp.md) + +## TrueTimestamp interface + +A representation of a True Timestamp (ttm) + +Signature: + +```typescript +interface TrueTimestamp +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [type](./node-tracker.truetimestamp.type.md) | "ttm" | | +| [value](./node-tracker.truetimestamp.value.md) | number | | + diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.truetimestamp.type.md b/api-docs/docs/node-tracker/markdown/node-tracker.truetimestamp.type.md new file mode 100644 index 000000000..1eb184bf3 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.truetimestamp.type.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrueTimestamp](./node-tracker.truetimestamp.md) > [type](./node-tracker.truetimestamp.type.md) + +## TrueTimestamp.type property + +Signature: + +```typescript +readonly type: "ttm"; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.truetimestamp.value.md b/api-docs/docs/node-tracker/markdown/node-tracker.truetimestamp.value.md new file mode 100644 index 000000000..0f8349f7b --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.truetimestamp.value.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [TrueTimestamp](./node-tracker.truetimestamp.md) > [value](./node-tracker.truetimestamp.value.md) + +## TrueTimestamp.value property + +Signature: + +```typescript +readonly value: number; +``` diff --git a/api-docs/docs/node-tracker/markdown/node-tracker.version.md b/api-docs/docs/node-tracker/markdown/node-tracker.version.md new file mode 100644 index 000000000..6d17a1434 --- /dev/null +++ b/api-docs/docs/node-tracker/markdown/node-tracker.version.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/node-tracker](./node-tracker.md) > [version](./node-tracker.version.md) + +## version variable + +Signature: + +```typescript +version: string +``` diff --git a/api-docs/docs/node-tracker/node-tracker.api.md b/api-docs/docs/node-tracker/node-tracker.api.md new file mode 100644 index 000000000..40280aaea --- /dev/null +++ b/api-docs/docs/node-tracker/node-tracker.api.md @@ -0,0 +1,566 @@ +## API Report File for "@snowplow/node-tracker" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public +export interface AdClickEvent { + advertiserId?: string; + bannerId?: string; + campaignId?: string; + clickId?: string; + cost?: number; + costModel?: "cpa" | "cpc" | "cpm"; + impressionId?: string; + targetUrl: string; + zoneId?: string; +} + +// @public +export interface AdConversionEvent { + action?: string; + advertiserId?: string; + campaignId?: string; + category?: string; + conversionId?: string; + cost?: number; + costModel?: "cpa" | "cpc" | "cpm"; + initialValue?: number; + property?: string; +} + +// @public +export interface AddToCartEvent { + category?: string; + currency?: string; + name?: string; + quantity: number; + sku: string; + unitPrice?: number; +} + +// @public +export interface AdImpressionEvent { + advertiserId?: string; + bannerId?: string; + campaignId?: string; + cost?: number; + costModel?: "cpa" | "cpc" | "cpm"; + impressionId?: string; + targetUrl?: string; + zoneId?: string; +} + +// @public +export function buildAdClick(event: AdClickEvent): PayloadBuilder; + +// @public +export function buildAdConversion(event: AdConversionEvent): PayloadBuilder; + +// @public +export function buildAddToCart(event: AddToCartEvent): PayloadBuilder; + +// @public +export function buildAdImpression(event: AdImpressionEvent): PayloadBuilder; + +// @public +export function buildConsentGranted(event: ConsentGrantedEvent): EventPayloadAndContext; + +// @public +export function buildConsentWithdrawn(event: ConsentWithdrawnEvent): EventPayloadAndContext; + +// @public +export function buildEcommerceTransaction(event: EcommerceTransactionEvent): PayloadBuilder; + +// @public +export function buildEcommerceTransactionItem(event: EcommerceTransactionItemEvent): PayloadBuilder; + +// @public +export function buildFormFocusOrChange(event: FormFocusOrChangeEvent): PayloadBuilder; + +// @public +export function buildFormSubmission(event: FormSubmissionEvent): PayloadBuilder; + +// @public +export function buildLinkClick(event: LinkClickEvent): PayloadBuilder; + +// @public +export function buildPagePing(event: PagePingEvent): PayloadBuilder; + +// @public +export function buildPageView(event: PageViewEvent): PayloadBuilder; + +// @public +export function buildRemoveFromCart(event: RemoveFromCartEvent): PayloadBuilder; + +// @public +export function buildScreenView(event: ScreenViewEvent): PayloadBuilder; + +// @public +export function buildSelfDescribingEvent>(event: SelfDescribingEvent): PayloadBuilder; + +// @public +export function buildSiteSearch(event: SiteSearchEvent): PayloadBuilder; + +// @public +export function buildSocialInteraction(event: SocialInteractionEvent): PayloadBuilder; + +// @public +export function buildStructEvent(event: StructuredEvent): PayloadBuilder; + +// @public +export type ConditionalContextProvider = FilterProvider | RuleSetProvider; + +// @public +export interface ConsentGrantedEvent { + description?: string; + expiry?: string; + id: string; + name?: string; + version: string; +} + +// @public +export interface ConsentWithdrawnEvent { + all: boolean; + description?: string; + id?: string; + name?: string; + version?: string; +} + +// @public +export interface ContextEvent { + event: Payload; + eventSchema: string; + eventType: string; +} + +// @public +export type ContextFilter = (args?: ContextEvent) => boolean; + +// @public +export type ContextGenerator = (args?: ContextEvent) => SelfDescribingJson | SelfDescribingJson[] | undefined; + +// @public +export type ContextPrimitive = SelfDescribingJson | ContextGenerator; + +// @public +export interface CoreConfiguration { + /* Should payloads be base64 encoded when built */ + // (undocumented) + base64?: boolean; + /* A list of all the plugins to include at load */ + // (undocumented) + callback?: (PayloadData: PayloadBuilder) => void; + /* A list of all the plugins to include at load */ + // (undocumented) + corePlugins?: Array; +} + +// @public +export interface CorePlugin { + activateCorePlugin?: (core: TrackerCore) => void; + afterTrack?: (payload: Payload) => void; + beforeTrack?: (payloadBuilder: PayloadBuilder) => void; + contexts?: () => SelfDescribingJson[]; + deactivatePlugin?: (core: TrackerCore) => void; + filter?: (payload: Payload) => boolean; + logger?: (logger: Logger) => void; +} + +// @public +export interface CorePluginConfiguration { + /* The plugin to add */ + // (undocumented) + plugin: CorePlugin; +} + +// @public (undocumented) +export type CustomEmitter = { + /* Function returning custom Emitter or Emitter[] to be used. If set, other options are irrelevant */ + customEmitter: () => Emitter | Array; +}; + +// @public +export interface DeviceTimestamp { + // (undocumented) + readonly type: "dtm"; + // (undocumented) + readonly value: number; +} + +// @public +export interface EcommerceTransactionEvent { + affiliation?: string; + city?: string; + country?: string; + currency?: string; + orderId: string; + shipping?: number; + state?: string; + tax?: number; + total: number; +} + +// @public +export interface EcommerceTransactionItemEvent { + category?: string; + currency?: string; + name?: string; + orderId: string; + price: number; + quantity?: number; + sku: string; +} + +// @public +export interface Emitter { + flush: () => Promise; + input: (payload: Payload) => Promise; + setAnonymousTracking: (anonymous: boolean) => void; + setBufferSize: (bufferSize: number) => void; + setCollectorUrl: (url: string) => void; +} + +// @public (undocumented) +export interface EmitterConfiguration extends EmitterConfigurationBase { + /* The collector URL to which events will be sent */ + // (undocumented) + endpoint: string; + /* http or https. Defaults to https */ + // (undocumented) + port?: number; + /* http or https. Defaults to https */ + // (undocumented) + protocol?: "http" | "https"; + /* http or https. Defaults to https */ + // (undocumented) + serverAnonymization?: boolean; +} + +// @public (undocumented) +export interface EmitterConfigurationBase { + bufferSize?: number; + connectionTimeout?: number; + cookieExtensionService?: string; + credentials?: "omit" | "same-origin" | "include"; + customFetch?: (input: Request, options?: RequestInit) => Promise; + customHeaders?: Record; + dontRetryStatusCodes?: number[]; + eventMethod?: EventMethod; + eventStore?: EventStore; + // @deprecated (undocumented) + idService?: string; + keepalive?: boolean; + maxGetBytes?: number; + maxPostBytes?: number; + onRequestFailure?: (data: RequestFailure, response?: Response) => void; + onRequestSuccess?: (data: EventBatch, response: Response) => void; + postPath?: string; + retryFailedRequests?: boolean; + retryStatusCodes?: number[]; + useStm?: boolean; +} + +// @public +export type EventBatch = Payload[]; + +// @public +export type EventJson = Array; + +// @public +export type EventJsonWithKeys = { + keyIfEncoded: string; + keyIfNotEncoded: string; + json: Record; +}; + +// @public (undocumented) +export type EventMethod = "post" | "get"; + +// @public +export interface EventPayloadAndContext { + context: Array; + event: PayloadBuilder; +} + +// @public +export interface EventStore { + add: (payload: EventStorePayload) => Promise; + count: () => Promise; + getAll: () => Promise; + getAllPayloads: () => Promise; + iterator: () => EventStoreIterator; + removeHead: (count: number) => Promise; +} + +// @public (undocumented) +export interface EventStoreConfiguration { + maxSize?: number; +} + +// @public +export interface EventStoreIterator { + // Warning: (ae-forgotten-export) The symbol "EventStoreIteratorNextResult" needs to be exported by the entry point index.module.d.ts + next: () => Promise; +} + +// @public (undocumented) +export interface EventStorePayload { + payload: Payload; + svrAnon?: boolean; +} + +// @public +export type FilterProvider = [ +ContextFilter, +Array | ContextPrimitive +]; + +// @public +export type FormElement = { + name: string; + value: string | null; + nodeName: string; + type?: string | null; +}; + +// @public +export interface FormFocusOrChangeEvent { + elementClasses?: Array | null; + elementId: string; + formId: string; + nodeName: string; + schema: "change_form" | "focus_form"; + type?: string | null; + value: string | null; +} + +// @public +export interface FormSubmissionEvent { + elements?: Array; + formClasses?: Array; + formId: string; +} + +// @public +export type JsonProcessor = (payloadBuilder: PayloadBuilder, jsonForProcessing: EventJson, contextEntitiesForProcessing: SelfDescribingJson[]) => void; + +// @public +export interface LinkClickEvent { + elementClasses?: Array; + elementContent?: string; + elementId?: string; + elementTarget?: string; + targetUrl: string; +} + +// @public (undocumented) +export enum LOG_LEVEL { + // (undocumented) + debug = 3, + // (undocumented) + error = 1, + // (undocumented) + info = 4, + // (undocumented) + none = 0, + // (undocumented) + warn = 2 +} + +// @public (undocumented) +export interface Logger { + // (undocumented) + debug: (message: string, ...extraParams: unknown[]) => void; + // (undocumented) + error: (message: string, error?: unknown, ...extraParams: unknown[]) => void; + // (undocumented) + info: (message: string, ...extraParams: unknown[]) => void; + // (undocumented) + setLogLevel: (level: LOG_LEVEL) => void; + // (undocumented) + warn: (message: string, error?: unknown, ...extraParams: unknown[]) => void; +} + +// @public (undocumented) +export function newTracker(trackerConfiguration: TrackerConfiguration, emitterConfiguration: NodeEmitterConfiguration | NodeEmitterConfiguration[]): Tracker; + +// @public (undocumented) +export type NodeEmitterConfiguration = CustomEmitter | EmitterConfiguration; + +// @public +export interface PagePingEvent extends PageViewEvent { + maxXOffset?: number; + maxYOffset?: number; + minXOffset?: number; + minYOffset?: number; +} + +// @public +export interface PageViewEvent { + pageTitle?: string | null; + pageUrl?: string | null; + referrer?: string | null; +} + +// @public +export type Payload = Record; + +// @public +export interface PayloadBuilder { + add: (key: string, value: unknown) => void; + addContextEntity: (entity: SelfDescribingJson) => void; + addDict: (dict: Payload) => void; + addJson: (keyIfEncoded: string, keyIfNotEncoded: string, json: Record) => void; + build: () => Payload; + getJson: () => EventJson; + getPayload: () => Payload; + withJsonProcessor: (jsonProcessor: JsonProcessor) => void; +} + +// @public +export interface RemoveFromCartEvent { + category?: string; + currency?: string; + name?: string; + quantity: number; + sku: string; + unitPrice?: number; +} + +// @public +export type RequestFailure = { + events: EventBatch; + status?: number; + message?: string; + willRetry: boolean; +}; + +// @public +export interface RuleSet { + // (undocumented) + accept?: Array | string; + // (undocumented) + reject?: Array | string; +} + +// @public +export type RuleSetProvider = [ +RuleSet, +Array | ContextPrimitive +]; + +// @public +export interface ScreenViewEvent { + id?: string; + name?: string; +} + +// @public +export interface SelfDescribingEvent> { + event: SelfDescribingJson; +} + +// @public +export type SelfDescribingJson> = { + schema: string; + data: T extends any[] ? never : T extends {} ? T : never; +}; + +// @public +export interface SiteSearchEvent { + filters?: Record; + pageResults?: number; + terms: Array; + totalResults?: number; +} + +// @public +export interface SocialInteractionEvent { + action: string; + network: string; + target?: string; +} + +// @public +export interface StructuredEvent { + // (undocumented) + action: string; + // (undocumented) + category: string; + // (undocumented) + label?: string; + // (undocumented) + property?: string; + // (undocumented) + value?: number; +} + +// @public +export type Timestamp = TrueTimestamp | DeviceTimestamp | number; + +// @public (undocumented) +export interface Tracker extends TrackerCore { + flush: () => Promise; + setDomainUserId: (userId: string) => void; + setNetworkUserId: (userId: string) => void; + setSessionId: (sessionId: string) => void; + setSessionIndex: (sessionIndex: string | number) => void; +} + +// @public (undocumented) +export interface TrackerConfiguration { + /* The namespace of the tracker */ + // (undocumented) + appId: string; + /* The application ID */ + encodeBase64?: boolean; + /* The application ID */ + // (undocumented) + namespace: string; +} + +// @public +export interface TrackerCore { + addGlobalContexts(contexts: Array | Record): void; + addPayloadDict(dict: Payload): void; + addPayloadPair: (key: string, value: unknown) => void; + addPlugin(configuration: CorePluginConfiguration): void; + clearGlobalContexts(): void; + deactivate(): void; + getBase64Encoding(): boolean; + removeGlobalContexts(contexts: Array): void; + resetPayloadPairs(dict: Payload): void; + setAppId(appId: string): void; + setBase64Encoding(encode: boolean): void; + setColorDepth(depth: string): void; + setIpAddress(ip: string): void; + setLang(lang: string): void; + setPlatform(value: string): void; + setScreenResolution(width: string, height: string): void; + setTimezone(timezone: string): void; + setTrackerNamespace(name: string): void; + setTrackerVersion(version: string): void; + setUseragent(useragent: string): void; + setUserId(userId: string): void; + setViewport(width: string, height: string): void; + track: (pb: PayloadBuilder, context?: Array | null, timestamp?: Timestamp | null) => Payload | undefined; +} + +// @public +export interface TrueTimestamp { + // (undocumented) + readonly type: "ttm"; + // (undocumented) + readonly value: number; +} + +// @public (undocumented) +export const version: string; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/api-docs/docs/react-native-tracker/markdown/index.md b/api-docs/docs/react-native-tracker/markdown/index.md new file mode 100644 index 000000000..58bc37403 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/index.md @@ -0,0 +1,12 @@ + + +[Home](./index.md) + +## API Reference + +## Packages + +| Package | Description | +| --- | --- | +| [@snowplow/react-native-tracker](./react-native-tracker.md) | | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.applifecycleconfiguration.appbuild.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.applifecycleconfiguration.appbuild.md new file mode 100644 index 000000000..03a2ecbd5 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.applifecycleconfiguration.appbuild.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [AppLifecycleConfiguration](./react-native-tracker.applifecycleconfiguration.md) > [appBuild](./react-native-tracker.applifecycleconfiguration.appbuild.md) + +## AppLifecycleConfiguration.appBuild property + +Build name of the application e.g s9f2k2d or 1.1.0 beta + +Entity schema: `iglu:com.snowplowanalytics.mobile/application/jsonschema/1-0-0` + +Signature: + +```typescript +appBuild?: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.applifecycleconfiguration.appversion.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.applifecycleconfiguration.appversion.md new file mode 100644 index 000000000..06a720972 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.applifecycleconfiguration.appversion.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [AppLifecycleConfiguration](./react-native-tracker.applifecycleconfiguration.md) > [appVersion](./react-native-tracker.applifecycleconfiguration.appversion.md) + +## AppLifecycleConfiguration.appVersion property + +Version number of the application e.g 1.1.0 (semver or git commit hash). + +Entity schema if `appBuild` property is set: `iglu:com.snowplowanalytics.mobile/application/jsonschema/1-0-0` Entity schema if `appBuild` property is not set: `iglu:com.snowplowanalytics.snowplow/application/jsonschema/1-0-0` + +Signature: + +```typescript +appVersion?: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.applifecycleconfiguration.installautotracking.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.applifecycleconfiguration.installautotracking.md new file mode 100644 index 000000000..d052ad96e --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.applifecycleconfiguration.installautotracking.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [AppLifecycleConfiguration](./react-native-tracker.applifecycleconfiguration.md) > [installAutotracking](./react-native-tracker.applifecycleconfiguration.installautotracking.md) + +## AppLifecycleConfiguration.installAutotracking property + +Whether to automatically track app install event on first run. + +Schema: `iglu:com.snowplowanalytics.mobile/application_install/jsonschema/1-0-0` + +Signature: + +```typescript +installAutotracking?: boolean; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.applifecycleconfiguration.lifecycleautotracking.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.applifecycleconfiguration.lifecycleautotracking.md new file mode 100644 index 000000000..47c7faf07 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.applifecycleconfiguration.lifecycleautotracking.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [AppLifecycleConfiguration](./react-native-tracker.applifecycleconfiguration.md) > [lifecycleAutotracking](./react-native-tracker.applifecycleconfiguration.lifecycleautotracking.md) + +## AppLifecycleConfiguration.lifecycleAutotracking property + +Whether to automatically track app lifecycle events (app foreground and background events). Also adds a lifecycle context entity to all events. + +Foreground event schema: `iglu:com.snowplowanalytics.snowplow/application_foreground/jsonschema/1-0-0` Background event schema: `iglu:com.snowplowanalytics.snowplow/application_background/jsonschema/1-0-0` Context entity schema: `iglu:com.snowplowanalytics.mobile/application_lifecycle/jsonschema/1-0-0` + +Signature: + +```typescript +lifecycleAutotracking?: boolean; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.applifecycleconfiguration.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.applifecycleconfiguration.md new file mode 100644 index 000000000..bc402d9b3 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.applifecycleconfiguration.md @@ -0,0 +1,23 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [AppLifecycleConfiguration](./react-native-tracker.applifecycleconfiguration.md) + +## AppLifecycleConfiguration interface + +Configuration for app lifecycle tracking + +Signature: + +```typescript +export interface AppLifecycleConfiguration +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [appBuild?](./react-native-tracker.applifecycleconfiguration.appbuild.md) | string | (Optional) Build name of the application e.g s9f2k2d or 1.1.0 betaEntity schema: iglu:com.snowplowanalytics.mobile/application/jsonschema/1-0-0 | +| [appVersion?](./react-native-tracker.applifecycleconfiguration.appversion.md) | string | (Optional) Version number of the application e.g 1.1.0 (semver or git commit hash).Entity schema if appBuild property is set: iglu:com.snowplowanalytics.mobile/application/jsonschema/1-0-0 Entity schema if appBuild property is not set: iglu:com.snowplowanalytics.snowplow/application/jsonschema/1-0-0 | +| [installAutotracking?](./react-native-tracker.applifecycleconfiguration.installautotracking.md) | boolean | (Optional) Whether to automatically track app install event on first run.Schema: iglu:com.snowplowanalytics.mobile/application_install/jsonschema/1-0-0 | +| [lifecycleAutotracking?](./react-native-tracker.applifecycleconfiguration.lifecycleautotracking.md) | boolean | (Optional) Whether to automatically track app lifecycle events (app foreground and background events). Also adds a lifecycle context entity to all events.Foreground event schema: iglu:com.snowplowanalytics.snowplow/application_foreground/jsonschema/1-0-0 Background event schema: iglu:com.snowplowanalytics.snowplow/application_background/jsonschema/1-0-0 Context entity schema: iglu:com.snowplowanalytics.mobile/application_lifecycle/jsonschema/1-0-0 | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.asyncstorage.getitem.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.asyncstorage.getitem.md new file mode 100644 index 000000000..1fcf3de87 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.asyncstorage.getitem.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [AsyncStorage](./react-native-tracker.asyncstorage.md) > [getItem](./react-native-tracker.asyncstorage.getitem.md) + +## AsyncStorage.getItem property + +Signature: + +```typescript +getItem: (key: string) => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.asyncstorage.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.asyncstorage.md new file mode 100644 index 000000000..ad1c77a88 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.asyncstorage.md @@ -0,0 +1,19 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [AsyncStorage](./react-native-tracker.asyncstorage.md) + +## AsyncStorage interface + +Signature: + +```typescript +export interface AsyncStorage +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [getItem](./react-native-tracker.asyncstorage.getitem.md) | (key: string) => Promise<string \| null> | | +| [setItem](./react-native-tracker.asyncstorage.setitem.md) | (key: string, value: string) => Promise<void> | | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.asyncstorage.setitem.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.asyncstorage.setitem.md new file mode 100644 index 000000000..5d3b79d9d --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.asyncstorage.setitem.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [AsyncStorage](./react-native-tracker.asyncstorage.md) > [setItem](./react-native-tracker.asyncstorage.setitem.md) + +## AsyncStorage.setItem property + +Signature: + +```typescript +setItem: (key: string, value: string) => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.conditionalcontextprovider.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.conditionalcontextprovider.md new file mode 100644 index 000000000..ae264a7a2 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.conditionalcontextprovider.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [ConditionalContextProvider](./react-native-tracker.conditionalcontextprovider.md) + +## ConditionalContextProvider type + +Conditional context providers are two element arrays used to decide when to attach contexts, where: - the first element is some conditional criterion - the second element is any number of context primitives + +Signature: + +```typescript +type ConditionalContextProvider = FilterProvider | RuleSetProvider; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.contextfilter.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.contextfilter.md new file mode 100644 index 000000000..b458e6646 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.contextfilter.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [ContextFilter](./react-native-tracker.contextfilter.md) + +## ContextFilter type + +A context filter is a user-supplied callback that is evaluated for each event to determine if the context associated with the filter should be attached to the event + +Signature: + +```typescript +type ContextFilter = (args?: ContextEvent) => boolean; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.contextgenerator.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.contextgenerator.md new file mode 100644 index 000000000..0cbf292e9 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.contextgenerator.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [ContextGenerator](./react-native-tracker.contextgenerator.md) + +## ContextGenerator type + +A context generator is a user-supplied callback that is evaluated for each event to allow an additional context to be dynamically attached to the event + +Signature: + +```typescript +type ContextGenerator = (args?: ContextEvent) => SelfDescribingJson | SelfDescribingJson[] | undefined; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.contextprimitive.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.contextprimitive.md new file mode 100644 index 000000000..e2fe51369 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.contextprimitive.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [ContextPrimitive](./react-native-tracker.contextprimitive.md) + +## ContextPrimitive type + +A context primitive is either a self-describing JSON or a context generator + +Signature: + +```typescript +type ContextPrimitive = SelfDescribingJson | ContextGenerator; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreconfiguration.base64.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreconfiguration.base64.md new file mode 100644 index 000000000..0bceab7f6 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreconfiguration.base64.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [CoreConfiguration](./react-native-tracker.coreconfiguration.md) > [base64](./react-native-tracker.coreconfiguration.base64.md) + +## CoreConfiguration.base64 property + +Signature: + +```typescript +base64?: boolean; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreconfiguration.callback.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreconfiguration.callback.md new file mode 100644 index 000000000..1e771a210 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreconfiguration.callback.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [CoreConfiguration](./react-native-tracker.coreconfiguration.md) > [callback](./react-native-tracker.coreconfiguration.callback.md) + +## CoreConfiguration.callback property + +Signature: + +```typescript +callback?: (PayloadData: PayloadBuilder) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreconfiguration.coreplugins.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreconfiguration.coreplugins.md new file mode 100644 index 000000000..01cb1e158 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreconfiguration.coreplugins.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [CoreConfiguration](./react-native-tracker.coreconfiguration.md) > [corePlugins](./react-native-tracker.coreconfiguration.coreplugins.md) + +## CoreConfiguration.corePlugins property + +Signature: + +```typescript +corePlugins?: Array; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreconfiguration.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreconfiguration.md new file mode 100644 index 000000000..1b3a10636 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreconfiguration.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [CoreConfiguration](./react-native-tracker.coreconfiguration.md) + +## CoreConfiguration interface + +The configuration object for the tracker core library + +Signature: + +```typescript +interface CoreConfiguration +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [base64?](./react-native-tracker.coreconfiguration.base64.md) | boolean | (Optional) | +| [callback?](./react-native-tracker.coreconfiguration.callback.md) | (PayloadData: PayloadBuilder) => void | (Optional) | +| [corePlugins?](./react-native-tracker.coreconfiguration.coreplugins.md) | Array<CorePlugin> | (Optional) | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.activatecoreplugin.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.activatecoreplugin.md new file mode 100644 index 000000000..90d55d741 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.activatecoreplugin.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [CorePlugin](./react-native-tracker.coreplugin.md) > [activateCorePlugin](./react-native-tracker.coreplugin.activatecoreplugin.md) + +## CorePlugin.activateCorePlugin property + +Called when the plugin is initialised during the trackerCore construction + +Signature: + +```typescript +activateCorePlugin?: (core: TrackerCore) => void; +``` + +## Remarks + +Use to capture the specific core instance for each instance of a core plugin + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.aftertrack.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.aftertrack.md new file mode 100644 index 000000000..d50881781 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.aftertrack.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [CorePlugin](./react-native-tracker.coreplugin.md) > [afterTrack](./react-native-tracker.coreplugin.aftertrack.md) + +## CorePlugin.afterTrack property + +Called just after the trackerCore callback fires + +Signature: + +```typescript +afterTrack?: (payload: Payload) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.beforetrack.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.beforetrack.md new file mode 100644 index 000000000..a172901cf --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.beforetrack.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [CorePlugin](./react-native-tracker.coreplugin.md) > [beforeTrack](./react-native-tracker.coreplugin.beforetrack.md) + +## CorePlugin.beforeTrack property + +Called before the `filter` method is called and before the trackerCore callback fires (if the filter passes) + +Signature: + +```typescript +beforeTrack?: (payloadBuilder: PayloadBuilder) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.contexts.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.contexts.md new file mode 100644 index 000000000..015b3117c --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.contexts.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [CorePlugin](./react-native-tracker.coreplugin.md) > [contexts](./react-native-tracker.coreplugin.contexts.md) + +## CorePlugin.contexts property + +Called when constructing the context for each event Useful for adding additional context to events + +Signature: + +```typescript +contexts?: () => SelfDescribingJson[]; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.deactivateplugin.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.deactivateplugin.md new file mode 100644 index 000000000..edbdd11ce --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.deactivateplugin.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [CorePlugin](./react-native-tracker.coreplugin.md) > [deactivatePlugin](./react-native-tracker.coreplugin.deactivateplugin.md) + +## CorePlugin.deactivatePlugin property + +Called when the tracker is being destroyed. Should be used to clean up any resources or listeners that the plugin has created. + +Signature: + +```typescript +deactivatePlugin?: (core: TrackerCore) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.filter.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.filter.md new file mode 100644 index 000000000..7c621722c --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.filter.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [CorePlugin](./react-native-tracker.coreplugin.md) > [filter](./react-native-tracker.coreplugin.filter.md) + +## CorePlugin.filter property + +Called before the payload is sent to the callback to decide whether to send the payload or skip it + +Signature: + +```typescript +filter?: (payload: Payload) => boolean; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.logger.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.logger.md new file mode 100644 index 000000000..65ad62785 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.logger.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [CorePlugin](./react-native-tracker.coreplugin.md) > [logger](./react-native-tracker.coreplugin.logger.md) + +## CorePlugin.logger property + +Passed a logger instance which can be used to send log information to the active logger + +Signature: + +```typescript +logger?: (logger: Logger) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.md new file mode 100644 index 000000000..85529ca8c --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.coreplugin.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [CorePlugin](./react-native-tracker.coreplugin.md) + +## CorePlugin interface + +Interface which defines Core Plugins + +Signature: + +```typescript +interface CorePlugin +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [activateCorePlugin?](./react-native-tracker.coreplugin.activatecoreplugin.md) | (core: TrackerCore) => void | (Optional) Called when the plugin is initialised during the trackerCore construction | +| [afterTrack?](./react-native-tracker.coreplugin.aftertrack.md) | (payload: Payload) => void | (Optional) Called just after the trackerCore callback fires | +| [beforeTrack?](./react-native-tracker.coreplugin.beforetrack.md) | (payloadBuilder: PayloadBuilder) => void | (Optional) Called before the filter method is called and before the trackerCore callback fires (if the filter passes) | +| [contexts?](./react-native-tracker.coreplugin.contexts.md) | () => SelfDescribingJson\[\] | (Optional) Called when constructing the context for each event Useful for adding additional context to events | +| [deactivatePlugin?](./react-native-tracker.coreplugin.deactivateplugin.md) | (core: TrackerCore) => void | (Optional) Called when the tracker is being destroyed. Should be used to clean up any resources or listeners that the plugin has created. | +| [filter?](./react-native-tracker.coreplugin.filter.md) | (payload: Payload) => boolean | (Optional) Called before the payload is sent to the callback to decide whether to send the payload or skip it | +| [logger?](./react-native-tracker.coreplugin.logger.md) | (logger: Logger) => void | (Optional) Passed a logger instance which can be used to send log information to the active logger | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.corepluginconfiguration.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.corepluginconfiguration.md new file mode 100644 index 000000000..e14a922ec --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.corepluginconfiguration.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [CorePluginConfiguration](./react-native-tracker.corepluginconfiguration.md) + +## CorePluginConfiguration interface + +The configuration of the plugin to add + +Signature: + +```typescript +interface CorePluginConfiguration +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [plugin](./react-native-tracker.corepluginconfiguration.plugin.md) | CorePlugin | | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.corepluginconfiguration.plugin.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.corepluginconfiguration.plugin.md new file mode 100644 index 000000000..6ab300b27 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.corepluginconfiguration.plugin.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [CorePluginConfiguration](./react-native-tracker.corepluginconfiguration.md) > [plugin](./react-native-tracker.corepluginconfiguration.plugin.md) + +## CorePluginConfiguration.plugin property + +Signature: + +```typescript +plugin: CorePlugin; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.deeplinkconfiguration.deeplinkcontext.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.deeplinkconfiguration.deeplinkcontext.md new file mode 100644 index 000000000..ad1dc7387 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.deeplinkconfiguration.deeplinkcontext.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [DeepLinkConfiguration](./react-native-tracker.deeplinkconfiguration.md) > [deepLinkContext](./react-native-tracker.deeplinkconfiguration.deeplinkcontext.md) + +## DeepLinkConfiguration.deepLinkContext property + +Whether to track the deep link context entity with information from the deep link received event on the first screen view event. + +Signature: + +```typescript +deepLinkContext?: boolean; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.deeplinkconfiguration.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.deeplinkconfiguration.md new file mode 100644 index 000000000..506c7ed7a --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.deeplinkconfiguration.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [DeepLinkConfiguration](./react-native-tracker.deeplinkconfiguration.md) + +## DeepLinkConfiguration interface + +Configuration for deep link tracking + +Signature: + +```typescript +export interface DeepLinkConfiguration +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [deepLinkContext?](./react-native-tracker.deeplinkconfiguration.deeplinkcontext.md) | boolean | (Optional) Whether to track the deep link context entity with information from the deep link received event on the first screen view event. | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.deeplinkreceivedprops.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.deeplinkreceivedprops.md new file mode 100644 index 000000000..6a10e920c --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.deeplinkreceivedprops.md @@ -0,0 +1,16 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [DeepLinkReceivedProps](./react-native-tracker.deeplinkreceivedprops.md) + +## DeepLinkReceivedProps type + +DeepLinkReceived event properties schema: iglu:com.snowplowanalytics.mobile/deep\_link\_received/jsonschema/1-0-0 + +Signature: + +```typescript +export declare type DeepLinkReceivedProps = { + url: string; + referrer?: string; +}; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.devicetimestamp.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.devicetimestamp.md new file mode 100644 index 000000000..22804fc75 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.devicetimestamp.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [DeviceTimestamp](./react-native-tracker.devicetimestamp.md) + +## DeviceTimestamp interface + +A representation of a Device Timestamp (dtm) + +Signature: + +```typescript +interface DeviceTimestamp +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [type](./react-native-tracker.devicetimestamp.type.md) | "dtm" | | +| [value](./react-native-tracker.devicetimestamp.value.md) | number | | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.devicetimestamp.type.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.devicetimestamp.type.md new file mode 100644 index 000000000..b02eee053 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.devicetimestamp.type.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [DeviceTimestamp](./react-native-tracker.devicetimestamp.md) > [type](./react-native-tracker.devicetimestamp.type.md) + +## DeviceTimestamp.type property + +Signature: + +```typescript +readonly type: "dtm"; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.devicetimestamp.value.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.devicetimestamp.value.md new file mode 100644 index 000000000..2b5a2fb23 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.devicetimestamp.value.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [DeviceTimestamp](./react-native-tracker.devicetimestamp.md) > [value](./react-native-tracker.devicetimestamp.value.md) + +## DeviceTimestamp.value property + +Signature: + +```typescript +readonly value: number; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitter.flush.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitter.flush.md new file mode 100644 index 000000000..351d0e37e --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitter.flush.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [Emitter](./react-native-tracker.emitter.md) > [flush](./react-native-tracker.emitter.flush.md) + +## Emitter.flush property + +Forces the emitter to send all events in the event store to the collector. + +Signature: + +```typescript +flush: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitter.input.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitter.input.md new file mode 100644 index 000000000..5f22e9b5c --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitter.input.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [Emitter](./react-native-tracker.emitter.md) > [input](./react-native-tracker.emitter.input.md) + +## Emitter.input property + +Adds a payload to the event store or sends it to the collector. + +Signature: + +```typescript +input: (payload: Payload) => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitter.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitter.md new file mode 100644 index 000000000..24f95cde0 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitter.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [Emitter](./react-native-tracker.emitter.md) + +## Emitter interface + +Emitter is responsible for sending events to the collector. It manages the event queue and sends events in batches depending on configuration. + +Signature: + +```typescript +interface Emitter +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [flush](./react-native-tracker.emitter.flush.md) | () => Promise<void> | Forces the emitter to send all events in the event store to the collector. | +| [input](./react-native-tracker.emitter.input.md) | (payload: Payload) => Promise<void> | Adds a payload to the event store or sends it to the collector. | +| [setAnonymousTracking](./react-native-tracker.emitter.setanonymoustracking.md) | (anonymous: boolean) => void | Sets the server anonymization flag. | +| [setBufferSize](./react-native-tracker.emitter.setbuffersize.md) | (bufferSize: number) => void | Updates the buffer size of the emitter. | +| [setCollectorUrl](./react-native-tracker.emitter.setcollectorurl.md) | (url: string) => void | Updates the collector URL to which events will be sent. | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitter.setanonymoustracking.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitter.setanonymoustracking.md new file mode 100644 index 000000000..7de2afba3 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitter.setanonymoustracking.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [Emitter](./react-native-tracker.emitter.md) > [setAnonymousTracking](./react-native-tracker.emitter.setanonymoustracking.md) + +## Emitter.setAnonymousTracking property + +Sets the server anonymization flag. + +Signature: + +```typescript +setAnonymousTracking: (anonymous: boolean) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitter.setbuffersize.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitter.setbuffersize.md new file mode 100644 index 000000000..630e81e5e --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitter.setbuffersize.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [Emitter](./react-native-tracker.emitter.md) > [setBufferSize](./react-native-tracker.emitter.setbuffersize.md) + +## Emitter.setBufferSize property + +Updates the buffer size of the emitter. + +Signature: + +```typescript +setBufferSize: (bufferSize: number) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitter.setcollectorurl.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitter.setcollectorurl.md new file mode 100644 index 000000000..2d170a707 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitter.setcollectorurl.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [Emitter](./react-native-tracker.emitter.md) > [setCollectorUrl](./react-native-tracker.emitter.setcollectorurl.md) + +## Emitter.setCollectorUrl property + +Updates the collector URL to which events will be sent. + +Signature: + +```typescript +setCollectorUrl: (url: string) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfiguration.endpoint.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfiguration.endpoint.md new file mode 100644 index 000000000..6e3c59555 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfiguration.endpoint.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfiguration](./react-native-tracker.emitterconfiguration.md) > [endpoint](./react-native-tracker.emitterconfiguration.endpoint.md) + +## EmitterConfiguration.endpoint property + +Signature: + +```typescript +endpoint: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfiguration.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfiguration.md new file mode 100644 index 000000000..e8f5c3fc3 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfiguration.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfiguration](./react-native-tracker.emitterconfiguration.md) + +## EmitterConfiguration interface + +Signature: + +```typescript +interface EmitterConfiguration extends EmitterConfigurationBase +``` +Extends: EmitterConfigurationBase + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [endpoint](./react-native-tracker.emitterconfiguration.endpoint.md) | string | | +| [port?](./react-native-tracker.emitterconfiguration.port.md) | number | (Optional) | +| [protocol?](./react-native-tracker.emitterconfiguration.protocol.md) | "http" \| "https" | (Optional) | +| [serverAnonymization?](./react-native-tracker.emitterconfiguration.serveranonymization.md) | boolean | (Optional) | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfiguration.port.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfiguration.port.md new file mode 100644 index 000000000..082b7ac51 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfiguration.port.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfiguration](./react-native-tracker.emitterconfiguration.md) > [port](./react-native-tracker.emitterconfiguration.port.md) + +## EmitterConfiguration.port property + +Signature: + +```typescript +port?: number; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfiguration.protocol.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfiguration.protocol.md new file mode 100644 index 000000000..8a3715d36 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfiguration.protocol.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfiguration](./react-native-tracker.emitterconfiguration.md) > [protocol](./react-native-tracker.emitterconfiguration.protocol.md) + +## EmitterConfiguration.protocol property + +Signature: + +```typescript +protocol?: "http" | "https"; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfiguration.serveranonymization.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfiguration.serveranonymization.md new file mode 100644 index 000000000..74628321b --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfiguration.serveranonymization.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfiguration](./react-native-tracker.emitterconfiguration.md) > [serverAnonymization](./react-native-tracker.emitterconfiguration.serveranonymization.md) + +## EmitterConfiguration.serverAnonymization property + +Signature: + +```typescript +serverAnonymization?: boolean; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.buffersize.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.buffersize.md new file mode 100644 index 000000000..5141933a2 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.buffersize.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfigurationBase](./react-native-tracker.emitterconfigurationbase.md) > [bufferSize](./react-native-tracker.emitterconfigurationbase.buffersize.md) + +## EmitterConfigurationBase.bufferSize property + +The amount of events that should be buffered before sending Recommended to leave as 1 to reduce change of losing events + +Signature: + +```typescript +bufferSize?: number; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.connectiontimeout.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.connectiontimeout.md new file mode 100644 index 000000000..01c13b8bc --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.connectiontimeout.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfigurationBase](./react-native-tracker.emitterconfigurationbase.md) > [connectionTimeout](./react-native-tracker.emitterconfigurationbase.connectiontimeout.md) + +## EmitterConfigurationBase.connectionTimeout property + +How long to wait before aborting requests to the collector + +Signature: + +```typescript +connectionTimeout?: number; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.cookieextensionservice.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.cookieextensionservice.md new file mode 100644 index 000000000..86cabc539 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.cookieextensionservice.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfigurationBase](./react-native-tracker.emitterconfigurationbase.md) > [cookieExtensionService](./react-native-tracker.emitterconfigurationbase.cookieextensionservice.md) + +## EmitterConfigurationBase.cookieExtensionService property + +Cookie extension service full URL. This URL will be added to the queue and will be called using a GET method. This option is there to allow the service URL to be called in order to set any required identifiers e.g. extra cookies. + +The request respects the `anonymousTracking` option, including the SP-Anonymous header if needed, and any additional custom headers from the customHeaders option. + +Signature: + +```typescript +cookieExtensionService?: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.credentials.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.credentials.md new file mode 100644 index 000000000..1219ad5b7 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.credentials.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfigurationBase](./react-native-tracker.emitterconfigurationbase.md) > [credentials](./react-native-tracker.emitterconfigurationbase.credentials.md) + +## EmitterConfigurationBase.credentials property + +Controls whether or not the browser sends credentials (defaults to 'include') + +Signature: + +```typescript +credentials?: "omit" | "same-origin" | "include"; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.customfetch.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.customfetch.md new file mode 100644 index 000000000..3831bffeb --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.customfetch.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfigurationBase](./react-native-tracker.emitterconfigurationbase.md) > [customFetch](./react-native-tracker.emitterconfigurationbase.customfetch.md) + +## EmitterConfigurationBase.customFetch property + +Enables overriding the default fetch function with a custom implementation. + +Signature: + +```typescript +customFetch?: (input: Request, options?: RequestInit) => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.customheaders.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.customheaders.md new file mode 100644 index 000000000..19bb72078 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.customheaders.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfigurationBase](./react-native-tracker.emitterconfigurationbase.md) > [customHeaders](./react-native-tracker.emitterconfigurationbase.customheaders.md) + +## EmitterConfigurationBase.customHeaders property + +An object of key value pairs which represent headers to attach when sending a POST request, only works for POST + +Signature: + +```typescript +customHeaders?: Record; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.dontretrystatuscodes.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.dontretrystatuscodes.md new file mode 100644 index 000000000..899a420d2 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.dontretrystatuscodes.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfigurationBase](./react-native-tracker.emitterconfigurationbase.md) > [dontRetryStatusCodes](./react-native-tracker.emitterconfigurationbase.dontretrystatuscodes.md) + +## EmitterConfigurationBase.dontRetryStatusCodes property + +List of HTTP response status codes for which events sent to Collector should not be retried in future request. Only non-success status codes are considered (greater or equal to 300). The don't retry codes are only considered for GET and POST requests. By default, the tracker retries on all non-success status codes except for 400, 401, 403, 410, and 422 (these don't retry codes will remain even if you set your own `dontRetryStatusCodes` but can be changed using the `retryStatusCodes`). + +Signature: + +```typescript +dontRetryStatusCodes?: number[]; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.eventmethod.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.eventmethod.md new file mode 100644 index 000000000..dfb2be7e8 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.eventmethod.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfigurationBase](./react-native-tracker.emitterconfigurationbase.md) > [eventMethod](./react-native-tracker.emitterconfigurationbase.eventmethod.md) + +## EmitterConfigurationBase.eventMethod property + +The preferred technique to use to send events + +Signature: + +```typescript +eventMethod?: EventMethod; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.eventstore.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.eventstore.md new file mode 100644 index 000000000..8c872a534 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.eventstore.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfigurationBase](./react-native-tracker.emitterconfigurationbase.md) > [eventStore](./react-native-tracker.emitterconfigurationbase.eventstore.md) + +## EmitterConfigurationBase.eventStore property + +Enables providing a custom EventStore implementation to store events before sending them to the collector. + +Signature: + +```typescript +eventStore?: EventStore; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.idservice.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.idservice.md new file mode 100644 index 000000000..63952083d --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.idservice.md @@ -0,0 +1,16 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfigurationBase](./react-native-tracker.emitterconfigurationbase.md) > [idService](./react-native-tracker.emitterconfigurationbase.idservice.md) + +## EmitterConfigurationBase.idService property + +> Warning: This API is now obsolete. +> +> Use `cookieExtensionService` instead. +> + +Signature: + +```typescript +idService?: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.keepalive.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.keepalive.md new file mode 100644 index 000000000..01c8c2818 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.keepalive.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfigurationBase](./react-native-tracker.emitterconfigurationbase.md) > [keepalive](./react-native-tracker.emitterconfigurationbase.keepalive.md) + +## EmitterConfigurationBase.keepalive property + +Indicates that the request should be allowed to outlive the webpage that initiated it. Enables collector requests to complete even if the page is closed or navigated away from. Note: Browsers put a limit on keepalive requests of 64KB. In case of multiple keepalive requests in parallel (may happen in case of multiple trackers), the limit is shared. + +Signature: + +```typescript +keepalive?: boolean; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.maxgetbytes.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.maxgetbytes.md new file mode 100644 index 000000000..f9dfdedc5 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.maxgetbytes.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfigurationBase](./react-native-tracker.emitterconfigurationbase.md) > [maxGetBytes](./react-native-tracker.emitterconfigurationbase.maxgetbytes.md) + +## EmitterConfigurationBase.maxGetBytes property + +The max size a GET request (its complete URL) can be. Requests over this size will be tried as a POST request. + +Signature: + +```typescript +maxGetBytes?: number; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.maxpostbytes.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.maxpostbytes.md new file mode 100644 index 000000000..1933473d1 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.maxpostbytes.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfigurationBase](./react-native-tracker.emitterconfigurationbase.md) > [maxPostBytes](./react-native-tracker.emitterconfigurationbase.maxpostbytes.md) + +## EmitterConfigurationBase.maxPostBytes property + +The max size a POST request can be before the tracker will force send it Also dictates the max size of a POST request before a batch of events is split into multiple requests + +Signature: + +```typescript +maxPostBytes?: number; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.md new file mode 100644 index 000000000..d30a00963 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.md @@ -0,0 +1,36 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfigurationBase](./react-native-tracker.emitterconfigurationbase.md) + +## EmitterConfigurationBase interface + +Signature: + +```typescript +interface EmitterConfigurationBase +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [bufferSize?](./react-native-tracker.emitterconfigurationbase.buffersize.md) | number | (Optional) The amount of events that should be buffered before sending Recommended to leave as 1 to reduce change of losing events | +| [connectionTimeout?](./react-native-tracker.emitterconfigurationbase.connectiontimeout.md) | number | (Optional) How long to wait before aborting requests to the collector | +| [cookieExtensionService?](./react-native-tracker.emitterconfigurationbase.cookieextensionservice.md) | string | (Optional) Cookie extension service full URL. This URL will be added to the queue and will be called using a GET method. This option is there to allow the service URL to be called in order to set any required identifiers e.g. extra cookies.The request respects the anonymousTracking option, including the SP-Anonymous header if needed, and any additional custom headers from the customHeaders option. | +| [credentials?](./react-native-tracker.emitterconfigurationbase.credentials.md) | "omit" \| "same-origin" \| "include" | (Optional) Controls whether or not the browser sends credentials (defaults to 'include') | +| [customFetch?](./react-native-tracker.emitterconfigurationbase.customfetch.md) | (input: Request, options?: RequestInit) => Promise<Response> | (Optional) Enables overriding the default fetch function with a custom implementation. | +| [customHeaders?](./react-native-tracker.emitterconfigurationbase.customheaders.md) | Record<string, string> | (Optional) An object of key value pairs which represent headers to attach when sending a POST request, only works for POST | +| [dontRetryStatusCodes?](./react-native-tracker.emitterconfigurationbase.dontretrystatuscodes.md) | number\[\] | (Optional) List of HTTP response status codes for which events sent to Collector should not be retried in future request. Only non-success status codes are considered (greater or equal to 300). The don't retry codes are only considered for GET and POST requests. By default, the tracker retries on all non-success status codes except for 400, 401, 403, 410, and 422 (these don't retry codes will remain even if you set your own dontRetryStatusCodes but can be changed using the retryStatusCodes). | +| [eventMethod?](./react-native-tracker.emitterconfigurationbase.eventmethod.md) | EventMethod | (Optional) The preferred technique to use to send events | +| [eventStore?](./react-native-tracker.emitterconfigurationbase.eventstore.md) | EventStore | (Optional) Enables providing a custom EventStore implementation to store events before sending them to the collector. | +| [idService?](./react-native-tracker.emitterconfigurationbase.idservice.md) | string | (Optional) | +| [keepalive?](./react-native-tracker.emitterconfigurationbase.keepalive.md) | boolean | (Optional) Indicates that the request should be allowed to outlive the webpage that initiated it. Enables collector requests to complete even if the page is closed or navigated away from. Note: Browsers put a limit on keepalive requests of 64KB. In case of multiple keepalive requests in parallel (may happen in case of multiple trackers), the limit is shared. | +| [maxGetBytes?](./react-native-tracker.emitterconfigurationbase.maxgetbytes.md) | number | (Optional) The max size a GET request (its complete URL) can be. Requests over this size will be tried as a POST request. | +| [maxPostBytes?](./react-native-tracker.emitterconfigurationbase.maxpostbytes.md) | number | (Optional) The max size a POST request can be before the tracker will force send it Also dictates the max size of a POST request before a batch of events is split into multiple requests | +| [onRequestFailure?](./react-native-tracker.emitterconfigurationbase.onrequestfailure.md) | (data: RequestFailure, response?: Response) => void | (Optional) A callback function to be executed whenever a request fails to be sent to the collector. This is the inverse of the onRequestSuccess callback, so any non 2xx status code will trigger this callback. | +| [onRequestSuccess?](./react-native-tracker.emitterconfigurationbase.onrequestsuccess.md) | (data: EventBatch, response: Response) => void | (Optional) A callback function to be executed whenever a request is successfully sent to the collector. In practice this means any request which returns a 2xx status code will trigger this callback. | +| [postPath?](./react-native-tracker.emitterconfigurationbase.postpath.md) | string | (Optional) The post path which events will be sent to. Ensure your collector is configured to accept events on this post path | +| [retryFailedRequests?](./react-native-tracker.emitterconfigurationbase.retryfailedrequests.md) | boolean | (Optional) Whether to retry failed requests to the collector.Failed requests are requests that failed due to \[timeouts\](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/timeout\_event), \[network errors\](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/error\_event), and \[abort events\](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/abort\_event).Takes precedent over retryStatusCodes and dontRetryStatusCodes. | +| [retryStatusCodes?](./react-native-tracker.emitterconfigurationbase.retrystatuscodes.md) | number\[\] | (Optional) List of HTTP response status codes for which events sent to Collector should be retried in future requests. Only non-success status codes are considered (greater or equal to 300). The retry codes are only considered for GET and POST requests. They take priority over the dontRetryStatusCodes option. By default, the tracker retries on all non-success status codes except for 400, 401, 403, 410, and 422. | +| [useStm?](./react-native-tracker.emitterconfigurationbase.usestm.md) | boolean | (Optional) Should the Sent Timestamp be attached to events. Only applies for GET events. | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.onrequestfailure.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.onrequestfailure.md new file mode 100644 index 000000000..966c194ad --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.onrequestfailure.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfigurationBase](./react-native-tracker.emitterconfigurationbase.md) > [onRequestFailure](./react-native-tracker.emitterconfigurationbase.onrequestfailure.md) + +## EmitterConfigurationBase.onRequestFailure property + +A callback function to be executed whenever a request fails to be sent to the collector. This is the inverse of the onRequestSuccess callback, so any non 2xx status code will trigger this callback. + +Signature: + +```typescript +onRequestFailure?: (data: RequestFailure, response?: Response) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.onrequestsuccess.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.onrequestsuccess.md new file mode 100644 index 000000000..aa3a00827 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.onrequestsuccess.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfigurationBase](./react-native-tracker.emitterconfigurationbase.md) > [onRequestSuccess](./react-native-tracker.emitterconfigurationbase.onrequestsuccess.md) + +## EmitterConfigurationBase.onRequestSuccess property + +A callback function to be executed whenever a request is successfully sent to the collector. In practice this means any request which returns a 2xx status code will trigger this callback. + +Signature: + +```typescript +onRequestSuccess?: (data: EventBatch, response: Response) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.postpath.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.postpath.md new file mode 100644 index 000000000..f12cdb29b --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.postpath.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfigurationBase](./react-native-tracker.emitterconfigurationbase.md) > [postPath](./react-native-tracker.emitterconfigurationbase.postpath.md) + +## EmitterConfigurationBase.postPath property + +The post path which events will be sent to. Ensure your collector is configured to accept events on this post path + +Signature: + +```typescript +postPath?: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.retryfailedrequests.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.retryfailedrequests.md new file mode 100644 index 000000000..133d36e9d --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.retryfailedrequests.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfigurationBase](./react-native-tracker.emitterconfigurationbase.md) > [retryFailedRequests](./react-native-tracker.emitterconfigurationbase.retryfailedrequests.md) + +## EmitterConfigurationBase.retryFailedRequests property + +Whether to retry failed requests to the collector. + +Failed requests are requests that failed due to \[timeouts\](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/timeout\_event), \[network errors\](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/error\_event), and \[abort events\](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/abort\_event). + +Takes precedent over `retryStatusCodes` and `dontRetryStatusCodes`. + +Signature: + +```typescript +retryFailedRequests?: boolean; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.retrystatuscodes.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.retrystatuscodes.md new file mode 100644 index 000000000..2e275eb64 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.retrystatuscodes.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfigurationBase](./react-native-tracker.emitterconfigurationbase.md) > [retryStatusCodes](./react-native-tracker.emitterconfigurationbase.retrystatuscodes.md) + +## EmitterConfigurationBase.retryStatusCodes property + +List of HTTP response status codes for which events sent to Collector should be retried in future requests. Only non-success status codes are considered (greater or equal to 300). The retry codes are only considered for GET and POST requests. They take priority over the `dontRetryStatusCodes` option. By default, the tracker retries on all non-success status codes except for 400, 401, 403, 410, and 422. + +Signature: + +```typescript +retryStatusCodes?: number[]; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.usestm.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.usestm.md new file mode 100644 index 000000000..357628928 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.emitterconfigurationbase.usestm.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EmitterConfigurationBase](./react-native-tracker.emitterconfigurationbase.md) > [useStm](./react-native-tracker.emitterconfigurationbase.usestm.md) + +## EmitterConfigurationBase.useStm property + +Should the Sent Timestamp be attached to events. Only applies for GET events. + +Signature: + +```typescript +useStm?: boolean; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventbatch.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventbatch.md new file mode 100644 index 000000000..3eda10ed8 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventbatch.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EventBatch](./react-native-tracker.eventbatch.md) + +## EventBatch type + +A collection of event payloads which are sent to the collector. + +Signature: + +```typescript +type EventBatch = Payload[]; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventcontext.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventcontext.md new file mode 100644 index 000000000..9e3cbe32b --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventcontext.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EventContext](./react-native-tracker.eventcontext.md) + +## EventContext type + +EventContext type + +Signature: + +```typescript +export declare type EventContext = SelfDescribingJson; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventjson.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventjson.md new file mode 100644 index 000000000..6772b5486 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventjson.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EventJson](./react-native-tracker.eventjson.md) + +## EventJson type + +An array of tuples which represents the unprocessed JSON to be added to the Payload + +Signature: + +```typescript +type EventJson = Array; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventjsonwithkeys.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventjsonwithkeys.md new file mode 100644 index 000000000..025ecd9e2 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventjsonwithkeys.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EventJsonWithKeys](./react-native-tracker.eventjsonwithkeys.md) + +## EventJsonWithKeys type + +A tuple which represents the unprocessed JSON to be added to the Payload + +Signature: + +```typescript +type EventJsonWithKeys = { + keyIfEncoded: string; + keyIfNotEncoded: string; + json: Record; +}; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventmethod.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventmethod.md new file mode 100644 index 000000000..c76297fad --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventmethod.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EventMethod](./react-native-tracker.eventmethod.md) + +## EventMethod type + +Signature: + +```typescript +type EventMethod = "post" | "get"; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventpayloadandcontext.context.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventpayloadandcontext.context.md new file mode 100644 index 000000000..e4dfd9d8a --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventpayloadandcontext.context.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EventPayloadAndContext](./react-native-tracker.eventpayloadandcontext.md) > [context](./react-native-tracker.eventpayloadandcontext.context.md) + +## EventPayloadAndContext.context property + +List of context entities to track along with the event + +Signature: + +```typescript +context: Array; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventpayloadandcontext.event.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventpayloadandcontext.event.md new file mode 100644 index 000000000..4046b70a7 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventpayloadandcontext.event.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EventPayloadAndContext](./react-native-tracker.eventpayloadandcontext.md) > [event](./react-native-tracker.eventpayloadandcontext.event.md) + +## EventPayloadAndContext.event property + +Tracker payload for the event data + +Signature: + +```typescript +event: PayloadBuilder; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventpayloadandcontext.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventpayloadandcontext.md new file mode 100644 index 000000000..2d62a8d95 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventpayloadandcontext.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EventPayloadAndContext](./react-native-tracker.eventpayloadandcontext.md) + +## EventPayloadAndContext interface + +Interface for returning a built event (PayloadBuilder) and context (Array of SelfDescribingJson). + +Signature: + +```typescript +interface EventPayloadAndContext +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [context](./react-native-tracker.eventpayloadandcontext.context.md) | Array<SelfDescribingJson> | List of context entities to track along with the event | +| [event](./react-native-tracker.eventpayloadandcontext.event.md) | PayloadBuilder | Tracker payload for the event data | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstoreconfiguration.asyncstorage.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstoreconfiguration.asyncstorage.md new file mode 100644 index 000000000..980c7f6c9 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstoreconfiguration.asyncstorage.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EventStoreConfiguration](./react-native-tracker.eventstoreconfiguration.md) > [asyncStorage](./react-native-tracker.eventstoreconfiguration.asyncstorage.md) + +## EventStoreConfiguration.asyncStorage property + +The Async storage implementation. In environments where AsyncStorage is not available or where another kind of storage is used, you can provide a custom implementation. + +Signature: + +```typescript +asyncStorage?: AsyncStorage; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstoreconfiguration.maxeventstoresize.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstoreconfiguration.maxeventstoresize.md new file mode 100644 index 000000000..ccc4debe4 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstoreconfiguration.maxeventstoresize.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EventStoreConfiguration](./react-native-tracker.eventstoreconfiguration.md) > [maxEventStoreSize](./react-native-tracker.eventstoreconfiguration.maxeventstoresize.md) + +## EventStoreConfiguration.maxEventStoreSize property + +The maximum amount of events that will be buffered in the event store + +Will drop events once the limit is hit + +Signature: + +```typescript +maxEventStoreSize?: number; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstoreconfiguration.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstoreconfiguration.md new file mode 100644 index 000000000..deee2aeca --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstoreconfiguration.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EventStoreConfiguration](./react-native-tracker.eventstoreconfiguration.md) + +## EventStoreConfiguration interface + +Configuration for the event store + +Signature: + +```typescript +export interface EventStoreConfiguration +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [asyncStorage?](./react-native-tracker.eventstoreconfiguration.asyncstorage.md) | [AsyncStorage](./react-native-tracker.asyncstorage.md) | (Optional) The Async storage implementation. In environments where AsyncStorage is not available or where another kind of storage is used, you can provide a custom implementation. | +| [maxEventStoreSize?](./react-native-tracker.eventstoreconfiguration.maxeventstoresize.md) | number | (Optional) The maximum amount of events that will be buffered in the event storeWill drop events once the limit is hit | +| [useAsyncStorageForEventStore?](./react-native-tracker.eventstoreconfiguration.useasyncstorageforeventstore.md) | boolean | (Optional) Whether to use the AsyncStorage library as the persistent event store for the event store | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstoreconfiguration.useasyncstorageforeventstore.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstoreconfiguration.useasyncstorageforeventstore.md new file mode 100644 index 000000000..275e64ede --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstoreconfiguration.useasyncstorageforeventstore.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EventStoreConfiguration](./react-native-tracker.eventstoreconfiguration.md) > [useAsyncStorageForEventStore](./react-native-tracker.eventstoreconfiguration.useasyncstorageforeventstore.md) + +## EventStoreConfiguration.useAsyncStorageForEventStore property + +Whether to use the AsyncStorage library as the persistent event store for the event store + +Signature: + +```typescript +useAsyncStorageForEventStore?: boolean; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstoreiterator.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstoreiterator.md new file mode 100644 index 000000000..4b9d4e13b --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstoreiterator.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EventStoreIterator](./react-native-tracker.eventstoreiterator.md) + +## EventStoreIterator interface + +EventStoreIterator allows iterating over all events in the store. + +Signature: + +```typescript +interface EventStoreIterator +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [next](./react-native-tracker.eventstoreiterator.next.md) | () => Promise<EventStoreIteratorNextResult> | Retrieve the next event in the store | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstoreiterator.next.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstoreiterator.next.md new file mode 100644 index 000000000..c2e95a935 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstoreiterator.next.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EventStoreIterator](./react-native-tracker.eventstoreiterator.md) > [next](./react-native-tracker.eventstoreiterator.next.md) + +## EventStoreIterator.next property + +Retrieve the next event in the store + +Signature: + +```typescript +next: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstorepayload.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstorepayload.md new file mode 100644 index 000000000..472ba6f8f --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstorepayload.md @@ -0,0 +1,19 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EventStorePayload](./react-native-tracker.eventstorepayload.md) + +## EventStorePayload interface + +Signature: + +```typescript +interface EventStorePayload +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [payload](./react-native-tracker.eventstorepayload.payload.md) | Payload | The event payload to be stored | +| [svrAnon?](./react-native-tracker.eventstorepayload.svranon.md) | boolean | (Optional) If the request should undergo server anonymization. | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstorepayload.payload.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstorepayload.payload.md new file mode 100644 index 000000000..76807caf0 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstorepayload.payload.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EventStorePayload](./react-native-tracker.eventstorepayload.md) > [payload](./react-native-tracker.eventstorepayload.payload.md) + +## EventStorePayload.payload property + +The event payload to be stored + +Signature: + +```typescript +payload: Payload; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstorepayload.svranon.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstorepayload.svranon.md new file mode 100644 index 000000000..5db52ecfc --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.eventstorepayload.svranon.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [EventStorePayload](./react-native-tracker.eventstorepayload.md) > [svrAnon](./react-native-tracker.eventstorepayload.svranon.md) + +## EventStorePayload.svrAnon property + +If the request should undergo server anonymization. + +Signature: + +```typescript +svrAnon?: boolean; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.filterprovider.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.filterprovider.md new file mode 100644 index 000000000..a58d155e1 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.filterprovider.md @@ -0,0 +1,16 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [FilterProvider](./react-native-tracker.filterprovider.md) + +## FilterProvider type + +A filter provider is a tuple that has two parts: a context filter and the context primitive(s) If the context filter evaluates to true, the tracker will attach the context primitive(s) + +Signature: + +```typescript +type FilterProvider = [ + ContextFilter, + Array | ContextPrimitive +]; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.elementclasses.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.elementclasses.md new file mode 100644 index 000000000..f5fcd4679 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.elementclasses.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [FormFocusOrChangeEvent](./react-native-tracker.formfocusorchangeevent.md) > [elementClasses](./react-native-tracker.formfocusorchangeevent.elementclasses.md) + +## FormFocusOrChangeEvent.elementClasses property + +The class names on the element + +Signature: + +```typescript +elementClasses?: Array | null; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.elementid.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.elementid.md new file mode 100644 index 000000000..b0432e03b --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.elementid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [FormFocusOrChangeEvent](./react-native-tracker.formfocusorchangeevent.md) > [elementId](./react-native-tracker.formfocusorchangeevent.elementid.md) + +## FormFocusOrChangeEvent.elementId property + +The element ID which the user is interacting with + +Signature: + +```typescript +elementId: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.formid.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.formid.md new file mode 100644 index 000000000..2d90c18ee --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.formid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [FormFocusOrChangeEvent](./react-native-tracker.formfocusorchangeevent.md) > [formId](./react-native-tracker.formfocusorchangeevent.formid.md) + +## FormFocusOrChangeEvent.formId property + +The ID of the form which the element belongs to + +Signature: + +```typescript +formId: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.md new file mode 100644 index 000000000..534758912 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [FormFocusOrChangeEvent](./react-native-tracker.formfocusorchangeevent.md) + +## FormFocusOrChangeEvent interface + +Represents either a Form Focus or Form Change event When a user focuses on a form element or when a user makes a change to a form element. + +Signature: + +```typescript +interface FormFocusOrChangeEvent +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [elementClasses?](./react-native-tracker.formfocusorchangeevent.elementclasses.md) | Array<string> \| null | (Optional) The class names on the element | +| [elementId](./react-native-tracker.formfocusorchangeevent.elementid.md) | string | The element ID which the user is interacting with | +| [formId](./react-native-tracker.formfocusorchangeevent.formid.md) | string | The ID of the form which the element belongs to | +| [nodeName](./react-native-tracker.formfocusorchangeevent.nodename.md) | string | The name of the node ("INPUT", "TEXTAREA", "SELECT") | +| [schema](./react-native-tracker.formfocusorchangeevent.schema.md) | "change\_form" \| "focus\_form" | The schema which will be used for the event | +| [type?](./react-native-tracker.formfocusorchangeevent.type.md) | string \| null | (Optional) The type of element (e.g. "datetime", "text", "radio", etc.) | +| [value](./react-native-tracker.formfocusorchangeevent.value.md) | string \| null | The value of the element at the time of the event firing | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.nodename.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.nodename.md new file mode 100644 index 000000000..ee9f369ae --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.nodename.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [FormFocusOrChangeEvent](./react-native-tracker.formfocusorchangeevent.md) > [nodeName](./react-native-tracker.formfocusorchangeevent.nodename.md) + +## FormFocusOrChangeEvent.nodeName property + +The name of the node ("INPUT", "TEXTAREA", "SELECT") + +Signature: + +```typescript +nodeName: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.schema.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.schema.md new file mode 100644 index 000000000..474e39187 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.schema.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [FormFocusOrChangeEvent](./react-native-tracker.formfocusorchangeevent.md) > [schema](./react-native-tracker.formfocusorchangeevent.schema.md) + +## FormFocusOrChangeEvent.schema property + +The schema which will be used for the event + +Signature: + +```typescript +schema: "change_form" | "focus_form"; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.type.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.type.md new file mode 100644 index 000000000..da56b8396 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.type.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [FormFocusOrChangeEvent](./react-native-tracker.formfocusorchangeevent.md) > [type](./react-native-tracker.formfocusorchangeevent.type.md) + +## FormFocusOrChangeEvent.type property + +The type of element (e.g. "datetime", "text", "radio", etc.) + +Signature: + +```typescript +type?: string | null; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.value.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.value.md new file mode 100644 index 000000000..9af73bad8 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.formfocusorchangeevent.value.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [FormFocusOrChangeEvent](./react-native-tracker.formfocusorchangeevent.md) > [value](./react-native-tracker.formfocusorchangeevent.value.md) + +## FormFocusOrChangeEvent.value property + +The value of the element at the time of the event firing + +Signature: + +```typescript +value: string | null; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.getalltrackers.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.getalltrackers.md new file mode 100644 index 000000000..2d148726e --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.getalltrackers.md @@ -0,0 +1,19 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [getAllTrackers](./react-native-tracker.getalltrackers.md) + +## getAllTrackers() function + +Retrieves all initialized trackers + +Signature: + +```typescript +export declare function getAllTrackers(): ReactNativeTracker[]; +``` +Returns: + +[ReactNativeTracker](./react-native-tracker.reactnativetracker.md)\[\] + +All initialized trackers + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.gettracker.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.gettracker.md new file mode 100644 index 000000000..7a3376ae2 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.gettracker.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [getTracker](./react-native-tracker.gettracker.md) + +## getTracker() function + +Retrieves an initialized tracker given its namespace + +Signature: + +```typescript +export declare function getTracker(trackerNamespace: string): ReactNativeTracker | undefined; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| trackerNamespace | string | Tracker namespace | + +Returns: + +[ReactNativeTracker](./react-native-tracker.reactnativetracker.md) \| undefined + +Tracker instance if exists + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.getwebviewcallback.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.getwebviewcallback.md new file mode 100644 index 000000000..cf17e1b19 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.getwebviewcallback.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [getWebViewCallback](./react-native-tracker.getwebviewcallback.md) + +## getWebViewCallback() function + +Enables tracking events from apps rendered in react-native-webview components. The apps need to use the Snowplow WebView tracker to track the events. + +To subscribe for the events, use as the `onMessage` prop for a `WebView` component. + +Signature: + +```typescript +export declare function getWebViewCallback(): WebViewMessageHandler; +``` +Returns: + +[WebViewMessageHandler](./react-native-tracker.webviewmessagehandler.md) + +Callback to subscribe for events from Web views tracked using the Snowplow WebView tracker. + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.jsonprocessor.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.jsonprocessor.md new file mode 100644 index 000000000..35d77f46d --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.jsonprocessor.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [JsonProcessor](./react-native-tracker.jsonprocessor.md) + +## JsonProcessor type + +A function which will processor the Json onto the injected PayloadBuilder + +Signature: + +```typescript +type JsonProcessor = (payloadBuilder: PayloadBuilder, jsonForProcessing: EventJson, contextEntitiesForProcessing: SelfDescribingJson[]) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.listitemviewprops.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.listitemviewprops.md new file mode 100644 index 000000000..70e90a10f --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.listitemviewprops.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [ListItemViewProps](./react-native-tracker.listitemviewprops.md) + +## ListItemViewProps type + +Event tracking the view of an item in a list. If screen engagement tracking is enabled, the list item view events will be aggregated into a `screen_summary` entity. + +Schema: `iglu:com.snowplowanalytics.mobile/list_item_view/jsonschema/1-0-0` + +Signature: + +```typescript +export declare type ListItemViewProps = { + index: number; + itemsCount?: number; +}; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.log_level.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.log_level.md new file mode 100644 index 000000000..820f56307 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.log_level.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [LOG\_LEVEL](./react-native-tracker.log_level.md) + +## LOG\_LEVEL enum + +Signature: + +```typescript +declare enum LOG_LEVEL +``` + +## Enumeration Members + +| Member | Value | Description | +| --- | --- | --- | +| debug | 3 | | +| error | 1 | | +| info | 4 | | +| none | 0 | | +| warn | 2 | | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.logger.debug.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.logger.debug.md new file mode 100644 index 000000000..a5470c124 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.logger.debug.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [Logger](./react-native-tracker.logger.md) > [debug](./react-native-tracker.logger.debug.md) + +## Logger.debug property + +Signature: + +```typescript +debug: (message: string, ...extraParams: unknown[]) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.logger.error.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.logger.error.md new file mode 100644 index 000000000..b13733fc3 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.logger.error.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [Logger](./react-native-tracker.logger.md) > [error](./react-native-tracker.logger.error.md) + +## Logger.error property + +Signature: + +```typescript +error: (message: string, error?: unknown, ...extraParams: unknown[]) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.logger.info.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.logger.info.md new file mode 100644 index 000000000..27b3239e6 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.logger.info.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [Logger](./react-native-tracker.logger.md) > [info](./react-native-tracker.logger.info.md) + +## Logger.info property + +Signature: + +```typescript +info: (message: string, ...extraParams: unknown[]) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.logger.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.logger.md new file mode 100644 index 000000000..edbfd7edd --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.logger.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [Logger](./react-native-tracker.logger.md) + +## Logger interface + +Signature: + +```typescript +interface Logger +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [debug](./react-native-tracker.logger.debug.md) | (message: string, ...extraParams: unknown\[\]) => void | | +| [error](./react-native-tracker.logger.error.md) | (message: string, error?: unknown, ...extraParams: unknown\[\]) => void | | +| [info](./react-native-tracker.logger.info.md) | (message: string, ...extraParams: unknown\[\]) => void | | +| [setLogLevel](./react-native-tracker.logger.setloglevel.md) | (level: LOG\_LEVEL) => void | | +| [warn](./react-native-tracker.logger.warn.md) | (message: string, error?: unknown, ...extraParams: unknown\[\]) => void | | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.logger.setloglevel.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.logger.setloglevel.md new file mode 100644 index 000000000..700d5b330 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.logger.setloglevel.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [Logger](./react-native-tracker.logger.md) > [setLogLevel](./react-native-tracker.logger.setloglevel.md) + +## Logger.setLogLevel property + +Signature: + +```typescript +setLogLevel: (level: LOG_LEVEL) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.logger.warn.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.logger.warn.md new file mode 100644 index 000000000..07bd67498 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.logger.warn.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [Logger](./react-native-tracker.logger.md) > [warn](./react-native-tracker.logger.warn.md) + +## Logger.warn property + +Signature: + +```typescript +warn: (message: string, error?: unknown, ...extraParams: unknown[]) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.md new file mode 100644 index 000000000..22ecb8b29 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.md @@ -0,0 +1,95 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) + +## react-native-tracker package + +## Enumerations + +| Enumeration | Description | +| --- | --- | +| [LOG\_LEVEL](./react-native-tracker.log_level.md) | | +| [PlatformContextProperty](./react-native-tracker.platformcontextproperty.md) | | + +## Functions + +| Function | Description | +| --- | --- | +| [getAllTrackers()](./react-native-tracker.getalltrackers.md) | Retrieves all initialized trackers | +| [getTracker(trackerNamespace)](./react-native-tracker.gettracker.md) | Retrieves an initialized tracker given its namespace | +| [getWebViewCallback()](./react-native-tracker.getwebviewcallback.md) | Enables tracking events from apps rendered in react-native-webview components. The apps need to use the Snowplow WebView tracker to track the events.To subscribe for the events, use as the onMessage prop for a WebView component. | +| [newTracker(configuration)](./react-native-tracker.newtracker.md) | Creates a new tracker instance with the given configuration | +| [removeAllTrackers()](./react-native-tracker.removealltrackers.md) | Removes all initialized trackers | +| [removeTracker(trackerNamespace)](./react-native-tracker.removetracker.md) | Removes a tracker given its namespace | + +## Interfaces + +| Interface | Description | +| --- | --- | +| [AppLifecycleConfiguration](./react-native-tracker.applifecycleconfiguration.md) | Configuration for app lifecycle tracking | +| [AsyncStorage](./react-native-tracker.asyncstorage.md) | | +| [CoreConfiguration](./react-native-tracker.coreconfiguration.md) | The configuration object for the tracker core library | +| [CorePlugin](./react-native-tracker.coreplugin.md) | Interface which defines Core Plugins | +| [CorePluginConfiguration](./react-native-tracker.corepluginconfiguration.md) | The configuration of the plugin to add | +| [DeepLinkConfiguration](./react-native-tracker.deeplinkconfiguration.md) | Configuration for deep link tracking | +| [DeviceTimestamp](./react-native-tracker.devicetimestamp.md) | A representation of a Device Timestamp (dtm) | +| [Emitter](./react-native-tracker.emitter.md) | Emitter is responsible for sending events to the collector. It manages the event queue and sends events in batches depending on configuration. | +| [EmitterConfiguration](./react-native-tracker.emitterconfiguration.md) | | +| [EmitterConfigurationBase](./react-native-tracker.emitterconfigurationbase.md) | | +| [EventPayloadAndContext](./react-native-tracker.eventpayloadandcontext.md) | Interface for returning a built event (PayloadBuilder) and context (Array of SelfDescribingJson). | +| [EventStoreConfiguration](./react-native-tracker.eventstoreconfiguration.md) | Configuration for the event store | +| [EventStoreIterator](./react-native-tracker.eventstoreiterator.md) | EventStoreIterator allows iterating over all events in the store. | +| [EventStorePayload](./react-native-tracker.eventstorepayload.md) | | +| [FormFocusOrChangeEvent](./react-native-tracker.formfocusorchangeevent.md) | Represents either a Form Focus or Form Change event When a user focuses on a form element or when a user makes a change to a form element. | +| [Logger](./react-native-tracker.logger.md) | | +| [PageViewEvent](./react-native-tracker.pageviewevent.md) | A Page View Event Represents a Page View, which is typically fired as soon as possible when a web page is loaded within the users browser. Often also fired on "virtual page views" within Single Page Applications (SPA). | +| [PayloadBuilder](./react-native-tracker.payloadbuilder.md) | Interface for mutable object encapsulating tracker payload | +| [PlatformContextConfiguration](./react-native-tracker.platformcontextconfiguration.md) | | +| [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) | Overrides for the values for properties of the platform context. | +| [RuleSet](./react-native-tracker.ruleset.md) | A ruleset has accept or reject properties that contain rules for matching Iglu schema URIs | +| [SessionConfiguration](./react-native-tracker.sessionconfiguration.md) | Configuration for session tracking | +| [SessionState](./react-native-tracker.sessionstate.md) | Current session state that is tracked in events. | +| [SubjectConfiguration](./react-native-tracker.subjectconfiguration.md) | Configuration of subject properties tracked with events | +| [TrackerConfiguration](./react-native-tracker.trackerconfiguration.md) | The configuration object for initialising the tracker | +| [TrackerCore](./react-native-tracker.trackercore.md) | Export interface containing all Core functions | +| [TrueTimestamp](./react-native-tracker.truetimestamp.md) | A representation of a True Timestamp (ttm) | + +## Variables + +| Variable | Description | +| --- | --- | +| [version](./react-native-tracker.version.md) | | + +## Type Aliases + +| Type Alias | Description | +| --- | --- | +| [ConditionalContextProvider](./react-native-tracker.conditionalcontextprovider.md) | Conditional context providers are two element arrays used to decide when to attach contexts, where: - the first element is some conditional criterion - the second element is any number of context primitives | +| [ContextFilter](./react-native-tracker.contextfilter.md) | A context filter is a user-supplied callback that is evaluated for each event to determine if the context associated with the filter should be attached to the event | +| [ContextGenerator](./react-native-tracker.contextgenerator.md) | A context generator is a user-supplied callback that is evaluated for each event to allow an additional context to be dynamically attached to the event | +| [ContextPrimitive](./react-native-tracker.contextprimitive.md) | A context primitive is either a self-describing JSON or a context generator | +| [DeepLinkReceivedProps](./react-native-tracker.deeplinkreceivedprops.md) | DeepLinkReceived event properties schema: iglu:com.snowplowanalytics.mobile/deep\_link\_received/jsonschema/1-0-0 | +| [EventBatch](./react-native-tracker.eventbatch.md) | A collection of event payloads which are sent to the collector. | +| [EventContext](./react-native-tracker.eventcontext.md) | EventContext type | +| [EventJson](./react-native-tracker.eventjson.md) | An array of tuples which represents the unprocessed JSON to be added to the Payload | +| [EventJsonWithKeys](./react-native-tracker.eventjsonwithkeys.md) | A tuple which represents the unprocessed JSON to be added to the Payload | +| [EventMethod](./react-native-tracker.eventmethod.md) | | +| [FilterProvider](./react-native-tracker.filterprovider.md) | A filter provider is a tuple that has two parts: a context filter and the context primitive(s) If the context filter evaluates to true, the tracker will attach the context primitive(s) | +| [JsonProcessor](./react-native-tracker.jsonprocessor.md) | A function which will processor the Json onto the injected PayloadBuilder | +| [ListItemViewProps](./react-native-tracker.listitemviewprops.md) | Event tracking the view of an item in a list. If screen engagement tracking is enabled, the list item view events will be aggregated into a screen_summary entity.Schema: iglu:com.snowplowanalytics.mobile/list_item_view/jsonschema/1-0-0 | +| [MessageNotificationAttachmentProps](./react-native-tracker.messagenotificationattachmentprops.md) | Attachment object that identify an attachment in the MessageNotification. | +| [MessageNotificationProps](./react-native-tracker.messagenotificationprops.md) | MessageNotification event properties schema: iglu:com.snowplowanalytics.mobile/message\_notification/jsonschema/1-0-0 | +| [Payload](./react-native-tracker.payload.md) | Type for a Payload dictionary | +| [ReactNativeTracker](./react-native-tracker.reactnativetracker.md) | The ReactNativeTracker type | +| [RequestFailure](./react-native-tracker.requestfailure.md) | The data that will be available to the onRequestFailure callback | +| [RuleSetProvider](./react-native-tracker.rulesetprovider.md) | A ruleset provider is aa tuple that has two parts: a ruleset and the context primitive(s) If the ruleset allows the current event schema URI, the tracker will attach the context primitive(s) | +| [ScreenSize](./react-native-tracker.screensize.md) | Screen size in pixels | +| [ScreenViewProps](./react-native-tracker.screenviewprops.md) | ScreenView event properties schema: iglu:com.snowplowanalytics.mobile/screen\_view/jsonschema/1-0-0 | +| [ScrollChangedProps](./react-native-tracker.scrollchangedprops.md) | Event tracked when a scroll view's scroll position changes. If screen engagement tracking is enabled, the scroll changed events will be aggregated into a screen_summary entity.Schema: iglu:com.snowplowanalytics.mobile/scroll_changed/jsonschema/1-0-0 | +| [SelfDescribing](./react-native-tracker.selfdescribing.md) | Interface for any self-describing JSON such as context entities or self-describing events | +| [StructuredProps](./react-native-tracker.structuredprops.md) | Properties for a structured event. A classic style of event tracking, allows for easier movement between analytics systems. Self-describing events are preferred for their schema validation. | +| [Timestamp](./react-native-tracker.timestamp.md) | Algebraic datatype representing possible timestamp type choice | +| [TimingProps](./react-native-tracker.timingprops.md) | Timing event properties | +| [Trigger](./react-native-tracker.trigger.md) | Trigger for MessageNotification event | +| [WebViewMessageHandler](./react-native-tracker.webviewmessagehandler.md) | A callback to be used for the onMessage prop of a WebView component. | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.messagenotificationattachmentprops.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.messagenotificationattachmentprops.md new file mode 100644 index 000000000..fe7d17288 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.messagenotificationattachmentprops.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [MessageNotificationAttachmentProps](./react-native-tracker.messagenotificationattachmentprops.md) + +## MessageNotificationAttachmentProps type + +Attachment object that identify an attachment in the MessageNotification. + +Signature: + +```typescript +export declare type MessageNotificationAttachmentProps = { + identifier: string; + type: string; + url: string; +}; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.messagenotificationprops.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.messagenotificationprops.md new file mode 100644 index 000000000..392fe4a38 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.messagenotificationprops.md @@ -0,0 +1,35 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [MessageNotificationProps](./react-native-tracker.messagenotificationprops.md) + +## MessageNotificationProps type + +MessageNotification event properties schema: iglu:com.snowplowanalytics.mobile/message\_notification/jsonschema/1-0-0 + +Signature: + +```typescript +export declare type MessageNotificationProps = { + action?: string; + attachments?: MessageNotificationAttachmentProps[]; + body: string; + bodyLocArgs?: string[]; + bodyLocKey?: string; + category?: string; + contentAvailable?: boolean; + group?: string; + icon?: string; + notificationCount?: number; + notificationTimestamp?: string; + sound?: string; + subtitle?: string; + tag?: string; + threadIdentifier?: string; + title: string; + titleLocArgs?: string[]; + titleLocKey?: string; + trigger: Trigger; +}; +``` +References: [MessageNotificationAttachmentProps](./react-native-tracker.messagenotificationattachmentprops.md), [Trigger](./react-native-tracker.trigger.md) + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.newtracker.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.newtracker.md new file mode 100644 index 000000000..8859e9070 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.newtracker.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [newTracker](./react-native-tracker.newtracker.md) + +## newTracker() function + +Creates a new tracker instance with the given configuration + +Signature: + +```typescript +export declare function newTracker(configuration: Configuration): Promise; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| configuration | Configuration | Configuration for the tracker | + +Returns: + +Promise<[ReactNativeTracker](./react-native-tracker.reactnativetracker.md)> + +Tracker instance + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.pageviewevent.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.pageviewevent.md new file mode 100644 index 000000000..87f820cf5 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.pageviewevent.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PageViewEvent](./react-native-tracker.pageviewevent.md) + +## PageViewEvent interface + +A Page View Event Represents a Page View, which is typically fired as soon as possible when a web page is loaded within the users browser. Often also fired on "virtual page views" within Single Page Applications (SPA). + +Signature: + +```typescript +interface PageViewEvent +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [pageTitle?](./react-native-tracker.pageviewevent.pagetitle.md) | string \| null | (Optional) The current page title in the users browser | +| [pageUrl?](./react-native-tracker.pageviewevent.pageurl.md) | string \| null | (Optional) The current URL visible in the users browser | +| [referrer?](./react-native-tracker.pageviewevent.referrer.md) | string \| null | (Optional) The URL of the referring page | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.pageviewevent.pagetitle.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.pageviewevent.pagetitle.md new file mode 100644 index 000000000..b7bf7a9e9 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.pageviewevent.pagetitle.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PageViewEvent](./react-native-tracker.pageviewevent.md) > [pageTitle](./react-native-tracker.pageviewevent.pagetitle.md) + +## PageViewEvent.pageTitle property + +The current page title in the users browser + +Signature: + +```typescript +pageTitle?: string | null; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.pageviewevent.pageurl.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.pageviewevent.pageurl.md new file mode 100644 index 000000000..048e84af6 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.pageviewevent.pageurl.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PageViewEvent](./react-native-tracker.pageviewevent.md) > [pageUrl](./react-native-tracker.pageviewevent.pageurl.md) + +## PageViewEvent.pageUrl property + +The current URL visible in the users browser + +Signature: + +```typescript +pageUrl?: string | null; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.pageviewevent.referrer.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.pageviewevent.referrer.md new file mode 100644 index 000000000..9796c0cd6 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.pageviewevent.referrer.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PageViewEvent](./react-native-tracker.pageviewevent.md) > [referrer](./react-native-tracker.pageviewevent.referrer.md) + +## PageViewEvent.referrer property + +The URL of the referring page + +Signature: + +```typescript +referrer?: string | null; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payload.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payload.md new file mode 100644 index 000000000..37d76b5ad --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payload.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [Payload](./react-native-tracker.payload.md) + +## Payload type + +Type for a Payload dictionary + +Signature: + +```typescript +type Payload = Record; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.add.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.add.md new file mode 100644 index 000000000..74190086a --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.add.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PayloadBuilder](./react-native-tracker.payloadbuilder.md) > [add](./react-native-tracker.payloadbuilder.add.md) + +## PayloadBuilder.add property + +Adds an entry to the Payload + +Signature: + +```typescript +add: (key: string, value: unknown) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.addcontextentity.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.addcontextentity.md new file mode 100644 index 000000000..4b6346ea6 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.addcontextentity.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PayloadBuilder](./react-native-tracker.payloadbuilder.md) > [addContextEntity](./react-native-tracker.payloadbuilder.addcontextentity.md) + +## PayloadBuilder.addContextEntity property + +Caches a context entity to be added to payload on build + +Signature: + +```typescript +addContextEntity: (entity: SelfDescribingJson) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.adddict.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.adddict.md new file mode 100644 index 000000000..720e5fbea --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.adddict.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PayloadBuilder](./react-native-tracker.payloadbuilder.md) > [addDict](./react-native-tracker.payloadbuilder.adddict.md) + +## PayloadBuilder.addDict property + +Merges a payload into the existing payload + +Signature: + +```typescript +addDict: (dict: Payload) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.addjson.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.addjson.md new file mode 100644 index 000000000..fb29f5c20 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.addjson.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PayloadBuilder](./react-native-tracker.payloadbuilder.md) > [addJson](./react-native-tracker.payloadbuilder.addjson.md) + +## PayloadBuilder.addJson property + +Caches a JSON object to be added to payload on build + +Signature: + +```typescript +addJson: (keyIfEncoded: string, keyIfNotEncoded: string, json: Record) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.build.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.build.md new file mode 100644 index 000000000..473ffa6d9 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.build.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PayloadBuilder](./react-native-tracker.payloadbuilder.md) > [build](./react-native-tracker.payloadbuilder.build.md) + +## PayloadBuilder.build property + +Builds and returns the Payload + +Signature: + +```typescript +build: () => Payload; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.getjson.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.getjson.md new file mode 100644 index 000000000..0007e17f7 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.getjson.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PayloadBuilder](./react-native-tracker.payloadbuilder.md) > [getJson](./react-native-tracker.payloadbuilder.getjson.md) + +## PayloadBuilder.getJson property + +Gets all JSON objects added to payload + +Signature: + +```typescript +getJson: () => EventJson; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.getpayload.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.getpayload.md new file mode 100644 index 000000000..f76229127 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.getpayload.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PayloadBuilder](./react-native-tracker.payloadbuilder.md) > [getPayload](./react-native-tracker.payloadbuilder.getpayload.md) + +## PayloadBuilder.getPayload property + +Gets the current payload, before cached JSON is processed + +Signature: + +```typescript +getPayload: () => Payload; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.md new file mode 100644 index 000000000..656667e94 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.md @@ -0,0 +1,27 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PayloadBuilder](./react-native-tracker.payloadbuilder.md) + +## PayloadBuilder interface + +Interface for mutable object encapsulating tracker payload + +Signature: + +```typescript +interface PayloadBuilder +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [add](./react-native-tracker.payloadbuilder.add.md) | (key: string, value: unknown) => void | Adds an entry to the Payload | +| [addContextEntity](./react-native-tracker.payloadbuilder.addcontextentity.md) | (entity: SelfDescribingJson) => void | Caches a context entity to be added to payload on build | +| [addDict](./react-native-tracker.payloadbuilder.adddict.md) | (dict: Payload) => void | Merges a payload into the existing payload | +| [addJson](./react-native-tracker.payloadbuilder.addjson.md) | (keyIfEncoded: string, keyIfNotEncoded: string, json: Record<string, unknown>) => void | Caches a JSON object to be added to payload on build | +| [build](./react-native-tracker.payloadbuilder.build.md) | () => Payload | Builds and returns the Payload | +| [getJson](./react-native-tracker.payloadbuilder.getjson.md) | () => EventJson | Gets all JSON objects added to payload | +| [getPayload](./react-native-tracker.payloadbuilder.getpayload.md) | () => Payload | Gets the current payload, before cached JSON is processed | +| [withJsonProcessor](./react-native-tracker.payloadbuilder.withjsonprocessor.md) | (jsonProcessor: JsonProcessor) => void | Adds a function which will be executed when building the payload to process the JSON which has been added to this payload | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.withjsonprocessor.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.withjsonprocessor.md new file mode 100644 index 000000000..247963bea --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.payloadbuilder.withjsonprocessor.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PayloadBuilder](./react-native-tracker.payloadbuilder.md) > [withJsonProcessor](./react-native-tracker.payloadbuilder.withjsonprocessor.md) + +## PayloadBuilder.withJsonProcessor property + +Adds a function which will be executed when building the payload to process the JSON which has been added to this payload + +Signature: + +```typescript +withJsonProcessor: (jsonProcessor: JsonProcessor) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextconfiguration.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextconfiguration.md new file mode 100644 index 000000000..dbcbbbe9e --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextconfiguration.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextConfiguration](./react-native-tracker.platformcontextconfiguration.md) + +## PlatformContextConfiguration interface + +Signature: + +```typescript +export interface PlatformContextConfiguration +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [platformContext?](./react-native-tracker.platformcontextconfiguration.platformcontext.md) | boolean | (Optional) Whether to track the mobile context with information about the device. Note: Only some properties (osType, osVersion, deviceManufacturer, deviceModel, resolution, language, scale) will be tracked by default. Other properties can be assigned using the PlatformContextRetriever. | +| [platformContextProperties?](./react-native-tracker.platformcontextconfiguration.platformcontextproperties.md) | [PlatformContextProperty](./react-native-tracker.platformcontextproperty.md)\[\] | (Optional) List of properties of the platform context to track. If not passed and platformContext is enabled, all available properties will be tracked. The required osType, osVersion, deviceManufacturer, and deviceModel properties will be tracked in the entity regardless of this setting. | +| [platformContextRetriever?](./react-native-tracker.platformcontextconfiguration.platformcontextretriever.md) | [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) | (Optional) Set of callbacks to be used to retrieve properties of the platform context. Overrides the tracker implementation for setting the properties. | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextconfiguration.platformcontext.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextconfiguration.platformcontext.md new file mode 100644 index 000000000..1bd9ded23 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextconfiguration.platformcontext.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextConfiguration](./react-native-tracker.platformcontextconfiguration.md) > [platformContext](./react-native-tracker.platformcontextconfiguration.platformcontext.md) + +## PlatformContextConfiguration.platformContext property + +Whether to track the mobile context with information about the device. Note: Only some properties (osType, osVersion, deviceManufacturer, deviceModel, resolution, language, scale) will be tracked by default. Other properties can be assigned using the PlatformContextRetriever. + +Signature: + +```typescript +platformContext?: boolean; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextconfiguration.platformcontextproperties.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextconfiguration.platformcontextproperties.md new file mode 100644 index 000000000..c8b5a4c0a --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextconfiguration.platformcontextproperties.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextConfiguration](./react-native-tracker.platformcontextconfiguration.md) > [platformContextProperties](./react-native-tracker.platformcontextconfiguration.platformcontextproperties.md) + +## PlatformContextConfiguration.platformContextProperties property + +List of properties of the platform context to track. If not passed and `platformContext` is enabled, all available properties will be tracked. The required `osType`, `osVersion`, `deviceManufacturer`, and `deviceModel` properties will be tracked in the entity regardless of this setting. + +Signature: + +```typescript +platformContextProperties?: PlatformContextProperty[]; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextconfiguration.platformcontextretriever.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextconfiguration.platformcontextretriever.md new file mode 100644 index 000000000..5200d1c37 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextconfiguration.platformcontextretriever.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextConfiguration](./react-native-tracker.platformcontextconfiguration.md) > [platformContextRetriever](./react-native-tracker.platformcontextconfiguration.platformcontextretriever.md) + +## PlatformContextConfiguration.platformContextRetriever property + +Set of callbacks to be used to retrieve properties of the platform context. Overrides the tracker implementation for setting the properties. + +Signature: + +```typescript +platformContextRetriever?: PlatformContextRetriever; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextproperty.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextproperty.md new file mode 100644 index 000000000..ecab1bfd9 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextproperty.md @@ -0,0 +1,37 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextProperty](./react-native-tracker.platformcontextproperty.md) + +## PlatformContextProperty enum + +Signature: + +```typescript +export declare enum PlatformContextProperty +``` + +## Enumeration Members + +| Member | Value | Description | +| --- | --- | --- | +| AndroidIdfa | "androidIdfa" | Advertising identifier on Android. Note: This is not automatically assigned by the tracker as it may be considered as fingerprinting. You can assign it using the PlatformContextRetriever. | +| AppAvailableMemory | "appAvailableMemory" | Amount of memory in bytes available to the current app. The property is not tracked in the current version of the tracker due to the tracker not being able to access the API, see the issue here: https://github.com/snowplow/snowplow-ios-tracker/issues/772 Note: this property is not automatically assigned but can be assigned using the PlatformContextRetriever. | +| AppleIdfa | "appleIdfa" | Advertising identifier on iOS. Note: this property is not automatically assigned but can be assigned using the PlatformContextRetriever. | +| AppleIdfv | "appleIdfv" | UUID identifier for vendors on iOS. Note: this property is not automatically assigned but can be assigned using the PlatformContextRetriever. | +| AppSetId | "appSetId" | Android vendor ID scoped to the set of apps published under the same Google Play developer account (see https://developer.android.com/training/articles/app-set-id). Note: This is not automatically assigned by the tracker as it may be considered as fingerprinting. You can assign it using the PlatformContextRetriever. | +| AppSetIdScope | "appSetIdScope" | Scope of the appSetId. Can be scoped to the app or to a developer account on an app store (all apps from the same developer on the same device will have the same ID). Note: This is not automatically assigned by the tracker as it may be considered as fingerprinting. You can assign it using the PlatformContextRetriever. | +| AvailableStorage | "availableStorage" | Bytes of storage remaining. Note: This is not automatically assigned by the tracker as it may be considered as fingerprinting. You can assign it using the PlatformContextRetriever. | +| BatteryLevel | "batteryLevel" | Remaining battery level as an integer percentage of total battery capacity. Note: this property is not automatically assigned but can be assigned using the PlatformContextRetriever. | +| BatteryState | "batteryState" | Battery state for the device. Note: this property is not automatically assigned but can be assigned using the PlatformContextRetriever. | +| Carrier | "carrier" | The carrier of the SIM inserted in the device. Note: this property is not automatically assigned but can be assigned using the PlatformContextRetriever. | +| IsPortrait | "isPortrait" | A Boolean indicating whether the device orientation is portrait (either upright or upside down). Note: This is not automatically assigned by the tracker as it may be considered as fingerprinting. You can assign it using the PlatformContextRetriever. | +| Language | "language" | System language currently used on the device (ISO 639). | +| LowPowerMode | "lowPowerMode" | A Boolean indicating whether Low Power Mode is enabled. | +| NetworkTechnology | "networkTechnology" | Radio access technology that the device is using. Note: this property is not automatically assigned but can be assigned using the PlatformContextRetriever. | +| NetworkType | "networkType" | Type of network the device is connected to. Note: this property is not automatically assigned but can be assigned using the PlatformContextRetriever. | +| PhysicalMemory | "physicalMemory" | Total physical system memory in bytes. Note: this property is not automatically assigned but can be assigned using the PlatformContextRetriever. | +| Resolution | "resolution" | Screen resolution in pixels. Arrives in the form of WIDTHxHEIGHT (e.g., 1200x900). Doesn't change when device orientation changes. Note: This is not automatically assigned by the tracker as it may be considered as fingerprinting. You can assign it using the PlatformContextRetriever. | +| Scale | "scale" | Scale factor used to convert logical coordinates to device coordinates of the screen (uses UIScreen.scale on iOS). | +| SystemAvailableMemory | "systemAvailableMemory" | Available memory on the system in bytes (Android only). Note: This is not automatically assigned by the tracker as it may be considered as fingerprinting. You can assign it using the PlatformContextRetriever. | +| TotalStorage | "totalStorage" | Total size of storage in bytes. Note: This is not automatically assigned by the tracker as it may be considered as fingerprinting. You can assign it using the PlatformContextRetriever. | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getandroididfa.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getandroididfa.md new file mode 100644 index 000000000..ddb929aba --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getandroididfa.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getAndroidIdfa](./react-native-tracker.platformcontextretriever.getandroididfa.md) + +## PlatformContextRetriever.getAndroidIdfa property + +Advertising identifier on Android. + +Signature: + +```typescript +getAndroidIdfa?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getappavailablememory.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getappavailablememory.md new file mode 100644 index 000000000..b3d16dd2c --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getappavailablememory.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getAppAvailableMemory](./react-native-tracker.platformcontextretriever.getappavailablememory.md) + +## PlatformContextRetriever.getAppAvailableMemory property + +Amount of memory in bytes available to the current app + +Signature: + +```typescript +getAppAvailableMemory?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getappleidfa.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getappleidfa.md new file mode 100644 index 000000000..d7df9689b --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getappleidfa.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getAppleIdfa](./react-native-tracker.platformcontextretriever.getappleidfa.md) + +## PlatformContextRetriever.getAppleIdfa property + +Advertising identifier on iOS (UUID formatted string) + +Signature: + +```typescript +getAppleIdfa?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getappleidfv.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getappleidfv.md new file mode 100644 index 000000000..708c2fab8 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getappleidfv.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getAppleIdfv](./react-native-tracker.platformcontextretriever.getappleidfv.md) + +## PlatformContextRetriever.getAppleIdfv property + +UUID identifier for vendors on iOS + +Signature: + +```typescript +getAppleIdfv?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getappsetid.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getappsetid.md new file mode 100644 index 000000000..26883e060 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getappsetid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getAppSetId](./react-native-tracker.platformcontextretriever.getappsetid.md) + +## PlatformContextRetriever.getAppSetId property + +Android vendor ID scoped to the set of apps published under the same Google Play developer account (see https://developer.android.com/training/articles/app-set-id). + +Signature: + +```typescript +getAppSetId?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getappsetidscope.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getappsetidscope.md new file mode 100644 index 000000000..ba739a067 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getappsetidscope.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getAppSetIdScope](./react-native-tracker.platformcontextretriever.getappsetidscope.md) + +## PlatformContextRetriever.getAppSetIdScope property + +Scope of the `appSetId`. Can be scoped to the app or to a developer account on an app store (all apps from the same developer on the same device will have the same ID). + +Signature: + +```typescript +getAppSetIdScope?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getavailablestorage.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getavailablestorage.md new file mode 100644 index 000000000..3e272c06d --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getavailablestorage.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getAvailableStorage](./react-native-tracker.platformcontextretriever.getavailablestorage.md) + +## PlatformContextRetriever.getAvailableStorage property + +Bytes of storage remaining + +Signature: + +```typescript +getAvailableStorage?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getbatterylevel.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getbatterylevel.md new file mode 100644 index 000000000..903119131 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getbatterylevel.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getBatteryLevel](./react-native-tracker.platformcontextretriever.getbatterylevel.md) + +## PlatformContextRetriever.getBatteryLevel property + +Remaining battery level as an integer percentage of total battery capacity + +Signature: + +```typescript +getBatteryLevel?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getbatterystate.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getbatterystate.md new file mode 100644 index 000000000..572cf8433 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getbatterystate.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getBatteryState](./react-native-tracker.platformcontextretriever.getbatterystate.md) + +## PlatformContextRetriever.getBatteryState property + +Battery state for the device + +Signature: + +```typescript +getBatteryState?: () => Promise<'unplugged' | 'charging' | 'full' | undefined>; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getcarrier.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getcarrier.md new file mode 100644 index 000000000..1e585d9e3 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getcarrier.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getCarrier](./react-native-tracker.platformcontextretriever.getcarrier.md) + +## PlatformContextRetriever.getCarrier property + +The carrier of the SIM inserted in the device + +Signature: + +```typescript +getCarrier?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getdevicemanufacturer.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getdevicemanufacturer.md new file mode 100644 index 000000000..fd01882c8 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getdevicemanufacturer.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getDeviceManufacturer](./react-native-tracker.platformcontextretriever.getdevicemanufacturer.md) + +## PlatformContextRetriever.getDeviceManufacturer property + +The manufacturer of the product/hardware + +Signature: + +```typescript +getDeviceManufacturer?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getdevicemodel.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getdevicemodel.md new file mode 100644 index 000000000..d4e678e30 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getdevicemodel.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getDeviceModel](./react-native-tracker.platformcontextretriever.getdevicemodel.md) + +## PlatformContextRetriever.getDeviceModel property + +The end-user-visible name for the end product + +Signature: + +```typescript +getDeviceModel?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getlanguage.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getlanguage.md new file mode 100644 index 000000000..f898f2ee3 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getlanguage.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getLanguage](./react-native-tracker.platformcontextretriever.getlanguage.md) + +## PlatformContextRetriever.getLanguage property + +System language currently used on the device (ISO 639) + +Signature: + +```typescript +getLanguage?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getlowpowermode.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getlowpowermode.md new file mode 100644 index 000000000..a977aee13 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getlowpowermode.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getLowPowerMode](./react-native-tracker.platformcontextretriever.getlowpowermode.md) + +## PlatformContextRetriever.getLowPowerMode property + +A Boolean indicating whether Low Power Mode is enabled + +Signature: + +```typescript +getLowPowerMode?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getnetworktechnology.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getnetworktechnology.md new file mode 100644 index 000000000..aaea92c69 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getnetworktechnology.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getNetworkTechnology](./react-native-tracker.platformcontextretriever.getnetworktechnology.md) + +## PlatformContextRetriever.getNetworkTechnology property + +Radio access technology that the device is using + +Signature: + +```typescript +getNetworkTechnology?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getnetworktype.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getnetworktype.md new file mode 100644 index 000000000..1890e85a6 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getnetworktype.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getNetworkType](./react-native-tracker.platformcontextretriever.getnetworktype.md) + +## PlatformContextRetriever.getNetworkType property + +Type of network the device is connected to + +Signature: + +```typescript +getNetworkType?: () => Promise<'mobile' | 'wifi' | 'offline' | undefined>; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getostype.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getostype.md new file mode 100644 index 000000000..3c2904a26 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getostype.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getOsType](./react-native-tracker.platformcontextretriever.getostype.md) + +## PlatformContextRetriever.getOsType property + +Operating system type (e.g., ios, tvos, watchos, osx, android) + +Signature: + +```typescript +getOsType?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getosversion.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getosversion.md new file mode 100644 index 000000000..204cf64b2 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getosversion.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getOsVersion](./react-native-tracker.platformcontextretriever.getosversion.md) + +## PlatformContextRetriever.getOsVersion property + +The current version of the operating system + +Signature: + +```typescript +getOsVersion?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getphysicalmemory.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getphysicalmemory.md new file mode 100644 index 000000000..333e960da --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getphysicalmemory.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getPhysicalMemory](./react-native-tracker.platformcontextretriever.getphysicalmemory.md) + +## PlatformContextRetriever.getPhysicalMemory property + +Total physical system memory in bytes + +Signature: + +```typescript +getPhysicalMemory?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getresolution.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getresolution.md new file mode 100644 index 000000000..12ea40cc5 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getresolution.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getResolution](./react-native-tracker.platformcontextretriever.getresolution.md) + +## PlatformContextRetriever.getResolution property + +Screen resolution in pixels. Arrives in the form of WIDTHxHEIGHT (e.g., 1200x900). Doesn't change when device orientation changes + +Signature: + +```typescript +getResolution?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getscale.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getscale.md new file mode 100644 index 000000000..3a4f0351a --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getscale.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getScale](./react-native-tracker.platformcontextretriever.getscale.md) + +## PlatformContextRetriever.getScale property + +Scale factor used to convert logical coordinates to device coordinates of the screen (uses UIScreen.scale on iOS) + +Signature: + +```typescript +getScale?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getsystemavailablememory.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getsystemavailablememory.md new file mode 100644 index 000000000..43e158abc --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.getsystemavailablememory.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getSystemAvailableMemory](./react-native-tracker.platformcontextretriever.getsystemavailablememory.md) + +## PlatformContextRetriever.getSystemAvailableMemory property + +Available memory on the system in bytes (Android only). + +Signature: + +```typescript +getSystemAvailableMemory?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.gettotalstorage.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.gettotalstorage.md new file mode 100644 index 000000000..af2f197c9 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.gettotalstorage.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [getTotalStorage](./react-native-tracker.platformcontextretriever.gettotalstorage.md) + +## PlatformContextRetriever.getTotalStorage property + +Total size of storage in bytes + +Signature: + +```typescript +getTotalStorage?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.isportrait.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.isportrait.md new file mode 100644 index 000000000..dcbcf2877 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.isportrait.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) > [isPortrait](./react-native-tracker.platformcontextretriever.isportrait.md) + +## PlatformContextRetriever.isPortrait property + +A Boolean indicating whether the device orientation is portrait (either upright or upside down) + +Signature: + +```typescript +isPortrait?: () => Promise; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.md new file mode 100644 index 000000000..cbaea8df5 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.platformcontextretriever.md @@ -0,0 +1,43 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [PlatformContextRetriever](./react-native-tracker.platformcontextretriever.md) + +## PlatformContextRetriever interface + +Overrides for the values for properties of the platform context. + +Signature: + +```typescript +export interface PlatformContextRetriever +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [getAndroidIdfa?](./react-native-tracker.platformcontextretriever.getandroididfa.md) | () => Promise<string \| undefined> | (Optional) Advertising identifier on Android. | +| [getAppAvailableMemory?](./react-native-tracker.platformcontextretriever.getappavailablememory.md) | () => Promise<number \| undefined> | (Optional) Amount of memory in bytes available to the current app | +| [getAppleIdfa?](./react-native-tracker.platformcontextretriever.getappleidfa.md) | () => Promise<string \| undefined> | (Optional) Advertising identifier on iOS (UUID formatted string) | +| [getAppleIdfv?](./react-native-tracker.platformcontextretriever.getappleidfv.md) | () => Promise<string \| undefined> | (Optional) UUID identifier for vendors on iOS | +| [getAppSetId?](./react-native-tracker.platformcontextretriever.getappsetid.md) | () => Promise<string \| undefined> | (Optional) Android vendor ID scoped to the set of apps published under the same Google Play developer account (see https://developer.android.com/training/articles/app-set-id). | +| [getAppSetIdScope?](./react-native-tracker.platformcontextretriever.getappsetidscope.md) | () => Promise<string \| undefined> | (Optional) Scope of the appSetId. Can be scoped to the app or to a developer account on an app store (all apps from the same developer on the same device will have the same ID). | +| [getAvailableStorage?](./react-native-tracker.platformcontextretriever.getavailablestorage.md) | () => Promise<number \| undefined> | (Optional) Bytes of storage remaining | +| [getBatteryLevel?](./react-native-tracker.platformcontextretriever.getbatterylevel.md) | () => Promise<number \| undefined> | (Optional) Remaining battery level as an integer percentage of total battery capacity | +| [getBatteryState?](./react-native-tracker.platformcontextretriever.getbatterystate.md) | () => Promise<'unplugged' \| 'charging' \| 'full' \| undefined> | (Optional) Battery state for the device | +| [getCarrier?](./react-native-tracker.platformcontextretriever.getcarrier.md) | () => Promise<string \| undefined> | (Optional) The carrier of the SIM inserted in the device | +| [getDeviceManufacturer?](./react-native-tracker.platformcontextretriever.getdevicemanufacturer.md) | () => Promise<string> | (Optional) The manufacturer of the product/hardware | +| [getDeviceModel?](./react-native-tracker.platformcontextretriever.getdevicemodel.md) | () => Promise<string> | (Optional) The end-user-visible name for the end product | +| [getLanguage?](./react-native-tracker.platformcontextretriever.getlanguage.md) | () => Promise<string \| undefined> | (Optional) System language currently used on the device (ISO 639) | +| [getLowPowerMode?](./react-native-tracker.platformcontextretriever.getlowpowermode.md) | () => Promise<boolean \| undefined> | (Optional) A Boolean indicating whether Low Power Mode is enabled | +| [getNetworkTechnology?](./react-native-tracker.platformcontextretriever.getnetworktechnology.md) | () => Promise<string \| undefined> | (Optional) Radio access technology that the device is using | +| [getNetworkType?](./react-native-tracker.platformcontextretriever.getnetworktype.md) | () => Promise<'mobile' \| 'wifi' \| 'offline' \| undefined> | (Optional) Type of network the device is connected to | +| [getOsType?](./react-native-tracker.platformcontextretriever.getostype.md) | () => Promise<string> | (Optional) Operating system type (e.g., ios, tvos, watchos, osx, android) | +| [getOsVersion?](./react-native-tracker.platformcontextretriever.getosversion.md) | () => Promise<string> | (Optional) The current version of the operating system | +| [getPhysicalMemory?](./react-native-tracker.platformcontextretriever.getphysicalmemory.md) | () => Promise<number \| undefined> | (Optional) Total physical system memory in bytes | +| [getResolution?](./react-native-tracker.platformcontextretriever.getresolution.md) | () => Promise<string \| undefined> | (Optional) Screen resolution in pixels. Arrives in the form of WIDTHxHEIGHT (e.g., 1200x900). Doesn't change when device orientation changes | +| [getScale?](./react-native-tracker.platformcontextretriever.getscale.md) | () => Promise<number \| undefined> | (Optional) Scale factor used to convert logical coordinates to device coordinates of the screen (uses UIScreen.scale on iOS) | +| [getSystemAvailableMemory?](./react-native-tracker.platformcontextretriever.getsystemavailablememory.md) | () => Promise<number \| undefined> | (Optional) Available memory on the system in bytes (Android only). | +| [getTotalStorage?](./react-native-tracker.platformcontextretriever.gettotalstorage.md) | () => Promise<number \| undefined> | (Optional) Total size of storage in bytes | +| [isPortrait?](./react-native-tracker.platformcontextretriever.isportrait.md) | () => Promise<boolean \| undefined> | (Optional) A Boolean indicating whether the device orientation is portrait (either upright or upside down) | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.reactnativetracker.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.reactnativetracker.md new file mode 100644 index 000000000..c6354bb03 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.reactnativetracker.md @@ -0,0 +1,54 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [ReactNativeTracker](./react-native-tracker.reactnativetracker.md) + +## ReactNativeTracker type + +The ReactNativeTracker type + +Signature: + +```typescript +export declare type ReactNativeTracker = { + namespace: string; + readonly trackSelfDescribingEvent: = Record>(argmap: SelfDescribing, contexts?: EventContext[]) => void; + readonly trackScreenViewEvent: (argmap: ScreenViewProps, contexts?: EventContext[]) => void; + readonly trackScrollChangedEvent: (argmap: ScrollChangedProps, contexts?: EventContext[]) => void; + readonly trackListItemViewEvent: (argmap: ListItemViewProps, contexts?: EventContext[]) => void; + readonly trackStructuredEvent: (argmap: StructuredProps, contexts?: EventContext[]) => void; + readonly trackPageViewEvent: (argmap: PageViewEvent, contexts?: EventContext[]) => void; + readonly trackTimingEvent: (argmap: TimingProps, contexts?: EventContext[]) => void; + readonly trackDeepLinkReceivedEvent: (argmap: DeepLinkReceivedProps, contexts?: EventContext[]) => void; + readonly trackMessageNotificationEvent: (argmap: MessageNotificationProps, contexts?: EventContext[]) => void; + addGlobalContexts(contexts: Array | Record): void; + clearGlobalContexts(): void; + removeGlobalContexts(contexts: Array): void; + addPlugin(configuration: BrowserPluginConfiguration): void; + flush: () => Promise; + readonly setAppId: (appId: string) => void; + readonly setPlatform: (value: string) => void; + readonly setUserId: (newUid: string) => void; + readonly setNetworkUserId: (newNuid: string | undefined) => void; + readonly setDomainUserId: (newDuid: string | undefined) => void; + readonly setIpAddress: (newIp: string) => void; + readonly setUseragent: (newUagent: string) => void; + readonly setTimezone: (newTz: string) => void; + readonly setLanguage: (newLang: string) => void; + readonly setScreenResolution: (newRes: ScreenSize) => void; + readonly setScreenViewport: (newView: ScreenSize) => void; + readonly setColorDepth: (newLang: number) => void; + readonly setSubjectData: (config: SubjectConfiguration) => void; + readonly getSessionUserId: () => Promise; + readonly getSessionId: () => Promise; + readonly getSessionIndex: () => Promise; + readonly getSessionState: () => Promise; + readonly getIsInBackground: () => boolean | undefined; + readonly getBackgroundIndex: () => number | undefined; + readonly getForegroundIndex: () => number | undefined; + readonly enablePlatformContext: () => Promise; + readonly disablePlatformContext: () => void; + readonly refreshPlatformContext: () => Promise; +}; +``` +References: [SelfDescribing](./react-native-tracker.selfdescribing.md), [EventContext](./react-native-tracker.eventcontext.md), [ScreenViewProps](./react-native-tracker.screenviewprops.md), [ScrollChangedProps](./react-native-tracker.scrollchangedprops.md), [ListItemViewProps](./react-native-tracker.listitemviewprops.md), [StructuredProps](./react-native-tracker.structuredprops.md), [TimingProps](./react-native-tracker.timingprops.md), [DeepLinkReceivedProps](./react-native-tracker.deeplinkreceivedprops.md), [MessageNotificationProps](./react-native-tracker.messagenotificationprops.md), [ScreenSize](./react-native-tracker.screensize.md), [SubjectConfiguration](./react-native-tracker.subjectconfiguration.md), [SessionState](./react-native-tracker.sessionstate.md) + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.removealltrackers.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.removealltrackers.md new file mode 100644 index 000000000..f89c21a42 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.removealltrackers.md @@ -0,0 +1,19 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [removeAllTrackers](./react-native-tracker.removealltrackers.md) + +## removeAllTrackers() function + +Removes all initialized trackers + +Signature: + +```typescript +export declare function removeAllTrackers(): void; +``` +Returns: + +void + +- A boolean promise + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.removetracker.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.removetracker.md new file mode 100644 index 000000000..fd63a38eb --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.removetracker.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [removeTracker](./react-native-tracker.removetracker.md) + +## removeTracker() function + +Removes a tracker given its namespace + +Signature: + +```typescript +export declare function removeTracker(trackerNamespace: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| trackerNamespace | string | Tracker namespace | + +Returns: + +void + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.requestfailure.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.requestfailure.md new file mode 100644 index 000000000..063d363fc --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.requestfailure.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [RequestFailure](./react-native-tracker.requestfailure.md) + +## RequestFailure type + +The data that will be available to the `onRequestFailure` callback + +Signature: + +```typescript +type RequestFailure = { + events: EventBatch; + status?: number; + message?: string; + willRetry: boolean; +}; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.ruleset.accept.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.ruleset.accept.md new file mode 100644 index 000000000..d47792084 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.ruleset.accept.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [RuleSet](./react-native-tracker.ruleset.md) > [accept](./react-native-tracker.ruleset.accept.md) + +## RuleSet.accept property + +Signature: + +```typescript +accept?: Array | string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.ruleset.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.ruleset.md new file mode 100644 index 000000000..157720f6c --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.ruleset.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [RuleSet](./react-native-tracker.ruleset.md) + +## RuleSet interface + +A ruleset has accept or reject properties that contain rules for matching Iglu schema URIs + +Signature: + +```typescript +interface RuleSet +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [accept?](./react-native-tracker.ruleset.accept.md) | Array<string> \| string | (Optional) | +| [reject?](./react-native-tracker.ruleset.reject.md) | Array<string> \| string | (Optional) | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.ruleset.reject.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.ruleset.reject.md new file mode 100644 index 000000000..a3b017794 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.ruleset.reject.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [RuleSet](./react-native-tracker.ruleset.md) > [reject](./react-native-tracker.ruleset.reject.md) + +## RuleSet.reject property + +Signature: + +```typescript +reject?: Array | string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.rulesetprovider.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.rulesetprovider.md new file mode 100644 index 000000000..a9798a553 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.rulesetprovider.md @@ -0,0 +1,16 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [RuleSetProvider](./react-native-tracker.rulesetprovider.md) + +## RuleSetProvider type + +A ruleset provider is aa tuple that has two parts: a ruleset and the context primitive(s) If the ruleset allows the current event schema URI, the tracker will attach the context primitive(s) + +Signature: + +```typescript +type RuleSetProvider = [ + RuleSet, + Array | ContextPrimitive +]; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.screensize.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.screensize.md new file mode 100644 index 000000000..fb7a11e45 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.screensize.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [ScreenSize](./react-native-tracker.screensize.md) + +## ScreenSize type + +Screen size in pixels + +Signature: + +```typescript +export declare type ScreenSize = [number, number]; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.screenviewprops.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.screenviewprops.md new file mode 100644 index 000000000..22ed34862 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.screenviewprops.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [ScreenViewProps](./react-native-tracker.screenviewprops.md) + +## ScreenViewProps type + +ScreenView event properties schema: iglu:com.snowplowanalytics.mobile/screen\_view/jsonschema/1-0-0 + +Signature: + +```typescript +export declare type ScreenViewProps = { + name: string; + id?: string; + type?: string; + previousName?: string; + previousId?: string; + previousType?: string; + transitionType?: string; +}; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.scrollchangedprops.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.scrollchangedprops.md new file mode 100644 index 000000000..32d3980b5 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.scrollchangedprops.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [ScrollChangedProps](./react-native-tracker.scrollchangedprops.md) + +## ScrollChangedProps type + +Event tracked when a scroll view's scroll position changes. If screen engagement tracking is enabled, the scroll changed events will be aggregated into a `screen_summary` entity. + +Schema: `iglu:com.snowplowanalytics.mobile/scroll_changed/jsonschema/1-0-0` + +Signature: + +```typescript +export declare type ScrollChangedProps = { + yOffset?: number; + xOffset?: number; + viewHeight?: number; + viewWidth?: number; + contentHeight?: number; + contentWidth?: number; +}; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.selfdescribing.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.selfdescribing.md new file mode 100644 index 000000000..35c03afef --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.selfdescribing.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SelfDescribing](./react-native-tracker.selfdescribing.md) + +## SelfDescribing type + +Interface for any self-describing JSON such as context entities or self-describing events + +Signature: + +```typescript +export declare type SelfDescribing> = SelfDescribingJson; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionconfiguration.backgroundsessiontimeout.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionconfiguration.backgroundsessiontimeout.md new file mode 100644 index 000000000..823f3e277 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionconfiguration.backgroundsessiontimeout.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SessionConfiguration](./react-native-tracker.sessionconfiguration.md) > [backgroundSessionTimeout](./react-native-tracker.sessionconfiguration.backgroundsessiontimeout.md) + +## SessionConfiguration.backgroundSessionTimeout property + +The amount of time in seconds before the session id is updated while the app is in the background + +Signature: + +```typescript +backgroundSessionTimeout?: number; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionconfiguration.foregroundsessiontimeout.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionconfiguration.foregroundsessiontimeout.md new file mode 100644 index 000000000..5282a3ef2 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionconfiguration.foregroundsessiontimeout.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SessionConfiguration](./react-native-tracker.sessionconfiguration.md) > [foregroundSessionTimeout](./react-native-tracker.sessionconfiguration.foregroundsessiontimeout.md) + +## SessionConfiguration.foregroundSessionTimeout property + +The amount of time in seconds before the session id is updated while the app is in the foreground + +Signature: + +```typescript +foregroundSessionTimeout?: number; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionconfiguration.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionconfiguration.md new file mode 100644 index 000000000..1123c753c --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionconfiguration.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SessionConfiguration](./react-native-tracker.sessionconfiguration.md) + +## SessionConfiguration interface + +Configuration for session tracking + +Signature: + +```typescript +export interface SessionConfiguration +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [backgroundSessionTimeout?](./react-native-tracker.sessionconfiguration.backgroundsessiontimeout.md) | number | (Optional) The amount of time in seconds before the session id is updated while the app is in the background | +| [foregroundSessionTimeout?](./react-native-tracker.sessionconfiguration.foregroundsessiontimeout.md) | number | (Optional) The amount of time in seconds before the session id is updated while the app is in the foreground | +| [sessionContext?](./react-native-tracker.sessionconfiguration.sessioncontext.md) | boolean | (Optional) Whether session context is attached to tracked events. | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionconfiguration.sessioncontext.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionconfiguration.sessioncontext.md new file mode 100644 index 000000000..080fd7c72 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionconfiguration.sessioncontext.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SessionConfiguration](./react-native-tracker.sessionconfiguration.md) > [sessionContext](./react-native-tracker.sessionconfiguration.sessioncontext.md) + +## SessionConfiguration.sessionContext property + +Whether session context is attached to tracked events. + +Signature: + +```typescript +sessionContext?: boolean; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.eventindex.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.eventindex.md new file mode 100644 index 000000000..2fcff3c89 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.eventindex.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SessionState](./react-native-tracker.sessionstate.md) > [eventIndex](./react-native-tracker.sessionstate.eventindex.md) + +## SessionState.eventIndex property + +Optional index of the current event in the session + +Signature: + +```typescript +eventIndex?: number; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.firsteventid.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.firsteventid.md new file mode 100644 index 000000000..8cb3eb771 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.firsteventid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SessionState](./react-native-tracker.sessionstate.md) > [firstEventId](./react-native-tracker.sessionstate.firsteventid.md) + +## SessionState.firstEventId property + +The optional identifier of the first event for this session + +Signature: + +```typescript +firstEventId?: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.firsteventtimestamp.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.firsteventtimestamp.md new file mode 100644 index 000000000..8277b59f8 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.firsteventtimestamp.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SessionState](./react-native-tracker.sessionstate.md) > [firstEventTimestamp](./react-native-tracker.sessionstate.firsteventtimestamp.md) + +## SessionState.firstEventTimestamp property + +Optional date-time timestamp of when the first event in the session was tracked + +Signature: + +```typescript +firstEventTimestamp?: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.md new file mode 100644 index 000000000..a0a5ec91c --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.md @@ -0,0 +1,27 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SessionState](./react-native-tracker.sessionstate.md) + +## SessionState interface + +Current session state that is tracked in events. + +Signature: + +```typescript +export interface SessionState +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [eventIndex?](./react-native-tracker.sessionstate.eventindex.md) | number | (Optional) Optional index of the current event in the session | +| [firstEventId?](./react-native-tracker.sessionstate.firsteventid.md) | string | (Optional) The optional identifier of the first event for this session | +| [firstEventTimestamp?](./react-native-tracker.sessionstate.firsteventtimestamp.md) | string | (Optional) Optional date-time timestamp of when the first event in the session was tracked | +| [previousSessionId?](./react-native-tracker.sessionstate.previoussessionid.md) | string | (Optional) The previous session identifier for this user | +| [sessionId](./react-native-tracker.sessionstate.sessionid.md) | string | An identifier for the session | +| [sessionIndex](./react-native-tracker.sessionstate.sessionindex.md) | number | The index of the current session for this user | +| [storageMechanism](./react-native-tracker.sessionstate.storagemechanism.md) | string | The mechanism that the session information has been stored on the device | +| [userId](./react-native-tracker.sessionstate.userid.md) | string | An identifier for the user of the session | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.previoussessionid.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.previoussessionid.md new file mode 100644 index 000000000..bd7063348 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.previoussessionid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SessionState](./react-native-tracker.sessionstate.md) > [previousSessionId](./react-native-tracker.sessionstate.previoussessionid.md) + +## SessionState.previousSessionId property + +The previous session identifier for this user + +Signature: + +```typescript +previousSessionId?: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.sessionid.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.sessionid.md new file mode 100644 index 000000000..2a5411f66 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.sessionid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SessionState](./react-native-tracker.sessionstate.md) > [sessionId](./react-native-tracker.sessionstate.sessionid.md) + +## SessionState.sessionId property + +An identifier for the session + +Signature: + +```typescript +sessionId: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.sessionindex.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.sessionindex.md new file mode 100644 index 000000000..132af44a1 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.sessionindex.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SessionState](./react-native-tracker.sessionstate.md) > [sessionIndex](./react-native-tracker.sessionstate.sessionindex.md) + +## SessionState.sessionIndex property + +The index of the current session for this user + +Signature: + +```typescript +sessionIndex: number; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.storagemechanism.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.storagemechanism.md new file mode 100644 index 000000000..be6f76270 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.storagemechanism.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SessionState](./react-native-tracker.sessionstate.md) > [storageMechanism](./react-native-tracker.sessionstate.storagemechanism.md) + +## SessionState.storageMechanism property + +The mechanism that the session information has been stored on the device + +Signature: + +```typescript +storageMechanism: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.userid.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.userid.md new file mode 100644 index 000000000..9fd0de69e --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.sessionstate.userid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SessionState](./react-native-tracker.sessionstate.md) > [userId](./react-native-tracker.sessionstate.userid.md) + +## SessionState.userId property + +An identifier for the user of the session + +Signature: + +```typescript +userId: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.structuredprops.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.structuredprops.md new file mode 100644 index 000000000..4d0ea6262 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.structuredprops.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [StructuredProps](./react-native-tracker.structuredprops.md) + +## StructuredProps type + +Properties for a structured event. A classic style of event tracking, allows for easier movement between analytics systems. Self-describing events are preferred for their schema validation. + +Signature: + +```typescript +export declare type StructuredProps = StructuredEvent; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.colordepth.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.colordepth.md new file mode 100644 index 000000000..293d0019e --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.colordepth.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SubjectConfiguration](./react-native-tracker.subjectconfiguration.md) > [colorDepth](./react-native-tracker.subjectconfiguration.colordepth.md) + +## SubjectConfiguration.colorDepth property + +Color depth (integer) + +Signature: + +```typescript +colorDepth?: number; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.domainuserid.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.domainuserid.md new file mode 100644 index 000000000..ae25b158c --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.domainuserid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SubjectConfiguration](./react-native-tracker.subjectconfiguration.md) > [domainUserId](./react-native-tracker.subjectconfiguration.domainuserid.md) + +## SubjectConfiguration.domainUserId property + +The domain user id (DUID) is a generated identifier that is stored in a first party cookie on Web. The React Native tracker does not assign it automatically. + +Signature: + +```typescript +domainUserId?: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.ipaddress.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.ipaddress.md new file mode 100644 index 000000000..9e2dbe11d --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.ipaddress.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SubjectConfiguration](./react-native-tracker.subjectconfiguration.md) > [ipAddress](./react-native-tracker.subjectconfiguration.ipaddress.md) + +## SubjectConfiguration.ipAddress property + +Override the IP address of the device + +Signature: + +```typescript +ipAddress?: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.language.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.language.md new file mode 100644 index 000000000..381bc4ec0 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.language.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SubjectConfiguration](./react-native-tracker.subjectconfiguration.md) > [language](./react-native-tracker.subjectconfiguration.language.md) + +## SubjectConfiguration.language property + +The language set in the device + +Signature: + +```typescript +language?: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.md new file mode 100644 index 000000000..142bbc301 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.md @@ -0,0 +1,29 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SubjectConfiguration](./react-native-tracker.subjectconfiguration.md) + +## SubjectConfiguration interface + +Configuration of subject properties tracked with events + +Signature: + +```typescript +export interface SubjectConfiguration +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [colorDepth?](./react-native-tracker.subjectconfiguration.colordepth.md) | number | (Optional) Color depth (integer) | +| [domainUserId?](./react-native-tracker.subjectconfiguration.domainuserid.md) | string | (Optional) The domain user id (DUID) is a generated identifier that is stored in a first party cookie on Web. The React Native tracker does not assign it automatically. | +| [ipAddress?](./react-native-tracker.subjectconfiguration.ipaddress.md) | string | (Optional) Override the IP address of the device | +| [language?](./react-native-tracker.subjectconfiguration.language.md) | string | (Optional) The language set in the device | +| [networkUserId?](./react-native-tracker.subjectconfiguration.networkuserid.md) | string | (Optional) Override the network user id (UUIDv4) that is assigned by the collector and stored in cookies | +| [screenResolution?](./react-native-tracker.subjectconfiguration.screenresolution.md) | [ScreenSize](./react-native-tracker.screensize.md) | (Optional) The screen resolution | +| [screenViewport?](./react-native-tracker.subjectconfiguration.screenviewport.md) | [ScreenSize](./react-native-tracker.screensize.md) | (Optional) The screen viewport size | +| [timezone?](./react-native-tracker.subjectconfiguration.timezone.md) | string | (Optional) The timezone label | +| [useragent?](./react-native-tracker.subjectconfiguration.useragent.md) | string | (Optional) The custom user-agent. It overrides the user-agent used by default. | +| [userId?](./react-native-tracker.subjectconfiguration.userid.md) | string | (Optional) Business-defined user ID for this user | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.networkuserid.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.networkuserid.md new file mode 100644 index 000000000..94be46858 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.networkuserid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SubjectConfiguration](./react-native-tracker.subjectconfiguration.md) > [networkUserId](./react-native-tracker.subjectconfiguration.networkuserid.md) + +## SubjectConfiguration.networkUserId property + +Override the network user id (UUIDv4) that is assigned by the collector and stored in cookies + +Signature: + +```typescript +networkUserId?: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.screenresolution.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.screenresolution.md new file mode 100644 index 000000000..54cead3b9 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.screenresolution.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SubjectConfiguration](./react-native-tracker.subjectconfiguration.md) > [screenResolution](./react-native-tracker.subjectconfiguration.screenresolution.md) + +## SubjectConfiguration.screenResolution property + +The screen resolution + +Signature: + +```typescript +screenResolution?: ScreenSize; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.screenviewport.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.screenviewport.md new file mode 100644 index 000000000..76e8df0ac --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.screenviewport.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SubjectConfiguration](./react-native-tracker.subjectconfiguration.md) > [screenViewport](./react-native-tracker.subjectconfiguration.screenviewport.md) + +## SubjectConfiguration.screenViewport property + +The screen viewport size + +Signature: + +```typescript +screenViewport?: ScreenSize; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.timezone.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.timezone.md new file mode 100644 index 000000000..7e49640c4 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.timezone.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SubjectConfiguration](./react-native-tracker.subjectconfiguration.md) > [timezone](./react-native-tracker.subjectconfiguration.timezone.md) + +## SubjectConfiguration.timezone property + +The timezone label + +Signature: + +```typescript +timezone?: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.useragent.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.useragent.md new file mode 100644 index 000000000..cca9bdc93 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.useragent.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SubjectConfiguration](./react-native-tracker.subjectconfiguration.md) > [useragent](./react-native-tracker.subjectconfiguration.useragent.md) + +## SubjectConfiguration.useragent property + +The custom user-agent. It overrides the user-agent used by default. + +Signature: + +```typescript +useragent?: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.userid.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.userid.md new file mode 100644 index 000000000..6a64efa57 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.subjectconfiguration.userid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [SubjectConfiguration](./react-native-tracker.subjectconfiguration.md) > [userId](./react-native-tracker.subjectconfiguration.userid.md) + +## SubjectConfiguration.userId property + +Business-defined user ID for this user + +Signature: + +```typescript +userId?: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.timestamp.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.timestamp.md new file mode 100644 index 000000000..015586490 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.timestamp.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [Timestamp](./react-native-tracker.timestamp.md) + +## Timestamp type + +Algebraic datatype representing possible timestamp type choice + +Signature: + +```typescript +type Timestamp = TrueTimestamp | DeviceTimestamp | number; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.timingprops.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.timingprops.md new file mode 100644 index 000000000..6aaee34f7 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.timingprops.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TimingProps](./react-native-tracker.timingprops.md) + +## TimingProps type + +Timing event properties + +Signature: + +```typescript +export declare type TimingProps = { + category: string; + variable: string; + timing: number; + label?: string; +}; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackerconfiguration.appid.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackerconfiguration.appid.md new file mode 100644 index 000000000..fe9ce9c7b --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackerconfiguration.appid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerConfiguration](./react-native-tracker.trackerconfiguration.md) > [appId](./react-native-tracker.trackerconfiguration.appid.md) + +## TrackerConfiguration.appId property + +The application ID + +Signature: + +```typescript +appId?: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackerconfiguration.deviceplatform.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackerconfiguration.deviceplatform.md new file mode 100644 index 000000000..524068eb4 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackerconfiguration.deviceplatform.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerConfiguration](./react-native-tracker.trackerconfiguration.md) > [devicePlatform](./react-native-tracker.trackerconfiguration.deviceplatform.md) + +## TrackerConfiguration.devicePlatform property + +The device platform the tracker runs on. + +Signature: + +```typescript +devicePlatform?: Platform; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackerconfiguration.encodebase64.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackerconfiguration.encodebase64.md new file mode 100644 index 000000000..9e2fcafe8 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackerconfiguration.encodebase64.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerConfiguration](./react-native-tracker.trackerconfiguration.md) > [encodeBase64](./react-native-tracker.trackerconfiguration.encodebase64.md) + +## TrackerConfiguration.encodeBase64 property + +Whether unstructured events and custom contexts should be base64 encoded. + +Signature: + +```typescript +encodeBase64?: boolean; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackerconfiguration.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackerconfiguration.md new file mode 100644 index 000000000..957545535 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackerconfiguration.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerConfiguration](./react-native-tracker.trackerconfiguration.md) + +## TrackerConfiguration interface + +The configuration object for initialising the tracker + +Signature: + +```typescript +export interface TrackerConfiguration +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [appId?](./react-native-tracker.trackerconfiguration.appid.md) | string | (Optional) The application ID | +| [devicePlatform?](./react-native-tracker.trackerconfiguration.deviceplatform.md) | Platform | (Optional) The device platform the tracker runs on. | +| [encodeBase64?](./react-native-tracker.trackerconfiguration.encodebase64.md) | boolean | (Optional) Whether unstructured events and custom contexts should be base64 encoded. | +| [namespace](./react-native-tracker.trackerconfiguration.namespace.md) | string | The namespace of the tracker | +| [plugins?](./react-native-tracker.trackerconfiguration.plugins.md) | BrowserPlugin\[\] | (Optional) Inject plugins which will be evaluated for each event | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackerconfiguration.namespace.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackerconfiguration.namespace.md new file mode 100644 index 000000000..dc1b7c27b --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackerconfiguration.namespace.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerConfiguration](./react-native-tracker.trackerconfiguration.md) > [namespace](./react-native-tracker.trackerconfiguration.namespace.md) + +## TrackerConfiguration.namespace property + +The namespace of the tracker + +Signature: + +```typescript +namespace: string; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackerconfiguration.plugins.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackerconfiguration.plugins.md new file mode 100644 index 000000000..747583695 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackerconfiguration.plugins.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerConfiguration](./react-native-tracker.trackerconfiguration.md) > [plugins](./react-native-tracker.trackerconfiguration.plugins.md) + +## TrackerConfiguration.plugins property + +Inject plugins which will be evaluated for each event + +Signature: + +```typescript +plugins?: BrowserPlugin[]; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.addglobalcontexts.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.addglobalcontexts.md new file mode 100644 index 000000000..4d7ef62ba --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.addglobalcontexts.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [addGlobalContexts](./react-native-tracker.trackercore.addglobalcontexts.md) + +## TrackerCore.addGlobalContexts() method + +Adds contexts globally, contexts added here will be attached to all applicable events + +Signature: + +```typescript +addGlobalContexts(contexts: Array | Record): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| contexts | Array<ConditionalContextProvider \| ContextPrimitive> \| Record<string, ConditionalContextProvider \| ContextPrimitive> | An array containing either contexts or a conditional contexts | + +Returns: + +void + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.addpayloaddict.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.addpayloaddict.md new file mode 100644 index 000000000..5c5affebf --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.addpayloaddict.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [addPayloadDict](./react-native-tracker.trackercore.addpayloaddict.md) + +## TrackerCore.addPayloadDict() method + +Merges a dictionary into payloadPairs + +Signature: + +```typescript +addPayloadDict(dict: Payload): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| dict | Payload | Adds a new payload dictionary to the existing one | + +Returns: + +void + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.addpayloadpair.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.addpayloadpair.md new file mode 100644 index 000000000..9de08f3da --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.addpayloadpair.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [addPayloadPair](./react-native-tracker.trackercore.addpayloadpair.md) + +## TrackerCore.addPayloadPair property + +Set a persistent key-value pair to be added to every payload + +Signature: + +```typescript +addPayloadPair: (key: string, value: unknown) => void; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.addplugin.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.addplugin.md new file mode 100644 index 000000000..1df2fa1a7 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.addplugin.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [addPlugin](./react-native-tracker.trackercore.addplugin.md) + +## TrackerCore.addPlugin() method + +Add a plugin into the plugin collection after Core has already been initialised + +Signature: + +```typescript +addPlugin(configuration: CorePluginConfiguration): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| configuration | CorePluginConfiguration | The plugin to add | + +Returns: + +void + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.clearglobalcontexts.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.clearglobalcontexts.md new file mode 100644 index 000000000..35a7fce36 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.clearglobalcontexts.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [clearGlobalContexts](./react-native-tracker.trackercore.clearglobalcontexts.md) + +## TrackerCore.clearGlobalContexts() method + +Removes all global contexts + +Signature: + +```typescript +clearGlobalContexts(): void; +``` +Returns: + +void + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.deactivate.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.deactivate.md new file mode 100644 index 000000000..cb5771396 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.deactivate.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [deactivate](./react-native-tracker.trackercore.deactivate.md) + +## TrackerCore.deactivate() method + +Deactivate tracker core including all plugins. This is useful for cleaning up resources or listeners that have been created. Once deactivated, the tracker won't be able to track any events. + +Signature: + +```typescript +deactivate(): void; +``` +Returns: + +void + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.getbase64encoding.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.getbase64encoding.md new file mode 100644 index 000000000..6398bf5b1 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.getbase64encoding.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [getBase64Encoding](./react-native-tracker.trackercore.getbase64encoding.md) + +## TrackerCore.getBase64Encoding() method + +Get current base64 encoding state + +Signature: + +```typescript +getBase64Encoding(): boolean; +``` +Returns: + +boolean + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.md new file mode 100644 index 000000000..d2e490b5c --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.md @@ -0,0 +1,47 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) + +## TrackerCore interface + +Export interface containing all Core functions + +Signature: + +```typescript +interface TrackerCore +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [addPayloadPair](./react-native-tracker.trackercore.addpayloadpair.md) | (key: string, value: unknown) => void | Set a persistent key-value pair to be added to every payload | +| [track](./react-native-tracker.trackercore.track.md) | (pb: PayloadBuilder, context?: Array<SelfDescribingJson> \| null, timestamp?: Timestamp \| null) => Payload \| undefined | Call with a payload from a buildX function Adds context and payloadPairs name-value pairs to the payload Applies the callback to the built payload | + +## Methods + +| Method | Description | +| --- | --- | +| [addGlobalContexts(contexts)](./react-native-tracker.trackercore.addglobalcontexts.md) | Adds contexts globally, contexts added here will be attached to all applicable events | +| [addPayloadDict(dict)](./react-native-tracker.trackercore.addpayloaddict.md) | Merges a dictionary into payloadPairs | +| [addPlugin(configuration)](./react-native-tracker.trackercore.addplugin.md) | Add a plugin into the plugin collection after Core has already been initialised | +| [clearGlobalContexts()](./react-native-tracker.trackercore.clearglobalcontexts.md) | Removes all global contexts | +| [deactivate()](./react-native-tracker.trackercore.deactivate.md) | Deactivate tracker core including all plugins. This is useful for cleaning up resources or listeners that have been created. Once deactivated, the tracker won't be able to track any events. | +| [getBase64Encoding()](./react-native-tracker.trackercore.getbase64encoding.md) | Get current base64 encoding state | +| [removeGlobalContexts(contexts)](./react-native-tracker.trackercore.removeglobalcontexts.md) | Removes previously added global context, performs a deep comparison of the contexts or conditional contexts | +| [resetPayloadPairs(dict)](./react-native-tracker.trackercore.resetpayloadpairs.md) | Replace payloadPairs with a new dictionary | +| [setAppId(appId)](./react-native-tracker.trackercore.setappid.md) | Set the application ID | +| [setBase64Encoding(encode)](./react-native-tracker.trackercore.setbase64encoding.md) | Turn base 64 encoding on or off | +| [setColorDepth(depth)](./react-native-tracker.trackercore.setcolordepth.md) | Set the color depth | +| [setIpAddress(ip)](./react-native-tracker.trackercore.setipaddress.md) | Set the IP address | +| [setLang(lang)](./react-native-tracker.trackercore.setlang.md) | Set the language | +| [setPlatform(value)](./react-native-tracker.trackercore.setplatform.md) | Set the platform | +| [setScreenResolution(width, height)](./react-native-tracker.trackercore.setscreenresolution.md) | Set the screen resolution | +| [setTimezone(timezone)](./react-native-tracker.trackercore.settimezone.md) | Set the timezone | +| [setTrackerNamespace(name)](./react-native-tracker.trackercore.settrackernamespace.md) | Set the tracker namespace | +| [setTrackerVersion(version)](./react-native-tracker.trackercore.settrackerversion.md) | Set the tracker version | +| [setUseragent(useragent)](./react-native-tracker.trackercore.setuseragent.md) | Set the Useragent | +| [setUserId(userId)](./react-native-tracker.trackercore.setuserid.md) | Set the user ID | +| [setViewport(width, height)](./react-native-tracker.trackercore.setviewport.md) | Set the viewport dimensions | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.removeglobalcontexts.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.removeglobalcontexts.md new file mode 100644 index 000000000..c34c36ae9 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.removeglobalcontexts.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [removeGlobalContexts](./react-native-tracker.trackercore.removeglobalcontexts.md) + +## TrackerCore.removeGlobalContexts() method + +Removes previously added global context, performs a deep comparison of the contexts or conditional contexts + +Signature: + +```typescript +removeGlobalContexts(contexts: Array): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| contexts | Array<ConditionalContextProvider \| ContextPrimitive \| string> | An array containing either contexts or a conditional contexts | + +Returns: + +void + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.resetpayloadpairs.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.resetpayloadpairs.md new file mode 100644 index 000000000..7aa688a02 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.resetpayloadpairs.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [resetPayloadPairs](./react-native-tracker.trackercore.resetpayloadpairs.md) + +## TrackerCore.resetPayloadPairs() method + +Replace payloadPairs with a new dictionary + +Signature: + +```typescript +resetPayloadPairs(dict: Payload): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| dict | Payload | Resets all current payload pairs with a new dictionary of pairs | + +Returns: + +void + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setappid.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setappid.md new file mode 100644 index 000000000..abd0a93a1 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setappid.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [setAppId](./react-native-tracker.trackercore.setappid.md) + +## TrackerCore.setAppId() method + +Set the application ID + +Signature: + +```typescript +setAppId(appId: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| appId | string | An application ID which identifies the current application | + +Returns: + +void + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setbase64encoding.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setbase64encoding.md new file mode 100644 index 000000000..dba55d738 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setbase64encoding.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [setBase64Encoding](./react-native-tracker.trackercore.setbase64encoding.md) + +## TrackerCore.setBase64Encoding() method + +Turn base 64 encoding on or off + +Signature: + +```typescript +setBase64Encoding(encode: boolean): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| encode | boolean | Whether to encode payload | + +Returns: + +void + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setcolordepth.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setcolordepth.md new file mode 100644 index 000000000..112999575 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setcolordepth.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [setColorDepth](./react-native-tracker.trackercore.setcolordepth.md) + +## TrackerCore.setColorDepth() method + +Set the color depth + +Signature: + +```typescript +setColorDepth(depth: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| depth | string | A color depth value as string | + +Returns: + +void + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setipaddress.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setipaddress.md new file mode 100644 index 000000000..31498859f --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setipaddress.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [setIpAddress](./react-native-tracker.trackercore.setipaddress.md) + +## TrackerCore.setIpAddress() method + +Set the IP address + +Signature: + +```typescript +setIpAddress(ip: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| ip | string | An IP Address string | + +Returns: + +void + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setlang.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setlang.md new file mode 100644 index 000000000..7100dc2ee --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setlang.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [setLang](./react-native-tracker.trackercore.setlang.md) + +## TrackerCore.setLang() method + +Set the language + +Signature: + +```typescript +setLang(lang: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| lang | string | A language string e.g. 'en-UK' | + +Returns: + +void + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setplatform.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setplatform.md new file mode 100644 index 000000000..6c1ba1297 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setplatform.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [setPlatform](./react-native-tracker.trackercore.setplatform.md) + +## TrackerCore.setPlatform() method + +Set the platform + +Signature: + +```typescript +setPlatform(value: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| value | string | A valid Snowplow platform value | + +Returns: + +void + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setscreenresolution.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setscreenresolution.md new file mode 100644 index 000000000..b24ab49f7 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setscreenresolution.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [setScreenResolution](./react-native-tracker.trackercore.setscreenresolution.md) + +## TrackerCore.setScreenResolution() method + +Set the screen resolution + +Signature: + +```typescript +setScreenResolution(width: string, height: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| width | string | screen resolution width | +| height | string | screen resolution height | + +Returns: + +void + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.settimezone.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.settimezone.md new file mode 100644 index 000000000..3268c1374 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.settimezone.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [setTimezone](./react-native-tracker.trackercore.settimezone.md) + +## TrackerCore.setTimezone() method + +Set the timezone + +Signature: + +```typescript +setTimezone(timezone: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| timezone | string | A timezone string | + +Returns: + +void + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.settrackernamespace.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.settrackernamespace.md new file mode 100644 index 000000000..a07eb93af --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.settrackernamespace.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [setTrackerNamespace](./react-native-tracker.trackercore.settrackernamespace.md) + +## TrackerCore.setTrackerNamespace() method + +Set the tracker namespace + +Signature: + +```typescript +setTrackerNamespace(name: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| name | string | The trackers namespace | + +Returns: + +void + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.settrackerversion.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.settrackerversion.md new file mode 100644 index 000000000..a2abc9b95 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.settrackerversion.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [setTrackerVersion](./react-native-tracker.trackercore.settrackerversion.md) + +## TrackerCore.setTrackerVersion() method + +Set the tracker version + +Signature: + +```typescript +setTrackerVersion(version: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| version | string | The version of the current tracker | + +Returns: + +void + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setuseragent.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setuseragent.md new file mode 100644 index 000000000..eb86f389d --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setuseragent.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [setUseragent](./react-native-tracker.trackercore.setuseragent.md) + +## TrackerCore.setUseragent() method + +Set the Useragent + +Signature: + +```typescript +setUseragent(useragent: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| useragent | string | A useragent string | + +Returns: + +void + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setuserid.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setuserid.md new file mode 100644 index 000000000..e0b1a998c --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setuserid.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [setUserId](./react-native-tracker.trackercore.setuserid.md) + +## TrackerCore.setUserId() method + +Set the user ID + +Signature: + +```typescript +setUserId(userId: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| userId | string | The custom user id | + +Returns: + +void + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setviewport.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setviewport.md new file mode 100644 index 000000000..b7fffbf25 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.setviewport.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [setViewport](./react-native-tracker.trackercore.setviewport.md) + +## TrackerCore.setViewport() method + +Set the viewport dimensions + +Signature: + +```typescript +setViewport(width: string, height: string): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| width | string | viewport width | +| height | string | viewport height | + +Returns: + +void + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.track.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.track.md new file mode 100644 index 000000000..c6787defc --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trackercore.track.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrackerCore](./react-native-tracker.trackercore.md) > [track](./react-native-tracker.trackercore.track.md) + +## TrackerCore.track property + +Call with a payload from a buildX function Adds context and payloadPairs name-value pairs to the payload Applies the callback to the built payload + +Signature: + +```typescript +track: (pb: PayloadBuilder, context?: Array | null, timestamp?: Timestamp | null) => Payload | undefined; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trigger.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trigger.md new file mode 100644 index 000000000..649a12dbe --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.trigger.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [Trigger](./react-native-tracker.trigger.md) + +## Trigger type + +Trigger for MessageNotification event + +Signature: + +```typescript +export declare type Trigger = 'push' | 'location' | 'calendar' | 'timeInterval' | 'other'; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.truetimestamp.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.truetimestamp.md new file mode 100644 index 000000000..5f72c3dc2 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.truetimestamp.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrueTimestamp](./react-native-tracker.truetimestamp.md) + +## TrueTimestamp interface + +A representation of a True Timestamp (ttm) + +Signature: + +```typescript +interface TrueTimestamp +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [type](./react-native-tracker.truetimestamp.type.md) | "ttm" | | +| [value](./react-native-tracker.truetimestamp.value.md) | number | | + diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.truetimestamp.type.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.truetimestamp.type.md new file mode 100644 index 000000000..0c5f08f1d --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.truetimestamp.type.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrueTimestamp](./react-native-tracker.truetimestamp.md) > [type](./react-native-tracker.truetimestamp.type.md) + +## TrueTimestamp.type property + +Signature: + +```typescript +readonly type: "ttm"; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.truetimestamp.value.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.truetimestamp.value.md new file mode 100644 index 000000000..0adbe9cae --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.truetimestamp.value.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [TrueTimestamp](./react-native-tracker.truetimestamp.md) > [value](./react-native-tracker.truetimestamp.value.md) + +## TrueTimestamp.value property + +Signature: + +```typescript +readonly value: number; +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.version.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.version.md new file mode 100644 index 000000000..2614e08f0 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.version.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [version](./react-native-tracker.version.md) + +## version variable + +Signature: + +```typescript +version: string +``` diff --git a/api-docs/docs/react-native-tracker/markdown/react-native-tracker.webviewmessagehandler.md b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.webviewmessagehandler.md new file mode 100644 index 000000000..3d556a1b0 --- /dev/null +++ b/api-docs/docs/react-native-tracker/markdown/react-native-tracker.webviewmessagehandler.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [@snowplow/react-native-tracker](./react-native-tracker.md) > [WebViewMessageHandler](./react-native-tracker.webviewmessagehandler.md) + +## WebViewMessageHandler type + +A callback to be used for the `onMessage` prop of a `WebView` component. + +Signature: + +```typescript +export declare type WebViewMessageHandler = (message: { + nativeEvent: { + data: string; + }; +}) => void; +``` diff --git a/api-docs/docs/react-native-tracker/react-native-tracker.api.md b/api-docs/docs/react-native-tracker/react-native-tracker.api.md new file mode 100644 index 000000000..f362c5679 --- /dev/null +++ b/api-docs/docs/react-native-tracker/react-native-tracker.api.md @@ -0,0 +1,572 @@ +## API Report File for "@snowplow/react-native-tracker" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { BrowserPlugin } from '@snowplow/browser-tracker-core'; +import { BrowserPluginConfiguration } from '@snowplow/browser-tracker-core'; +import { Platform } from '@snowplow/browser-tracker-core'; +import { ScreenTrackingConfiguration } from '@snowplow/browser-plugin-screen-tracking'; + +// @public +export interface AppLifecycleConfiguration { + appBuild?: string; + appVersion?: string; + installAutotracking?: boolean; + lifecycleAutotracking?: boolean; +} + +// @public (undocumented) +export interface AsyncStorage { + // (undocumented) + getItem: (key: string) => Promise; + // (undocumented) + setItem: (key: string, value: string) => Promise; +} + +// @public +export type ConditionalContextProvider = FilterProvider | RuleSetProvider; + +// Warning: (ae-forgotten-export) The symbol "ContextEvent" needs to be exported by the entry point index.d.ts +// +// @public +export type ContextFilter = (args?: ContextEvent) => boolean; + +// Warning: (ae-forgotten-export) The symbol "SelfDescribingJson" needs to be exported by the entry point index.d.ts +// +// @public +export type ContextGenerator = (args?: ContextEvent) => SelfDescribingJson | SelfDescribingJson[] | undefined; + +// @public +export type ContextPrimitive = SelfDescribingJson | ContextGenerator; + +// @public +export interface CoreConfiguration { + /* Should payloads be base64 encoded when built */ + // (undocumented) + base64?: boolean; + /* A list of all the plugins to include at load */ + // (undocumented) + callback?: (PayloadData: PayloadBuilder) => void; + /* A list of all the plugins to include at load */ + // (undocumented) + corePlugins?: Array; +} + +// @public +export interface CorePlugin { + activateCorePlugin?: (core: TrackerCore) => void; + afterTrack?: (payload: Payload) => void; + beforeTrack?: (payloadBuilder: PayloadBuilder) => void; + contexts?: () => SelfDescribingJson[]; + deactivatePlugin?: (core: TrackerCore) => void; + filter?: (payload: Payload) => boolean; + logger?: (logger: Logger) => void; +} + +// @public +export interface CorePluginConfiguration { + /* The plugin to add */ + // (undocumented) + plugin: CorePlugin; +} + +// @public +export interface DeepLinkConfiguration { + deepLinkContext?: boolean; +} + +// @public +export type DeepLinkReceivedProps = { + url: string; + referrer?: string; +}; + +// @public +export interface DeviceTimestamp { + // (undocumented) + readonly type: "dtm"; + // (undocumented) + readonly value: number; +} + +// @public +export interface Emitter { + flush: () => Promise; + input: (payload: Payload) => Promise; + setAnonymousTracking: (anonymous: boolean) => void; + setBufferSize: (bufferSize: number) => void; + setCollectorUrl: (url: string) => void; +} + +// @public (undocumented) +export interface EmitterConfiguration extends EmitterConfigurationBase { + /* The collector URL to which events will be sent */ + // (undocumented) + endpoint: string; + /* http or https. Defaults to https */ + // (undocumented) + port?: number; + /* http or https. Defaults to https */ + // (undocumented) + protocol?: "http" | "https"; + /* http or https. Defaults to https */ + // (undocumented) + serverAnonymization?: boolean; +} + +// @public (undocumented) +export interface EmitterConfigurationBase { + bufferSize?: number; + connectionTimeout?: number; + cookieExtensionService?: string; + credentials?: "omit" | "same-origin" | "include"; + customFetch?: (input: Request, options?: RequestInit) => Promise; + customHeaders?: Record; + dontRetryStatusCodes?: number[]; + eventMethod?: EventMethod; + // Warning: (ae-forgotten-export) The symbol "EventStore" needs to be exported by the entry point index.d.ts + eventStore?: EventStore; + // @deprecated (undocumented) + idService?: string; + keepalive?: boolean; + maxGetBytes?: number; + maxPostBytes?: number; + onRequestFailure?: (data: RequestFailure, response?: Response) => void; + onRequestSuccess?: (data: EventBatch, response: Response) => void; + postPath?: string; + retryFailedRequests?: boolean; + retryStatusCodes?: number[]; + useStm?: boolean; +} + +// @public +export type EventBatch = Payload[]; + +// @public +export type EventContext = SelfDescribingJson; + +// @public +export type EventJson = Array; + +// @public +export type EventJsonWithKeys = { + keyIfEncoded: string; + keyIfNotEncoded: string; + json: Record; +}; + +// @public (undocumented) +export type EventMethod = "post" | "get"; + +// @public +export interface EventPayloadAndContext { + context: Array; + event: PayloadBuilder; +} + +// @public +export interface EventStoreConfiguration { + asyncStorage?: AsyncStorage; + maxEventStoreSize?: number; + useAsyncStorageForEventStore?: boolean; +} + +// @public +export interface EventStoreIterator { + // Warning: (ae-forgotten-export) The symbol "EventStoreIteratorNextResult" needs to be exported by the entry point index.d.ts + next: () => Promise; +} + +// @public (undocumented) +export interface EventStorePayload { + payload: Payload; + svrAnon?: boolean; +} + +// @public +export type FilterProvider = [ +ContextFilter, +Array | ContextPrimitive +]; + +// @public +export interface FormFocusOrChangeEvent { + elementClasses?: Array | null; + elementId: string; + formId: string; + nodeName: string; + schema: "change_form" | "focus_form"; + type?: string | null; + value: string | null; +} + +// @public +export function getAllTrackers(): ReactNativeTracker[]; + +// @public +export function getTracker(trackerNamespace: string): ReactNativeTracker | undefined; + +// @public +export function getWebViewCallback(): WebViewMessageHandler; + +// @public +export type JsonProcessor = (payloadBuilder: PayloadBuilder, jsonForProcessing: EventJson, contextEntitiesForProcessing: SelfDescribingJson[]) => void; + +// @public +export type ListItemViewProps = { + index: number; + itemsCount?: number; +}; + +// @public (undocumented) +export enum LOG_LEVEL { + // (undocumented) + debug = 3, + // (undocumented) + error = 1, + // (undocumented) + info = 4, + // (undocumented) + none = 0, + // (undocumented) + warn = 2 +} + +// @public (undocumented) +export interface Logger { + // (undocumented) + debug: (message: string, ...extraParams: unknown[]) => void; + // (undocumented) + error: (message: string, error?: unknown, ...extraParams: unknown[]) => void; + // (undocumented) + info: (message: string, ...extraParams: unknown[]) => void; + // (undocumented) + setLogLevel: (level: LOG_LEVEL) => void; + // (undocumented) + warn: (message: string, error?: unknown, ...extraParams: unknown[]) => void; +} + +// @public +export type MessageNotificationAttachmentProps = { + identifier: string; + type: string; + url: string; +}; + +// @public +export type MessageNotificationProps = { + action?: string; + attachments?: MessageNotificationAttachmentProps[]; + body: string; + bodyLocArgs?: string[]; + bodyLocKey?: string; + category?: string; + contentAvailable?: boolean; + group?: string; + icon?: string; + notificationCount?: number; + notificationTimestamp?: string; + sound?: string; + subtitle?: string; + tag?: string; + threadIdentifier?: string; + title: string; + titleLocArgs?: string[]; + titleLocKey?: string; + trigger: Trigger; +}; + +// Warning: (ae-forgotten-export) The symbol "Configuration" needs to be exported by the entry point index.d.ts +// +// @public +export function newTracker(configuration: Configuration): Promise; + +// @public +export interface PageViewEvent { + pageTitle?: string | null; + pageUrl?: string | null; + referrer?: string | null; +} + +// @public +export type Payload = Record; + +// @public +export interface PayloadBuilder { + add: (key: string, value: unknown) => void; + addContextEntity: (entity: SelfDescribingJson) => void; + addDict: (dict: Payload) => void; + addJson: (keyIfEncoded: string, keyIfNotEncoded: string, json: Record) => void; + build: () => Payload; + getJson: () => EventJson; + getPayload: () => Payload; + withJsonProcessor: (jsonProcessor: JsonProcessor) => void; +} + +// @public (undocumented) +export interface PlatformContextConfiguration { + platformContext?: boolean; + platformContextProperties?: PlatformContextProperty[]; + platformContextRetriever?: PlatformContextRetriever; +} + +// @public (undocumented) +export enum PlatformContextProperty { + AndroidIdfa = "androidIdfa", + AppAvailableMemory = "appAvailableMemory", + AppleIdfa = "appleIdfa", + AppleIdfv = "appleIdfv", + AppSetId = "appSetId", + AppSetIdScope = "appSetIdScope", + AvailableStorage = "availableStorage", + BatteryLevel = "batteryLevel", + BatteryState = "batteryState", + Carrier = "carrier", + IsPortrait = "isPortrait", + Language = "language", + LowPowerMode = "lowPowerMode", + NetworkTechnology = "networkTechnology", + NetworkType = "networkType", + PhysicalMemory = "physicalMemory", + Resolution = "resolution", + Scale = "scale", + SystemAvailableMemory = "systemAvailableMemory", + TotalStorage = "totalStorage" +} + +// @public +export interface PlatformContextRetriever { + getAndroidIdfa?: () => Promise; + getAppAvailableMemory?: () => Promise; + getAppleIdfa?: () => Promise; + getAppleIdfv?: () => Promise; + getAppSetId?: () => Promise; + getAppSetIdScope?: () => Promise; + getAvailableStorage?: () => Promise; + getBatteryLevel?: () => Promise; + getBatteryState?: () => Promise<'unplugged' | 'charging' | 'full' | undefined>; + getCarrier?: () => Promise; + getDeviceManufacturer?: () => Promise; + getDeviceModel?: () => Promise; + getLanguage?: () => Promise; + getLowPowerMode?: () => Promise; + getNetworkTechnology?: () => Promise; + getNetworkType?: () => Promise<'mobile' | 'wifi' | 'offline' | undefined>; + getOsType?: () => Promise; + getOsVersion?: () => Promise; + getPhysicalMemory?: () => Promise; + getResolution?: () => Promise; + getScale?: () => Promise; + getSystemAvailableMemory?: () => Promise; + getTotalStorage?: () => Promise; + isPortrait?: () => Promise; +} + +// @public +export type ReactNativeTracker = { + namespace: string; + readonly trackSelfDescribingEvent: = Record>(argmap: SelfDescribing, contexts?: EventContext[]) => void; + readonly trackScreenViewEvent: (argmap: ScreenViewProps, contexts?: EventContext[]) => void; + readonly trackScrollChangedEvent: (argmap: ScrollChangedProps, contexts?: EventContext[]) => void; + readonly trackListItemViewEvent: (argmap: ListItemViewProps, contexts?: EventContext[]) => void; + readonly trackStructuredEvent: (argmap: StructuredProps, contexts?: EventContext[]) => void; + readonly trackPageViewEvent: (argmap: PageViewEvent, contexts?: EventContext[]) => void; + readonly trackTimingEvent: (argmap: TimingProps, contexts?: EventContext[]) => void; + readonly trackDeepLinkReceivedEvent: (argmap: DeepLinkReceivedProps, contexts?: EventContext[]) => void; + readonly trackMessageNotificationEvent: (argmap: MessageNotificationProps, contexts?: EventContext[]) => void; + addGlobalContexts(contexts: Array | Record): void; + clearGlobalContexts(): void; + removeGlobalContexts(contexts: Array): void; + addPlugin(configuration: BrowserPluginConfiguration): void; + flush: () => Promise; + readonly setAppId: (appId: string) => void; + readonly setPlatform: (value: string) => void; + readonly setUserId: (newUid: string) => void; + readonly setNetworkUserId: (newNuid: string | undefined) => void; + readonly setDomainUserId: (newDuid: string | undefined) => void; + readonly setIpAddress: (newIp: string) => void; + readonly setUseragent: (newUagent: string) => void; + readonly setTimezone: (newTz: string) => void; + readonly setLanguage: (newLang: string) => void; + readonly setScreenResolution: (newRes: ScreenSize) => void; + readonly setScreenViewport: (newView: ScreenSize) => void; + readonly setColorDepth: (newLang: number) => void; + readonly setSubjectData: (config: SubjectConfiguration) => void; + readonly getSessionUserId: () => Promise; + readonly getSessionId: () => Promise; + readonly getSessionIndex: () => Promise; + readonly getSessionState: () => Promise; + readonly getIsInBackground: () => boolean | undefined; + readonly getBackgroundIndex: () => number | undefined; + readonly getForegroundIndex: () => number | undefined; + readonly enablePlatformContext: () => Promise; + readonly disablePlatformContext: () => void; + readonly refreshPlatformContext: () => Promise; +}; + +// @public +export function removeAllTrackers(): void; + +// @public +export function removeTracker(trackerNamespace: string): void; + +// @public +export type RequestFailure = { + events: EventBatch; + status?: number; + message?: string; + willRetry: boolean; +}; + +// @public +export interface RuleSet { + // (undocumented) + accept?: Array | string; + // (undocumented) + reject?: Array | string; +} + +// @public +export type RuleSetProvider = [ +RuleSet, +Array | ContextPrimitive +]; + +// @public +export type ScreenSize = [number, number]; + +// @public +export type ScreenViewProps = { + name: string; + id?: string; + type?: string; + previousName?: string; + previousId?: string; + previousType?: string; + transitionType?: string; +}; + +// @public +export type ScrollChangedProps = { + yOffset?: number; + xOffset?: number; + viewHeight?: number; + viewWidth?: number; + contentHeight?: number; + contentWidth?: number; +}; + +// @public +export type SelfDescribing> = SelfDescribingJson; + +// @public +export interface SessionConfiguration { + backgroundSessionTimeout?: number; + foregroundSessionTimeout?: number; + sessionContext?: boolean; +} + +// @public +export interface SessionState { + eventIndex?: number; + firstEventId?: string; + firstEventTimestamp?: string; + previousSessionId?: string; + sessionId: string; + sessionIndex: number; + storageMechanism: string; + userId: string; +} + +// Warning: (ae-forgotten-export) The symbol "StructuredEvent" needs to be exported by the entry point index.d.ts +// +// @public +export type StructuredProps = StructuredEvent; + +// @public +export interface SubjectConfiguration { + colorDepth?: number; + domainUserId?: string; + ipAddress?: string; + language?: string; + networkUserId?: string; + screenResolution?: ScreenSize; + screenViewport?: ScreenSize; + timezone?: string; + useragent?: string; + userId?: string; +} + +// @public +export type Timestamp = TrueTimestamp | DeviceTimestamp | number; + +// @public +export type TimingProps = { + category: string; + variable: string; + timing: number; + label?: string; +}; + +// @public +export interface TrackerConfiguration { + appId?: string; + devicePlatform?: Platform; + encodeBase64?: boolean; + namespace: string; + plugins?: BrowserPlugin[]; +} + +// @public +export interface TrackerCore { + addGlobalContexts(contexts: Array | Record): void; + addPayloadDict(dict: Payload): void; + addPayloadPair: (key: string, value: unknown) => void; + addPlugin(configuration: CorePluginConfiguration): void; + clearGlobalContexts(): void; + deactivate(): void; + getBase64Encoding(): boolean; + removeGlobalContexts(contexts: Array): void; + resetPayloadPairs(dict: Payload): void; + setAppId(appId: string): void; + setBase64Encoding(encode: boolean): void; + setColorDepth(depth: string): void; + setIpAddress(ip: string): void; + setLang(lang: string): void; + setPlatform(value: string): void; + setScreenResolution(width: string, height: string): void; + setTimezone(timezone: string): void; + setTrackerNamespace(name: string): void; + setTrackerVersion(version: string): void; + setUseragent(useragent: string): void; + setUserId(userId: string): void; + setViewport(width: string, height: string): void; + track: (pb: PayloadBuilder, context?: Array | null, timestamp?: Timestamp | null) => Payload | undefined; +} + +// @public +export type Trigger = 'push' | 'location' | 'calendar' | 'timeInterval' | 'other'; + +// @public +export interface TrueTimestamp { + // (undocumented) + readonly type: "ttm"; + // (undocumented) + readonly value: number; +} + +// @public (undocumented) +export const version: string; + +// @public +export type WebViewMessageHandler = (message: { + nativeEvent: { + data: string; + }; +}) => void; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/api-docs/docusaurus.config.js b/api-docs/docusaurus.config.js new file mode 100644 index 000000000..7573216a1 --- /dev/null +++ b/api-docs/docusaurus.config.js @@ -0,0 +1,100 @@ +// @ts-check +// `@type` JSDoc annotations allow editor autocompletion and type checking +// (when paired with `@ts-check`). +// There are various equivalent ways to declare your Docusaurus config. +// See: https://docusaurus.io/docs/api/docusaurus-config + +import { themes as prismThemes } from 'prism-react-renderer'; + +/** @type {import('@docusaurus/types').Config} */ +const config = { + title: 'Snowplow Javascript API Docs', + favicon: 'img/favicon.ico', + url: 'http://snowplow.github.io', + baseUrl: '/snowplow-javascript-tracker/', + organizationName: 'snowplow', + projectName: 'snowplow-javascript-tracker', + onBrokenLinks: 'throw', + onBrokenMarkdownLinks: 'warn', + i18n: { + defaultLocale: 'en', + locales: ['en'], + }, + presets: [ + [ + 'classic', + /** @type {import('@docusaurus/preset-classic').Options} */ + ({ + docs: { + sidebarPath: './sidebars.js', + // Please change this to your repo. + }, + theme: { + customCss: './src/css/custom.css', + }, + }), + ], + ], + + themeConfig: + /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ + ({ + navbar: { + title: 'API Docs', + logo: { + src: 'img/favicon.ico', + href: '/docs', + target: '_self', + }, + items: [ + { + href: 'https://github.com/snowplow/snowplow-javascript-tracker', + label: 'GitHub', + position: 'right', + }, + ], + }, + footer: { + style: 'dark', + links: [ + { + title: 'Docs', + items: [ + { + label: 'Snowplow JS Docs', + to: 'https://docs.snowplow.io/docs/sources/trackers/web-trackers/', + }, + ], + }, + { + title: 'Community', + items: [ + { + label: 'Community', + href: 'https://community.snowplow.io/', + }, + { + label: 'Website', + href: 'https://snowplow.io/', + }, + ], + }, + { + title: 'More', + items: [ + { + label: 'GitHub', + href: 'https://github.com/snowplow/snowplow-javascript-tracker', + }, + ], + }, + ], + }, + prism: { + theme: prismThemes.github, + darkTheme: prismThemes.dracula, + }, + }), +}; + +export default config; diff --git a/api-docs/package-lock.json b/api-docs/package-lock.json new file mode 100644 index 000000000..694fffc0e --- /dev/null +++ b/api-docs/package-lock.json @@ -0,0 +1,18381 @@ +{ + "name": "api-docs", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "api-docs", + "version": "0.0.0", + "license": "ISC", + "dependencies": { + "@docusaurus/core": "3.10.0", + "@docusaurus/preset-classic": "3.10.0", + "@mdx-js/react": "^3.0.1", + "clsx": "^1.2.1", + "prism-react-renderer": "^2.3.1", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@docusaurus/module-type-aliases": "3.10.0", + "@docusaurus/types": "3.10.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@algolia/abtesting": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.16.2.tgz", + "integrity": "sha512-n9s6bEV6imdtIEd+BGP7WkA4pEZ5YTdgQ05JQhHwWawHg3hyjpNwC0TShGz6zWhv+jfLDGA/6FFNbySFS0P9cw==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.50.2", + "@algolia/requester-browser-xhr": "5.50.2", + "@algolia/requester-fetch": "5.50.2", + "@algolia/requester-node-http": "5.50.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.19.8", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.19.8.tgz", + "integrity": "sha512-3YEorYg44niXcm7gkft3nXYItHd44e8tmh4D33CTszPgP0QWkaLEaFywiNyJBo7UL/mqObA/G9RYuU7R8tN1IA==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.19.8", + "@algolia/autocomplete-shared": "1.19.8" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.19.8", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.19.8.tgz", + "integrity": "sha512-ZvJWO8ZZJDpc1LNM2TTBdmQsZBLMR4rU5iNR2OYvEeFBiaf/0ESnRSSLQbryarJY4SVxtoz6A2ZtDMNM+iQEAA==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.19.8" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.19.8", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.19.8.tgz", + "integrity": "sha512-h5hf2t8ejF6vlOgvLaZzQbWs5SyH2z4PAWygNAvvD/2RI29hdQ54ldUGwqVuj9Srs+n8XUKTPUqb7fvhBhQrnQ==", + "license": "MIT", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/client-abtesting": { + "version": "5.50.2", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.50.2.tgz", + "integrity": "sha512-52iq0vHy1sphgnwoZyx5PmbEt8hsh+m7jD123LmBs6qy4GK7LbYZIeKd+nSnSipN2zvKRZ2zScS6h9PW3J7SXg==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.50.2", + "@algolia/requester-browser-xhr": "5.50.2", + "@algolia/requester-fetch": "5.50.2", + "@algolia/requester-node-http": "5.50.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "5.50.2", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.50.2.tgz", + "integrity": "sha512-WpPIUg+cSG2aPUG0gS8Ko9DwRgbRPUZxJkolhL2aCsmSlcEEZT65dILrfg5ovcxtx0Kvr+xtBVsTMtsQWRtPDQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.50.2", + "@algolia/requester-browser-xhr": "5.50.2", + "@algolia/requester-fetch": "5.50.2", + "@algolia/requester-node-http": "5.50.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.50.2", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.50.2.tgz", + "integrity": "sha512-Gj2MgtArGcsr82kIqRlo6/dCAFjrs2gLByEqyRENuT7ugrSMFuqg1vDzeBjRL1t3EJEJCFtT0PLX3gB8A6Hq4Q==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.50.2", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.50.2.tgz", + "integrity": "sha512-CUqoid5jDpmrc0oK3/xuZXFt6kwT0P9Lw7/nsM14YTr6puvmi+OUKmURpmebQF22S2vCG8L1DAoXXujxQUi/ug==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.50.2", + "@algolia/requester-browser-xhr": "5.50.2", + "@algolia/requester-fetch": "5.50.2", + "@algolia/requester-node-http": "5.50.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "5.50.2", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.50.2.tgz", + "integrity": "sha512-AndZWFoc0gbP5901OeQJ73BazgGgSGiBEba4ohdoJuZwHTO2Gio8Q4L1VLmytMBYcviVigB0iICToMvEJxI4ug==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.50.2", + "@algolia/requester-browser-xhr": "5.50.2", + "@algolia/requester-fetch": "5.50.2", + "@algolia/requester-node-http": "5.50.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.50.2", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.50.2.tgz", + "integrity": "sha512-NWoL+psEkz5dIzweaByVXuEB45wS8/rk0E0AhMMnaVJdVs7TcACPH2/OURm+N0xRDITkTHqCna823rd6Uqntdg==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.50.2", + "@algolia/requester-browser-xhr": "5.50.2", + "@algolia/requester-fetch": "5.50.2", + "@algolia/requester-node-http": "5.50.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.50.2", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.50.2.tgz", + "integrity": "sha512-ypSboUJ3XJoQz5DeDo82hCnrRuwq3q9ZdFhVKAik9TnZh1DvLqoQsrbBjXg7C7zQOtV/Qbge/HmyoV6V5L7MhQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.50.2", + "@algolia/requester-browser-xhr": "5.50.2", + "@algolia/requester-fetch": "5.50.2", + "@algolia/requester-node-http": "5.50.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/events": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@algolia/events/-/events-4.0.1.tgz", + "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==", + "license": "MIT" + }, + "node_modules/@algolia/ingestion": { + "version": "1.50.2", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.50.2.tgz", + "integrity": "sha512-VlR2FRXLw2bCB94SQo6zxg/Qi+547aOji6Pb+dKE7h1DMCCY317St+OpjpmgzE+bT2O9ALIc0V4nVIBOd7Gy+Q==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.50.2", + "@algolia/requester-browser-xhr": "5.50.2", + "@algolia/requester-fetch": "5.50.2", + "@algolia/requester-node-http": "5.50.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/monitoring": { + "version": "1.50.2", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.50.2.tgz", + "integrity": "sha512-Cmvfp2+qopzQt8OilU97rhLhosq7ZrB6uieok3EwFUqG/aalPg6DgfCmu0yJMrYe+KMC1qRVt1MTRAUwLknUMQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.50.2", + "@algolia/requester-browser-xhr": "5.50.2", + "@algolia/requester-fetch": "5.50.2", + "@algolia/requester-node-http": "5.50.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "5.50.2", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.50.2.tgz", + "integrity": "sha512-jrkuyKoOM7dFWQ/6Y4hQAse2SC3L/RldG6GnPjMvAj65h+7Ubb51S0pKk4ofSStF0xm4LCNe0C4T6XX4nOFDiQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.50.2", + "@algolia/requester-browser-xhr": "5.50.2", + "@algolia/requester-fetch": "5.50.2", + "@algolia/requester-node-http": "5.50.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.50.2", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.50.2.tgz", + "integrity": "sha512-4107YLJqCudPiBUlwnk6oTSUVwU7ab+qL1SfQGEDYI8DZH5gsf1ekPt9JykXRKYXf2IfouFL5GiCY/PHTFIjYw==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.50.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.50.2", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.50.2.tgz", + "integrity": "sha512-vOrd3MQpLgmf6wXAueTuZ/cA0W4uRwIHHaxNy3h+a6YcNn6bCV/gFdZuv3F13v593zRU2k5R75NmvRWLenvMrw==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.50.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.50.2", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.50.2.tgz", + "integrity": "sha512-Mu9BFtgzGqDUy5Bcs2nMyoILIFSN13GKQaklKAFIsd0K3/9CpNyfeBc+/+Qs6mFZLlxG9qzullO7h+bjcTBuGQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.50.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", + "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", + "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "regexpu-core": "^6.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", + "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "debug": "^4.4.3", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.11" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", + "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", + "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.6.tgz", + "integrity": "sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", + "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", + "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.6.tgz", + "integrity": "sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.28.6.tgz", + "integrity": "sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.0.tgz", + "integrity": "sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.28.6.tgz", + "integrity": "sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-remap-async-to-generator": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.6.tgz", + "integrity": "sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.28.6.tgz", + "integrity": "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.6.tgz", + "integrity": "sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.6.tgz", + "integrity": "sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-globals": "^7.28.0", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-replace-supers": "^7.28.6", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.28.6.tgz", + "integrity": "sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/template": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", + "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.28.6.tgz", + "integrity": "sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.0.tgz", + "integrity": "sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.6.tgz", + "integrity": "sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.6.tgz", + "integrity": "sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.28.6.tgz", + "integrity": "sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.6.tgz", + "integrity": "sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz", + "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.0.tgz", + "integrity": "sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.0.tgz", + "integrity": "sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.28.6.tgz", + "integrity": "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.28.6.tgz", + "integrity": "sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.6.tgz", + "integrity": "sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.28.6.tgz", + "integrity": "sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.6.tgz", + "integrity": "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.28.6.tgz", + "integrity": "sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.28.6.tgz", + "integrity": "sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.27.1.tgz", + "integrity": "sha512-edoidOjl/ZxvYo4lSBOQGDSyToYVkTAwyVoa2tkuYTSmjrB1+uAedoL5iROVLXkxH+vRgA7uP4tMg2pUJpZ3Ug==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.28.0.tgz", + "integrity": "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.28.6.tgz", + "integrity": "sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-syntax-jsx": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.27.1.tgz", + "integrity": "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==", + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.27.1.tgz", + "integrity": "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.0.tgz", + "integrity": "sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.28.6.tgz", + "integrity": "sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.29.0.tgz", + "integrity": "sha512-jlaRT5dJtMaMCV6fAuLbsQMSwz/QkvaHOHOSXRitGGwSpR1blCY4KUKoyP2tYO8vJcqYe8cEj96cqSztv3uF9w==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.28.6.tgz", + "integrity": "sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.6.tgz", + "integrity": "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.28.6.tgz", + "integrity": "sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.28.6.tgz", + "integrity": "sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.2.tgz", + "integrity": "sha512-DYD23veRYGvBFhcTY1iUvJnDNpuqNd/BzBwCvzOTKUnJjKg5kpUBh3/u9585Agdkgj+QuygG7jLfOPWMa2KVNw==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.6", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.28.6", + "@babel/plugin-syntax-import-attributes": "^7.28.6", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.29.0", + "@babel/plugin-transform-async-to-generator": "^7.28.6", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.6", + "@babel/plugin-transform-class-properties": "^7.28.6", + "@babel/plugin-transform-class-static-block": "^7.28.6", + "@babel/plugin-transform-classes": "^7.28.6", + "@babel/plugin-transform-computed-properties": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5", + "@babel/plugin-transform-dotall-regex": "^7.28.6", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.0", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-explicit-resource-management": "^7.28.6", + "@babel/plugin-transform-exponentiation-operator": "^7.28.6", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.28.6", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.28.6", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.28.6", + "@babel/plugin-transform-modules-systemjs": "^7.29.0", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.0", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.28.6", + "@babel/plugin-transform-numeric-separator": "^7.28.6", + "@babel/plugin-transform-object-rest-spread": "^7.28.6", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.28.6", + "@babel/plugin-transform-optional-chaining": "^7.28.6", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/plugin-transform-private-methods": "^7.28.6", + "@babel/plugin-transform-private-property-in-object": "^7.28.6", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.29.0", + "@babel/plugin-transform-regexp-modifiers": "^7.28.6", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.28.6", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.28.6", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.28.6", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.15", + "babel-plugin-polyfill-corejs3": "^0.14.0", + "babel-plugin-polyfill-regenerator": "^0.6.6", + "core-js-compat": "^3.48.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz", + "integrity": "sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8", + "core-js-compat": "^3.48.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.28.5.tgz", + "integrity": "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-transform-react-display-name": "^7.28.0", + "@babel/plugin-transform-react-jsx": "^7.27.1", + "@babel/plugin-transform-react-jsx-development": "^7.27.1", + "@babel/plugin-transform-react-pure-annotations": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz", + "integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@csstools/cascade-layer-name-parser": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-2.0.5.tgz", + "integrity": "sha512-p1ko5eHgV+MgXFVa4STPKpvPxr6ReS8oS2jzTukjR74i5zJNyWO1ZM1m8YKBXnzDKWfBN1ztLYlHxbVemDD88A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/media-query-list-parser": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.3.tgz", + "integrity": "sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/postcss-alpha-function": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-alpha-function/-/postcss-alpha-function-1.0.1.tgz", + "integrity": "sha512-isfLLwksH3yHkFXfCI2Gcaqg7wGGHZZwunoJzEZk0yKYIokgre6hYVFibKL3SYAoR1kBXova8LB+JoO5vZzi9w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-cascade-layers": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-5.0.2.tgz", + "integrity": "sha512-nWBE08nhO8uWl6kSAeCx4im7QfVko3zLrtgWZY4/bP87zrSPpSyN/3W3TDqz1jJuH+kbKOHXg5rJnK+ZVYcFFg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-cascade-layers/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/@csstools/postcss-cascade-layers/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@csstools/postcss-color-function": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-4.0.12.tgz", + "integrity": "sha512-yx3cljQKRaSBc2hfh8rMZFZzChaFgwmO2JfFgFr1vMcF3C/uyy5I4RFIBOIWGq1D+XbKCG789CGkG6zzkLpagA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-color-function-display-p3-linear": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function-display-p3-linear/-/postcss-color-function-display-p3-linear-1.0.1.tgz", + "integrity": "sha512-E5qusdzhlmO1TztYzDIi8XPdPoYOjoTY6HBYBCYSj+Gn4gQRBlvjgPQXzfzuPQqt8EhkC/SzPKObg4Mbn8/xMg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-color-mix-function": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-3.0.12.tgz", + "integrity": "sha512-4STERZfCP5Jcs13P1U5pTvI9SkgLgfMUMhdXW8IlJWkzOOOqhZIjcNhWtNJZes2nkBDsIKJ0CJtFtuaZ00moag==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-color-mix-variadic-function-arguments": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-variadic-function-arguments/-/postcss-color-mix-variadic-function-arguments-1.0.2.tgz", + "integrity": "sha512-rM67Gp9lRAkTo+X31DUqMEq+iK+EFqsidfecmhrteErxJZb6tUoJBVQca1Vn1GpDql1s1rD1pKcuYzMsg7Z1KQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-content-alt-text": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@csstools/postcss-content-alt-text/-/postcss-content-alt-text-2.0.8.tgz", + "integrity": "sha512-9SfEW9QCxEpTlNMnpSqFaHyzsiRpZ5J5+KqCu1u5/eEJAWsMhzT40qf0FIbeeglEvrGRMdDzAxMIz3wqoGSb+Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-contrast-color-function": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-contrast-color-function/-/postcss-contrast-color-function-2.0.12.tgz", + "integrity": "sha512-YbwWckjK3qwKjeYz/CijgcS7WDUCtKTd8ShLztm3/i5dhh4NaqzsbYnhm4bjrpFpnLZ31jVcbK8YL77z3GBPzA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-exponential-functions": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-2.0.9.tgz", + "integrity": "sha512-abg2W/PI3HXwS/CZshSa79kNWNZHdJPMBXeZNyPQFbbj8sKO3jXxOt/wF7juJVjyDTc6JrvaUZYFcSBZBhaxjw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-font-format-keywords": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-4.0.0.tgz", + "integrity": "sha512-usBzw9aCRDvchpok6C+4TXC57btc4bJtmKQWOHQxOVKen1ZfVqBUuCZ/wuqdX5GHsD0NRSr9XTP+5ID1ZZQBXw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-gamut-mapping": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-2.0.11.tgz", + "integrity": "sha512-fCpCUgZNE2piVJKC76zFsgVW1apF6dpYsqGyH8SIeCcM4pTEsRTWTLCaJIMKFEundsCKwY1rwfhtrio04RJ4Dw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-gradients-interpolation-method": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-5.0.12.tgz", + "integrity": "sha512-jugzjwkUY0wtNrZlFeyXzimUL3hN4xMvoPnIXxoZqxDvjZRiSh+itgHcVUWzJ2VwD/VAMEgCLvtaJHX+4Vj3Ow==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-hwb-function": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-4.0.12.tgz", + "integrity": "sha512-mL/+88Z53KrE4JdePYFJAQWFrcADEqsLprExCM04GDNgHIztwFzj0Mbhd/yxMBngq0NIlz58VVxjt5abNs1VhA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-ic-unit": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-4.0.4.tgz", + "integrity": "sha512-yQ4VmossuOAql65sCPppVO1yfb7hDscf4GseF0VCA/DTDaBc0Wtf8MTqVPfjGYlT5+2buokG0Gp7y0atYZpwjg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-initial": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-initial/-/postcss-initial-2.0.1.tgz", + "integrity": "sha512-L1wLVMSAZ4wovznquK0xmC7QSctzO4D0Is590bxpGqhqjboLXYA16dWZpfwImkdOgACdQ9PqXsuRroW6qPlEsg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-5.0.3.tgz", + "integrity": "sha512-jS/TY4SpG4gszAtIg7Qnf3AS2pjcUM5SzxpApOrlndMeGhIbaTzWBzzP/IApXoNWEW7OhcjkRT48jnAUIFXhAQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@csstools/postcss-light-dark-function": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@csstools/postcss-light-dark-function/-/postcss-light-dark-function-2.0.11.tgz", + "integrity": "sha512-fNJcKXJdPM3Lyrbmgw2OBbaioU7yuKZtiXClf4sGdQttitijYlZMD5K7HrC/eF83VRWRrYq6OZ0Lx92leV2LFA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-float-and-clear": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-float-and-clear/-/postcss-logical-float-and-clear-3.0.0.tgz", + "integrity": "sha512-SEmaHMszwakI2rqKRJgE+8rpotFfne1ZS6bZqBoQIicFyV+xT1UF42eORPxJkVJVrH9C0ctUgwMSn3BLOIZldQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-overflow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overflow/-/postcss-logical-overflow-2.0.0.tgz", + "integrity": "sha512-spzR1MInxPuXKEX2csMamshR4LRaSZ3UXVaRGjeQxl70ySxOhMpP2252RAFsg8QyyBXBzuVOOdx1+bVO5bPIzA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-overscroll-behavior": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overscroll-behavior/-/postcss-logical-overscroll-behavior-2.0.0.tgz", + "integrity": "sha512-e/webMjoGOSYfqLunyzByZj5KKe5oyVg/YSbie99VEaSDE2kimFm0q1f6t/6Jo+VVCQ/jbe2Xy+uX+C4xzWs4w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-resize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-resize/-/postcss-logical-resize-3.0.0.tgz", + "integrity": "sha512-DFbHQOFW/+I+MY4Ycd/QN6Dg4Hcbb50elIJCfnwkRTCX05G11SwViI5BbBlg9iHRl4ytB7pmY5ieAFk3ws7yyg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-viewport-units": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-3.0.4.tgz", + "integrity": "sha512-q+eHV1haXA4w9xBwZLKjVKAWn3W2CMqmpNpZUk5kRprvSiBEGMgrNH3/sJZ8UA3JgyHaOt3jwT9uFa4wLX4EqQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-media-minmax": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-2.0.9.tgz", + "integrity": "sha512-af9Qw3uS3JhYLnCbqtZ9crTvvkR+0Se+bBqSr7ykAnl9yKhk6895z9rf+2F4dClIDJWxgn0iZZ1PSdkhrbs2ig==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/media-query-list-parser": "^4.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-media-queries-aspect-ratio-number-values": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-3.0.5.tgz", + "integrity": "sha512-zhAe31xaaXOY2Px8IYfoVTB3wglbJUVigGphFLj6exb7cjZRH9A6adyE22XfFK3P2PzwRk0VDeTJmaxpluyrDg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/media-query-list-parser": "^4.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-nested-calc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-4.0.0.tgz", + "integrity": "sha512-jMYDdqrQQxE7k9+KjstC3NbsmC063n1FTPLCgCRS2/qHUbHM0mNy9pIn4QIiQGs9I/Bg98vMqw7mJXBxa0N88A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-normalize-display-values": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.1.tgz", + "integrity": "sha512-TQUGBuRvxdc7TgNSTevYqrL8oItxiwPDixk20qCB5me/W8uF7BPbhRrAvFuhEoywQp/woRsUZ6SJ+sU5idZAIA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-oklab-function": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-4.0.12.tgz", + "integrity": "sha512-HhlSmnE1NKBhXsTnNGjxvhryKtO7tJd1w42DKOGFD6jSHtYOrsJTQDKPMwvOfrzUAk8t7GcpIfRyM7ssqHpFjg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-position-area-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-position-area-property/-/postcss-position-area-property-1.0.0.tgz", + "integrity": "sha512-fUP6KR8qV2NuUZV3Cw8itx0Ep90aRjAZxAEzC3vrl6yjFv+pFsQbR18UuQctEKmA72K9O27CoYiKEgXxkqjg8Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-progressive-custom-properties": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-4.2.1.tgz", + "integrity": "sha512-uPiiXf7IEKtUQXsxu6uWtOlRMXd2QWWy5fhxHDnPdXKCQckPP3E34ZgDoZ62r2iT+UOgWsSbM4NvHE5m3mAEdw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-property-rule-prelude-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-property-rule-prelude-list/-/postcss-property-rule-prelude-list-1.0.0.tgz", + "integrity": "sha512-IxuQjUXq19fobgmSSvUDO7fVwijDJaZMvWQugxfEUxmjBeDCVaDuMpsZ31MsTm5xbnhA+ElDi0+rQ7sQQGisFA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-random-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-random-function/-/postcss-random-function-2.0.1.tgz", + "integrity": "sha512-q+FQaNiRBhnoSNo+GzqGOIBKoHQ43lYz0ICrV+UudfWnEF6ksS6DsBIJSISKQT2Bvu3g4k6r7t0zYrk5pDlo8w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-relative-color-syntax": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-3.0.12.tgz", + "integrity": "sha512-0RLIeONxu/mtxRtf3o41Lq2ghLimw0w9ByLWnnEVuy89exmEEq8bynveBxNW3nyHqLAFEeNtVEmC1QK9MZ8Huw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-scope-pseudo-class": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-scope-pseudo-class/-/postcss-scope-pseudo-class-4.0.1.tgz", + "integrity": "sha512-IMi9FwtH6LMNuLea1bjVMQAsUhFxJnyLSgOp/cpv5hrzWmrUYU5fm0EguNDIIOHUqzXode8F/1qkC/tEo/qN8Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-scope-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@csstools/postcss-sign-functions": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-sign-functions/-/postcss-sign-functions-1.1.4.tgz", + "integrity": "sha512-P97h1XqRPcfcJndFdG95Gv/6ZzxUBBISem0IDqPZ7WMvc/wlO+yU0c5D/OCpZ5TJoTt63Ok3knGk64N+o6L2Pg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-stepped-value-functions": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-4.0.9.tgz", + "integrity": "sha512-h9btycWrsex4dNLeQfyU3y3w40LMQooJWFMm/SK9lrKguHDcFl4VMkncKKoXi2z5rM9YGWbUQABI8BT2UydIcA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-syntax-descriptor-syntax-production": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-syntax-descriptor-syntax-production/-/postcss-syntax-descriptor-syntax-production-1.0.1.tgz", + "integrity": "sha512-GneqQWefjM//f4hJ/Kbox0C6f2T7+pi4/fqTqOFGTL3EjnvOReTqO1qUQ30CaUjkwjYq9qZ41hzarrAxCc4gow==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-system-ui-font-family": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-system-ui-font-family/-/postcss-system-ui-font-family-1.0.0.tgz", + "integrity": "sha512-s3xdBvfWYfoPSBsikDXbuorcMG1nN1M6GdU0qBsGfcmNR0A/qhloQZpTxjA3Xsyrk1VJvwb2pOfiOT3at/DuIQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-text-decoration-shorthand": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-4.0.3.tgz", + "integrity": "sha512-KSkGgZfx0kQjRIYnpsD7X2Om9BUXX/Kii77VBifQW9Ih929hK0KNjVngHDH0bFB9GmfWcR9vJYJJRvw/NQjkrA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-trigonometric-functions": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-4.0.9.tgz", + "integrity": "sha512-Hnh5zJUdpNrJqK9v1/E3BbrQhaDTj5YiX7P61TOvUhoDHnUmsNNxcDAgkQ32RrcWx9GVUvfUNPcUkn8R3vIX6A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-unset-value": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-4.0.0.tgz", + "integrity": "sha512-cBz3tOCI5Fw6NIFEwU3RiwK6mn3nKegjpJuzCndoGq3BZPkUjnsq7uQmIeMNeMbMk7YD2MfKcgCpZwX5jyXqCA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/utilities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/utilities/-/utilities-2.0.0.tgz", + "integrity": "sha512-5VdOr0Z71u+Yp3ozOx8T11N703wIFGVRgOWbOZMKgglPJsWA54MRIoMNVMa7shUToIhx5J8vX4sOZgD2XiihiQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@docsearch/core": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/@docsearch/core/-/core-4.6.2.tgz", + "integrity": "sha512-/S0e6Dj7Zcm8m9Rru49YEX49dhU11be68c+S/BCyN8zQsTTgkKzXlhRbVL5mV6lOLC2+ZRRryaTdcm070Ug2oA==", + "license": "MIT", + "peerDependencies": { + "@types/react": ">= 16.8.0 < 20.0.0", + "react": ">= 16.8.0 < 20.0.0", + "react-dom": ">= 16.8.0 < 20.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@docsearch/css": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-4.6.2.tgz", + "integrity": "sha512-fH/cn8BjEEdM2nJdjNMHIvOVYupG6AIDtFVDgIZrNzdCSj4KXr9kd+hsehqsNGYjpUjObeKYKvgy/IwCb1jZYQ==", + "license": "MIT" + }, + "node_modules/@docsearch/react": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-4.6.2.tgz", + "integrity": "sha512-/BbtGFtqVOGwZx0dw/UfhN/0/DmMQYnulY4iv0tPRhC2JCXv0ka/+izwt3Jzo1ZxXS/2eMvv9zHsBJOK1I9f/w==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-core": "1.19.2", + "@docsearch/core": "4.6.2", + "@docsearch/css": "4.6.2" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 20.0.0", + "react": ">= 16.8.0 < 20.0.0", + "react-dom": ">= 16.8.0 < 20.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } + } + }, + "node_modules/@docsearch/react/node_modules/@algolia/autocomplete-core": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.19.2.tgz", + "integrity": "sha512-mKv7RyuAzXvwmq+0XRK8HqZXt9iZ5Kkm2huLjgn5JoCPtDy+oh9yxUMfDDaVCw0oyzZ1isdJBc7l9nuCyyR7Nw==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.19.2", + "@algolia/autocomplete-shared": "1.19.2" + } + }, + "node_modules/@docsearch/react/node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.19.2.tgz", + "integrity": "sha512-TjxbcC/r4vwmnZaPwrHtkXNeqvlpdyR+oR9Wi2XyfORkiGkLTVhX2j+O9SaCCINbKoDfc+c2PB8NjfOnz7+oKg==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.19.2" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@docsearch/react/node_modules/@algolia/autocomplete-shared": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.19.2.tgz", + "integrity": "sha512-jEazxZTVD2nLrC+wYlVHQgpBoBB5KPStrJxLzsIFl6Kqd1AlG9sIAGl39V5tECLpIQzB3Qa2T6ZPJ1ChkwMK/w==", + "license": "MIT", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@docusaurus/babel": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/babel/-/babel-3.10.0.tgz", + "integrity": "sha512-mqCJhCZNZUDg0zgDEaPTM4DnRsisa24HdqTy/qn/MQlbwhTb4WVaZg6ZyX6yIVKqTz8fS1hBMgM+98z+BeJJDg==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.25.9", + "@babel/preset-env": "^7.25.9", + "@babel/preset-react": "^7.25.9", + "@babel/preset-typescript": "^7.25.9", + "@babel/runtime": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@docusaurus/logger": "3.10.0", + "@docusaurus/utils": "3.10.0", + "babel-plugin-dynamic-import-node": "^2.3.3", + "fs-extra": "^11.1.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/bundler": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/bundler/-/bundler-3.10.0.tgz", + "integrity": "sha512-iONUGZGgp+lAkw/cJZH6irONcF4p8+278IsdRlq8lYhxGjkoNUs0w7F4gVXBYSNChq5KG5/JleTSsdJySShxow==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.9", + "@docusaurus/babel": "3.10.0", + "@docusaurus/cssnano-preset": "3.10.0", + "@docusaurus/logger": "3.10.0", + "@docusaurus/types": "3.10.0", + "@docusaurus/utils": "3.10.0", + "babel-loader": "^9.2.1", + "clean-css": "^5.3.3", + "copy-webpack-plugin": "^11.0.0", + "css-loader": "^6.11.0", + "css-minimizer-webpack-plugin": "^5.0.1", + "cssnano": "^6.1.2", + "file-loader": "^6.2.0", + "html-minifier-terser": "^7.2.0", + "mini-css-extract-plugin": "^2.9.2", + "null-loader": "^4.0.1", + "postcss": "^8.5.4", + "postcss-loader": "^7.3.4", + "postcss-preset-env": "^10.2.1", + "terser-webpack-plugin": "^5.3.9", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.95.0", + "webpackbar": "^6.0.1" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "@docusaurus/faster": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/faster": { + "optional": true + } + } + }, + "node_modules/@docusaurus/core": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.10.0.tgz", + "integrity": "sha512-mgLdQsO8xppnQZc3LPi+Mf+PkPeyxJeIx11AXAq/14fsaMefInQiMEZUUmrc7J+956G/f7MwE7tn8KZgi3iRcA==", + "license": "MIT", + "dependencies": { + "@docusaurus/babel": "3.10.0", + "@docusaurus/bundler": "3.10.0", + "@docusaurus/logger": "3.10.0", + "@docusaurus/mdx-loader": "3.10.0", + "@docusaurus/utils": "3.10.0", + "@docusaurus/utils-common": "3.10.0", + "@docusaurus/utils-validation": "3.10.0", + "boxen": "^6.2.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cli-table3": "^0.6.3", + "combine-promises": "^1.1.0", + "commander": "^5.1.0", + "core-js": "^3.31.1", + "detect-port": "^1.5.1", + "escape-html": "^1.0.3", + "eta": "^2.2.0", + "eval": "^0.1.8", + "execa": "^5.1.1", + "fs-extra": "^11.1.1", + "html-tags": "^3.3.1", + "html-webpack-plugin": "^5.6.0", + "leven": "^3.1.0", + "lodash": "^4.17.21", + "open": "^8.4.0", + "p-map": "^4.0.0", + "prompts": "^2.4.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "react-loadable": "npm:@docusaurus/react-loadable@6.0.0", + "react-loadable-ssr-addon-v5-slorber": "^1.0.3", + "react-router": "^5.3.4", + "react-router-config": "^5.1.1", + "react-router-dom": "^5.3.4", + "semver": "^7.5.4", + "serve-handler": "^6.1.7", + "tinypool": "^1.0.2", + "tslib": "^2.6.0", + "update-notifier": "^6.0.2", + "webpack": "^5.95.0", + "webpack-bundle-analyzer": "^4.10.2", + "webpack-dev-server": "^5.2.2", + "webpack-merge": "^6.0.1" + }, + "bin": { + "docusaurus": "bin/docusaurus.mjs" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "@docusaurus/faster": "*", + "@mdx-js/react": "^3.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@docusaurus/faster": { + "optional": true + } + } + }, + "node_modules/@docusaurus/cssnano-preset": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.10.0.tgz", + "integrity": "sha512-qzSshTO1DB3TYW+dPUal5KHM7XPc5YQfzF3Kdb2NDACJUyGbNcFtw3tGkCJlYwhNCRKbZcmwraKUS1i5dcHdGg==", + "license": "MIT", + "dependencies": { + "cssnano-preset-advanced": "^6.1.2", + "postcss": "^8.5.4", + "postcss-sort-media-queries": "^5.2.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/logger": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.10.0.tgz", + "integrity": "sha512-9jrZzFuBH1LDRlZ7cznAhCLmAZ3HSDqgwdrSSZdGHq9SPUOQgXXu8mnxe2ZRB9NS1PCpMTIOVUqDtZPIhMafZg==", + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/mdx-loader": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.10.0.tgz", + "integrity": "sha512-mQQV97080AH4PYNs087l202NMDqRopZA4mg5W76ZZyTFrmWhJ3mHg+8A+drJVENxw5/Q+wHMHLgsx+9z1nEs0A==", + "license": "MIT", + "dependencies": { + "@docusaurus/logger": "3.10.0", + "@docusaurus/utils": "3.10.0", + "@docusaurus/utils-validation": "3.10.0", + "@mdx-js/mdx": "^3.0.0", + "@slorber/remark-comment": "^1.0.0", + "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^3.0.1", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "image-size": "^2.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-raw": "^7.0.0", + "remark-directive": "^3.0.0", + "remark-emoji": "^4.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", + "stringify-object": "^3.3.0", + "tslib": "^2.6.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0", + "url-loader": "^4.1.1", + "vfile": "^6.0.1", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/module-type-aliases": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.10.0.tgz", + "integrity": "sha512-/1O0Zg8w3DFrYX/I6Fbss7OJrtZw1QoyjDhegiFNHVi9A9Y0gQ3jUAytVxF6ywpAWpLyLxch8nN8H/V3XfzdJQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/types": "3.10.0", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "@types/react-router-dom": "*", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "react-loadable": "npm:@docusaurus/react-loadable@6.0.0" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/@docusaurus/plugin-content-blog": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.10.0.tgz", + "integrity": "sha512-RuTz68DhB7CL96QO5UsFbciD7GPYq6QV+YMfF9V0+N4ZgLhJIBgpVAr8GobrKF6NRe5cyWWETU5z5T834piG9g==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.0", + "@docusaurus/logger": "3.10.0", + "@docusaurus/mdx-loader": "3.10.0", + "@docusaurus/theme-common": "3.10.0", + "@docusaurus/types": "3.10.0", + "@docusaurus/utils": "3.10.0", + "@docusaurus/utils-common": "3.10.0", + "@docusaurus/utils-validation": "3.10.0", + "cheerio": "1.0.0-rc.12", + "combine-promises": "^1.1.0", + "feed": "^4.2.2", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", + "schema-dts": "^1.1.2", + "srcset": "^4.0.0", + "tslib": "^2.6.0", + "unist-util-visit": "^5.0.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "@docusaurus/plugin-content-docs": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-docs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.10.0.tgz", + "integrity": "sha512-9BjHhf15ct8Z7TThTC0xRndKDVvMKmVsAGAN7W9FpNRzfMdScOGcXtLmcCWtJGvAezjOJIm6CxOYCy3Io5+RnQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.0", + "@docusaurus/logger": "3.10.0", + "@docusaurus/mdx-loader": "3.10.0", + "@docusaurus/module-type-aliases": "3.10.0", + "@docusaurus/theme-common": "3.10.0", + "@docusaurus/types": "3.10.0", + "@docusaurus/utils": "3.10.0", + "@docusaurus/utils-common": "3.10.0", + "@docusaurus/utils-validation": "3.10.0", + "@types/react-router-config": "^5.0.7", + "combine-promises": "^1.1.0", + "fs-extra": "^11.1.1", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "schema-dts": "^1.1.2", + "tslib": "^2.6.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-pages": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.10.0.tgz", + "integrity": "sha512-5amX8kEJI+nIGtuLVjYk59Y5utEJ3CHETFOPEE4cooIRLA4xM4iBsA6zFgu4ljcopeYwvBzFEWf5g2I6Yb9SkA==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.0", + "@docusaurus/mdx-loader": "3.10.0", + "@docusaurus/types": "3.10.0", + "@docusaurus/utils": "3.10.0", + "@docusaurus/utils-validation": "3.10.0", + "fs-extra": "^11.1.1", + "tslib": "^2.6.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-css-cascade-layers": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-css-cascade-layers/-/plugin-css-cascade-layers-3.10.0.tgz", + "integrity": "sha512-6q1vtt5FJcg5osgkHeM1euErECNqEZ5Z1j69yiNx2luEBIso+nxCkS9nqj8w+MK5X7rvKEToGhFfOFWncs51pQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.0", + "@docusaurus/types": "3.10.0", + "@docusaurus/utils": "3.10.0", + "@docusaurus/utils-validation": "3.10.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/plugin-debug": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.10.0.tgz", + "integrity": "sha512-XcljKN+G+nmmK69uQA1d9BlYU3ZftG3T3zpK8/7Hf/wrOlV7TA4Ampdrdwkg0jElKdKAoSnPhCO0/U3bQGsVQQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.0", + "@docusaurus/types": "3.10.0", + "@docusaurus/utils": "3.10.0", + "fs-extra": "^11.1.1", + "react-json-view-lite": "^2.3.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-analytics": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.10.0.tgz", + "integrity": "sha512-hTEoodatpBZnUat5nFExbuTGA1lhWGy7vZGuTew5Q3QDtGKFpSJLYmZJhdTjvCFwv1+qQ67hgAVlKdJOB8TXow==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.0", + "@docusaurus/types": "3.10.0", + "@docusaurus/utils-validation": "3.10.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-gtag": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.10.0.tgz", + "integrity": "sha512-iB/Zzjv/eelJRbdULZqzWCbgMgJ7ht4ONVjXtN3+BI/muil6S87gQ1OJyPwlXD+ELdKkitC7bWv5eJdYOZLhrQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.0", + "@docusaurus/types": "3.10.0", + "@docusaurus/utils-validation": "3.10.0", + "@types/gtag.js": "^0.0.20", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-tag-manager": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.10.0.tgz", + "integrity": "sha512-FEjZxqKgLHa+Wez/EgKxRwvArNCWIScfyEQD95rot7jkxp6nonjI5XIbGfO/iYhM5Qinwe8aIEQHP2KZtpqVuA==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.0", + "@docusaurus/types": "3.10.0", + "@docusaurus/utils-validation": "3.10.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-sitemap": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.10.0.tgz", + "integrity": "sha512-DVTSLjB97hIjmayGnGcBfognCeI7ZuUKgEnU7Oz81JYqXtVg94mVTthDjq3QHTylYNeCUbkaW8VF0FDLcc8pPw==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.0", + "@docusaurus/logger": "3.10.0", + "@docusaurus/types": "3.10.0", + "@docusaurus/utils": "3.10.0", + "@docusaurus/utils-common": "3.10.0", + "@docusaurus/utils-validation": "3.10.0", + "fs-extra": "^11.1.1", + "sitemap": "^7.1.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-svgr": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-svgr/-/plugin-svgr-3.10.0.tgz", + "integrity": "sha512-lNljBESaETZqVBMPqkrGchr+UPT1eZzEPLmJhz8I76BxbjqgsUnRvrq6lQJ9sYjgmgX52KB7kkgczqd2yzoswQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.0", + "@docusaurus/types": "3.10.0", + "@docusaurus/utils": "3.10.0", + "@docusaurus/utils-validation": "3.10.0", + "@svgr/core": "8.1.0", + "@svgr/webpack": "^8.1.0", + "tslib": "^2.6.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/preset-classic": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.10.0.tgz", + "integrity": "sha512-kw/Ye02Hc6xP1OdTswy8yxQEHg0fdPpyWAQRxr5b2x3h7LlG2Zgbb5BDFROnXDDMpUxB7YejlocJIE5HIEfpNA==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.0", + "@docusaurus/plugin-content-blog": "3.10.0", + "@docusaurus/plugin-content-docs": "3.10.0", + "@docusaurus/plugin-content-pages": "3.10.0", + "@docusaurus/plugin-css-cascade-layers": "3.10.0", + "@docusaurus/plugin-debug": "3.10.0", + "@docusaurus/plugin-google-analytics": "3.10.0", + "@docusaurus/plugin-google-gtag": "3.10.0", + "@docusaurus/plugin-google-tag-manager": "3.10.0", + "@docusaurus/plugin-sitemap": "3.10.0", + "@docusaurus/plugin-svgr": "3.10.0", + "@docusaurus/theme-classic": "3.10.0", + "@docusaurus/theme-common": "3.10.0", + "@docusaurus/theme-search-algolia": "3.10.0", + "@docusaurus/types": "3.10.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/theme-classic": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.10.0.tgz", + "integrity": "sha512-9msCAsRdN+UG+RwPwCFb0uKy4tGoPh5YfBozXeGUtIeAgsMdn6f3G/oY861luZ3t8S2ET8S9Y/1GnpJAGWytww==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.10.0", + "@docusaurus/logger": "3.10.0", + "@docusaurus/mdx-loader": "3.10.0", + "@docusaurus/module-type-aliases": "3.10.0", + "@docusaurus/plugin-content-blog": "3.10.0", + "@docusaurus/plugin-content-docs": "3.10.0", + "@docusaurus/plugin-content-pages": "3.10.0", + "@docusaurus/theme-common": "3.10.0", + "@docusaurus/theme-translations": "3.10.0", + "@docusaurus/types": "3.10.0", + "@docusaurus/utils": "3.10.0", + "@docusaurus/utils-common": "3.10.0", + "@docusaurus/utils-validation": "3.10.0", + "@mdx-js/react": "^3.0.0", + "clsx": "^2.0.0", + "copy-text-to-clipboard": "^3.2.0", + "infima": "0.2.0-alpha.45", + "lodash": "^4.17.21", + "nprogress": "^0.2.0", + "postcss": "^8.5.4", + "prism-react-renderer": "^2.3.0", + "prismjs": "^1.29.0", + "react-router-dom": "^5.3.4", + "rtlcss": "^4.1.0", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/theme-classic/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@docusaurus/theme-common": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.10.0.tgz", + "integrity": "sha512-Dkp1YXKn16ByCJAdIjbDIOpVb4Z66MsVD694/ilX1vAAHaVEMrVsf/NPd9VgreyFx08rJ9GqV1MtzsbTcU73Kg==", + "license": "MIT", + "dependencies": { + "@docusaurus/mdx-loader": "3.10.0", + "@docusaurus/module-type-aliases": "3.10.0", + "@docusaurus/utils": "3.10.0", + "@docusaurus/utils-common": "3.10.0", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "clsx": "^2.0.0", + "parse-numeric-range": "^1.3.0", + "prism-react-renderer": "^2.3.0", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "@docusaurus/plugin-content-docs": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/theme-common/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@docusaurus/theme-search-algolia": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.10.0.tgz", + "integrity": "sha512-f5FPKI08e3JRG63vR/o4qeuUVHUHzFzM0nnF+AkB67soAZgNsKJRf2qmUZvlQkGwlV+QFkKe4D0ANMh1jToU3g==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-core": "^1.19.2", + "@docsearch/react": "^3.9.0 || ^4.3.2", + "@docusaurus/core": "3.10.0", + "@docusaurus/logger": "3.10.0", + "@docusaurus/plugin-content-docs": "3.10.0", + "@docusaurus/theme-common": "3.10.0", + "@docusaurus/theme-translations": "3.10.0", + "@docusaurus/utils": "3.10.0", + "@docusaurus/utils-validation": "3.10.0", + "algoliasearch": "^5.37.0", + "algoliasearch-helper": "^3.26.0", + "clsx": "^2.0.0", + "eta": "^2.2.0", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/theme-search-algolia/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@docusaurus/theme-translations": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.10.0.tgz", + "integrity": "sha512-L9IbFLwTc5+XdgH45iQYufLn0SVZd6BUNelDbKIFlH+E4hhjuj/XHWAFMX/w2K59rfy8wak9McOaei7BSUfRPA==", + "license": "MIT", + "dependencies": { + "fs-extra": "^11.1.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/types": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.10.0.tgz", + "integrity": "sha512-F0dOt3FOoO20rRaFK7whGFQZ3ggyrWEdQc/c8/UiRuzhtg4y1w9FspXH5zpCT07uMnJKBPGh+qNazbNlCQqvSw==", + "license": "MIT", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/mdast": "^4.0.2", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/types/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@docusaurus/utils": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.10.0.tgz", + "integrity": "sha512-T3B0WTigsIthe0D4LQa2k+7bJY+c3WS+Wq2JhcznOSpn1lSN64yNtHQXboCj3QnUs1EuAZszQG1SHKu5w5ZrlA==", + "license": "MIT", + "dependencies": { + "@docusaurus/logger": "3.10.0", + "@docusaurus/types": "3.10.0", + "@docusaurus/utils-common": "3.10.0", + "escape-string-regexp": "^4.0.0", + "execa": "^5.1.1", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "p-queue": "^6.6.2", + "prompts": "^2.4.2", + "resolve-pathname": "^3.0.0", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/utils-common": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.10.0.tgz", + "integrity": "sha512-JyL7sb9QVDgYvudIS81Dv0lsWm7le0vGZSDwsztxWam1SPBqrnkvBy9UYL/amh6pbybkyYTd3CMTkO24oMlCSw==", + "license": "MIT", + "dependencies": { + "@docusaurus/types": "3.10.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/utils-validation": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.10.0.tgz", + "integrity": "sha512-c+6n2+ZPOJtWWc8Bb/EYdpSDfjYEScdCu9fB/SNjOmSCf1IdVnGf2T53o0tsz0gDRtCL90tifTL0JE/oMuP1Mw==", + "license": "MIT", + "dependencies": { + "@docusaurus/logger": "3.10.0", + "@docusaurus/utils": "3.10.0", + "@docusaurus/utils-common": "3.10.0", + "fs-extra": "^11.2.0", + "joi": "^17.9.2", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/buffers": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-17.67.0.tgz", + "integrity": "sha512-tfExRpYxBvi32vPs9ZHaTjSP4fHAfzSmcahOfNxtvGHcyJel+aibkPlGeBB+7AoC6hL7lXIE++8okecBxx7lcw==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/codegen": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-1.0.0.tgz", + "integrity": "sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-core": { + "version": "4.57.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-core/-/fs-core-4.57.2.tgz", + "integrity": "sha512-SVjwklkpIV5wrynpYtuYnfYH1QF4/nDuLBX7VXdb+3miglcAgBVZb/5y0cOsehRV/9Vb+3UqhkMq3/NR3ztdkQ==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-node-builtins": "4.57.2", + "@jsonjoy.com/fs-node-utils": "4.57.2", + "thingies": "^2.5.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-fsa": { + "version": "4.57.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-fsa/-/fs-fsa-4.57.2.tgz", + "integrity": "sha512-fhO8+iR2I+OCw668ISDJdn1aArc9zx033sWejIyzQ8RBeXa9bDSaUeA3ix0poYOfrj1KdOzytmYNv2/uLDfV6g==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-core": "4.57.2", + "@jsonjoy.com/fs-node-builtins": "4.57.2", + "@jsonjoy.com/fs-node-utils": "4.57.2", + "thingies": "^2.5.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node": { + "version": "4.57.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node/-/fs-node-4.57.2.tgz", + "integrity": "sha512-nX2AdL6cOFwLdju9G4/nbRnYevmCJbh7N7hvR3gGm97Cs60uEjyd0rpR+YBS7cTg175zzl22pGKXR5USaQMvKg==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-core": "4.57.2", + "@jsonjoy.com/fs-node-builtins": "4.57.2", + "@jsonjoy.com/fs-node-utils": "4.57.2", + "@jsonjoy.com/fs-print": "4.57.2", + "@jsonjoy.com/fs-snapshot": "4.57.2", + "glob-to-regex.js": "^1.0.0", + "thingies": "^2.5.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node-builtins": { + "version": "4.57.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-builtins/-/fs-node-builtins-4.57.2.tgz", + "integrity": "sha512-xhiegylRmhw43Ki2HO1ZBL7DQ5ja/qpRsL29VtQ2xuUHiuDGbgf2uD4p9Qd8hJI5P6RCtGYD50IXHXVq/Ocjcg==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node-to-fsa": { + "version": "4.57.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-to-fsa/-/fs-node-to-fsa-4.57.2.tgz", + "integrity": "sha512-18LmWTSONhoAPW+IWRuf8w/+zRolPFGPeGwMxlAhhfY11EKzX+5XHDBPAw67dBF5dxDErHJbl40U+3IXSDRXSQ==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-fsa": "4.57.2", + "@jsonjoy.com/fs-node-builtins": "4.57.2", + "@jsonjoy.com/fs-node-utils": "4.57.2" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node-utils": { + "version": "4.57.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-utils/-/fs-node-utils-4.57.2.tgz", + "integrity": "sha512-rsPSJgekz43IlNbLyAM/Ab+ouYLWGp5DDBfYBNNEqDaSpsbXfthBn29Q4muFA9L0F+Z3mKo+CWlgSCXrf+mOyQ==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-node-builtins": "4.57.2" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-print": { + "version": "4.57.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-print/-/fs-print-4.57.2.tgz", + "integrity": "sha512-wK9NSow48i4DbDl9F1CQE5TqnyZOJ04elU3WFG5aJ76p+YxO/ulyBBQvKsessPxdo381Bc2pcEoyPujMOhcRqQ==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-node-utils": "4.57.2", + "tree-dump": "^1.1.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot": { + "version": "4.57.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-snapshot/-/fs-snapshot-4.57.2.tgz", + "integrity": "sha512-GdduDZuoP5V/QCgJkx9+BZ6SC0EZ/smXAdTS7PfMqgMTGXLlt/bH/FqMYaqB9JmLf05sJPtO0XRbAwwkEEPbVw==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/buffers": "^17.65.0", + "@jsonjoy.com/fs-node-utils": "4.57.2", + "@jsonjoy.com/json-pack": "^17.65.0", + "@jsonjoy.com/util": "^17.65.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/base64": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-17.67.0.tgz", + "integrity": "sha512-5SEsJGsm15aP8TQGkDfJvz9axgPwAEm98S5DxOuYe8e1EbfajcDmgeXXzccEjh+mLnjqEKrkBdjHWS5vFNwDdw==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/codegen": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-17.67.0.tgz", + "integrity": "sha512-idnkUplROpdBOV0HMcwhsCUS5TRUi9poagdGs70A6S4ux9+/aPuKbh8+UYRTLYQHtXvAdNfQWXDqZEx5k4Dj2Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pack": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-17.67.0.tgz", + "integrity": "sha512-t0ejURcGaZsn1ClbJ/3kFqSOjlryd92eQY465IYrezsXmPcfHPE/av4twRSxf6WE+TkZgLY+71vCZbiIiFKA/w==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/base64": "17.67.0", + "@jsonjoy.com/buffers": "17.67.0", + "@jsonjoy.com/codegen": "17.67.0", + "@jsonjoy.com/json-pointer": "17.67.0", + "@jsonjoy.com/util": "17.67.0", + "hyperdyperid": "^1.2.0", + "thingies": "^2.5.0", + "tree-dump": "^1.1.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pointer": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-17.67.0.tgz", + "integrity": "sha512-+iqOFInH+QZGmSuaybBUNdh7yvNrXvqR+h3wjXm0N/3JK1EyyFAeGJvqnmQL61d1ARLlk/wJdFKSL+LHJ1eaUA==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/util": "17.67.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/util": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-17.67.0.tgz", + "integrity": "sha512-6+8xBaz1rLSohlGh68D1pdw3AwDi9xydm8QNlAFkvnavCJYSze+pxoW2VKP8p308jtlMRLs5NTHfPlZLd4w7ew==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/buffers": "17.67.0", + "@jsonjoy.com/codegen": "17.67.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.21.0.tgz", + "integrity": "sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/base64": "^1.1.2", + "@jsonjoy.com/buffers": "^1.2.0", + "@jsonjoy.com/codegen": "^1.0.0", + "@jsonjoy.com/json-pointer": "^1.0.2", + "@jsonjoy.com/util": "^1.9.0", + "hyperdyperid": "^1.2.0", + "thingies": "^2.5.0", + "tree-dump": "^1.1.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack/node_modules/@jsonjoy.com/buffers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz", + "integrity": "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pointer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-1.0.2.tgz", + "integrity": "sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/codegen": "^1.0.0", + "@jsonjoy.com/util": "^1.9.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.9.0.tgz", + "integrity": "sha512-pLuQo+VPRnN8hfPqUTLTHk126wuYdXVxE6aDmjSeV4NCAgyxWbiOIeNJVtID3h1Vzpoi9m4jXezf73I6LgabgQ==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/buffers": "^1.0.0", + "@jsonjoy.com/codegen": "^1.0.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util/node_modules/@jsonjoy.com/buffers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz", + "integrity": "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "license": "MIT" + }, + "node_modules/@mdx-js/mdx": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.1.tgz", + "integrity": "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "acorn": "^8.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-scope": "^1.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "recma-build-jsx": "^1.0.0", + "recma-jsx": "^1.0.0", + "recma-stringify": "^1.0.0", + "rehype-recma": "^1.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/react": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.1.tgz", + "integrity": "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==", + "license": "MIT", + "dependencies": { + "@types/mdx": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@peculiar/asn1-cms": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.6.1.tgz", + "integrity": "sha512-vdG4fBF6Lkirkcl53q6eOdn3XYKt+kJTG59edgRZORlg/3atWWEReRCx5rYE1ZzTTX6vLK5zDMjHh7vbrcXGtw==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-x509-attr": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-csr": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.6.1.tgz", + "integrity": "sha512-WRWnKfIocHyzFYQTka8O/tXCiBquAPSrRjXbOkHbO4qdmS6loffCEGs+rby6WxxGdJCuunnhS2duHURhjyio6w==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-ecc": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.6.1.tgz", + "integrity": "sha512-+Vqw8WFxrtDIN5ehUdvlN2m73exS2JVG0UAyfVB31gIfor3zWEAQPD+K9ydCxaj3MLen9k0JhKpu9LqviuCE1g==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-pfx": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.6.1.tgz", + "integrity": "sha512-nB5jVQy3MAAWvq0KY0R2JUZG8bO/bTLpnwyOzXyEh/e54ynGTatAR+csOnXkkVD9AFZ2uL8Z7EV918+qB1qDvw==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-cms": "^2.6.1", + "@peculiar/asn1-pkcs8": "^2.6.1", + "@peculiar/asn1-rsa": "^2.6.1", + "@peculiar/asn1-schema": "^2.6.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-pkcs8": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.6.1.tgz", + "integrity": "sha512-JB5iQ9Izn5yGMw3ZG4Nw3Xn/hb/G38GYF3lf7WmJb8JZUydhVGEjK/ZlFSWhnlB7K/4oqEs8HnfFIKklhR58Tw==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-pkcs9": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.6.1.tgz", + "integrity": "sha512-5EV8nZoMSxeWmcxWmmcolg22ojZRgJg+Y9MX2fnE2bGRo5KQLqV5IL9kdSQDZxlHz95tHvIq9F//bvL1OeNILw==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-cms": "^2.6.1", + "@peculiar/asn1-pfx": "^2.6.1", + "@peculiar/asn1-pkcs8": "^2.6.1", + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-x509-attr": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-rsa": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.6.1.tgz", + "integrity": "sha512-1nVMEh46SElUt5CB3RUTV4EG/z7iYc7EoaDY5ECwganibQPkZ/Y2eMsTKB/LeyrUJ+W/tKoD9WUqIy8vB+CEdA==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-schema": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.6.0.tgz", + "integrity": "sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==", + "license": "MIT", + "dependencies": { + "asn1js": "^3.0.6", + "pvtsutils": "^1.3.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-x509": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.6.1.tgz", + "integrity": "sha512-O9jT5F1A2+t3r7C4VT7LYGXqkGLK7Kj1xFpz7U0isPrubwU5PbDoyYtx6MiGst29yq7pXN5vZbQFKRCP+lLZlA==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "asn1js": "^3.0.6", + "pvtsutils": "^1.3.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-x509-attr": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.6.1.tgz", + "integrity": "sha512-tlW6cxoHwgcQghnJwv3YS+9OO1737zgPogZ+CgWRUK4roEwIPzRH4JEiG770xe5HX2ATfCpmX60gurfWIF9dcQ==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/x509": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.3.tgz", + "integrity": "sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-cms": "^2.6.0", + "@peculiar/asn1-csr": "^2.6.0", + "@peculiar/asn1-ecc": "^2.6.0", + "@peculiar/asn1-pkcs9": "^2.6.0", + "@peculiar/asn1-rsa": "^2.6.0", + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.0", + "pvtsutils": "^1.3.6", + "reflect-metadata": "^0.2.2", + "tslib": "^2.8.1", + "tsyringe": "^4.10.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "license": "MIT", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "license": "MIT", + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "license": "ISC" + }, + "node_modules/@pnpm/npm-conf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-3.0.2.tgz", + "integrity": "sha512-h104Kh26rR8tm+a3Qkc5S4VLYint3FE48as7+/5oCEcKR2idC/pF1G6AhIXKI+eHPJa/3J9i5z0Al47IeGHPkA==", + "license": "MIT", + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "license": "MIT" + }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "license": "BSD-3-Clause" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.10", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", + "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", + "license": "MIT" + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@slorber/remark-comment": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@slorber/remark-comment/-/remark-comment-1.0.0.tgz", + "integrity": "sha512-RCE24n7jsOj1M0UPvIQCHTe7fI0sFL4S2nwKVWwHyVr/wI/H8GosgsJGyhnsZoGFnD/P2hLf1mSbrrgSLN93NA==", + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.1.0", + "micromark-util-symbol": "^1.0.1" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", + "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", + "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", + "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", + "license": "MIT", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.21.3", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/plugin-svgo": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", + "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", + "license": "MIT", + "dependencies": { + "cosmiconfig": "^8.1.3", + "deepmerge": "^4.3.1", + "svgo": "^3.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/webpack": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", + "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@babel/plugin-transform-react-constant-elements": "^7.21.3", + "@babel/preset-env": "^7.20.2", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.21.0", + "@svgr/core": "8.1.0", + "@svgr/plugin-jsx": "8.1.0", + "@svgr/plugin-svgo": "8.1.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "license": "MIT", + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", + "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "^1" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.8", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.8.tgz", + "integrity": "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/gtag.js": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@types/gtag.js/-/gtag.js-0.0.20.tgz", + "integrity": "sha512-wwAbk3SA2QeU67unN7zPxjEHmPmlXwZXZvQEpbEUQuMCRGgKyE1m6XDuTUA9b6pCGb/GqJmdfMOY5LuDjJSbbg==", + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", + "license": "MIT" + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "license": "MIT" + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==", + "license": "MIT" + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "license": "MIT" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.17", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.17.tgz", + "integrity": "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.19.0" + } + }, + "node_modules/@types/prismjs": { + "version": "1.26.6", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.6.tgz", + "integrity": "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==", + "license": "MIT" + }, + "node_modules/@types/qs": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.0.tgz", + "integrity": "sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==", + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "license": "MIT", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-config": { + "version": "5.0.11", + "resolved": "https://registry.npmjs.org/@types/react-router-config/-/react-router-config-5.0.11.tgz", + "integrity": "sha512-WmSAg7WgqW7m4x8Mt4N6ZyKz0BubSj/2tVUMsAHp+Yd2AMwcSbeFq9WympT19p5heCFmF97R9eD5uUR/t4HEqw==", + "license": "MIT", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "^5.1.0" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "license": "MIT", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", + "license": "MIT" + }, + "node_modules/@types/sax": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", + "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", + "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "license": "Apache-2.0" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/algoliasearch": { + "version": "5.50.2", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.50.2.tgz", + "integrity": "sha512-Tfp26yoNWurUjfgK4GOrVJQhSNXu9tJtHfFFNosgT2YClG+vPyUjX/gbC8rG39qLncnZg8Fj34iarQWpMkqefw==", + "license": "MIT", + "dependencies": { + "@algolia/abtesting": "1.16.2", + "@algolia/client-abtesting": "5.50.2", + "@algolia/client-analytics": "5.50.2", + "@algolia/client-common": "5.50.2", + "@algolia/client-insights": "5.50.2", + "@algolia/client-personalization": "5.50.2", + "@algolia/client-query-suggestions": "5.50.2", + "@algolia/client-search": "5.50.2", + "@algolia/ingestion": "1.50.2", + "@algolia/monitoring": "1.50.2", + "@algolia/recommend": "5.50.2", + "@algolia/requester-browser-xhr": "5.50.2", + "@algolia/requester-fetch": "5.50.2", + "@algolia/requester-node-http": "5.50.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/algoliasearch-helper": { + "version": "3.28.1", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.28.1.tgz", + "integrity": "sha512-6iXpbkkrAI5HFpCWXlNmIDSBuoN/U1XnEvb2yJAoWfqrZ+DrybI7MQ5P5mthFaprmocq+zbi6HxnR28xnZAYBw==", + "license": "MIT", + "dependencies": { + "@algolia/events": "^4.0.1" + }, + "peerDependencies": { + "algoliasearch": ">= 3.1 < 6" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansis": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-3.17.0.tgz", + "integrity": "sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg==", + "license": "ISC", + "engines": { + "node": ">=14" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/asn1js": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.9.tgz", + "integrity": "sha512-g35Ef4IMkE3mDaMAYd3GOJ/c41LKcaiJuuLZ9BF0EXkZwYc0tkFpmZqxWsKlmXS3Um42dAkyx//kibIETBjfqg==", + "license": "BSD-3-Clause", + "dependencies": { + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.5", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/astring": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", + "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", + "license": "MIT", + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/autoprefixer": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", + "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.2", + "caniuse-lite": "^1.0.30001787", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/babel-loader": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz", + "integrity": "sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==", + "license": "MIT", + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "license": "MIT", + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", + "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-define-polyfill-provider": "^0.6.8", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz", + "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.20", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.20.tgz", + "integrity": "sha512-1AaXxEPfXT+GvTBJFuy4yXVHWJBXa4OdbIebGN/wX5DlsIkU0+wzGnd2lOzokSk51d5LUmqjgBLRLlypLUqInQ==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "license": "MIT" + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/bonjour-service": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz", + "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, + "node_modules/boxen": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-6.2.1.tgz", + "integrity": "sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==", + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^6.2.0", + "chalk": "^4.1.2", + "cli-boxes": "^3.0.0", + "string-width": "^5.0.1", + "type-fest": "^2.5.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bytestreamjs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bytestreamjs/-/bytestreamjs-2.0.1.tgz", + "integrity": "sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "license": "MIT", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "license": "MIT", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001788", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001788.tgz", + "integrity": "sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "license": "MIT", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "license": "MIT", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-table3/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/cli-table3/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/collapse-white-space": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT" + }, + "node_modules/combine-promises": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/combine-promises/-/combine-promises-1.2.0.tgz", + "integrity": "sha512-VcQB1ziGD0NXrhKxiwyNbCDmRzs/OShMs2GqW2DlU2A/Sd0nQxE1oWDAE5O0ygSx5mgQOn9eIFh7yKPgFRVkPQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "license": "ISC" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compressible/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "license": "MIT", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/config-chain/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, + "node_modules/configstore": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz", + "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==", + "license": "BSD-2-Clause", + "dependencies": { + "dot-prop": "^6.0.1", + "graceful-fs": "^4.2.6", + "unique-string": "^3.0.0", + "write-file-atomic": "^3.0.3", + "xdg-basedir": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/yeoman/configstore?sponsor=1" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, + "node_modules/copy-text-to-clipboard": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.2.tgz", + "integrity": "sha512-T6SqyLd1iLuqPA90J5N4cTalrtovCySh58iiZDGJ6FGznbclKh4UI+FGacQSgFzwKG77W7XT5gwbVEbd9cIH1A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "license": "MIT", + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "license": "MIT", + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/core-js": { + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.49.0.tgz", + "integrity": "sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", + "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "license": "MIT", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "license": "MIT", + "dependencies": { + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/css-blank-pseudo": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-7.0.1.tgz", + "integrity": "sha512-jf+twWGDf6LDoXDUode+nc7ZlrqfaNphrBIBrcmeP3D8yw1uPaix1gCC8LUQUGQ6CycuK2opkbFFWFuq/a94ag==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-blank-pseudo/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/css-declaration-sorter": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.4.0.tgz", + "integrity": "sha512-LTuzjPoyA2vMGKKcaOqKSp7Ub2eGrNfKiZH4LpezxpNrsICGCSFvsQOI29psISxNZtaXibkC2CXzrQ5enMeGGw==", + "license": "ISC", + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-has-pseudo": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-7.0.3.tgz", + "integrity": "sha512-oG+vKuGyqe/xvEMoxAQrhi7uY16deJR3i7wwhBerVrGQKSqUC5GiOVxTpM9F9B9hw0J+eKeOWLH7E9gZ1Dr5rA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-has-pseudo/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/css-has-pseudo/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/css-loader": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "license": "MIT", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-minimizer-webpack-plugin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-5.0.1.tgz", + "integrity": "sha512-3caImjKFQkS+ws1TGcFn0V1HyDJFq1Euy589JlD6/3rV2kj+w7r5G9WDMgSHvpvXHNZ2calVypZWuEDQd9wfLg==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "cssnano": "^6.0.1", + "jest-worker": "^29.4.3", + "postcss": "^8.4.24", + "schema-utils": "^4.0.1", + "serialize-javascript": "^6.0.1" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@parcel/css": { + "optional": true + }, + "@swc/css": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "lightningcss": { + "optional": true + } + } + }, + "node_modules/css-prefers-color-scheme": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-10.0.0.tgz", + "integrity": "sha512-VCtXZAWivRglTZditUfB4StnsWr6YVZ2PRtuxQLKTNRdtAf8tpzaVPE9zXIF3VaSc7O70iK/j1+NXxyQCqdPjQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssdb": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-8.8.0.tgz", + "integrity": "sha512-QbLeyz2Bgso1iRlh7IpWk6OKa3lLNGXsujVjDMPl9rOZpxKeiG69icLpbLCFxeURwmcdIfZqQyhlooKJYM4f8Q==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + } + ], + "license": "MIT-0" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.1.2.tgz", + "integrity": "sha512-rYk5UeX7VAM/u0lNqewCdasdtPK81CgX8wJFLEIXHbV2oldWRgJAsZrdhRXkV1NJzA2g850KiFm9mMU2HxNxMA==", + "license": "MIT", + "dependencies": { + "cssnano-preset-default": "^6.1.2", + "lilconfig": "^3.1.1" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-preset-advanced": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-6.1.2.tgz", + "integrity": "sha512-Nhao7eD8ph2DoHolEzQs5CfRpiEP0xa1HBdnFZ82kvqdmbwVBUr2r1QuQ4t1pi+D1ZpqpcO4T+wy/7RxzJ/WPQ==", + "license": "MIT", + "dependencies": { + "autoprefixer": "^10.4.19", + "browserslist": "^4.23.0", + "cssnano-preset-default": "^6.1.2", + "postcss-discard-unused": "^6.0.5", + "postcss-merge-idents": "^6.0.3", + "postcss-reduce-idents": "^6.0.3", + "postcss-zindex": "^6.0.2" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-preset-default": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.1.2.tgz", + "integrity": "sha512-1C0C+eNaeN8OcHQa193aRgYexyJtU8XwbdieEjClw+J9d94E41LwT6ivKH0WT+fYwYWB0Zp3I3IZ7tI/BbUbrg==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "css-declaration-sorter": "^7.2.0", + "cssnano-utils": "^4.0.2", + "postcss-calc": "^9.0.1", + "postcss-colormin": "^6.1.0", + "postcss-convert-values": "^6.1.0", + "postcss-discard-comments": "^6.0.2", + "postcss-discard-duplicates": "^6.0.3", + "postcss-discard-empty": "^6.0.3", + "postcss-discard-overridden": "^6.0.2", + "postcss-merge-longhand": "^6.0.5", + "postcss-merge-rules": "^6.1.1", + "postcss-minify-font-values": "^6.1.0", + "postcss-minify-gradients": "^6.0.3", + "postcss-minify-params": "^6.1.0", + "postcss-minify-selectors": "^6.0.4", + "postcss-normalize-charset": "^6.0.2", + "postcss-normalize-display-values": "^6.0.2", + "postcss-normalize-positions": "^6.0.2", + "postcss-normalize-repeat-style": "^6.0.2", + "postcss-normalize-string": "^6.0.2", + "postcss-normalize-timing-functions": "^6.0.2", + "postcss-normalize-unicode": "^6.1.0", + "postcss-normalize-url": "^6.0.2", + "postcss-normalize-whitespace": "^6.0.2", + "postcss-ordered-values": "^6.0.2", + "postcss-reduce-initial": "^6.1.0", + "postcss-reduce-transforms": "^6.0.2", + "postcss-svgo": "^6.0.3", + "postcss-unique-selectors": "^6.0.4" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-utils": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.2.tgz", + "integrity": "sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "license": "MIT", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "license": "CC0-1.0" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-browser": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", + "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "license": "MIT" + }, + "node_modules/detect-port": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.6.1.tgz", + "integrity": "sha512-CmnVc+Hek2egPx1PeTFVta2W78xy2K/9Rkf6cC4T59S50tVnzKj+tnx5mmx5lwvCkujZ4uRrpRSuV+IVs3f90Q==", + "license": "MIT", + "dependencies": { + "address": "^1.0.1", + "debug": "4" + }, + "bin": { + "detect": "bin/detect-port.js", + "detect-port": "bin/detect-port.js" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "license": "MIT", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "license": "MIT", + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dot-prop/node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "license": "MIT" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.340", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.340.tgz", + "integrity": "sha512-908qahOGocRMinT2nM3ajCEM99H4iPdv84eagPP3FfZy/1ZGeOy2CZYzjhms81ckOPCXPlW7LkY4XpxD8r1DrA==", + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/emojilib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==", + "license": "MIT" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/emoticon": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-4.1.0.tgz", + "integrity": "sha512-VWZfnxqwNcc51hIy/sbOdEem6D+cVtpPzEEtVAFdaas30+1dgkyaOQ4sQ6Bp0tOMqWO1v+HQfYaoodOkdhK6SQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz", + "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esast-util-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", + "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esast-util-from-js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz", + "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "acorn": "^8.0.0", + "esast-util-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", + "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-attach-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-scope": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz", + "integrity": "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-value-to-estree": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/estree-util-value-to-estree/-/estree-util-value-to-estree-3.5.0.tgz", + "integrity": "sha512-aMV56R27Gv3QmfmF1MY12GWkGzzeAezAX+UplqHVASfjc9wNzI/X6hC0S9oxq61WT4aQesLGslWP9tKk6ghRZQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/remcohaszing" + } + }, + "node_modules/estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eta": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eta/-/eta-2.2.0.tgz", + "integrity": "sha512-UVQ72Rqjy/ZKQalzV5dCCJP80GrmPrMxh6NlNf+erV6ObL0ZFkhCstWRawS85z3smdr3d2wXPsZEY7rDPfGd2g==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "url": "https://github.com/eta-dev/eta?sponsor=1" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eval": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eval/-/eval-0.1.8.tgz", + "integrity": "sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==", + "dependencies": { + "@types/node": "*", + "require-like": ">= 0.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.14.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/express/node_modules/path-to-regexp": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "license": "MIT" + }, + "node_modules/express/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fault": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", + "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", + "license": "MIT", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "license": "Apache-2.0", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/feed": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", + "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", + "license": "MIT", + "dependencies": { + "xml-js": "^1.6.11" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/file-loader/node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/file-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/file-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/file-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "license": "MIT", + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "license": "MIT", + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "license": "MIT", + "engines": { + "node": ">= 14.17" + } + }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "11.3.4", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", + "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", + "license": "ISC" + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/github-slugger": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.5.0.tgz", + "integrity": "sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==", + "license": "ISC" + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regex.js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/glob-to-regex.js/-/glob-to-regex.js-1.2.0.tgz", + "integrity": "sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "license": "BSD-2-Clause" + }, + "node_modules/global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "license": "MIT", + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/got/node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "license": "MIT", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "license": "MIT", + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-yarn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", + "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hasown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", + "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-estree": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz", + "integrity": "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.1.tgz", + "integrity": "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "license": "MIT" + }, + "node_modules/html-minifier-terser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", + "license": "MIT", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.15.1" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.7", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.7.tgz", + "integrity": "sha512-md+vXtdCAe60s1k6AU3dUyMJnDxUyQAwfwPKoLisvgUF1IXjtlLsk2se54+qfL9Mdm26bbwvjJybpNx48NKRLw==", + "license": "MIT", + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/html-webpack-plugin/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-webpack-plugin/node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "license": "MIT", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "license": "BSD-2-Clause" + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", + "license": "MIT" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", + "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", + "license": "MIT", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "license": "MIT", + "engines": { + "node": ">=10.18" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-size": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-2.0.2.tgz", + "integrity": "sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w==", + "license": "MIT", + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/infima": { + "version": "0.2.0-alpha.45", + "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.45.tgz", + "integrity": "sha512-uyH0zfr1erU1OohLk0fT4Rrb94AOhguWNOcD9uGrSpRvNB+6gZXUoJX5J0NtvzBO10YZ9PgvA4NFgt+fYg8ojw==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/inline-style-parser": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", + "license": "MIT" + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz", + "integrity": "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "license": "MIT", + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container/node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "license": "MIT", + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-network-error": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.1.tgz", + "integrity": "sha512-6QCxa49rQbmUWLfk0nuGqzql9U8uaV2H6279bRErPBHe/109hCzsLUBUHfbEtvLIHBd6hyXbgedBSHevm43Edw==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-npm": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.1.0.tgz", + "integrity": "sha512-O2z4/kNgyjhQwVR1Wpkbfc19JIhggF97NZNCpWTnjH7kVcZMUrnut9XSN7txI7VdyIYk5ZatOq3zvSuWpU8hoA==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "license": "MIT" + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-yarn-global": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz", + "integrity": "sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/joi": { + "version": "17.13.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", + "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/latest-version": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", + "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", + "license": "MIT", + "dependencies": { + "package-json": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/launch-editor": { + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.13.2.tgz", + "integrity": "sha512-4VVDnbOpLXy/s8rdRCSXb+zfMeFR0WlJWpET1iA9CQdlZDfwyLjUuGQzXU4VeOoey6AicSAluWan7Etga6Kcmg==", + "license": "MIT", + "dependencies": { + "picocolors": "^1.1.1", + "shell-quote": "^1.8.3" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/loader-runner": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", + "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", + "license": "MIT", + "engines": { + "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "license": "MIT", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "license": "MIT" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/markdown-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-directive": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.1.0.tgz", + "integrity": "sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", + "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/mdast-util-frontmatter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", + "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "escape-string-regexp": "^5.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-frontmatter/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "license": "CC0-1.0" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "4.57.2", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.57.2.tgz", + "integrity": "sha512-2nWzSsJzrukurSDna4Z0WywuScK4Id3tSKejgu74u8KCdW4uNrseKRSIDg75C6Yw5ZRqBe0F0EtMNlTbUq8bAQ==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-core": "4.57.2", + "@jsonjoy.com/fs-fsa": "4.57.2", + "@jsonjoy.com/fs-node": "4.57.2", + "@jsonjoy.com/fs-node-builtins": "4.57.2", + "@jsonjoy.com/fs-node-to-fsa": "4.57.2", + "@jsonjoy.com/fs-node-utils": "4.57.2", + "@jsonjoy.com/fs-print": "4.57.2", + "@jsonjoy.com/fs-snapshot": "4.57.2", + "@jsonjoy.com/json-pack": "^1.11.0", + "@jsonjoy.com/util": "^1.9.0", + "glob-to-regex.js": "^1.0.1", + "thingies": "^2.5.0", + "tree-dump": "^1.0.3", + "tslib": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-directive": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-3.0.2.tgz", + "integrity": "sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "parse-entities": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-directive/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-directive/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-directive/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-frontmatter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", + "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", + "license": "MIT", + "dependencies": { + "fault": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-frontmatter/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-frontmatter/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz", + "integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz", + "integrity": "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", + "license": "MIT", + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz", + "integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-space": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz", + "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-space/node_modules/micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-character": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz", + "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-character/node_modules/micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz", + "integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-util-events-to-acorn/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-normalize-identifier/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-symbol": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz", + "integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "license": "MIT", + "dependencies": { + "mime-db": "~1.33.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.10.2.tgz", + "integrity": "sha512-AOSS0IdEB95ayVkxn5oGzNQwqAi2J0Jb/kKm43t7H73s8+f5873g0yuj0PNvK4dO75mu5DHg4nlgp4k6Kga8eg==", + "license": "MIT", + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "license": "MIT", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "license": "MIT", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-emoji": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.2.0.tgz", + "integrity": "sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "char-regex": "^1.0.2", + "emojilib": "^2.4.0", + "skin-tone": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/node-releases": { + "version": "2.0.37", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", + "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==", + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.1.tgz", + "integrity": "sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==", + "license": "MIT" + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/null-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/null-loader/-/null-loader-4.0.1.tgz", + "integrity": "sha512-pxqVbi4U6N26lq+LmgIbB5XATP0VdZKOG25DhHi8btMmJJefGArFyDg1yc4U3hWCJbMqSrw0qyrz1UQX+qYXqg==", + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/null-loader/node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/null-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/null-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/null-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "license": "(WTFPL OR MIT)", + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "license": "MIT", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", + "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "license": "MIT", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", + "license": "MIT", + "dependencies": { + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-numeric-range": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", + "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==", + "license": "ISC" + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", + "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", + "license": "MIT", + "dependencies": { + "domhandler": "^5.0.3", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "license": "(WTFPL OR MIT)" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.9.0.tgz", + "integrity": "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==", + "license": "MIT", + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "license": "MIT", + "dependencies": { + "find-up": "^6.3.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkijs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.4.0.tgz", + "integrity": "sha512-emEcLuomt2j03vxD54giVB4SxTjnsqkU692xZOZXHDVoYyypEm+b3jpiTcc+Cf+myooc+/Ly0z01jqeNHVgJGw==", + "license": "BSD-3-Clause", + "dependencies": { + "@noble/hashes": "1.4.0", + "asn1js": "^3.0.6", + "bytestreamjs": "^2.0.1", + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/postcss": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", + "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-attribute-case-insensitive": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-7.0.1.tgz", + "integrity": "sha512-Uai+SupNSqzlschRyNx3kbCTWgY/2hcwtHEI/ej2LJWc9JJ77qKgGptd8DHwY1mXtZ7Aoh4z4yxfwMBue9eNgw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-attribute-case-insensitive/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-calc": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", + "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-clamp": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", + "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=7.6.0" + }, + "peerDependencies": { + "postcss": "^8.4.6" + } + }, + "node_modules/postcss-color-functional-notation": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-7.0.12.tgz", + "integrity": "sha512-TLCW9fN5kvO/u38/uesdpbx3e8AkTYhMvDZYa9JpmImWuTE99bDQ7GU7hdOADIZsiI9/zuxfAJxny/khknp1Zw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-hex-alpha": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-10.0.0.tgz", + "integrity": "sha512-1kervM2cnlgPs2a8Vt/Qbe5cQ++N7rkYo/2rz2BkqJZIHQwaVuJgQH38REHrAi4uM0b1fqxMkWYmese94iMp3w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-rebeccapurple": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-10.0.0.tgz", + "integrity": "sha512-JFta737jSP+hdAIEhk1Vs0q0YF5P8fFcj+09pweS8ktuGuZ8pPlykHsk6mPxZ8awDl4TrcxUqJo9l1IhVr/OjQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-colormin": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.1.0.tgz", + "integrity": "sha512-x9yX7DOxeMAR+BgGVnNSAxmAj98NX/YxEMNFP+SDCEeNLb2r3i6Hh1ksMsnW8Ub5SLCpbescQqn9YEbE9554Sw==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0", + "colord": "^2.9.3", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-convert-values": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.1.0.tgz", + "integrity": "sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-custom-media": { + "version": "11.0.6", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-11.0.6.tgz", + "integrity": "sha512-C4lD4b7mUIw+RZhtY7qUbf4eADmb7Ey8BFA2px9jUbwg7pjTZDl4KY4bvlUV+/vXQvzQRfiGEVJyAbtOsCMInw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/cascade-layer-name-parser": "^2.0.5", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/media-query-list-parser": "^4.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-properties": { + "version": "14.0.6", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-14.0.6.tgz", + "integrity": "sha512-fTYSp3xuk4BUeVhxCSJdIPhDLpJfNakZKoiTDx7yRGCdlZrSJR7mWKVOBS4sBF+5poPQFMj2YdXx1VHItBGihQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/cascade-layer-name-parser": "^2.0.5", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-selectors": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-8.0.5.tgz", + "integrity": "sha512-9PGmckHQswiB2usSO6XMSswO2yFWVoCAuih1yl9FVcwkscLjRKjwsjM3t+NIWpSU2Jx3eOiK2+t4vVTQaoCHHg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/cascade-layer-name-parser": "^2.0.5", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-selectors/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-dir-pseudo-class": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-9.0.1.tgz", + "integrity": "sha512-tRBEK0MHYvcMUrAuYMEOa0zg9APqirBcgzi6P21OhxtJyJADo/SWBwY1CAwEohQ/6HDaa9jCjLRG7K3PVQYHEA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-dir-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-discard-comments": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.2.tgz", + "integrity": "sha512-65w/uIqhSBBfQmYnG92FO1mWZjJ4GL5b8atm5Yw2UgrwD7HiNiSSNwJor1eCFGzUgYnN/iIknhNRVqjrrpuglw==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.3.tgz", + "integrity": "sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-empty": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.3.tgz", + "integrity": "sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.2.tgz", + "integrity": "sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-unused": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-6.0.5.tgz", + "integrity": "sha512-wHalBlRHkaNnNwfC8z+ppX57VhvS+HWgjW508esjdaEYr3Mx7Gnn2xA4R/CKf5+Z9S5qsqC+Uzh4ueENWwCVUA==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-double-position-gradients": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-6.0.4.tgz", + "integrity": "sha512-m6IKmxo7FxSP5nF2l63QbCC3r+bWpFUWmZXZf096WxG0m7Vl1Q1+ruFOhpdDRmKrRS+S3Jtk+TVk/7z0+BVK6g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-visible": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-10.0.1.tgz", + "integrity": "sha512-U58wyjS/I1GZgjRok33aE8juW9qQgQUNwTSdxQGuShHzwuYdcklnvK/+qOWX1Q9kr7ysbraQ6ht6r+udansalA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-visible/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-focus-within": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-9.0.1.tgz", + "integrity": "sha512-fzNUyS1yOYa7mOjpci/bR+u+ESvdar6hk8XNK/TRR0fiGTp2QT5N+ducP0n3rfH/m9I7H/EQU6lsa2BrgxkEjw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-within/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-font-variant": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "license": "MIT", + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-gap-properties": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-6.0.0.tgz", + "integrity": "sha512-Om0WPjEwiM9Ru+VhfEDPZJAKWUd0mV1HmNXqp2C29z80aQ2uP9UVhLc7e3aYMIor/S5cVhoPgYQ7RtfeZpYTRw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-image-set-function": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-7.0.0.tgz", + "integrity": "sha512-QL7W7QNlZuzOwBTeXEmbVckNt1FSmhQtbMRvGGqqU4Nf4xk6KUEQhAoWuMzwbSv5jxiRiSZ5Tv7eiDB9U87znA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-lab-function": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-7.0.12.tgz", + "integrity": "sha512-tUcyRk1ZTPec3OuKFsqtRzW2Go5lehW29XA21lZ65XmzQkz43VY2tyWEC202F7W3mILOjw0voOiuxRGTsN+J9w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-loader": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.4.tgz", + "integrity": "sha512-iW5WTTBSC5BfsBJ9daFMPVrLT36MrNiC6fqOZTTaHjBNX6Pfd5p+hSBqe/fEeNd7pc13QiAyGt7VdGMw4eRC4A==", + "license": "MIT", + "dependencies": { + "cosmiconfig": "^8.3.5", + "jiti": "^1.20.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-logical": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-8.1.0.tgz", + "integrity": "sha512-pL1hXFQ2fEXNKiNiAgtfA005T9FBxky5zkX6s4GZM2D8RkVgRqz3f4g1JUoq925zXv495qk8UNldDwh8uGEDoA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-merge-idents": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-6.0.3.tgz", + "integrity": "sha512-1oIoAsODUs6IHQZkLQGO15uGEbK3EAl5wi9SS8hs45VgsxQfMnxvt+L+zIr7ifZFIH14cfAeVe2uCTa+SPRa3g==", + "license": "MIT", + "dependencies": { + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.5.tgz", + "integrity": "sha512-5LOiordeTfi64QhICp07nzzuTDjNSO8g5Ksdibt44d+uvIIAE1oZdRn8y/W5ZtYgRH/lnLDlvi9F8btZcVzu3w==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^6.1.1" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-merge-rules": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.1.1.tgz", + "integrity": "sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^4.0.2", + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.1.0.tgz", + "integrity": "sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.3.tgz", + "integrity": "sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q==", + "license": "MIT", + "dependencies": { + "colord": "^2.9.3", + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-params": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.1.0.tgz", + "integrity": "sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.4.tgz", + "integrity": "sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", + "license": "MIT", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "license": "ISC", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-nesting": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-13.0.2.tgz", + "integrity": "sha512-1YCI290TX+VP0U/K/aFxzHzQWHWURL+CtHMSbex1lCdpXD1SoR2sYuxDu5aNI9lPoXpKTCggFZiDJbwylU0LEQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-resolve-nested": "^3.1.0", + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-nesting/node_modules/@csstools/selector-resolve-nested": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-resolve-nested/-/selector-resolve-nested-3.1.0.tgz", + "integrity": "sha512-mf1LEW0tJLKfWyvn5KdDrhpxHyuxpbNwTIwOYLIvsTffeyOf85j5oIzfG0yosxDgx/sswlqBnESYUcQH0vgZ0g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/postcss-nesting/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/postcss-nesting/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.2.tgz", + "integrity": "sha512-a8N9czmdnrjPHa3DeFlwqst5eaL5W8jYu3EBbTTkI5FHkfMhFZh1EGbku6jhHhIzTA6tquI2P42NtZ59M/H/kQ==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.2.tgz", + "integrity": "sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.2.tgz", + "integrity": "sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.2.tgz", + "integrity": "sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-string": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.2.tgz", + "integrity": "sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.2.tgz", + "integrity": "sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.1.0.tgz", + "integrity": "sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-url": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.2.tgz", + "integrity": "sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.2.tgz", + "integrity": "sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-opacity-percentage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-3.0.0.tgz", + "integrity": "sha512-K6HGVzyxUxd/VgZdX04DCtdwWJ4NGLG212US4/LA1TLAbHgmAsTWVR86o+gGIbFtnTkfOpb9sCRBx8K7HO66qQ==", + "funding": [ + { + "type": "kofi", + "url": "https://ko-fi.com/mrcgrtz" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/mrcgrtz" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-ordered-values": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.2.tgz", + "integrity": "sha512-VRZSOB+JU32RsEAQrO94QPkClGPKJEL/Z9PCBImXMhIeK5KAYo6slP/hBYlLgrCjFxyqvn5VC81tycFEDBLG1Q==", + "license": "MIT", + "dependencies": { + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-overflow-shorthand": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-6.0.0.tgz", + "integrity": "sha512-BdDl/AbVkDjoTofzDQnwDdm/Ym6oS9KgmO7Gr+LHYjNWJ6ExORe4+3pcLQsLA9gIROMkiGVjjwZNoL/mpXHd5Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-page-break": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "license": "MIT", + "peerDependencies": { + "postcss": "^8" + } + }, + "node_modules/postcss-place": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-10.0.0.tgz", + "integrity": "sha512-5EBrMzat2pPAxQNWYavwAfoKfYcTADJ8AXGVPcUZ2UkNloUTWzJQExgrzrDkh3EKzmAx1evfTAzF9I8NGcc+qw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-preset-env": { + "version": "10.6.1", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-10.6.1.tgz", + "integrity": "sha512-yrk74d9EvY+W7+lO9Aj1QmjWY9q5NsKjK2V9drkOPZB/X6KZ0B3igKsHUYakb7oYVhnioWypQX3xGuePf89f3g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/postcss-alpha-function": "^1.0.1", + "@csstools/postcss-cascade-layers": "^5.0.2", + "@csstools/postcss-color-function": "^4.0.12", + "@csstools/postcss-color-function-display-p3-linear": "^1.0.1", + "@csstools/postcss-color-mix-function": "^3.0.12", + "@csstools/postcss-color-mix-variadic-function-arguments": "^1.0.2", + "@csstools/postcss-content-alt-text": "^2.0.8", + "@csstools/postcss-contrast-color-function": "^2.0.12", + "@csstools/postcss-exponential-functions": "^2.0.9", + "@csstools/postcss-font-format-keywords": "^4.0.0", + "@csstools/postcss-gamut-mapping": "^2.0.11", + "@csstools/postcss-gradients-interpolation-method": "^5.0.12", + "@csstools/postcss-hwb-function": "^4.0.12", + "@csstools/postcss-ic-unit": "^4.0.4", + "@csstools/postcss-initial": "^2.0.1", + "@csstools/postcss-is-pseudo-class": "^5.0.3", + "@csstools/postcss-light-dark-function": "^2.0.11", + "@csstools/postcss-logical-float-and-clear": "^3.0.0", + "@csstools/postcss-logical-overflow": "^2.0.0", + "@csstools/postcss-logical-overscroll-behavior": "^2.0.0", + "@csstools/postcss-logical-resize": "^3.0.0", + "@csstools/postcss-logical-viewport-units": "^3.0.4", + "@csstools/postcss-media-minmax": "^2.0.9", + "@csstools/postcss-media-queries-aspect-ratio-number-values": "^3.0.5", + "@csstools/postcss-nested-calc": "^4.0.0", + "@csstools/postcss-normalize-display-values": "^4.0.1", + "@csstools/postcss-oklab-function": "^4.0.12", + "@csstools/postcss-position-area-property": "^1.0.0", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/postcss-property-rule-prelude-list": "^1.0.0", + "@csstools/postcss-random-function": "^2.0.1", + "@csstools/postcss-relative-color-syntax": "^3.0.12", + "@csstools/postcss-scope-pseudo-class": "^4.0.1", + "@csstools/postcss-sign-functions": "^1.1.4", + "@csstools/postcss-stepped-value-functions": "^4.0.9", + "@csstools/postcss-syntax-descriptor-syntax-production": "^1.0.1", + "@csstools/postcss-system-ui-font-family": "^1.0.0", + "@csstools/postcss-text-decoration-shorthand": "^4.0.3", + "@csstools/postcss-trigonometric-functions": "^4.0.9", + "@csstools/postcss-unset-value": "^4.0.0", + "autoprefixer": "^10.4.23", + "browserslist": "^4.28.1", + "css-blank-pseudo": "^7.0.1", + "css-has-pseudo": "^7.0.3", + "css-prefers-color-scheme": "^10.0.0", + "cssdb": "^8.6.0", + "postcss-attribute-case-insensitive": "^7.0.1", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^7.0.12", + "postcss-color-hex-alpha": "^10.0.0", + "postcss-color-rebeccapurple": "^10.0.0", + "postcss-custom-media": "^11.0.6", + "postcss-custom-properties": "^14.0.6", + "postcss-custom-selectors": "^8.0.5", + "postcss-dir-pseudo-class": "^9.0.1", + "postcss-double-position-gradients": "^6.0.4", + "postcss-focus-visible": "^10.0.1", + "postcss-focus-within": "^9.0.1", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^6.0.0", + "postcss-image-set-function": "^7.0.0", + "postcss-lab-function": "^7.0.12", + "postcss-logical": "^8.1.0", + "postcss-nesting": "^13.0.2", + "postcss-opacity-percentage": "^3.0.0", + "postcss-overflow-shorthand": "^6.0.0", + "postcss-page-break": "^3.0.4", + "postcss-place": "^10.0.0", + "postcss-pseudo-class-any-link": "^10.0.1", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^8.0.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-pseudo-class-any-link": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-10.0.1.tgz", + "integrity": "sha512-3el9rXlBOqTFaMFkWDOkHUTQekFIYnaQY55Rsp8As8QQkpiSgIYEcF/6Ond93oHiDsGb4kad8zjt+NPlOC1H0Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-pseudo-class-any-link/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-reduce-idents": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-6.0.3.tgz", + "integrity": "sha512-G3yCqZDpsNPoQgbDUy3T0E6hqOQ5xigUtBQyrmq3tn2GxlyiL0yyl7H+T8ulQR6kOcHJ9t7/9H4/R2tv8tJbMA==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.1.0.tgz", + "integrity": "sha512-RarLgBK/CrL1qZags04oKbVbrrVK2wcxhvta3GCxrZO4zveibqbRPmm2VI8sSgCXwoUHEliRSbOfpR0b/VIoiw==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.2.tgz", + "integrity": "sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-replace-overflow-wrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "license": "MIT", + "peerDependencies": { + "postcss": "^8.0.3" + } + }, + "node_modules/postcss-selector-not": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-8.0.1.tgz", + "integrity": "sha512-kmVy/5PYVb2UOhy0+LqUYAhKj7DUGDpSWa5LZqlkWJaaAV+dxxsOG3+St0yNLu6vsKD7Dmqx+nWQt0iil89+WA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-selector-not/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-sort-media-queries": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-5.2.0.tgz", + "integrity": "sha512-AZ5fDMLD8SldlAYlvi8NIqo0+Z8xnXU2ia0jxmuhxAU+Lqt9K+AlmLNJ/zWEnE9x+Zx3qL3+1K20ATgNOr3fAA==", + "license": "MIT", + "dependencies": { + "sort-css-media-queries": "2.2.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.4.23" + } + }, + "node_modules/postcss-svgo": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.3.tgz", + "integrity": "sha512-dlrahRmxP22bX6iKEjOM+c8/1p+81asjKT+V5lrgOH944ryx/OHpclnIbGsKVd3uWOXFLYJwCVf0eEkJGvO96g==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^3.2.0" + }, + "engines": { + "node": "^14 || ^16 || >= 18" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.4.tgz", + "integrity": "sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/postcss-zindex": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-6.0.2.tgz", + "integrity": "sha512-5BxW9l1evPB/4ZIc+2GobEBoKC+h8gPGCMi+jxsYvd2x0mjq7wazk6DrP71pStqxE9Foxh5TVnonbWpFZzXaYg==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", + "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/prism-react-renderer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.4.1.tgz", + "integrity": "sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig==", + "license": "MIT", + "dependencies": { + "@types/prismjs": "^1.26.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.0.0" + } + }, + "node_modules/prism-react-renderer/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "license": "ISC" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pupa": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.3.0.tgz", + "integrity": "sha512-LjgDO2zPtoXP2wJpDjZrGdojii1uqO0cnwKoIoUzkfS98HDmbeiGmYiXo3lXeFlq2xvne1QFQhwYXSUCLKtEuA==", + "license": "MIT", + "dependencies": { + "escape-goat": "^4.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pvtsutils": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/pvutils": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz", + "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/qs": { + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==", + "license": "MIT" + }, + "node_modules/react-helmet-async": { + "name": "@slorber/react-helmet-async", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@slorber/react-helmet-async/-/react-helmet-async-1.3.0.tgz", + "integrity": "sha512-e9/OK8VhwUSc67diWI8Rb3I0YgI9/SBQtnhe9aEuK6MhZm7ntZZimXgwXnd8W96YTmSOb9M4d8LwhRZyhWr/1A==", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.12.5", + "invariant": "^2.2.4", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.2.0", + "shallowequal": "^1.1.0" + }, + "peerDependencies": { + "react": "^16.6.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-json-view-lite": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/react-json-view-lite/-/react-json-view-lite-2.5.0.tgz", + "integrity": "sha512-tk7o7QG9oYyELWHL8xiMQ8x4WzjCzbWNyig3uexmkLb54r8jO0yH3WCWx8UZS0c49eSA4QUmG5caiRJ8fAn58g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-loadable": { + "name": "@docusaurus/react-loadable", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz", + "integrity": "sha512-YMMxTUQV/QFSnbgrP3tjDzLHRg7vsbMn8e9HAa8o/1iXoiomo48b7sk/kkmWEuWNDPJVlKSJRB6Y2fHqdJk+SQ==", + "license": "MIT", + "dependencies": { + "@types/react": "*" + }, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-loadable-ssr-addon-v5-slorber": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.3.tgz", + "integrity": "sha512-GXfh9VLwB5ERaCsU6RULh7tkemeX15aNh6wuMEBtfdyMa7fFG8TXrhXlx1SoEK2Ty/l6XIkzzYIQmyaWW3JgdQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.3" + }, + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "react-loadable": "*", + "webpack": ">=4.41.1 || 5.x" + } + }, + "node_modules/react-router": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", + "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/react-router-config": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/react-router-config/-/react-router-config-5.1.1.tgz", + "integrity": "sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.1.2" + }, + "peerDependencies": { + "react": ">=15", + "react-router": ">=5" + } + }, + "node_modules/react-router-dom": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz", + "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.3.4", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/recma-build-jsx": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz", + "integrity": "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-jsx": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.1.tgz", + "integrity": "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==", + "license": "MIT", + "dependencies": { + "acorn-jsx": "^5.0.0", + "estree-util-to-js": "^2.0.0", + "recma-parse": "^1.0.0", + "recma-stringify": "^1.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/recma-parse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-parse/-/recma-parse-1.0.0.tgz", + "integrity": "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "esast-util-from-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-stringify/-/recma-stringify-1.0.0.tgz", + "integrity": "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-to-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "license": "Apache-2.0" + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/registry-auth-token": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.1.1.tgz", + "integrity": "sha512-P7B4+jq8DeD2nMsAcdfaqHbssgHtZ7Z5+++a5ask90fvmJ8p5je4mOa+wzu+DB4vQ5tdJV/xywY+UnVFeQLV5Q==", + "license": "MIT", + "dependencies": { + "@pnpm/npm-conf": "^3.0.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "license": "MIT", + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.1.tgz", + "integrity": "sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw==", + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-recma": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz", + "integrity": "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "hast-util-to-estree": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remark-directive": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/remark-directive/-/remark-directive-3.0.1.tgz", + "integrity": "sha512-gwglrEQEZcZYgVyG1tQuA+h58EZfq5CSULw7J90AFuCTyib1thgHPoqQ+h9iFvU6R+vnZ5oNFQR5QKgGpk741A==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-directive": "^3.0.0", + "micromark-extension-directive": "^3.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-emoji": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-4.0.1.tgz", + "integrity": "sha512-fHdvsTR1dHkWKev9eNyhTo4EFwbUvJ8ka9SgeWkMPYFX4WoI7ViVBms3PjlQYgw5TLvNQso3GUB/b/8t3yo+dg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.2", + "emoticon": "^4.0.1", + "mdast-util-find-and-replace": "^3.0.1", + "node-emoji": "^2.1.0", + "unified": "^11.0.4" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/remark-frontmatter": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-5.0.0.tgz", + "integrity": "sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-frontmatter": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.1.tgz", + "integrity": "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==", + "license": "MIT", + "dependencies": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "license": "MIT", + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/renderkid/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/renderkid/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-like": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", + "integrity": "sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==", + "engines": { + "node": "*" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "license": "MIT" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==", + "license": "MIT" + }, + "node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "license": "MIT", + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rtlcss": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.3.0.tgz", + "integrity": "sha512-FI+pHEn7Wc4NqKXMXFM+VAYKEj/mRIcW4h24YVwVtyjI+EqGrLc2Hx/Ny0lrZ21cBWU2goLy36eqMcNj3AQJig==", + "license": "MIT", + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0", + "postcss": "^8.4.21", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "rtlcss": "bin/rtlcss.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-dts": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/schema-dts/-/schema-dts-1.1.5.tgz", + "integrity": "sha512-RJr9EaCmsLzBX2NDiO5Z3ux2BVosNZN5jo0gWgsyKvxKIUL5R3swNvoorulAeL9kLB0iTSX7V6aokhla2m7xbg==", + "license": "Apache-2.0" + }, + "node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/search-insights": { + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", + "license": "MIT", + "peer": true + }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "license": "MIT" + }, + "node_modules/selfsigned": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-5.5.0.tgz", + "integrity": "sha512-ftnu3TW4+3eBfLRFnDEkzGxSF/10BJBkaLJuBHZX0kiPS7bRdlpZGu6YGt4KngMkdTwJE6MbjavFpqHvqVt+Ew==", + "license": "MIT", + "dependencies": { + "@peculiar/x509": "^1.14.2", + "pkijs": "^3.3.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", + "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serialize-javascript": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.5.tgz", + "integrity": "sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/serve-handler": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.7.tgz", + "integrity": "sha512-CinAq1xWb0vR3twAv9evEU8cNWkXCb9kd5ePAHUKJBkOsUpR1wt/CvGdeca7vqumL1U5cSaeVQ6zZMxiJ3yWsg==", + "license": "MIT", + "dependencies": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "mime-types": "2.1.18", + "minimatch": "3.1.5", + "path-is-inside": "1.0.2", + "path-to-regexp": "3.3.0", + "range-parser": "1.2.0" + } + }, + "node_modules/serve-handler/node_modules/path-to-regexp": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", + "integrity": "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==", + "license": "MIT" + }, + "node_modules/serve-index": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.2.tgz", + "integrity": "sha512-KDj11HScOaLmrPxl70KYNW1PksP4Nb/CLL2yvC+Qd2kHMPEEpfc4Re2e4FOay+bC/+XQl/7zAcWON3JVo5v3KQ==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.8.0", + "mime-types": "~2.1.35", + "parseurl": "~1.3.3" + }, + "engines": { + "node": ">= 0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "license": "MIT", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, + "node_modules/sitemap": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-7.1.3.tgz", + "integrity": "sha512-tAjEd+wt/YwnEbfNB2ht51ybBJxbEWwe5ki/Z//Wh0rpBFTCUSj46GnxUKEWzhfuJTsee8x3lybHxFgUMig2hw==", + "license": "MIT", + "dependencies": { + "@types/node": "^17.0.5", + "@types/sax": "^1.2.1", + "arg": "^5.0.0", + "sax": "^1.2.4" + }, + "bin": { + "sitemap": "dist/cli.js" + }, + "engines": { + "node": ">=12.0.0", + "npm": ">=5.6.0" + } + }, + "node_modules/sitemap/node_modules/@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", + "license": "MIT" + }, + "node_modules/skin-tone": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", + "license": "MIT", + "dependencies": { + "unicode-emoji-modifier-base": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "license": "MIT", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/sort-css-media-queries": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.2.0.tgz", + "integrity": "sha512-0xtkGhWCC9MGt/EzgnvbbbKhqWjl1+/rncmhTh5qCpbYguXh6S/qwePfv/JQ8jePXXmqingylxoC49pCkSPIbA==", + "license": "MIT", + "engines": { + "node": ">= 6.3.0" + } + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/srcset": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz", + "integrity": "sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "license": "BSD-2-Clause", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-to-js": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", + "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.14" + } + }, + "node_modules/style-to-object": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", + "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.7" + } + }, + "node_modules/stylehacks": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.1.1.tgz", + "integrity": "sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "license": "MIT" + }, + "node_modules/svgo": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.3.tgz", + "integrity": "sha512-+wn7I4p7YgJhHs38k2TNjy1vCfPIfLIJWR5MnCStsN8WuuTcBnRKcMHQLMM2ijxGZmDoZwNv8ipl5aTTen62ng==", + "license": "MIT", + "dependencies": { + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0", + "sax": "^1.5.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/tapable": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.2.tgz", + "integrity": "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.1.tgz", + "integrity": "sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==", + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.4.0.tgz", + "integrity": "sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "terser": "^5.31.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/thingies": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.6.0.tgz", + "integrity": "sha512-rMHRjmlFLM1R96UYPvpmnc3LYtdFrT33JIB7L9hetGue1qAPfn1N2LJeEjxUSidu1Iku+haLZXDuEXUHNGO/lg==", + "license": "MIT", + "engines": { + "node": ">=10.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "^2" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "license": "MIT" + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", + "license": "MIT" + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tree-dump": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.1.0.tgz", + "integrity": "sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsyringe": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.10.0.tgz", + "integrity": "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==", + "license": "MIT", + "dependencies": { + "tslib": "^1.9.3" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/tsyringe/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/undici-types": { + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", + "license": "MIT" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-emoji-modifier-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", + "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "license": "MIT", + "dependencies": { + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/update-notifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz", + "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==", + "license": "BSD-2-Clause", + "dependencies": { + "boxen": "^7.0.0", + "chalk": "^5.0.1", + "configstore": "^6.0.0", + "has-yarn": "^3.0.0", + "import-lazy": "^4.0.0", + "is-ci": "^3.0.1", + "is-installed-globally": "^0.4.0", + "is-npm": "^6.0.0", + "is-yarn-global": "^0.4.0", + "latest-version": "^7.0.0", + "pupa": "^3.1.0", + "semver": "^7.3.7", + "semver-diff": "^4.0.0", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/boxen": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", + "integrity": "sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==", + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-notifier/node_modules/camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-notifier/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "file-loader": "*", + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "file-loader": { + "optional": true + } + } + }, + "node_modules/url-loader/node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/url-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/url-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/url-loader/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/url-loader/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/url-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "license": "MIT" + }, + "node_modules/utility-types": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", + "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==", + "license": "MIT" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/watchpack": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "license": "MIT", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/webpack": { + "version": "5.106.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.106.2.tgz", + "integrity": "sha512-wGN3qcrBQIFmQ/c0AiOAQBvrZ5lmY8vbbMv4Mxfgzqd/B6+9pXtLo73WuS1dSGXM5QYY3hZnIbvx+K1xxe6FyA==", + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.16.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.20.0", + "es-module-lexer": "^2.0.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "loader-runner": "^4.3.1", + "mime-db": "^1.54.0", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.17", + "watchpack": "^2.5.1", + "webpack-sources": "^3.3.4" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz", + "integrity": "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==", + "license": "MIT", + "dependencies": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", + "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", + "opener": "^1.5.2", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.5.tgz", + "integrity": "sha512-uxQ6YqGdE4hgDKNf7hUiPXOdtkXvBJXrfEGYSx7P7LC8hnUYGK70X6xQXUvXeNyBDDcsiQXpG2m3G9vxowaEuA==", + "license": "MIT", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^4.43.1", + "mime-types": "^3.0.1", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/webpack-dev-middleware/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-server": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.3.tgz", + "integrity": "sha512-9Gyu2F7+bg4Vv+pjbovuYDhHX+mqdqITykfzdM9UyKqKHlsE5aAjRhR+oOEfXW5vBeu8tarzlJFIZva4ZjAdrQ==", + "license": "MIT", + "dependencies": { + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.25", + "@types/express-serve-static-core": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", + "colorette": "^2.0.10", + "compression": "^1.8.1", + "connect-history-api-fallback": "^2.0.0", + "express": "^4.22.1", + "graceful-fs": "^4.2.6", + "http-proxy-middleware": "^2.0.9", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "schema-utils": "^4.2.0", + "selfsigned": "^5.5.0", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^7.4.2", + "ws": "^8.18.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webpack-dev-server/node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.4.tgz", + "integrity": "sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpackbar": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-7.0.0.tgz", + "integrity": "sha512-aS9soqSO2iCHgqHoCrj4LbfGQUboDCYJPSFOAchEK+9psIjNrfSWW4Y0YEz67MKURNvMmfo0ycOg9d/+OOf9/Q==", + "license": "MIT", + "dependencies": { + "ansis": "^3.2.0", + "consola": "^3.2.3", + "pretty-time": "^1.1.0", + "std-env": "^3.7.0" + }, + "engines": { + "node": ">=14.21.3" + }, + "peerDependencies": { + "@rspack/core": "*", + "webpack": "3 || 4 || 5" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "license": "Apache-2.0", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "license": "MIT", + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wsl-utils/node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "license": "MIT", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/api-docs/package.json b/api-docs/package.json new file mode 100644 index 000000000..5c9483c7e --- /dev/null +++ b/api-docs/package.json @@ -0,0 +1,56 @@ +{ + "name": "api-docs", + "version": "0.0.0", + "private": true, + "scripts": { + "docusaurus": "docusaurus", + "start": "docusaurus start", + "build": "docusaurus build", + "swizzle": "docusaurus swizzle", + "deploy": "docusaurus deploy", + "clear": "docusaurus clear", + "serve": "docusaurus serve", + "write-translations": "docusaurus write-translations", + "write-heading-ids": "docusaurus write-heading-ids" + }, + "dependencies": { + "@docusaurus/core": "3.10.0", + "@docusaurus/preset-classic": "3.10.0", + "@mdx-js/react": "^3.0.1", + "clsx": "^1.2.1", + "prism-react-renderer": "^2.3.1", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@docusaurus/module-type-aliases": "3.10.0", + "@docusaurus/types": "3.10.0" + }, + "overrides": { + "serialize-javascript": "^6.0.2 || ^7.0.3", + "lodash": "^4.17.21", + "webpackbar": "^7.0.0" + }, + "browserslist": { + "production": [ + ">0.5%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 3 chrome version", + "last 3 firefox version", + "last 5 safari version" + ] + }, + "engines": { + "node": ">=18.0" + }, + "description": "This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator.", + "main": "babel.config.js", + "directories": { + "doc": "docs" + }, + "author": "", + "license": "ISC" +} diff --git a/api-docs/sidebars.js b/api-docs/sidebars.js new file mode 100644 index 000000000..c1ca6072d --- /dev/null +++ b/api-docs/sidebars.js @@ -0,0 +1,8 @@ +// @ts-check + +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const sidebars = { + tutorialSidebar: [{ type: 'autogenerated', dirName: '.' }], +}; + +export default sidebars; diff --git a/api-docs/src/css/custom.css b/api-docs/src/css/custom.css new file mode 100644 index 000000000..2bc6a4cfd --- /dev/null +++ b/api-docs/src/css/custom.css @@ -0,0 +1,30 @@ +/** + * Any CSS included here will be global. The classic template + * bundles Infima by default. Infima is a CSS framework designed to + * work well for content-centric websites. + */ + +/* You can override the default Infima variables here. */ +:root { + --ifm-color-primary: #2e8555; + --ifm-color-primary-dark: #29784c; + --ifm-color-primary-darker: #277148; + --ifm-color-primary-darkest: #205d3b; + --ifm-color-primary-light: #33925d; + --ifm-color-primary-lighter: #359962; + --ifm-color-primary-lightest: #3cad6e; + --ifm-code-font-size: 95%; + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); +} + +/* For readability concerns, you should choose a lighter palette in dark mode. */ +[data-theme='dark'] { + --ifm-color-primary: #25c2a0; + --ifm-color-primary-dark: #21af90; + --ifm-color-primary-darker: #1fa588; + --ifm-color-primary-darkest: #1a8870; + --ifm-color-primary-light: #29d5b0; + --ifm-color-primary-lighter: #32d8b4; + --ifm-color-primary-lightest: #4fddbf; + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); +} diff --git a/api-docs/src/pages/index.module.css b/api-docs/src/pages/index.module.css new file mode 100644 index 000000000..9f71a5da7 --- /dev/null +++ b/api-docs/src/pages/index.module.css @@ -0,0 +1,23 @@ +/** + * CSS files with the .module.css suffix will be treated as CSS modules + * and scoped locally. + */ + +.heroBanner { + padding: 4rem 0; + text-align: center; + position: relative; + overflow: hidden; +} + +@media screen and (max-width: 996px) { + .heroBanner { + padding: 2rem; + } +} + +.buttons { + display: flex; + align-items: center; + justify-content: center; +} diff --git a/api-docs/src/pages/index.tsx b/api-docs/src/pages/index.tsx new file mode 100644 index 000000000..8925295d8 --- /dev/null +++ b/api-docs/src/pages/index.tsx @@ -0,0 +1,6 @@ +import React from 'react'; +import { Redirect } from '@docusaurus/router'; + +export default function HomeRedirect() { + return ; +} diff --git a/api-docs/static/.nojekyll b/api-docs/static/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/api-docs/static/img/favicon.ico b/api-docs/static/img/favicon.ico new file mode 100644 index 000000000..a0e01c17c Binary files /dev/null and b/api-docs/static/img/favicon.ico differ diff --git a/aws.sample.json b/aws.sample.json deleted file mode 100644 index 6045e257a..000000000 --- a/aws.sample.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "key": "ADD HERE", - "secret": "ADD HERE", - "bucket": "ADD HERE", - "region": "ADD HERE", - "distribution": "ADD HERE" -} diff --git a/banner.js b/banner.js new file mode 100644 index 000000000..fd394f25d --- /dev/null +++ b/banner.js @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import license from 'rollup-plugin-license'; + +const mainCopyright = 'Copyright 2022 Snowplow Analytics Ltd, 2010 Anthon Pang'; +const snowplowCopyright = 'Copyright 2022 Snowplow Analytics Ltd'; + +const bannerContent = (snowplowOnlyCopyright) => `<%= pkg.description %> v<%= pkg.version %> (<%= pkg.homepage %>) +${snowplowOnlyCopyright ? snowplowCopyright : mainCopyright} +Licensed under <%= pkg.license %>`; + +export const banner = (snowplowOnlyCopyright = false) => + license({ + sourcemap: true, + banner: { + content: bannerContent(snowplowOnlyCopyright), + commentStyle: 'ignored', + }, + }); diff --git a/common/autoinstallers/rush-prettier/.npmrc b/common/autoinstallers/rush-prettier/.npmrc new file mode 100644 index 000000000..b902e270c --- /dev/null +++ b/common/autoinstallers/rush-prettier/.npmrc @@ -0,0 +1,22 @@ +# Rush uses this file to configure the NPM package registry during installation. It is applicable +# to PNPM, NPM, and Yarn package managers. It is used by operations such as "rush install", +# "rush update", and the "install-run.js" scripts. +# +# NOTE: The "rush publish" command uses .npmrc-publish instead. +# +# Before invoking the package manager, Rush will copy this file to the folder where installation +# is performed. The copied file will omit any config lines that reference environment variables +# that are undefined in that session; this avoids problems that would otherwise result due to +# a missing variable being replaced by an empty string. +# +# * * * SECURITY WARNING * * * +# +# It is NOT recommended to store authentication tokens in a text file on a lab machine, because +# other unrelated processes may be able to read the file. Also, the file may persist indefinitely, +# for example if the machine loses power. A safer practice is to pass the token via an +# environment variable, which can be referenced from .npmrc using ${} expansion. For example: +# +# //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN} +# +registry=https://registry.npmjs.org/ +always-auth=false diff --git a/common/autoinstallers/rush-prettier/package.json b/common/autoinstallers/rush-prettier/package.json new file mode 100644 index 000000000..bcd2c466b --- /dev/null +++ b/common/autoinstallers/rush-prettier/package.json @@ -0,0 +1,9 @@ +{ + "name": "rush-prettier", + "version": "1.0.0", + "private": true, + "dependencies": { + "prettier": "^2.5.1", + "pretty-quick": "^3.1.3" + } +} diff --git a/common/autoinstallers/rush-prettier/pnpm-lock.yaml b/common/autoinstallers/rush-prettier/pnpm-lock.yaml new file mode 100644 index 000000000..430c80350 --- /dev/null +++ b/common/autoinstallers/rush-prettier/pnpm-lock.yaml @@ -0,0 +1,263 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + prettier: + specifier: ^2.5.1 + version: 2.8.8 + pretty-quick: + specifier: ^3.1.3 + version: 3.3.1(prettier@2.8.8) + +packages: + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + execa@4.1.0: + resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==} + engines: {node: '>=10'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + + human-signals@1.1.1: + resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} + engines: {node: '>=8.12.0'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@3.0.2: + resolution: {integrity: sha512-cfDHL6LStTEKlNilboNtobT/kEa30PtAf2Q1OgszfrG/rpVl1xaFWT9ktfkS306GmHgmnad1Sw4wabhlvFtsTw==} + engines: {node: '>=10'} + + prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + + pretty-quick@3.3.1: + resolution: {integrity: sha512-3b36UXfYQ+IXXqex6mCca89jC8u0mYLqFAN5eTQKoXO6oCQYcIVYZEB/5AlBHI7JPYygReM2Vv6Vom/Gln7fBg==} + engines: {node: '>=10.13'} + hasBin: true + peerDependencies: + prettier: ^2.0.0 + + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + +snapshots: + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + execa@4.1.0: + dependencies: + cross-spawn: 7.0.6 + get-stream: 5.2.0 + human-signals: 1.1.1 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + get-stream@5.2.0: + dependencies: + pump: 3.0.4 + + human-signals@1.1.1: {} + + ignore@5.3.2: {} + + is-stream@2.0.1: {} + + isexe@2.0.0: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + merge-stream@2.0.0: {} + + mimic-fn@2.1.0: {} + + mri@1.2.0: {} + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-try@2.2.0: {} + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + picocolors@1.1.1: {} + + picomatch@3.0.2: {} + + prettier@2.8.8: {} + + pretty-quick@3.3.1(prettier@2.8.8): + dependencies: + execa: 4.1.0 + find-up: 4.1.0 + ignore: 5.3.2 + mri: 1.2.0 + picocolors: 1.1.1 + picomatch: 3.0.2 + prettier: 2.8.8 + tslib: 2.8.1 + + pump@3.0.4: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + signal-exit@3.0.7: {} + + strip-final-newline@2.0.0: {} + + tslib@2.8.1: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wrappy@1.0.2: {} diff --git a/common/changes/@snowplow/browser-plugin-browser-features/feature-revise-default-plugins_2023-02-06-13-02.json b/common/changes/@snowplow/browser-plugin-browser-features/feature-revise-default-plugins_2023-02-06-13-02.json new file mode 100644 index 000000000..41b45477e --- /dev/null +++ b/common/changes/@snowplow/browser-plugin-browser-features/feature-revise-default-plugins_2023-02-06-13-02.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@snowplow/browser-plugin-browser-features", + "comment": "Add deprecation warning", + "type": "none" + } + ], + "packageName": "@snowplow/browser-plugin-browser-features" +} \ No newline at end of file diff --git a/common/changes/@snowplow/browser-plugin-consent/feature-1138-upgrade-uuid_2023-01-10-10-11.json b/common/changes/@snowplow/browser-plugin-consent/feature-1138-upgrade-uuid_2023-01-10-10-11.json new file mode 100644 index 000000000..b92b62a0a --- /dev/null +++ b/common/changes/@snowplow/browser-plugin-consent/feature-1138-upgrade-uuid_2023-01-10-10-11.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@snowplow/browser-plugin-consent", + "comment": "", + "type": "none" + } + ], + "packageName": "@snowplow/browser-plugin-consent" +} \ No newline at end of file diff --git a/common/changes/@snowplow/browser-plugin-consent/feature-revise-default-plugins_2023-02-06-08-43.json b/common/changes/@snowplow/browser-plugin-consent/feature-revise-default-plugins_2023-02-06-08-43.json new file mode 100644 index 000000000..37fb44b58 --- /dev/null +++ b/common/changes/@snowplow/browser-plugin-consent/feature-revise-default-plugins_2023-02-06-08-43.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@snowplow/browser-plugin-consent", + "comment": "Add deprecation warning", + "type": "none" + } + ], + "packageName": "@snowplow/browser-plugin-consent" +} \ No newline at end of file diff --git a/common/changes/@snowplow/browser-plugin-ecommerce/feature-1138-upgrade-uuid_2023-01-10-10-11.json b/common/changes/@snowplow/browser-plugin-ecommerce/feature-1138-upgrade-uuid_2023-01-10-10-11.json new file mode 100644 index 000000000..b5c87e859 --- /dev/null +++ b/common/changes/@snowplow/browser-plugin-ecommerce/feature-1138-upgrade-uuid_2023-01-10-10-11.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@snowplow/browser-plugin-ecommerce", + "comment": "", + "type": "none" + } + ], + "packageName": "@snowplow/browser-plugin-ecommerce" +} \ No newline at end of file diff --git a/common/changes/@snowplow/browser-plugin-ecommerce/feature-revise-default-plugins_2023-02-06-08-43.json b/common/changes/@snowplow/browser-plugin-ecommerce/feature-revise-default-plugins_2023-02-06-08-43.json new file mode 100644 index 000000000..227d2f55d --- /dev/null +++ b/common/changes/@snowplow/browser-plugin-ecommerce/feature-revise-default-plugins_2023-02-06-08-43.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@snowplow/browser-plugin-ecommerce", + "comment": "Add deprecation warning", + "type": "none" + } + ], + "packageName": "@snowplow/browser-plugin-ecommerce" +} \ No newline at end of file diff --git a/common/changes/@snowplow/browser-plugin-optimizely/feature-revise-default-plugins_2023-02-06-13-02.json b/common/changes/@snowplow/browser-plugin-optimizely/feature-revise-default-plugins_2023-02-06-13-02.json new file mode 100644 index 000000000..738929318 --- /dev/null +++ b/common/changes/@snowplow/browser-plugin-optimizely/feature-revise-default-plugins_2023-02-06-13-02.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@snowplow/browser-plugin-optimizely", + "comment": "Add deprecation warning", + "type": "none" + } + ], + "packageName": "@snowplow/browser-plugin-optimizely" +} \ No newline at end of file diff --git a/common/config/rush/.npmrc b/common/config/rush/.npmrc new file mode 100644 index 000000000..c5980e62e --- /dev/null +++ b/common/config/rush/.npmrc @@ -0,0 +1,22 @@ +# Rush uses this file to configure the NPM package registry during installation. It is applicable +# to PNPM, NPM, and Yarn package managers. It is used by operations such as "rush install", +# "rush update", and the "install-run.js" scripts. +# +# NOTE: The "rush publish" command uses .npmrc-publish instead. +# +# Before invoking the package manager, Rush will copy this file to the folder where installation +# is performed. The copied file will omit any config lines that reference environment variables +# that are undefined in that session; this avoids problems that would otherwise result due to +# a missing variable being replaced by an empty string. +# +# * * * SECURITY WARNING * * * +# +# It is NOT recommended to store authentication tokens in a text file on a lab machine, because +# other unrelated processes may be able to read the file. Also, the file may persist indefinitely, +# for example if the machine loses power. A safer practice is to pass the token via an +# environment variable, which can be referenced from .npmrc using ${} expansion. For example: +# +# //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN} +# +registry=https://registry.npmjs.org/ +always-auth=false diff --git a/common/config/rush/.npmrc-publish b/common/config/rush/.npmrc-publish new file mode 100644 index 000000000..5c84bbe5e --- /dev/null +++ b/common/config/rush/.npmrc-publish @@ -0,0 +1,23 @@ +# This config file is very similar to common/config/rush/.npmrc, except that .npmrc-publish +# is used by the "rush publish" command, as publishing often involves different credentials +# and registries than other operations. +# +# Before invoking the package manager, Rush will copy this file to "common/temp/publish-home/.npmrc" +# and then temporarily map that folder as the "home directory" for the current user account. +# This enables the same settings to apply for each project folder that gets published. The copied file +# will omit any config lines that reference environment variables that are undefined in that session; +# this avoids problems that would otherwise result due to a missing variable being replaced by +# an empty string. +# +# * * * SECURITY WARNING * * * +# +# It is NOT recommended to store authentication tokens in a text file on a lab machine, because +# other unrelated processes may be able to read the file. Also, the file may persist indefinitely, +# for example if the machine loses power. A safer practice is to pass the token via an +# environment variable, which can be referenced from .npmrc using ${} expansion. For example: +# +# //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN} +# +registry=https://registry.npmjs.org/ +always-auth=true +//registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN} \ No newline at end of file diff --git a/common/config/rush/.pnpmfile.cjs b/common/config/rush/.pnpmfile.cjs new file mode 100644 index 000000000..94561748f --- /dev/null +++ b/common/config/rush/.pnpmfile.cjs @@ -0,0 +1,38 @@ +'use strict'; + +/** + * When using the PNPM package manager, you can use pnpmfile.js to workaround + * dependencies that have mistakes in their package.json file. (This feature is + * functionally similar to Yarn's "resolutions".) + * + * For details, see the PNPM documentation: + * https://pnpm.js.org/docs/en/hooks.html + * + * IMPORTANT: SINCE THIS FILE CONTAINS EXECUTABLE CODE, MODIFYING IT IS LIKELY TO INVALIDATE + * ANY CACHED DEPENDENCY ANALYSIS. After any modification to pnpmfile.js, it's recommended to run + * "rush update --full" so that PNPM will recalculate all version selections. + */ +module.exports = { + hooks: { + readPackage + } +}; + +/** + * This hook is invoked during installation before a package's dependencies + * are selected. + * The `packageJson` parameter is the deserialized package.json + * contents for the package that is about to be installed. + * The `context` parameter provides a log() function. + * The return value is the updated object. + */ +function readPackage(packageJson, context) { + + // // The karma types have a missing dependency on typings from the log4js package. + // if (packageJson.name === '@types/karma') { + // context.log('Fixed up dependencies for @types/karma'); + // packageJson.dependencies['log4js'] = '0.6.38'; + // } + + return packageJson; +} diff --git a/common/config/rush/browser-approved-packages.json b/common/config/rush/browser-approved-packages.json new file mode 100644 index 000000000..3b15c2084 --- /dev/null +++ b/common/config/rush/browser-approved-packages.json @@ -0,0 +1,486 @@ +// DO NOT ADD COMMENTS IN THIS FILE. They will be lost when the Rush tool resaves it. +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/approved-packages.schema.json", + "packages": [ + { + "name": "@ampproject/rollup-plugin-closure-compiler", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "@fingerprintjs/botd", + "allowedCategories": [ "plugins" ] + }, + { + "name": "@react-native-async-storage/async-storage", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@react-native/babel-preset", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@react-native/eslint-config", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@rollup/plugin-alias", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@rollup/plugin-commonjs", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "@rollup/plugin-json", + "allowedCategories": [ "libraries", "trackers" ] + }, + { + "name": "@rollup/plugin-node-resolve", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "@rollup/plugin-replace", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-ad-tracking", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-bot-detection", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-browser-features", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-button-click-tracking", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-client-hints", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-consent", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-ecommerce", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-element-tracking", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-enhanced-consent", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-enhanced-ecommerce", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-error-tracking", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-event-specifications", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-focalmeter", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-form-tracking", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-ga-cookies", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-geolocation", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-link-click-tracking", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-media", + "allowedCategories": [ "plugins", "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-media-tracking", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-optimizely", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-optimizely-x", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-performance-navigation-timing", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-performance-timing", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-privacy-sandbox", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-screen-tracking", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-site-tracking", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-snowplow-ecommerce", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-timezone", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-vimeo-tracking", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-web-vitals", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-webview", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-plugin-youtube-tracking", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@snowplow/browser-tracker", + "allowedCategories": [ "plugins", "trackers" ] + }, + { + "name": "@snowplow/browser-tracker-core", + "allowedCategories": [ "plugins", "trackers" ] + }, + { + "name": "@snowplow/tracker-core", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "@snowplow/webview-tracker", + "allowedCategories": [ "plugins" ] + }, + { + "name": "@testing-library/dom", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@types/dockerode", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@types/jest", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "@types/jsdom", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "@types/jstimezonedetect", + "allowedCategories": [ "plugins" ] + }, + { + "name": "@types/lodash", + "allowedCategories": [ "plugins", "trackers" ] + }, + { + "name": "@types/node", + "allowedCategories": [ "libraries", "trackers" ] + }, + { + "name": "@types/node-fetch", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@types/randomcolor", + "allowedCategories": [ "plugins" ] + }, + { + "name": "@types/react", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@types/sinon", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@types/uuid", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "@types/vimeo__player", + "allowedCategories": [ "plugins" ] + }, + { + "name": "@types/youtube", + "allowedCategories": [ "plugins", "trackers" ] + }, + { + "name": "@typescript-eslint/eslint-plugin", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "@typescript-eslint/parser", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "@vimeo/player", + "allowedCategories": [ "plugins" ] + }, + { + "name": "@wdio/cli", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@wdio/globals", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@wdio/jasmine-framework", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@wdio/local-runner", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@wdio/sauce-service", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@wdio/shared-store-service", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@wdio/spec-reporter", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@wdio/static-server-service", + "allowedCategories": [ "trackers" ] + }, + { + "name": "@wdio/types", + "allowedCategories": [ "trackers" ] + }, + { + "name": "ava", + "allowedCategories": [ "libraries", "trackers" ] + }, + { + "name": "chalk", + "allowedCategories": [ "trackers" ] + }, + { + "name": "chromedriver", + "allowedCategories": [ "trackers" ] + }, + { + "name": "dockerode", + "allowedCategories": [ "trackers" ] + }, + { + "name": "edgedriver", + "allowedCategories": [ "trackers" ] + }, + { + "name": "eslint", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "eslint-plugin-ava", + "allowedCategories": [ "trackers" ] + }, + { + "name": "got", + "allowedCategories": [ "trackers" ] + }, + { + "name": "jest", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "jest-config", + "allowedCategories": [ "trackers" ] + }, + { + "name": "jest-environment-jsdom", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "jest-environment-jsdom-global", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "jest-environment-node", + "allowedCategories": [ "trackers" ] + }, + { + "name": "jest-expo", + "allowedCategories": [ "trackers" ] + }, + { + "name": "jest-react-native", + "allowedCategories": [ "trackers" ] + }, + { + "name": "jest-standard-reporter", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "jstimezonedetect", + "allowedCategories": [ "plugins" ] + }, + { + "name": "lodash", + "allowedCategories": [ "plugins", "trackers" ] + }, + { + "name": "moment-timezone", + "allowedCategories": [ "plugins" ] + }, + { + "name": "nock", + "allowedCategories": [ "trackers" ] + }, + { + "name": "node-fetch", + "allowedCategories": [ "trackers" ] + }, + { + "name": "npm-run-all", + "allowedCategories": [ "trackers" ] + }, + { + "name": "randomcolor", + "allowedCategories": [ "plugins" ] + }, + { + "name": "react", + "allowedCategories": [ "trackers" ] + }, + { + "name": "react-native", + "allowedCategories": [ "trackers" ] + }, + { + "name": "react-native-builder-bob", + "allowedCategories": [ "trackers" ] + }, + { + "name": "react-native-get-random-values", + "allowedCategories": [ "trackers" ] + }, + { + "name": "rollup", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "rollup-plugin-cleanup", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "rollup-plugin-filesize", + "allowedCategories": [ "trackers" ] + }, + { + "name": "rollup-plugin-license", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "rollup-plugin-sizes", + "allowedCategories": [ "trackers" ] + }, + { + "name": "rollup-plugin-terser", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "rollup-plugin-ts", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "saucelabs", + "allowedCategories": [ "trackers" ] + }, + { + "name": "sinon", + "allowedCategories": [ "trackers" ] + }, + { + "name": "ts-jest", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "ts-node", + "allowedCategories": [ "libraries", "trackers" ] + }, + { + "name": "tslib", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "tsx", + "allowedCategories": [ "trackers" ] + }, + { + "name": "typescript", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "uuid", + "allowedCategories": [ "libraries", "plugins", "trackers" ] + }, + { + "name": "wdio-chromedriver-service", + "allowedCategories": [ "trackers" ] + }, + { + "name": "wdio-edgedriver-service", + "allowedCategories": [ "trackers" ] + }, + { + "name": "wdio-safaridriver-service", + "allowedCategories": [ "trackers" ] + }, + { + "name": "web-vitals", + "allowedCategories": [ "plugins" ] + }, + { + "name": "webdriverio", + "allowedCategories": [ "trackers" ] + }, + { + "name": "whatwg-fetch", + "allowedCategories": [ "libraries", "trackers" ] + } + ] +} diff --git a/common/config/rush/command-line.json b/common/config/rush/command-line.json new file mode 100644 index 000000000..cad1c1787 --- /dev/null +++ b/common/config/rush/command-line.json @@ -0,0 +1,299 @@ +/** + * This configuration file defines custom commands for the "rush" command-line. + * For full documentation, please see https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", + + /** + * Custom "commands" introduce new verbs for the command-line. To see the help for these + * example commands, try "rush --help", "rush my-bulk-command --help", or + * "rush my-global-command --help". + */ + "commands": [ + // { + // /** + // * (Required) Determines the type of custom command. + // * Rush's "bulk" commands are invoked separately for each project. Rush will look in + // * each project's package.json file for a "scripts" entry whose name matches the + // * command name. By default, the command will run for every project in the repo, + // * according to the dependency graph (similar to how "rush build" works). + // * The set of projects can be restricted e.g. using the "--to" or "--from" parameters. + // */ + // "commandKind": "bulk", + // + // /** + // * (Required) The name that will be typed as part of the command line. This is also the name + // * of the "scripts" hook in the project's package.json file. + // * The name should be comprised of lower case words separated by hyphens or colons. The name should include an + // * English verb (e.g. "deploy"). Use a hyphen to separate words (e.g. "upload-docs"). A group of related commands + // * can be prefixed with a colon (e.g. "docs:generate", "docs:deploy", "docs:serve", etc). + // * + // * Note that if the "rebuild" command is overridden here, it becomes separated from the "build" command + // * and will call the "rebuild" script instead of the "build" script. + // */ + // "name": "my-bulk-command", + // + // /** + // * (Required) A short summary of the custom command to be shown when printing command line + // * help, e.g. "rush --help". + // */ + // "summary": "Example bulk custom command", + // + // /** + // * A detailed description of the command to be shown when printing command line + // * help (e.g. "rush --help my-command"). + // * If omitted, the "summary" text will be shown instead. + // * + // * Whenever you introduce commands/parameters, taking a little time to write meaningful + // * documentation can make a big difference for the developer experience in your repo. + // */ + // "description": "This is an example custom command that runs separately for each project", + // + // /** + // * By default, Rush operations acquire a lock file which prevents multiple commands from executing simultaneously + // * in the same repo folder. (For example, it would be a mistake to run "rush install" and "rush build" at the + // * same time.) If your command makes sense to run concurrently with other operations, + // * set "safeForSimultaneousRushProcesses" to true to disable this protection. + // * + // * In particular, this is needed for custom scripts that invoke other Rush commands. + // */ + // "safeForSimultaneousRushProcesses": false, + // + // /** + // * (Required) If true, then this command is safe to be run in parallel, i.e. executed + // * simultaneously for multiple projects. Similar to "rush build", regardless of parallelism + // * projects will not start processing until their dependencies have completed processing. + // */ + // "enableParallelism": false, + // + // /** + // * Normally projects will be processed according to their dependency order: a given project will not start + // * processing the command until all of its dependencies have completed. This restriction doesn't apply for + // * certain operations, for example a "clean" task that deletes output files. In this case + // * you can set "ignoreDependencyOrder" to true to increase parallelism. + // */ + // "ignoreDependencyOrder": false, + // + // /** + // * Normally Rush requires that each project's package.json has a "scripts" entry matching + // * the custom command name. To disable this check, set "ignoreMissingScript" to true; + // * projects with a missing definition will be skipped. + // */ + // "ignoreMissingScript": false, + // + // /** + // * When invoking shell scripts, Rush uses a heuristic to distinguish errors from warnings: + // * - If the shell script returns a nonzero process exit code, Rush interprets this as "one or more errors". + // * Error output is displayed in red, and it prevents Rush from attempting to process any downstream projects. + // * - If the shell script returns a zero process exit code but writes something to its stderr stream, + // * Rush interprets this as "one or more warnings". Warning output is printed in yellow, but does NOT prevent + // * Rush from processing downstream projects. + // * + // * Thus, warnings do not interfere with local development, but they will cause a CI job to fail, because + // * the Rush process itself returns a nonzero exit code if there are any warnings or errors. This is by design. + // * In an active monorepo, we've found that if you allow any warnings in your master branch, it inadvertently + // * teaches developers to ignore warnings, which quickly leads to a situation where so many "expected" warnings + // * have accumulated that warnings no longer serve any useful purpose. + // * + // * Sometimes a poorly behaved task will write output to stderr even though its operation was successful. + // * In that case, it's strongly recommended to fix the task. However, as a workaround you can set + // * allowWarningsInSuccessfulBuild=true, which causes Rush to return a nonzero exit code for errors only. + // * + // * Note: The default value is false. In Rush 5.7.x and earlier, the default value was true. + // */ + // "allowWarningsInSuccessfulBuild": false, + // + // /** + // * If true then this command will be incremental like the built-in "build" command + // */ + // "incremental": false + // }, + // + // { + // /** + // * (Required) Determines the type of custom command. + // * Rush's "global" commands are invoked once for the entire repo. + // */ + // "commandKind": "global", + // + // "name": "my-global-command", + // "summary": "Example global custom command", + // "description": "This is an example custom command that runs once for the entire repo", + // + // "safeForSimultaneousRushProcesses": false, + // + // /** + // * (Required) A script that will be invoked using the OS shell. The working directory will be + // * the folder that contains rush.json. If custom parameters are associated with this command, their + // * values will be appended to the end of this string. + // */ + // "shellCommand": "node common/scripts/my-global-command.js", + // + // /** + // * If your "shellCommand" script depends on NPM packages, the recommended best practice is + // * to make it into a regular Rush project that builds using your normal toolchain. In cases where + // * the command needs to work without first having to run "rush build", the recommended practice + // * is to publish the project to an NPM registry and use common/scripts/install-run.js to launch it. + // * + // * Autoinstallers offer another possibility: They are folders under "common/autoinstallers" with + // * a package.json file and shrinkwrap file. Rush will automatically invoke the package manager to + // * install these dependencies before an associated command is invoked. Autoinstallers have the + // * advantage that they work even in a branch where "rush install" is broken, which makes them a + // * good solution for Git hook scripts. But they have the disadvantages of not being buildable + // * projects, and of increasing the overall installation footprint for your monorepo. + // * + // * The "autoinstallerName" setting must not contain a path and must be a valid NPM package name. + // * For example, the name "my-task" would map to "common/autoinstallers/my-task/package.json", and + // * the "common/autoinstallers/my-task/node_modules/.bin" folder would be added to the shell PATH when + // * invoking the "shellCommand". + // */ + // "autoinstallerName": "my-task" + // } + { + "name": "test", + "commandKind": "bulk", + "summary": "Runs unit tests in each project.", + "description": "Runs the 'test' script within each project.json", + "enableParallelism": true, + "ignoreDependencyOrder": true, + "incremental": false, + "disableBuildCache": true + }, + { + "name": "prettier", + "commandKind": "global", + "summary": "Used by the pre-commit Git hook. This command invokes Prettier to reformat staged changes.", + "autoinstallerName": "rush-prettier", + // This will invoke common/autoinstallers/rush-prettier/node_modules/.bin/pretty-quick + "shellCommand": "pretty-quick --staged" + } + ], + + /** + * Custom "parameters" introduce new parameters for specified Rush command-line commands. + * For example, you might define a "--production" parameter for the "rush build" command. + */ + "parameters": [ + // { + // /** + // * (Required) Determines the type of custom parameter. + // * A "flag" is a custom command-line parameter whose presence acts as an on/off switch. + // */ + // "parameterKind": "flag", + // + // /** + // * (Required) The long name of the parameter. It must be lower-case and use dash delimiters. + // */ + // "longName": "--my-flag", + // + // /** + // * An optional alternative short name for the parameter. It must be a dash followed by a single + // * lower-case or upper-case letter, which is case-sensitive. + // * + // * NOTE: The Rush developers recommend that automation scripts should always use the long name + // * to improve readability. The short name is only intended as a convenience for humans. + // * The alphabet letters run out quickly, and are difficult to memorize, so *only* use + // * a short name if you expect the parameter to be needed very often in everyday operations. + // */ + // "shortName": "-m", + // + // /** + // * (Required) A long description to be shown in the command-line help. + // * + // * Whenever you introduce commands/parameters, taking a little time to write meaningful + // * documentation can make a big difference for the developer experience in your repo. + // */ + // "description": "A custom flag parameter that is passed to the scripts that are invoked when building projects", + // + // /** + // * (Required) A list of custom commands and/or built-in Rush commands that this parameter may + // * be used with. The parameter will be appended to the shell command that Rush invokes. + // */ + // "associatedCommands": ["build", "rebuild"] + // }, + // + // { + // /** + // * (Required) Determines the type of custom parameter. + // * A "string" is a custom command-line parameter whose value is a simple text string. + // */ + // "parameterKind": "string", + // "longName": "--my-string", + // "description": "A custom string parameter for the \"my-global-command\" custom command", + // + // "associatedCommands": ["my-global-command"], + // + // /** + // * The name of the argument, which will be shown in the command-line help. + // * + // * For example, if the parameter name is '--count" and the argument name is "NUMBER", + // * then the command-line help would display "--count NUMBER". The argument name must + // * be comprised of upper-case letters, numbers, and underscores. It should be kept short. + // */ + // "argumentName": "SOME_TEXT", + // + // /** + // * If true, this parameter must be included with the command. The default is false. + // */ + // "required": false + // }, + // + // { + // /** + // * (Required) Determines the type of custom parameter. + // * A "choice" is a custom command-line parameter whose argument must be chosen from a list of + // * allowable alternatives. + // */ + // "parameterKind": "choice", + // "longName": "--my-choice", + // "description": "A custom choice parameter for the \"my-global-command\" custom command", + // + // "associatedCommands": ["my-global-command"], + // + // /** + // * If true, this parameter must be included with the command. The default is false. + // */ + // "required": false, + // + // /** + // * Normally if a parameter is omitted from the command line, it will not be passed + // * to the shell command. this value will be inserted by default. Whereas if a "defaultValue" + // * is defined, the parameter will always be passed to the shell command, and will use the + // * default value if unspecified. The value must be one of the defined alternatives. + // */ + // "defaultValue": "vanilla", + // + // /** + // * (Required) A list of alternative argument values that can be chosen for this parameter. + // */ + // "alternatives": [ + // { + // /** + // * A token that is one of the alternatives that can be used with the choice parameter, + // * e.g. "vanilla" in "--flavor vanilla". + // */ + // "name": "vanilla", + // + // /** + // * A detailed description for the alternative that can be shown in the command-line help. + // * + // * Whenever you introduce commands/parameters, taking a little time to write meaningful + // * documentation can make a big difference for the developer experience in your repo. + // */ + // "description": "Use the vanilla flavor (the default)" + // }, + // + // { + // "name": "chocolate", + // "description": "Use the chocolate flavor" + // }, + // + // { + // "name": "strawberry", + // "description": "Use the strawberry flavor" + // } + // ] + // } + ] +} diff --git a/common/config/rush/common-versions.json b/common/config/rush/common-versions.json new file mode 100644 index 000000000..481fceada --- /dev/null +++ b/common/config/rush/common-versions.json @@ -0,0 +1,62 @@ +/** + * This configuration file specifies NPM dependency version selections that affect all projects + * in a Rush repo. For full documentation, please see https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/common-versions.schema.json", + + /** + * A table that specifies a "preferred version" for a given NPM package. This feature is typically used + * to hold back an indirect dependency to a specific older version, or to reduce duplication of indirect dependencies. + * + * The "preferredVersions" value can be any SemVer range specifier (e.g. "~1.2.3"). Rush injects these values into + * the "dependencies" field of the top-level common/temp/package.json, which influences how the package manager + * will calculate versions. The specific effect depends on your package manager. Generally it will have no + * effect on an incompatible or already constrained SemVer range. If you are using PNPM, similar effects can be + * achieved using the pnpmfile.js hook. See the Rush documentation for more details. + * + * After modifying this field, it's recommended to run "rush update --full" so that the package manager + * will recalculate all version selections. + */ + "preferredVersions": { + /** + * When someone asks for "^1.0.0" make sure they get "1.2.3" when working in this repo, + * instead of the latest version. + */ + // "some-library": "1.2.3" + }, + + /** + * When set to true, for all projects in the repo, all dependencies will be automatically added as preferredVersions, + * except in cases where different projects specify different version ranges for a given dependency. For older + * package managers, this tended to reduce duplication of indirect dependencies. However, it can sometimes cause + * trouble for indirect dependencies with incompatible peerDependencies ranges. + * + * The default value is true. If you're encountering installation errors related to peer dependencies, + * it's recommended to set this to false. + * + * After modifying this field, it's recommended to run "rush update --full" so that the package manager + * will recalculate all version selections. + */ + // "implicitlyPreferredVersions": false, + + /** + * The "rush check" command can be used to enforce that every project in the repo must specify + * the same SemVer range for a given dependency. However, sometimes exceptions are needed. + * The allowedAlternativeVersions table allows you to list other SemVer ranges that will be + * accepted by "rush check" for a given dependency. + * + * IMPORTANT: THIS TABLE IS FOR *ADDITIONAL* VERSION RANGES THAT ARE ALTERNATIVES TO THE + * USUAL VERSION (WHICH IS INFERRED BY LOOKING AT ALL PROJECTS IN THE REPO). + * This design avoids unnecessary churn in this file. + */ + "allowedAlternativeVersions": { + /** + * For example, allow some projects to use an older TypeScript compiler + * (in addition to whatever "usual" version is being used by other projects in the repo): + */ + // "typescript": [ + // "~2.4.0" + // ] + } +} diff --git a/common/config/rush/experiments.json b/common/config/rush/experiments.json new file mode 100644 index 000000000..e8ff8e8f3 --- /dev/null +++ b/common/config/rush/experiments.json @@ -0,0 +1,28 @@ +/** + * This configuration file allows repo maintainers to enable and disable experimental + * Rush features. For full documentation, please see https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/experiments.schema.json", + + /** + * Rush 5.14.0 improved incremental builds to ignore spurious changes in the pnpm-lock.json file. + * This optimization is enabled by default. If you encounter a problem where "rush build" is neglecting + * to build some projects, please open a GitHub issue. As a workaround you can uncomment this line + * to temporarily restore the old behavior where everything must be rebuilt whenever pnpm-lock.json + * is modified. + */ + // "legacyIncrementalBuildDependencyDetection": true, + + /** + * By default, rush passes --no-prefer-frozen-lockfile to 'pnpm install'. + * Set this option to true to pass '--frozen-lockfile' instead. + */ + // "usePnpmFrozenLockfileForRushInstall": true, + + /** + * If true, the chmod field in temporary project tar headers will not be normalized. + * This normalization can help ensure consistent tarball integrity across platforms. + */ + // "noChmodFieldInTarHeaderNormalization": true +} diff --git a/common/config/rush/nonbrowser-approved-packages.json b/common/config/rush/nonbrowser-approved-packages.json new file mode 100644 index 000000000..b409b010a --- /dev/null +++ b/common/config/rush/nonbrowser-approved-packages.json @@ -0,0 +1,5 @@ +// DO NOT ADD COMMENTS IN THIS FILE. They will be lost when the Rush tool resaves it. +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/approved-packages.schema.json", + "packages": [] +} diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml new file mode 100644 index 000000000..81b895e74 --- /dev/null +++ b/common/config/rush/pnpm-lock.yaml @@ -0,0 +1,18419 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: false + excludeLinksFromLockfile: false + +pnpmfileChecksum: jmsifwrxg4slleckty7qyuymte + +importers: + + .: {} + + ../../libraries/browser-tracker-core: + dependencies: + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + uuid: + specifier: ^11.1.1 + version: 11.1.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@testing-library/dom': + specifier: ~9.3.1 + version: 9.3.4 + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + whatwg-fetch: + specifier: ~3.6.20 + version: 3.6.20 + + ../../libraries/tracker-core: + dependencies: + tslib: + specifier: ^2.3.1 + version: 2.8.1 + uuid: + specifier: ^11.1.1 + version: 11.1.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-json': + specifier: ~4.1.0 + version: 4.1.0(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/node': + specifier: ~14.6.0 + version: 14.6.4 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + ava: + specifier: ~5.1.1 + version: 5.1.1 + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-node: + specifier: ~10.9.1 + version: 10.9.2(@types/node@14.6.4)(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-ad-tracking: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@types/lodash': + specifier: ~4.14.180 + version: 4.14.202 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + lodash: + specifier: ~4.17.21 + version: 4.17.21 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-bot-detection: + dependencies: + '@fingerprintjs/botd': + specifier: 2.0.0 + version: 2.0.0 + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-button-click-tracking: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@types/lodash': + specifier: ~4.14.180 + version: 4.14.202 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + lodash: + specifier: ~4.17.21 + version: 4.17.21 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-client-hints: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-debugger: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + randomcolor: + specifier: ^0.6.2 + version: 0.6.2 + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@types/randomcolor': + specifier: ~0.5.5 + version: 0.5.9 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-element-tracking: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-enhanced-consent: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@types/lodash': + specifier: ~4.14.180 + version: 4.14.202 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + lodash: + specifier: ~4.17.21 + version: 4.17.21 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-enhanced-ecommerce: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@types/lodash': + specifier: ~4.14.180 + version: 4.14.202 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + lodash: + specifier: ~4.17.21 + version: 4.17.21 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-error-tracking: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@types/lodash': + specifier: ~4.14.180 + version: 4.14.202 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + lodash: + specifier: ~4.17.21 + version: 4.17.21 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-event-specifications: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-focalmeter: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-form-tracking: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-ga-cookies: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-geolocation: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-link-click-tracking: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@types/lodash': + specifier: ~4.14.180 + version: 4.14.202 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + lodash: + specifier: ~4.17.21 + version: 4.17.21 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-media: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + uuid: + specifier: ^11.1.1 + version: 11.1.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-media-tracking: + dependencies: + '@snowplow/browser-plugin-media': + specifier: workspace:* + version: link:../browser-plugin-media + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + uuid: + specifier: ^11.1.1 + version: 11.1.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-optimizely-x: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-performance-navigation-timing: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-performance-timing: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-privacy-sandbox: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-screen-tracking: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + uuid: + specifier: ^11.1.1 + version: 11.1.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@types/lodash': + specifier: ~4.14.180 + version: 4.14.202 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + lodash: + specifier: ~4.17.21 + version: 4.17.21 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-site-tracking: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@types/lodash': + specifier: ~4.14.180 + version: 4.14.202 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + lodash: + specifier: ~4.17.21 + version: 4.17.21 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-snowplow-ecommerce: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@types/lodash': + specifier: ~4.14.180 + version: 4.14.202 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + lodash: + specifier: ~4.17.21 + version: 4.17.21 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-timezone: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + jstimezonedetect: + specifier: 1.0.7 + version: 1.0.7 + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@types/jstimezonedetect': + specifier: ~1.0.3 + version: 1.0.6 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + moment-timezone: + specifier: ~0.5.26 + version: 0.5.46 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-vimeo-tracking: + dependencies: + '@snowplow/browser-plugin-media': + specifier: workspace:* + version: link:../browser-plugin-media + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + '@vimeo/player': + specifier: 2.16.4 + version: 2.16.4 + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@types/vimeo__player': + specifier: ~2.16.3 + version: 2.16.3 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-web-vitals: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + web-vitals: + specifier: ~4.2.4 + version: 4.2.4 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-webview: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + '@snowplow/webview-tracker': + specifier: ^0.3.1 + version: 0.3.1 + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../plugins/browser-plugin-youtube-tracking: + dependencies: + '@snowplow/browser-plugin-media': + specifier: workspace:* + version: link:../browser-plugin-media + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + uuid: + specifier: ^11.1.1 + version: 11.1.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@types/youtube': + specifier: ~0.0.46 + version: 0.0.50 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../trackers/browser-tracker: + dependencies: + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@types/lodash': + specifier: ~4.14.180 + version: 4.14.202 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + lodash: + specifier: ~4.17.21 + version: 4.17.21 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + whatwg-fetch: + specifier: ~3.6.20 + version: 3.6.20 + + ../../trackers/javascript-tracker: + dependencies: + '@snowplow/browser-plugin-ad-tracking': + specifier: workspace:* + version: link:../../plugins/browser-plugin-ad-tracking + '@snowplow/browser-plugin-button-click-tracking': + specifier: workspace:* + version: link:../../plugins/browser-plugin-button-click-tracking + '@snowplow/browser-plugin-client-hints': + specifier: workspace:* + version: link:../../plugins/browser-plugin-client-hints + '@snowplow/browser-plugin-element-tracking': + specifier: workspace:* + version: link:../../plugins/browser-plugin-element-tracking + '@snowplow/browser-plugin-enhanced-consent': + specifier: workspace:* + version: link:../../plugins/browser-plugin-enhanced-consent + '@snowplow/browser-plugin-enhanced-ecommerce': + specifier: workspace:* + version: link:../../plugins/browser-plugin-enhanced-ecommerce + '@snowplow/browser-plugin-error-tracking': + specifier: workspace:* + version: link:../../plugins/browser-plugin-error-tracking + '@snowplow/browser-plugin-event-specifications': + specifier: workspace:* + version: link:../../plugins/browser-plugin-event-specifications + '@snowplow/browser-plugin-form-tracking': + specifier: workspace:* + version: link:../../plugins/browser-plugin-form-tracking + '@snowplow/browser-plugin-ga-cookies': + specifier: workspace:* + version: link:../../plugins/browser-plugin-ga-cookies + '@snowplow/browser-plugin-geolocation': + specifier: workspace:* + version: link:../../plugins/browser-plugin-geolocation + '@snowplow/browser-plugin-link-click-tracking': + specifier: workspace:* + version: link:../../plugins/browser-plugin-link-click-tracking + '@snowplow/browser-plugin-media': + specifier: workspace:* + version: link:../../plugins/browser-plugin-media + '@snowplow/browser-plugin-media-tracking': + specifier: workspace:* + version: link:../../plugins/browser-plugin-media-tracking + '@snowplow/browser-plugin-optimizely-x': + specifier: workspace:* + version: link:../../plugins/browser-plugin-optimizely-x + '@snowplow/browser-plugin-performance-navigation-timing': + specifier: workspace:* + version: link:../../plugins/browser-plugin-performance-navigation-timing + '@snowplow/browser-plugin-performance-timing': + specifier: workspace:* + version: link:../../plugins/browser-plugin-performance-timing + '@snowplow/browser-plugin-privacy-sandbox': + specifier: workspace:* + version: link:../../plugins/browser-plugin-privacy-sandbox + '@snowplow/browser-plugin-site-tracking': + specifier: workspace:* + version: link:../../plugins/browser-plugin-site-tracking + '@snowplow/browser-plugin-snowplow-ecommerce': + specifier: workspace:* + version: link:../../plugins/browser-plugin-snowplow-ecommerce + '@snowplow/browser-plugin-timezone': + specifier: workspace:* + version: link:../../plugins/browser-plugin-timezone + '@snowplow/browser-plugin-vimeo-tracking': + specifier: workspace:* + version: link:../../plugins/browser-plugin-vimeo-tracking + '@snowplow/browser-plugin-web-vitals': + specifier: workspace:* + version: link:../../plugins/browser-plugin-web-vitals + '@snowplow/browser-plugin-webview': + specifier: workspace:* + version: link:../../plugins/browser-plugin-webview + '@snowplow/browser-plugin-youtube-tracking': + specifier: workspace:* + version: link:../../plugins/browser-plugin-youtube-tracking + '@snowplow/browser-tracker': + specifier: workspace:* + version: link:../browser-tracker + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-alias': + specifier: ~3.1.9 + version: 3.1.9(rollup@2.70.2) + '@rollup/plugin-commonjs': + specifier: ~21.0.2 + version: 21.0.3(rollup@2.70.2) + '@rollup/plugin-json': + specifier: ~4.1.0 + version: 4.1.0(rollup@2.70.2) + '@rollup/plugin-node-resolve': + specifier: ~13.1.3 + version: 13.1.3(rollup@2.70.2) + '@rollup/plugin-replace': + specifier: ~4.0.0 + version: 4.0.0(rollup@2.70.2) + '@types/dockerode': + specifier: ~3.3.5 + version: 3.3.32 + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/jsdom': + specifier: ~16.2.14 + version: 16.2.15 + '@types/lodash': + specifier: ~4.14.180 + version: 4.14.202 + '@types/node': + specifier: ~14.6.0 + version: 14.6.4 + '@types/youtube': + specifier: ~0.0.46 + version: 0.0.50 + '@wdio/cli': + specifier: ~8.39.1 + version: 8.39.1(encoding@0.1.13)(typescript@4.6.4) + '@wdio/globals': + specifier: ~8.39.1 + version: 8.39.1(encoding@0.1.13)(typescript@4.6.4) + '@wdio/jasmine-framework': + specifier: ~8.39.1 + version: 8.39.1(encoding@0.1.13)(typescript@4.6.4) + '@wdio/local-runner': + specifier: ~8.39.1 + version: 8.39.1(encoding@0.1.13)(typescript@4.6.4) + '@wdio/sauce-service': + specifier: ~8.39.1 + version: 8.39.1(encoding@0.1.13)(typescript@4.6.4) + '@wdio/shared-store-service': + specifier: ~8.39.1 + version: 8.39.1(encoding@0.1.13)(typescript@4.6.4) + '@wdio/spec-reporter': + specifier: ~8.39.0 + version: 8.39.0 + '@wdio/static-server-service': + specifier: ~8.39.0 + version: 8.39.0 + '@wdio/types': + specifier: ~8.39.0 + version: 8.39.0 + chalk: + specifier: 4.1.2 + version: 4.1.2 + chromedriver: + specifier: ~131.0.0 + version: 131.0.4 + dockerode: + specifier: ~3.3.1 + version: 3.3.5 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@14.6.4)(ts-node@10.9.2(@types/node@14.6.4)(typescript@4.6.4)) + jest-environment-jsdom: + specifier: ~28.1.3 + version: 28.1.3 + jest-environment-jsdom-global: + specifier: ~4.0.0 + version: 4.0.0(jest-environment-jsdom@28.1.3) + jest-standard-reporter: + specifier: ~2.0.0 + version: 2.0.0 + lodash: + specifier: ~4.17.21 + version: 4.17.21 + npm-run-all: + specifier: ~4.1.5 + version: 4.1.5 + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-cleanup: + specifier: ~3.2.1 + version: 3.2.1(rollup@2.70.2) + rollup-plugin-filesize: + specifier: ~9.1.2 + version: 9.1.2 + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-sizes: + specifier: ~1.0.4 + version: 1.0.6(rollup@2.70.2) + rollup-plugin-terser: + specifier: ~7.0.2 + version: 7.0.2(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + saucelabs: + specifier: ~7.5.0 + version: 7.5.0 + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@14.6.4)(ts-node@10.9.2(@types/node@14.6.4)(typescript@4.6.4)))(typescript@4.6.4) + ts-node: + specifier: ~10.9.1 + version: 10.9.2(@types/node@14.6.4)(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + wdio-chromedriver-service: + specifier: ~8.1.1 + version: 8.1.1(@wdio/types@8.39.0)(chromedriver@131.0.4)(webdriverio@8.39.1(encoding@0.1.13)(typescript@4.6.4)) + wdio-edgedriver-service: + specifier: ~3.0.3 + version: 3.0.3(@wdio/types@8.39.0) + wdio-safaridriver-service: + specifier: ~2.1.1 + version: 2.1.1(@wdio/types@8.39.0)(webdriverio@8.39.1(encoding@0.1.13)(typescript@4.6.4)) + webdriverio: + specifier: ~8.39.1 + version: 8.39.1(encoding@0.1.13)(typescript@4.6.4) + + ../../trackers/node-tracker: + dependencies: + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + devDependencies: + '@rollup/plugin-json': + specifier: ~4.1.0 + version: 4.1.0(rollup@2.70.2) + '@types/node': + specifier: ~14.6.0 + version: 14.6.4 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + ava: + specifier: ~5.1.1 + version: 5.1.1 + eslint: + specifier: ~8.11.0 + version: 8.11.0 + eslint-plugin-ava: + specifier: ~13.2.0 + version: 13.2.0(eslint@8.11.0) + rollup: + specifier: ~2.70.1 + version: 2.70.2 + rollup-plugin-license: + specifier: ~2.6.1 + version: 2.6.1(rollup@2.70.2) + rollup-plugin-ts: + specifier: ~2.0.5 + version: 2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4) + ts-node: + specifier: ~10.9.1 + version: 10.9.2(@types/node@14.6.4)(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + + ../../trackers/react-native-tracker: + dependencies: + '@snowplow/browser-plugin-screen-tracking': + specifier: workspace:* + version: link:../../plugins/browser-plugin-screen-tracking + '@snowplow/browser-tracker-core': + specifier: workspace:* + version: link:../../libraries/browser-tracker-core + '@snowplow/tracker-core': + specifier: workspace:* + version: link:../../libraries/tracker-core + tslib: + specifier: ^2.3.1 + version: 2.8.1 + uuid: + specifier: ^11.1.1 + version: 11.1.1 + devDependencies: + '@react-native-async-storage/async-storage': + specifier: ^2.0.0 + version: 2.0.0(react-native@0.74.5(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@types/react@18.3.18)(encoding@0.1.13)(react@18.2.0)) + '@snowplow/browser-plugin-snowplow-ecommerce': + specifier: workspace:* + version: link:../../plugins/browser-plugin-snowplow-ecommerce + '@types/jest': + specifier: ~28.1.1 + version: 28.1.8 + '@types/node': + specifier: ~14.6.0 + version: 14.6.4 + '@types/react': + specifier: ^18.2.44 + version: 18.3.18 + '@typescript-eslint/eslint-plugin': + specifier: ~5.15.0 + version: 5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/parser': + specifier: ~5.15.0 + version: 5.15.0(eslint@8.11.0)(typescript@4.6.4) + eslint: + specifier: ~8.11.0 + version: 8.11.0 + jest: + specifier: ~28.1.3 + version: 28.1.3(@types/node@14.6.4)(ts-node@10.9.2(@types/node@14.6.4)(typescript@4.6.4)) + node-fetch: + specifier: ~3.3.2 + version: 3.3.2 + react: + specifier: 18.2.0 + version: 18.2.0 + react-native: + specifier: 0.74.5 + version: 0.74.5(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@types/react@18.3.18)(encoding@0.1.13)(react@18.2.0) + react-native-builder-bob: + specifier: ^0.42.1 + version: 0.42.1 + react-native-get-random-values: + specifier: ^1.11.0 || ^2.0.0 + version: 1.11.0(react-native@0.74.5(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@types/react@18.3.18)(encoding@0.1.13)(react@18.2.0)) + ts-jest: + specifier: ~28.0.8 + version: 28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@14.6.4)(ts-node@10.9.2(@types/node@14.6.4)(typescript@4.6.4)))(typescript@4.6.4) + typescript: + specifier: ~4.6.2 + version: 4.6.4 + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@ark/schema@0.56.0': + resolution: {integrity: sha512-ECg3hox/6Z/nLajxXqNhgPtNdHWC9zNsDyskwO28WinoFEnWow4IsERNz9AnXRhTZJnYIlAJ4uGn3nlLk65vZA==} + + '@ark/util@0.56.0': + resolution: {integrity: sha512-BghfRC8b9pNs3vBoDJhcta0/c1J1rsoS1+HgVUreMFPdhz/CRAKReAu57YEllNaSy98rWAdY1gE+gFup7OXpgA==} + + '@arr/every@1.0.1': + resolution: {integrity: sha512-UQFQ6SgyJ6LX42W8rHCs8KVc0JS0tzVL9ct4XYedJukskYVWTo49tNiMEK9C2HTyarbNiT/RVIRSY82vH+6sTg==} + engines: {node: '>=4'} + + '@babel/code-frame@7.26.2': + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + engines: {node: '>=6.9.0'} + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.26.3': + resolution: {integrity: sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.26.0': + resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.26.3': + resolution: {integrity: sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.7': + resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-annotate-as-pure@7.25.9': + resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-annotate-as-pure@7.29.7': + resolution: {integrity: sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.25.9': + resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-create-class-features-plugin@7.25.9': + resolution: {integrity: sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-create-class-features-plugin@7.29.7': + resolution: {integrity: sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-create-regexp-features-plugin@7.26.3': + resolution: {integrity: sha512-G7ZRb40uUgdKOQqPLjfD12ZmGA54PzqDFUv2BKImnC9QIfGhIHKvVML0oN8IUiDq4iRqpq74ABpvOaerfWdong==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-create-regexp-features-plugin@7.29.7': + resolution: {integrity: sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-define-polyfill-provider@0.6.3': + resolution: {integrity: sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + '@babel/helper-define-polyfill-provider@0.6.8': + resolution: {integrity: sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + '@babel/helper-environment-visitor@7.24.7': + resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-member-expression-to-functions@7.25.9': + resolution: {integrity: sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-member-expression-to-functions@7.29.7': + resolution: {integrity: sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.25.9': + resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.26.0': + resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-optimise-call-expression@7.25.9': + resolution: {integrity: sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-optimise-call-expression@7.29.7': + resolution: {integrity: sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==} + engines: {node: '>=6.9.0'} + + '@babel/helper-plugin-utils@7.25.9': + resolution: {integrity: sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-plugin-utils@7.29.7': + resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-remap-async-to-generator@7.25.9': + resolution: {integrity: sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-remap-async-to-generator@7.29.7': + resolution: {integrity: sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-replace-supers@7.25.9': + resolution: {integrity: sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-replace-supers@7.29.7': + resolution: {integrity: sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-skip-transparent-expression-wrappers@7.25.9': + resolution: {integrity: sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-skip-transparent-expression-wrappers@7.29.7': + resolution: {integrity: sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.25.9': + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.25.9': + resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-wrap-function@7.25.9': + resolution: {integrity: sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-wrap-function@7.29.7': + resolution: {integrity: sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.26.0': + resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.26.3': + resolution: {integrity: sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.29.7': + resolution: {integrity: sha512-j8SrR0zLZrRsC09DlszEx8FpMiwukKffYXMK0d5LmOglO7vGG6sz/BR/20yHqWH+Lnn31JTt2PE3hIWNgM2J6w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.29.7': + resolution: {integrity: sha512-r8j8escF+U2FUHo0KOhPUdMzUO+jp9fInva6+ACVAF3Y97Ev+5iNZwiqTghmzNeWwDkOPlYuTcfb1vDaoZKmAQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.29.7': + resolution: {integrity: sha512-GE1TFSiuFeGsCxmYXZl8HwoPrVlwe4rHPFE8weieGKZqnDORK+Ar3vgWMgW+AOxQ6/2TgLSKx9p6W7O4rC6qgQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@7.29.7': + resolution: {integrity: sha512-oBNVCvnO5tND+xSopWvV8WNGfpTfgP4Zr/YXXSj8zfmcPktp5Ku/aZlsIowgSD4fjmgHn6sGmB9APVsU5zOdhA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.29.7': + resolution: {integrity: sha512-QQt9qKHZ2sg/kivaLr7lnQr8HVrQDdBNSfCsTjiDxRuX/K5ORyKq+Bu8Xr0cDE3Dfkv0cw28Ve0EKyKMvulkOw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.13.0 + + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.29.7': + resolution: {integrity: sha512-pn6QacGLgvCcwc+syUhKE/qSjV2D1IHDB84RNxWYSt1mW3K/SCtjinZ2p0cETJxAWBjPy3K/1lHwG5BjjPxNlw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-proposal-async-generator-functions@7.20.7': + resolution: {integrity: sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==} + engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead. + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-proposal-class-properties@7.18.6': + resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} + engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead. + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-proposal-export-default-from@7.25.9': + resolution: {integrity: sha512-ykqgwNfSnNOB+C8fV5X4mG3AVmvu+WVxcaU9xHHtBb7PCrPeweMmPjGsn8eMaeJg6SJuoUuZENeeSWaarWqonQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-proposal-logical-assignment-operators@7.20.7': + resolution: {integrity: sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==} + engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-logical-assignment-operators instead. + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6': + resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==} + engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead. + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-proposal-numeric-separator@7.18.6': + resolution: {integrity: sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==} + engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead. + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-proposal-object-rest-spread@7.20.7': + resolution: {integrity: sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==} + engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead. + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-proposal-optional-catch-binding@7.18.6': + resolution: {integrity: sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==} + engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-catch-binding instead. + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-proposal-optional-chaining@7.21.0': + resolution: {integrity: sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==} + engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead. + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2': + resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-async-generators@7.8.4': + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-bigint@7.8.3': + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-properties@7.12.13': + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-static-block@7.14.5': + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-dynamic-import@7.8.3': + resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-export-default-from@7.25.9': + resolution: {integrity: sha512-9MhJ/SMTsVqsd69GyQg89lYR4o9T+oDGv5F6IsigxxqFVOyR/IflDLYP8WDI1l8fkhNGGktqkvL5qwNCtGEpgQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-flow@7.26.0': + resolution: {integrity: sha512-B+O2DnPc0iG+YXFqOxv2WNuNU97ToWjOomUQ78DouOENWUaM5sVrmet9mcomUGQFwpJd//gvUagXBSdzO1fRKg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-flow@7.29.7': + resolution: {integrity: sha512-ajMX6QPcyomotqwpzhkYGxcK2i/us0rs1Qo9QvUpa+Fca0FTmqrzKrctoIYLMxcOhGZldGT/BAVkRGTWBiR8gQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-assertions@7.29.7': + resolution: {integrity: sha512-/An1OCBN93thpBAGyfsK2pcf0jvju1SAtKkL2Ny++B5Sy6sqgzXDQH1cZxWbF96Wuk+bn41MDA9bLd4VVAw6rw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-attributes@7.26.0': + resolution: {integrity: sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-attributes@7.29.7': + resolution: {integrity: sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-json-strings@7.8.3': + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.25.9': + resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.29.7': + resolution: {integrity: sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-numeric-separator@7.10.4': + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-object-rest-spread@7.8.3': + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3': + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-chaining@7.8.3': + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-private-property-in-object@7.14.5': + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-top-level-await@7.14.5': + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.25.9': + resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.29.7': + resolution: {integrity: sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-unicode-sets-regex@7.18.6': + resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-arrow-functions@7.25.9': + resolution: {integrity: sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-arrow-functions@7.29.7': + resolution: {integrity: sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-async-generator-functions@7.29.7': + resolution: {integrity: sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-async-to-generator@7.25.9': + resolution: {integrity: sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-async-to-generator@7.29.7': + resolution: {integrity: sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-block-scoped-functions@7.29.7': + resolution: {integrity: sha512-cUSmjh72N+rN4PrkFlN1dJwNCwjVp5d38/CQrEsFggkD10UiFlBFgdH3tv5dNsLuHY+3S8db2xCHjhZcv5WgvA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-block-scoping@7.25.9': + resolution: {integrity: sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-block-scoping@7.29.7': + resolution: {integrity: sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-class-properties@7.29.7': + resolution: {integrity: sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-class-static-block@7.29.7': + resolution: {integrity: sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + + '@babel/plugin-transform-classes@7.25.9': + resolution: {integrity: sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-classes@7.29.7': + resolution: {integrity: sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-computed-properties@7.25.9': + resolution: {integrity: sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-computed-properties@7.29.7': + resolution: {integrity: sha512-RK7/IyU5phpuCdBAuig5VkzG/EnbDaui5SQGdU9BFrHdV+mV4cUjLMQ9lJDjLNtWHsqtiefpGZUXQP2BiTYMsA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-destructuring@7.25.9': + resolution: {integrity: sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-destructuring@7.29.7': + resolution: {integrity: sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-dotall-regex@7.29.7': + resolution: {integrity: sha512-3qc18hsD2RdZiyJNDNc7HQpv6xbncwh8FYtxNFFzclSyh/trPD9KkVR9BDECUjDLvb7yJVF15GfYUuC+LMkkiQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-duplicate-keys@7.29.7': + resolution: {integrity: sha512-6IvRRriEMqnBwD6chtxdLpMYCHWEzN+oL5cyQtjykya19UgzbmKhxmhZgKC/LHxS2nYr9Q/qYPZ5Lr6jOL9+yQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.7': + resolution: {integrity: sha512-2wiIyo2BjtgU7HufSeDnL9L2O7zr8jmhFKuSr65VpRkUiRKRNpb0mdlk56+XPPKoIrfHqzbMuglDvZun0RISsA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-dynamic-import@7.29.7': + resolution: {integrity: sha512-giOlEm/EFjfjr+te9NsdjkUo2v4f8rS/SXPumRVHAtbNcyNlvtREkU1dZzaIDclNpnaVhlCqRdFKhJBjBikzLg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-explicit-resource-management@7.29.7': + resolution: {integrity: sha512-Rstj7coNz8sE+7Ju7ihpHLI564lsK5pUpNNlvptCIC/16E/S5hbl6n3kESPKdNRmqEWlpn5xpS5Q2dvXBsySLw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-exponentiation-operator@7.29.7': + resolution: {integrity: sha512-zFpMOTLZBdW5LfObqcSbL6kefg4R4eLdmvS0wbN9M6D5Mym/sKm9toOoWyVOa+xDjvCnuWcHls2YonXwHvH3CQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-export-namespace-from@7.29.7': + resolution: {integrity: sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-flow-strip-types@7.25.9': + resolution: {integrity: sha512-/VVukELzPDdci7UUsWQaSkhgnjIWXnIyRpM02ldxaVoFK96c41So8JcKT3m0gYjyv7j5FNPGS5vfELrWalkbDA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-flow-strip-types@7.29.7': + resolution: {integrity: sha512-wRHeUjUjCZnMHmiO5bRgjFLcoEh7JyTdByOW11ahhwNa4V0bmeGEaIvt51yq0zQp2yWIpqfxXXPyUP6GFJZHOQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-for-of@7.29.7': + resolution: {integrity: sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-function-name@7.25.9': + resolution: {integrity: sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-function-name@7.29.7': + resolution: {integrity: sha512-otRWaHXE6fbAGkePvaj/kvs3HsqXfPhlnzwSOlnFgbqCPMd975dW+4wZ00WFBt+/YlBGcJwNrARQTOJOb4ZrIg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-json-strings@7.29.7': + resolution: {integrity: sha512-RRnE2+eon1rJAq8MnoF1b5kTpY1vU88twHcvcKMrsqP/jxIRqDVs9iJB5fqPuqyeFAW0wJo4MlUIPpQCq/aRsg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-literals@7.25.9': + resolution: {integrity: sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-literals@7.29.7': + resolution: {integrity: sha512-DZ/oLP21ZuWx1vKqnoNv6/tvEK48AQOBRai40CX9dTjGluvT/YZCyY3rryDtyUqCEoyNroy5KKPwX2iQCiRvyw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-logical-assignment-operators@7.29.7': + resolution: {integrity: sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-member-expression-literals@7.29.7': + resolution: {integrity: sha512-hl1kwFZCCiDyfH25Xmco9jTrkPgnS9pmOzSG7W5I4SaGbLeqKv417hcU2RKmaxoPEgsoJh7ZPOrnPGq99bHoUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-amd@7.29.7': + resolution: {integrity: sha512-fxtQoH3m5ywUSIfaH0FGCzWu4McsYon5bD3K4XnskC7f+OyQMj7rsOMi4NvvmJ83WwBAg4UCe+ov4VZlqEvyew==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-commonjs@7.26.3': + resolution: {integrity: sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-commonjs@7.29.7': + resolution: {integrity: sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-systemjs@7.29.7': + resolution: {integrity: sha512-TM2ZcQLoG2/y4HODiStCo10DibYhWhGWAwVv+EQKmG/7GFl0N+AAmUiXOMKM+aiJ9XBJ9AHVZBvTzMnJ2sM3cQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-umd@7.29.7': + resolution: {integrity: sha512-B4UkaTK3QpgCwJnrxKfMPKdo92CN7OKXAlpAAnM3UPu0Q0lCCk57ylA9AJbRy2v8dDKOPAAWcoR6CMyeoHwRCA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-named-capturing-groups-regex@7.25.9': + resolution: {integrity: sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-named-capturing-groups-regex@7.29.7': + resolution: {integrity: sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-new-target@7.29.7': + resolution: {integrity: sha512-fEo41GmsOUhOBlw8ioo6zvjX5Xc2Lqkzlyfqbpsk3eB6TReV18uhxZ0esfEokVbY2+PVJAQHNKxER6lGrzNd3A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-nullish-coalescing-operator@7.29.7': + resolution: {integrity: sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-numeric-separator@7.29.7': + resolution: {integrity: sha512-zR7fv/z14OjgHl4AgRtkDBvBMhIzCxqV/qN/2BCRC7LjFwvuzjYe7gDWxC4Wl/SNsLM6SE1IWvRPYMgSJaUvNw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-object-rest-spread@7.29.7': + resolution: {integrity: sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-object-super@7.29.7': + resolution: {integrity: sha512-Ea/diGcw0twB5IlZPO5sgET6fJsLJqPABqTuFWIR+iMPGPZJkATEIWx0wa+aEQ5UY1CBQyP/gkAiLEqn1vBiQA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-optional-catch-binding@7.29.7': + resolution: {integrity: sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-optional-chaining@7.29.7': + resolution: {integrity: sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-parameters@7.25.9': + resolution: {integrity: sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-parameters@7.29.7': + resolution: {integrity: sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-private-methods@7.25.9': + resolution: {integrity: sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-private-methods@7.29.7': + resolution: {integrity: sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-private-property-in-object@7.25.9': + resolution: {integrity: sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-private-property-in-object@7.29.7': + resolution: {integrity: sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-property-literals@7.29.7': + resolution: {integrity: sha512-bOMRLQuI0A5ZqHq3OWJ89/rXpJ/NJrbVhXiP4zwPGMs6kpcVsuTUNjwoE30K0Qm3mf48a/TnRYYD6vPNqcg6jA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-display-name@7.25.9': + resolution: {integrity: sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-display-name@7.29.7': + resolution: {integrity: sha512-+1wdDMGNb4UPeY3Q4L5yLiYe6TXPXubs4NjrgRFw13hPRLJfEMw2Q5OXkee6/IfdqePIeW4Jjwe3aBh7SdKz4Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-development@7.29.7': + resolution: {integrity: sha512-Xfy3UVMF04+ypnFbkhvfqtmvwfe92qwQdbGZVonhE+6v35GzlofmOnA1szaZqzb9xYWr0nl1e5EMmzi0DNON1g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-self@7.25.9': + resolution: {integrity: sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.25.9': + resolution: {integrity: sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx@7.25.9': + resolution: {integrity: sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx@7.29.7': + resolution: {integrity: sha512-WsZulLVBUHXVj2cUcPVx6UE21TpalB6bHbSFErKT0Ib++ax24jjXe73FqlWvdylFOjiuPHYi6VCcgRad1ItN+A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-pure-annotations@7.29.7': + resolution: {integrity: sha512-H5E+HBgDpr6Q5t+Aj11tL7XkIui1jhbIoArVQnqjgXo5/3YxkN7ZEBcWF4RQlB0T4rrxJQbXS6kiFV6B7XTqUA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-regenerator@7.29.7': + resolution: {integrity: sha512-rNNFV0DBAJp988xW2DOntfDoYn1eR8GGF5AT5vYc+rjyfaQkM242c9tZUHHPe7KYaiJizXPWhQTzzdbXySyhBw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-regexp-modifiers@7.29.7': + resolution: {integrity: sha512-mB5Fs0VWrJ42ZCmc8114v60qetdaUVNkj9PmSZRmanCZM3S9hm0CFRLjRmYIsuXav14l2jvZ+4T8iiCGnhj3nQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-reserved-words@7.29.7': + resolution: {integrity: sha512-5+YhdpVgmfSmwZyLMftfaiffLRMHjzIRHFHHLdibcSyJm2pasMrKHrO3Ptrt2DRshjvpgjEJJ1zVW14WPq/6QA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-runtime@7.25.9': + resolution: {integrity: sha512-nZp7GlEl+yULJrClz0SwHPqir3lc0zsPrDHQUcxGspSL7AKrexNSEfTbfqnDNJUO13bgKyfuOLMF8Xqtu8j3YQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-shorthand-properties@7.25.9': + resolution: {integrity: sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-shorthand-properties@7.29.7': + resolution: {integrity: sha512-I+WYbGBAiCn7nA6xBrlgPH+MB7HWb4u8pv5S0Pv7OtwNvIFvCCb24YlttKEeUFVurfBCEaOTnuhlqsb7f0Z5Dg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-spread@7.25.9': + resolution: {integrity: sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-spread@7.29.7': + resolution: {integrity: sha512-/u5K1QWada7tbYNqTjMh96718g9NTwh9tfPJMsSmVsQwGT447FskV+KcfeXkXq2GWki4EM/MuTdmBec+hOuVTQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-sticky-regex@7.25.9': + resolution: {integrity: sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-sticky-regex@7.29.7': + resolution: {integrity: sha512-BCHzNYJGe9l7EpwwDBN/ztlL2NYFFq8hp9ddjtUEM9f2O7S7kKV/lL6Fwo7IF7NSkYhPK2vO+86nIGltA90MsA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-strict-mode@7.29.7': + resolution: {integrity: sha512-YjFcy7S8kEndK6dsK4UBISrMZa2MHiitApdZ7hTxAyQpX+Ct+aKgKOZoTx/Kcz6drgKxe50TIPUvZq7V4HGGKg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-template-literals@7.29.7': + resolution: {integrity: sha512-NCSEJ4sLFU2gqAub45HYh4fus2yQ36rr6ei6vpU7NdoJqCpxvEG8E6eJpscGyXP3VHD2Ny+fSXr04k1hoUrFqA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typeof-symbol@7.29.7': + resolution: {integrity: sha512-223mNGoTkBiTEWFoK+Q6Go3tueMRclO8vxxxxquNCYuNI4jWOofFKJRRDu6SDrB8Sgo1UEGW9T4GAQ8ZyRso1A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typescript@7.26.3': + resolution: {integrity: sha512-6+5hpdr6mETwSKjmJUdYw0EIkATiQhnELWlE3kJFBwSg/BGIVwVaVbX+gOXBCdc7Ln1RXZxyWGecIXhUfnl7oA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typescript@7.29.7': + resolution: {integrity: sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-escapes@7.29.7': + resolution: {integrity: sha512-jCfXxSjf94lf4E0hKE0AByxF6F3/pVFqRdUUNkDJhsY0m1ZKjnN6ZYyMeHNpzflxb/0q5b7t3p+BE+SLF1WOtA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-property-regex@7.29.7': + resolution: {integrity: sha512-OgZ+zoAJgZLUCunsTRQ5LAjOywDv5zzZ2/hQ5aMw1pGXyY2rtE8/chXYUmu3AlVHKpm10KEdG9aMwbI/K76ZGw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-regex@7.25.9': + resolution: {integrity: sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-regex@7.29.7': + resolution: {integrity: sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-sets-regex@7.29.7': + resolution: {integrity: sha512-BLOhLht9DOJwIxlmp91wHvkXv1lguuHS3/FwUO8HL1H0u8s4hR1gASVFyilu9iGtcTRYqjTZmlsFFeQletntEg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/preset-env@7.29.7': + resolution: {integrity: sha512-GYzX36n1nsciIb0uyH0GHwxwtNwPQIcpxSeiVLDtG/B7jB5xXgchnmL1f/jCX5o+pwnaDBtO60ONSJhEBJfxYA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-flow@7.25.9': + resolution: {integrity: sha512-EASHsAhE+SSlEzJ4bzfusnXSHiU+JfAYzj+jbw2vgQKgq5HrUr8qs+vgtiEL5dOH6sEweI+PNt2D7AqrDSHyqQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-modules@0.1.6-no-external-plugins': + resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} + peerDependencies: + '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 + + '@babel/preset-react@7.29.7': + resolution: {integrity: sha512-C+PV1TFUPTmBQGoPBL8j2QmLpZ117YTCwxIZeJOM96GbYMFSc7/pOXU5lVykwnZxyTqQxRsvoRk6f2FktZgGHA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-typescript@7.26.0': + resolution: {integrity: sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-typescript@7.29.7': + resolution: {integrity: sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/register@7.25.9': + resolution: {integrity: sha512-8D43jXtGsYmEeDvm4MWHYUpWf8iiXgWYx3fW7E7Wb7Oe6FWqJPl5K6TuFW0dOwNZzEE5rjlaSJYH9JjrUKJszA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.26.0': + resolution: {integrity: sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.25.9': + resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.26.4': + resolution: {integrity: sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.7': + resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.26.3': + resolution: {integrity: sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + engines: {node: '>=6.9.0'} + + '@balena/dockerignore@1.0.2': + resolution: {integrity: sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==} + + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@eggjs/yauzl@2.11.0': + resolution: {integrity: sha512-Jq+k2fCZJ3i3HShb0nxLUiAgq5pwo8JTT1TrH22JoehZQ0Nm2dvByGIja1NYfNyuE4Tx5/Dns5nVsBN/mlC8yg==} + + '@eslint/eslintrc@1.4.1': + resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@fingerprintjs/botd@2.0.0': + resolution: {integrity: sha512-yhuz23NKEcBDTHmGz/ULrXlGnbHenO+xZmVwuBkuqHUkqvaZ5TAA0kAgcRy4Wyo5dIBdkIf57UXX8/c9UlMLJg==} + + '@gar/promisify@1.1.3': + resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} + + '@hapi/hoek@9.3.0': + resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + + '@hapi/topo@5.1.0': + resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + + '@humanwhocodes/config-array@0.9.5': + resolution: {integrity: sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + + '@humanwhocodes/object-schema@1.2.1': + resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + deprecated: Use @eslint/object-schema instead + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@isaacs/ttlcache@1.4.1': + resolution: {integrity: sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==} + engines: {node: '>=12'} + + '@istanbuljs/load-nyc-config@1.1.0': + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + + '@jest/console@26.6.2': + resolution: {integrity: sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==} + engines: {node: '>= 10.14.2'} + + '@jest/console@28.1.3': + resolution: {integrity: sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + '@jest/core@28.1.3': + resolution: {integrity: sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/create-cache-key-function@29.7.0': + resolution: {integrity: sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/environment@28.1.3': + resolution: {integrity: sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + '@jest/environment@29.7.0': + resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect-utils@28.1.3': + resolution: {integrity: sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + '@jest/expect-utils@29.7.0': + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect@28.1.3': + resolution: {integrity: sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + '@jest/fake-timers@28.1.3': + resolution: {integrity: sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + '@jest/fake-timers@29.7.0': + resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/globals@28.1.3': + resolution: {integrity: sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + '@jest/reporters@28.1.3': + resolution: {integrity: sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/schemas@28.1.3': + resolution: {integrity: sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/source-map@28.1.2': + resolution: {integrity: sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + '@jest/test-result@28.1.3': + resolution: {integrity: sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + '@jest/test-sequencer@28.1.3': + resolution: {integrity: sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + '@jest/transform@28.1.3': + resolution: {integrity: sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + '@jest/types@26.6.2': + resolution: {integrity: sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==} + engines: {node: '>= 10.14.2'} + + '@jest/types@28.1.3': + resolution: {integrity: sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/gen-mapping@0.3.8': + resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} + engines: {node: '>=6.0.0'} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/source-map@0.3.6': + resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@ljharb/through@2.3.13': + resolution: {integrity: sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ==} + engines: {node: '>= 0.4'} + + '@mdn/browser-compat-data@4.2.1': + resolution: {integrity: sha512-EWUguj2kd7ldmrF9F+vI5hUOralPd+sdsUnYbRy33vZTuZkduC1shE9TtEMEjAQwyfyMb4ole5KtjF8MsnQOlA==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@npmcli/fs@1.1.1': + resolution: {integrity: sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==} + + '@npmcli/git@2.1.0': + resolution: {integrity: sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw==} + + '@npmcli/installed-package-contents@1.0.7': + resolution: {integrity: sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==} + engines: {node: '>= 10'} + hasBin: true + + '@npmcli/move-file@1.1.2': + resolution: {integrity: sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==} + engines: {node: '>=10'} + deprecated: This functionality has been moved to @npmcli/fs + + '@npmcli/node-gyp@1.0.3': + resolution: {integrity: sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA==} + + '@npmcli/promise-spawn@1.3.2': + resolution: {integrity: sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg==} + + '@npmcli/run-script@1.8.6': + resolution: {integrity: sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g==} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@polka/parse@1.0.0-next.0': + resolution: {integrity: sha512-zcPNrc3PNrRLSCQ7ca8XR7h18VxdPIXhn+yvrYMdUFCHM7mhXGSPw5xBdbcf/dQ1cI4uE8pDfmm5uU+HX+WfFg==} + + '@polka/url@0.5.0': + resolution: {integrity: sha512-oZLYFEAzUKyi3SKnXvj32ZCEGH6RDnao7COuCVhDydMS9NrCSVXhM79VaKyP5+Zc33m0QXEd2DN3UkU7OsHcfw==} + + '@promptbook/utils@0.69.5': + resolution: {integrity: sha512-xm5Ti/Hp3o4xHrsK9Yy3MS6KbDxYbq485hDsFvxqaNA7equHLPdo8H8faTitTeb14QCDfLW4iwCxdVYu5sn6YQ==} + + '@puppeteer/browsers@1.4.6': + resolution: {integrity: sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==} + engines: {node: '>=16.3.0'} + hasBin: true + peerDependencies: + typescript: '>= 4.7.4' + peerDependenciesMeta: + typescript: + optional: true + + '@puppeteer/browsers@1.9.1': + resolution: {integrity: sha512-PuvK6xZzGhKPvlx3fpfdM2kYY3P/hB1URtK8wA7XUJ6prn6pp22zvJHu48th0SGcHL9SutbPHrFuQgfXTFobWA==} + engines: {node: '>=16.3.0'} + hasBin: true + + '@react-native-async-storage/async-storage@2.0.0': + resolution: {integrity: sha512-af6H9JjfL6G/PktBfUivvexoiFKQTJGQCtSWxMdivLzNIY94mu9DdiY0JqCSg/LyPCLGKhHPUlRQhNvpu3/KVA==} + peerDependencies: + react-native: ^0.0.0-0 || >=0.65 <1.0 + + '@react-native-community/cli-clean@13.6.9': + resolution: {integrity: sha512-7Dj5+4p9JggxuVNOjPbduZBAP1SUgNhLKVw5noBUzT/3ZpUZkDM+RCSwyoyg8xKWoE4OrdUAXwAFlMcFDPKykA==} + + '@react-native-community/cli-config@13.6.9': + resolution: {integrity: sha512-rFfVBcNojcMm+KKHE/xqpqXg8HoKl4EC7bFHUrahMJ+y/tZll55+oX/PGG37rzB8QzP2UbMQ19DYQKC1G7kXeg==} + + '@react-native-community/cli-debugger-ui@13.6.9': + resolution: {integrity: sha512-TkN7IdFmGPPvTpAo3nCAH9uwGCPxWBEAwpqEZDrq0NWllI7Tdie8vDpGdrcuCcKalmhq6OYnkXzeBah7O1Ztpw==} + + '@react-native-community/cli-doctor@13.6.9': + resolution: {integrity: sha512-5quFaLdWFQB+677GXh5dGU9I5eg2z6Vg4jOX9vKnc9IffwyIFAyJfCZHrxLSRPDGNXD7biDQUdoezXYGwb6P/A==} + + '@react-native-community/cli-hermes@13.6.9': + resolution: {integrity: sha512-GvwiwgvFw4Ws+krg2+gYj8sR3g05evmNjAHkKIKMkDTJjZ8EdyxbkifRUs1ZCq3TMZy2oeblZBXCJVOH4W7ZbA==} + + '@react-native-community/cli-platform-android@13.6.9': + resolution: {integrity: sha512-9KsYGdr08QhdvT3Ht7e8phQB3gDX9Fs427NJe0xnoBh+PDPTI2BD5ks5ttsH8CzEw8/P6H8tJCHq6hf2nxd9cw==} + + '@react-native-community/cli-platform-apple@13.6.9': + resolution: {integrity: sha512-KoeIHfhxMhKXZPXmhQdl6EE+jGKWwoO9jUVWgBvibpVmsNjo7woaG/tfJMEWfWF3najX1EkQAoJWpCDBMYWtlA==} + + '@react-native-community/cli-platform-ios@13.6.9': + resolution: {integrity: sha512-CiUcHlGs8vE0CAB4oi1f+dzniqfGuhWPNrDvae2nm8dewlahTBwIcK5CawyGezjcJoeQhjBflh9vloska+nlnw==} + + '@react-native-community/cli-server-api@13.6.9': + resolution: {integrity: sha512-W8FSlCPWymO+tlQfM3E0JmM8Oei5HZsIk5S0COOl0MRi8h0NmHI4WSTF2GCfbFZkcr2VI/fRsocoN8Au4EZAug==} + + '@react-native-community/cli-tools@13.6.9': + resolution: {integrity: sha512-OXaSjoN0mZVw3nrAwcY1PC0uMfyTd9fz7Cy06dh+EJc+h0wikABsVRzV8cIOPrVV+PPEEXE0DBrH20T2puZzgQ==} + + '@react-native-community/cli-types@13.6.9': + resolution: {integrity: sha512-RLxDppvRxXfs3hxceW/mShi+6o5yS+kFPnPqZTaMKKR5aSg7LwDpLQW4K2D22irEG8e6RKDkZUeH9aL3vO2O0w==} + + '@react-native-community/cli@13.6.9': + resolution: {integrity: sha512-hFJL4cgLPxncJJd/epQ4dHnMg5Jy/7Q56jFvA3MHViuKpzzfTCJCB+pGY54maZbtym53UJON9WTGpM3S81UfjQ==} + engines: {node: '>=18'} + hasBin: true + + '@react-native/assets-registry@0.74.87': + resolution: {integrity: sha512-1XmRhqQchN+pXPKEKYdpJlwESxVomJOxtEnIkbo7GAlaN2sym84fHEGDXAjLilih5GVPpcpSmFzTy8jx3LtaFg==} + engines: {node: '>=18'} + + '@react-native/babel-plugin-codegen@0.74.87': + resolution: {integrity: sha512-+vJYpMnENFrwtgvDfUj+CtVJRJuUnzAUYT0/Pb68Sq9RfcZ5xdcCuUgyf7JO+akW2VTBoJY427wkcxU30qrWWw==} + engines: {node: '>=18'} + + '@react-native/babel-preset@0.74.87': + resolution: {integrity: sha512-hyKpfqzN2nxZmYYJ0tQIHG99FQO0OWXp/gVggAfEUgiT+yNKas1C60LuofUsK7cd+2o9jrpqgqW4WzEDZoBlTg==} + engines: {node: '>=18'} + + '@react-native/codegen@0.74.87': + resolution: {integrity: sha512-GMSYDiD+86zLKgMMgz9z0k6FxmRn+z6cimYZKkucW4soGbxWsbjUAZoZ56sJwt2FJ3XVRgXCrnOCgXoH/Bkhcg==} + engines: {node: '>=18'} + peerDependencies: + '@babel/preset-env': ^7.1.6 + + '@react-native/community-cli-plugin@0.74.87': + resolution: {integrity: sha512-EgJG9lSr8x3X67dHQKQvU6EkO+3ksVlJHYIVv6U/AmW9dN80BEFxgYbSJ7icXS4wri7m4kHdgeq2PQ7/3vvrTQ==} + engines: {node: '>=18'} + + '@react-native/debugger-frontend@0.74.87': + resolution: {integrity: sha512-MN95DJLYTv4EqJc+9JajA3AJZSBYJz2QEJ3uWlHrOky2vKrbbRVaW1ityTmaZa2OXIvNc6CZwSRSE7xCoHbXhQ==} + engines: {node: '>=18'} + + '@react-native/dev-middleware@0.74.87': + resolution: {integrity: sha512-7TmZ3hTHwooYgIHqc/z87BMe1ryrIqAUi+AF7vsD+EHCGxHFdMjSpf1BZ2SUPXuLnF2cTiTfV2RwhbPzx0tYIA==} + engines: {node: '>=18'} + + '@react-native/gradle-plugin@0.74.87': + resolution: {integrity: sha512-T+VX0N1qP+U9V4oAtn7FTX7pfsoVkd1ocyw9swYXgJqU2fK7hC9famW7b3s3ZiufPGPr1VPJe2TVGtSopBjL6A==} + engines: {node: '>=18'} + + '@react-native/js-polyfills@0.74.87': + resolution: {integrity: sha512-M5Evdn76CuVEF0GsaXiGi95CBZ4IWubHqwXxV9vG9CC9kq0PSkoM2Pn7Lx7dgyp4vT7ccJ8a3IwHbe+5KJRnpw==} + engines: {node: '>=18'} + + '@react-native/metro-babel-transformer@0.74.87': + resolution: {integrity: sha512-UsJCO24sNax2NSPBmV1zLEVVNkS88kcgAiYrZHtYSwSjpl4WZ656tIeedBfiySdJ94Hr3kQmBYLipV5zk0NI1A==} + engines: {node: '>=18'} + + '@react-native/normalize-colors@0.74.87': + resolution: {integrity: sha512-Xh7Nyk/MPefkb0Itl5Z+3oOobeG9lfLb7ZOY2DKpFnoCE1TzBmib9vMNdFaLdSxLIP+Ec6icgKtdzYg8QUPYzA==} + + '@react-native/virtualized-lists@0.74.87': + resolution: {integrity: sha512-lsGxoFMb0lyK/MiplNKJpD+A1EoEUumkLrCjH4Ht+ZlG8S0BfCxmskLZ6qXn3BiDSkLjfjI/qyZ3pnxNBvkXpQ==} + engines: {node: '>=18'} + peerDependencies: + '@types/react': ^18.2.6 + react: '*' + react-native: '*' + peerDependenciesMeta: + '@types/react': + optional: true + + '@rnx-kit/chromium-edge-launcher@1.0.0': + resolution: {integrity: sha512-lzD84av1ZQhYUS+jsGqJiCMaJO2dn9u+RTT9n9q6D3SaKVwWqv+7AoRKqBu19bkwyE+iFRl1ymr40QS90jVFYg==} + engines: {node: '>=14.15'} + + '@rollup/plugin-alias@3.1.9': + resolution: {integrity: sha512-QI5fsEvm9bDzt32k39wpOwZhVzRcL5ydcffUHMyLVaVaLeC70I8TJZ17F1z1eMoLu4E/UOcH9BWVkKpIKdrfiw==} + engines: {node: '>=8.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0 + + '@rollup/plugin-commonjs@21.0.3': + resolution: {integrity: sha512-ThGfwyvcLc6cfP/MWxA5ACF+LZCvsuhUq7V5134Az1oQWsiC7lNpLT4mJI86WQunK7BYmpUiHmMk2Op6OAHs0g==} + engines: {node: '>= 8.0.0'} + peerDependencies: + rollup: ^2.38.3 + + '@rollup/plugin-json@4.1.0': + resolution: {integrity: sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==} + peerDependencies: + rollup: ^1.20.0 || ^2.0.0 + + '@rollup/plugin-node-resolve@13.1.3': + resolution: {integrity: sha512-BdxNk+LtmElRo5d06MGY4zoepyrXX1tkzX2hrnPEZ53k78GuOMWLqmJDGIIOPwVRIFZrLQOo+Yr6KtCuLIA0AQ==} + engines: {node: '>= 10.0.0'} + peerDependencies: + rollup: ^2.42.0 + + '@rollup/plugin-replace@4.0.0': + resolution: {integrity: sha512-+rumQFiaNac9y64OHtkHGmdjm7us9bo1PlbgQfdihQtuNxzjpaB064HbRnewUOggLQxVCCyINfStkgmBeQpv1g==} + peerDependencies: + rollup: ^1.20.0 || ^2.0.0 + + '@rollup/pluginutils@3.1.0': + resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} + engines: {node: '>= 8.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0 + + '@rollup/pluginutils@4.2.1': + resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} + engines: {node: '>= 8.0.0'} + + '@sideway/address@4.1.5': + resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} + + '@sideway/formula@3.0.1': + resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} + + '@sideway/pinpoint@2.0.0': + resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} + + '@sinclair/typebox@0.24.51': + resolution: {integrity: sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==} + + '@sinclair/typebox@0.27.8': + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + + '@sindresorhus/is@4.6.0': + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} + engines: {node: '>=10'} + + '@sindresorhus/is@5.6.0': + resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==} + engines: {node: '>=14.16'} + + '@sindresorhus/merge-streams@2.3.0': + resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} + engines: {node: '>=18'} + + '@sinonjs/commons@1.8.6': + resolution: {integrity: sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==} + + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@10.3.0': + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + + '@sinonjs/fake-timers@9.1.2': + resolution: {integrity: sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==} + + '@snowplow/webview-tracker@0.3.1': + resolution: {integrity: sha512-jQnflWxPFYwE4DeQ/JYTkRXiCUxZLkPyHybO7BI/Yp6R6dcLGx7uIZuX8F1zAmv+FKKkSXtEG4r52WD0jnoQxg==} + + '@szmarczak/http-timer@4.0.6': + resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} + engines: {node: '>=10'} + + '@szmarczak/http-timer@5.0.1': + resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} + engines: {node: '>=14.16'} + + '@testim/chrome-version@1.1.4': + resolution: {integrity: sha512-kIhULpw9TrGYnHp/8VfdcneIcxKnLixmADtukQRtJUmsVlMg0niMkwV0xZmi8hqa57xqilIHjWFA0GKvEjVU5g==} + + '@testing-library/dom@9.3.4': + resolution: {integrity: sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==} + engines: {node: '>=14'} + + '@tootallnate/once@1.1.2': + resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} + engines: {node: '>= 6'} + + '@tootallnate/once@2.0.0': + resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} + engines: {node: '>= 10'} + + '@tootallnate/quickjs-emscripten@0.23.0': + resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + + '@tsconfig/node10@1.0.11': + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.6.8': + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.20.6': + resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} + + '@types/cacheable-request@6.0.3': + resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} + + '@types/docker-modem@3.0.6': + resolution: {integrity: sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg==} + + '@types/dockerode@3.3.32': + resolution: {integrity: sha512-xxcG0g5AWKtNyh7I7wswLdFvym4Mlqks5ZlKzxEUrGHS0r0PUOfxm2T0mspwu10mHQqu3Ck3MI3V2HqvLWE1fg==} + + '@types/estree@0.0.39': + resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} + + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + + '@types/graceful-fs@4.1.9': + resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + + '@types/http-cache-semantics@4.0.4': + resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/jest@28.1.8': + resolution: {integrity: sha512-8TJkV++s7B6XqnDrzR1m/TT0A0h948Pnl/097veySPN67VRAgQ4gZ7n2KfJo2rVq6njQjdxU3GCCyDvAeuHoiw==} + + '@types/jsdom@16.2.15': + resolution: {integrity: sha512-nwF87yjBKuX/roqGYerZZM0Nv1pZDMAT5YhOHYeM/72Fic+VEqJh4nyoqoapzJnW3pUlfxPY5FhgsJtM+dRnQQ==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/jstimezonedetect@1.0.6': + resolution: {integrity: sha512-MKi1fgLzyqEWKgmvjwa+1p6k+phAACpFOK4eA1gBCHzbx4RyNGcO29IQWThGo1oKxSFa57gqm4iQn1lDaFJCQg==} + + '@types/keyv@3.1.4': + resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + + '@types/lodash@4.14.202': + resolution: {integrity: sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==} + + '@types/node-forge@1.3.11': + resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} + + '@types/node@14.6.4': + resolution: {integrity: sha512-Wk7nG1JSaMfMpoMJDKUsWYugliB2Vy55pdjLpmLixeyMi7HizW2I/9QoxsPCkXl3dO+ZOVqPumKaDUv5zJu2uQ==} + + '@types/node@16.18.122': + resolution: {integrity: sha512-rF6rUBS80n4oK16EW8nE75U+9fw0SSUgoPtWSvHhPXdT7itbvmS7UjB/jyM8i3AkvI6yeSM5qCwo+xN0npGDHg==} + + '@types/node@18.19.68': + resolution: {integrity: sha512-QGtpFH1vB99ZmTa63K4/FU8twThj4fuVSBkGddTp7uIL/cuoLWIUSL2RcOaigBhfR+hg5pgGkBnkoOxrTVBMKw==} + + '@types/node@20.17.10': + resolution: {integrity: sha512-/jrvh5h6NXhEauFFexRin69nA0uHJ5gwk4iDivp/DeoEua3uwCUto6PC86IpRITBOs4+6i2I56K5x5b6WYGXHA==} + + '@types/normalize-package-data@2.4.4': + resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + + '@types/object-path@0.11.4': + resolution: {integrity: sha512-4tgJ1Z3elF/tOMpA8JLVuR9spt9Ynsf7+JjqsQ2IqtiPJtcLoHoXcT6qU4E10cPFqyXX5HDm9QwIzZhBSkLxsw==} + + '@types/parse5@6.0.3': + resolution: {integrity: sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==} + + '@types/prettier@2.7.3': + resolution: {integrity: sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==} + + '@types/prop-types@15.7.14': + resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==} + + '@types/randomcolor@0.5.9': + resolution: {integrity: sha512-k58cfpkK15AKn1m+oRd9nh5BnuiowhbyvBBdAzcddtARMr3xRzP0VlFaAKovSG6N6Knx08EicjPlOMzDejerrQ==} + + '@types/react@18.3.18': + resolution: {integrity: sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==} + + '@types/resolve@1.17.1': + resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} + + '@types/responselike@1.0.3': + resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} + + '@types/semver@7.5.8': + resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} + + '@types/split2@4.2.3': + resolution: {integrity: sha512-59OXIlfUsi2k++H6CHgUQKEb2HKRokUA39HY1i1dS8/AIcqVjtAAFdf8u+HxTWK/4FUHMJQlKSZ4I6irCBJ1Zw==} + + '@types/ssh2@1.15.1': + resolution: {integrity: sha512-ZIbEqKAsi5gj35y4P4vkJYly642wIbY6PqoN0xiyQGshKUGXR9WQjF/iF9mXBQ8uBKy3ezfsCkcoHKhd0BzuDA==} + + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + '@types/tcp-port-used@1.0.4': + resolution: {integrity: sha512-0vQ4fz9TTM4bCdllYWEJ2JHBUXR9xqPtc70dJ7BMRDVfvZyYdrgey3nP5RRcVj+qAgnHJM8r9fvgrfnPMxdnhA==} + + '@types/tough-cookie@4.0.5': + resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + + '@types/ua-parser-js@0.7.39': + resolution: {integrity: sha512-P/oDfpofrdtF5xw433SPALpdSchtJmY7nsJItf8h3KXqOslkbySh8zq4dSWXH2oTjRvJ5PczVEoCZPow6GicLg==} + + '@types/vimeo__player@2.16.3': + resolution: {integrity: sha512-hsOe6CZFTNyfjRjQUrNHBF4LDmjvjcU2yQIPWp5AglKeGxt11JYGToQhKUPM876gBXggqR6rMQ0/sNI06ec2Rg==} + + '@types/which@2.0.2': + resolution: {integrity: sha512-113D3mDkZDjo+EeUEHCFy0qniNc1ZpecGiAU7WSo7YDoSzolZIQKpYFHrPpjkB2nuyahcKfrmLXeQlh7gqJYdw==} + + '@types/ws@8.5.13': + resolution: {integrity: sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==} + + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@15.0.19': + resolution: {integrity: sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==} + + '@types/yargs@17.0.33': + resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + + '@types/yauzl@2.10.3': + resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + + '@types/youtube@0.0.50': + resolution: {integrity: sha512-d4GpH4uPYp9W07kc487tiq6V/EUHl18vZWFMbQoe4Sk9LXEWzFi/BMf9x7TI4m7/j7gU3KeX8H6M8aPBgykeLw==} + + '@typescript-eslint/eslint-plugin@5.15.0': + resolution: {integrity: sha512-u6Db5JfF0Esn3tiAKELvoU5TpXVSkOpZ78cEGn/wXtT2RVqs2vkt4ge6N8cRCyw7YVKhmmLDbwI2pg92mlv7cA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/parser': ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/parser@5.15.0': + resolution: {integrity: sha512-NGAYP/+RDM2sVfmKiKOCgJYPstAO40vPAgACoWPO/+yoYKSgAXIFaBKsV8P0Cc7fwKgvj27SjRNX4L7f4/jCKQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/scope-manager@5.15.0': + resolution: {integrity: sha512-EFiZcSKrHh4kWk0pZaa+YNJosvKE50EnmN4IfgjkA3bTHElPtYcd2U37QQkNTqwMCS7LXeDeZzEqnsOH8chjSg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@typescript-eslint/type-utils@5.15.0': + resolution: {integrity: sha512-KGeDoEQ7gHieLydujGEFLyLofipe9PIzfvA/41urz4hv+xVxPEbmMQonKSynZ0Ks2xDhJQ4VYjB3DnRiywvKDA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/types@5.15.0': + resolution: {integrity: sha512-yEiTN4MDy23vvsIksrShjNwQl2vl6kJeG9YkVJXjXZnkJElzVK8nfPsWKYxcsGWG8GhurYXP4/KGj3aZAxbeOA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@typescript-eslint/typescript-estree@5.15.0': + resolution: {integrity: sha512-Hb0e3dGc35b75xLzixM3cSbG1sSbrTBQDfIScqdyvrfJZVEi4XWAT+UL/HMxEdrJNB8Yk28SKxPLtAhfCbBInA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/utils@5.15.0': + resolution: {integrity: sha512-081rWu2IPKOgTOhHUk/QfxuFog8m4wxW43sXNOMSCdh578tGJ1PAaWPsj42LOa7pguh173tNlMigsbrHvh/mtA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + + '@typescript-eslint/visitor-keys@5.15.0': + resolution: {integrity: sha512-+vX5FKtgvyHbmIJdxMJ2jKm9z2BIlXJiuewI8dsDYMp5LzPUcuTT78Ya5iwvQg3VqSVdmxyM8Anj1Jeq7733ZQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@vimeo/player@2.16.4': + resolution: {integrity: sha512-i+ids9ziQuai3mp8XzF9Q5b2hLgRCekRcefdnoy+RkKUR8Xq0cJndnk9jHugEOw8v6PLj7tO3eEAw4lu2/AG2Q==} + + '@vitest/pretty-format@2.1.8': + resolution: {integrity: sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==} + + '@vitest/snapshot@1.6.0': + resolution: {integrity: sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==} + + '@vitest/snapshot@2.1.8': + resolution: {integrity: sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==} + + '@wdio/cli@8.39.1': + resolution: {integrity: sha512-CUze/nbOMzgSEp+Qo27dnM5IhlOPAiBJCPX3xO85/kjweqqxmAB1QBKww1Mz9YlNIXineaHrkgqlUQIvEqOJdQ==} + engines: {node: ^16.13 || >=18} + hasBin: true + + '@wdio/config@8.39.0': + resolution: {integrity: sha512-yNuGPMPibY91s936gnJCHWlStvIyDrwLwGfLC/NCdTin4F7HL4Gp5iJnHWkJFty1/DfFi8jjoIUBNLM8HEez+A==} + engines: {node: ^16.13 || >=18} + + '@wdio/globals@8.39.1': + resolution: {integrity: sha512-kNb1TlxI8Le/tsOiw7CMQcG0+ZGyxk9ZDO/PQLxkJvjo/q2QmiBcgaNMPuf+j1ABETcQK4bI7QtiT5uZ+f2AGA==} + engines: {node: ^16.13 || >=18} + + '@wdio/jasmine-framework@8.39.1': + resolution: {integrity: sha512-WnoNvdVyj1HzBv8KpftNWsj7aCy5/v2NQt66lTewxG6KfxEFGgjCRVtnH46dK/HlOFGrh0J8qCTRZDYerUqR9w==} + engines: {node: ^16.13 || >=18} + + '@wdio/local-runner@8.39.1': + resolution: {integrity: sha512-VYRD7pSkl5JTsYXroM65yb+vJVn9pFJf0XZMB7Xj+WVUqGXuVkZ+XybsQetUlhruXvHIsPdiFj12V1tMyaUHrQ==} + engines: {node: ^16.13 || >=18} + + '@wdio/logger@8.38.0': + resolution: {integrity: sha512-kcHL86RmNbcQP+Gq/vQUGlArfU6IIcbbnNp32rRIraitomZow+iEoc519rdQmSVusDozMS5DZthkgDdxK+vz6Q==} + engines: {node: ^16.13 || >=18} + + '@wdio/logger@9.4.4': + resolution: {integrity: sha512-BXx8RXFUW2M4dcO6t5Le95Hi2ZkTQBRsvBQqLekT2rZ6Xmw8ZKZBPf0FptnoftFGg6dYmwnDidYv/0+4PiHjpQ==} + engines: {node: '>=18.20.0'} + + '@wdio/protocols@8.38.0': + resolution: {integrity: sha512-7BPi7aXwUtnXZPeWJRmnCNFjyDvGrXlBmN9D4Pi58nILkyjVRQKEY9/qv/pcdyB0cvmIvw++Kl/1Lg+RxG++UA==} + + '@wdio/repl@8.24.12': + resolution: {integrity: sha512-321F3sWafnlw93uRTSjEBVuvWCxTkWNDs7ektQS15drrroL3TMeFOynu4rDrIz0jXD9Vas0HCD2Tq/P0uxFLdw==} + engines: {node: ^16.13 || >=18} + + '@wdio/reporter@8.39.0': + resolution: {integrity: sha512-XahXhmaA1okdwg4/ThHFSqy/41KywxhbtszPcTzyXB+9INaqFNHA1b1vvWs0mrD5+tTtKbg4caTcEHVJU4iv0w==} + engines: {node: ^16.13 || >=18} + + '@wdio/runner@8.39.1': + resolution: {integrity: sha512-hCGI+TSAyb14UtdDjswI5AAdW1CZMi6di+rDZ6ml43hQyHc6sw+74CXI8dwoJ29dcTzbg7QCJZZXV1qMn0kh2w==} + engines: {node: ^16.13 || >=18} + + '@wdio/sauce-service@8.39.1': + resolution: {integrity: sha512-tt0oNqh2FxnR4JaMTwc7LRRLO03ERZxbZjeNf5IzK8PsjQ/JFUefeRBWmqoa93FVi3YGO8gUPCVElaS7OEqkRg==} + engines: {node: ^16.13 || >=18} + + '@wdio/shared-store-service@8.39.1': + resolution: {integrity: sha512-o6Hcd2BzMy8bjrNccb4Fw8hAqbd6wJ9fh24hdsp7KbRBymOMuYJajpCHzU5bFDFGr3rPL/wL0Ji671pY8gcS1g==} + engines: {node: ^16.13 || >=18} + + '@wdio/spec-reporter@8.39.0': + resolution: {integrity: sha512-2DX0+xvP+PyeVTBd6iGCH/RU66WXaa8HL+HpsJXZu5rSkZ4+6B2Tv8JB3ZE/pOWGNpI+B4ac/NfDs1DrX9sB7A==} + engines: {node: ^16.13 || >=18} + + '@wdio/static-server-service@8.39.0': + resolution: {integrity: sha512-blP4dLlPcNmVqu1YtCPOQVENePVpbZNSPAGixLRAe+db9gGLVZDD1c8TcUSabJ0yRUICpKlQ2otH/AHAib/+4w==} + engines: {node: ^16.13 || >=18} + + '@wdio/types@8.39.0': + resolution: {integrity: sha512-86lcYROTapOJuFd9ouomFDfzDnv3Kn+jE0RmqfvN9frZAeLVJ5IKjX9M6HjplsyTZhjGO1uCaehmzx+HJus33Q==} + engines: {node: ^16.13 || >=18} + + '@wdio/utils@8.39.0': + resolution: {integrity: sha512-jY+n6jlGeK+9Tx8T659PKLwMQTGpLW5H78CSEWgZLbjbVSr2LfGR8Lx0CRktNXxAtqEVZPj16Pi74OtAhvhE6Q==} + engines: {node: ^16.13 || >=18} + + '@wessberg/stringutil@1.0.19': + resolution: {integrity: sha512-9AZHVXWlpN8Cn9k5BC/O0Dzb9E9xfEMXzYrNunwvkUTvuK7xgQPVRZpLo+jWCOZ5r8oBa8NIrHuPEu1hzbb6bg==} + engines: {node: '>=8.0.0'} + + '@zip.js/zip.js@2.7.54': + resolution: {integrity: sha512-qMrJVg2hoEsZJjMJez9yI2+nZlBUxgYzGV3mqcb2B/6T1ihXp0fWBDYlVHlHquuorgNUQP5a8qSmX6HF5rFJNg==} + engines: {bun: '>=0.7.0', deno: '>=1.0.0', node: '>=16.5.0'} + + abab@2.0.6: + resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} + deprecated: Use your platform's native atob() and btoa() methods instead + + abbrev@1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + + acorn-globals@6.0.0: + resolution: {integrity: sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn-walk@7.2.0: + resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} + engines: {node: '>=0.4.0'} + + acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + engines: {node: '>=0.4.0'} + + acorn@7.4.1: + resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} + engines: {node: '>=0.4.0'} + hasBin: true + + acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + + agent-base@7.1.3: + resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} + engines: {node: '>= 14'} + + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} + engines: {node: '>= 8.0.0'} + + aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + + aggregate-error@4.0.1: + resolution: {integrity: sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==} + engines: {node: '>=12'} + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + anser@1.4.10: + resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==} + + ansi-align@3.0.1: + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + + ansi-fragments@0.2.1: + resolution: {integrity: sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w==} + + ansi-regex@2.1.1: + resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} + engines: {node: '>=0.10.0'} + + ansi-regex@4.1.1: + resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} + engines: {node: '>=6'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + appdirsjs@1.2.7: + resolution: {integrity: sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==} + + aproba@1.2.0: + resolution: {integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==} + + archiver-utils@5.0.2: + resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} + engines: {node: '>= 14'} + + archiver@7.0.1: + resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} + engines: {node: '>= 14'} + + are-we-there-yet@1.1.7: + resolution: {integrity: sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==} + deprecated: This package is no longer supported. + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.1.3: + resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + arkregex@0.0.5: + resolution: {integrity: sha512-ncYjBdLlh5/QnVsAA8De16Tc9EqmYM7y/WU9j+236KcyYNUXogpz3sC4ATIZYzzLxwI+0sEOaQLEmLmRleaEXw==} + + arktype@2.2.0: + resolution: {integrity: sha512-t54MZ7ti5BhOEvzEkgKnWvqj+UbDfWig+DHr5I34xatymPusKLS0lQpNJd8M6DzmIto2QGszHfNKoFIT8tMCZQ==} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-find-index@1.0.2: + resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==} + engines: {node: '>=0.10.0'} + + array-flatten@1.1.1: + resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + + arrgv@1.0.2: + resolution: {integrity: sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==} + engines: {node: '>=8.0.0'} + + arrify@3.0.0: + resolution: {integrity: sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==} + engines: {node: '>=12'} + + asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + + asn1@0.2.6: + resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} + + assert-plus@1.0.0: + resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} + engines: {node: '>=0.8'} + + ast-types@0.13.4: + resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} + engines: {node: '>=4'} + + ast-types@0.15.2: + resolution: {integrity: sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==} + engines: {node: '>=4'} + + astral-regex@1.0.0: + resolution: {integrity: sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==} + engines: {node: '>=4'} + + async-exit-hook@2.0.1: + resolution: {integrity: sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==} + engines: {node: '>=0.12.0'} + + async-limiter@1.0.1: + resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + ava@5.1.1: + resolution: {integrity: sha512-od1CWgWVIKZSdEc1dhQWhbsd6KBs0EYjek7eqZNGPvy+NyC9Q1bXixcadlgOXwDG9aM0zLMQZwRXfe9gMb1LQQ==} + engines: {node: '>=14.19 <15 || >=16.15 <17 || >=18'} + hasBin: true + peerDependencies: + '@ava/typescript': '*' + peerDependenciesMeta: + '@ava/typescript': + optional: true + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + aws-sign2@0.7.0: + resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} + + aws4@1.13.2: + resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} + + axios@1.7.9: + resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==} + + b4a@1.6.7: + resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==} + + babel-core@7.0.0-bridge.0: + resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + babel-jest@28.1.3: + resolution: {integrity: sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + + babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + + babel-plugin-jest-hoist@28.1.3: + resolution: {integrity: sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + babel-plugin-polyfill-corejs2@0.4.12: + resolution: {integrity: sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-corejs2@0.4.17: + resolution: {integrity: sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-corejs3@0.10.6: + resolution: {integrity: sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-corejs3@0.14.2: + resolution: {integrity: sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-regenerator@0.6.3: + resolution: {integrity: sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-regenerator@0.6.8: + resolution: {integrity: sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-syntax-hermes-parser@0.34.0: + resolution: {integrity: sha512-q4xeAymMrot/21MHA3+fd5mcFF7stx6ntKFO/Of5ldyDpgTBcK1l0NiHAh4NdHHdb4aHqHgQOy7r6yk0IIlz8Q==} + + babel-plugin-transform-flow-enums@0.0.2: + resolution: {integrity: sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==} + + babel-preset-current-node-syntax@1.1.0: + resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==} + peerDependencies: + '@babel/core': ^7.0.0 + + babel-preset-jest@28.1.3: + resolution: {integrity: sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + peerDependencies: + '@babel/core': ^7.0.0 + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + bare-events@2.5.0: + resolution: {integrity: sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==} + + bare-fs@2.3.5: + resolution: {integrity: sha512-SlE9eTxifPDJrT6YgemQ1WGFleevzwY+XAP1Xqgl56HtcrisC2CHCZ2tq6dBpcH2TnNxwUEUGhweo+lrQtYuiw==} + + bare-os@2.4.4: + resolution: {integrity: sha512-z3UiI2yi1mK0sXeRdc4O1Kk8aOa/e+FNWZcTiPB/dfTWyLypuE99LibgRaQki914Jq//yAWylcAt+mknKdixRQ==} + + bare-path@2.1.3: + resolution: {integrity: sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==} + + bare-stream@2.6.1: + resolution: {integrity: sha512-eVZbtKM+4uehzrsj49KtCy3Pbg7kO1pJ3SKZ1SFrIH/0pnj9scuGGgUlNDf/7qS8WKtGdiJY5Kyhs/ivYPTB/g==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + baseline-browser-mapping@2.10.36: + resolution: {integrity: sha512-lVq/Df7LXlO79MVaaUHztSwWiG9oXoWHlgvNS51v8Dpd4+G4/VIy6qYePTw31nAVls33nUtnfezYeLkYAak9dg==} + engines: {node: '>=6.0.0'} + hasBin: true + + basic-auth@2.0.1: + resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==} + engines: {node: '>= 0.8'} + + basic-ftp@5.0.5: + resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} + engines: {node: '>=10.0.0'} + + bcrypt-pbkdf@1.0.2: + resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + bl@1.2.3: + resolution: {integrity: sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + blueimp-md5@2.19.0: + resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} + + body-parser@1.20.3: + resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + boxen@5.1.2: + resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==} + engines: {node: '>=10'} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + brace-expansion@5.0.6: + resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} + engines: {node: 18 || 20 || >=22} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + brotli-size@4.0.0: + resolution: {integrity: sha512-uA9fOtlTRC0iqKfzff1W34DXUA3GyVqbUaeo3Rw3d4gd1eavKVCETXrn3NzO74W+UVkG3UHu8WxUi+XvKI/huA==} + engines: {node: '>= 10.16.0'} + + browser-process-hrtime@1.0.0: + resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==} + + browserslist-generator@1.0.66: + resolution: {integrity: sha512-aFDax4Qzh29DdyhHQBD2Yu2L5OvaDnvYFMbmpLrLwwaNK4H6dHEhC/Nxv93/+mfAA+a/t94ln0P2JZvHO6LZDA==} + engines: {node: '>=8.0.0'} + + browserslist@4.20.2: + resolution: {integrity: sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + browserslist@4.24.3: + resolution: {integrity: sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bs-logger@0.2.6: + resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} + engines: {node: '>= 6'} + + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + + buffer-alloc-unsafe@1.1.0: + resolution: {integrity: sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==} + + buffer-alloc@1.2.0: + resolution: {integrity: sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==} + + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + + buffer-crc32@1.0.0: + resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} + engines: {node: '>=8.0.0'} + + buffer-fill@1.0.0: + resolution: {integrity: sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + + buildcheck@0.0.6: + resolution: {integrity: sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==} + engines: {node: '>=10.0.0'} + + builtin-modules@3.3.0: + resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} + engines: {node: '>=6'} + + builtins@1.0.3: + resolution: {integrity: sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + cacache@15.3.0: + resolution: {integrity: sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==} + engines: {node: '>= 10'} + + cacheable-lookup@5.0.4: + resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} + engines: {node: '>=10.6.0'} + + cacheable-lookup@7.0.0: + resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==} + engines: {node: '>=14.16'} + + cacheable-request@10.2.14: + resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==} + engines: {node: '>=14.16'} + + cacheable-request@7.0.4: + resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.1: + resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.3: + resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} + engines: {node: '>= 0.4'} + + caller-callsite@2.0.0: + resolution: {integrity: sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==} + engines: {node: '>=4'} + + caller-path@2.0.0: + resolution: {integrity: sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==} + engines: {node: '>=4'} + + callsites@2.0.0: + resolution: {integrity: sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==} + engines: {node: '>=4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + callsites@4.2.0: + resolution: {integrity: sha512-kfzR4zzQtAE9PC7CzZsjl3aBNbXWuXiSeOCdLcPpBfGW8YuCqQHcRPFDbr/BPVmd3EEPVpuFzLyuT/cUhPr4OQ==} + engines: {node: '>=12.20'} + + camel-case@4.1.2: + resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} + + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-lite@1.0.30001690: + resolution: {integrity: sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==} + + caniuse-lite@1.0.30001799: + resolution: {integrity: sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==} + + capital-case@1.0.4: + resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==} + + caseless@0.12.0: + resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} + + cbor@8.1.0: + resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} + engines: {node: '>=12.19'} + + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.4.1: + resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + change-case@4.1.2: + resolution: {integrity: sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==} + + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + + chardet@0.7.0: + resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + + chownr@2.0.0: + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} + + chrome-launcher@0.15.2: + resolution: {integrity: sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==} + engines: {node: '>=12.13.0'} + hasBin: true + + chromedriver@131.0.4: + resolution: {integrity: sha512-JgIkept8YrnqT05ldLaOzxxEJDUV1t3PFIIMO/gQz9AbnpZx7Pl1zq6tQTTz2HoY5T2JKZ5kyiEWwc48g4fJ5w==} + engines: {node: '>=18'} + hasBin: true + + chromium-bidi@0.4.16: + resolution: {integrity: sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==} + peerDependencies: + devtools-protocol: '*' + + chunkd@2.0.1: + resolution: {integrity: sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==} + + ci-info@2.0.0: + resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + ci-parallel-vars@1.0.1: + resolution: {integrity: sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==} + + cjs-module-lexer@1.4.1: + resolution: {integrity: sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==} + + clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + + clean-stack@4.2.0: + resolution: {integrity: sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==} + engines: {node: '>=12'} + + clean-yaml-object@0.1.0: + resolution: {integrity: sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==} + engines: {node: '>=0.10.0'} + + cli-boxes@2.2.1: + resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==} + engines: {node: '>=6'} + + cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + + cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} + + cli-truncate@3.1.0: + resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} + + cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + cliui@9.0.1: + resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} + engines: {node: '>=20'} + + clone-deep@4.0.1: + resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} + engines: {node: '>=6'} + + clone-response@1.0.3: + resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} + + clone@1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + + co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + + code-excerpt@4.0.0: + resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + code-point-at@1.1.0: + resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==} + engines: {node: '>=0.10.0'} + + collect-v8-coverage@1.0.2: + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + colorette@1.4.0: + resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} + + colors@1.4.0: + resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} + engines: {node: '>=0.1.90'} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + command-exists@1.2.9: + resolution: {integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + + commenting@1.1.0: + resolution: {integrity: sha512-YeNK4tavZwtH7jEgK1ZINXzLKm6DZdEMfsaaieOsCAN0S8vsY7UeuO3Q7d/M018EFgE+IeUAuBOKkFccBZsUZA==} + + common-path-prefix@3.0.0: + resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} + + commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + + compare-versions@6.1.1: + resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} + + compatfactory@0.0.13: + resolution: {integrity: sha512-k9Sl/Qal3xQPnjAFZaRpl7jlCh0hDEhVaxyiTMfiHKC/w5TYn4Nds+7340X/v1OrAQC5xGBtaD2JpWgPhXWaAw==} + engines: {node: '>=10.0.0'} + peerDependencies: + typescript: '>=3.x || >= 4.x' + + compress-commons@6.0.2: + resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} + engines: {node: '>= 14'} + + compressible@2.0.18: + resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} + engines: {node: '>= 0.6'} + + compressing@1.10.1: + resolution: {integrity: sha512-XXwUffcVjqv8NGSQu1ttp6eMmuZ3zZEAec28Rt30o/vkXE20jXhowRQ9LXLY4uOgFkxXrNzApLobpam53Dc1AA==} + engines: {node: '>= 4.0.0'} + + compression@1.7.5: + resolution: {integrity: sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==} + engines: {node: '>= 0.8.0'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + concordance@5.0.4: + resolution: {integrity: sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==} + engines: {node: '>=10.18.0 <11 || >=12.14.0 <13 || >=14'} + + connect@3.7.0: + resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} + engines: {node: '>= 0.10.0'} + + console-control-strings@1.1.0: + resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} + + constant-case@3.0.4: + resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==} + + content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + convert-to-spaces@2.0.1: + resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + cookie-signature@1.0.6: + resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + + cookie@0.7.1: + resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} + engines: {node: '>= 0.6'} + + core-js-compat@3.39.0: + resolution: {integrity: sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==} + + core-js-compat@3.49.0: + resolution: {integrity: sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==} + + core-util-is@1.0.2: + resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + cosmiconfig@5.2.1: + resolution: {integrity: sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==} + engines: {node: '>=4'} + + cpu-features@0.0.10: + resolution: {integrity: sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==} + engines: {node: '>=10.0.0'} + + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + crc32-stream@6.0.0: + resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} + engines: {node: '>= 14'} + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + + cross-fetch@4.0.0: + resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==} + + cross-spawn@6.0.6: + resolution: {integrity: sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==} + engines: {node: '>=4.8'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + crosspath@1.0.0: + resolution: {integrity: sha512-mpjkSErNO6vioL/Cde2aF4UBysPFEMyn+1AN1t7Oc4yqvzSRWe8iBte4P8BHyjo64OmC+ZBxwjIqmpSpIWiQ7Q==} + engines: {node: '>=10.0.0'} + + css-shorthand-properties@1.1.2: + resolution: {integrity: sha512-C2AugXIpRGQTxaCW0N7n5jD/p5irUmCrwl03TrnMFBHDbdq44CFWR2zO7rK9xPN4Eo3pUxC4vQzQgbIpzrD1PQ==} + + css-value@0.0.1: + resolution: {integrity: sha512-FUV3xaJ63buRLgHrLQVlVgQnQdR4yqdLGaDu7g8CQcWjInDfM9plBTPI9FRfpahju1UBSaMckeb2/46ApS/V1Q==} + + cssom@0.3.8: + resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} + + cssom@0.5.0: + resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==} + + cssstyle@2.3.0: + resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==} + engines: {node: '>=8'} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + currently-unhandled@0.4.1: + resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} + engines: {node: '>=0.10.0'} + + dashdash@1.14.1: + resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} + engines: {node: '>=0.10'} + + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + + data-uri-to-buffer@6.0.2: + resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} + engines: {node: '>= 14'} + + data-urls@3.0.2: + resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==} + engines: {node: '>=12'} + + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + + date-time@3.1.0: + resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==} + engines: {node: '>=6'} + + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + + debug@4.3.1: + resolution: {integrity: sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + + decamelize@6.0.0: + resolution: {integrity: sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + decimal.js@10.4.3: + resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} + + decode-uri-component@0.2.2: + resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} + engines: {node: '>=0.10'} + + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + dedent@0.7.0: + resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} + + dedent@1.7.2: + resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + + deep-equal@2.2.3: + resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==} + engines: {node: '>= 0.4'} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + deepmerge-ts@5.1.0: + resolution: {integrity: sha512-eS8dRJOckyo9maw9Tu5O5RUi/4inFLrnoLkBe3cPfDMx3WZioXtmOew4TXQaxq7Rhl4xjDtR7c6x8nNTxOvbFw==} + engines: {node: '>=16.0.0'} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + defaults@1.0.4: + resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + + defer-to-connect@2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + degenerator@5.0.1: + resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} + engines: {node: '>= 14'} + + del@7.1.0: + resolution: {integrity: sha512-v2KyNk7efxhlyHpjEvfyxaAihKKK0nWCuf6ZtqZcFFpQRG0bJ12Qsr0RpvsICMjAAZ8DOVCxrlqpxISlMHC4Kg==} + engines: {node: '>=14.16'} + + del@8.0.1: + resolution: {integrity: sha512-gPqh0mKTPvaUZGAuHbrBUYKZWBNAeHG7TU3QH5EhVwPMyKvmfJaNXhcD2jTcXsJRRcffuho4vaYweu80dRrMGA==} + engines: {node: '>=18'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + delegates@1.0.0: + resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} + + denodeify@1.2.1: + resolution: {integrity: sha512-KNTihKNmQENUZeKu5fzfpzRqR5S2VMp4gl9RFHiWzj9DfvYQPMJ6XHKNaQxaGCXwPk6y9yme3aUoaiAe+KX+vg==} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + + devtools-protocol@0.0.1147663: + resolution: {integrity: sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==} + + devtools-protocol@0.0.1302984: + resolution: {integrity: sha512-Rgh2Sk5fUSCtEx4QGH9iwTyECdFPySG2nlz5J8guGh2Wlha6uzSOCq/DCEC8faHlLaMPZJMuZ4ovgcX4LvOkKA==} + + diff-sequences@28.1.1: + resolution: {integrity: sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + + diff@5.2.0: + resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} + engines: {node: '>=0.3.1'} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + docker-modem@3.0.8: + resolution: {integrity: sha512-f0ReSURdM3pcKPNS30mxOHSbaFLcknGmQjwSfmbcdOw1XWKXVhukM3NJHhr7NpY9BIyyWQb0EBo3KQvvuU5egQ==} + engines: {node: '>= 8.0'} + + dockerode@3.3.5: + resolution: {integrity: sha512-/0YNa3ZDNeLr/tSckmD69+Gq+qVNhvKfAHNeZJBnp7EOP6RGKV8ORrJHkUn20So5wU+xxT7+1n5u8PjHbfjbSA==} + engines: {node: '>= 8.0'} + + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + + domexception@4.0.0: + resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} + engines: {node: '>=12'} + deprecated: Use your platform's native DOMException instead + + dot-case@3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + + dotenv@16.4.7: + resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} + engines: {node: '>=12'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + duplexer@0.1.1: + resolution: {integrity: sha512-sxNZ+ljy+RA1maXoUReeqBBpBC6RLKmg5ewzV+x+mSETmWNoKdZN6vcQjpFROemza23hGFskJtFNoUWUaQ+R4Q==} + + duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + easy-table@1.2.0: + resolution: {integrity: sha512-OFzVOv03YpvtcWGe5AayU5G2hgybsg3iqA6drU8UaoZyB9jLGMTrz9+asnLp/E+6qPh88yEI1gvyZFZ41dmgww==} + + ecc-jsbn@0.1.2: + resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} + + edge-paths@3.0.5: + resolution: {integrity: sha512-sB7vSrDnFa4ezWQk9nZ/n0FdpdUuC6R1EOrlU3DL+bovcNFK28rqu2emmAUjujYEJTWIgQGqgVVWUZXMnc8iWg==} + engines: {node: '>=14.0.0'} + + edgedriver@5.6.1: + resolution: {integrity: sha512-3Ve9cd5ziLByUdigw6zovVeWJjVs8QHVmqOB0sJ0WNeVPcwf4p18GnxMmVvlFmYRloUwf5suNuorea4QzwBIOA==} + hasBin: true + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} + hasBin: true + + electron-to-chromium@1.5.372: + resolution: {integrity: sha512-M3yhbAlilnwqC8D21t28UCDGHyitShTmmLRU/H+b74P6Ski16Nb9HONYEaVpMj/pwC7BEo5B95FpjODLCWbtfA==} + + electron-to-chromium@1.5.76: + resolution: {integrity: sha512-CjVQyG7n7Sr+eBXE86HIulnL5N8xZY1sgmOPGuq/F0Rr0FJq63lg0kEtOIDfZBk44FnDLf6FUJ+dsJcuiUDdDQ==} + + emittery@0.10.2: + resolution: {integrity: sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==} + engines: {node: '>=12'} + + emittery@1.0.3: + resolution: {integrity: sha512-tJdCJitoy2lrC2ldJcqN4vkqJ00lT+tOWNT1hBJjO/3FDMJa5TTIiYGCKGkn/WfCyOzUMObeohbVTj00fhiLiA==} + engines: {node: '>=14.16'} + + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + encoding@0.1.13: + resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} + + end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + + enhance-visitors@1.0.0: + resolution: {integrity: sha512-+29eJLiUixTEDRaZ35Vu8jP3gPLNcQQkQkOQjLp2X+6cZGGPDD/uasbFzvLsJKnGZnvmyZ0srxudwOtskHeIDA==} + engines: {node: '>=4.0.0'} + + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + + envinfo@7.14.0: + resolution: {integrity: sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==} + engines: {node: '>=4'} + hasBin: true + + err-code@2.0.3: + resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + + error-stack-parser@2.1.4: + resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} + + errorhandler@1.5.1: + resolution: {integrity: sha512-rcOwbfvP1WTViVoUjcfZicVzjhjTuhSMntHh6mW3IrEiyE6mJyXvsToJUJGlGlw/2xU9P5whlWNGlIDVeCiT4A==} + engines: {node: '>= 0.8'} + + es-abstract@1.23.8: + resolution: {integrity: sha512-lfab8IzDn6EpI1ibZakcgS6WsfEBiB+43cuJo+wgylx1xKXf+Sp+YR3vFuQwC/u3sxYwV8Cxe3B0DpVUu/WiJQ==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-get-iterator@1.1.3: + resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} + + es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.0.3: + resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + + eslint-plugin-ava@13.2.0: + resolution: {integrity: sha512-i5B5izsEdERKQLruk1nIWzTTE7C26/ju8qQf7JeyRv32XT2lRMW0zMFZNhIrEf5/5VvpSz2rqrV7UcjClGbKsw==} + engines: {node: '>=12.22 <13 || >=14.17 <15 || >=16.4'} + peerDependencies: + eslint: '>=7.22.0' + + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-utils@3.0.0: + resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} + engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} + peerDependencies: + eslint: '>=5' + + eslint-visitor-keys@2.1.0: + resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} + engines: {node: '>=10'} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint@8.11.0: + resolution: {integrity: sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + espurify@2.1.1: + resolution: {integrity: sha512-zttWvnkhcDyGOhSH4vO2qCBILpdCMv/MX8lp4cqgRkQoDRGK2oZxi2GfWhlP2dIXmk7BaKeOTuzbHhyC68o8XQ==} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@0.6.1: + resolution: {integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==} + + estree-walker@1.0.1: + resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + + exit@0.1.2: + resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + engines: {node: '>= 0.8.0'} + + expect-webdriverio@4.15.4: + resolution: {integrity: sha512-Op1xZoevlv1pohCq7g2Og5Gr3xP2NhY7MQueOApmopVxgweoJ/BqJxyvMNP0A//QsMg8v0WsN/1j81Sx2er9Wg==} + engines: {node: '>=16 || >=18 || >=20'} + + expect@28.1.3: + resolution: {integrity: sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + exponential-backoff@3.1.1: + resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==} + + express@4.21.2: + resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} + engines: {node: '>= 0.10.0'} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + external-editor@3.1.0: + resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} + engines: {node: '>=4'} + + extract-zip@2.0.1: + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + + extsprintf@1.3.0: + resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} + engines: {'0': node >=0.6.0} + + fast-base64-decode@1.0.0: + resolution: {integrity: sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==} + + fast-deep-equal@2.0.1: + resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + + fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-xml-parser@4.5.1: + resolution: {integrity: sha512-y655CeyUQ+jj7KBbYMc4FG01V8ZQqjN+gDYGJ50RtfsUB8iG9AmwmwoAgeKLJdmueKKMrH1RJ7yXHTSoczdv5w==} + hasBin: true + + fastq@1.18.0: + resolution: {integrity: sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==} + + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + + fd-slicer2@1.2.0: + resolution: {integrity: sha512-3lBUNUckhMZduCc4g+Pw4Ve16LD9vpX9b8qUkkKq2mgDRLYWzblszZH2luADnJqjJe+cypngjCuKRm/IW12rRw==} + + fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + + figures@5.0.0: + resolution: {integrity: sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==} + engines: {node: '>=14'} + + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + + filelist@1.0.4: + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + + filesize@6.4.0: + resolution: {integrity: sha512-mjFIpOHC4jbfcTfoh4rkWpI31mF7viw9ikj/JyLoKzqlwG/YsefKfvYlYhdYdg/9mtK2z1AzgN/0LvVQ3zdlSQ==} + engines: {node: '>= 0.4.0'} + + filesize@9.0.11: + resolution: {integrity: sha512-gTAiTtI0STpKa5xesyTA9hA3LX4ga8sm2nWRcffEa1L/5vQwb4mj2MdzMkoHoGv4QzfDshQZuYscQSf8c4TKOA==} + engines: {node: '>= 0.4.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + filter-obj@1.1.0: + resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==} + engines: {node: '>=0.10.0'} + + finalhandler@1.1.2: + resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} + engines: {node: '>= 0.8'} + + finalhandler@1.3.1: + resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} + engines: {node: '>= 0.8'} + + find-cache-dir@2.1.0: + resolution: {integrity: sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==} + engines: {node: '>=6'} + + find-up@3.0.0: + resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} + engines: {node: '>=6'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + find-up@6.3.0: + resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + + flatted@3.3.2: + resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==} + + flow-enums-runtime@0.0.6: + resolution: {integrity: sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==} + + flow-parser@0.257.1: + resolution: {integrity: sha512-7+KYDpAXyBPD/wODhbPYO6IGUx+WwtJcLLG/r3DvbNyxaDyuYaTBKbSqeCldWQzuFcj+MsOVx2bpkEwVPB9JRw==} + engines: {node: '>=0.4.0'} + + flushwritable@1.0.0: + resolution: {integrity: sha512-3VELfuWCLVzt5d2Gblk8qcqFro6nuwvxwMzHaENVDHI7rxcBRtMCwTk/E9FXcgh+82DSpavPNDueA9+RxXJoFg==} + + follow-redirects@1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + + foreground-child@3.3.0: + resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} + engines: {node: '>=14'} + + forever-agent@0.6.1: + resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} + + form-data-encoder@2.1.4: + resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} + engines: {node: '>= 14.17'} + + form-data@2.3.3: + resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} + engines: {node: '>= 0.12'} + + form-data@4.0.1: + resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} + engines: {node: '>= 6'} + + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + + fs-extra@11.2.0: + resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} + engines: {node: '>=14.14'} + + fs-extra@11.3.5: + resolution: {integrity: sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==} + engines: {node: '>=14.14'} + + fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + + fs-minipass@2.1.0: + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + + functional-red-black-tree@1.0.1: + resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + gauge@2.7.4: + resolution: {integrity: sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==} + deprecated: This package is no longer supported. + + gaze@1.1.3: + resolution: {integrity: sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==} + engines: {node: '>= 4.0.0'} + + geckodriver@4.5.1: + resolution: {integrity: sha512-lGCRqPMuzbRNDWJOQcUqhNqPvNsIFu6yzXF8J/6K3WCYFd2r5ckbeF7h1cxsnjA7YLSEiWzERCt6/gjZ3tW0ug==} + engines: {node: ^16.13 || >=18 || >=20} + hasBin: true + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-east-asian-width@1.6.0: + resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} + engines: {node: '>=18'} + + get-intrinsic@1.2.6: + resolution: {integrity: sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==} + engines: {node: '>= 0.4'} + + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + + get-port@7.1.0: + resolution: {integrity: sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==} + engines: {node: '>=16'} + + get-ready@1.0.0: + resolution: {integrity: sha512-mFXCZPJIlcYcth+N8267+mghfYN9h3EhsDa6JSnbA3Wrhh/XFpuowviFcsDeYZtKspQyWyJqfs4O6P8CHeTwzw==} + + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + + get-uri@6.0.4: + resolution: {integrity: sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==} + engines: {node: '>= 14'} + + getpass@0.1.7: + resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + + glob@13.0.6: + resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + engines: {node: 18 || 20 || >=22} + + glob@7.1.7: + resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + + glob@7.2.0: + resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} + deprecated: Glob versions prior to v9 are no longer supported + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + globby@13.2.2: + resolution: {integrity: sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + globby@14.1.0: + resolution: {integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==} + engines: {node: '>=18'} + + globule@1.3.4: + resolution: {integrity: sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==} + engines: {node: '>= 0.10'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + got@11.8.6: + resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} + engines: {node: '>=10.19.0'} + + got@12.6.1: + resolution: {integrity: sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==} + engines: {node: '>=14.16'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + grapheme-splitter@1.0.4: + resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} + + gzip-size@6.0.0: + resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==} + engines: {node: '>=10'} + + har-schema@2.0.0: + resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==} + engines: {node: '>=4'} + + har-validator@5.1.5: + resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==} + engines: {node: '>=6'} + deprecated: this library is no longer supported + + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + has-unicode@2.0.1: + resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} + + hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + header-case@2.0.4: + resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==} + + helpertypes@0.0.18: + resolution: {integrity: sha512-XRhfbSEmR+poXUC5/8AbmYNJb2riOT6qPzjGJZr0S9YedHiaY+/tzPYzWMUclYMEdCYo/1l8PDYrQFCj02v97w==} + engines: {node: '>=10.0.0'} + + hermes-estree@0.19.1: + resolution: {integrity: sha512-daLGV3Q2MKk8w4evNMKwS8zBE/rcpA800nu1Q5kM08IKijoSnPe9Uo1iIxzPKRkn95IxxsgBMPeYHt3VG4ej2g==} + + hermes-estree@0.23.1: + resolution: {integrity: sha512-eT5MU3f5aVhTqsfIReZ6n41X5sYn4IdQL0nvz6yO+MMlPxw49aSARHLg/MSehQftyjnrE8X6bYregzSumqc6cg==} + + hermes-estree@0.34.0: + resolution: {integrity: sha512-6qLylexjmuKa/YYhMiNn/3VejBsdzwmYUGmNpc693/pJzymmbufhkRW/2K6GqFgu0ApRWoqF0NbM6u82jFcOXA==} + + hermes-parser@0.19.1: + resolution: {integrity: sha512-Vp+bXzxYJWrpEuJ/vXxUsLnt0+y4q9zyi4zUlkLqD8FKv4LjIfOvP69R/9Lty3dCyKh0E2BU7Eypqr63/rKT/A==} + + hermes-parser@0.23.1: + resolution: {integrity: sha512-oxl5h2DkFW83hT4DAUJorpah8ou4yvmweUzLJmmr6YV2cezduCdlil1AvU/a/xSsAFo4WUcNA4GoV5Bvq6JffA==} + + hermes-parser@0.34.0: + resolution: {integrity: sha512-tcgan5UNZvu3WwmR3jDAlmwEAR2CMv8cwQVMe5j0NrLQkstf0l3ULbYPuTZWbXxbPa0PyZPiq5LYEcFVmhM9LQ==} + + hermes-profile-transformer@0.0.6: + resolution: {integrity: sha512-cnN7bQUm65UWOy6cbGcCcZ3rpwW8Q/j4OP5aWRhEry4Z2t2aR1cjrbp0BS+KiBN0smvP1caBgAuxutvyvJILzQ==} + engines: {node: '>=8'} + + hosted-git-info@2.8.9: + resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + + hosted-git-info@4.1.0: + resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} + engines: {node: '>=10'} + + hosted-git-info@7.0.2: + resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} + engines: {node: ^16.14.0 || >=18.0.0} + + html-encoding-sniffer@3.0.0: + resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} + engines: {node: '>=12'} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + http-cache-semantics@4.1.1: + resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + + http-proxy-agent@4.0.1: + resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==} + engines: {node: '>= 6'} + + http-proxy-agent@5.0.0: + resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} + engines: {node: '>= 6'} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + http-signature@1.2.0: + resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==} + engines: {node: '>=0.8', npm: '>=1.3.7'} + + http2-wrapper@1.0.3: + resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} + engines: {node: '>=10.19.0'} + + http2-wrapper@2.2.1: + resolution: {integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==} + engines: {node: '>=10.19.0'} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + + iconv-lite@0.5.2: + resolution: {integrity: sha512-kERHXvpSaB4aU3eANwidg79K8FlrN77m8G9V+0vOR3HYaRifrlwMEpT7ZBJqLSEIHnEgJTHcWK82wwLwwKwtag==} + engines: {node: '>=0.10.0'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore-by-default@2.1.0: + resolution: {integrity: sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==} + engines: {node: '>=10 <11 || >=12 <13 || >=14'} + + ignore-walk@3.0.4: + resolution: {integrity: sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + image-size@1.2.0: + resolution: {integrity: sha512-4S8fwbO6w3GeCVN6OPtA9I5IGKkcDMPcKndtUlpJuCwu7JLjtj7JZpwqLuyY2nrmQT3AWsCJLSKPsc2mPBSl3w==} + engines: {node: '>=16.x'} + hasBin: true + + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + + import-fresh@2.0.0: + resolution: {integrity: sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==} + engines: {node: '>=4'} + + import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + + import-local@3.2.0: + resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} + engines: {node: '>=8'} + hasBin: true + + import-meta-resolve@4.1.0: + resolution: {integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==} + + import-modules@2.1.0: + resolution: {integrity: sha512-8HEWcnkbGpovH9yInoisxaSoIg9Brbul+Ju3Kqe2UsYDUBJD/iQjSgEj0zPcTDPKfPp2fs5xlv1i+JSye/m1/A==} + engines: {node: '>=8'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + + indent-string@5.0.0: + resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} + engines: {node: '>=12'} + + infer-owner@1.0.4: + resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.3: + resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + inquirer@9.2.12: + resolution: {integrity: sha512-mg3Fh9g2zfuVWJn6lhST0O7x4n03k7G8Tx5nvikJkbq8/CK47WDVm+UznF0G6s5Zi0KcyUisr6DU8T67N5U+1Q==} + engines: {node: '>=14.18.0'} + + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + + invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + + ip-address@9.0.5: + resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} + engines: {node: '>= 12'} + + ip-regex@4.3.0: + resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==} + engines: {node: '>=8'} + + ip@2.0.1: + resolution: {integrity: sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + irregular-plurals@3.5.0: + resolution: {integrity: sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==} + engines: {node: '>=8'} + + is-arguments@1.2.0: + resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} + engines: {node: '>= 0.4'} + + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-async-function@2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-boolean-object@1.2.1: + resolution: {integrity: sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==} + engines: {node: '>= 0.4'} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-ci@2.0.0: + resolution: {integrity: sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==} + hasBin: true + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + + is-directory@0.3.1: + resolution: {integrity: sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==} + engines: {node: '>=0.10.0'} + + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + + is-error@2.2.2: + resolution: {integrity: sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + + is-fullwidth-code-point@1.0.0: + resolution: {integrity: sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@2.0.0: + resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} + engines: {node: '>=4'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + + is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + + is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-interactive@1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} + + is-lambda@1.0.1: + resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-module@1.0.0: + resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-path-cwd@3.0.0: + resolution: {integrity: sha512-kyiNFFLU0Ampr6SDZitD/DwUo4Zs1nSdnygUBqsu3LooL00Qvb5j+UnvApUn/TTj1J3OuE6BTdQ5rudKmU2ZaA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-path-inside@4.0.0: + resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} + engines: {node: '>=12'} + + is-plain-obj@2.1.0: + resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} + engines: {node: '>=8'} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-plain-object@2.0.4: + resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} + engines: {node: '>=0.10.0'} + + is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + + is-reference@1.2.1: + resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-typedarray@1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + + is-unicode-supported@1.3.0: + resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} + engines: {node: '>=12'} + + is-url@1.2.4: + resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.0: + resolution: {integrity: sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + is-wsl@1.1.0: + resolution: {integrity: sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==} + engines: {node: '>=4'} + + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + + is2@2.0.9: + resolution: {integrity: sha512-rZkHeBn9Zzq52sd9IUIV3a5mfwBY+o2HePMh0wkGBM4z4qjvy2GwVxQ6nNXSfw6MmVP6gf1QIlWjiOavhM3x5g==} + engines: {node: '>=v0.10.0'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isbot@3.4.5: + resolution: {integrity: sha512-+KD6q1BBtw0iK9aGBGSfxJ31/ZgizKRjhm8ebgJUBMx0aeeQuIJ1I72beCoIrltIZGrSm4vmrxRxrG5n1aUTtw==} + engines: {node: '>=12'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isexe@3.1.1: + resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} + engines: {node: '>=16'} + + isexe@4.0.0: + resolution: {integrity: sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==} + engines: {node: '>=20'} + + isobject@3.0.1: + resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} + engines: {node: '>=0.10.0'} + + isstream@0.1.2: + resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} + + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + + istanbul-reports@3.1.7: + resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} + engines: {node: '>=8'} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jake@10.9.2: + resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==} + engines: {node: '>=10'} + hasBin: true + + jasmine-core@5.5.0: + resolution: {integrity: sha512-NHOvoPO6o9gVR6pwqEACTEpbgcH+JJ6QDypyymGbSUIFIFsMMbBJ/xsFNud8MSClfnWclXd7RQlAZBz7yVo5TQ==} + + jasmine@5.5.0: + resolution: {integrity: sha512-JKlEVCVD5QBPYLsg/VE+IUtjyseDCrW8rMBu8la+9ysYashDgavMLM9Kotls1FhI6dCJLJ40dBCIfQjGLPZI1Q==} + hasBin: true + + jest-changed-files@28.1.3: + resolution: {integrity: sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-circus@28.1.3: + resolution: {integrity: sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-cli@28.1.3: + resolution: {integrity: sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jest-config@28.1.3: + resolution: {integrity: sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + + jest-diff@28.1.3: + resolution: {integrity: sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-docblock@28.1.1: + resolution: {integrity: sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-each@28.1.3: + resolution: {integrity: sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-environment-jsdom-global@4.0.0: + resolution: {integrity: sha512-qEV8j61oV5XhOBUQbrld2nMYKnp/AGINUaoYTtkwJ9rjvMNRN7ZaZ/dgoPpW83oFtrSiVM1gie6ajdsKFBUlLA==} + engines: {node: '>= 14'} + peerDependencies: + jest-environment-jsdom: 22.x || 23.x || 24.x || 25.x || 26.x || 27.x || 28.x || 29.x + + jest-environment-jsdom@28.1.3: + resolution: {integrity: sha512-HnlGUmZRdxfCByd3GM2F100DgQOajUBzEitjGqIREcb45kGjZvRrKUdlaF6escXBdcXNl0OBh+1ZrfeZT3GnAg==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-environment-node@28.1.3: + resolution: {integrity: sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-environment-node@29.7.0: + resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-get-type@28.0.2: + resolution: {integrity: sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-haste-map@28.1.3: + resolution: {integrity: sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-leak-detector@28.1.3: + resolution: {integrity: sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-matcher-utils@28.1.3: + resolution: {integrity: sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-message-util@26.6.2: + resolution: {integrity: sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==} + engines: {node: '>= 10.14.2'} + + jest-message-util@28.1.3: + resolution: {integrity: sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-mock@28.1.3: + resolution: {integrity: sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-mock@29.7.0: + resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-pnp-resolver@1.2.3: + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + + jest-regex-util@28.0.2: + resolution: {integrity: sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-resolve-dependencies@28.1.3: + resolution: {integrity: sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-resolve@28.1.3: + resolution: {integrity: sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-runner@28.1.3: + resolution: {integrity: sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-runtime@28.1.3: + resolution: {integrity: sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-snapshot@28.1.3: + resolution: {integrity: sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-standard-reporter@2.0.0: + resolution: {integrity: sha512-JhV3qzNzs5u/T1mzN9ivVrf2i4xYOQJgyPMKQbAmwRAZIprCpkikt8GF1kQKrP5ch1qBMn5xYyNdUUOKi8bltA==} + + jest-util@26.6.2: + resolution: {integrity: sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==} + engines: {node: '>= 10.14.2'} + + jest-util@28.1.3: + resolution: {integrity: sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-validate@28.1.3: + resolution: {integrity: sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-watcher@28.1.3: + resolution: {integrity: sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-worker@26.6.2: + resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} + engines: {node: '>= 10.13.0'} + + jest-worker@28.1.3: + resolution: {integrity: sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest@28.1.3: + resolution: {integrity: sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + joi@17.13.3: + resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} + + js-cleanup@1.2.0: + resolution: {integrity: sha512-JeDD0yiiSt80fXzAVa/crrS0JDPQljyBG/RpOtaSbyDq03VHa9szJWMaWOYU/bcTn412uMN2MxApXq8v79cUiQ==} + engines: {node: ^10.14.2 || >=12.0.0} + + js-string-escape@1.0.1: + resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==} + engines: {node: '>= 0.8'} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + jsbn@0.1.1: + resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} + + jsbn@1.1.0: + resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} + + jsc-android@250231.0.0: + resolution: {integrity: sha512-rS46PvsjYmdmuz1OAWXY/1kCYG7pnf1TBqeTiOJr1iDz7s5DLxxC9n/ZMknLDxzYzNVfI7R95MH10emSSG1Wuw==} + + jsc-safe-url@0.2.4: + resolution: {integrity: sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==} + + jscodeshift@0.14.0: + resolution: {integrity: sha512-7eCC1knD7bLUPuSCwXsMZUH51O8jIcoVyKtI6P0XM0IVzlGjckPy3FIwQlorzbN0Sg79oK+RlohN32Mqf/lrYA==} + hasBin: true + peerDependencies: + '@babel/preset-env': ^7.1.6 + + jsdom@19.0.0: + resolution: {integrity: sha512-RYAyjCbxy/vri/CfnjUWJQQtZ3LKlLnDqj+9XLNnJPgEGeirZs3hllKR20re8LUZ6o1b1X4Jat+Qd26zmP41+A==} + engines: {node: '>=12'} + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + + jsesc@3.0.2: + resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} + engines: {node: '>=6'} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-parse-better-errors@1.0.2: + resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-parse-even-better-errors@3.0.2: + resolution: {integrity: sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + + jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + + jsonparse@1.3.1: + resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} + engines: {'0': node >= 0.2.0} + + jsprim@1.4.2: + resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==} + engines: {node: '>=0.6.0'} + + jstimezonedetect@1.0.7: + resolution: {integrity: sha512-ARADHortktl9IZ1tr4GHwGPIAzgz3mLNCbR/YjWtRtc/O0o634O3NeFlpLjv95EvuDA5dc8z6yfgbS8nUc4zcQ==} + + jszip@3.10.1: + resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + ky@0.33.3: + resolution: {integrity: sha512-CasD9OCEQSFIam2U8efFK81Yeg8vNMTBUqtMOHlrcWQHqUX3HeCl9Dr31u4toV7emlH8Mymk5+9p0lL6mKb/Xw==} + engines: {node: '>=14.16'} + + lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lie@3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + + lighthouse-logger@1.4.2: + resolution: {integrity: sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + lines-and-columns@2.0.4: + resolution: {integrity: sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + load-json-file@4.0.0: + resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==} + engines: {node: '>=4'} + + load-json-file@7.0.1: + resolution: {integrity: sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + locate-app@2.5.0: + resolution: {integrity: sha512-xIqbzPMBYArJRmPGUZD9CzV9wOqmVtQnaAn3wrj3s6WYW0bQvPI7x+sPYUGmDTYMHefVK//zc6HEYZ1qnxIK+Q==} + + locate-path@3.0.0: + resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} + engines: {node: '>=6'} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + locate-path@7.2.0: + resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + lodash.clonedeep@4.5.0: + resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} + + lodash.debounce@4.0.8: + resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + + lodash.flattendeep@4.4.0: + resolution: {integrity: sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==} + + lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.pickby@4.6.0: + resolution: {integrity: sha512-AZV+GsS/6ckvPOVQPXSiFFacKvKB4kOQu6ynt9wz0F3LO4R9Ij4K1ddYsIytDpSgLz88JHd9P+oaLeej5/Sl7Q==} + + lodash.throttle@4.1.1: + resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} + + lodash.union@4.6.0: + resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==} + + lodash.zip@4.2.0: + resolution: {integrity: sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + + logkitty@0.7.1: + resolution: {integrity: sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ==} + hasBin: true + + loglevel-plugin-prefix@0.8.4: + resolution: {integrity: sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==} + + loglevel@1.9.2: + resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} + engines: {node: '>= 0.6.0'} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + + lowercase-keys@2.0.0: + resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} + engines: {node: '>=8'} + + lowercase-keys@3.0.0: + resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@11.5.1: + resolution: {integrity: sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==} + engines: {node: 20 || >=22} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + + lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + + magic-string@0.25.7: + resolution: {integrity: sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==} + + magic-string@0.25.9: + resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} + + magic-string@0.26.7: + resolution: {integrity: sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==} + engines: {node: '>=12'} + + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + + make-dir@2.1.0: + resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} + engines: {node: '>=6'} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + make-fetch-happen@9.1.0: + resolution: {integrity: sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==} + engines: {node: '>= 10'} + + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + + map-age-cleaner@0.1.3: + resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} + engines: {node: '>=6'} + + marky@1.2.5: + resolution: {integrity: sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==} + + matcher@5.0.0: + resolution: {integrity: sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + matchit@1.1.0: + resolution: {integrity: sha512-+nGYoOlfHmxe5BW5tE0EMJppXEwdSf8uBA1GTZC7Q77kbT35+VKLYJMzVNWCHSsga1ps1tPYFtFyvxvKzWVmMA==} + engines: {node: '>=6'} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + md5-hex@3.0.1: + resolution: {integrity: sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==} + engines: {node: '>=8'} + + media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + + mem@9.0.2: + resolution: {integrity: sha512-F2t4YIv9XQUBHt6AOJ0y7lSmP1+cY7Fm1DRh9GClTGzKST7UWLMx6ly9WZdLH/G/ppM5RL4MlQfRT71ri9t19A==} + engines: {node: '>=12.20'} + + memoize-one@5.2.1: + resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} + + memorystream@0.3.1: + resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} + engines: {node: '>= 0.10.0'} + + merge-descriptors@1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + + merge-options@3.0.4: + resolution: {integrity: sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==} + engines: {node: '>=10'} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + + metro-babel-transformer@0.80.12: + resolution: {integrity: sha512-YZziRs0MgA3pzCkkvOoQRXjIoVjvrpi/yRlJnObyIvMP6lFdtyG4nUGIwGY9VXnBvxmXD6mPY2e+NSw6JAyiRg==} + engines: {node: '>=18'} + + metro-cache-key@0.80.12: + resolution: {integrity: sha512-o4BspKnugg/pE45ei0LGHVuBJXwRgruW7oSFAeSZvBKA/sGr0UhOGY3uycOgWInnS3v5yTTfiBA9lHlNRhsvGA==} + engines: {node: '>=18'} + + metro-cache@0.80.12: + resolution: {integrity: sha512-p5kNHh2KJ0pbQI/H7ZBPCEwkyNcSz7OUkslzsiIWBMPQGFJ/xArMwkV7I+GJcWh+b4m6zbLxE5fk6fqbVK1xGA==} + engines: {node: '>=18'} + + metro-config@0.80.12: + resolution: {integrity: sha512-4rwOWwrhm62LjB12ytiuR5NgK1ZBNr24/He8mqCsC+HXZ+ATbrewLNztzbAZHtFsrxP4D4GLTGgh96pCpYLSAQ==} + engines: {node: '>=18'} + + metro-core@0.80.12: + resolution: {integrity: sha512-QqdJ/yAK+IpPs2HU/h5v2pKEdANBagSsc6DRSjnwSyJsCoHlmyJKCaCJ7KhWGx+N4OHxh37hoA8fc2CuZbx0Fw==} + engines: {node: '>=18'} + + metro-file-map@0.80.12: + resolution: {integrity: sha512-sYdemWSlk66bWzW2wp79kcPMzwuG32x1ZF3otI0QZTmrnTaaTiGyhE66P1z6KR4n2Eu5QXiABa6EWbAQv0r8bw==} + engines: {node: '>=18'} + + metro-minify-terser@0.80.12: + resolution: {integrity: sha512-muWzUw3y5k+9083ZoX9VaJLWEV2Jcgi+Oan0Mmb/fBNMPqP9xVDuy4pOMn/HOiGndgfh/MK7s4bsjkyLJKMnXQ==} + engines: {node: '>=18'} + + metro-resolver@0.80.12: + resolution: {integrity: sha512-PR24gYRZnYHM3xT9pg6BdbrGbM/Cu1TcyIFBVlAk7qDAuHkUNQ1nMzWumWs+kwSvtd9eZGzHoucGJpTUEeLZAw==} + engines: {node: '>=18'} + + metro-runtime@0.80.12: + resolution: {integrity: sha512-LIx7+92p5rpI0i6iB4S4GBvvLxStNt6fF0oPMaUd1Weku7jZdfkCZzmrtDD9CSQ6EPb0T9NUZoyXIxlBa3wOCw==} + engines: {node: '>=18'} + + metro-source-map@0.80.12: + resolution: {integrity: sha512-o+AXmE7hpvM8r8MKsx7TI21/eerYYy2DCDkWfoBkv+jNkl61khvDHlQn0cXZa6lrcNZiZkl9oHSMcwLLIrFmpw==} + engines: {node: '>=18'} + + metro-symbolicate@0.80.12: + resolution: {integrity: sha512-/dIpNdHksXkGHZXARZpL7doUzHqSNxgQ8+kQGxwpJuHnDhGkENxB5PS2QBaTDdEcmyTMjS53CN1rl9n1gR6fmw==} + engines: {node: '>=18'} + hasBin: true + + metro-transform-plugins@0.80.12: + resolution: {integrity: sha512-WQWp00AcZvXuQdbjQbx1LzFR31IInlkCDYJNRs6gtEtAyhwpMMlL2KcHmdY+wjDO9RPcliZ+Xl1riOuBecVlPA==} + engines: {node: '>=18'} + + metro-transform-worker@0.80.12: + resolution: {integrity: sha512-KAPFN1y3eVqEbKLx1I8WOarHPqDMUa8WelWxaJCNKO/yHCP26zELeqTJvhsQup+8uwB6EYi/sp0b6TGoh6lOEA==} + engines: {node: '>=18'} + + metro@0.80.12: + resolution: {integrity: sha512-1UsH5FzJd9quUsD1qY+zUG4JY3jo3YEMxbMYH9jT6NK3j4iORhlwTK8fYTfAUBhDKjgLfKjAh7aoazNE23oIRA==} + engines: {node: '>=18'} + hasBin: true + + micro-spelling-correcter@1.1.1: + resolution: {integrity: sha512-lkJ3Rj/mtjlRcHk6YyCbvZhyWTOzdBvTHsxMmZSk5jxN1YyVSQ+JETAom55mdzfcyDrY/49Z7UCW760BK30crg==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-db@1.53.0: + resolution: {integrity: sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + + mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + + mimic-response@1.0.1: + resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} + engines: {node: '>=4'} + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + + mimic-response@4.0.0: + resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} + + minimatch@3.0.8: + resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass-collect@1.0.2: + resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} + engines: {node: '>= 8'} + + minipass-fetch@1.4.1: + resolution: {integrity: sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==} + engines: {node: '>=8'} + + minipass-flush@1.0.5: + resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} + engines: {node: '>= 8'} + + minipass-json-stream@1.0.2: + resolution: {integrity: sha512-myxeeTm57lYs8pH2nxPzmEEg8DGIgW+9mv6D4JZD2pa81I/OBjeU7PtICXV6c9eRGTA5JMDsuIPUZRCyBMYNhg==} + + minipass-pipeline@1.2.4: + resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} + engines: {node: '>=8'} + + minipass-sized@1.0.3: + resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} + engines: {node: '>=8'} + + minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + + minipass@5.0.0: + resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} + engines: {node: '>=8'} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@2.1.2: + resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} + engines: {node: '>= 8'} + + mitt@3.0.0: + resolution: {integrity: sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==} + + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + + module-details-from-path@1.0.3: + resolution: {integrity: sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==} + + moment-timezone@0.5.46: + resolution: {integrity: sha512-ZXm9b36esbe7OmdABqIWJuBBiLLwAjrN7CE+7sYdCCx82Nabt1wHDj8TVseS59QIlfFPbOoiBPm6ca9BioG4hw==} + + moment@2.29.1: + resolution: {integrity: sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==} + + moment@2.30.1: + resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} + + morgan@1.10.0: + resolution: {integrity: sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==} + engines: {node: '>= 0.8.0'} + + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mute-stream@1.0.0: + resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + nan@2.22.0: + resolution: {integrity: sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==} + + native-promise-only@0.8.1: + resolution: {integrity: sha512-zkVhZUA3y8mbz652WrL5x0fB0ehrBkulWT3TomAQ9iDtyXZvzKeEA6GPxAItBYeNYl5yngKRX612qHOhvMkDeg==} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + + negotiator@0.6.4: + resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} + engines: {node: '>= 0.6'} + + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + netmask@2.0.2: + resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} + engines: {node: '>= 0.4.0'} + + nice-try@1.0.5: + resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} + + no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + + nocache@3.0.4: + resolution: {integrity: sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw==} + engines: {node: '>=12.0.0'} + + node-abort-controller@3.1.1: + resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} + + node-dir@0.1.17: + resolution: {integrity: sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==} + engines: {node: '>= 0.10.5'} + + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + node-forge@1.3.1: + resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} + engines: {node: '>= 6.13.0'} + + node-gyp@7.1.2: + resolution: {integrity: sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==} + engines: {node: '>= 10.12.0'} + hasBin: true + + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + + node-releases@2.0.47: + resolution: {integrity: sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==} + engines: {node: '>=18'} + + node-stream-zip@1.15.0: + resolution: {integrity: sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==} + engines: {node: '>=0.12.0'} + + nofilter@3.1.0: + resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} + engines: {node: '>=12.19'} + + nopt@5.0.0: + resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} + engines: {node: '>=6'} + hasBin: true + + normalize-package-data@2.5.0: + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + + normalize-package-data@6.0.2: + resolution: {integrity: sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==} + engines: {node: ^16.14.0 || >=18.0.0} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-url@6.1.0: + resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} + engines: {node: '>=10'} + + normalize-url@8.0.1: + resolution: {integrity: sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==} + engines: {node: '>=14.16'} + + npm-bundled@1.1.2: + resolution: {integrity: sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==} + + npm-install-checks@4.0.0: + resolution: {integrity: sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w==} + engines: {node: '>=10'} + + npm-normalize-package-bin@1.0.1: + resolution: {integrity: sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==} + + npm-package-arg@8.1.5: + resolution: {integrity: sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q==} + engines: {node: '>=10'} + + npm-packlist@2.2.2: + resolution: {integrity: sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg==} + engines: {node: '>=10'} + hasBin: true + + npm-pick-manifest@6.1.1: + resolution: {integrity: sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA==} + + npm-registry-fetch@11.0.0: + resolution: {integrity: sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA==} + engines: {node: '>=10'} + + npm-run-all@4.1.5: + resolution: {integrity: sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==} + engines: {node: '>= 4'} + hasBin: true + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + npmlog@4.1.2: + resolution: {integrity: sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==} + deprecated: This package is no longer supported. + + nullthrows@1.1.1: + resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} + + number-is-nan@1.0.1: + resolution: {integrity: sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==} + engines: {node: '>=0.10.0'} + + nwsapi@2.2.16: + resolution: {integrity: sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==} + + oauth-sign@0.9.0: + resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==} + + ob1@0.80.12: + resolution: {integrity: sha512-VMArClVT6LkhUGpnuEoBuyjG9rzUyEzg4PDkav6wK1cLhOK02gPCYFxoiB4mqVnrMhDpIzJcrGNAMVi9P+hXrw==} + engines: {node: '>=18'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.3: + resolution: {integrity: sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==} + engines: {node: '>= 0.4'} + + object-is@1.1.6: + resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object-path@0.11.8: + resolution: {integrity: sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==} + engines: {node: '>= 10.12.0'} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + on-finished@2.3.0: + resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} + engines: {node: '>= 0.8'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + on-headers@1.0.2: + resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + + open@6.4.0: + resolution: {integrity: sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==} + engines: {node: '>=8'} + + open@7.4.2: + resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} + engines: {node: '>=8'} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + ora@5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + + os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + + p-cancelable@2.1.1: + resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} + engines: {node: '>=8'} + + p-cancelable@3.0.0: + resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==} + engines: {node: '>=12.20'} + + p-defer@1.0.0: + resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==} + engines: {node: '>=4'} + + p-event@5.0.1: + resolution: {integrity: sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-limit@4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + p-locate@3.0.0: + resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} + engines: {node: '>=6'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-locate@6.0.0: + resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + p-map@4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + + p-map@5.5.0: + resolution: {integrity: sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==} + engines: {node: '>=12'} + + p-map@7.0.4: + resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==} + engines: {node: '>=18'} + + p-timeout@5.1.0: + resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==} + engines: {node: '>=12'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + pac-proxy-agent@7.1.0: + resolution: {integrity: sha512-Z5FnLVVZSnX7WjBg0mhDtydeRZ1xMcATZThjySQUHqr+0ksP8kqaw23fNKkaaN/Z8gwLUs/W7xdl0I75eP2Xyw==} + engines: {node: '>= 14'} + + pac-resolver@7.0.1: + resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} + engines: {node: '>= 14'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + package-name-regex@2.0.5: + resolution: {integrity: sha512-F0lX+FBs/Bo7KWY6EuUXj+oarXU0Og1R2Zdg3F/fVcNw3pPQAKFKxUrugno0Ds5NUztlx/gRLnQW9MF+7VTqAw==} + engines: {node: '>=12'} + + pacote@11.3.5: + resolution: {integrity: sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg==} + engines: {node: '>=10'} + hasBin: true + + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + + param-case@3.0.4: + resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-json@4.0.0: + resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} + engines: {node: '>=4'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parse-json@7.1.1: + resolution: {integrity: sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw==} + engines: {node: '>=16'} + + parse-ms@2.1.0: + resolution: {integrity: sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==} + engines: {node: '>=6'} + + parse-ms@3.0.0: + resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==} + engines: {node: '>=12'} + + parse5@6.0.1: + resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + pascal-case@3.1.2: + resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} + + path-case@3.0.4: + resolution: {integrity: sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==} + + path-exists@3.0.0: + resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} + engines: {node: '>=4'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-exists@5.0.0: + resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@2.0.1: + resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==} + engines: {node: '>=4'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} + + path-to-regexp@0.1.12: + resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} + + path-type@3.0.0: + resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} + engines: {node: '>=4'} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + path-type@6.0.0: + resolution: {integrity: sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==} + engines: {node: '>=18'} + + path@0.12.7: + resolution: {integrity: sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==} + + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + + perf-regexes@1.0.1: + resolution: {integrity: sha512-L7MXxUDtqr4PUaLFCDCXBfGV/6KLIuSEccizDI7JxT+c9x1G1v04BQ4+4oag84SHaCdrBgQAIs/Cqn+flwFPng==} + engines: {node: '>=6.14'} + + performance-now@2.1.0: + resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pidtree@0.3.1: + resolution: {integrity: sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==} + engines: {node: '>=0.10'} + hasBin: true + + pify@3.0.0: + resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} + engines: {node: '>=4'} + + pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + + pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + + pkg-conf@4.0.0: + resolution: {integrity: sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + pkg-dir@3.0.0: + resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==} + engines: {node: '>=6'} + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + + pkg-dir@5.0.0: + resolution: {integrity: sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==} + engines: {node: '>=10'} + + plur@5.1.0: + resolution: {integrity: sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + polka@0.5.2: + resolution: {integrity: sha512-FVg3vDmCqP80tOrs+OeNlgXYmFppTXdjD5E7I4ET1NjvtNmQrb1/mJibybKkb/d4NA7YWAr1ojxuhpL3FHqdlw==} + + possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + presentable-error@0.0.1: + resolution: {integrity: sha512-E6rsNU1QNJgB3sjj7OANinGncFKuK+164sLXw1/CqBjj/EkXSoSdHCtWQGBNlREIGLnL7IEUEGa08YFVUbrhVg==} + engines: {node: '>=16'} + + pretty-format@26.6.2: + resolution: {integrity: sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==} + engines: {node: '>= 10'} + + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + pretty-format@28.1.3: + resolution: {integrity: sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + pretty-ms@7.0.1: + resolution: {integrity: sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==} + engines: {node: '>=10'} + + pretty-ms@8.0.0: + resolution: {integrity: sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==} + engines: {node: '>=14.16'} + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + + progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + + promise-inflight@1.0.1: + resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} + + promise-retry@2.0.1: + resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} + engines: {node: '>=10'} + + promise@8.3.0: + resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + proxy-agent@6.3.0: + resolution: {integrity: sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==} + engines: {node: '>= 14'} + + proxy-agent@6.3.1: + resolution: {integrity: sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==} + engines: {node: '>= 14'} + + proxy-agent@6.5.0: + resolution: {integrity: sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==} + engines: {node: '>= 14'} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + psl@1.15.0: + resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} + + pump@3.0.2: + resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + puppeteer-core@20.9.0: + resolution: {integrity: sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==} + engines: {node: '>=16.3.0'} + peerDependencies: + typescript: '>= 4.7.4' + peerDependenciesMeta: + typescript: + optional: true + + qs@6.13.0: + resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} + engines: {node: '>=0.6'} + + qs@6.5.3: + resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==} + engines: {node: '>=0.6'} + + query-selector-shadow-dom@1.0.1: + resolution: {integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==} + + query-string@7.1.3: + resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} + engines: {node: '>=6'} + + querystring@0.2.1: + resolution: {integrity: sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==} + engines: {node: '>=0.4.x'} + deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. + + querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + queue-tick@1.0.1: + resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} + + queue@6.0.2: + resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} + + quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + randomcolor@0.6.2: + resolution: {integrity: sha512-Mn6TbyYpFgwFuQ8KJKqf3bqqY9O1y37/0jgSK/61PUxV4QfIMv0+K2ioq8DfOjkBslcjwSzRfIDEXfzA9aCx7A==} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@2.5.2: + resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} + engines: {node: '>= 0.8'} + + react-devtools-core@5.3.2: + resolution: {integrity: sha512-crr9HkVrDiJ0A4zot89oS0Cgv0Oa4OG1Em4jit3P3ZxZSKPMYyMjfwMqgcJna9o625g8oN87rBm8SWWrSTBZxg==} + + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react-native-builder-bob@0.42.1: + resolution: {integrity: sha512-piw301vvc+lDydNkKJfpJfLFyKH5ORcdFeHUUiSo/NIxhAT2SU8TZjvYyZsUmTpCPKwnapmZis3fRSOJpJTCkw==} + engines: {node: ^20.19.0 || ^22.12.0 || >= 23.4.0} + hasBin: true + + react-native-get-random-values@1.11.0: + resolution: {integrity: sha512-4BTbDbRmS7iPdhYLRcz3PGFIpFJBwNZg9g42iwa2P6FOv9vZj/xJc678RZXnLNZzd0qd7Q3CCF6Yd+CU2eoXKQ==} + peerDependencies: + react-native: '>=0.56' + + react-native-monorepo-config@0.3.5: + resolution: {integrity: sha512-Xdu7k0s4V2FHn2OGnlr3D22Dgt5ij0ek9yzloPoLkHh3rL/jUQbPrawieKsAbkqoenv/7pfPJwMlPT27bvN1fg==} + + react-native@0.74.5: + resolution: {integrity: sha512-Bgg2WvxaGODukJMTZFTZBNMKVaROHLwSb8VAGEdrlvKwfb1hHg/3aXTUICYk7dwgAnb+INbGMwnF8yeAgIUmqw==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@types/react': ^18.2.6 + react: 18.2.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-refresh@0.14.2: + resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} + engines: {node: '>=0.10.0'} + + react-shallow-renderer@16.15.0: + resolution: {integrity: sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==} + peerDependencies: + react: ^16.0.0 || ^17.0.0 || ^18.0.0 + + react@18.2.0: + resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} + engines: {node: '>=0.10.0'} + + read-package-json-fast@2.0.3: + resolution: {integrity: sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==} + engines: {node: '>=10'} + + read-pkg-up@10.0.0: + resolution: {integrity: sha512-jgmKiS//w2Zs+YbX039CorlkOp8FIVbSAN8r8GJHDsGlmNPXo+VeHkqAwCiQVTTx5/LwLZTcEw59z3DvcLbr0g==} + engines: {node: '>=16'} + + read-pkg@3.0.0: + resolution: {integrity: sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==} + engines: {node: '>=4'} + + read-pkg@8.1.0: + resolution: {integrity: sha512-PORM8AgzXeskHO/WEv312k9U03B8K9JSiWF/8N9sUuFjBa+9SF2u6K7VClzXwDXab51jCd8Nd36CNM+zR97ScQ==} + engines: {node: '>=16'} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readable-stream@4.6.0: + resolution: {integrity: sha512-cbAdYt0VcnpN2Bekq7PU+k363ZRsPwJoEEJOEtSJQlJXzwaxt3FIo/uL+KeDSGIjJqtkwyge4KQgD2S2kd+CQw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + readline@1.3.0: + resolution: {integrity: sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==} + + recast@0.21.5: + resolution: {integrity: sha512-hjMmLaUXAm1hIuTqOdeYObMslq/q+Xff6QE3Y2P+uoHAg2nmVlLBps2hzh1UJDdMtDTMXOFewK6ky51JQIeECg==} + engines: {node: '>= 4'} + + recursive-readdir@2.2.3: + resolution: {integrity: sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==} + engines: {node: '>=6.0.0'} + + reflect.getprototypeof@1.0.9: + resolution: {integrity: sha512-r0Ay04Snci87djAsI4U+WNRcSw5S4pOH7qFjd/veA5gC7TbqESR3tcj28ia95L/fYUDw11JKP7uqUKUAfVvV5Q==} + engines: {node: '>= 0.4'} + + regenerate-unicode-properties@10.2.0: + resolution: {integrity: sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==} + engines: {node: '>=4'} + + regenerate-unicode-properties@10.2.2: + resolution: {integrity: sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==} + engines: {node: '>=4'} + + regenerate@1.4.2: + resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} + + regenerator-runtime@0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + + regexp.prototype.flags@1.5.3: + resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} + engines: {node: '>= 0.4'} + + regexpp@3.2.0: + resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} + engines: {node: '>=8'} + + regexpu-core@6.2.0: + resolution: {integrity: sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==} + engines: {node: '>=4'} + + regexpu-core@6.4.0: + resolution: {integrity: sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==} + engines: {node: '>=4'} + + regjsgen@0.8.0: + resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} + + regjsparser@0.12.0: + resolution: {integrity: sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==} + hasBin: true + + regjsparser@0.13.1: + resolution: {integrity: sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw==} + hasBin: true + + request@2.88.2: + resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==} + engines: {node: '>= 6'} + deprecated: request has been deprecated, see https://github.com/request/request/issues/3142 + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + + requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + + resolve-alpn@1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + + resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + + resolve-from@3.0.0: + resolution: {integrity: sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==} + engines: {node: '>=4'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve.exports@1.1.1: + resolution: {integrity: sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==} + engines: {node: '>=10'} + + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + + resolve@1.22.12: + resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} + engines: {node: '>= 0.4'} + hasBin: true + + responselike@2.0.1: + resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} + + responselike@3.0.0: + resolution: {integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==} + engines: {node: '>=14.16'} + + resq@1.11.0: + resolution: {integrity: sha512-G10EBz+zAAy3zUd/CDoBbXRL6ia9kOo3xRHrMDsHljI0GDkhYlyjwoCx5+3eCC4swi1uCoZQhskuJkj7Gp57Bw==} + + restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rgb2hex@0.2.5: + resolution: {integrity: sha512-22MOP1Rh7sAo1BZpDG6R5RFYzR2lYEgwq7HEmyW2qcsOqR2lQKmn+O//xV3YG/0rrhMC6KVX2hU+ZXuaw9a5bw==} + + rimraf@2.6.3: + resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + rollup-plugin-cleanup@3.2.1: + resolution: {integrity: sha512-zuv8EhoO3TpnrU8MX8W7YxSbO4gmOR0ny06Lm3nkFfq0IVKdBUtHwhVzY1OAJyNCIAdLiyPnOrU0KnO0Fri1GQ==} + engines: {node: ^10.14.2 || >=12.0.0} + peerDependencies: + rollup: '>=2.0' + + rollup-plugin-filesize@9.1.2: + resolution: {integrity: sha512-m2fE9hFaKgWKisJzyWXctOFKlgMRelo/58HgeC0lXUK/qykxiqkr6bsrotlvo2bvrwPsjgT7scNdQSr6qtl37A==} + engines: {node: '>=10.0.0'} + + rollup-plugin-license@2.6.1: + resolution: {integrity: sha512-JPtlXF0tZKyHztKJsyd3HHmQFSkXei+596Xrb/a/bHIdDhvFuNSKimCKkQpoXyspfeVQk7CNay1MyGpFHAXjvg==} + engines: {node: '>=10.0.0'} + peerDependencies: + rollup: ^1.0.0 || ^2.0.0 + + rollup-plugin-sizes@1.0.6: + resolution: {integrity: sha512-TQlfd2Ef+1BQjsDIuXyoBPAFFJfA9q4DXSCT5/jsUEtsyn99CzwGH98StQOg+sriq9+j8VgCxPO4yodMbvynPg==} + peerDependencies: + rollup: ^2 || ^3 || ^4 + + rollup-plugin-terser@7.0.2: + resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==} + deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser + peerDependencies: + rollup: ^2.0.0 + + rollup-plugin-ts@2.0.7: + resolution: {integrity: sha512-M9sppRKX6y/b2KXbGdUdHid0tshAEK/sEeYLBHBJiBa4swukSsoFVXKGGZasLcjaXhgUnnizFuvFFj6znxwvSA==} + engines: {node: '>=10.0.0', npm: '>=7.0.0', pnpm: '>=3.2.0', yarn: '>=1.13'} + deprecated: please use @rollup/plugin-typescript and rollup-plugin-dts instead + peerDependencies: + '@babel/core': '>=6.x || >=7.x' + '@babel/plugin-transform-runtime': '>=6.x || >=7.x' + '@babel/preset-env': '>=6.x || >=7.x' + '@babel/runtime': '>=6.x || >=7.x' + '@swc/core': '>=1.x' + '@swc/helpers': '>=0.2' + rollup: '>=1.x || >=2.x' + typescript: '>=3.2.x || >= 4.x' + peerDependenciesMeta: + '@babel/core': + optional: true + '@babel/plugin-transform-runtime': + optional: true + '@babel/preset-env': + optional: true + '@babel/runtime': + optional: true + '@swc/core': + optional: true + '@swc/helpers': + optional: true + + rollup-pluginutils@2.8.2: + resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} + + rollup@2.70.2: + resolution: {integrity: sha512-EitogNZnfku65I1DD5Mxe8JYRUCy0hkK5X84IlDtUs+O6JRMpRciXTzyCUuX11b5L5pvjH+OmFXiQ3XjabcXgg==} + engines: {node: '>=10.0.0'} + hasBin: true + + run-async@3.0.0: + resolution: {integrity: sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==} + engines: {node: '>=0.12.0'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + + safaridriver@0.0.6: + resolution: {integrity: sha512-cU8eBBOOoCsPKb3o/lvx8ppYWFVmTsnAu2MofkPbUPCfDvyFRtD8VyOGwWTtuJTdMNIC+dPnOgaoPNnsk7zs0Q==} + + safaridriver@0.1.2: + resolution: {integrity: sha512-4R309+gWflJktzPXBQCobbWEHlzC4aK3a+Ov3tz2Ib2aBxiwd11phkdIBH1l0EO22x24CJMUQkpKFumRriCSRg==} + + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + saucelabs@7.5.0: + resolution: {integrity: sha512-wq89BtE7xb4ns7ApbgAshaUgXHlPoseytPTNwaVQNPwAaD+0klYpBrsCy/Lj77EJ+kf/vKvX1tjhRT67eDyCXg==} + hasBin: true + + saxes@5.0.1: + resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==} + engines: {node: '>=10'} + + scheduler@0.24.0-canary-efb381bbf-20230505: + resolution: {integrity: sha512-ABvovCDe/k9IluqSh4/ISoq8tIJnW8euVAWYt5j/bg6dRnqwQwiGO1F/V4AyK96NGF/FB04FhOUDuWj8IKfABA==} + + selfsigned@2.4.1: + resolution: {integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==} + engines: {node: '>=10'} + + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + + send@0.19.0: + resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} + engines: {node: '>= 0.8.0'} + + sentence-case@3.0.4: + resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==} + + serialize-error@11.0.3: + resolution: {integrity: sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==} + engines: {node: '>=14.16'} + + serialize-error@2.1.0: + resolution: {integrity: sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==} + engines: {node: '>=0.10.0'} + + serialize-error@7.0.1: + resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} + engines: {node: '>=10'} + + serialize-javascript@4.0.0: + resolution: {integrity: sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==} + + serve-static@1.16.2: + resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} + engines: {node: '>= 0.8.0'} + + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shallow-clone@3.0.1: + resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} + engines: {node: '>=8'} + + shebang-command@1.2.0: + resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} + engines: {node: '>=0.10.0'} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@1.0.0: + resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} + engines: {node: '>=0.10.0'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + shell-quote@1.8.2: + resolution: {integrity: sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==} + engines: {node: '>= 0.4'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + skip-regex@1.0.2: + resolution: {integrity: sha512-pEjMUbwJ5Pl/6Vn6FsamXHXItJXSRftcibixDmNCWbWhic0hzHrwkMZo0IZ7fMRH9KxcWDFSkzhccB4285PutA==} + engines: {node: '>=4.2'} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + slash@4.0.0: + resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} + engines: {node: '>=12'} + + slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + + slice-ansi@2.1.0: + resolution: {integrity: sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==} + engines: {node: '>=6'} + + slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + + smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + + snake-case@3.0.4: + resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + + socks-proxy-agent@6.2.1: + resolution: {integrity: sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==} + engines: {node: '>= 10'} + + socks-proxy-agent@8.0.5: + resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} + engines: {node: '>= 14'} + + socks@2.8.3: + resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + + source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + + sourcemap-codec@1.4.8: + resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} + deprecated: Please use @jridgewell/sourcemap-codec instead + + spacetrim@0.11.59: + resolution: {integrity: sha512-lLYsktklSRKprreOm7NXReW8YiX2VBjbgmXYEziOoGf/qsJqAEACaDvoTtUOycwjpaSh+bT8eu0KrJn7UNxiCg==} + + spdx-compare@1.0.0: + resolution: {integrity: sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==} + + spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + + spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + + spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + + spdx-expression-validate@2.0.0: + resolution: {integrity: sha512-b3wydZLM+Tc6CFvaRDBOF9d76oGIHNCLYFeHbftFXUWjnfZWganmDmvtM5sm1cRwJc/VDBMLyGGrsLFd1vOxbg==} + + spdx-license-ids@3.0.20: + resolution: {integrity: sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==} + + spdx-ranges@2.1.1: + resolution: {integrity: sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==} + + spdx-satisfies@5.0.1: + resolution: {integrity: sha512-Nwor6W6gzFp8XX4neaKQ7ChV4wmpSh2sSDemMFSzHxpTw460jxFYeOn+jq4ybnSSw/5sc3pjka9MQPouksQNpw==} + + split-ca@1.0.1: + resolution: {integrity: sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==} + + split-on-first@1.1.0: + resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==} + engines: {node: '>=6'} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + sprintf-js@1.1.3: + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + + ssh2@1.16.0: + resolution: {integrity: sha512-r1X4KsBGedJqo7h8F5c4Ybpcr5RjyP+aWIG007uBPRjmdQWfEiVLzSK71Zji1B9sKxwaCvD8y8cwSkYrlLiRRg==} + engines: {node: '>=10.16.0'} + + sshpk@1.18.0: + resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==} + engines: {node: '>=0.10.0'} + hasBin: true + + ssri@8.0.1: + resolution: {integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==} + engines: {node: '>= 8'} + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + stackframe@1.3.4: + resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} + + stacktrace-parser@0.1.10: + resolution: {integrity: sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==} + engines: {node: '>=6'} + + statuses@1.5.0: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} + + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + + stream-buffers@3.0.3: + resolution: {integrity: sha512-pqMqwQCso0PBJt2PQmDO0cFj0lyqmiwOMiMSkVtRokl7e+ZTRYgDHKnuZNbqjiJXgsg4nuqtD/zxuo9KqTp0Yw==} + engines: {node: '>= 0.10.0'} + + streamifier@0.1.1: + resolution: {integrity: sha512-zDgl+muIlWzXNsXeyUfOk9dChMjlpkq0DRsxujtYPgyJ676yQ8jEm6zzaaWHFDg5BNcLuif0eD2MTyJdZqXpdg==} + engines: {node: '>=0.10'} + + streamx@2.21.1: + resolution: {integrity: sha512-PhP9wUnFLa+91CPy3N6tiQsK+gnYyUNuk15S3YG/zjYE7RuPeCjJngqnzpC31ow0lzBHQ+QGO4cNJnd0djYUsw==} + + strict-uri-encode@2.0.0: + resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} + engines: {node: '>=4'} + + string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + + string-width@1.0.2: + resolution: {integrity: sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==} + engines: {node: '>=0.10.0'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + string.prototype.padend@3.1.6: + resolution: {integrity: sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==} + engines: {node: '>= 0.4'} + + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@3.0.1: + resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} + engines: {node: '>=0.10.0'} + + strip-ansi@5.2.0: + resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==} + engines: {node: '>=6'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + strnum@1.0.5: + resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} + + sudo-prompt@9.2.1: + resolution: {integrity: sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + + supertap@3.0.1: + resolution: {integrity: sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-hyperlinks@2.3.0: + resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + + tar-fs@2.0.1: + resolution: {integrity: sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==} + + tar-fs@3.0.4: + resolution: {integrity: sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==} + + tar-fs@3.0.6: + resolution: {integrity: sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==} + + tar-stream@1.6.2: + resolution: {integrity: sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==} + engines: {node: '>= 0.8.0'} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + + tar-stream@3.1.7: + resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + + tar@6.2.1: + resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} + engines: {node: '>=10'} + + tcp-port-used@1.0.2: + resolution: {integrity: sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA==} + + temp-dir@2.0.0: + resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} + engines: {node: '>=8'} + + temp-dir@3.0.0: + resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==} + engines: {node: '>=14.16'} + + temp@0.8.4: + resolution: {integrity: sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==} + engines: {node: '>=6.0.0'} + + terminal-link@2.1.1: + resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==} + engines: {node: '>=8'} + + terser@5.37.0: + resolution: {integrity: sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==} + engines: {node: '>=10'} + hasBin: true + + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + + text-decoder@1.2.3: + resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + throat@5.0.0: + resolution: {integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==} + + through2@2.0.5: + resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} + + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + + time-zone@1.0.0: + resolution: {integrity: sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==} + engines: {node: '>=4'} + + tinyrainbow@1.2.0: + resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} + engines: {node: '>=14.0.0'} + + tmp@0.0.33: + resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} + engines: {node: '>=0.6.0'} + + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + + to-buffer@1.1.1: + resolution: {integrity: sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tough-cookie@2.5.0: + resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==} + engines: {node: '>=0.8'} + + tough-cookie@4.1.4: + resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} + engines: {node: '>=6'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + tr46@3.0.0: + resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==} + engines: {node: '>=12'} + + trouter@2.0.1: + resolution: {integrity: sha512-kr8SKKw94OI+xTGOkfsvwZQ8mWoikZDd2n8XZHjJVZUARZT+4/VV6cacRS6CLsH9bNm+HFIPU1Zx4CnNnb4qlQ==} + engines: {node: '>=6'} + + ts-clone-node@0.3.32: + resolution: {integrity: sha512-YYGvoWy2Ba98/YC/0leD7IRsU/q5pu/KRg9dD8omzkbgoZ8g7gfYfED9mWMTyNp7J3CQiiKyvM62B7mXXHKU7Q==} + engines: {node: '>=10.0.0'} + peerDependencies: + typescript: ^3.x || ^4.x + + ts-jest@28.0.8: + resolution: {integrity: sha512-5FaG0lXmRPzApix8oFG8RKjAz4ehtm8yMKOTy5HX3fY6W8kmvOrmcY0hKDElW52FJov+clhUbrKAqofnj4mXTg==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@jest/types': ^28.0.0 + babel-jest: ^28.0.0 + esbuild: '*' + jest: ^28.0.0 + typescript: '>=4.3' + peerDependenciesMeta: + '@babel/core': + optional: true + '@jest/types': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsutils@3.21.0: + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + + tunnel@0.0.6: + resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} + engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} + + tweetnacl@0.14.5: + resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + type-fest@0.13.1: + resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} + engines: {node: '>=10'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + type-fest@0.7.1: + resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} + engines: {node: '>=8'} + + type-fest@2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + + type-fest@3.13.1: + resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} + engines: {node: '>=14.16'} + + type-fest@4.26.0: + resolution: {integrity: sha512-OduNjVJsFbifKb57UqZ2EMP1i4u64Xwow3NYXUtBbD4vIwJdQd4+xl8YDou1dlm4DVrtwT/7Ky8z8WyCULVfxw==} + engines: {node: '>=16'} + + type-fest@4.31.0: + resolution: {integrity: sha512-yCxltHW07Nkhv/1F6wWBr8kz+5BGMfP+RbRSYFnegVb0qV/UMT0G0ElBloPVerqn4M2ZV80Ir1FtCcYv1cT6vQ==} + engines: {node: '>=16'} + + type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + + typescript@4.6.4: + resolution: {integrity: sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==} + engines: {node: '>=4.2.0'} + hasBin: true + + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} + engines: {node: '>=14.17'} + hasBin: true + + ua-parser-js@1.0.40: + resolution: {integrity: sha512-z6PJ8Lml+v3ichVojCiB8toQJBuwR42ySM4ezjXIqXK3M0HczmKQ3LF4rhU55PfD99KEEXQG6yb7iOMyvYuHew==} + hasBin: true + + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + unbzip2-stream@1.4.3: + resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==} + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + + unicode-canonical-property-names-ecmascript@2.0.1: + resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} + engines: {node: '>=4'} + + unicode-match-property-ecmascript@2.0.0: + resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} + engines: {node: '>=4'} + + unicode-match-property-value-ecmascript@2.2.0: + resolution: {integrity: sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==} + engines: {node: '>=4'} + + unicode-match-property-value-ecmascript@2.2.1: + resolution: {integrity: sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==} + engines: {node: '>=4'} + + unicode-property-aliases-ecmascript@2.1.0: + resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} + engines: {node: '>=4'} + + unicorn-magic@0.3.0: + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} + engines: {node: '>=18'} + + unique-filename@1.1.1: + resolution: {integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==} + + unique-slug@2.0.2: + resolution: {integrity: sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==} + + universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + + universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + update-browserslist-db@1.1.1: + resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + upper-case-first@2.0.2: + resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==} + + upper-case@2.0.2: + resolution: {integrity: sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + + userhome@1.0.1: + resolution: {integrity: sha512-5cnLm4gseXjAclKowC4IjByaGsjtAoV6PrOQOljplNB54ReUYJP8HdAFq2muHinSDAh09PPX/uXDPfdxRHvuSA==} + engines: {node: '>= 0.8.0'} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + util@0.10.4: + resolution: {integrity: sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==} + + utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + + uuid@11.1.1: + resolution: {integrity: sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==} + hasBin: true + + uuid@3.4.0: + resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). + hasBin: true + + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + + v8-compile-cache@2.4.0: + resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==} + + v8-to-istanbul@9.3.0: + resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} + engines: {node: '>=10.12.0'} + + validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + + validate-npm-package-name@3.0.0: + resolution: {integrity: sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + verror@1.10.0: + resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} + engines: {'0': node >=0.6.0} + + vlq@1.0.1: + resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} + + w3c-hr-time@1.0.2: + resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==} + deprecated: Use your platform's native performance.now() and performance.timeOrigin. + + w3c-xmlserializer@3.0.0: + resolution: {integrity: sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==} + engines: {node: '>=12'} + + wait-port@1.1.0: + resolution: {integrity: sha512-3e04qkoN3LxTMLakdqeWth8nih8usyg+sf1Bgdf9wwUkp05iuK1eSY/QpLvscT/+F/gA89+LpUmmgBtesbqI2Q==} + engines: {node: '>=10'} + hasBin: true + + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + + wcwidth@1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + + wdio-chromedriver-service@8.1.1: + resolution: {integrity: sha512-pN3GiOkTIMnalfq4PJAHdX95pDp1orHnTY8W1fIbd6ok81ba97UjerTgS7lUDRUh1p0MAm35Ww0uc0/9wzB7SA==} + engines: {node: ^16.13 || >=18} + peerDependencies: + '@wdio/types': ^7.0.0 || ^8.0.0-alpha.219 + chromedriver: '*' + webdriverio: ^7.0.0 || ^8.0.0-alpha.219 + peerDependenciesMeta: + '@wdio/types': + optional: true + chromedriver: + optional: true + + wdio-edgedriver-service@3.0.3: + resolution: {integrity: sha512-oHKUFnh9Nn4s749Yl8hp20xvfF8GnK4jNV84qoy52/a0ETgWh0FG5qlRVXBIqIulqhGlfrCgL5/pIizMnEix1w==} + engines: {node: ^16.13 || >=18} + peerDependencies: + '@wdio/types': ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@wdio/types': + optional: true + + wdio-safaridriver-service@2.1.1: + resolution: {integrity: sha512-Rz8uls7EY0bHOZJpykmAMIQzT0gNe6lg32XdCjO/ppSvscWKP57lePGWD80RCU4kKnwX1TbrTivqfjl6vK/1rQ==} + engines: {node: ^16.13 || >=18} + peerDependencies: + '@wdio/types': ^7.0.0 || ^8.0.0-alpha.219 + webdriverio: ^7.0.0 || ^8.0.0-alpha.219 + peerDependenciesMeta: + '@wdio/types': + optional: true + + weakmap-polyfill@2.0.4: + resolution: {integrity: sha512-ZzxBf288iALJseijWelmECm/1x7ZwQn3sMYIkDr2VvZp7r6SEKuT8D0O9Wiq6L9Nl5mazrOMcmiZE/2NCenaxw==} + engines: {node: '>=8.10.0'} + + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + + web-vitals@4.2.4: + resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==} + + webdriver@8.39.0: + resolution: {integrity: sha512-Kc3+SfiH4ufyrIht683VT2vnJocx0pfH8rYdyPvEh1b2OYewtFTHK36k9rBDHZiBmk6jcSXs4M2xeFgOuon9Lg==} + engines: {node: ^16.13 || >=18} + + webdriverio@8.39.1: + resolution: {integrity: sha512-dPwLgLNtP+l4vnybz+YFxxH8nBKOP7j6VVzKtfDyTLDQg9rz3U8OA4xMMQCBucnrVXy3KcKxGqlnMa+c4IfWCQ==} + engines: {node: ^16.13 || >=18} + peerDependencies: + devtools: ^8.14.0 + peerDependenciesMeta: + devtools: + optional: true + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + well-known-symbols@2.0.0: + resolution: {integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==} + engines: {node: '>=6'} + + whatwg-encoding@2.0.0: + resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} + engines: {node: '>=12'} + + whatwg-fetch@3.6.20: + resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} + + whatwg-mimetype@3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + + whatwg-url@10.0.0: + resolution: {integrity: sha512-CLxxCmdUby142H5FZzn4D8ikO1cmypvXVQktsgosNy4a4BHrDHeciBBGZhb0bNoR5/MltoCatso+vFjjGx8t0w==} + engines: {node: '>=12'} + + whatwg-url@11.0.0: + resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==} + engines: {node: '>=12'} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + + which-typed-array@1.1.18: + resolution: {integrity: sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==} + engines: {node: '>= 0.4'} + + which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + which@4.0.0: + resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} + engines: {node: ^16.13.0 || >=18.0.0} + hasBin: true + + which@6.0.1: + resolution: {integrity: sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + + wide-align@1.1.5: + resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + + widest-line@3.1.0: + resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==} + engines: {node: '>=8'} + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrap-ansi@9.0.2: + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} + engines: {node: '>=18'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + write-file-atomic@2.4.3: + resolution: {integrity: sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==} + + write-file-atomic@4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + ws@6.2.3: + resolution: {integrity: sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==} + + ws@7.5.10: + resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.13.0: + resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xml-name-validator@4.0.0: + resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} + engines: {node: '>=12'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yaml@2.6.1: + resolution: {integrity: sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==} + engines: {node: '>= 14'} + hasBin: true + + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + + yargs@17.7.1: + resolution: {integrity: sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yargs@18.0.0: + resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + + yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + + yazl@2.5.1: + resolution: {integrity: sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==} + + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + yocto-queue@1.1.1: + resolution: {integrity: sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==} + engines: {node: '>=12.20'} + + zip-stream@6.0.1: + resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} + engines: {node: '>= 14'} + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + + '@ark/schema@0.56.0': + dependencies: + '@ark/util': 0.56.0 + + '@ark/util@0.56.0': {} + + '@arr/every@1.0.1': {} + + '@babel/code-frame@7.26.2': + dependencies: + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.26.3': {} + + '@babel/compat-data@7.29.7': {} + + '@babel/core@7.26.0': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.3 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helpers': 7.26.0 + '@babel/parser': 7.26.3 + '@babel/template': 7.25.9 + '@babel/traverse': 7.26.4 + '@babel/types': 7.26.3 + convert-source-map: 2.0.0 + debug: 4.4.0 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/core@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.0 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.26.3': + dependencies: + '@babel/parser': 7.26.3 + '@babel/types': 7.26.3 + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.1.0 + + '@babel/generator@7.29.7': + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-annotate-as-pure@7.25.9': + dependencies: + '@babel/types': 7.26.3 + + '@babel/helper-annotate-as-pure@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/helper-compilation-targets@7.25.9': + dependencies: + '@babel/compat-data': 7.26.3 + '@babel/helper-validator-option': 7.25.9 + browserslist: 4.24.3 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.28.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-member-expression-to-functions': 7.25.9 + '@babel/helper-optimise-call-expression': 7.25.9 + '@babel/helper-replace-supers': 7.25.9(@babel/core@7.26.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/traverse': 7.26.4 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/helper-optimise-call-expression': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/traverse': 7.29.7 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-create-regexp-features-plugin@7.26.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + regexpu-core: 6.2.0 + semver: 6.3.1 + + '@babel/helper-create-regexp-features-plugin@7.26.3(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.25.9 + regexpu-core: 6.2.0 + semver: 6.3.1 + + '@babel/helper-create-regexp-features-plugin@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + regexpu-core: 6.4.0 + semver: 6.3.1 + + '@babel/helper-define-polyfill-provider@0.6.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + debug: 4.4.0 + lodash.debounce: 4.0.8 + resolve: 1.22.10 + transitivePeerDependencies: + - supports-color + + '@babel/helper-define-polyfill-provider@0.6.3(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + debug: 4.4.0 + lodash.debounce: 4.0.8 + resolve: 1.22.10 + transitivePeerDependencies: + - supports-color + optional: true + + '@babel/helper-define-polyfill-provider@0.6.8(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + debug: 4.4.3 + lodash.debounce: 4.0.8 + resolve: 1.22.12 + transitivePeerDependencies: + - supports-color + + '@babel/helper-environment-visitor@7.24.7': + dependencies: + '@babel/types': 7.26.3 + + '@babel/helper-globals@7.29.7': {} + + '@babel/helper-member-expression-to-functions@7.25.9': + dependencies: + '@babel/traverse': 7.26.4 + '@babel/types': 7.26.3 + transitivePeerDependencies: + - supports-color + + '@babel/helper-member-expression-to-functions@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.25.9': + dependencies: + '@babel/traverse': 7.26.4 + '@babel/types': 7.26.3 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + '@babel/traverse': 7.26.4 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-optimise-call-expression@7.25.9': + dependencies: + '@babel/types': 7.26.3 + + '@babel/helper-optimise-call-expression@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/helper-plugin-utils@7.25.9': {} + + '@babel/helper-plugin-utils@7.29.7': {} + + '@babel/helper-remap-async-to-generator@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-wrap-function': 7.25.9 + '@babel/traverse': 7.26.4 + transitivePeerDependencies: + - supports-color + + '@babel/helper-remap-async-to-generator@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-wrap-function': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-replace-supers@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-member-expression-to-functions': 7.25.9 + '@babel/helper-optimise-call-expression': 7.25.9 + '@babel/traverse': 7.26.4 + transitivePeerDependencies: + - supports-color + + '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/helper-optimise-call-expression': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.25.9': + dependencies: + '@babel/traverse': 7.26.4 + '@babel/types': 7.26.3 + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.25.9': {} + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.25.9': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/helper-validator-option@7.25.9': {} + + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helper-wrap-function@7.25.9': + dependencies: + '@babel/template': 7.25.9 + '@babel/traverse': 7.26.4 + '@babel/types': 7.26.3 + transitivePeerDependencies: + - supports-color + + '@babel/helper-wrap-function@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helpers@7.26.0': + dependencies: + '@babel/template': 7.25.9 + '@babel/types': 7.26.3 + + '@babel/helpers@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/parser@7.26.3': + dependencies: + '@babel/types': 7.26.3 + + '@babel/parser@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-proposal-export-default-from@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-proposal-logical-assignment-operators@7.20.7(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.26.0) + + '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0) + + '@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.26.0) + + '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.26.0)': + dependencies: + '@babel/compat-data': 7.26.3 + '@babel/core': 7.26.0 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) + + '@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.26.0) + + '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.25.9 + optional: true + + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.25.9 + optional: true + + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.25.9 + optional: true + + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.25.9 + optional: true + + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-export-default-from@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-flow@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-flow@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-import-assertions@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.25.9 + optional: true + + '@babel/plugin-syntax-import-attributes@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.25.9 + optional: true + + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.25.9 + optional: true + + '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.25.9 + optional: true + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.25.9 + optional: true + + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.25.9 + optional: true + + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.25.9 + optional: true + + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.25.9 + optional: true + + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.25.9 + optional: true + + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.25.9 + optional: true + + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.25.9 + optional: true + + '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-arrow-functions@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-transform-arrow-functions@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-async-generator-functions@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7) + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-async-to-generator@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-async-to-generator@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-block-scoped-functions@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-block-scoping@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-transform-block-scoping@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-class-properties@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-class-static-block@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-classes@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-replace-supers': 7.25.9(@babel/core@7.26.0) + '@babel/traverse': 7.26.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-classes@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-computed-properties@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/template': 7.25.9 + + '@babel/plugin-transform-computed-properties@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/template': 7.29.7 + + '@babel/plugin-transform-destructuring@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-transform-destructuring@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-dotall-regex@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-duplicate-keys@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-dynamic-import@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-explicit-resource-management@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-exponentiation-operator@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-export-namespace-from@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-flow-strip-types@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-flow': 7.26.0(@babel/core@7.26.0) + + '@babel/plugin-transform-flow-strip-types@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-syntax-flow': 7.29.7(@babel/core@7.29.7) + + '@babel/plugin-transform-for-of@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-function-name@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/traverse': 7.26.4 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-function-name@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-json-strings@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-literals@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-transform-literals@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-logical-assignment-operators@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-member-expression-literals@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-modules-amd@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-commonjs@7.26.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-commonjs@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-systemjs@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-umd@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-named-capturing-groups-regex@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-transform-named-capturing-groups-regex@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-new-target@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-nullish-coalescing-operator@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-numeric-separator@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-object-rest-spread@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7) + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-object-super@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-optional-catch-binding@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-optional-chaining@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-parameters@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-transform-parameters@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-private-methods@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-private-methods@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-private-property-in-object@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-private-property-in-object@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-property-literals@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-react-display-name@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-transform-react-display-name@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-react-jsx-development@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-transform-react-jsx@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) + '@babel/types': 7.26.3 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-react-pure-annotations@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-regenerator@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-regexp-modifiers@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-reserved-words@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-runtime@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + babel-plugin-polyfill-corejs2: 0.4.12(@babel/core@7.26.0) + babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.26.0) + babel-plugin-polyfill-regenerator: 0.6.3(@babel/core@7.26.0) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-plugin-utils': 7.25.9 + babel-plugin-polyfill-corejs2: 0.4.12(@babel/core@7.29.7) + babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.29.7) + babel-plugin-polyfill-regenerator: 0.6.3(@babel/core@7.29.7) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + optional: true + + '@babel/plugin-transform-shorthand-properties@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-transform-shorthand-properties@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-spread@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-spread@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-sticky-regex@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-transform-sticky-regex@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-strict-mode@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-template-literals@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-typeof-symbol@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-typescript@7.26.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-typescript@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-unicode-escapes@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-unicode-property-regex@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-unicode-regex@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-transform-unicode-regex@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-unicode-sets-regex@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/preset-env@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/core': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.7) + '@babel/plugin-syntax-import-assertions': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-import-attributes': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.29.7) + '@babel/plugin-transform-arrow-functions': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-async-generator-functions': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-async-to-generator': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-block-scoped-functions': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-block-scoping': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-class-properties': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-class-static-block': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-classes': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-computed-properties': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-dotall-regex': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-duplicate-keys': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-dynamic-import': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-explicit-resource-management': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-exponentiation-operator': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-export-namespace-from': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-for-of': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-function-name': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-json-strings': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-literals': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-logical-assignment-operators': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-member-expression-literals': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-modules-amd': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-modules-systemjs': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-modules-umd': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-new-target': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-nullish-coalescing-operator': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-numeric-separator': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-object-rest-spread': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-object-super': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-optional-catch-binding': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-private-methods': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-private-property-in-object': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-property-literals': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-regenerator': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-regexp-modifiers': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-reserved-words': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-shorthand-properties': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-spread': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-sticky-regex': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-template-literals': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-typeof-symbol': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-unicode-escapes': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-unicode-property-regex': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-unicode-regex': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-unicode-sets-regex': 7.29.7(@babel/core@7.29.7) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.29.7) + babel-plugin-polyfill-corejs2: 0.4.17(@babel/core@7.29.7) + babel-plugin-polyfill-corejs3: 0.14.2(@babel/core@7.29.7) + babel-plugin-polyfill-regenerator: 0.6.8(@babel/core@7.29.7) + core-js-compat: 3.49.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/preset-flow@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-validator-option': 7.25.9 + '@babel/plugin-transform-flow-strip-types': 7.25.9(@babel/core@7.26.0) + + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/types': 7.26.3 + esutils: 2.0.3 + + '@babel/preset-react@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + '@babel/plugin-transform-react-display-name': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-react-jsx-development': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-react-pure-annotations': 7.29.7(@babel/core@7.29.7) + transitivePeerDependencies: + - supports-color + + '@babel/preset-typescript@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/helper-validator-option': 7.25.9 + '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-modules-commonjs': 7.26.3(@babel/core@7.26.0) + '@babel/plugin-transform-typescript': 7.26.3(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color + + '@babel/preset-typescript@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) + transitivePeerDependencies: + - supports-color + + '@babel/register@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + clone-deep: 4.0.1 + find-cache-dir: 2.1.0 + make-dir: 2.1.0 + pirates: 4.0.6 + source-map-support: 0.5.21 + + '@babel/runtime@7.26.0': + dependencies: + regenerator-runtime: 0.14.1 + + '@babel/template@7.25.9': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/parser': 7.26.3 + '@babel/types': 7.26.3 + + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/traverse@7.26.4': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.3 + '@babel/parser': 7.26.3 + '@babel/template': 7.25.9 + '@babel/types': 7.26.3 + debug: 4.4.0 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/traverse@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.26.3': + dependencies: + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + + '@babel/types@7.29.7': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@balena/dockerignore@1.0.2': {} + + '@bcoe/v8-coverage@0.2.3': {} + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@eggjs/yauzl@2.11.0': + dependencies: + buffer-crc32: 0.2.13 + fd-slicer2: 1.2.0 + + '@eslint/eslintrc@1.4.1': + dependencies: + ajv: 6.12.6 + debug: 4.4.0 + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.2 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@fingerprintjs/botd@2.0.0': {} + + '@gar/promisify@1.1.3': {} + + '@hapi/hoek@9.3.0': {} + + '@hapi/topo@5.1.0': + dependencies: + '@hapi/hoek': 9.3.0 + + '@humanwhocodes/config-array@0.9.5': + dependencies: + '@humanwhocodes/object-schema': 1.2.1 + debug: 4.4.0 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@humanwhocodes/object-schema@1.2.1': {} + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@isaacs/ttlcache@1.4.1': {} + + '@istanbuljs/load-nyc-config@1.1.0': + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.1 + resolve-from: 5.0.0 + + '@istanbuljs/schema@0.1.3': {} + + '@jest/console@26.6.2': + dependencies: + '@jest/types': 26.6.2 + '@types/node': 14.6.4 + chalk: 4.1.2 + jest-message-util: 26.6.2 + jest-util: 26.6.2 + slash: 3.0.0 + + '@jest/console@28.1.3': + dependencies: + '@jest/types': 28.1.3 + '@types/node': 14.6.4 + chalk: 4.1.2 + jest-message-util: 28.1.3 + jest-util: 28.1.3 + slash: 3.0.0 + + '@jest/core@28.1.3(ts-node@10.9.2(@types/node@14.6.4)(typescript@4.6.4))': + dependencies: + '@jest/console': 28.1.3 + '@jest/reporters': 28.1.3 + '@jest/test-result': 28.1.3 + '@jest/transform': 28.1.3 + '@jest/types': 28.1.3 + '@types/node': 14.6.4 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 28.1.3 + jest-config: 28.1.3(@types/node@14.6.4)(ts-node@10.9.2(@types/node@14.6.4)(typescript@4.6.4)) + jest-haste-map: 28.1.3 + jest-message-util: 28.1.3 + jest-regex-util: 28.0.2 + jest-resolve: 28.1.3 + jest-resolve-dependencies: 28.1.3 + jest-runner: 28.1.3 + jest-runtime: 28.1.3 + jest-snapshot: 28.1.3 + jest-util: 28.1.3 + jest-validate: 28.1.3 + jest-watcher: 28.1.3 + micromatch: 4.0.8 + pretty-format: 28.1.3 + rimraf: 3.0.2 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - supports-color + - ts-node + + '@jest/core@28.1.3(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4))': + dependencies: + '@jest/console': 28.1.3 + '@jest/reporters': 28.1.3 + '@jest/test-result': 28.1.3 + '@jest/transform': 28.1.3 + '@jest/types': 28.1.3 + '@types/node': 14.6.4 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 28.1.3 + jest-config: 28.1.3(@types/node@14.6.4)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-haste-map: 28.1.3 + jest-message-util: 28.1.3 + jest-regex-util: 28.0.2 + jest-resolve: 28.1.3 + jest-resolve-dependencies: 28.1.3 + jest-runner: 28.1.3 + jest-runtime: 28.1.3 + jest-snapshot: 28.1.3 + jest-util: 28.1.3 + jest-validate: 28.1.3 + jest-watcher: 28.1.3 + micromatch: 4.0.8 + pretty-format: 28.1.3 + rimraf: 3.0.2 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - supports-color + - ts-node + + '@jest/create-cache-key-function@29.7.0': + dependencies: + '@jest/types': 29.6.3 + + '@jest/environment@28.1.3': + dependencies: + '@jest/fake-timers': 28.1.3 + '@jest/types': 28.1.3 + '@types/node': 14.6.4 + jest-mock: 28.1.3 + + '@jest/environment@29.7.0': + dependencies: + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 14.6.4 + jest-mock: 29.7.0 + + '@jest/expect-utils@28.1.3': + dependencies: + jest-get-type: 28.0.2 + + '@jest/expect-utils@29.7.0': + dependencies: + jest-get-type: 29.6.3 + + '@jest/expect@28.1.3': + dependencies: + expect: 28.1.3 + jest-snapshot: 28.1.3 + transitivePeerDependencies: + - supports-color + + '@jest/fake-timers@28.1.3': + dependencies: + '@jest/types': 28.1.3 + '@sinonjs/fake-timers': 9.1.2 + '@types/node': 14.6.4 + jest-message-util: 28.1.3 + jest-mock: 28.1.3 + jest-util: 28.1.3 + + '@jest/fake-timers@29.7.0': + dependencies: + '@jest/types': 29.6.3 + '@sinonjs/fake-timers': 10.3.0 + '@types/node': 14.6.4 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + '@jest/globals@28.1.3': + dependencies: + '@jest/environment': 28.1.3 + '@jest/expect': 28.1.3 + '@jest/types': 28.1.3 + transitivePeerDependencies: + - supports-color + + '@jest/reporters@28.1.3': + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 28.1.3 + '@jest/test-result': 28.1.3 + '@jest/transform': 28.1.3 + '@jest/types': 28.1.3 + '@jridgewell/trace-mapping': 0.3.25 + '@types/node': 14.6.4 + chalk: 4.1.2 + collect-v8-coverage: 1.0.2 + exit: 0.1.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 5.2.1 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.7 + jest-message-util: 28.1.3 + jest-util: 28.1.3 + jest-worker: 28.1.3 + slash: 3.0.0 + string-length: 4.0.2 + strip-ansi: 6.0.1 + terminal-link: 2.1.1 + v8-to-istanbul: 9.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/schemas@28.1.3': + dependencies: + '@sinclair/typebox': 0.24.51 + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.8 + + '@jest/source-map@28.1.2': + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + callsites: 3.1.0 + graceful-fs: 4.2.11 + + '@jest/test-result@28.1.3': + dependencies: + '@jest/console': 28.1.3 + '@jest/types': 28.1.3 + '@types/istanbul-lib-coverage': 2.0.6 + collect-v8-coverage: 1.0.2 + + '@jest/test-sequencer@28.1.3': + dependencies: + '@jest/test-result': 28.1.3 + graceful-fs: 4.2.11 + jest-haste-map: 28.1.3 + slash: 3.0.0 + + '@jest/transform@28.1.3': + dependencies: + '@babel/core': 7.26.0 + '@jest/types': 28.1.3 + '@jridgewell/trace-mapping': 0.3.25 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 1.9.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 28.1.3 + jest-regex-util: 28.0.2 + jest-util: 28.1.3 + micromatch: 4.0.8 + pirates: 4.0.6 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + + '@jest/types@26.6.2': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 14.6.4 + '@types/yargs': 15.0.19 + chalk: 4.1.2 + + '@jest/types@28.1.3': + dependencies: + '@jest/schemas': 28.1.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 14.6.4 + '@types/yargs': 17.0.33 + chalk: 4.1.2 + + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 14.6.4 + '@types/yargs': 17.0.33 + chalk: 4.1.2 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/gen-mapping@0.3.8': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/source-map@0.3.6': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@ljharb/through@2.3.13': + dependencies: + call-bind: 1.0.8 + + '@mdn/browser-compat-data@4.2.1': {} + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.18.0 + + '@npmcli/fs@1.1.1': + dependencies: + '@gar/promisify': 1.1.3 + semver: 7.6.3 + + '@npmcli/git@2.1.0': + dependencies: + '@npmcli/promise-spawn': 1.3.2 + lru-cache: 6.0.0 + mkdirp: 1.0.4 + npm-pick-manifest: 6.1.1 + promise-inflight: 1.0.1 + promise-retry: 2.0.1 + semver: 7.6.3 + which: 2.0.2 + + '@npmcli/installed-package-contents@1.0.7': + dependencies: + npm-bundled: 1.1.2 + npm-normalize-package-bin: 1.0.1 + + '@npmcli/move-file@1.1.2': + dependencies: + mkdirp: 1.0.4 + rimraf: 3.0.2 + + '@npmcli/node-gyp@1.0.3': {} + + '@npmcli/promise-spawn@1.3.2': + dependencies: + infer-owner: 1.0.4 + + '@npmcli/run-script@1.8.6': + dependencies: + '@npmcli/node-gyp': 1.0.3 + '@npmcli/promise-spawn': 1.3.2 + node-gyp: 7.1.2 + read-package-json-fast: 2.0.3 + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@polka/parse@1.0.0-next.0': {} + + '@polka/url@0.5.0': {} + + '@promptbook/utils@0.69.5': + dependencies: + spacetrim: 0.11.59 + + '@puppeteer/browsers@1.4.6(typescript@4.6.4)': + dependencies: + debug: 4.3.4 + extract-zip: 2.0.1 + progress: 2.0.3 + proxy-agent: 6.3.0 + tar-fs: 3.0.4 + unbzip2-stream: 1.4.3 + yargs: 17.7.1 + optionalDependencies: + typescript: 4.6.4 + transitivePeerDependencies: + - supports-color + + '@puppeteer/browsers@1.9.1': + dependencies: + debug: 4.3.4 + extract-zip: 2.0.1 + progress: 2.0.3 + proxy-agent: 6.3.1 + tar-fs: 3.0.4 + unbzip2-stream: 1.4.3 + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color + + '@react-native-async-storage/async-storage@2.0.0(react-native@0.74.5(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@types/react@18.3.18)(encoding@0.1.13)(react@18.2.0))': + dependencies: + merge-options: 3.0.4 + react-native: 0.74.5(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@types/react@18.3.18)(encoding@0.1.13)(react@18.2.0) + + '@react-native-community/cli-clean@13.6.9(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-tools': 13.6.9(encoding@0.1.13) + chalk: 4.1.2 + execa: 5.1.1 + fast-glob: 3.3.2 + transitivePeerDependencies: + - encoding + + '@react-native-community/cli-config@13.6.9(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-tools': 13.6.9(encoding@0.1.13) + chalk: 4.1.2 + cosmiconfig: 5.2.1 + deepmerge: 4.3.1 + fast-glob: 3.3.2 + joi: 17.13.3 + transitivePeerDependencies: + - encoding + + '@react-native-community/cli-debugger-ui@13.6.9': + dependencies: + serve-static: 1.16.2 + + '@react-native-community/cli-doctor@13.6.9(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-config': 13.6.9(encoding@0.1.13) + '@react-native-community/cli-platform-android': 13.6.9(encoding@0.1.13) + '@react-native-community/cli-platform-apple': 13.6.9(encoding@0.1.13) + '@react-native-community/cli-platform-ios': 13.6.9(encoding@0.1.13) + '@react-native-community/cli-tools': 13.6.9(encoding@0.1.13) + chalk: 4.1.2 + command-exists: 1.2.9 + deepmerge: 4.3.1 + envinfo: 7.14.0 + execa: 5.1.1 + hermes-profile-transformer: 0.0.6 + node-stream-zip: 1.15.0 + ora: 5.4.1 + semver: 7.6.3 + strip-ansi: 5.2.0 + wcwidth: 1.0.1 + yaml: 2.6.1 + transitivePeerDependencies: + - encoding + + '@react-native-community/cli-hermes@13.6.9(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-platform-android': 13.6.9(encoding@0.1.13) + '@react-native-community/cli-tools': 13.6.9(encoding@0.1.13) + chalk: 4.1.2 + hermes-profile-transformer: 0.0.6 + transitivePeerDependencies: + - encoding + + '@react-native-community/cli-platform-android@13.6.9(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-tools': 13.6.9(encoding@0.1.13) + chalk: 4.1.2 + execa: 5.1.1 + fast-glob: 3.3.2 + fast-xml-parser: 4.5.1 + logkitty: 0.7.1 + transitivePeerDependencies: + - encoding + + '@react-native-community/cli-platform-apple@13.6.9(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-tools': 13.6.9(encoding@0.1.13) + chalk: 4.1.2 + execa: 5.1.1 + fast-glob: 3.3.2 + fast-xml-parser: 4.5.1 + ora: 5.4.1 + transitivePeerDependencies: + - encoding + + '@react-native-community/cli-platform-ios@13.6.9(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-platform-apple': 13.6.9(encoding@0.1.13) + transitivePeerDependencies: + - encoding + + '@react-native-community/cli-server-api@13.6.9(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-debugger-ui': 13.6.9 + '@react-native-community/cli-tools': 13.6.9(encoding@0.1.13) + compression: 1.7.5 + connect: 3.7.0 + errorhandler: 1.5.1 + nocache: 3.0.4 + pretty-format: 26.6.2 + serve-static: 1.16.2 + ws: 6.2.3 + transitivePeerDependencies: + - encoding + + '@react-native-community/cli-tools@13.6.9(encoding@0.1.13)': + dependencies: + appdirsjs: 1.2.7 + chalk: 4.1.2 + execa: 5.1.1 + find-up: 5.0.0 + mime: 2.6.0 + node-fetch: 2.7.0(encoding@0.1.13) + open: 6.4.0 + ora: 5.4.1 + semver: 7.6.3 + shell-quote: 1.8.2 + sudo-prompt: 9.2.1 + transitivePeerDependencies: + - encoding + + '@react-native-community/cli-types@13.6.9': + dependencies: + joi: 17.13.3 + + '@react-native-community/cli@13.6.9(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-clean': 13.6.9(encoding@0.1.13) + '@react-native-community/cli-config': 13.6.9(encoding@0.1.13) + '@react-native-community/cli-debugger-ui': 13.6.9 + '@react-native-community/cli-doctor': 13.6.9(encoding@0.1.13) + '@react-native-community/cli-hermes': 13.6.9(encoding@0.1.13) + '@react-native-community/cli-server-api': 13.6.9(encoding@0.1.13) + '@react-native-community/cli-tools': 13.6.9(encoding@0.1.13) + '@react-native-community/cli-types': 13.6.9 + chalk: 4.1.2 + commander: 9.5.0 + deepmerge: 4.3.1 + execa: 5.1.1 + find-up: 4.1.0 + fs-extra: 8.1.0 + graceful-fs: 4.2.11 + prompts: 2.4.2 + semver: 7.6.3 + transitivePeerDependencies: + - encoding + + '@react-native/assets-registry@0.74.87': {} + + '@react-native/babel-plugin-codegen@0.74.87(@babel/preset-env@7.29.7(@babel/core@7.29.7))': + dependencies: + '@react-native/codegen': 0.74.87(@babel/preset-env@7.29.7(@babel/core@7.29.7)) + transitivePeerDependencies: + - '@babel/preset-env' + - supports-color + + '@react-native/babel-preset@0.74.87(@babel/preset-env@7.29.7(@babel/core@7.29.7))': + dependencies: + '@babel/core': 7.26.0 + '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.26.0) + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.26.0) + '@babel/plugin-proposal-export-default-from': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-proposal-logical-assignment-operators': 7.20.7(@babel/core@7.26.0) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.26.0) + '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.26.0) + '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.26.0) + '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.26.0) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.26.0) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-export-default-from': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-syntax-flow': 7.26.0(@babel/core@7.26.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-flow-strip-types': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-modules-commonjs': 7.26.3(@babel/core@7.26.0) + '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-react-display-name': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-runtime': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-typescript': 7.26.3(@babel/core@7.26.0) + '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.26.0) + '@babel/template': 7.25.9 + '@react-native/babel-plugin-codegen': 0.74.87(@babel/preset-env@7.29.7(@babel/core@7.29.7)) + babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.26.0) + react-refresh: 0.14.2 + transitivePeerDependencies: + - '@babel/preset-env' + - supports-color + + '@react-native/codegen@0.74.87(@babel/preset-env@7.29.7(@babel/core@7.29.7))': + dependencies: + '@babel/parser': 7.26.3 + '@babel/preset-env': 7.29.7(@babel/core@7.29.7) + glob: 7.2.3 + hermes-parser: 0.19.1 + invariant: 2.2.4 + jscodeshift: 0.14.0(@babel/preset-env@7.29.7(@babel/core@7.29.7)) + mkdirp: 0.5.6 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + + '@react-native/community-cli-plugin@0.74.87(@babel/preset-env@7.29.7(@babel/core@7.29.7))(encoding@0.1.13)': + dependencies: + '@react-native-community/cli-server-api': 13.6.9(encoding@0.1.13) + '@react-native-community/cli-tools': 13.6.9(encoding@0.1.13) + '@react-native/dev-middleware': 0.74.87(encoding@0.1.13) + '@react-native/metro-babel-transformer': 0.74.87(@babel/preset-env@7.29.7(@babel/core@7.29.7)) + chalk: 4.1.2 + execa: 5.1.1 + metro: 0.80.12 + metro-config: 0.80.12 + metro-core: 0.80.12 + node-fetch: 2.7.0(encoding@0.1.13) + querystring: 0.2.1 + readline: 1.3.0 + transitivePeerDependencies: + - '@babel/preset-env' + - bufferutil + - encoding + - supports-color + - utf-8-validate + + '@react-native/debugger-frontend@0.74.87': {} + + '@react-native/dev-middleware@0.74.87(encoding@0.1.13)': + dependencies: + '@isaacs/ttlcache': 1.4.1 + '@react-native/debugger-frontend': 0.74.87 + '@rnx-kit/chromium-edge-launcher': 1.0.0 + chrome-launcher: 0.15.2 + connect: 3.7.0 + debug: 2.6.9 + node-fetch: 2.7.0(encoding@0.1.13) + nullthrows: 1.1.1 + open: 7.4.2 + selfsigned: 2.4.1 + serve-static: 1.16.2 + temp-dir: 2.0.0 + ws: 6.2.3 + transitivePeerDependencies: + - encoding + + '@react-native/gradle-plugin@0.74.87': {} + + '@react-native/js-polyfills@0.74.87': {} + + '@react-native/metro-babel-transformer@0.74.87(@babel/preset-env@7.29.7(@babel/core@7.29.7))': + dependencies: + '@babel/core': 7.26.0 + '@react-native/babel-preset': 0.74.87(@babel/preset-env@7.29.7(@babel/core@7.29.7)) + hermes-parser: 0.19.1 + nullthrows: 1.1.1 + transitivePeerDependencies: + - '@babel/preset-env' + - supports-color + + '@react-native/normalize-colors@0.74.87': {} + + '@react-native/virtualized-lists@0.74.87(@types/react@18.3.18)(react-native@0.74.5(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@types/react@18.3.18)(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': + dependencies: + invariant: 2.2.4 + nullthrows: 1.1.1 + react: 18.2.0 + react-native: 0.74.5(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@types/react@18.3.18)(encoding@0.1.13)(react@18.2.0) + optionalDependencies: + '@types/react': 18.3.18 + + '@rnx-kit/chromium-edge-launcher@1.0.0': + dependencies: + '@types/node': 18.19.68 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 1.4.2 + mkdirp: 1.0.4 + rimraf: 3.0.2 + + '@rollup/plugin-alias@3.1.9(rollup@2.70.2)': + dependencies: + rollup: 2.70.2 + slash: 3.0.0 + + '@rollup/plugin-commonjs@21.0.3(rollup@2.70.2)': + dependencies: + '@rollup/pluginutils': 3.1.0(rollup@2.70.2) + commondir: 1.0.1 + estree-walker: 2.0.2 + glob: 7.2.3 + is-reference: 1.2.1 + magic-string: 0.25.9 + resolve: 1.22.10 + rollup: 2.70.2 + + '@rollup/plugin-json@4.1.0(rollup@2.70.2)': + dependencies: + '@rollup/pluginutils': 3.1.0(rollup@2.70.2) + rollup: 2.70.2 + + '@rollup/plugin-node-resolve@13.1.3(rollup@2.70.2)': + dependencies: + '@rollup/pluginutils': 3.1.0(rollup@2.70.2) + '@types/resolve': 1.17.1 + builtin-modules: 3.3.0 + deepmerge: 4.3.1 + is-module: 1.0.0 + resolve: 1.22.10 + rollup: 2.70.2 + + '@rollup/plugin-replace@4.0.0(rollup@2.70.2)': + dependencies: + '@rollup/pluginutils': 3.1.0(rollup@2.70.2) + magic-string: 0.25.9 + rollup: 2.70.2 + + '@rollup/pluginutils@3.1.0(rollup@2.70.2)': + dependencies: + '@types/estree': 0.0.39 + estree-walker: 1.0.1 + picomatch: 2.3.1 + rollup: 2.70.2 + + '@rollup/pluginutils@4.2.1': + dependencies: + estree-walker: 2.0.2 + picomatch: 2.3.1 + + '@sideway/address@4.1.5': + dependencies: + '@hapi/hoek': 9.3.0 + + '@sideway/formula@3.0.1': {} + + '@sideway/pinpoint@2.0.0': {} + + '@sinclair/typebox@0.24.51': {} + + '@sinclair/typebox@0.27.8': {} + + '@sindresorhus/is@4.6.0': {} + + '@sindresorhus/is@5.6.0': {} + + '@sindresorhus/merge-streams@2.3.0': {} + + '@sinonjs/commons@1.8.6': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/fake-timers@10.3.0': + dependencies: + '@sinonjs/commons': 3.0.1 + + '@sinonjs/fake-timers@9.1.2': + dependencies: + '@sinonjs/commons': 1.8.6 + + '@snowplow/webview-tracker@0.3.1': {} + + '@szmarczak/http-timer@4.0.6': + dependencies: + defer-to-connect: 2.0.1 + + '@szmarczak/http-timer@5.0.1': + dependencies: + defer-to-connect: 2.0.1 + + '@testim/chrome-version@1.1.4': {} + + '@testing-library/dom@9.3.4': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/runtime': 7.26.0 + '@types/aria-query': 5.0.4 + aria-query: 5.1.3 + chalk: 4.1.2 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + pretty-format: 27.5.1 + + '@tootallnate/once@1.1.2': {} + + '@tootallnate/once@2.0.0': {} + + '@tootallnate/quickjs-emscripten@0.23.0': {} + + '@tsconfig/node10@1.0.11': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + + '@types/aria-query@5.0.4': {} + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.26.3 + '@babel/types': 7.26.3 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.6 + + '@types/babel__generator@7.6.8': + dependencies: + '@babel/types': 7.26.3 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.26.3 + '@babel/types': 7.26.3 + + '@types/babel__traverse@7.20.6': + dependencies: + '@babel/types': 7.26.3 + + '@types/cacheable-request@6.0.3': + dependencies: + '@types/http-cache-semantics': 4.0.4 + '@types/keyv': 3.1.4 + '@types/node': 14.6.4 + '@types/responselike': 1.0.3 + + '@types/docker-modem@3.0.6': + dependencies: + '@types/node': 14.6.4 + '@types/ssh2': 1.15.1 + + '@types/dockerode@3.3.32': + dependencies: + '@types/docker-modem': 3.0.6 + '@types/node': 14.6.4 + '@types/ssh2': 1.15.1 + + '@types/estree@0.0.39': {} + + '@types/estree@1.0.6': {} + + '@types/graceful-fs@4.1.9': + dependencies: + '@types/node': 14.6.4 + + '@types/http-cache-semantics@4.0.4': {} + + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + + '@types/jest@28.1.8': + dependencies: + expect: 28.1.3 + pretty-format: 28.1.3 + + '@types/jsdom@16.2.15': + dependencies: + '@types/node': 14.6.4 + '@types/parse5': 6.0.3 + '@types/tough-cookie': 4.0.5 + + '@types/json-schema@7.0.15': {} + + '@types/jstimezonedetect@1.0.6': {} + + '@types/keyv@3.1.4': + dependencies: + '@types/node': 14.6.4 + + '@types/lodash@4.14.202': {} + + '@types/node-forge@1.3.11': + dependencies: + '@types/node': 14.6.4 + + '@types/node@14.6.4': {} + + '@types/node@16.18.122': {} + + '@types/node@18.19.68': + dependencies: + undici-types: 5.26.5 + + '@types/node@20.17.10': + dependencies: + undici-types: 6.19.8 + + '@types/normalize-package-data@2.4.4': {} + + '@types/object-path@0.11.4': {} + + '@types/parse5@6.0.3': {} + + '@types/prettier@2.7.3': {} + + '@types/prop-types@15.7.14': {} + + '@types/randomcolor@0.5.9': {} + + '@types/react@18.3.18': + dependencies: + '@types/prop-types': 15.7.14 + csstype: 3.1.3 + + '@types/resolve@1.17.1': + dependencies: + '@types/node': 14.6.4 + + '@types/responselike@1.0.3': + dependencies: + '@types/node': 14.6.4 + + '@types/semver@7.5.8': {} + + '@types/split2@4.2.3': + dependencies: + '@types/node': 14.6.4 + + '@types/ssh2@1.15.1': + dependencies: + '@types/node': 18.19.68 + + '@types/stack-utils@2.0.3': {} + + '@types/tcp-port-used@1.0.4': {} + + '@types/tough-cookie@4.0.5': {} + + '@types/ua-parser-js@0.7.39': {} + + '@types/vimeo__player@2.16.3': {} + + '@types/which@2.0.2': {} + + '@types/ws@8.5.13': + dependencies: + '@types/node': 14.6.4 + + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@15.0.19': + dependencies: + '@types/yargs-parser': 21.0.3 + + '@types/yargs@17.0.33': + dependencies: + '@types/yargs-parser': 21.0.3 + + '@types/yauzl@2.10.3': + dependencies: + '@types/node': 14.6.4 + optional: true + + '@types/youtube@0.0.50': {} + + '@typescript-eslint/eslint-plugin@5.15.0(@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4))(eslint@8.11.0)(typescript@4.6.4)': + dependencies: + '@typescript-eslint/parser': 5.15.0(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/scope-manager': 5.15.0 + '@typescript-eslint/type-utils': 5.15.0(eslint@8.11.0)(typescript@4.6.4) + '@typescript-eslint/utils': 5.15.0(eslint@8.11.0)(typescript@4.6.4) + debug: 4.4.0 + eslint: 8.11.0 + functional-red-black-tree: 1.0.1 + ignore: 5.3.2 + regexpp: 3.2.0 + semver: 7.6.3 + tsutils: 3.21.0(typescript@4.6.4) + optionalDependencies: + typescript: 4.6.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@5.15.0(eslint@8.11.0)(typescript@4.6.4)': + dependencies: + '@typescript-eslint/scope-manager': 5.15.0 + '@typescript-eslint/types': 5.15.0 + '@typescript-eslint/typescript-estree': 5.15.0(typescript@4.6.4) + debug: 4.4.0 + eslint: 8.11.0 + optionalDependencies: + typescript: 4.6.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@5.15.0': + dependencies: + '@typescript-eslint/types': 5.15.0 + '@typescript-eslint/visitor-keys': 5.15.0 + + '@typescript-eslint/type-utils@5.15.0(eslint@8.11.0)(typescript@4.6.4)': + dependencies: + '@typescript-eslint/utils': 5.15.0(eslint@8.11.0)(typescript@4.6.4) + debug: 4.4.0 + eslint: 8.11.0 + tsutils: 3.21.0(typescript@4.6.4) + optionalDependencies: + typescript: 4.6.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@5.15.0': {} + + '@typescript-eslint/typescript-estree@5.15.0(typescript@4.6.4)': + dependencies: + '@typescript-eslint/types': 5.15.0 + '@typescript-eslint/visitor-keys': 5.15.0 + debug: 4.4.0 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.6.3 + tsutils: 3.21.0(typescript@4.6.4) + optionalDependencies: + typescript: 4.6.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@5.15.0(eslint@8.11.0)(typescript@4.6.4)': + dependencies: + '@types/json-schema': 7.0.15 + '@typescript-eslint/scope-manager': 5.15.0 + '@typescript-eslint/types': 5.15.0 + '@typescript-eslint/typescript-estree': 5.15.0(typescript@4.6.4) + eslint: 8.11.0 + eslint-scope: 5.1.1 + eslint-utils: 3.0.0(eslint@8.11.0) + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/visitor-keys@5.15.0': + dependencies: + '@typescript-eslint/types': 5.15.0 + eslint-visitor-keys: 3.4.3 + + '@vimeo/player@2.16.4': + dependencies: + native-promise-only: 0.8.1 + weakmap-polyfill: 2.0.4 + + '@vitest/pretty-format@2.1.8': + dependencies: + tinyrainbow: 1.2.0 + + '@vitest/snapshot@1.6.0': + dependencies: + magic-string: 0.30.17 + pathe: 1.1.2 + pretty-format: 29.7.0 + + '@vitest/snapshot@2.1.8': + dependencies: + '@vitest/pretty-format': 2.1.8 + magic-string: 0.30.17 + pathe: 1.1.2 + + '@wdio/cli@8.39.1(encoding@0.1.13)(typescript@4.6.4)': + dependencies: + '@types/node': 20.17.10 + '@vitest/snapshot': 1.6.0 + '@wdio/config': 8.39.0 + '@wdio/globals': 8.39.1(encoding@0.1.13)(typescript@4.6.4) + '@wdio/logger': 8.38.0 + '@wdio/protocols': 8.38.0 + '@wdio/types': 8.39.0 + '@wdio/utils': 8.39.0 + async-exit-hook: 2.0.1 + chalk: 5.4.1 + chokidar: 3.6.0 + cli-spinners: 2.9.2 + dotenv: 16.4.7 + ejs: 3.1.10 + execa: 8.0.1 + import-meta-resolve: 4.1.0 + inquirer: 9.2.12 + lodash.flattendeep: 4.4.0 + lodash.pickby: 4.6.0 + lodash.union: 4.6.0 + read-pkg-up: 10.0.0 + recursive-readdir: 2.2.3 + webdriverio: 8.39.1(encoding@0.1.13)(typescript@4.6.4) + yargs: 17.7.2 + transitivePeerDependencies: + - bufferutil + - devtools + - encoding + - supports-color + - typescript + - utf-8-validate + + '@wdio/config@8.39.0': + dependencies: + '@wdio/logger': 8.38.0 + '@wdio/types': 8.39.0 + '@wdio/utils': 8.39.0 + decamelize: 6.0.0 + deepmerge-ts: 5.1.0 + glob: 10.4.5 + import-meta-resolve: 4.1.0 + transitivePeerDependencies: + - supports-color + + '@wdio/globals@8.39.1(encoding@0.1.13)(typescript@4.6.4)': + optionalDependencies: + expect-webdriverio: 4.15.4(encoding@0.1.13)(typescript@4.6.4) + webdriverio: 8.39.1(encoding@0.1.13)(typescript@4.6.4) + transitivePeerDependencies: + - bufferutil + - devtools + - encoding + - supports-color + - typescript + - utf-8-validate + + '@wdio/jasmine-framework@8.39.1(encoding@0.1.13)(typescript@4.6.4)': + dependencies: + '@types/node': 20.17.10 + '@wdio/globals': 8.39.1(encoding@0.1.13)(typescript@4.6.4) + '@wdio/logger': 8.38.0 + '@wdio/types': 8.39.0 + '@wdio/utils': 8.39.0 + expect-webdriverio: 4.15.4(encoding@0.1.13)(typescript@4.6.4) + jasmine: 5.5.0 + transitivePeerDependencies: + - bufferutil + - devtools + - encoding + - supports-color + - typescript + - utf-8-validate + + '@wdio/local-runner@8.39.1(encoding@0.1.13)(typescript@4.6.4)': + dependencies: + '@types/node': 20.17.10 + '@wdio/logger': 8.38.0 + '@wdio/repl': 8.24.12 + '@wdio/runner': 8.39.1(encoding@0.1.13)(typescript@4.6.4) + '@wdio/types': 8.39.0 + async-exit-hook: 2.0.1 + split2: 4.2.0 + stream-buffers: 3.0.3 + transitivePeerDependencies: + - bufferutil + - devtools + - encoding + - supports-color + - typescript + - utf-8-validate + + '@wdio/logger@8.38.0': + dependencies: + chalk: 5.4.1 + loglevel: 1.9.2 + loglevel-plugin-prefix: 0.8.4 + strip-ansi: 7.1.0 + + '@wdio/logger@9.4.4': + dependencies: + chalk: 5.4.1 + loglevel: 1.9.2 + loglevel-plugin-prefix: 0.8.4 + strip-ansi: 7.1.0 + + '@wdio/protocols@8.38.0': {} + + '@wdio/repl@8.24.12': + dependencies: + '@types/node': 20.17.10 + + '@wdio/reporter@8.39.0': + dependencies: + '@types/node': 20.17.10 + '@wdio/logger': 8.38.0 + '@wdio/types': 8.39.0 + diff: 5.2.0 + object-inspect: 1.13.3 + + '@wdio/runner@8.39.1(encoding@0.1.13)(typescript@4.6.4)': + dependencies: + '@types/node': 20.17.10 + '@wdio/config': 8.39.0 + '@wdio/globals': 8.39.1(encoding@0.1.13)(typescript@4.6.4) + '@wdio/logger': 8.38.0 + '@wdio/types': 8.39.0 + '@wdio/utils': 8.39.0 + deepmerge-ts: 5.1.0 + expect-webdriverio: 4.15.4(encoding@0.1.13)(typescript@4.6.4) + gaze: 1.1.3 + webdriver: 8.39.0 + webdriverio: 8.39.1(encoding@0.1.13)(typescript@4.6.4) + transitivePeerDependencies: + - bufferutil + - devtools + - encoding + - supports-color + - typescript + - utf-8-validate + + '@wdio/sauce-service@8.39.1(encoding@0.1.13)(typescript@4.6.4)': + dependencies: + '@wdio/logger': 8.38.0 + '@wdio/types': 8.39.0 + '@wdio/utils': 8.39.0 + ip: 2.0.1 + saucelabs: 7.5.0 + webdriverio: 8.39.1(encoding@0.1.13)(typescript@4.6.4) + transitivePeerDependencies: + - bufferutil + - devtools + - encoding + - supports-color + - typescript + - utf-8-validate + + '@wdio/shared-store-service@8.39.1(encoding@0.1.13)(typescript@4.6.4)': + dependencies: + '@polka/parse': 1.0.0-next.0 + '@wdio/logger': 8.38.0 + '@wdio/types': 8.39.0 + got: 12.6.1 + polka: 0.5.2 + webdriverio: 8.39.1(encoding@0.1.13)(typescript@4.6.4) + transitivePeerDependencies: + - bufferutil + - devtools + - encoding + - supports-color + - typescript + - utf-8-validate + + '@wdio/spec-reporter@8.39.0': + dependencies: + '@wdio/reporter': 8.39.0 + '@wdio/types': 8.39.0 + chalk: 5.4.1 + easy-table: 1.2.0 + pretty-ms: 7.0.1 + + '@wdio/static-server-service@8.39.0': + dependencies: + '@wdio/logger': 8.38.0 + '@wdio/types': 8.39.0 + express: 4.21.2 + morgan: 1.10.0 + + '@wdio/types@8.39.0': + dependencies: + '@types/node': 20.17.10 + + '@wdio/utils@8.39.0': + dependencies: + '@puppeteer/browsers': 1.9.1 + '@wdio/logger': 8.38.0 + '@wdio/types': 8.39.0 + decamelize: 6.0.0 + deepmerge-ts: 5.1.0 + edgedriver: 5.6.1 + geckodriver: 4.5.1 + get-port: 7.1.0 + import-meta-resolve: 4.1.0 + locate-app: 2.5.0 + safaridriver: 0.1.2 + split2: 4.2.0 + wait-port: 1.1.0 + transitivePeerDependencies: + - supports-color + + '@wessberg/stringutil@1.0.19': {} + + '@zip.js/zip.js@2.7.54': {} + + abab@2.0.6: {} + + abbrev@1.1.1: {} + + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + + accepts@1.3.8: + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + + acorn-globals@6.0.0: + dependencies: + acorn: 7.4.1 + acorn-walk: 7.2.0 + + acorn-jsx@5.3.2(acorn@8.14.0): + dependencies: + acorn: 8.14.0 + + acorn-walk@7.2.0: {} + + acorn-walk@8.3.4: + dependencies: + acorn: 8.14.0 + + acorn@7.4.1: {} + + acorn@8.14.0: {} + + agent-base@6.0.2: + dependencies: + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + + agent-base@7.1.3: {} + + agentkeepalive@4.6.0: + dependencies: + humanize-ms: 1.2.1 + + aggregate-error@3.1.0: + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + + aggregate-error@4.0.1: + dependencies: + clean-stack: 4.2.0 + indent-string: 5.0.0 + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + anser@1.4.10: {} + + ansi-align@3.0.1: + dependencies: + string-width: 4.2.3 + + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + + ansi-fragments@0.2.1: + dependencies: + colorette: 1.4.0 + slice-ansi: 2.1.0 + strip-ansi: 5.2.0 + + ansi-regex@2.1.1: {} + + ansi-regex@4.1.1: {} + + ansi-regex@5.0.1: {} + + ansi-regex@6.1.0: {} + + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + ansi-styles@6.2.1: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + appdirsjs@1.2.7: {} + + aproba@1.2.0: {} + + archiver-utils@5.0.2: + dependencies: + glob: 10.4.5 + graceful-fs: 4.2.11 + is-stream: 2.0.1 + lazystream: 1.0.1 + lodash: 4.17.21 + normalize-path: 3.0.0 + readable-stream: 4.6.0 + + archiver@7.0.1: + dependencies: + archiver-utils: 5.0.2 + async: 3.2.6 + buffer-crc32: 1.0.0 + readable-stream: 4.6.0 + readdir-glob: 1.1.3 + tar-stream: 3.1.7 + zip-stream: 6.0.1 + + are-we-there-yet@1.1.7: + dependencies: + delegates: 1.0.0 + readable-stream: 2.3.8 + + arg@4.1.3: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + aria-query@5.1.3: + dependencies: + deep-equal: 2.2.3 + + aria-query@5.3.2: {} + + arkregex@0.0.5: + dependencies: + '@ark/util': 0.56.0 + + arktype@2.2.0: + dependencies: + '@ark/schema': 0.56.0 + '@ark/util': 0.56.0 + arkregex: 0.0.5 + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.3 + is-array-buffer: 3.0.5 + + array-find-index@1.0.2: {} + + array-flatten@1.1.1: {} + + array-union@2.1.0: {} + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.8 + es-errors: 1.3.0 + get-intrinsic: 1.2.6 + is-array-buffer: 3.0.5 + + arrgv@1.0.2: {} + + arrify@3.0.0: {} + + asap@2.0.6: {} + + asn1@0.2.6: + dependencies: + safer-buffer: 2.1.2 + + assert-plus@1.0.0: {} + + ast-types@0.13.4: + dependencies: + tslib: 2.8.1 + + ast-types@0.15.2: + dependencies: + tslib: 2.8.1 + + astral-regex@1.0.0: {} + + async-exit-hook@2.0.1: {} + + async-limiter@1.0.1: {} + + async@3.2.6: {} + + asynckit@0.4.0: {} + + ava@5.1.1: + dependencies: + acorn: 8.14.0 + acorn-walk: 8.3.4 + ansi-styles: 6.2.1 + arrgv: 1.0.2 + arrify: 3.0.0 + callsites: 4.2.0 + cbor: 8.1.0 + chalk: 5.4.1 + chokidar: 3.6.0 + chunkd: 2.0.1 + ci-info: 3.9.0 + ci-parallel-vars: 1.0.1 + clean-yaml-object: 0.1.0 + cli-truncate: 3.1.0 + code-excerpt: 4.0.0 + common-path-prefix: 3.0.0 + concordance: 5.0.4 + currently-unhandled: 0.4.1 + debug: 4.4.0 + del: 7.1.0 + emittery: 1.0.3 + figures: 5.0.0 + globby: 13.2.2 + ignore-by-default: 2.1.0 + indent-string: 5.0.0 + is-error: 2.2.2 + is-plain-object: 5.0.0 + is-promise: 4.0.0 + matcher: 5.0.0 + mem: 9.0.2 + ms: 2.1.3 + p-event: 5.0.1 + p-map: 5.5.0 + picomatch: 2.3.1 + pkg-conf: 4.0.0 + plur: 5.1.0 + pretty-ms: 8.0.0 + resolve-cwd: 3.0.0 + slash: 3.0.0 + stack-utils: 2.0.6 + strip-ansi: 7.1.0 + supertap: 3.0.1 + temp-dir: 3.0.0 + write-file-atomic: 5.0.1 + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.0.0 + + aws-sign2@0.7.0: {} + + aws4@1.13.2: {} + + axios@1.7.9: + dependencies: + follow-redirects: 1.15.9 + form-data: 4.0.1 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + b4a@1.6.7: {} + + babel-core@7.0.0-bridge.0(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + + babel-jest@28.1.3(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + '@jest/transform': 28.1.3 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 28.1.3(@babel/core@7.26.0) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + + babel-jest@28.1.3(@babel/core@7.29.7): + dependencies: + '@babel/core': 7.29.7 + '@jest/transform': 28.1.3 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 28.1.3(@babel/core@7.29.7) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + optional: true + + babel-plugin-istanbul@6.1.1: + dependencies: + '@babel/helper-plugin-utils': 7.25.9 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 5.2.1 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-jest-hoist@28.1.3: + dependencies: + '@babel/template': 7.25.9 + '@babel/types': 7.26.3 + '@types/babel__core': 7.20.5 + '@types/babel__traverse': 7.20.6 + + babel-plugin-polyfill-corejs2@0.4.12(@babel/core@7.26.0): + dependencies: + '@babel/compat-data': 7.26.3 + '@babel/core': 7.26.0 + '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.26.0) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-corejs2@0.4.12(@babel/core@7.29.7): + dependencies: + '@babel/compat-data': 7.26.3 + '@babel/core': 7.29.7 + '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.29.7) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + optional: true + + babel-plugin-polyfill-corejs2@0.4.17(@babel/core@7.29.7): + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/core': 7.29.7 + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-corejs3@0.10.6(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.26.0) + core-js-compat: 3.39.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-corejs3@0.10.6(@babel/core@7.29.7): + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.29.7) + core-js-compat: 3.39.0 + transitivePeerDependencies: + - supports-color + optional: true + + babel-plugin-polyfill-corejs3@0.14.2(@babel/core@7.29.7): + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7) + core-js-compat: 3.49.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-regenerator@0.6.3(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-regenerator@0.6.3(@babel/core@7.29.7): + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.29.7) + transitivePeerDependencies: + - supports-color + optional: true + + babel-plugin-polyfill-regenerator@0.6.8(@babel/core@7.29.7): + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7) + transitivePeerDependencies: + - supports-color + + babel-plugin-syntax-hermes-parser@0.34.0: + dependencies: + hermes-parser: 0.34.0 + + babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.26.0): + dependencies: + '@babel/plugin-syntax-flow': 7.26.0(@babel/core@7.26.0) + transitivePeerDependencies: + - '@babel/core' + + babel-preset-current-node-syntax@1.1.0(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.26.0) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.26.0) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.26.0) + '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.26.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.26.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.26.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.26.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.26.0) + + babel-preset-current-node-syntax@1.1.0(@babel/core@7.29.7): + dependencies: + '@babel/core': 7.29.7 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.7) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.7) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.7) + '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.29.7) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.7) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.7) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.7) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.7) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.7) + optional: true + + babel-preset-jest@28.1.3(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + babel-plugin-jest-hoist: 28.1.3 + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.0) + + babel-preset-jest@28.1.3(@babel/core@7.29.7): + dependencies: + '@babel/core': 7.29.7 + babel-plugin-jest-hoist: 28.1.3 + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.29.7) + optional: true + + balanced-match@1.0.2: {} + + balanced-match@4.0.4: {} + + bare-events@2.5.0: + optional: true + + bare-fs@2.3.5: + dependencies: + bare-events: 2.5.0 + bare-path: 2.1.3 + bare-stream: 2.6.1 + optional: true + + bare-os@2.4.4: + optional: true + + bare-path@2.1.3: + dependencies: + bare-os: 2.4.4 + optional: true + + bare-stream@2.6.1: + dependencies: + streamx: 2.21.1 + optional: true + + base64-js@1.5.1: {} + + baseline-browser-mapping@2.10.36: {} + + basic-auth@2.0.1: + dependencies: + safe-buffer: 5.1.2 + + basic-ftp@5.0.5: {} + + bcrypt-pbkdf@1.0.2: + dependencies: + tweetnacl: 0.14.5 + + binary-extensions@2.3.0: {} + + bl@1.2.3: + dependencies: + readable-stream: 2.3.8 + safe-buffer: 5.2.1 + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + blueimp-md5@2.19.0: {} + + body-parser@1.20.3: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.13.0 + raw-body: 2.5.2 + type-is: 1.6.18 + unpipe: 1.0.0 + + boxen@5.1.2: + dependencies: + ansi-align: 3.0.1 + camelcase: 6.3.0 + chalk: 4.1.2 + cli-boxes: 2.2.1 + string-width: 4.2.3 + type-fest: 0.20.2 + widest-line: 3.1.0 + wrap-ansi: 7.0.0 + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + brace-expansion@5.0.6: + dependencies: + balanced-match: 4.0.4 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + brotli-size@4.0.0: + dependencies: + duplexer: 0.1.1 + + browser-process-hrtime@1.0.0: {} + + browserslist-generator@1.0.66: + dependencies: + '@mdn/browser-compat-data': 4.2.1 + '@types/object-path': 0.11.4 + '@types/semver': 7.5.8 + '@types/ua-parser-js': 0.7.39 + browserslist: 4.20.2 + caniuse-lite: 1.0.30001690 + isbot: 3.4.5 + object-path: 0.11.8 + semver: 7.6.3 + ua-parser-js: 1.0.40 + + browserslist@4.20.2: + dependencies: + caniuse-lite: 1.0.30001690 + electron-to-chromium: 1.5.76 + escalade: 3.2.0 + node-releases: 2.0.19 + picocolors: 1.1.1 + + browserslist@4.24.3: + dependencies: + caniuse-lite: 1.0.30001690 + electron-to-chromium: 1.5.76 + node-releases: 2.0.19 + update-browserslist-db: 1.1.1(browserslist@4.24.3) + + browserslist@4.28.2: + dependencies: + baseline-browser-mapping: 2.10.36 + caniuse-lite: 1.0.30001799 + electron-to-chromium: 1.5.372 + node-releases: 2.0.47 + update-browserslist-db: 1.2.3(browserslist@4.28.2) + + bs-logger@0.2.6: + dependencies: + fast-json-stable-stringify: 2.1.0 + + bser@2.1.1: + dependencies: + node-int64: 0.4.0 + + buffer-alloc-unsafe@1.1.0: {} + + buffer-alloc@1.2.0: + dependencies: + buffer-alloc-unsafe: 1.1.0 + buffer-fill: 1.0.0 + + buffer-crc32@0.2.13: {} + + buffer-crc32@1.0.0: {} + + buffer-fill@1.0.0: {} + + buffer-from@1.1.2: {} + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + buildcheck@0.0.6: + optional: true + + builtin-modules@3.3.0: {} + + builtins@1.0.3: {} + + bytes@3.1.2: {} + + cacache@15.3.0: + dependencies: + '@npmcli/fs': 1.1.1 + '@npmcli/move-file': 1.1.2 + chownr: 2.0.0 + fs-minipass: 2.1.0 + glob: 7.2.3 + infer-owner: 1.0.4 + lru-cache: 6.0.0 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + mkdirp: 1.0.4 + p-map: 4.0.0 + promise-inflight: 1.0.1 + rimraf: 3.0.2 + ssri: 8.0.1 + tar: 6.2.1 + unique-filename: 1.1.1 + + cacheable-lookup@5.0.4: {} + + cacheable-lookup@7.0.0: {} + + cacheable-request@10.2.14: + dependencies: + '@types/http-cache-semantics': 4.0.4 + get-stream: 6.0.1 + http-cache-semantics: 4.1.1 + keyv: 4.5.4 + mimic-response: 4.0.0 + normalize-url: 8.0.1 + responselike: 3.0.0 + + cacheable-request@7.0.4: + dependencies: + clone-response: 1.0.3 + get-stream: 5.2.0 + http-cache-semantics: 4.1.1 + keyv: 4.5.4 + lowercase-keys: 2.0.0 + normalize-url: 6.1.0 + responselike: 2.0.1 + + call-bind-apply-helpers@1.0.1: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-define-property: 1.0.1 + get-intrinsic: 1.2.6 + set-function-length: 1.2.2 + + call-bound@1.0.3: + dependencies: + call-bind-apply-helpers: 1.0.1 + get-intrinsic: 1.2.6 + + caller-callsite@2.0.0: + dependencies: + callsites: 2.0.0 + + caller-path@2.0.0: + dependencies: + caller-callsite: 2.0.0 + + callsites@2.0.0: {} + + callsites@3.1.0: {} + + callsites@4.2.0: {} + + camel-case@4.1.2: + dependencies: + pascal-case: 3.1.2 + tslib: 2.8.1 + + camelcase@5.3.1: {} + + camelcase@6.3.0: {} + + caniuse-lite@1.0.30001690: {} + + caniuse-lite@1.0.30001799: {} + + capital-case@1.0.4: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + upper-case-first: 2.0.2 + + caseless@0.12.0: {} + + cbor@8.1.0: + dependencies: + nofilter: 3.1.0 + + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.4.1: {} + + change-case@4.1.2: + dependencies: + camel-case: 4.1.2 + capital-case: 1.0.4 + constant-case: 3.0.4 + dot-case: 3.0.4 + header-case: 2.0.4 + no-case: 3.0.4 + param-case: 3.0.4 + pascal-case: 3.1.2 + path-case: 3.0.4 + sentence-case: 3.0.4 + snake-case: 3.0.4 + tslib: 2.8.1 + + char-regex@1.0.2: {} + + chardet@0.7.0: {} + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + chownr@1.1.4: {} + + chownr@2.0.0: {} + + chrome-launcher@0.15.2: + dependencies: + '@types/node': 14.6.4 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 1.4.2 + + chromedriver@131.0.4: + dependencies: + '@testim/chrome-version': 1.1.4 + axios: 1.7.9 + compare-versions: 6.1.1 + extract-zip: 2.0.1 + proxy-agent: 6.5.0 + proxy-from-env: 1.1.0 + tcp-port-used: 1.0.2 + transitivePeerDependencies: + - debug + - supports-color + + chromium-bidi@0.4.16(devtools-protocol@0.0.1147663): + dependencies: + devtools-protocol: 0.0.1147663 + mitt: 3.0.0 + + chunkd@2.0.1: {} + + ci-info@2.0.0: {} + + ci-info@3.9.0: {} + + ci-parallel-vars@1.0.1: {} + + cjs-module-lexer@1.4.1: {} + + clean-stack@2.2.0: {} + + clean-stack@4.2.0: + dependencies: + escape-string-regexp: 5.0.0 + + clean-yaml-object@0.1.0: {} + + cli-boxes@2.2.1: {} + + cli-cursor@3.1.0: + dependencies: + restore-cursor: 3.1.0 + + cli-spinners@2.9.2: {} + + cli-truncate@3.1.0: + dependencies: + slice-ansi: 5.0.0 + string-width: 5.1.2 + + cli-width@4.1.0: {} + + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + cliui@9.0.1: + dependencies: + string-width: 7.2.0 + strip-ansi: 7.1.0 + wrap-ansi: 9.0.2 + + clone-deep@4.0.1: + dependencies: + is-plain-object: 2.0.4 + kind-of: 6.0.3 + shallow-clone: 3.0.1 + + clone-response@1.0.3: + dependencies: + mimic-response: 1.0.1 + + clone@1.0.4: {} + + co@4.6.0: {} + + code-excerpt@4.0.0: + dependencies: + convert-to-spaces: 2.0.1 + + code-point-at@1.1.0: {} + + collect-v8-coverage@1.0.2: {} + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.3: {} + + color-name@1.1.4: {} + + colorette@1.4.0: {} + + colors@1.4.0: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + command-exists@1.2.9: {} + + commander@2.20.3: {} + + commander@9.5.0: {} + + commenting@1.1.0: {} + + common-path-prefix@3.0.0: {} + + commondir@1.0.1: {} + + compare-versions@6.1.1: {} + + compatfactory@0.0.13(typescript@4.6.4): + dependencies: + helpertypes: 0.0.18 + typescript: 4.6.4 + + compress-commons@6.0.2: + dependencies: + crc-32: 1.2.2 + crc32-stream: 6.0.0 + is-stream: 2.0.1 + normalize-path: 3.0.0 + readable-stream: 4.6.0 + + compressible@2.0.18: + dependencies: + mime-db: 1.53.0 + + compressing@1.10.1: + dependencies: + '@eggjs/yauzl': 2.11.0 + flushwritable: 1.0.0 + get-ready: 1.0.0 + iconv-lite: 0.5.2 + mkdirp: 0.5.6 + pump: 3.0.2 + streamifier: 0.1.1 + tar-stream: 1.6.2 + yazl: 2.5.1 + + compression@1.7.5: + dependencies: + bytes: 3.1.2 + compressible: 2.0.18 + debug: 2.6.9 + negotiator: 0.6.4 + on-headers: 1.0.2 + safe-buffer: 5.2.1 + vary: 1.1.2 + + concat-map@0.0.1: {} + + concordance@5.0.4: + dependencies: + date-time: 3.1.0 + esutils: 2.0.3 + fast-diff: 1.3.0 + js-string-escape: 1.0.1 + lodash: 4.17.21 + md5-hex: 3.0.1 + semver: 7.6.3 + well-known-symbols: 2.0.0 + + connect@3.7.0: + dependencies: + debug: 2.6.9 + finalhandler: 1.1.2 + parseurl: 1.3.3 + utils-merge: 1.0.1 + + console-control-strings@1.1.0: {} + + constant-case@3.0.4: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + upper-case: 2.0.2 + + content-disposition@0.5.4: + dependencies: + safe-buffer: 5.2.1 + + content-type@1.0.5: {} + + convert-source-map@1.9.0: {} + + convert-source-map@2.0.0: {} + + convert-to-spaces@2.0.1: {} + + cookie-signature@1.0.6: {} + + cookie@0.7.1: {} + + core-js-compat@3.39.0: + dependencies: + browserslist: 4.24.3 + + core-js-compat@3.49.0: + dependencies: + browserslist: 4.28.2 + + core-util-is@1.0.2: {} + + core-util-is@1.0.3: {} + + cosmiconfig@5.2.1: + dependencies: + import-fresh: 2.0.0 + is-directory: 0.3.1 + js-yaml: 3.14.1 + parse-json: 4.0.0 + + cpu-features@0.0.10: + dependencies: + buildcheck: 0.0.6 + nan: 2.22.0 + optional: true + + crc-32@1.2.2: {} + + crc32-stream@6.0.0: + dependencies: + crc-32: 1.2.2 + readable-stream: 4.6.0 + + create-require@1.1.1: {} + + cross-fetch@4.0.0(encoding@0.1.13): + dependencies: + node-fetch: 2.7.0(encoding@0.1.13) + transitivePeerDependencies: + - encoding + + cross-spawn@6.0.6: + dependencies: + nice-try: 1.0.5 + path-key: 2.0.1 + semver: 5.7.2 + shebang-command: 1.2.0 + which: 1.3.1 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + crosspath@1.0.0: + dependencies: + '@types/node': 16.18.122 + + css-shorthand-properties@1.1.2: {} + + css-value@0.0.1: {} + + cssom@0.3.8: {} + + cssom@0.5.0: {} + + cssstyle@2.3.0: + dependencies: + cssom: 0.3.8 + + csstype@3.1.3: {} + + currently-unhandled@0.4.1: + dependencies: + array-find-index: 1.0.2 + + dashdash@1.14.1: + dependencies: + assert-plus: 1.0.0 + + data-uri-to-buffer@4.0.1: {} + + data-uri-to-buffer@6.0.2: {} + + data-urls@3.0.2: + dependencies: + abab: 2.0.6 + whatwg-mimetype: 3.0.0 + whatwg-url: 11.0.0 + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + date-time@3.1.0: + dependencies: + time-zone: 1.0.0 + + dayjs@1.11.13: {} + + debug@2.6.9: + dependencies: + ms: 2.0.0 + + debug@4.3.1: + dependencies: + ms: 2.1.2 + + debug@4.3.4: + dependencies: + ms: 2.1.2 + + debug@4.4.0: + dependencies: + ms: 2.1.3 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decamelize@1.2.0: {} + + decamelize@6.0.0: {} + + decimal.js@10.4.3: {} + + decode-uri-component@0.2.2: {} + + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + + dedent@0.7.0: {} + + dedent@1.7.2: {} + + deep-equal@2.2.3: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + es-get-iterator: 1.1.3 + get-intrinsic: 1.2.6 + is-arguments: 1.2.0 + is-array-buffer: 3.0.5 + is-date-object: 1.1.0 + is-regex: 1.2.1 + is-shared-array-buffer: 1.0.4 + isarray: 2.0.5 + object-is: 1.1.6 + object-keys: 1.1.1 + object.assign: 4.1.7 + regexp.prototype.flags: 1.5.3 + side-channel: 1.1.0 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.18 + + deep-is@0.1.4: {} + + deepmerge-ts@5.1.0: {} + + deepmerge@4.3.1: {} + + defaults@1.0.4: + dependencies: + clone: 1.0.4 + + defer-to-connect@2.0.1: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + degenerator@5.0.1: + dependencies: + ast-types: 0.13.4 + escodegen: 2.1.0 + esprima: 4.0.1 + + del@7.1.0: + dependencies: + globby: 13.2.2 + graceful-fs: 4.2.11 + is-glob: 4.0.3 + is-path-cwd: 3.0.0 + is-path-inside: 4.0.0 + p-map: 5.5.0 + rimraf: 3.0.2 + slash: 4.0.0 + + del@8.0.1: + dependencies: + globby: 14.1.0 + is-glob: 4.0.3 + is-path-cwd: 3.0.0 + is-path-inside: 4.0.0 + p-map: 7.0.4 + presentable-error: 0.0.1 + slash: 5.1.0 + + delayed-stream@1.0.0: {} + + delegates@1.0.0: {} + + denodeify@1.2.1: {} + + depd@2.0.0: {} + + destroy@1.2.0: {} + + detect-newline@3.1.0: {} + + devtools-protocol@0.0.1147663: {} + + devtools-protocol@0.0.1302984: {} + + diff-sequences@28.1.1: {} + + diff-sequences@29.6.3: {} + + diff@4.0.2: {} + + diff@5.2.0: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + docker-modem@3.0.8: + dependencies: + debug: 4.4.0 + readable-stream: 3.6.2 + split-ca: 1.0.1 + ssh2: 1.16.0 + transitivePeerDependencies: + - supports-color + + dockerode@3.3.5: + dependencies: + '@balena/dockerignore': 1.0.2 + docker-modem: 3.0.8 + tar-fs: 2.0.1 + transitivePeerDependencies: + - supports-color + + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + + dom-accessibility-api@0.5.16: {} + + domexception@4.0.0: + dependencies: + webidl-conversions: 7.0.0 + + dot-case@3.0.4: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + + dotenv@16.4.7: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + duplexer@0.1.1: {} + + duplexer@0.1.2: {} + + eastasianwidth@0.2.0: {} + + easy-table@1.2.0: + dependencies: + ansi-regex: 5.0.1 + optionalDependencies: + wcwidth: 1.0.1 + + ecc-jsbn@0.1.2: + dependencies: + jsbn: 0.1.1 + safer-buffer: 2.1.2 + + edge-paths@3.0.5: + dependencies: + '@types/which': 2.0.2 + which: 2.0.2 + + edgedriver@5.6.1: + dependencies: + '@wdio/logger': 8.38.0 + '@zip.js/zip.js': 2.7.54 + decamelize: 6.0.0 + edge-paths: 3.0.5 + fast-xml-parser: 4.5.1 + node-fetch: 3.3.2 + which: 4.0.0 + + ee-first@1.1.1: {} + + ejs@3.1.10: + dependencies: + jake: 10.9.2 + + electron-to-chromium@1.5.372: {} + + electron-to-chromium@1.5.76: {} + + emittery@0.10.2: {} + + emittery@1.0.3: {} + + emoji-regex@10.6.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + encodeurl@1.0.2: {} + + encodeurl@2.0.0: {} + + encoding@0.1.13: + dependencies: + iconv-lite: 0.6.3 + optional: true + + end-of-stream@1.4.4: + dependencies: + once: 1.4.0 + + enhance-visitors@1.0.0: + dependencies: + lodash: 4.17.21 + + env-paths@2.2.1: {} + + envinfo@7.14.0: {} + + err-code@2.0.3: {} + + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + + error-stack-parser@2.1.4: + dependencies: + stackframe: 1.3.4 + + errorhandler@1.5.1: + dependencies: + accepts: 1.3.8 + escape-html: 1.0.3 + + es-abstract@1.23.8: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.3 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-set-tostringtag: 2.0.3 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.2.6 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-regex: 1.2.1 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.0 + math-intrinsics: 1.1.0 + object-inspect: 1.13.3 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.3 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.18 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-get-iterator@1.1.3: + dependencies: + call-bind: 1.0.8 + get-intrinsic: 1.2.6 + has-symbols: 1.1.0 + is-arguments: 1.2.0 + is-map: 2.0.3 + is-set: 2.0.3 + is-string: 1.1.1 + isarray: 2.0.5 + stop-iteration-iterator: 1.1.0 + + es-object-atoms@1.0.0: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.0.3: + dependencies: + get-intrinsic: 1.2.6 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + escalade@3.2.0: {} + + escape-html@1.0.3: {} + + escape-string-regexp@1.0.5: {} + + escape-string-regexp@2.0.0: {} + + escape-string-regexp@4.0.0: {} + + escape-string-regexp@5.0.0: {} + + escodegen@2.1.0: + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + + eslint-plugin-ava@13.2.0(eslint@8.11.0): + dependencies: + enhance-visitors: 1.0.0 + eslint: 8.11.0 + eslint-utils: 3.0.0(eslint@8.11.0) + espree: 9.6.1 + espurify: 2.1.1 + import-modules: 2.1.0 + micro-spelling-correcter: 1.1.1 + pkg-dir: 5.0.0 + resolve-from: 5.0.0 + + eslint-scope@5.1.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + + eslint-scope@7.2.2: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-utils@3.0.0(eslint@8.11.0): + dependencies: + eslint: 8.11.0 + eslint-visitor-keys: 2.1.0 + + eslint-visitor-keys@2.1.0: {} + + eslint-visitor-keys@3.4.3: {} + + eslint@8.11.0: + dependencies: + '@eslint/eslintrc': 1.4.1 + '@humanwhocodes/config-array': 0.9.5 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.0 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-utils: 3.0.0(eslint@8.11.0) + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + functional-red-black-tree: 1.0.1 + glob-parent: 6.0.2 + globals: 13.24.0 + ignore: 5.3.2 + import-fresh: 3.3.0 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + regexpp: 3.2.0 + strip-ansi: 6.0.1 + strip-json-comments: 3.1.1 + text-table: 0.2.0 + v8-compile-cache: 2.4.0 + transitivePeerDependencies: + - supports-color + + espree@9.6.1: + dependencies: + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) + eslint-visitor-keys: 3.4.3 + + esprima@4.0.1: {} + + espurify@2.1.1: {} + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@4.3.0: {} + + estraverse@5.3.0: {} + + estree-walker@0.6.1: {} + + estree-walker@1.0.1: {} + + estree-walker@2.0.2: {} + + esutils@2.0.3: {} + + etag@1.8.1: {} + + event-target-shim@5.0.1: {} + + events@3.3.0: {} + + execa@5.1.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + execa@8.0.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + + exit@0.1.2: {} + + expect-webdriverio@4.15.4(encoding@0.1.13)(typescript@4.6.4): + dependencies: + '@vitest/snapshot': 2.1.8 + expect: 29.7.0 + jest-matcher-utils: 29.7.0 + lodash.isequal: 4.5.0 + optionalDependencies: + '@wdio/globals': 8.39.1(encoding@0.1.13)(typescript@4.6.4) + '@wdio/logger': 8.38.0 + webdriverio: 8.39.1(encoding@0.1.13)(typescript@4.6.4) + transitivePeerDependencies: + - bufferutil + - devtools + - encoding + - supports-color + - typescript + - utf-8-validate + + expect@28.1.3: + dependencies: + '@jest/expect-utils': 28.1.3 + jest-get-type: 28.0.2 + jest-matcher-utils: 28.1.3 + jest-message-util: 28.1.3 + jest-util: 28.1.3 + + expect@29.7.0: + dependencies: + '@jest/expect-utils': 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + + exponential-backoff@3.1.1: {} + + express@4.21.2: + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.3 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.7.1 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.3.1 + fresh: 0.5.2 + http-errors: 2.0.0 + merge-descriptors: 1.0.3 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.12 + proxy-addr: 2.0.7 + qs: 6.13.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.19.0 + serve-static: 1.16.2 + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + + extend@3.0.2: {} + + external-editor@3.1.0: + dependencies: + chardet: 0.7.0 + iconv-lite: 0.4.24 + tmp: 0.0.33 + + extract-zip@2.0.1: + dependencies: + debug: 4.4.0 + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.3 + transitivePeerDependencies: + - supports-color + + extsprintf@1.3.0: {} + + fast-base64-decode@1.0.0: {} + + fast-deep-equal@2.0.1: {} + + fast-deep-equal@3.1.3: {} + + fast-diff@1.3.0: {} + + fast-fifo@1.3.2: {} + + fast-glob@3.3.2: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-xml-parser@4.5.1: + dependencies: + strnum: 1.0.5 + + fastq@1.18.0: + dependencies: + reusify: 1.0.4 + + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + + fd-slicer2@1.2.0: + dependencies: + pend: 1.2.0 + + fd-slicer@1.1.0: + dependencies: + pend: 1.2.0 + + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + + figures@5.0.0: + dependencies: + escape-string-regexp: 5.0.0 + is-unicode-supported: 1.3.0 + + file-entry-cache@6.0.1: + dependencies: + flat-cache: 3.2.0 + + filelist@1.0.4: + dependencies: + minimatch: 5.1.6 + + filesize@6.4.0: {} + + filesize@9.0.11: {} + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + filter-obj@1.1.0: {} + + finalhandler@1.1.2: + dependencies: + debug: 2.6.9 + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.3.0 + parseurl: 1.3.3 + statuses: 1.5.0 + unpipe: 1.0.0 + + finalhandler@1.3.1: + dependencies: + debug: 2.6.9 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + unpipe: 1.0.0 + + find-cache-dir@2.1.0: + dependencies: + commondir: 1.0.1 + make-dir: 2.1.0 + pkg-dir: 3.0.0 + + find-up@3.0.0: + dependencies: + locate-path: 3.0.0 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + find-up@6.3.0: + dependencies: + locate-path: 7.2.0 + path-exists: 5.0.0 + + flat-cache@3.2.0: + dependencies: + flatted: 3.3.2 + keyv: 4.5.4 + rimraf: 3.0.2 + + flatted@3.3.2: {} + + flow-enums-runtime@0.0.6: {} + + flow-parser@0.257.1: {} + + flushwritable@1.0.0: {} + + follow-redirects@1.15.9: {} + + for-each@0.3.3: + dependencies: + is-callable: 1.2.7 + + foreground-child@3.3.0: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + forever-agent@0.6.1: {} + + form-data-encoder@2.1.4: {} + + form-data@2.3.3: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + form-data@4.0.1: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + + forwarded@0.2.0: {} + + fresh@0.5.2: {} + + fs-constants@1.0.0: {} + + fs-extra@11.2.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + fs-extra@11.3.5: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + fs-extra@8.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs-minipass@2.1.0: + dependencies: + minipass: 3.3.6 + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + + functional-red-black-tree@1.0.1: {} + + functions-have-names@1.2.3: {} + + gauge@2.7.4: + dependencies: + aproba: 1.2.0 + console-control-strings: 1.1.0 + has-unicode: 2.0.1 + object-assign: 4.1.1 + signal-exit: 3.0.7 + string-width: 1.0.2 + strip-ansi: 3.0.1 + wide-align: 1.1.5 + + gaze@1.1.3: + dependencies: + globule: 1.3.4 + + geckodriver@4.5.1: + dependencies: + '@wdio/logger': 9.4.4 + '@zip.js/zip.js': 2.7.54 + decamelize: 6.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + node-fetch: 3.3.2 + tar-fs: 3.0.6 + which: 4.0.0 + transitivePeerDependencies: + - supports-color + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-east-asian-width@1.6.0: {} + + get-intrinsic@1.2.6: + dependencies: + call-bind-apply-helpers: 1.0.1 + dunder-proto: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + function-bind: 1.1.2 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-package-type@0.1.0: {} + + get-port@7.1.0: {} + + get-ready@1.0.0: {} + + get-stream@5.2.0: + dependencies: + pump: 3.0.2 + + get-stream@6.0.1: {} + + get-stream@8.0.1: {} + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.6 + + get-uri@6.0.4: + dependencies: + basic-ftp: 5.0.5 + data-uri-to-buffer: 6.0.2 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + + getpass@0.1.7: + dependencies: + assert-plus: 1.0.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@10.4.5: + dependencies: + foreground-child: 3.3.0 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@13.0.6: + dependencies: + minimatch: 10.2.5 + minipass: 7.1.3 + path-scurry: 2.0.2 + + glob@7.1.7: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + glob@7.2.0: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + globals@11.12.0: {} + + globals@13.24.0: + dependencies: + type-fest: 0.20.2 + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + + globby@13.2.2: + dependencies: + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 4.0.0 + + globby@14.1.0: + dependencies: + '@sindresorhus/merge-streams': 2.3.0 + fast-glob: 3.3.3 + ignore: 7.0.5 + path-type: 6.0.0 + slash: 5.1.0 + unicorn-magic: 0.3.0 + + globule@1.3.4: + dependencies: + glob: 7.1.7 + lodash: 4.17.21 + minimatch: 3.0.8 + + gopd@1.2.0: {} + + got@11.8.6: + dependencies: + '@sindresorhus/is': 4.6.0 + '@szmarczak/http-timer': 4.0.6 + '@types/cacheable-request': 6.0.3 + '@types/responselike': 1.0.3 + cacheable-lookup: 5.0.4 + cacheable-request: 7.0.4 + decompress-response: 6.0.0 + http2-wrapper: 1.0.3 + lowercase-keys: 2.0.0 + p-cancelable: 2.1.1 + responselike: 2.0.1 + + got@12.6.1: + dependencies: + '@sindresorhus/is': 5.6.0 + '@szmarczak/http-timer': 5.0.1 + cacheable-lookup: 7.0.0 + cacheable-request: 10.2.14 + decompress-response: 6.0.0 + form-data-encoder: 2.1.4 + get-stream: 6.0.1 + http2-wrapper: 2.2.1 + lowercase-keys: 3.0.0 + p-cancelable: 3.0.0 + responselike: 3.0.0 + + graceful-fs@4.2.11: {} + + grapheme-splitter@1.0.4: {} + + gzip-size@6.0.0: + dependencies: + duplexer: 0.1.2 + + har-schema@2.0.0: {} + + har-validator@5.1.5: + dependencies: + ajv: 6.12.6 + har-schema: 2.0.0 + + has-bigints@1.1.0: {} + + has-flag@3.0.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + has-unicode@2.0.1: {} + + hash.js@1.1.7: + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + header-case@2.0.4: + dependencies: + capital-case: 1.0.4 + tslib: 2.8.1 + + helpertypes@0.0.18: {} + + hermes-estree@0.19.1: {} + + hermes-estree@0.23.1: {} + + hermes-estree@0.34.0: {} + + hermes-parser@0.19.1: + dependencies: + hermes-estree: 0.19.1 + + hermes-parser@0.23.1: + dependencies: + hermes-estree: 0.23.1 + + hermes-parser@0.34.0: + dependencies: + hermes-estree: 0.34.0 + + hermes-profile-transformer@0.0.6: + dependencies: + source-map: 0.7.4 + + hosted-git-info@2.8.9: {} + + hosted-git-info@4.1.0: + dependencies: + lru-cache: 6.0.0 + + hosted-git-info@7.0.2: + dependencies: + lru-cache: 10.4.3 + + html-encoding-sniffer@3.0.0: + dependencies: + whatwg-encoding: 2.0.0 + + html-escaper@2.0.2: {} + + http-cache-semantics@4.1.1: {} + + http-errors@2.0.0: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + + http-proxy-agent@4.0.1: + dependencies: + '@tootallnate/once': 1.1.2 + agent-base: 6.0.2 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + + http-proxy-agent@5.0.0: + dependencies: + '@tootallnate/once': 2.0.0 + agent-base: 6.0.2 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.3 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + + http-signature@1.2.0: + dependencies: + assert-plus: 1.0.0 + jsprim: 1.4.2 + sshpk: 1.18.0 + + http2-wrapper@1.0.3: + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + + http2-wrapper@2.2.1: + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.3 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + + human-signals@2.1.0: {} + + human-signals@5.0.0: {} + + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + + iconv-lite@0.5.2: + dependencies: + safer-buffer: 2.1.2 + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + ieee754@1.2.1: {} + + ignore-by-default@2.1.0: {} + + ignore-walk@3.0.4: + dependencies: + minimatch: 3.1.2 + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + image-size@1.2.0: + dependencies: + queue: 6.0.2 + + immediate@3.0.6: {} + + import-fresh@2.0.0: + dependencies: + caller-path: 2.0.0 + resolve-from: 3.0.0 + + import-fresh@3.3.0: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + import-local@3.2.0: + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + + import-meta-resolve@4.1.0: {} + + import-modules@2.1.0: {} + + imurmurhash@0.1.4: {} + + indent-string@4.0.0: {} + + indent-string@5.0.0: {} + + infer-owner@1.0.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.3: {} + + inherits@2.0.4: {} + + inquirer@9.2.12: + dependencies: + '@ljharb/through': 2.3.13 + ansi-escapes: 4.3.2 + chalk: 5.4.1 + cli-cursor: 3.1.0 + cli-width: 4.1.0 + external-editor: 3.1.0 + figures: 5.0.0 + lodash: 4.17.21 + mute-stream: 1.0.0 + ora: 5.4.1 + run-async: 3.0.0 + rxjs: 7.8.1 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + + invariant@2.2.4: + dependencies: + loose-envify: 1.4.0 + + ip-address@9.0.5: + dependencies: + jsbn: 1.1.0 + sprintf-js: 1.1.3 + + ip-regex@4.3.0: {} + + ip@2.0.1: {} + + ipaddr.js@1.9.1: {} + + irregular-plurals@3.5.0: {} + + is-arguments@1.2.0: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + get-intrinsic: 1.2.6 + + is-arrayish@0.2.1: {} + + is-async-function@2.0.0: + dependencies: + has-tostringtag: 1.0.2 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-boolean-object@1.2.1: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + + is-callable@1.2.7: {} + + is-ci@2.0.0: + dependencies: + ci-info: 2.0.0 + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.3 + get-intrinsic: 1.2.6 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + + is-directory@0.3.1: {} + + is-docker@2.2.1: {} + + is-error@2.2.2: {} + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.3 + + is-fullwidth-code-point@1.0.0: + dependencies: + number-is-nan: 1.0.1 + + is-fullwidth-code-point@2.0.0: {} + + is-fullwidth-code-point@3.0.0: {} + + is-fullwidth-code-point@4.0.0: {} + + is-generator-fn@2.1.0: {} + + is-generator-function@1.0.10: + dependencies: + has-tostringtag: 1.0.2 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-interactive@1.0.0: {} + + is-lambda@1.0.1: {} + + is-map@2.0.3: {} + + is-module@1.0.0: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-path-cwd@3.0.0: {} + + is-path-inside@4.0.0: {} + + is-plain-obj@2.1.0: {} + + is-plain-obj@4.1.0: {} + + is-plain-object@2.0.4: + dependencies: + isobject: 3.0.1 + + is-plain-object@5.0.0: {} + + is-potential-custom-element-name@1.0.1: {} + + is-promise@4.0.0: {} + + is-reference@1.2.1: + dependencies: + '@types/estree': 1.0.6 + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.3 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.3 + + is-stream@2.0.1: {} + + is-stream@3.0.0: {} + + is-string@1.1.1: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.3 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.18 + + is-typedarray@1.0.0: {} + + is-unicode-supported@0.1.0: {} + + is-unicode-supported@1.3.0: {} + + is-url@1.2.4: {} + + is-weakmap@2.0.2: {} + + is-weakref@1.1.0: + dependencies: + call-bound: 1.0.3 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.3 + get-intrinsic: 1.2.6 + + is-wsl@1.1.0: {} + + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + + is2@2.0.9: + dependencies: + deep-is: 0.1.4 + ip-regex: 4.3.0 + is-url: 1.2.4 + + isarray@1.0.0: {} + + isarray@2.0.5: {} + + isbot@3.4.5: {} + + isexe@2.0.0: {} + + isexe@3.1.1: {} + + isexe@4.0.0: {} + + isobject@3.0.1: {} + + isstream@0.1.2: {} + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-instrument@5.2.1: + dependencies: + '@babel/core': 7.26.0 + '@babel/parser': 7.26.3 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@4.0.1: + dependencies: + debug: 4.4.0 + istanbul-lib-coverage: 3.2.2 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.1.7: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jake@10.9.2: + dependencies: + async: 3.2.6 + chalk: 4.1.2 + filelist: 1.0.4 + minimatch: 3.1.2 + + jasmine-core@5.5.0: {} + + jasmine@5.5.0: + dependencies: + glob: 10.4.5 + jasmine-core: 5.5.0 + + jest-changed-files@28.1.3: + dependencies: + execa: 5.1.1 + p-limit: 3.1.0 + + jest-circus@28.1.3: + dependencies: + '@jest/environment': 28.1.3 + '@jest/expect': 28.1.3 + '@jest/test-result': 28.1.3 + '@jest/types': 28.1.3 + '@types/node': 14.6.4 + chalk: 4.1.2 + co: 4.6.0 + dedent: 0.7.0 + is-generator-fn: 2.1.0 + jest-each: 28.1.3 + jest-matcher-utils: 28.1.3 + jest-message-util: 28.1.3 + jest-runtime: 28.1.3 + jest-snapshot: 28.1.3 + jest-util: 28.1.3 + p-limit: 3.1.0 + pretty-format: 28.1.3 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - supports-color + + jest-cli@28.1.3(@types/node@14.6.4)(ts-node@10.9.2(@types/node@14.6.4)(typescript@4.6.4)): + dependencies: + '@jest/core': 28.1.3(ts-node@10.9.2(@types/node@14.6.4)(typescript@4.6.4)) + '@jest/test-result': 28.1.3 + '@jest/types': 28.1.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + import-local: 3.2.0 + jest-config: 28.1.3(@types/node@14.6.4)(ts-node@10.9.2(@types/node@14.6.4)(typescript@4.6.4)) + jest-util: 28.1.3 + jest-validate: 28.1.3 + prompts: 2.4.2 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - supports-color + - ts-node + + jest-cli@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)): + dependencies: + '@jest/core': 28.1.3(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + '@jest/test-result': 28.1.3 + '@jest/types': 28.1.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + import-local: 3.2.0 + jest-config: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-util: 28.1.3 + jest-validate: 28.1.3 + prompts: 2.4.2 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - supports-color + - ts-node + + jest-config@28.1.3(@types/node@14.6.4)(ts-node@10.9.2(@types/node@14.6.4)(typescript@4.6.4)): + dependencies: + '@babel/core': 7.26.0 + '@jest/test-sequencer': 28.1.3 + '@jest/types': 28.1.3 + babel-jest: 28.1.3(@babel/core@7.26.0) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 28.1.3 + jest-environment-node: 28.1.3 + jest-get-type: 28.0.2 + jest-regex-util: 28.0.2 + jest-resolve: 28.1.3 + jest-runner: 28.1.3 + jest-util: 28.1.3 + jest-validate: 28.1.3 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 28.1.3 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 14.6.4 + ts-node: 10.9.2(@types/node@14.6.4)(typescript@4.6.4) + transitivePeerDependencies: + - supports-color + + jest-config@28.1.3(@types/node@14.6.4)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)): + dependencies: + '@babel/core': 7.26.0 + '@jest/test-sequencer': 28.1.3 + '@jest/types': 28.1.3 + babel-jest: 28.1.3(@babel/core@7.26.0) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 28.1.3 + jest-environment-node: 28.1.3 + jest-get-type: 28.0.2 + jest-regex-util: 28.0.2 + jest-resolve: 28.1.3 + jest-runner: 28.1.3 + jest-util: 28.1.3 + jest-validate: 28.1.3 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 28.1.3 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 14.6.4 + ts-node: 10.9.2(@types/node@20.17.10)(typescript@4.6.4) + transitivePeerDependencies: + - supports-color + + jest-config@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)): + dependencies: + '@babel/core': 7.26.0 + '@jest/test-sequencer': 28.1.3 + '@jest/types': 28.1.3 + babel-jest: 28.1.3(@babel/core@7.26.0) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 28.1.3 + jest-environment-node: 28.1.3 + jest-get-type: 28.0.2 + jest-regex-util: 28.0.2 + jest-resolve: 28.1.3 + jest-runner: 28.1.3 + jest-util: 28.1.3 + jest-validate: 28.1.3 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 28.1.3 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 20.17.10 + ts-node: 10.9.2(@types/node@20.17.10)(typescript@4.6.4) + transitivePeerDependencies: + - supports-color + + jest-diff@28.1.3: + dependencies: + chalk: 4.1.2 + diff-sequences: 28.1.1 + jest-get-type: 28.0.2 + pretty-format: 28.1.3 + + jest-diff@29.7.0: + dependencies: + chalk: 4.1.2 + diff-sequences: 29.6.3 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-docblock@28.1.1: + dependencies: + detect-newline: 3.1.0 + + jest-each@28.1.3: + dependencies: + '@jest/types': 28.1.3 + chalk: 4.1.2 + jest-get-type: 28.0.2 + jest-util: 28.1.3 + pretty-format: 28.1.3 + + jest-environment-jsdom-global@4.0.0(jest-environment-jsdom@28.1.3): + dependencies: + jest-environment-jsdom: 28.1.3 + + jest-environment-jsdom@28.1.3: + dependencies: + '@jest/environment': 28.1.3 + '@jest/fake-timers': 28.1.3 + '@jest/types': 28.1.3 + '@types/jsdom': 16.2.15 + '@types/node': 14.6.4 + jest-mock: 28.1.3 + jest-util: 28.1.3 + jsdom: 19.0.0 + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - utf-8-validate + + jest-environment-node@28.1.3: + dependencies: + '@jest/environment': 28.1.3 + '@jest/fake-timers': 28.1.3 + '@jest/types': 28.1.3 + '@types/node': 14.6.4 + jest-mock: 28.1.3 + jest-util: 28.1.3 + + jest-environment-node@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 14.6.4 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + jest-get-type@28.0.2: {} + + jest-get-type@29.6.3: {} + + jest-haste-map@28.1.3: + dependencies: + '@jest/types': 28.1.3 + '@types/graceful-fs': 4.1.9 + '@types/node': 14.6.4 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 28.0.2 + jest-util: 28.1.3 + jest-worker: 28.1.3 + micromatch: 4.0.8 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + + jest-leak-detector@28.1.3: + dependencies: + jest-get-type: 28.0.2 + pretty-format: 28.1.3 + + jest-matcher-utils@28.1.3: + dependencies: + chalk: 4.1.2 + jest-diff: 28.1.3 + jest-get-type: 28.0.2 + pretty-format: 28.1.3 + + jest-matcher-utils@29.7.0: + dependencies: + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-message-util@26.6.2: + dependencies: + '@babel/code-frame': 7.26.2 + '@jest/types': 26.6.2 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + pretty-format: 26.6.2 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-message-util@28.1.3: + dependencies: + '@babel/code-frame': 7.26.2 + '@jest/types': 28.1.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + pretty-format: 28.1.3 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-message-util@29.7.0: + dependencies: + '@babel/code-frame': 7.26.2 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-mock@28.1.3: + dependencies: + '@jest/types': 28.1.3 + '@types/node': 14.6.4 + + jest-mock@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 14.6.4 + jest-util: 29.7.0 + + jest-pnp-resolver@1.2.3(jest-resolve@28.1.3): + optionalDependencies: + jest-resolve: 28.1.3 + + jest-regex-util@28.0.2: {} + + jest-resolve-dependencies@28.1.3: + dependencies: + jest-regex-util: 28.0.2 + jest-snapshot: 28.1.3 + transitivePeerDependencies: + - supports-color + + jest-resolve@28.1.3: + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 28.1.3 + jest-pnp-resolver: 1.2.3(jest-resolve@28.1.3) + jest-util: 28.1.3 + jest-validate: 28.1.3 + resolve: 1.22.10 + resolve.exports: 1.1.1 + slash: 3.0.0 + + jest-runner@28.1.3: + dependencies: + '@jest/console': 28.1.3 + '@jest/environment': 28.1.3 + '@jest/test-result': 28.1.3 + '@jest/transform': 28.1.3 + '@jest/types': 28.1.3 + '@types/node': 14.6.4 + chalk: 4.1.2 + emittery: 0.10.2 + graceful-fs: 4.2.11 + jest-docblock: 28.1.1 + jest-environment-node: 28.1.3 + jest-haste-map: 28.1.3 + jest-leak-detector: 28.1.3 + jest-message-util: 28.1.3 + jest-resolve: 28.1.3 + jest-runtime: 28.1.3 + jest-util: 28.1.3 + jest-watcher: 28.1.3 + jest-worker: 28.1.3 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + + jest-runtime@28.1.3: + dependencies: + '@jest/environment': 28.1.3 + '@jest/fake-timers': 28.1.3 + '@jest/globals': 28.1.3 + '@jest/source-map': 28.1.2 + '@jest/test-result': 28.1.3 + '@jest/transform': 28.1.3 + '@jest/types': 28.1.3 + chalk: 4.1.2 + cjs-module-lexer: 1.4.1 + collect-v8-coverage: 1.0.2 + execa: 5.1.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-haste-map: 28.1.3 + jest-message-util: 28.1.3 + jest-mock: 28.1.3 + jest-regex-util: 28.0.2 + jest-resolve: 28.1.3 + jest-snapshot: 28.1.3 + jest-util: 28.1.3 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + + jest-snapshot@28.1.3: + dependencies: + '@babel/core': 7.26.0 + '@babel/generator': 7.26.3 + '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0) + '@babel/traverse': 7.26.4 + '@babel/types': 7.26.3 + '@jest/expect-utils': 28.1.3 + '@jest/transform': 28.1.3 + '@jest/types': 28.1.3 + '@types/babel__traverse': 7.20.6 + '@types/prettier': 2.7.3 + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.0) + chalk: 4.1.2 + expect: 28.1.3 + graceful-fs: 4.2.11 + jest-diff: 28.1.3 + jest-get-type: 28.0.2 + jest-haste-map: 28.1.3 + jest-matcher-utils: 28.1.3 + jest-message-util: 28.1.3 + jest-util: 28.1.3 + natural-compare: 1.4.0 + pretty-format: 28.1.3 + semver: 7.6.3 + transitivePeerDependencies: + - supports-color + + jest-standard-reporter@2.0.0: + dependencies: + '@jest/console': 26.6.2 + chalk: 4.1.2 + jest-util: 26.6.2 + path: 0.12.7 + slash: 3.0.0 + string-length: 4.0.2 + + jest-util@26.6.2: + dependencies: + '@jest/types': 26.6.2 + '@types/node': 14.6.4 + chalk: 4.1.2 + graceful-fs: 4.2.11 + is-ci: 2.0.0 + micromatch: 4.0.8 + + jest-util@28.1.3: + dependencies: + '@jest/types': 28.1.3 + '@types/node': 14.6.4 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + + jest-util@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 14.6.4 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + + jest-validate@28.1.3: + dependencies: + '@jest/types': 28.1.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 28.0.2 + leven: 3.1.0 + pretty-format: 28.1.3 + + jest-validate@29.7.0: + dependencies: + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + + jest-watcher@28.1.3: + dependencies: + '@jest/test-result': 28.1.3 + '@jest/types': 28.1.3 + '@types/node': 14.6.4 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.10.2 + jest-util: 28.1.3 + string-length: 4.0.2 + + jest-worker@26.6.2: + dependencies: + '@types/node': 14.6.4 + merge-stream: 2.0.0 + supports-color: 7.2.0 + + jest-worker@28.1.3: + dependencies: + '@types/node': 14.6.4 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + jest-worker@29.7.0: + dependencies: + '@types/node': 14.6.4 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + jest@28.1.3(@types/node@14.6.4)(ts-node@10.9.2(@types/node@14.6.4)(typescript@4.6.4)): + dependencies: + '@jest/core': 28.1.3(ts-node@10.9.2(@types/node@14.6.4)(typescript@4.6.4)) + '@jest/types': 28.1.3 + import-local: 3.2.0 + jest-cli: 28.1.3(@types/node@14.6.4)(ts-node@10.9.2(@types/node@14.6.4)(typescript@4.6.4)) + transitivePeerDependencies: + - '@types/node' + - supports-color + - ts-node + + jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)): + dependencies: + '@jest/core': 28.1.3(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + '@jest/types': 28.1.3 + import-local: 3.2.0 + jest-cli: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + transitivePeerDependencies: + - '@types/node' + - supports-color + - ts-node + + joi@17.13.3: + dependencies: + '@hapi/hoek': 9.3.0 + '@hapi/topo': 5.1.0 + '@sideway/address': 4.1.5 + '@sideway/formula': 3.0.1 + '@sideway/pinpoint': 2.0.0 + + js-cleanup@1.2.0: + dependencies: + magic-string: 0.25.9 + perf-regexes: 1.0.1 + skip-regex: 1.0.2 + + js-string-escape@1.0.1: {} + + js-tokens@4.0.0: {} + + js-yaml@3.14.1: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + jsbn@0.1.1: {} + + jsbn@1.1.0: {} + + jsc-android@250231.0.0: {} + + jsc-safe-url@0.2.4: {} + + jscodeshift@0.14.0(@babel/preset-env@7.29.7(@babel/core@7.29.7)): + dependencies: + '@babel/core': 7.26.0 + '@babel/parser': 7.26.3 + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.26.0) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.26.0) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.26.0) + '@babel/plugin-transform-modules-commonjs': 7.26.3(@babel/core@7.26.0) + '@babel/preset-env': 7.29.7(@babel/core@7.29.7) + '@babel/preset-flow': 7.25.9(@babel/core@7.26.0) + '@babel/preset-typescript': 7.26.0(@babel/core@7.26.0) + '@babel/register': 7.25.9(@babel/core@7.26.0) + babel-core: 7.0.0-bridge.0(@babel/core@7.26.0) + chalk: 4.1.2 + flow-parser: 0.257.1 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + neo-async: 2.6.2 + node-dir: 0.1.17 + recast: 0.21.5 + temp: 0.8.4 + write-file-atomic: 2.4.3 + transitivePeerDependencies: + - supports-color + + jsdom@19.0.0: + dependencies: + abab: 2.0.6 + acorn: 8.14.0 + acorn-globals: 6.0.0 + cssom: 0.5.0 + cssstyle: 2.3.0 + data-urls: 3.0.2 + decimal.js: 10.4.3 + domexception: 4.0.0 + escodegen: 2.1.0 + form-data: 4.0.1 + html-encoding-sniffer: 3.0.0 + http-proxy-agent: 5.0.0 + https-proxy-agent: 5.0.1 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.16 + parse5: 6.0.1 + saxes: 5.0.1 + symbol-tree: 3.2.4 + tough-cookie: 4.1.4 + w3c-hr-time: 1.0.2 + w3c-xmlserializer: 3.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 2.0.0 + whatwg-mimetype: 3.0.0 + whatwg-url: 10.0.0 + ws: 8.18.0 + xml-name-validator: 4.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + jsesc@3.0.2: {} + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-parse-better-errors@1.0.2: {} + + json-parse-even-better-errors@2.3.1: {} + + json-parse-even-better-errors@3.0.2: {} + + json-schema-traverse@0.4.1: {} + + json-schema@0.4.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json-stringify-safe@5.0.1: {} + + json5@2.2.3: {} + + jsonfile@4.0.0: + optionalDependencies: + graceful-fs: 4.2.11 + + jsonfile@6.1.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + jsonparse@1.3.1: {} + + jsprim@1.4.2: + dependencies: + assert-plus: 1.0.0 + extsprintf: 1.3.0 + json-schema: 0.4.0 + verror: 1.10.0 + + jstimezonedetect@1.0.7: {} + + jszip@3.10.1: + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + kind-of@6.0.3: {} + + kleur@3.0.3: {} + + kleur@4.1.5: {} + + ky@0.33.3: {} + + lazystream@1.0.1: + dependencies: + readable-stream: 2.3.8 + + leven@3.1.0: {} + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lie@3.3.0: + dependencies: + immediate: 3.0.6 + + lighthouse-logger@1.4.2: + dependencies: + debug: 2.6.9 + marky: 1.2.5 + + lines-and-columns@1.2.4: {} + + lines-and-columns@2.0.4: {} + + load-json-file@4.0.0: + dependencies: + graceful-fs: 4.2.11 + parse-json: 4.0.0 + pify: 3.0.0 + strip-bom: 3.0.0 + + load-json-file@7.0.1: {} + + locate-app@2.5.0: + dependencies: + '@promptbook/utils': 0.69.5 + type-fest: 4.26.0 + userhome: 1.0.1 + + locate-path@3.0.0: + dependencies: + p-locate: 3.0.0 + path-exists: 3.0.0 + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + locate-path@7.2.0: + dependencies: + p-locate: 6.0.0 + + lodash.clonedeep@4.5.0: {} + + lodash.debounce@4.0.8: {} + + lodash.flattendeep@4.4.0: {} + + lodash.isequal@4.5.0: {} + + lodash.memoize@4.1.2: {} + + lodash.merge@4.6.2: {} + + lodash.pickby@4.6.0: {} + + lodash.throttle@4.1.1: {} + + lodash.union@4.6.0: {} + + lodash.zip@4.2.0: {} + + lodash@4.17.21: {} + + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + + logkitty@0.7.1: + dependencies: + ansi-fragments: 0.2.1 + dayjs: 1.11.13 + yargs: 15.4.1 + + loglevel-plugin-prefix@0.8.4: {} + + loglevel@1.9.2: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lower-case@2.0.2: + dependencies: + tslib: 2.8.1 + + lowercase-keys@2.0.0: {} + + lowercase-keys@3.0.0: {} + + lru-cache@10.4.3: {} + + lru-cache@11.5.1: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + + lru-cache@7.18.3: {} + + lz-string@1.5.0: {} + + magic-string@0.25.7: + dependencies: + sourcemap-codec: 1.4.8 + + magic-string@0.25.9: + dependencies: + sourcemap-codec: 1.4.8 + + magic-string@0.26.7: + dependencies: + sourcemap-codec: 1.4.8 + + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + make-dir@2.1.0: + dependencies: + pify: 4.0.1 + semver: 5.7.2 + + make-dir@4.0.0: + dependencies: + semver: 7.6.3 + + make-error@1.3.6: {} + + make-fetch-happen@9.1.0: + dependencies: + agentkeepalive: 4.6.0 + cacache: 15.3.0 + http-cache-semantics: 4.1.1 + http-proxy-agent: 4.0.1 + https-proxy-agent: 5.0.1 + is-lambda: 1.0.1 + lru-cache: 6.0.0 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-fetch: 1.4.1 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + negotiator: 0.6.4 + promise-retry: 2.0.1 + socks-proxy-agent: 6.2.1 + ssri: 8.0.1 + transitivePeerDependencies: + - supports-color + + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + + map-age-cleaner@0.1.3: + dependencies: + p-defer: 1.0.0 + + marky@1.2.5: {} + + matcher@5.0.0: + dependencies: + escape-string-regexp: 5.0.0 + + matchit@1.1.0: + dependencies: + '@arr/every': 1.0.1 + + math-intrinsics@1.1.0: {} + + md5-hex@3.0.1: + dependencies: + blueimp-md5: 2.19.0 + + media-typer@0.3.0: {} + + mem@9.0.2: + dependencies: + map-age-cleaner: 0.1.3 + mimic-fn: 4.0.0 + + memoize-one@5.2.1: {} + + memorystream@0.3.1: {} + + merge-descriptors@1.0.3: {} + + merge-options@3.0.4: + dependencies: + is-plain-obj: 2.1.0 + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + methods@1.1.2: {} + + metro-babel-transformer@0.80.12: + dependencies: + '@babel/core': 7.26.0 + flow-enums-runtime: 0.0.6 + hermes-parser: 0.23.1 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + + metro-cache-key@0.80.12: + dependencies: + flow-enums-runtime: 0.0.6 + + metro-cache@0.80.12: + dependencies: + exponential-backoff: 3.1.1 + flow-enums-runtime: 0.0.6 + metro-core: 0.80.12 + + metro-config@0.80.12: + dependencies: + connect: 3.7.0 + cosmiconfig: 5.2.1 + flow-enums-runtime: 0.0.6 + jest-validate: 29.7.0 + metro: 0.80.12 + metro-cache: 0.80.12 + metro-core: 0.80.12 + metro-runtime: 0.80.12 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + metro-core@0.80.12: + dependencies: + flow-enums-runtime: 0.0.6 + lodash.throttle: 4.1.1 + metro-resolver: 0.80.12 + + metro-file-map@0.80.12: + dependencies: + anymatch: 3.1.3 + debug: 2.6.9 + fb-watchman: 2.0.2 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + invariant: 2.2.4 + jest-worker: 29.7.0 + micromatch: 4.0.8 + node-abort-controller: 3.1.1 + nullthrows: 1.1.1 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + + metro-minify-terser@0.80.12: + dependencies: + flow-enums-runtime: 0.0.6 + terser: 5.37.0 + + metro-resolver@0.80.12: + dependencies: + flow-enums-runtime: 0.0.6 + + metro-runtime@0.80.12: + dependencies: + '@babel/runtime': 7.26.0 + flow-enums-runtime: 0.0.6 + + metro-source-map@0.80.12: + dependencies: + '@babel/traverse': 7.26.4 + '@babel/types': 7.26.3 + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-symbolicate: 0.80.12 + nullthrows: 1.1.1 + ob1: 0.80.12 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + + metro-symbolicate@0.80.12: + dependencies: + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-source-map: 0.80.12 + nullthrows: 1.1.1 + source-map: 0.5.7 + through2: 2.0.5 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + + metro-transform-plugins@0.80.12: + dependencies: + '@babel/core': 7.26.0 + '@babel/generator': 7.26.3 + '@babel/template': 7.25.9 + '@babel/traverse': 7.26.4 + flow-enums-runtime: 0.0.6 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + + metro-transform-worker@0.80.12: + dependencies: + '@babel/core': 7.26.0 + '@babel/generator': 7.26.3 + '@babel/parser': 7.26.3 + '@babel/types': 7.26.3 + flow-enums-runtime: 0.0.6 + metro: 0.80.12 + metro-babel-transformer: 0.80.12 + metro-cache: 0.80.12 + metro-cache-key: 0.80.12 + metro-minify-terser: 0.80.12 + metro-source-map: 0.80.12 + metro-transform-plugins: 0.80.12 + nullthrows: 1.1.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + metro@0.80.12: + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/core': 7.26.0 + '@babel/generator': 7.26.3 + '@babel/parser': 7.26.3 + '@babel/template': 7.25.9 + '@babel/traverse': 7.26.4 + '@babel/types': 7.26.3 + accepts: 1.3.8 + chalk: 4.1.2 + ci-info: 2.0.0 + connect: 3.7.0 + debug: 2.6.9 + denodeify: 1.2.1 + error-stack-parser: 2.1.4 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + hermes-parser: 0.23.1 + image-size: 1.2.0 + invariant: 2.2.4 + jest-worker: 29.7.0 + jsc-safe-url: 0.2.4 + lodash.throttle: 4.1.1 + metro-babel-transformer: 0.80.12 + metro-cache: 0.80.12 + metro-cache-key: 0.80.12 + metro-config: 0.80.12 + metro-core: 0.80.12 + metro-file-map: 0.80.12 + metro-resolver: 0.80.12 + metro-runtime: 0.80.12 + metro-source-map: 0.80.12 + metro-symbolicate: 0.80.12 + metro-transform-plugins: 0.80.12 + metro-transform-worker: 0.80.12 + mime-types: 2.1.35 + nullthrows: 1.1.1 + serialize-error: 2.1.0 + source-map: 0.5.7 + strip-ansi: 6.0.1 + throat: 5.0.0 + ws: 7.5.10 + yargs: 17.7.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + micro-spelling-correcter@1.1.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-db@1.53.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime@1.6.0: {} + + mime@2.6.0: {} + + mimic-fn@2.1.0: {} + + mimic-fn@4.0.0: {} + + mimic-response@1.0.1: {} + + mimic-response@3.1.0: {} + + mimic-response@4.0.0: {} + + minimalistic-assert@1.0.1: {} + + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.6 + + minimatch@3.0.8: + dependencies: + brace-expansion: 1.1.11 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.1 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + minimist@1.2.8: {} + + minipass-collect@1.0.2: + dependencies: + minipass: 3.3.6 + + minipass-fetch@1.4.1: + dependencies: + minipass: 3.3.6 + minipass-sized: 1.0.3 + minizlib: 2.1.2 + optionalDependencies: + encoding: 0.1.13 + + minipass-flush@1.0.5: + dependencies: + minipass: 3.3.6 + + minipass-json-stream@1.0.2: + dependencies: + jsonparse: 1.3.1 + minipass: 3.3.6 + + minipass-pipeline@1.2.4: + dependencies: + minipass: 3.3.6 + + minipass-sized@1.0.3: + dependencies: + minipass: 3.3.6 + + minipass@3.3.6: + dependencies: + yallist: 4.0.0 + + minipass@5.0.0: {} + + minipass@7.1.2: {} + + minipass@7.1.3: {} + + minizlib@2.1.2: + dependencies: + minipass: 3.3.6 + yallist: 4.0.0 + + mitt@3.0.0: {} + + mkdirp-classic@0.5.3: {} + + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + + mkdirp@1.0.4: {} + + module-details-from-path@1.0.3: {} + + moment-timezone@0.5.46: + dependencies: + moment: 2.30.1 + + moment@2.29.1: {} + + moment@2.30.1: {} + + morgan@1.10.0: + dependencies: + basic-auth: 2.0.1 + debug: 2.6.9 + depd: 2.0.0 + on-finished: 2.3.0 + on-headers: 1.0.2 + + ms@2.0.0: {} + + ms@2.1.2: {} + + ms@2.1.3: {} + + mute-stream@1.0.0: {} + + nan@2.22.0: + optional: true + + native-promise-only@0.8.1: {} + + natural-compare@1.4.0: {} + + negotiator@0.6.3: {} + + negotiator@0.6.4: {} + + neo-async@2.6.2: {} + + netmask@2.0.2: {} + + nice-try@1.0.5: {} + + no-case@3.0.4: + dependencies: + lower-case: 2.0.2 + tslib: 2.8.1 + + nocache@3.0.4: {} + + node-abort-controller@3.1.1: {} + + node-dir@0.1.17: + dependencies: + minimatch: 3.1.2 + + node-domexception@1.0.0: {} + + node-fetch@2.7.0(encoding@0.1.13): + dependencies: + whatwg-url: 5.0.0 + optionalDependencies: + encoding: 0.1.13 + + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + + node-forge@1.3.1: {} + + node-gyp@7.1.2: + dependencies: + env-paths: 2.2.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + nopt: 5.0.0 + npmlog: 4.1.2 + request: 2.88.2 + rimraf: 3.0.2 + semver: 7.6.3 + tar: 6.2.1 + which: 2.0.2 + + node-int64@0.4.0: {} + + node-releases@2.0.19: {} + + node-releases@2.0.47: {} + + node-stream-zip@1.15.0: {} + + nofilter@3.1.0: {} + + nopt@5.0.0: + dependencies: + abbrev: 1.1.1 + + normalize-package-data@2.5.0: + dependencies: + hosted-git-info: 2.8.9 + resolve: 1.22.10 + semver: 5.7.2 + validate-npm-package-license: 3.0.4 + + normalize-package-data@6.0.2: + dependencies: + hosted-git-info: 7.0.2 + semver: 7.6.3 + validate-npm-package-license: 3.0.4 + + normalize-path@3.0.0: {} + + normalize-url@6.1.0: {} + + normalize-url@8.0.1: {} + + npm-bundled@1.1.2: + dependencies: + npm-normalize-package-bin: 1.0.1 + + npm-install-checks@4.0.0: + dependencies: + semver: 7.6.3 + + npm-normalize-package-bin@1.0.1: {} + + npm-package-arg@8.1.5: + dependencies: + hosted-git-info: 4.1.0 + semver: 7.6.3 + validate-npm-package-name: 3.0.0 + + npm-packlist@2.2.2: + dependencies: + glob: 7.2.3 + ignore-walk: 3.0.4 + npm-bundled: 1.1.2 + npm-normalize-package-bin: 1.0.1 + + npm-pick-manifest@6.1.1: + dependencies: + npm-install-checks: 4.0.0 + npm-normalize-package-bin: 1.0.1 + npm-package-arg: 8.1.5 + semver: 7.6.3 + + npm-registry-fetch@11.0.0: + dependencies: + make-fetch-happen: 9.1.0 + minipass: 3.3.6 + minipass-fetch: 1.4.1 + minipass-json-stream: 1.0.2 + minizlib: 2.1.2 + npm-package-arg: 8.1.5 + transitivePeerDependencies: + - supports-color + + npm-run-all@4.1.5: + dependencies: + ansi-styles: 3.2.1 + chalk: 2.4.2 + cross-spawn: 6.0.6 + memorystream: 0.3.1 + minimatch: 3.1.2 + pidtree: 0.3.1 + read-pkg: 3.0.0 + shell-quote: 1.8.2 + string.prototype.padend: 3.1.6 + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + + npmlog@4.1.2: + dependencies: + are-we-there-yet: 1.1.7 + console-control-strings: 1.1.0 + gauge: 2.7.4 + set-blocking: 2.0.0 + + nullthrows@1.1.1: {} + + number-is-nan@1.0.1: {} + + nwsapi@2.2.16: {} + + oauth-sign@0.9.0: {} + + ob1@0.80.12: + dependencies: + flow-enums-runtime: 0.0.6 + + object-assign@4.1.1: {} + + object-inspect@1.13.3: {} + + object-is@1.1.6: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + + object-keys@1.1.1: {} + + object-path@0.11.8: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + on-finished@2.3.0: + dependencies: + ee-first: 1.1.1 + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + on-headers@1.0.2: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + + open@6.4.0: + dependencies: + is-wsl: 1.1.0 + + open@7.4.2: + dependencies: + is-docker: 2.2.1 + is-wsl: 2.2.0 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + ora@5.4.1: + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.9.2 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + + os-tmpdir@1.0.2: {} + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.2.6 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-cancelable@2.1.1: {} + + p-cancelable@3.0.0: {} + + p-defer@1.0.0: {} + + p-event@5.0.1: + dependencies: + p-timeout: 5.1.0 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-limit@4.0.0: + dependencies: + yocto-queue: 1.1.1 + + p-locate@3.0.0: + dependencies: + p-limit: 2.3.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-locate@6.0.0: + dependencies: + p-limit: 4.0.0 + + p-map@4.0.0: + dependencies: + aggregate-error: 3.1.0 + + p-map@5.5.0: + dependencies: + aggregate-error: 4.0.1 + + p-map@7.0.4: {} + + p-timeout@5.1.0: {} + + p-try@2.2.0: {} + + pac-proxy-agent@7.1.0: + dependencies: + '@tootallnate/quickjs-emscripten': 0.23.0 + agent-base: 7.1.3 + debug: 4.4.0 + get-uri: 6.0.4 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + pac-resolver: 7.0.1 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color + + pac-resolver@7.0.1: + dependencies: + degenerator: 5.0.1 + netmask: 2.0.2 + + package-json-from-dist@1.0.1: {} + + package-name-regex@2.0.5: {} + + pacote@11.3.5: + dependencies: + '@npmcli/git': 2.1.0 + '@npmcli/installed-package-contents': 1.0.7 + '@npmcli/promise-spawn': 1.3.2 + '@npmcli/run-script': 1.8.6 + cacache: 15.3.0 + chownr: 2.0.0 + fs-minipass: 2.1.0 + infer-owner: 1.0.4 + minipass: 3.3.6 + mkdirp: 1.0.4 + npm-package-arg: 8.1.5 + npm-packlist: 2.2.2 + npm-pick-manifest: 6.1.1 + npm-registry-fetch: 11.0.0 + promise-retry: 2.0.1 + read-package-json-fast: 2.0.3 + rimraf: 3.0.2 + ssri: 8.0.1 + tar: 6.2.1 + transitivePeerDependencies: + - supports-color + + pako@1.0.11: {} + + param-case@3.0.4: + dependencies: + dot-case: 3.0.4 + tslib: 2.8.1 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@4.0.0: + dependencies: + error-ex: 1.3.2 + json-parse-better-errors: 1.0.2 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.26.2 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parse-json@7.1.1: + dependencies: + '@babel/code-frame': 7.26.2 + error-ex: 1.3.2 + json-parse-even-better-errors: 3.0.2 + lines-and-columns: 2.0.4 + type-fest: 3.13.1 + + parse-ms@2.1.0: {} + + parse-ms@3.0.0: {} + + parse5@6.0.1: {} + + parseurl@1.3.3: {} + + pascal-case@3.1.2: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + + path-case@3.0.4: + dependencies: + dot-case: 3.0.4 + tslib: 2.8.1 + + path-exists@3.0.0: {} + + path-exists@4.0.0: {} + + path-exists@5.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@2.0.1: {} + + path-key@3.1.1: {} + + path-key@4.0.0: {} + + path-parse@1.0.7: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + path-scurry@2.0.2: + dependencies: + lru-cache: 11.5.1 + minipass: 7.1.3 + + path-to-regexp@0.1.12: {} + + path-type@3.0.0: + dependencies: + pify: 3.0.0 + + path-type@4.0.0: {} + + path-type@6.0.0: {} + + path@0.12.7: + dependencies: + process: 0.11.10 + util: 0.10.4 + + pathe@1.1.2: {} + + pend@1.2.0: {} + + perf-regexes@1.0.1: {} + + performance-now@2.1.0: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + pidtree@0.3.1: {} + + pify@3.0.0: {} + + pify@4.0.1: {} + + pirates@4.0.6: {} + + pkg-conf@4.0.0: + dependencies: + find-up: 6.3.0 + load-json-file: 7.0.1 + + pkg-dir@3.0.0: + dependencies: + find-up: 3.0.0 + + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + + pkg-dir@5.0.0: + dependencies: + find-up: 5.0.0 + + plur@5.1.0: + dependencies: + irregular-plurals: 3.5.0 + + polka@0.5.2: + dependencies: + '@polka/url': 0.5.0 + trouter: 2.0.1 + + possible-typed-array-names@1.0.0: {} + + prelude-ls@1.2.1: {} + + presentable-error@0.0.1: {} + + pretty-format@26.6.2: + dependencies: + '@jest/types': 26.6.2 + ansi-regex: 5.0.1 + ansi-styles: 4.3.0 + react-is: 17.0.2 + + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + + pretty-format@28.1.3: + dependencies: + '@jest/schemas': 28.1.3 + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + pretty-ms@7.0.1: + dependencies: + parse-ms: 2.1.0 + + pretty-ms@8.0.0: + dependencies: + parse-ms: 3.0.0 + + process-nextick-args@2.0.1: {} + + process@0.11.10: {} + + progress@2.0.3: {} + + promise-inflight@1.0.1: {} + + promise-retry@2.0.1: + dependencies: + err-code: 2.0.3 + retry: 0.12.0 + + promise@8.3.0: + dependencies: + asap: 2.0.6 + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + proxy-agent@6.3.0: + dependencies: + agent-base: 7.1.3 + debug: 4.4.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + lru-cache: 7.18.3 + pac-proxy-agent: 7.1.0 + proxy-from-env: 1.1.0 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color + + proxy-agent@6.3.1: + dependencies: + agent-base: 7.1.3 + debug: 4.4.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + lru-cache: 7.18.3 + pac-proxy-agent: 7.1.0 + proxy-from-env: 1.1.0 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color + + proxy-agent@6.5.0: + dependencies: + agent-base: 7.1.3 + debug: 4.4.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + lru-cache: 7.18.3 + pac-proxy-agent: 7.1.0 + proxy-from-env: 1.1.0 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color + + proxy-from-env@1.1.0: {} + + psl@1.15.0: + dependencies: + punycode: 2.3.1 + + pump@3.0.2: + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + + punycode@2.3.1: {} + + puppeteer-core@20.9.0(encoding@0.1.13)(typescript@4.6.4): + dependencies: + '@puppeteer/browsers': 1.4.6(typescript@4.6.4) + chromium-bidi: 0.4.16(devtools-protocol@0.0.1147663) + cross-fetch: 4.0.0(encoding@0.1.13) + debug: 4.3.4 + devtools-protocol: 0.0.1147663 + ws: 8.13.0 + optionalDependencies: + typescript: 4.6.4 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + + qs@6.13.0: + dependencies: + side-channel: 1.1.0 + + qs@6.5.3: {} + + query-selector-shadow-dom@1.0.1: {} + + query-string@7.1.3: + dependencies: + decode-uri-component: 0.2.2 + filter-obj: 1.1.0 + split-on-first: 1.1.0 + strict-uri-encode: 2.0.0 + + querystring@0.2.1: {} + + querystringify@2.2.0: {} + + queue-microtask@1.2.3: {} + + queue-tick@1.0.1: {} + + queue@6.0.2: + dependencies: + inherits: 2.0.4 + + quick-lru@5.1.1: {} + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + randomcolor@0.6.2: {} + + range-parser@1.2.1: {} + + raw-body@2.5.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + + react-devtools-core@5.3.2: + dependencies: + shell-quote: 1.8.2 + ws: 7.5.10 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + react-is@17.0.2: {} + + react-is@18.3.1: {} + + react-native-builder-bob@0.42.1: + dependencies: + '@babel/core': 7.29.7 + '@babel/plugin-transform-flow-strip-types': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-strict-mode': 7.29.7(@babel/core@7.29.7) + '@babel/preset-env': 7.29.7(@babel/core@7.29.7) + '@babel/preset-react': 7.29.7(@babel/core@7.29.7) + '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7) + '@jridgewell/sourcemap-codec': 1.5.5 + arktype: 2.2.0 + babel-plugin-syntax-hermes-parser: 0.34.0 + browserslist: 4.28.2 + cross-spawn: 7.0.6 + dedent: 1.7.2 + del: 8.0.1 + escape-string-regexp: 5.0.0 + fs-extra: 11.3.5 + glob: 13.0.6 + json5: 2.2.3 + kleur: 4.1.5 + prompts: 2.4.2 + react-native-monorepo-config: 0.3.5 + typescript: 6.0.3 + which: 6.0.1 + yargs: 18.0.0 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + react-native-get-random-values@1.11.0(react-native@0.74.5(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@types/react@18.3.18)(encoding@0.1.13)(react@18.2.0)): + dependencies: + fast-base64-decode: 1.0.0 + react-native: 0.74.5(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@types/react@18.3.18)(encoding@0.1.13)(react@18.2.0) + + react-native-monorepo-config@0.3.5: + dependencies: + escape-string-regexp: 5.0.0 + fast-glob: 3.3.3 + + react-native@0.74.5(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@types/react@18.3.18)(encoding@0.1.13)(react@18.2.0): + dependencies: + '@jest/create-cache-key-function': 29.7.0 + '@react-native-community/cli': 13.6.9(encoding@0.1.13) + '@react-native-community/cli-platform-android': 13.6.9(encoding@0.1.13) + '@react-native-community/cli-platform-ios': 13.6.9(encoding@0.1.13) + '@react-native/assets-registry': 0.74.87 + '@react-native/codegen': 0.74.87(@babel/preset-env@7.29.7(@babel/core@7.29.7)) + '@react-native/community-cli-plugin': 0.74.87(@babel/preset-env@7.29.7(@babel/core@7.29.7))(encoding@0.1.13) + '@react-native/gradle-plugin': 0.74.87 + '@react-native/js-polyfills': 0.74.87 + '@react-native/normalize-colors': 0.74.87 + '@react-native/virtualized-lists': 0.74.87(@types/react@18.3.18)(react-native@0.74.5(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@types/react@18.3.18)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + abort-controller: 3.0.0 + anser: 1.4.10 + ansi-regex: 5.0.1 + base64-js: 1.5.1 + chalk: 4.1.2 + event-target-shim: 5.0.1 + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + jest-environment-node: 29.7.0 + jsc-android: 250231.0.0 + memoize-one: 5.2.1 + metro-runtime: 0.80.12 + metro-source-map: 0.80.12 + mkdirp: 0.5.6 + nullthrows: 1.1.1 + pretty-format: 26.6.2 + promise: 8.3.0 + react: 18.2.0 + react-devtools-core: 5.3.2 + react-refresh: 0.14.2 + react-shallow-renderer: 16.15.0(react@18.2.0) + regenerator-runtime: 0.13.11 + scheduler: 0.24.0-canary-efb381bbf-20230505 + stacktrace-parser: 0.1.10 + whatwg-fetch: 3.6.20 + ws: 6.2.3 + yargs: 17.7.2 + optionalDependencies: + '@types/react': 18.3.18 + transitivePeerDependencies: + - '@babel/preset-env' + - bufferutil + - encoding + - supports-color + - utf-8-validate + + react-refresh@0.14.2: {} + + react-shallow-renderer@16.15.0(react@18.2.0): + dependencies: + object-assign: 4.1.1 + react: 18.2.0 + react-is: 18.3.1 + + react@18.2.0: + dependencies: + loose-envify: 1.4.0 + + read-package-json-fast@2.0.3: + dependencies: + json-parse-even-better-errors: 2.3.1 + npm-normalize-package-bin: 1.0.1 + + read-pkg-up@10.0.0: + dependencies: + find-up: 6.3.0 + read-pkg: 8.1.0 + type-fest: 3.13.1 + + read-pkg@3.0.0: + dependencies: + load-json-file: 4.0.0 + normalize-package-data: 2.5.0 + path-type: 3.0.0 + + read-pkg@8.1.0: + dependencies: + '@types/normalize-package-data': 2.4.4 + normalize-package-data: 6.0.2 + parse-json: 7.1.1 + type-fest: 4.31.0 + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readable-stream@4.6.0: + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + + readdir-glob@1.1.3: + dependencies: + minimatch: 5.1.6 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + readline@1.3.0: {} + + recast@0.21.5: + dependencies: + ast-types: 0.15.2 + esprima: 4.0.1 + source-map: 0.6.1 + tslib: 2.8.1 + + recursive-readdir@2.2.3: + dependencies: + minimatch: 3.1.2 + + reflect.getprototypeof@1.0.9: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + dunder-proto: 1.0.1 + es-abstract: 1.23.8 + es-errors: 1.3.0 + get-intrinsic: 1.2.6 + gopd: 1.2.0 + which-builtin-type: 1.2.1 + + regenerate-unicode-properties@10.2.0: + dependencies: + regenerate: 1.4.2 + + regenerate-unicode-properties@10.2.2: + dependencies: + regenerate: 1.4.2 + + regenerate@1.4.2: {} + + regenerator-runtime@0.13.11: {} + + regenerator-runtime@0.14.1: {} + + regexp.prototype.flags@1.5.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + set-function-name: 2.0.2 + + regexpp@3.2.0: {} + + regexpu-core@6.2.0: + dependencies: + regenerate: 1.4.2 + regenerate-unicode-properties: 10.2.0 + regjsgen: 0.8.0 + regjsparser: 0.12.0 + unicode-match-property-ecmascript: 2.0.0 + unicode-match-property-value-ecmascript: 2.2.0 + + regexpu-core@6.4.0: + dependencies: + regenerate: 1.4.2 + regenerate-unicode-properties: 10.2.2 + regjsgen: 0.8.0 + regjsparser: 0.13.1 + unicode-match-property-ecmascript: 2.0.0 + unicode-match-property-value-ecmascript: 2.2.1 + + regjsgen@0.8.0: {} + + regjsparser@0.12.0: + dependencies: + jsesc: 3.0.2 + + regjsparser@0.13.1: + dependencies: + jsesc: 3.1.0 + + request@2.88.2: + dependencies: + aws-sign2: 0.7.0 + aws4: 1.13.2 + caseless: 0.12.0 + combined-stream: 1.0.8 + extend: 3.0.2 + forever-agent: 0.6.1 + form-data: 2.3.3 + har-validator: 5.1.5 + http-signature: 1.2.0 + is-typedarray: 1.0.0 + isstream: 0.1.2 + json-stringify-safe: 5.0.1 + mime-types: 2.1.35 + oauth-sign: 0.9.0 + performance-now: 2.1.0 + qs: 6.5.3 + safe-buffer: 5.2.1 + tough-cookie: 2.5.0 + tunnel-agent: 0.6.0 + uuid: 3.4.0 + + require-directory@2.1.1: {} + + require-main-filename@2.0.0: {} + + requires-port@1.0.0: {} + + resolve-alpn@1.2.1: {} + + resolve-cwd@3.0.0: + dependencies: + resolve-from: 5.0.0 + + resolve-from@3.0.0: {} + + resolve-from@4.0.0: {} + + resolve-from@5.0.0: {} + + resolve.exports@1.1.1: {} + + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + resolve@1.22.12: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + responselike@2.0.1: + dependencies: + lowercase-keys: 2.0.0 + + responselike@3.0.0: + dependencies: + lowercase-keys: 3.0.0 + + resq@1.11.0: + dependencies: + fast-deep-equal: 2.0.1 + + restore-cursor@3.1.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + + retry@0.12.0: {} + + reusify@1.0.4: {} + + rgb2hex@0.2.5: {} + + rimraf@2.6.3: + dependencies: + glob: 7.2.3 + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + rollup-plugin-cleanup@3.2.1(rollup@2.70.2): + dependencies: + js-cleanup: 1.2.0 + rollup: 2.70.2 + rollup-pluginutils: 2.8.2 + + rollup-plugin-filesize@9.1.2: + dependencies: + '@babel/runtime': 7.26.0 + boxen: 5.1.2 + brotli-size: 4.0.0 + colors: 1.4.0 + filesize: 6.4.0 + gzip-size: 6.0.0 + pacote: 11.3.5 + terser: 5.37.0 + transitivePeerDependencies: + - supports-color + + rollup-plugin-license@2.6.1(rollup@2.70.2): + dependencies: + commenting: 1.1.0 + glob: 7.2.0 + lodash: 4.17.21 + magic-string: 0.25.7 + mkdirp: 1.0.4 + moment: 2.29.1 + package-name-regex: 2.0.5 + rollup: 2.70.2 + spdx-expression-validate: 2.0.0 + spdx-satisfies: 5.0.1 + + rollup-plugin-sizes@1.0.6(rollup@2.70.2): + dependencies: + filesize: 9.0.11 + module-details-from-path: 1.0.3 + rollup: 2.70.2 + + rollup-plugin-terser@7.0.2(rollup@2.70.2): + dependencies: + '@babel/code-frame': 7.26.2 + jest-worker: 26.6.2 + rollup: 2.70.2 + serialize-javascript: 4.0.0 + terser: 5.37.0 + + rollup-plugin-ts@2.0.7(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.25.9(@babel/core@7.29.7))(@babel/preset-env@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.26.0)(rollup@2.70.2)(typescript@4.6.4): + dependencies: + '@rollup/pluginutils': 4.2.1 + '@wessberg/stringutil': 1.0.19 + browserslist: 4.24.3 + browserslist-generator: 1.0.66 + chalk: 4.1.2 + compatfactory: 0.0.13(typescript@4.6.4) + crosspath: 1.0.0 + magic-string: 0.26.7 + rollup: 2.70.2 + ts-clone-node: 0.3.32(typescript@4.6.4) + tslib: 2.8.1 + typescript: 4.6.4 + optionalDependencies: + '@babel/core': 7.29.7 + '@babel/plugin-transform-runtime': 7.25.9(@babel/core@7.29.7) + '@babel/preset-env': 7.29.7(@babel/core@7.29.7) + '@babel/runtime': 7.26.0 + + rollup-pluginutils@2.8.2: + dependencies: + estree-walker: 0.6.1 + + rollup@2.70.2: + optionalDependencies: + fsevents: 2.3.3 + + run-async@3.0.0: {} + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + rxjs@7.8.1: + dependencies: + tslib: 2.8.1 + + safaridriver@0.0.6: {} + + safaridriver@0.1.2: {} + + safe-array-concat@1.1.3: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + get-intrinsic: 1.2.6 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-buffer@5.1.2: {} + + safe-buffer@5.2.1: {} + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-regex: 1.2.1 + + safer-buffer@2.1.2: {} + + saucelabs@7.5.0: + dependencies: + change-case: 4.1.2 + compressing: 1.10.1 + form-data: 4.0.1 + got: 11.8.6 + hash.js: 1.1.7 + query-string: 7.1.3 + tunnel: 0.0.6 + yargs: 17.7.2 + + saxes@5.0.1: + dependencies: + xmlchars: 2.2.0 + + scheduler@0.24.0-canary-efb381bbf-20230505: + dependencies: + loose-envify: 1.4.0 + + selfsigned@2.4.1: + dependencies: + '@types/node-forge': 1.3.11 + node-forge: 1.3.1 + + semver@5.7.2: {} + + semver@6.3.1: {} + + semver@7.6.3: {} + + send@0.19.0: + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + + sentence-case@3.0.4: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + upper-case-first: 2.0.2 + + serialize-error@11.0.3: + dependencies: + type-fest: 2.19.0 + + serialize-error@2.1.0: {} + + serialize-error@7.0.1: + dependencies: + type-fest: 0.13.1 + + serialize-javascript@4.0.0: + dependencies: + randombytes: 2.1.0 + + serve-static@1.16.2: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.0 + + set-blocking@2.0.0: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.6 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + setimmediate@1.0.5: {} + + setprototypeof@1.2.0: {} + + shallow-clone@3.0.1: + dependencies: + kind-of: 6.0.3 + + shebang-command@1.2.0: + dependencies: + shebang-regex: 1.0.0 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@1.0.0: {} + + shebang-regex@3.0.0: {} + + shell-quote@1.8.2: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.3 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.6 + object-inspect: 1.13.3 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.6 + object-inspect: 1.13.3 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.3 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + signal-exit@3.0.7: {} + + signal-exit@4.1.0: {} + + sisteransi@1.0.5: {} + + skip-regex@1.0.2: {} + + slash@3.0.0: {} + + slash@4.0.0: {} + + slash@5.1.0: {} + + slice-ansi@2.1.0: + dependencies: + ansi-styles: 3.2.1 + astral-regex: 1.0.0 + is-fullwidth-code-point: 2.0.0 + + slice-ansi@5.0.0: + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + + smart-buffer@4.2.0: {} + + snake-case@3.0.4: + dependencies: + dot-case: 3.0.4 + tslib: 2.8.1 + + socks-proxy-agent@6.2.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.0 + socks: 2.8.3 + transitivePeerDependencies: + - supports-color + + socks-proxy-agent@8.0.5: + dependencies: + agent-base: 7.1.3 + debug: 4.4.0 + socks: 2.8.3 + transitivePeerDependencies: + - supports-color + + socks@2.8.3: + dependencies: + ip-address: 9.0.5 + smart-buffer: 4.2.0 + + source-map-support@0.5.13: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.5.7: {} + + source-map@0.6.1: {} + + source-map@0.7.4: {} + + sourcemap-codec@1.4.8: {} + + spacetrim@0.11.59: {} + + spdx-compare@1.0.0: + dependencies: + array-find-index: 1.0.2 + spdx-expression-parse: 3.0.1 + spdx-ranges: 2.1.1 + + spdx-correct@3.2.0: + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.20 + + spdx-exceptions@2.5.0: {} + + spdx-expression-parse@3.0.1: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.20 + + spdx-expression-validate@2.0.0: + dependencies: + spdx-expression-parse: 3.0.1 + + spdx-license-ids@3.0.20: {} + + spdx-ranges@2.1.1: {} + + spdx-satisfies@5.0.1: + dependencies: + spdx-compare: 1.0.0 + spdx-expression-parse: 3.0.1 + spdx-ranges: 2.1.1 + + split-ca@1.0.1: {} + + split-on-first@1.1.0: {} + + split2@4.2.0: {} + + sprintf-js@1.0.3: {} + + sprintf-js@1.1.3: {} + + ssh2@1.16.0: + dependencies: + asn1: 0.2.6 + bcrypt-pbkdf: 1.0.2 + optionalDependencies: + cpu-features: 0.0.10 + nan: 2.22.0 + + sshpk@1.18.0: + dependencies: + asn1: 0.2.6 + assert-plus: 1.0.0 + bcrypt-pbkdf: 1.0.2 + dashdash: 1.14.1 + ecc-jsbn: 0.1.2 + getpass: 0.1.7 + jsbn: 0.1.1 + safer-buffer: 2.1.2 + tweetnacl: 0.14.5 + + ssri@8.0.1: + dependencies: + minipass: 3.3.6 + + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + + stackframe@1.3.4: {} + + stacktrace-parser@0.1.10: + dependencies: + type-fest: 0.7.1 + + statuses@1.5.0: {} + + statuses@2.0.1: {} + + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + stream-buffers@3.0.3: {} + + streamifier@0.1.1: {} + + streamx@2.21.1: + dependencies: + fast-fifo: 1.3.2 + queue-tick: 1.0.1 + text-decoder: 1.2.3 + optionalDependencies: + bare-events: 2.5.0 + + strict-uri-encode@2.0.0: {} + + string-length@4.0.2: + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + + string-width@1.0.2: + dependencies: + code-point-at: 1.1.0 + is-fullwidth-code-point: 1.0.0 + strip-ansi: 3.0.1 + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + string-width@7.2.0: + dependencies: + emoji-regex: 10.6.0 + get-east-asian-width: 1.6.0 + strip-ansi: 7.1.0 + + string.prototype.padend@3.1.6: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.8 + es-object-atoms: 1.0.0 + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.23.8 + es-object-atoms: 1.0.0 + has-property-descriptors: 1.0.2 + + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@3.0.1: + dependencies: + ansi-regex: 2.1.1 + + strip-ansi@5.2.0: + dependencies: + ansi-regex: 4.1.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.1.0 + + strip-bom@3.0.0: {} + + strip-bom@4.0.0: {} + + strip-final-newline@2.0.0: {} + + strip-final-newline@3.0.0: {} + + strip-json-comments@3.1.1: {} + + strnum@1.0.5: {} + + sudo-prompt@9.2.1: {} + + supertap@3.0.1: + dependencies: + indent-string: 5.0.0 + js-yaml: 3.14.1 + serialize-error: 7.0.1 + strip-ansi: 7.1.0 + + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-hyperlinks@2.3.0: + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + symbol-tree@3.2.4: {} + + tar-fs@2.0.1: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.2 + tar-stream: 2.2.0 + + tar-fs@3.0.4: + dependencies: + mkdirp-classic: 0.5.3 + pump: 3.0.2 + tar-stream: 3.1.7 + + tar-fs@3.0.6: + dependencies: + pump: 3.0.2 + tar-stream: 3.1.7 + optionalDependencies: + bare-fs: 2.3.5 + bare-path: 2.1.3 + + tar-stream@1.6.2: + dependencies: + bl: 1.2.3 + buffer-alloc: 1.2.0 + end-of-stream: 1.4.4 + fs-constants: 1.0.0 + readable-stream: 2.3.8 + to-buffer: 1.1.1 + xtend: 4.0.2 + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.4 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + + tar-stream@3.1.7: + dependencies: + b4a: 1.6.7 + fast-fifo: 1.3.2 + streamx: 2.21.1 + + tar@6.2.1: + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 5.0.0 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 + + tcp-port-used@1.0.2: + dependencies: + debug: 4.3.1 + is2: 2.0.9 + transitivePeerDependencies: + - supports-color + + temp-dir@2.0.0: {} + + temp-dir@3.0.0: {} + + temp@0.8.4: + dependencies: + rimraf: 2.6.3 + + terminal-link@2.1.1: + dependencies: + ansi-escapes: 4.3.2 + supports-hyperlinks: 2.3.0 + + terser@5.37.0: + dependencies: + '@jridgewell/source-map': 0.3.6 + acorn: 8.14.0 + commander: 2.20.3 + source-map-support: 0.5.21 + + test-exclude@6.0.0: + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + + text-decoder@1.2.3: + dependencies: + b4a: 1.6.7 + + text-table@0.2.0: {} + + throat@5.0.0: {} + + through2@2.0.5: + dependencies: + readable-stream: 2.3.8 + xtend: 4.0.2 + + through@2.3.8: {} + + time-zone@1.0.0: {} + + tinyrainbow@1.2.0: {} + + tmp@0.0.33: + dependencies: + os-tmpdir: 1.0.2 + + tmpl@1.0.5: {} + + to-buffer@1.1.1: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + toidentifier@1.0.1: {} + + tough-cookie@2.5.0: + dependencies: + psl: 1.15.0 + punycode: 2.3.1 + + tough-cookie@4.1.4: + dependencies: + psl: 1.15.0 + punycode: 2.3.1 + universalify: 0.2.0 + url-parse: 1.5.10 + + tr46@0.0.3: {} + + tr46@3.0.0: + dependencies: + punycode: 2.3.1 + + trouter@2.0.1: + dependencies: + matchit: 1.1.0 + + ts-clone-node@0.3.32(typescript@4.6.4): + dependencies: + compatfactory: 0.0.13(typescript@4.6.4) + typescript: 4.6.4 + + ts-jest@28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@14.6.4)(ts-node@10.9.2(@types/node@14.6.4)(typescript@4.6.4)))(typescript@4.6.4): + dependencies: + bs-logger: 0.2.6 + fast-json-stable-stringify: 2.1.0 + jest: 28.1.3(@types/node@14.6.4)(ts-node@10.9.2(@types/node@14.6.4)(typescript@4.6.4)) + jest-util: 28.1.3 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.6.3 + typescript: 4.6.4 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.29.7 + '@jest/types': 28.1.3 + babel-jest: 28.1.3(@babel/core@7.29.7) + + ts-jest@28.0.8(@babel/core@7.29.7)(@jest/types@28.1.3)(babel-jest@28.1.3(@babel/core@7.29.7))(jest@28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)))(typescript@4.6.4): + dependencies: + bs-logger: 0.2.6 + fast-json-stable-stringify: 2.1.0 + jest: 28.1.3(@types/node@20.17.10)(ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4)) + jest-util: 28.1.3 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.6.3 + typescript: 4.6.4 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.29.7 + '@jest/types': 28.1.3 + babel-jest: 28.1.3(@babel/core@7.29.7) + + ts-node@10.9.2(@types/node@14.6.4)(typescript@4.6.4): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 14.6.4 + acorn: 8.14.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 4.6.4 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + + ts-node@10.9.2(@types/node@20.17.10)(typescript@4.6.4): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 20.17.10 + acorn: 8.14.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 4.6.4 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optional: true + + tslib@1.14.1: {} + + tslib@2.8.1: {} + + tsutils@3.21.0(typescript@4.6.4): + dependencies: + tslib: 1.14.1 + typescript: 4.6.4 + + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + + tunnel@0.0.6: {} + + tweetnacl@0.14.5: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-detect@4.0.8: {} + + type-fest@0.13.1: {} + + type-fest@0.20.2: {} + + type-fest@0.21.3: {} + + type-fest@0.7.1: {} + + type-fest@2.19.0: {} + + type-fest@3.13.1: {} + + type-fest@4.26.0: {} + + type-fest@4.31.0: {} + + type-is@1.6.18: + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.9 + + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.0.0 + reflect.getprototypeof: 1.0.9 + + typescript@4.6.4: {} + + typescript@6.0.3: {} + + ua-parser-js@1.0.40: {} + + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.3 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + unbzip2-stream@1.4.3: + dependencies: + buffer: 5.7.1 + through: 2.3.8 + + undici-types@5.26.5: {} + + undici-types@6.19.8: {} + + unicode-canonical-property-names-ecmascript@2.0.1: {} + + unicode-match-property-ecmascript@2.0.0: + dependencies: + unicode-canonical-property-names-ecmascript: 2.0.1 + unicode-property-aliases-ecmascript: 2.1.0 + + unicode-match-property-value-ecmascript@2.2.0: {} + + unicode-match-property-value-ecmascript@2.2.1: {} + + unicode-property-aliases-ecmascript@2.1.0: {} + + unicorn-magic@0.3.0: {} + + unique-filename@1.1.1: + dependencies: + unique-slug: 2.0.2 + + unique-slug@2.0.2: + dependencies: + imurmurhash: 0.1.4 + + universalify@0.1.2: {} + + universalify@0.2.0: {} + + universalify@2.0.1: {} + + unpipe@1.0.0: {} + + update-browserslist-db@1.1.1(browserslist@4.24.3): + dependencies: + browserslist: 4.24.3 + escalade: 3.2.0 + picocolors: 1.1.1 + + update-browserslist-db@1.2.3(browserslist@4.28.2): + dependencies: + browserslist: 4.28.2 + escalade: 3.2.0 + picocolors: 1.1.1 + + upper-case-first@2.0.2: + dependencies: + tslib: 2.8.1 + + upper-case@2.0.2: + dependencies: + tslib: 2.8.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + url-parse@1.5.10: + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + + userhome@1.0.1: {} + + util-deprecate@1.0.2: {} + + util@0.10.4: + dependencies: + inherits: 2.0.3 + + utils-merge@1.0.1: {} + + uuid@11.1.1: {} + + uuid@3.4.0: {} + + v8-compile-cache-lib@3.0.1: {} + + v8-compile-cache@2.4.0: {} + + v8-to-istanbul@9.3.0: + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + '@types/istanbul-lib-coverage': 2.0.6 + convert-source-map: 2.0.0 + + validate-npm-package-license@3.0.4: + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + + validate-npm-package-name@3.0.0: + dependencies: + builtins: 1.0.3 + + vary@1.1.2: {} + + verror@1.10.0: + dependencies: + assert-plus: 1.0.0 + core-util-is: 1.0.2 + extsprintf: 1.3.0 + + vlq@1.0.1: {} + + w3c-hr-time@1.0.2: + dependencies: + browser-process-hrtime: 1.0.0 + + w3c-xmlserializer@3.0.0: + dependencies: + xml-name-validator: 4.0.0 + + wait-port@1.1.0: + dependencies: + chalk: 4.1.2 + commander: 9.5.0 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + + walker@1.0.8: + dependencies: + makeerror: 1.0.12 + + wcwidth@1.0.1: + dependencies: + defaults: 1.0.4 + + wdio-chromedriver-service@8.1.1(@wdio/types@8.39.0)(chromedriver@131.0.4)(webdriverio@8.39.1(encoding@0.1.13)(typescript@4.6.4)): + dependencies: + '@wdio/logger': 8.38.0 + fs-extra: 11.2.0 + split2: 4.2.0 + tcp-port-used: 1.0.2 + webdriverio: 8.39.1(encoding@0.1.13)(typescript@4.6.4) + optionalDependencies: + '@wdio/types': 8.39.0 + chromedriver: 131.0.4 + transitivePeerDependencies: + - supports-color + + wdio-edgedriver-service@3.0.3(@wdio/types@8.39.0): + dependencies: + '@wdio/logger': 8.38.0 + edgedriver: 5.6.1 + get-port: 7.1.0 + split2: 4.2.0 + wait-port: 1.1.0 + optionalDependencies: + '@wdio/types': 8.39.0 + transitivePeerDependencies: + - supports-color + + wdio-safaridriver-service@2.1.1(@wdio/types@8.39.0)(webdriverio@8.39.1(encoding@0.1.13)(typescript@4.6.4)): + dependencies: + '@types/split2': 4.2.3 + '@types/tcp-port-used': 1.0.4 + '@wdio/logger': 8.38.0 + fs-extra: 11.2.0 + safaridriver: 0.0.6 + split2: 4.2.0 + tcp-port-used: 1.0.2 + webdriverio: 8.39.1(encoding@0.1.13)(typescript@4.6.4) + optionalDependencies: + '@wdio/types': 8.39.0 + transitivePeerDependencies: + - supports-color + + weakmap-polyfill@2.0.4: {} + + web-streams-polyfill@3.3.3: {} + + web-vitals@4.2.4: {} + + webdriver@8.39.0: + dependencies: + '@types/node': 20.17.10 + '@types/ws': 8.5.13 + '@wdio/config': 8.39.0 + '@wdio/logger': 8.38.0 + '@wdio/protocols': 8.38.0 + '@wdio/types': 8.39.0 + '@wdio/utils': 8.39.0 + deepmerge-ts: 5.1.0 + got: 12.6.1 + ky: 0.33.3 + ws: 8.18.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + webdriverio@8.39.1(encoding@0.1.13)(typescript@4.6.4): + dependencies: + '@types/node': 20.17.10 + '@wdio/config': 8.39.0 + '@wdio/logger': 8.38.0 + '@wdio/protocols': 8.38.0 + '@wdio/repl': 8.24.12 + '@wdio/types': 8.39.0 + '@wdio/utils': 8.39.0 + archiver: 7.0.1 + aria-query: 5.3.2 + css-shorthand-properties: 1.1.2 + css-value: 0.0.1 + devtools-protocol: 0.0.1302984 + grapheme-splitter: 1.0.4 + import-meta-resolve: 4.1.0 + is-plain-obj: 4.1.0 + jszip: 3.10.1 + lodash.clonedeep: 4.5.0 + lodash.zip: 4.2.0 + minimatch: 9.0.5 + puppeteer-core: 20.9.0(encoding@0.1.13)(typescript@4.6.4) + query-selector-shadow-dom: 1.0.1 + resq: 1.11.0 + rgb2hex: 0.2.5 + serialize-error: 11.0.3 + webdriver: 8.39.0 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - typescript + - utf-8-validate + + webidl-conversions@3.0.1: {} + + webidl-conversions@7.0.0: {} + + well-known-symbols@2.0.0: {} + + whatwg-encoding@2.0.0: + dependencies: + iconv-lite: 0.6.3 + + whatwg-fetch@3.6.20: {} + + whatwg-mimetype@3.0.0: {} + + whatwg-url@10.0.0: + dependencies: + tr46: 3.0.0 + webidl-conversions: 7.0.0 + + whatwg-url@11.0.0: + dependencies: + tr46: 3.0.0 + webidl-conversions: 7.0.0 + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.1 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.3 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.0.0 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.0.10 + is-regex: 1.2.1 + is-weakref: 1.1.0 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.18 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-module@2.0.1: {} + + which-typed-array@1.1.18: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.3 + for-each: 0.3.3 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@1.3.1: + dependencies: + isexe: 2.0.0 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + which@4.0.0: + dependencies: + isexe: 3.1.1 + + which@6.0.1: + dependencies: + isexe: 4.0.0 + + wide-align@1.1.5: + dependencies: + string-width: 4.2.3 + + widest-line@3.1.0: + dependencies: + string-width: 4.2.3 + + word-wrap@1.2.5: {} + + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + wrap-ansi@9.0.2: + dependencies: + ansi-styles: 6.2.1 + string-width: 7.2.0 + strip-ansi: 7.1.0 + + wrappy@1.0.2: {} + + write-file-atomic@2.4.3: + dependencies: + graceful-fs: 4.2.11 + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + + write-file-atomic@4.0.2: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + + write-file-atomic@5.0.1: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 4.1.0 + + ws@6.2.3: + dependencies: + async-limiter: 1.0.1 + + ws@7.5.10: {} + + ws@8.13.0: {} + + ws@8.18.0: {} + + xml-name-validator@4.0.0: {} + + xmlchars@2.2.0: {} + + xtend@4.0.2: {} + + y18n@4.0.3: {} + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yallist@4.0.0: {} + + yaml@2.6.1: {} + + yargs-parser@18.1.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + + yargs-parser@21.1.1: {} + + yargs-parser@22.0.0: {} + + yargs@15.4.1: + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + + yargs@17.7.1: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yargs@18.0.0: + dependencies: + cliui: 9.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + string-width: 7.2.0 + y18n: 5.0.8 + yargs-parser: 22.0.0 + + yauzl@2.10.0: + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + + yazl@2.5.1: + dependencies: + buffer-crc32: 0.2.13 + + yn@3.1.1: {} + + yocto-queue@0.1.0: {} + + yocto-queue@1.1.1: {} + + zip-stream@6.0.1: + dependencies: + archiver-utils: 5.0.2 + compress-commons: 6.0.2 + readable-stream: 4.6.0 diff --git a/common/config/rush/repo-state.json b/common/config/rush/repo-state.json new file mode 100644 index 000000000..08792e831 --- /dev/null +++ b/common/config/rush/repo-state.json @@ -0,0 +1,5 @@ +// DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush. +{ + "pnpmShrinkwrapHash": "abc453596eaf2cd7ff26dca182f8e42042b6326e", + "preferredVersionsHash": "bf21a9e8fbc5a3846fb05b4fa0859e0917b2202f" +} diff --git a/common/config/rush/version-policies.json b/common/config/rush/version-policies.json new file mode 100644 index 000000000..60a66ed3d --- /dev/null +++ b/common/config/rush/version-policies.json @@ -0,0 +1,43 @@ +/** + * This is configuration file is used for advanced publishing configurations with Rush. + * For full documentation, please see https://rushjs.io + */ +/** + * A list of version policy definitions. A "version policy" is a custom package versioning + * strategy that affects "rush change", "rush version", and "rush publish". The strategy applies + * to a set of projects that are specified using the "versionPolicyName" field in rush.json. + */ +[ + { + /** + * (Required) Indicates the kind of version policy being defined ("lockStepVersion" or "individualVersion"). + * + * The "lockStepVersion" mode specifies that the projects will use "lock-step versioning". This + * strategy is appropriate for a set of packages that act as selectable components of a + * unified product. The entire set of packages are always published together, and always share + * the same NPM version number. When the packages depend on other packages in the set, the + * SemVer range is usually restricted to a single version. + */ + "definitionName": "lockStepVersion", + /** + * (Required) The name that will be used for the "versionPolicyName" field in rush.json. + * This name is also used command-line parameters such as "--version-policy" + * and "--to-version-policy". + */ + "policyName": "tracker", + /** + * (Required) The current version. All packages belonging to the set should have this version + * in the current branch. When bumping versions, Rush uses this to determine the next version. + * (The "version" field in package.json is NOT considered.) + */ + "version": "4.10.0", + /** + * (Required) The type of bump that will be performed when publishing the next release. + * When creating a release branch in Git, this field should be updated according to the + * type of release. + * + * Valid values are: "prerelease", "release", "minor", "patch", "major" + */ + "nextBump": "minor" + } +] diff --git a/common/git-hooks/pre-commit b/common/git-hooks/pre-commit new file mode 100755 index 000000000..07b96ad6c --- /dev/null +++ b/common/git-hooks/pre-commit @@ -0,0 +1,24 @@ +#!/bin/sh +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. + +# Invoke the "rush prettier" custom command to reformat files whenever they +# are committed. The command is defined in common/config/rush/command-line.json +# and uses the "rush-prettier" autoinstaller. +node common/scripts/install-run-rush.js prettier || exit $? + +ERROR_COLOR='\033[0;31m' +WARNING_COLOR='\033[0;33m' +STOP_COLOR='\033[0m' + +if ! command -v gitleaks > /dev/null 2>&1 +then + echo "${ERROR_COLOR}\nGitleaks not found. To commit you safely, you need to install it per the instructions at https://github.com/gitleaks/gitleaks.${STOP_COLOR}" + exit 1 +elif [ "$SKIP" == "gitleaks" ] +then + echo "${WARNING_COLOR}\nGitleaks skipped for this commit.${STOP_COLOR}" +else + gitleaks protect -v --staged --report-path ./findings.json +fi diff --git a/common/media/snowplow_logo.png b/common/media/snowplow_logo.png new file mode 100644 index 000000000..11416ef28 Binary files /dev/null and b/common/media/snowplow_logo.png differ diff --git a/common/scripts/install-run-rush-pnpm.js b/common/scripts/install-run-rush-pnpm.js new file mode 100644 index 000000000..2356649f4 --- /dev/null +++ b/common/scripts/install-run-rush-pnpm.js @@ -0,0 +1,31 @@ +// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED. +// +// This script is intended for usage in an automated build environment where the Rush command may not have +// been preinstalled, or may have an unpredictable version. This script will automatically install the version of Rush +// specified in the rush.json configuration file (if not already installed), and then pass a command-line to the +// rush-pnpm command. +// +// An example usage would be: +// +// node common/scripts/install-run-rush-pnpm.js pnpm-command +// +// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/ +// +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See the @microsoft/rush package's LICENSE file for details. + +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +var __webpack_exports__ = {}; +/*!*****************************************************!*\ + !*** ./lib-esnext/scripts/install-run-rush-pnpm.js ***! + \*****************************************************/ + +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. +require('./install-run-rush'); +//# sourceMappingURL=install-run-rush-pnpm.js.map +module.exports = __webpack_exports__; +/******/ })() +; +//# sourceMappingURL=install-run-rush-pnpm.js.map \ No newline at end of file diff --git a/common/scripts/install-run-rush.js b/common/scripts/install-run-rush.js new file mode 100644 index 000000000..9676fc718 --- /dev/null +++ b/common/scripts/install-run-rush.js @@ -0,0 +1,218 @@ +// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED. +// +// This script is intended for usage in an automated build environment where the Rush command may not have +// been preinstalled, or may have an unpredictable version. This script will automatically install the version of Rush +// specified in the rush.json configuration file (if not already installed), and then pass a command-line to it. +// An example usage would be: +// +// node common/scripts/install-run-rush.js install +// +// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/ +// +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See the @microsoft/rush package's LICENSE file for details. + +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ({ + +/***/ 657147: +/*!*********************!*\ + !*** external "fs" ***! + \*********************/ +/***/ ((module) => { + +module.exports = require("fs"); + +/***/ }), + +/***/ 371017: +/*!***********************!*\ + !*** external "path" ***! + \***********************/ +/***/ ((module) => { + +module.exports = require("path"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/compat get default export */ +/******/ (() => { +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = (module) => { +/******/ var getter = module && module.__esModule ? +/******/ () => (module['default']) : +/******/ () => (module); +/******/ __webpack_require__.d(getter, { a: getter }); +/******/ return getter; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. +(() => { +/*!************************************************!*\ + !*** ./lib-esnext/scripts/install-run-rush.js ***! + \************************************************/ +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! path */ 371017); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! fs */ 657147); +/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_1__); +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. +/* eslint-disable no-console */ + + +const { installAndRun, findRushJsonFolder, RUSH_JSON_FILENAME, runWithErrorAndStatusCode } = require('./install-run'); +const PACKAGE_NAME = '@microsoft/rush'; +const RUSH_PREVIEW_VERSION = 'RUSH_PREVIEW_VERSION'; +const INSTALL_RUN_RUSH_LOCKFILE_PATH_VARIABLE = 'INSTALL_RUN_RUSH_LOCKFILE_PATH'; +function _getRushVersion(logger) { + const rushPreviewVersion = process.env[RUSH_PREVIEW_VERSION]; + if (rushPreviewVersion !== undefined) { + logger.info(`Using Rush version from environment variable ${RUSH_PREVIEW_VERSION}=${rushPreviewVersion}`); + return rushPreviewVersion; + } + const rushJsonFolder = findRushJsonFolder(); + const rushJsonPath = path__WEBPACK_IMPORTED_MODULE_0__.join(rushJsonFolder, RUSH_JSON_FILENAME); + try { + const rushJsonContents = fs__WEBPACK_IMPORTED_MODULE_1__.readFileSync(rushJsonPath, 'utf-8'); + // Use a regular expression to parse out the rushVersion value because rush.json supports comments, + // but JSON.parse does not and we don't want to pull in more dependencies than we need to in this script. + const rushJsonMatches = rushJsonContents.match(/\"rushVersion\"\s*\:\s*\"([0-9a-zA-Z.+\-]+)\"/); + return rushJsonMatches[1]; + } + catch (e) { + throw new Error(`Unable to determine the required version of Rush from ${RUSH_JSON_FILENAME} (${rushJsonFolder}). ` + + `The 'rushVersion' field is either not assigned in ${RUSH_JSON_FILENAME} or was specified ` + + 'using an unexpected syntax.'); + } +} +function _getBin(scriptName) { + switch (scriptName.toLowerCase()) { + case 'install-run-rush-pnpm.js': + return 'rush-pnpm'; + case 'install-run-rushx.js': + return 'rushx'; + default: + return 'rush'; + } +} +function _run() { + const [nodePath /* Ex: /bin/node */, scriptPath /* /repo/common/scripts/install-run-rush.js */, ...packageBinArgs /* [build, --to, myproject] */] = process.argv; + // Detect if this script was directly invoked, or if the install-run-rushx script was invokved to select the + // appropriate binary inside the rush package to run + const scriptName = path__WEBPACK_IMPORTED_MODULE_0__.basename(scriptPath); + const bin = _getBin(scriptName); + if (!nodePath || !scriptPath) { + throw new Error('Unexpected exception: could not detect node path or script path'); + } + let commandFound = false; + let logger = { info: console.log, error: console.error }; + for (const arg of packageBinArgs) { + if (arg === '-q' || arg === '--quiet') { + // The -q/--quiet flag is supported by both `rush` and `rushx`, and will suppress + // any normal informational/diagnostic information printed during startup. + // + // To maintain the same user experience, the install-run* scripts pass along this + // flag but also use it to suppress any diagnostic information normally printed + // to stdout. + logger = { + info: () => { }, + error: console.error + }; + } + else if (!arg.startsWith('-') || arg === '-h' || arg === '--help') { + // We either found something that looks like a command (i.e. - doesn't start with a "-"), + // or we found the -h/--help flag, which can be run without a command + commandFound = true; + } + } + if (!commandFound) { + console.log(`Usage: ${scriptName} [args...]`); + if (scriptName === 'install-run-rush-pnpm.js') { + console.log(`Example: ${scriptName} pnpm-command`); + } + else if (scriptName === 'install-run-rush.js') { + console.log(`Example: ${scriptName} build --to myproject`); + } + else { + console.log(`Example: ${scriptName} custom-command`); + } + process.exit(1); + } + runWithErrorAndStatusCode(logger, () => { + const version = _getRushVersion(logger); + logger.info(`The ${RUSH_JSON_FILENAME} configuration requests Rush version ${version}`); + const lockFilePath = process.env[INSTALL_RUN_RUSH_LOCKFILE_PATH_VARIABLE]; + if (lockFilePath) { + logger.info(`Found ${INSTALL_RUN_RUSH_LOCKFILE_PATH_VARIABLE}="${lockFilePath}", installing with lockfile.`); + } + return installAndRun(logger, PACKAGE_NAME, version, bin, packageBinArgs, lockFilePath); + }); +} +_run(); +//# sourceMappingURL=install-run-rush.js.map +})(); + +module.exports = __webpack_exports__; +/******/ })() +; +//# sourceMappingURL=install-run-rush.js.map \ No newline at end of file diff --git a/common/scripts/install-run-rushx.js b/common/scripts/install-run-rushx.js new file mode 100644 index 000000000..6581521f3 --- /dev/null +++ b/common/scripts/install-run-rushx.js @@ -0,0 +1,31 @@ +// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED. +// +// This script is intended for usage in an automated build environment where the Rush command may not have +// been preinstalled, or may have an unpredictable version. This script will automatically install the version of Rush +// specified in the rush.json configuration file (if not already installed), and then pass a command-line to the +// rushx command. +// +// An example usage would be: +// +// node common/scripts/install-run-rushx.js custom-command +// +// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/ +// +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See the @microsoft/rush package's LICENSE file for details. + +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +var __webpack_exports__ = {}; +/*!*************************************************!*\ + !*** ./lib-esnext/scripts/install-run-rushx.js ***! + \*************************************************/ + +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. +require('./install-run-rush'); +//# sourceMappingURL=install-run-rushx.js.map +module.exports = __webpack_exports__; +/******/ })() +; +//# sourceMappingURL=install-run-rushx.js.map \ No newline at end of file diff --git a/common/scripts/install-run.js b/common/scripts/install-run.js new file mode 100644 index 000000000..9283c4452 --- /dev/null +++ b/common/scripts/install-run.js @@ -0,0 +1,743 @@ +// THIS FILE WAS GENERATED BY A TOOL. ANY MANUAL MODIFICATIONS WILL GET OVERWRITTEN WHENEVER RUSH IS UPGRADED. +// +// This script is intended for usage in an automated build environment where a Node tool may not have +// been preinstalled, or may have an unpredictable version. This script will automatically install the specified +// version of the specified tool (if not already installed), and then pass a command-line to it. +// An example usage would be: +// +// node common/scripts/install-run.js qrcode@1.2.2 qrcode https://rushjs.io +// +// For more information, see: https://rushjs.io/pages/maintainer/setup_new_repo/ +// +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See the @microsoft/rush package's LICENSE file for details. + +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ({ + +/***/ 679877: +/*!************************************************!*\ + !*** ./lib-esnext/utilities/npmrcUtilities.js ***! + \************************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "isVariableSetInNpmrcFile": () => (/* binding */ isVariableSetInNpmrcFile), +/* harmony export */ "syncNpmrc": () => (/* binding */ syncNpmrc) +/* harmony export */ }); +/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! fs */ 657147); +/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! path */ 371017); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__); +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. +// IMPORTANT - do not use any non-built-in libraries in this file + + +/** + * This function reads the content for given .npmrc file path, and also trims + * unusable lines from the .npmrc file. + * + * @returns + * The text of the the .npmrc. + */ +// create a global _combinedNpmrc for cache purpose +const _combinedNpmrcMap = new Map(); +function _trimNpmrcFile(options) { + const { sourceNpmrcPath, linesToPrepend, linesToAppend } = options; + const combinedNpmrcFromCache = _combinedNpmrcMap.get(sourceNpmrcPath); + if (combinedNpmrcFromCache !== undefined) { + return combinedNpmrcFromCache; + } + let npmrcFileLines = []; + if (linesToPrepend) { + npmrcFileLines.push(...linesToPrepend); + } + if (fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath)) { + npmrcFileLines.push(...fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(sourceNpmrcPath).toString().split('\n')); + } + if (linesToAppend) { + npmrcFileLines.push(...linesToAppend); + } + npmrcFileLines = npmrcFileLines.map((line) => (line || '').trim()); + const resultLines = []; + // This finds environment variable tokens that look like "${VAR_NAME}" + const expansionRegExp = /\$\{([^\}]+)\}/g; + // Comment lines start with "#" or ";" + const commentRegExp = /^\s*[#;]/; + // Trim out lines that reference environment variables that aren't defined + for (let line of npmrcFileLines) { + let lineShouldBeTrimmed = false; + //remove spaces before or after key and value + line = line + .split('=') + .map((lineToTrim) => lineToTrim.trim()) + .join('='); + // Ignore comment lines + if (!commentRegExp.test(line)) { + const environmentVariables = line.match(expansionRegExp); + if (environmentVariables) { + for (const token of environmentVariables) { + // Remove the leading "${" and the trailing "}" from the token + const environmentVariableName = token.substring(2, token.length - 1); + // Is the environment variable defined? + if (!process.env[environmentVariableName]) { + // No, so trim this line + lineShouldBeTrimmed = true; + break; + } + } + } + } + if (lineShouldBeTrimmed) { + // Example output: + // "; MISSING ENVIRONMENT VARIABLE: //my-registry.com/npm/:_authToken=${MY_AUTH_TOKEN}" + resultLines.push('; MISSING ENVIRONMENT VARIABLE: ' + line); + } + else { + resultLines.push(line); + } + } + const combinedNpmrc = resultLines.join('\n'); + //save the cache + _combinedNpmrcMap.set(sourceNpmrcPath, combinedNpmrc); + return combinedNpmrc; +} +function _copyAndTrimNpmrcFile(options) { + const { logger, sourceNpmrcPath, targetNpmrcPath, linesToPrepend, linesToAppend } = options; + logger.info(`Transforming ${sourceNpmrcPath}`); // Verbose + logger.info(` --> "${targetNpmrcPath}"`); + const combinedNpmrc = _trimNpmrcFile({ + sourceNpmrcPath, + linesToPrepend, + linesToAppend + }); + fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(targetNpmrcPath, combinedNpmrc); + return combinedNpmrc; +} +function syncNpmrc(options) { + const { sourceNpmrcFolder, targetNpmrcFolder, useNpmrcPublish, logger = { + // eslint-disable-next-line no-console + info: console.log, + // eslint-disable-next-line no-console + error: console.error + }, createIfMissing = false, linesToAppend, linesToPrepend } = options; + const sourceNpmrcPath = path__WEBPACK_IMPORTED_MODULE_1__.join(sourceNpmrcFolder, !useNpmrcPublish ? '.npmrc' : '.npmrc-publish'); + const targetNpmrcPath = path__WEBPACK_IMPORTED_MODULE_1__.join(targetNpmrcFolder, '.npmrc'); + try { + if (fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath) || createIfMissing) { + // Ensure the target folder exists + if (!fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(targetNpmrcFolder)) { + fs__WEBPACK_IMPORTED_MODULE_0__.mkdirSync(targetNpmrcFolder, { recursive: true }); + } + return _copyAndTrimNpmrcFile({ + sourceNpmrcPath, + targetNpmrcPath, + logger, + linesToAppend, + linesToPrepend + }); + } + else if (fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(targetNpmrcPath)) { + // If the source .npmrc doesn't exist and there is one in the target, delete the one in the target + logger.info(`Deleting ${targetNpmrcPath}`); // Verbose + fs__WEBPACK_IMPORTED_MODULE_0__.unlinkSync(targetNpmrcPath); + } + } + catch (e) { + throw new Error(`Error syncing .npmrc file: ${e}`); + } +} +function isVariableSetInNpmrcFile(sourceNpmrcFolder, variableKey) { + const sourceNpmrcPath = `${sourceNpmrcFolder}/.npmrc`; + //if .npmrc file does not exist, return false directly + if (!fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath)) { + return false; + } + const trimmedNpmrcFile = _trimNpmrcFile({ sourceNpmrcPath }); + const variableKeyRegExp = new RegExp(`^${variableKey}=`, 'm'); + return trimmedNpmrcFile.match(variableKeyRegExp) !== null; +} +//# sourceMappingURL=npmrcUtilities.js.map + +/***/ }), + +/***/ 532081: +/*!********************************!*\ + !*** external "child_process" ***! + \********************************/ +/***/ ((module) => { + +module.exports = require("child_process"); + +/***/ }), + +/***/ 657147: +/*!*********************!*\ + !*** external "fs" ***! + \*********************/ +/***/ ((module) => { + +module.exports = require("fs"); + +/***/ }), + +/***/ 822037: +/*!*********************!*\ + !*** external "os" ***! + \*********************/ +/***/ ((module) => { + +module.exports = require("os"); + +/***/ }), + +/***/ 371017: +/*!***********************!*\ + !*** external "path" ***! + \***********************/ +/***/ ((module) => { + +module.exports = require("path"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/compat get default export */ +/******/ (() => { +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = (module) => { +/******/ var getter = module && module.__esModule ? +/******/ () => (module['default']) : +/******/ () => (module); +/******/ __webpack_require__.d(getter, { a: getter }); +/******/ return getter; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. +(() => { +/*!*******************************************!*\ + !*** ./lib-esnext/scripts/install-run.js ***! + \*******************************************/ +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "RUSH_JSON_FILENAME": () => (/* binding */ RUSH_JSON_FILENAME), +/* harmony export */ "findRushJsonFolder": () => (/* binding */ findRushJsonFolder), +/* harmony export */ "getNpmPath": () => (/* binding */ getNpmPath), +/* harmony export */ "installAndRun": () => (/* binding */ installAndRun), +/* harmony export */ "runWithErrorAndStatusCode": () => (/* binding */ runWithErrorAndStatusCode) +/* harmony export */ }); +/* harmony import */ var child_process__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! child_process */ 532081); +/* harmony import */ var child_process__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(child_process__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! fs */ 657147); +/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_1__); +/* harmony import */ var os__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! os */ 822037); +/* harmony import */ var os__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(os__WEBPACK_IMPORTED_MODULE_2__); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! path */ 371017); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_3__); +/* harmony import */ var _utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../utilities/npmrcUtilities */ 679877); +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. +/* eslint-disable no-console */ + + + + + +const RUSH_JSON_FILENAME = 'rush.json'; +const RUSH_TEMP_FOLDER_ENV_VARIABLE_NAME = 'RUSH_TEMP_FOLDER'; +const INSTALL_RUN_LOCKFILE_PATH_VARIABLE = 'INSTALL_RUN_LOCKFILE_PATH'; +const INSTALLED_FLAG_FILENAME = 'installed.flag'; +const NODE_MODULES_FOLDER_NAME = 'node_modules'; +const PACKAGE_JSON_FILENAME = 'package.json'; +/** + * Parse a package specifier (in the form of name\@version) into name and version parts. + */ +function _parsePackageSpecifier(rawPackageSpecifier) { + rawPackageSpecifier = (rawPackageSpecifier || '').trim(); + const separatorIndex = rawPackageSpecifier.lastIndexOf('@'); + let name; + let version = undefined; + if (separatorIndex === 0) { + // The specifier starts with a scope and doesn't have a version specified + name = rawPackageSpecifier; + } + else if (separatorIndex === -1) { + // The specifier doesn't have a version + name = rawPackageSpecifier; + } + else { + name = rawPackageSpecifier.substring(0, separatorIndex); + version = rawPackageSpecifier.substring(separatorIndex + 1); + } + if (!name) { + throw new Error(`Invalid package specifier: ${rawPackageSpecifier}`); + } + return { name, version }; +} +let _npmPath = undefined; +/** + * Get the absolute path to the npm executable + */ +function getNpmPath() { + if (!_npmPath) { + try { + if (_isWindows()) { + // We're on Windows + const whereOutput = child_process__WEBPACK_IMPORTED_MODULE_0__.execSync('where npm', { stdio: [] }).toString(); + const lines = whereOutput.split(os__WEBPACK_IMPORTED_MODULE_2__.EOL).filter((line) => !!line); + // take the last result, we are looking for a .cmd command + // see https://github.com/microsoft/rushstack/issues/759 + _npmPath = lines[lines.length - 1]; + } + else { + // We aren't on Windows - assume we're on *NIX or Darwin + _npmPath = child_process__WEBPACK_IMPORTED_MODULE_0__.execSync('command -v npm', { stdio: [] }).toString(); + } + } + catch (e) { + throw new Error(`Unable to determine the path to the NPM tool: ${e}`); + } + _npmPath = _npmPath.trim(); + if (!fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(_npmPath)) { + throw new Error('The NPM executable does not exist'); + } + } + return _npmPath; +} +function _ensureFolder(folderPath) { + if (!fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(folderPath)) { + const parentDir = path__WEBPACK_IMPORTED_MODULE_3__.dirname(folderPath); + _ensureFolder(parentDir); + fs__WEBPACK_IMPORTED_MODULE_1__.mkdirSync(folderPath); + } +} +/** + * Create missing directories under the specified base directory, and return the resolved directory. + * + * Does not support "." or ".." path segments. + * Assumes the baseFolder exists. + */ +function _ensureAndJoinPath(baseFolder, ...pathSegments) { + let joinedPath = baseFolder; + try { + for (let pathSegment of pathSegments) { + pathSegment = pathSegment.replace(/[\\\/]/g, '+'); + joinedPath = path__WEBPACK_IMPORTED_MODULE_3__.join(joinedPath, pathSegment); + if (!fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(joinedPath)) { + fs__WEBPACK_IMPORTED_MODULE_1__.mkdirSync(joinedPath); + } + } + } + catch (e) { + throw new Error(`Error building local installation folder (${path__WEBPACK_IMPORTED_MODULE_3__.join(baseFolder, ...pathSegments)}): ${e}`); + } + return joinedPath; +} +function _getRushTempFolder(rushCommonFolder) { + const rushTempFolder = process.env[RUSH_TEMP_FOLDER_ENV_VARIABLE_NAME]; + if (rushTempFolder !== undefined) { + _ensureFolder(rushTempFolder); + return rushTempFolder; + } + else { + return _ensureAndJoinPath(rushCommonFolder, 'temp'); + } +} +/** + * Compare version strings according to semantic versioning. + * Returns a positive integer if "a" is a later version than "b", + * a negative integer if "b" is later than "a", + * and 0 otherwise. + */ +function _compareVersionStrings(a, b) { + const aParts = a.split(/[.-]/); + const bParts = b.split(/[.-]/); + const numberOfParts = Math.max(aParts.length, bParts.length); + for (let i = 0; i < numberOfParts; i++) { + if (aParts[i] !== bParts[i]) { + return (Number(aParts[i]) || 0) - (Number(bParts[i]) || 0); + } + } + return 0; +} +/** + * Resolve a package specifier to a static version + */ +function _resolvePackageVersion(logger, rushCommonFolder, { name, version }) { + if (!version) { + version = '*'; // If no version is specified, use the latest version + } + if (version.match(/^[a-zA-Z0-9\-\+\.]+$/)) { + // If the version contains only characters that we recognize to be used in static version specifiers, + // pass the version through + return version; + } + else { + // version resolves to + try { + const rushTempFolder = _getRushTempFolder(rushCommonFolder); + const sourceNpmrcFolder = path__WEBPACK_IMPORTED_MODULE_3__.join(rushCommonFolder, 'config', 'rush'); + (0,_utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__.syncNpmrc)({ + sourceNpmrcFolder, + targetNpmrcFolder: rushTempFolder, + logger + }); + const npmPath = getNpmPath(); + // This returns something that looks like: + // ``` + // [ + // "3.0.0", + // "3.0.1", + // ... + // "3.0.20" + // ] + // ``` + // + // if multiple versions match the selector, or + // + // ``` + // "3.0.0" + // ``` + // + // if only a single version matches. + const spawnSyncOptions = { + cwd: rushTempFolder, + stdio: [], + shell: _isWindows() + }; + const platformNpmPath = _getPlatformPath(npmPath); + const npmVersionSpawnResult = child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync(platformNpmPath, ['view', `${name}@${version}`, 'version', '--no-update-notifier', '--json'], spawnSyncOptions); + if (npmVersionSpawnResult.status !== 0) { + throw new Error(`"npm view" returned error code ${npmVersionSpawnResult.status}`); + } + const npmViewVersionOutput = npmVersionSpawnResult.stdout.toString(); + const parsedVersionOutput = JSON.parse(npmViewVersionOutput); + const versions = Array.isArray(parsedVersionOutput) + ? parsedVersionOutput + : [parsedVersionOutput]; + let latestVersion = versions[0]; + for (let i = 1; i < versions.length; i++) { + const latestVersionCandidate = versions[i]; + if (_compareVersionStrings(latestVersionCandidate, latestVersion) > 0) { + latestVersion = latestVersionCandidate; + } + } + if (!latestVersion) { + throw new Error('No versions found for the specified version range.'); + } + return latestVersion; + } + catch (e) { + throw new Error(`Unable to resolve version ${version} of package ${name}: ${e}`); + } + } +} +let _rushJsonFolder; +/** + * Find the absolute path to the folder containing rush.json + */ +function findRushJsonFolder() { + if (!_rushJsonFolder) { + let basePath = __dirname; + let tempPath = __dirname; + do { + const testRushJsonPath = path__WEBPACK_IMPORTED_MODULE_3__.join(basePath, RUSH_JSON_FILENAME); + if (fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(testRushJsonPath)) { + _rushJsonFolder = basePath; + break; + } + else { + basePath = tempPath; + } + } while (basePath !== (tempPath = path__WEBPACK_IMPORTED_MODULE_3__.dirname(basePath))); // Exit the loop when we hit the disk root + if (!_rushJsonFolder) { + throw new Error(`Unable to find ${RUSH_JSON_FILENAME}.`); + } + } + return _rushJsonFolder; +} +/** + * Detects if the package in the specified directory is installed + */ +function _isPackageAlreadyInstalled(packageInstallFolder) { + try { + const flagFilePath = path__WEBPACK_IMPORTED_MODULE_3__.join(packageInstallFolder, INSTALLED_FLAG_FILENAME); + if (!fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(flagFilePath)) { + return false; + } + const fileContents = fs__WEBPACK_IMPORTED_MODULE_1__.readFileSync(flagFilePath).toString(); + return fileContents.trim() === process.version; + } + catch (e) { + return false; + } +} +/** + * Delete a file. Fail silently if it does not exist. + */ +function _deleteFile(file) { + try { + fs__WEBPACK_IMPORTED_MODULE_1__.unlinkSync(file); + } + catch (err) { + if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') { + throw err; + } + } +} +/** + * Removes the following files and directories under the specified folder path: + * - installed.flag + * - + * - node_modules + */ +function _cleanInstallFolder(rushTempFolder, packageInstallFolder, lockFilePath) { + try { + const flagFile = path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, INSTALLED_FLAG_FILENAME); + _deleteFile(flagFile); + const packageLockFile = path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, 'package-lock.json'); + if (lockFilePath) { + fs__WEBPACK_IMPORTED_MODULE_1__.copyFileSync(lockFilePath, packageLockFile); + } + else { + // Not running `npm ci`, so need to cleanup + _deleteFile(packageLockFile); + const nodeModulesFolder = path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME); + if (fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(nodeModulesFolder)) { + const rushRecyclerFolder = _ensureAndJoinPath(rushTempFolder, 'rush-recycler'); + fs__WEBPACK_IMPORTED_MODULE_1__.renameSync(nodeModulesFolder, path__WEBPACK_IMPORTED_MODULE_3__.join(rushRecyclerFolder, `install-run-${Date.now().toString()}`)); + } + } + } + catch (e) { + throw new Error(`Error cleaning the package install folder (${packageInstallFolder}): ${e}`); + } +} +function _createPackageJson(packageInstallFolder, name, version) { + try { + const packageJsonContents = { + name: 'ci-rush', + version: '0.0.0', + dependencies: { + [name]: version + }, + description: "DON'T WARN", + repository: "DON'T WARN", + license: 'MIT' + }; + const packageJsonPath = path__WEBPACK_IMPORTED_MODULE_3__.join(packageInstallFolder, PACKAGE_JSON_FILENAME); + fs__WEBPACK_IMPORTED_MODULE_1__.writeFileSync(packageJsonPath, JSON.stringify(packageJsonContents, undefined, 2)); + } + catch (e) { + throw new Error(`Unable to create package.json: ${e}`); + } +} +/** + * Run "npm install" in the package install folder. + */ +function _installPackage(logger, packageInstallFolder, name, version, command) { + try { + logger.info(`Installing ${name}...`); + const npmPath = getNpmPath(); + const platformNpmPath = _getPlatformPath(npmPath); + const result = child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync(platformNpmPath, [command], { + stdio: 'inherit', + cwd: packageInstallFolder, + env: process.env, + shell: _isWindows() + }); + if (result.status !== 0) { + throw new Error(`"npm ${command}" encountered an error`); + } + logger.info(`Successfully installed ${name}@${version}`); + } + catch (e) { + throw new Error(`Unable to install package: ${e}`); + } +} +/** + * Get the ".bin" path for the package. + */ +function _getBinPath(packageInstallFolder, binName) { + const binFolderPath = path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME, '.bin'); + const resolvedBinName = _isWindows() ? `${binName}.cmd` : binName; + return path__WEBPACK_IMPORTED_MODULE_3__.resolve(binFolderPath, resolvedBinName); +} +/** + * Returns a cross-platform path - windows must enclose any path containing spaces within double quotes. + */ +function _getPlatformPath(platformPath) { + return _isWindows() && platformPath.includes(' ') ? `"${platformPath}"` : platformPath; +} +function _isWindows() { + return os__WEBPACK_IMPORTED_MODULE_2__.platform() === 'win32'; +} +/** + * Write a flag file to the package's install directory, signifying that the install was successful. + */ +function _writeFlagFile(packageInstallFolder) { + try { + const flagFilePath = path__WEBPACK_IMPORTED_MODULE_3__.join(packageInstallFolder, INSTALLED_FLAG_FILENAME); + fs__WEBPACK_IMPORTED_MODULE_1__.writeFileSync(flagFilePath, process.version); + } + catch (e) { + throw new Error(`Unable to create installed.flag file in ${packageInstallFolder}`); + } +} +function installAndRun(logger, packageName, packageVersion, packageBinName, packageBinArgs, lockFilePath = process.env[INSTALL_RUN_LOCKFILE_PATH_VARIABLE]) { + const rushJsonFolder = findRushJsonFolder(); + const rushCommonFolder = path__WEBPACK_IMPORTED_MODULE_3__.join(rushJsonFolder, 'common'); + const rushTempFolder = _getRushTempFolder(rushCommonFolder); + const packageInstallFolder = _ensureAndJoinPath(rushTempFolder, 'install-run', `${packageName}@${packageVersion}`); + if (!_isPackageAlreadyInstalled(packageInstallFolder)) { + // The package isn't already installed + _cleanInstallFolder(rushTempFolder, packageInstallFolder, lockFilePath); + const sourceNpmrcFolder = path__WEBPACK_IMPORTED_MODULE_3__.join(rushCommonFolder, 'config', 'rush'); + (0,_utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__.syncNpmrc)({ + sourceNpmrcFolder, + targetNpmrcFolder: packageInstallFolder, + logger + }); + _createPackageJson(packageInstallFolder, packageName, packageVersion); + const command = lockFilePath ? 'ci' : 'install'; + _installPackage(logger, packageInstallFolder, packageName, packageVersion, command); + _writeFlagFile(packageInstallFolder); + } + const statusMessage = `Invoking "${packageBinName} ${packageBinArgs.join(' ')}"`; + const statusMessageLine = new Array(statusMessage.length + 1).join('-'); + logger.info('\n' + statusMessage + '\n' + statusMessageLine + '\n'); + const binPath = _getBinPath(packageInstallFolder, packageBinName); + const binFolderPath = path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME, '.bin'); + // Windows environment variables are case-insensitive. Instead of using SpawnSyncOptions.env, we need to + // assign via the process.env proxy to ensure that we append to the right PATH key. + const originalEnvPath = process.env.PATH || ''; + let result; + try { + // `npm` bin stubs on Windows are `.cmd` files + // Node.js will not directly invoke a `.cmd` file unless `shell` is set to `true` + const platformBinPath = _getPlatformPath(binPath); + process.env.PATH = [binFolderPath, originalEnvPath].join(path__WEBPACK_IMPORTED_MODULE_3__.delimiter); + result = child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync(platformBinPath, packageBinArgs, { + stdio: 'inherit', + windowsVerbatimArguments: false, + shell: _isWindows(), + cwd: process.cwd(), + env: process.env + }); + } + finally { + process.env.PATH = originalEnvPath; + } + if (result.status !== null) { + return result.status; + } + else { + throw result.error || new Error('An unknown error occurred.'); + } +} +function runWithErrorAndStatusCode(logger, fn) { + process.exitCode = 1; + try { + const exitCode = fn(); + process.exitCode = exitCode; + } + catch (e) { + logger.error('\n\n' + e.toString() + '\n\n'); + } +} +function _run() { + const [nodePath /* Ex: /bin/node */, scriptPath /* /repo/common/scripts/install-run-rush.js */, rawPackageSpecifier /* qrcode@^1.2.0 */, packageBinName /* qrcode */, ...packageBinArgs /* [-f, myproject/lib] */] = process.argv; + if (!nodePath) { + throw new Error('Unexpected exception: could not detect node path'); + } + if (path__WEBPACK_IMPORTED_MODULE_3__.basename(scriptPath).toLowerCase() !== 'install-run.js') { + // If install-run.js wasn't directly invoked, don't execute the rest of this function. Return control + // to the script that (presumably) imported this file + return; + } + if (process.argv.length < 4) { + console.log('Usage: install-run.js @ [args...]'); + console.log('Example: install-run.js qrcode@1.2.2 qrcode https://rushjs.io'); + process.exit(1); + } + const logger = { info: console.log, error: console.error }; + runWithErrorAndStatusCode(logger, () => { + const rushJsonFolder = findRushJsonFolder(); + const rushCommonFolder = _ensureAndJoinPath(rushJsonFolder, 'common'); + const packageSpecifier = _parsePackageSpecifier(rawPackageSpecifier); + const name = packageSpecifier.name; + const version = _resolvePackageVersion(logger, rushCommonFolder, packageSpecifier); + if (packageSpecifier.version !== version) { + console.log(`Resolved to ${name}@${version}`); + } + return installAndRun(logger, name, version, packageBinName, packageBinArgs); + }); +} +_run(); +//# sourceMappingURL=install-run.js.map +})(); + +module.exports = __webpack_exports__; +/******/ })() +; +//# sourceMappingURL=install-run.js.map \ No newline at end of file diff --git a/core/.dockerignore b/core/.dockerignore deleted file mode 100644 index 93f136199..000000000 --- a/core/.dockerignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -npm-debug.log diff --git a/core/.gitignore b/core/.gitignore deleted file mode 100644 index 9190bf466..000000000 --- a/core/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -index.js -lib/*.js -lib/*.js.map -.tscache diff --git a/core/.npmignore b/core/.npmignore deleted file mode 100644 index 8f33598ed..000000000 --- a/core/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -tests/ -Gruntfile.js diff --git a/core/Dockerfile b/core/Dockerfile deleted file mode 100644 index d173194ba..000000000 --- a/core/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM node:8.12.0-alpine - -RUN npm install -g grunt-cli - -WORKDIR /usr/src/app - -COPY package*.json ./ -RUN npm install - -COPY . . diff --git a/core/Gruntfile.js b/core/Gruntfile.js deleted file mode 100644 index 497955d15..000000000 --- a/core/Gruntfile.js +++ /dev/null @@ -1,58 +0,0 @@ -/* -* JavaScript tracker core for Snowplow: Gruntfile.js -* - * Copyright (c) 2014-2016 Snowplow Analytics Ltd. All rights reserved. - * - * This program is licensed to you under the Apache License Version 2.0, - * and you may not use this file except in compliance with the Apache License Version 2.0. - * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the Apache License Version 2.0 is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. - */ - -/*global module:false*/ -module.exports = function (grunt) { - - grunt.initConfig({ - - ts: { - default: { - tsconfig: true - } - }, - - dtsGenerator: { - default: { - options: { - name: 'snowplow-tracker', - project: '.', - out: 'main.d.ts' - } - } - }, - - intern: { - unit: { - options: { - runType: 'client', - config: 'tests/intern.js', - suites: [ - 'tests/unit/base64.js', - 'tests/unit/payload.js', - 'tests/unit/core.js', - 'tests/unit/contexts.js' - ] - } - } - } - }); - - grunt.loadNpmTasks('intern'); - grunt.loadNpmTasks('grunt-ts'); - grunt.loadNpmTasks('dts-generator'); - - grunt.registerTask('default', 'Compile and test', ['ts', 'dtsGenerator', 'intern']); -}; diff --git a/core/README.md b/core/README.md deleted file mode 100644 index 944458d88..000000000 --- a/core/README.md +++ /dev/null @@ -1,134 +0,0 @@ -# Snowplow JavaScript Tracker Core [![npm version][npm-image]][npm-url] - -Core module to be used by all Snowplow JavaScript trackers. - -## Installation - -With npm: - -```bash -npm install snowplow-tracker-core -``` - -## Example - -```js -var core = require('snowplow-tracker-core').trackerCore; - -// Create an instance with base 64 encoding set to false (it defaults to true) -var coreInstance = core(false); - -// Add a name-value pair to all payloads -coreInstance.addPayloadPair('vid', 2); - -// Add each name-value pair in a dictionary to all payloads -coreInstance.addPayloadDict({ - 'ds': '1160x620', - 'fp': 4070134789 -}); - -// Add name-value pairs to all payloads using convenience methods -coreInstance.setTrackerVersion('js-3.0.0'); -coreInstance.setPlatform('web'); -coreInstance.setUserId('user-321'); -coreInstance.setColorDepth(24); -coreInstance.setViewport(600, 400); -coreInstance.setUseragent('Snowplow/0.0.1'); - -// Track a page view with URL and title -var pageViewPayload = coreInstance.trackPageView('http://www.example.com', 'landing page'); - -console.log(pageViewPayload.build()); -/* -{ - 'e': 'pv', - 'url': 'http://www.example.com', - 'page': 'landing page', - 'uid': 'user-321', - 'vd': 2, - 'ds': '1160x620', - 'fp': 4070134789 - 'tv': 'js-3.0.0', - 'p': 'web', - 'cd': 24, - 'vp': '600x400', - 'ua': 'Snowplow/0.0.1', - 'dtm': 1406879959702, // timestamp - 'eid': '0718a85a-45dc-4f71-a949-27870442ed7d' // UUID -} -*/ - -// Stop automatically adding tv, p, and dtm to the payload -coreInstance.resetPayloadPairs(); - -// Track an unstructured event -var unstructEventPayload = coreInstance.trackUnstructEvent({ - 'schema': 'iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-0', - 'data': { - 'targetUrl': 'http://www.destination.com', - 'elementId': 'bannerLink' - } -}); - -console.log(unstructEventPayload.build()); -/* -{ - 'e': 'ue', - 'ue_pr': { - 'schema': 'iglu:com.snowplowanalytics.snowplow/unstruct_even/jsonschema/1-0-0', - 'data': { - 'schema': 'iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-0', - 'data': { - 'targetUrl': 'http://www.destination.com', - 'elementId': 'bannerLink' - } - } - }, - 'dtm': 1406879973439, - 'eid': '956c6670-cbf6-460b-9f96-143e0320fdf6' -} -*/ -``` - -## Other features - -Core instances can be initialized with two parameters. The first is a boolean and determines whether custom contexts and unstructured events will be base 64 encoded. The second is an optional callback function which gets applied to every payload created by the instance. - -```js -var coreInstance = core(true, console.log); -``` - -The above example would base 64 encode all unstructured events and custom contexts and would log each payload to the console. - -Use the `setBase64Encoding` method to turn base 64 encoding on or off after initializing a core instance: - -```js -var core = require('snowplow-tracker-core'); - -var coreInstance = core(); // Base 64 encoding on by default - -coreInstance.setBase64Encoding(false); // Base 64 encoding is now off -``` - -## Documentation - -For more information on the Snowplow JavaScript Tracker Core's API, view its [wiki page][wiki]. - -## Copyright and license - -The Snowplow JavaScript Tracker Core is copyright 2014 Snowplow Analytics Ltd. - -Licensed under the [Apache License, Version 2.0][apache-license] (the "License"); -you may not use this software except in compliance with the License. - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -[apache-license]: http://www.apache.org/licenses/LICENSE-2.0 - -[npm-url]: http://badge.fury.io/js/snowplow-tracker-core -[npm-image]: https://badge.fury.io/js/snowplow-tracker-core.svg -[wiki]: https://github.com/snowplow/snowplow/wiki/Javascript-Tracker-Core diff --git a/core/index.ts b/core/index.ts deleted file mode 100644 index 56cc0e8bf..000000000 --- a/core/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * JavaScript tracker core for Snowplow: index.js - * - * Copyright (c) 2014-2016 Snowplow Analytics Ltd. All rights reserved. - * - * This program is licensed to you under the Apache License Version 2.0, - * and you may not use this file except in compliance with the Apache License Version 2.0. - * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the Apache License Version 2.0 is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. - */ - -export {trackerCore} from "./lib/core"; diff --git a/core/lib/base64.ts b/core/lib/base64.ts deleted file mode 100644 index 53ade4341..000000000 --- a/core/lib/base64.ts +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (c) 2013 Kevin van Zonneveld (http://kvz.io) - * and Contributors (http://phpjs.org/authors) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do - * so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -// Deprecated and removed in TypeScript -declare function unescape(s: string): string; - -export function base64urldecode(data: string): string { - if (!data) { - return data; - } - var padding = 4 - data.length % 4; - switch (padding) { - case 2: - data += "=="; - break; - case 3: - data += "="; - break; - } - var b64Data = data.replace(/-/g, '+').replace(/_/g, '/'); - return base64decode(b64Data); -} - -/** - * Encode string as base64. - * Any type can be passed, but will be stringified - * - * @param data string to encode - * @returns base64-encoded string - */ -export function base64encode(data: string): string { - // discuss at: http://phpjs.org/functions/base64_encode/ - // original by: Tyler Akins (http://rumkin.com) - // improved by: Bayron Guevara - // improved by: Thunder.m - // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) - // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) - // improved by: Rafał Kukawski (http://kukawski.pl) - // bugfixed by: Pellentesque Malesuada - // example 1: base64_encode('Kevin van Zonneveld'); - // returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA==' - // example 2: base64_encode('a'); - // returns 2: 'YQ==' - // example 3: base64_encode('✓ à la mode'); - // returns 3: '4pyTIMOgIGxhIG1vZGU=' - - var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; - var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, - ac = 0, - enc: string, - tmp_arr: Array = []; - - if (!data) { - return data; - } - - data = unescape(encodeURIComponent(data)); - - do { - // pack three octets into four hexets - o1 = data.charCodeAt(i++); - o2 = data.charCodeAt(i++); - o3 = data.charCodeAt(i++); - - bits = o1 << 16 | o2 << 8 | o3; - - h1 = bits >> 18 & 0x3f; - h2 = bits >> 12 & 0x3f; - h3 = bits >> 6 & 0x3f; - h4 = bits & 0x3f; - - // use hexets to index into b64, and append result to encoded string - tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4); - } while (i < data.length); - - enc = tmp_arr.join(''); - - var r = data.length % 3; - - return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3); -} - -export function base64decode(encodedData:string): string { - // discuss at: http://locutus.io/php/base64_decode/ - // original by: Tyler Akins (http://rumkin.com) - // improved by: Thunder.m - // improved by: Kevin van Zonneveld (http://kvz.io) - // improved by: Kevin van Zonneveld (http://kvz.io) - // input by: Aman Gupta - // input by: Brett Zamir (http://brett-zamir.me) - // bugfixed by: Onno Marsman (https://twitter.com/onnomarsman) - // bugfixed by: Pellentesque Malesuada - // bugfixed by: Kevin van Zonneveld (http://kvz.io) - // improved by: Indigo744 - // example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==') - // returns 1: 'Kevin van Zonneveld' - // example 2: base64_decode('YQ==') - // returns 2: 'a' - // example 3: base64_decode('4pyTIMOgIGxhIG1vZGU=') - // returns 3: '✓ à la mode' - - // decodeUTF8string() - // Internal function to decode properly UTF8 string - // Adapted from Solution #1 at https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding - var decodeUTF8string = function (str) { - // Going backwards: from bytestream, to percent-encoding, to original string. - return decodeURIComponent(str.split('').map(function (c) { - return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2) - }).join('')) - }; - - var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; - var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, - ac = 0, - dec = '', - tmpArr: Array = []; - - if (!encodedData) { - return encodedData; - } - - encodedData += ''; - - do { - // unpack four hexets into three octets using index points in b64 - h1 = b64.indexOf(encodedData.charAt(i++)); - h2 = b64.indexOf(encodedData.charAt(i++)); - h3 = b64.indexOf(encodedData.charAt(i++)); - h4 = b64.indexOf(encodedData.charAt(i++)); - - bits = h1 << 18 | h2 << 12 | h3 << 6 | h4; - - o1 = bits >> 16 & 0xff; - o2 = bits >> 8 & 0xff; - o3 = bits & 0xff; - - if (h3 === 64) { - tmpArr[ac++] = String.fromCharCode(o1); - } else if (h4 === 64) { - tmpArr[ac++] = String.fromCharCode(o1, o2); - } else { - tmpArr[ac++] = String.fromCharCode(o1, o2, o3); - } - } while (i < encodedData.length); - - dec = tmpArr.join(''); - - return decodeUTF8string(dec.replace(/\0+$/, '')); -} - diff --git a/core/lib/contexts.ts b/core/lib/contexts.ts deleted file mode 100644 index 90ea1595a..000000000 --- a/core/lib/contexts.ts +++ /dev/null @@ -1,492 +0,0 @@ -/* - * JavaScript tracker core for Snowplow: contexts.js - * - * Copyright (c) 2014-2018 Snowplow Analytics Ltd. All rights reserved. - * - * This program is licensed to you under the Apache License Version 2.0, - * and you may not use this file except in compliance with the Apache License Version 2.0. - * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the Apache License Version 2.0 is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. - */ - -import { PayloadData, isNonEmptyJson } from "./payload"; -import { SelfDescribingJson } from "./core"; -import { base64urldecode } from "./base64"; -import isEqual = require('lodash/isEqual'); -import has = require('lodash/has'); -import get = require('lodash/get'); -import isPlainObject = require('lodash/isPlainObject'); -import every = require('lodash/every'); -import compact = require('lodash/compact'); -import map = require('lodash/map'); - -/** - * Datatypes (some algebraic) for representing context types - */ - -/** - * A context generator is a callback that returns a self-describing JSON - * @param {Object} args - Object that contains: event, eventType, eventSchema - * @return {SelfDescribingJson} A self-describing JSON - */ -export type ContextGenerator = (args?: Object) => SelfDescribingJson; - -/** - * A context primitive is either a self-describing JSON or a context generator - */ -export type ContextPrimitive = SelfDescribingJson | ContextGenerator; - -/** - * A context filter is a user-supplied callback that is evaluated for each event - * to determine if the context associated with the filter should be attached to the event - */ -export type ContextFilter = (args?: Object) => boolean; - -/** - * A filter provider is an array that has two parts: a context filter and context primitives - * If the context filter evaluates to true, the tracker will attach the context primitive(s) - */ -export type FilterProvider = [ContextFilter, Array | ContextPrimitive]; - -/** - * A ruleset has accept or reject properties that contain rules for matching Iglu schema URIs - */ -export interface RuleSet { - accept?: string[] | string; - reject?: string[] | string; -} - -/** - * A ruleset provider is an array that has two parts: a ruleset and context primitives - * If the ruleset allows the current event schema URI, the tracker will attach the context primitive(s) - */ -export type RuleSetProvider = [RuleSet, Array | ContextPrimitive]; - -/** - * Conditional context providers are two element arrays used to decide when to attach contexts, where: - * - the first element is some conditional criterion - * - the second element is any number of context primitives - */ -export type ConditionalContextProvider = FilterProvider | RuleSetProvider; - -export function getSchemaParts(input: string): Array | undefined { - let re = new RegExp('^iglu:([a-zA-Z0-9-_\.]+)\/([a-zA-Z0-9-_]+)\/jsonschema\/([1-9][0-9]*)\-(0|[1-9][0-9]*)\-(0|[1-9][0-9]*)$'); - let matches = re.exec(input); - if (matches !== null) - return matches.slice(1, 6); - return undefined; -} - -export function validateVendorParts(parts: Array): boolean { - if (parts[0] === '*' || parts[1] === '*') { - return false; // no wildcard in first or second part - } - if (parts.slice(2).length > 0) { - let asterisk = false; - for (let part of parts.slice(2)) { - if (part === '*') // mark when we've found a wildcard - asterisk = true; - else if (asterisk) // invalid if alpha parts come after wildcard - return false; - } - return true; - } else if (parts.length == 2) - return true; - - return false; -} - -export function validateVendor(input: string): boolean { - let parts = input.split('.'); - if (parts && parts.length > 1) - return validateVendorParts(parts); - return false; -} - -export function getRuleParts(input: string): Array | undefined { - const re = new RegExp('^iglu:((?:(?:[a-zA-Z0-9-_]+|\\*)\.)+(?:[a-zA-Z0-9-_]+|\\*))\/([a-zA-Z0-9-_.]+|\\*)\/jsonschema\/([1-9][0-9]*|\\*)-(0|[1-9][0-9]*|\\*)-(0|[1-9][0-9]*|\\*)$'); - let matches = re.exec(input); - if (matches !== null && validateVendor(matches[1])) - return matches.slice(1,6); - return undefined; -} - -export function isValidRule(input: string): boolean { - let ruleParts = getRuleParts(input); - if (ruleParts) { - let vendor = ruleParts[0]; - return ruleParts.length === 5 && validateVendor(vendor); - } - return false; -} - -export function isStringArray(input: any): boolean { - return Array.isArray(input) && input.every((x) => { return typeof x === 'string' }); -} - -export function isValidRuleSetArg(input: any): boolean { - if (isStringArray(input)) - return input.every((x) => { return isValidRule(x) }); - else if (typeof input === 'string') - return isValidRule(input); - return false; -} - -export function isSelfDescribingJson(input: any) : boolean { - if (isNonEmptyJson(input)) - if ('schema' in input && 'data' in input) - return (typeof(input.schema) === 'string' && typeof(input.data) === 'object'); - return false; -} - -export function isEventJson(input: any) : boolean { - if (isNonEmptyJson(input) && ('e' in input)) - return (typeof(input.e) === 'string'); - return false; -} - -export function isRuleSet(input: any) : boolean { - let ruleCount = 0; - if (isPlainObject(input)) { - if (has(input, 'accept')) { - if (isValidRuleSetArg(input['accept'])) { - ruleCount += 1; - } else { - return false; - } - } - if (has(input, 'reject')) { - if (isValidRuleSetArg(input['reject'])) { - ruleCount += 1; - } else { - return false; - } - } - // if either 'reject' or 'accept' or both exists, - // we have a valid ruleset - return ruleCount > 0 && ruleCount <= 2; - } - return false; -} - -export function isContextGenerator(input: any) : boolean { - return typeof(input) === 'function' && input.length <= 1; -} - -export function isContextFilter(input: any) : boolean { - return typeof(input) === 'function' && input.length <= 1; -} - -export function isContextPrimitive(input: any) : boolean { - return (isContextGenerator(input) || isSelfDescribingJson(input)); -} - -export function isFilterProvider(input: any) : boolean { - if (Array.isArray(input)) { - if (input.length === 2) { - if (Array.isArray(input[1])) { - return isContextFilter(input[0]) && every(input[1], isContextPrimitive); - } - return isContextFilter(input[0]) && isContextPrimitive(input[1]); - } - } - return false; -} - -export function isRuleSetProvider(input: any) : boolean { - if (Array.isArray(input) && input.length === 2) { - if (!isRuleSet(input[0])) - return false; - if (Array.isArray(input[1])) - return every(input[1], isContextPrimitive); - return isContextPrimitive(input[1]); - } - return false; -} - -export function isConditionalContextProvider(input: any) : boolean { - return isFilterProvider(input) || isRuleSetProvider(input); -} - -export function matchSchemaAgainstRule(rule: string, schema: string) : boolean { - if (!isValidRule(rule)) - return false; - let ruleParts = getRuleParts(rule); - let schemaParts = getSchemaParts(schema); - if (ruleParts && schemaParts) { - if (!matchVendor(ruleParts[0], schemaParts[0])) - return false; - for (let i=1; i<5; i++) { - if (!matchPart(ruleParts[i], schemaParts[i])) - return false; - } - return true; // if it hasn't failed, it passes - } - return false; -} - -export function matchVendor(rule: string, vendor: string): boolean { - // rule and vendor must have same number of elements - let vendorParts = vendor.split('.'); - let ruleParts = rule.split('.'); - if (vendorParts && ruleParts) { - if (vendorParts.length !== ruleParts.length) - return false; - for (let i=0; i).some((rule) => (matchSchemaAgainstRule(rule, schema)))) { - acceptCount++; - } - } else if (typeof(acceptRules) === 'string') { - if (matchSchemaAgainstRule(acceptRules, schema)) { - acceptCount++; - } - } - - let rejectRules = get(ruleSet, 'reject'); - if (Array.isArray(rejectRules)) { - if ((ruleSet.reject as Array).some((rule) => (matchSchemaAgainstRule(rule, schema)))) { - rejectCount++; - } - } else if (typeof(rejectRules) === 'string') { - if (matchSchemaAgainstRule(rejectRules, schema)) { - rejectCount++; - } - } - - if (acceptCount > 0 && rejectCount === 0) { - return true; - } else if (acceptCount === 0 && rejectCount > 0) { - return false; - } - - return false; -} - -// Returns the "useful" schema, i.e. what would someone want to use to identify events. -// The idea being that you can determine the event type from 'e', so getting the schema from -// 'ue_px.schema'/'ue_pr.schema' would be redundant - it'll return the unstructured event schema. -// Instead the schema nested inside the unstructured event is more useful! -// This doesn't decode ue_px, it works because it's called by code that has already decoded it -export function getUsefulSchema(sb: SelfDescribingJson): string { - if (typeof get(sb, 'ue_px.data.schema') === 'string') - return get(sb, 'ue_px.data.schema'); - else if (typeof get(sb, 'ue_pr.data.schema') === 'string') - return get(sb, 'ue_pr.data.schema'); - else if (typeof get(sb, 'schema') === 'string') - return get(sb, 'schema'); - return ''; -} - -export function getDecodedEvent(sb: SelfDescribingJson): SelfDescribingJson { - let decodedEvent = {...sb}; // spread operator, instantiates new object - try { - if (has(decodedEvent, 'ue_px')) { - decodedEvent['ue_px'] = JSON.parse(base64urldecode(get(decodedEvent, ['ue_px']))); - } - } catch(e) {} - return decodedEvent; -} - -export function getEventType(sb: {}): string { - return get(sb, 'e', ''); -} - -export function buildGenerator(generator: ContextGenerator, - event: SelfDescribingJson, - eventType: string, - eventSchema: string) : SelfDescribingJson | Array | undefined { - let contextGeneratorResult : SelfDescribingJson | Array | undefined = undefined; - try { - // try to evaluate context generator - let args = { - event: event, - eventType: eventType, - eventSchema: eventSchema - }; - contextGeneratorResult = generator(args); - // determine if the produced result is a valid SDJ - if (isSelfDescribingJson(contextGeneratorResult)) { - return contextGeneratorResult; - } else if (Array.isArray(contextGeneratorResult) && every(contextGeneratorResult, isSelfDescribingJson)) { - return contextGeneratorResult; - } else { - return undefined; - } - } catch (error) { - contextGeneratorResult = undefined; - } - return contextGeneratorResult; -} - -export function normalizeToArray(input: any) : Array { - if (Array.isArray(input)) { - return input; - } - return Array.of(input); -} - -export function generatePrimitives(contextPrimitives: Array | ContextPrimitive, - event: SelfDescribingJson, - eventType: string, - eventSchema: string) : Array { - let normalizedInputs : Array = normalizeToArray(contextPrimitives); - let partialEvaluate = (primitive) => { - let result = evaluatePrimitive(primitive, event, eventType, eventSchema); - if (result && result.length !== 0) { - return result; - } - }; - let generatedContexts = map(normalizedInputs, partialEvaluate); - return [].concat(...compact(generatedContexts)); -} - -export function evaluatePrimitive(contextPrimitive: ContextPrimitive, - event: SelfDescribingJson, - eventType: string, - eventSchema: string) : Array | undefined { - if (isSelfDescribingJson(contextPrimitive)) { - return [contextPrimitive as SelfDescribingJson]; - } else if (isContextGenerator(contextPrimitive)) { - let generatorOutput = buildGenerator(contextPrimitive as ContextGenerator, event, eventType, eventSchema); - if (isSelfDescribingJson(generatorOutput)) { - return [generatorOutput as SelfDescribingJson]; - } else if (Array.isArray(generatorOutput)) { - return generatorOutput; - } - } - return undefined; -} - -export function evaluateProvider(provider: ConditionalContextProvider, - event: SelfDescribingJson, - eventType: string, - eventSchema: string): Array { - if (isFilterProvider(provider)) { - let filter : ContextFilter = (provider as FilterProvider)[0]; - let filterResult = false; - try { - let args = { - event: event, - eventType: eventType, - eventSchema: eventSchema - }; - filterResult = filter(args); - } catch(error) { - filterResult = false; - } - if (filterResult === true) { - return generatePrimitives((provider as FilterProvider)[1], event, eventType, eventSchema); - } - } else if (isRuleSetProvider(provider)) { - if (matchSchemaAgainstRuleSet((provider as RuleSetProvider)[0], eventSchema)) { - return generatePrimitives((provider as RuleSetProvider)[1], event, eventType, eventSchema); - } - } - return []; -} - -export function generateConditionals(providers: Array | ConditionalContextProvider, - event: SelfDescribingJson, - eventType: string, - eventSchema: string) : Array { - let normalizedInput : Array = normalizeToArray(providers); - let partialEvaluate = (provider) => { - let result = evaluateProvider(provider, event, eventType, eventSchema); - if (result && result.length !== 0) { - return result; - } - }; - let generatedContexts = map(normalizedInput, partialEvaluate); - return [].concat(...compact(generatedContexts)); -} - -export function contextModule() { - let globalPrimitives : Array = []; - let conditionalProviders : Array = []; - - function assembleAllContexts(event: SelfDescribingJson) : Array { - let eventSchema = getUsefulSchema(event); - let eventType = getEventType(event); - let contexts : Array = []; - let generatedPrimitives = generatePrimitives(globalPrimitives, event, eventType, eventSchema); - contexts.push(...generatedPrimitives); - - let generatedConditionals = generateConditionals(conditionalProviders, event, eventType, eventSchema); - contexts.push(...generatedConditionals); - - return contexts; - } - - return { - getGlobalPrimitives: function () { - return globalPrimitives; - }, - - getConditionalProviders: function () { - return conditionalProviders; - }, - - addGlobalContexts: function (contexts: Array) { - let acceptedConditionalContexts : ConditionalContextProvider[] = []; - let acceptedContextPrimitives : ContextPrimitive[] = []; - for (let context of contexts) { - if (isConditionalContextProvider(context)) { - acceptedConditionalContexts.push(context); - } else if (isContextPrimitive(context)) { - acceptedContextPrimitives.push(context); - } - } - globalPrimitives = globalPrimitives.concat(acceptedContextPrimitives); - conditionalProviders = conditionalProviders.concat(acceptedConditionalContexts); - }, - - clearGlobalContexts: function () { - conditionalProviders = []; - globalPrimitives = []; - }, - - removeGlobalContexts: function (contexts: Array) { - for (let context of contexts) { - if (isConditionalContextProvider(context)) { - conditionalProviders = conditionalProviders.filter(item => !isEqual(item, context)); - } else if (isContextPrimitive(context)) { - globalPrimitives = globalPrimitives.filter(item => !isEqual(item, context)); - } else { - // error message here? - } - } - }, - - getApplicableContexts: function (event: PayloadData) : Array { - const builtEvent = event.build(); - if (isEventJson(builtEvent)) { - const decodedEvent = getDecodedEvent(builtEvent as SelfDescribingJson); - return assembleAllContexts(decodedEvent); - } else { - return []; - } - } - }; -} diff --git a/core/lib/core.ts b/core/lib/core.ts deleted file mode 100644 index 5c248ce62..000000000 --- a/core/lib/core.ts +++ /dev/null @@ -1,1018 +0,0 @@ -/* - * JavaScript tracker core for Snowplow: core.js - * - * Copyright (c) 2014-2016 Snowplow Analytics Ltd. All rights reserved. - * - * This program is licensed to you under the Apache License Version 2.0, - * and you may not use this file except in compliance with the Apache License Version 2.0. - * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the Apache License Version 2.0 is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. - */ - -import uuid = require('uuid'); - -import * as payload from './payload'; -import {PayloadData} from "./payload"; -import { - contextModule as contextConstructor -} from "./contexts"; - -/** - * Interface common for any Self-Describing JSON such as custom context or - * Self-describing (ex-unstuctured) event - */ -export interface SelfDescribingJson extends Object { - schema: string - data: Object -} - -/** - * Algebraic datatype representing possible timestamp type choice - */ -export type Timestamp = TrueTimestamp | DeviceTimestamp | number; -export interface TrueTimestamp { readonly type: "ttm"; readonly value: number } -export interface DeviceTimestamp { readonly type: "dtm"; readonly value: number } - -/** - * Pair of timestamp type ready to be included to payload - */ -type TimestampPayload = TrueTimestamp | DeviceTimestamp - -/** - * Transform optional/old-behavior number timestamp into - * `TrackerTimestamp` ADT - * - * @param tstamp optional number or correct timestamp object - * @returns {Timestamp} correct timestamp object - */ -function getTimestamp(tstamp?: Timestamp): TimestampPayload { - if (tstamp == null) { - return {type: 'dtm', value: new Date().getTime() } - } else if (typeof tstamp === 'number') { - return { type: 'dtm', value: tstamp } - } else if (tstamp.type === 'ttm') { // We can return tstamp here, but this is safer fallback - return { type: 'ttm', value: tstamp.value } - } else { - return { type: 'dtm', value: (tstamp.value || new Date().getTime()) } - } -} - -/** - * Create a tracker core object - * - * @param base64 Whether to base 64 encode contexts and unstructured event JSONs - * @param callback Function applied to every payload dictionary object - * @return Tracker core - */ -export function trackerCore(base64: boolean, callback?: (PayloadData) => void) { - - // base 64 encoding should default to true - if (typeof base64 === 'undefined') { - base64 = true; - } - - // Dictionary of key-value pairs which get added to every payload, e.g. tracker version - var payloadPairs = {}; - - let contextModule = contextConstructor(); - - /** - * Gets all global contexts to be added to events - * - * @param event - */ - function getAllContexts(event: PayloadData) : Array { - return contextModule.getApplicableContexts(event); - } - - /** - * Set a persistent key-value pair to be added to every payload - * - * @param key Field name - * @param value Field value - */ - function addPayloadPair(key: string, value: string) { - payloadPairs[key] = value; - } - - /** - * Returns a copy of a JSON with undefined and null properties removed - * - * @param eventJson JSON object to clean - * @param exemptFields Set of fields which should not be removed even if empty - * @return A cleaned copy of eventJson - */ - function removeEmptyProperties(eventJson: Object, exemptFields?: Object) { - var ret = {}; - exemptFields = exemptFields || {}; - for (var k in eventJson) { - if (exemptFields[k] || (eventJson[k] !== null && typeof eventJson[k] !== 'undefined')) { - ret[k] = eventJson[k]; - } - } - return ret; - } - - /** - * Wraps an array of custom contexts in a self-describing JSON - * - * @param contexts Array of custom context self-describing JSONs - * @return Outer JSON - */ - function completeContexts(contexts?: Array): Object | undefined { // TODO: can return nothing - if (contexts && contexts.length) { - return { - schema: 'iglu:com.snowplowanalytics.snowplow/contexts/jsonschema/1-0-0', - data: contexts - }; - } - } - - /** - * Adds all global contexts to a contexts array - * - * @param sb PayloadData - * @param contexts Array - */ - function attachGlobalContexts(sb: PayloadData, - contexts?: Array): Array { - let globalContexts : Array = getAllContexts(sb); - let returnedContexts : Array = []; - if (contexts && contexts.length) { - returnedContexts.push(...contexts); - } - if (globalContexts && globalContexts.length) { - returnedContexts.push(...globalContexts); - } - return returnedContexts; - } - - /** - * Gets called by every trackXXX method - * Adds context and payloadPairs name-value pairs to the payload - * Applies the callback to the built payload - * - * @param sb Payload - * @param context Custom contexts relating to the event - * @param tstamp TrackerTimestamp of the event - * @return Payload after the callback is applied - */ - function track(sb: PayloadData, context?: Array, tstamp?: Timestamp): PayloadData { - sb.addDict(payloadPairs); - sb.add('eid', uuid.v4()); - var timestamp = getTimestamp(tstamp); - sb.add(timestamp.type, timestamp.value.toString()); - var allContexts = attachGlobalContexts(sb, context); - var wrappedContexts = completeContexts(allContexts); - if (wrappedContexts !== undefined) { - sb.addJson('cx', 'co', wrappedContexts); - } - - if (typeof callback === 'function') { - callback(sb); - } - - return sb; - } - - /** - * Log an self-describing (previously unstruct) event - * - * @param properties Contains the properties and schema location for the event - * @param context Custom contexts relating to the event - * @param tstamp TrackerTimestamp of the event - * @return Payload - */ - function trackSelfDescribingEvent(properties: Object, context?: Array, tstamp?: Timestamp): PayloadData { - var sb = payload.payloadBuilder(base64); - var ueJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/unstruct_event/jsonschema/1-0-0', - data: properties - }; - - sb.add('e', 'ue'); - sb.addJson('ue_px', 'ue_pr', ueJson); - - return track(sb, context, tstamp); - } - - return { - - /** - * Turn base 64 encoding on or off - * - * @param encode Whether to encode payload - */ - setBase64Encoding: function (encode: boolean) { - base64 = encode; - }, - - addPayloadPair: addPayloadPair, - - /** - * Merges a dictionary into payloadPairs - * - * @param dict Dictionary to add - */ - addPayloadDict: function (dict: Object) { - for (var key in dict) { - if (dict.hasOwnProperty(key)) { - payloadPairs[key] = dict[key]; - } - } - }, - - /** - * Replace payloadPairs with a new dictionary - * - * @param dict object New dictionary - */ - resetPayloadPairs: function (dict: Object) { - payloadPairs = payload.isJson(dict) ? dict : {}; - }, - - /** - * Set the tracker version - * - * @param version string - */ - setTrackerVersion: function (version: string) { - addPayloadPair('tv', version); - }, - - /** - * Set the tracker namespace - * - * @param name string - */ - setTrackerNamespace: function (name: string) { - addPayloadPair('tna', name); - }, - - /** - * Set the application ID - * - * @param appId string - */ - setAppId: function (appId: string) { - addPayloadPair('aid', appId); - }, - - /** - * Set the platform - * - * @param value string - */ - setPlatform: function (value: string) { - addPayloadPair('p', value); - }, - - /** - * Set the user ID - * - * @param userId string - */ - setUserId: function (userId: string) { - addPayloadPair('uid', userId); - }, - - /** - * Set the screen resolution - * - * @param width number - * @param height number - */ - setScreenResolution: function (width: string, height: string) { - addPayloadPair('res', width + 'x' + height); - }, - - /** - * Set the viewport dimensions - * - * @param width number - * @param height number - */ - setViewport: function (width: string, height: string) { - addPayloadPair('vp', width + 'x' + height); - }, - - /** - * Set the color depth - * - * @param depth number - */ - setColorDepth: function (depth: string) { - addPayloadPair('cd', depth); - }, - - /** - * Set the timezone - * - * @param timezone string - */ - setTimezone: function (timezone: string) { - addPayloadPair('tz', timezone); - }, - - /** - * Set the language - * - * @param lang string - */ - setLang: function (lang: string) { - addPayloadPair('lang', lang); - }, - - /** - * Set the IP address - * - * @param ip string - */ - setIpAddress: function (ip: string) { - addPayloadPair('ip', ip); - }, - - /** - * Set the Useragent - * - * @param useragent string - */ - setUseragent: function (useragent: string) { - addPayloadPair('ua', useragent); - }, - - trackUnstructEvent: trackSelfDescribingEvent, - - trackSelfDescribingEvent: trackSelfDescribingEvent, - - /** - * Log the page view / visit - * - * @param pageUrl Current page URL - * @param pageTitle The user-defined page title to attach to this page view - * @param referrer URL users came from - * @param context Custom contexts relating to the event - * @param tstamp TrackerTimestamp of the event - * @return Payload - */ - trackPageView: function ( - pageUrl: string, - pageTitle: string, - referrer: string, - context?: Array, - tstamp?: Timestamp): PayloadData { - - var sb = payload.payloadBuilder(base64); - sb.add('e', 'pv'); // 'pv' for Page View - sb.add('url', pageUrl); - sb.add('page', pageTitle); - sb.add('refr', referrer); - - return track(sb, context, tstamp); - }, - /** - * Log that a user is still viewing a given page - * by sending a page ping - * - * @param pageUrl Current page URL - * @param pageTitle The page title to attach to this page ping - * @param referrer URL users came from - * @param minXOffset Minimum page x offset seen in the last ping period - * @param maxXOffset Maximum page x offset seen in the last ping period - * @param minYOffset Minimum page y offset seen in the last ping period - * @param maxYOffset Maximum page y offset seen in the last ping period - * @param context Custom contexts relating to the event - * @param tstamp TrackerTimestamp of the event - * @return object Payload - */ - trackPagePing: function ( - pageUrl: string, - pageTitle: string, - referrer: string, - minXOffset: number, - maxXOffset: number, - minYOffset: number, - maxYOffset: number, - context?: Array, - tstamp?: Timestamp): PayloadData { - - var sb = payload.payloadBuilder(base64); - sb.add('e', 'pp'); // 'pp' for Page Ping - sb.add('url', pageUrl); - sb.add('page', pageTitle); - sb.add('refr', referrer); - sb.add('pp_mix', minXOffset.toString()); - sb.add('pp_max', maxXOffset.toString()); - sb.add('pp_miy', minYOffset.toString()); - sb.add('pp_may', maxYOffset.toString()); - - return track(sb, context, tstamp); - }, - /** - * Track a structured event - * - * @param category The name you supply for the group of objects you want to track - * @param action A string that is uniquely paired with each category, and commonly used to define the type of user interaction for the web object - * @param label (optional) An optional string to provide additional dimensions to the event data - * @param property (optional) Describes the object or the action performed on it, e.g. quantity of item added to basket - * @param value (optional) An integer that you can use to provide numerical data about the user event - * @param context Custom contexts relating to the event - * @param tstamp TrackerTimestamp of the event - * @return Payload - */ - trackStructEvent: function ( - category: string, - action: string, - label: string, - property: string, - value?: number, - context?: Array, - tstamp?: Timestamp): PayloadData { - - var sb = payload.payloadBuilder(base64); - sb.add('e', 'se'); // 'se' for Structured Event - sb.add('se_ca', category); - sb.add('se_ac', action); - sb.add('se_la', label); - sb.add('se_pr', property); - sb.add('se_va', (value == null ? undefined : value.toString())); - - return track(sb, context, tstamp); - }, - - /** - * Track an ecommerce transaction - * - * @param orderId Required. Internal unique order id number for this transaction. - * @param affiliation Optional. Partner or store affiliation. - * @param totalValue Required. Total amount of the transaction. - * @param taxValue Optional. Tax amount of the transaction. - * @param shipping Optional. Shipping charge for the transaction. - * @param city Optional. City to associate with transaction. - * @param state Optional. State to associate with transaction. - * @param country Optional. Country to associate with transaction. - * @param currency Optional. Currency to associate with this transaction. - * @param context Optional. Context relating to the event. - * @param tstamp Optional. TrackerTimestamp of the event - * @return Payload - */ - trackEcommerceTransaction: function ( - orderId: string, - affiliation: string, - totalValue: string, - taxValue?: string, - shipping?: string, - city?: string, - state?: string, - country?: string, - currency?: string, - context?: Array, - tstamp?: Timestamp): PayloadData { - - var sb = payload.payloadBuilder(base64); - sb.add('e', 'tr'); // 'tr' for Transaction - sb.add("tr_id", orderId); - sb.add("tr_af", affiliation); - sb.add("tr_tt", totalValue); - sb.add("tr_tx", taxValue); - sb.add("tr_sh", shipping); - sb.add("tr_ci", city); - sb.add("tr_st", state); - sb.add("tr_co", country); - sb.add("tr_cu", currency); - - return track(sb, context, tstamp); - }, - - /** - * Track an ecommerce transaction item - * - * @param orderId Required Order ID of the transaction to associate with item. - * @param sku Required. Item's SKU code. - * @param name Optional. Product name. - * @param category Optional. Product category. - * @param price Required. Product price. - * @param quantity Required. Purchase quantity. - * @param currency Optional. Product price currency. - * @param context Optional. Context relating to the event. - * @param tstamp Optional. TrackerTimestamp of the event - * @return object Payload - */ - trackEcommerceTransactionItem: function ( - orderId: string, - sku: string, - name: string, - category: string, - price: string, - quantity: string, - currency?: string, - context?: Array, - tstamp?: Timestamp): PayloadData { - - var sb = payload.payloadBuilder(base64); - sb.add("e", "ti"); // 'tr' for Transaction Item - sb.add("ti_id", orderId); - sb.add("ti_sk", sku); - sb.add("ti_nm", name); - sb.add("ti_ca", category); - sb.add("ti_pr", price); - sb.add("ti_qu", quantity); - sb.add("ti_cu", currency); - - return track(sb, context, tstamp); - }, - - /** - * Track a screen view unstructured event - * - * @param name The name of the screen - * @param id The ID of the screen - * @param context Optional. Contexts relating to the event - * @param tstamp TrackerTimestamp of the event - * @return Payload - */ - trackScreenView: function ( - name: string, - id: string, - context?: Array, - tstamp?: Timestamp): PayloadData { - - return trackSelfDescribingEvent({ - schema: 'iglu:com.snowplowanalytics.snowplow/screen_view/jsonschema/1-0-0', - data: removeEmptyProperties({ - name: name, - id: id - }) - }, context, tstamp); - }, - - /** - * Log the link or click with the server - * - * @param targetUrl - * @param elementId - * @param elementClasses - * @param elementTarget - * @param elementContent innerHTML of the link - * @param context Custom contexts relating to the event - * @param tstamp TrackerTimestamp of the event - * @return Payload - */ - trackLinkClick: function ( - targetUrl: string, - elementId: string, - elementClasses: Array, - elementTarget: string, - elementContent: string, - context?: Array, - tstamp?: Timestamp) { - - var eventJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1', - data: removeEmptyProperties({ - targetUrl: targetUrl, - elementId: elementId, - elementClasses: elementClasses, - elementTarget: elementTarget, - elementContent: elementContent - }) - }; - - return trackSelfDescribingEvent(eventJson, context, tstamp); - }, - - /** - * Track an ad being served - * - * @param impressionId Identifier for a particular ad impression - * @param costModel The cost model. 'cpa', 'cpc', or 'cpm' - * @param cost Cost - * @param targetUrl URL ad pointing to - * @param bannerId Identifier for the ad banner displayed - * @param zoneId Identifier for the ad zone - * @param advertiserId Identifier for the advertiser - * @param campaignId Identifier for the campaign which the banner belongs to - * @param context Custom contexts relating to the event - * @param tstamp TrackerTimestamp of the event - * @return object Payload - */ - trackAdImpression: function ( - impressionId: string, - costModel: string, - cost: number, - targetUrl: string, - bannerId: string, - zoneId: string, - advertiserId: string, - campaignId: string, - context?: Array, - tstamp?: Timestamp): PayloadData { - - var eventJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/ad_impression/jsonschema/1-0-0', - data: removeEmptyProperties({ - impressionId: impressionId, - costModel: costModel, - cost: cost, - targetUrl: targetUrl, - bannerId: bannerId, - zoneId: zoneId, - advertiserId: advertiserId, - campaignId: campaignId - }) - }; - - return trackSelfDescribingEvent(eventJson, context, tstamp); - }, - - /** - * Track an ad being clicked - * - * @param targetUrl (required) The link's target URL - * @param clickId Identifier for the ad click - * @param costModel The cost model. 'cpa', 'cpc', or 'cpm' - * @param cost Cost - * @param bannerId Identifier for the ad banner displayed - * @param zoneId Identifier for the ad zone - * @param impressionId Identifier for a particular ad impression - * @param advertiserId Identifier for the advertiser - * @param campaignId Identifier for the campaign which the banner belongs to - * @param context Custom contexts relating to the event - * @param tstamp TrackerTimestamp of the event - * @return object Payload - */ - trackAdClick: function ( - targetUrl: string, - clickId: string, - costModel: string, - cost: number, - bannerId: string, - zoneId: string, - impressionId: string, - advertiserId: string, - campaignId: string, - context?: Array, - tstamp?: Timestamp): PayloadData { - - var eventJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/ad_click/jsonschema/1-0-0', - data: removeEmptyProperties({ - targetUrl: targetUrl, - clickId: clickId, - costModel: costModel, - cost: cost, - bannerId: bannerId, - zoneId: zoneId, - impressionId: impressionId, - advertiserId: advertiserId, - campaignId: campaignId - }) - }; - - return trackSelfDescribingEvent(eventJson, context, tstamp); - }, - - /** - * Track an ad conversion event - * - * @param conversionId Identifier for the ad conversion event - * @param costModel The cost model. 'cpa', 'cpc', or 'cpm' - * @param cost Cost - * @param category The name you supply for the group of objects you want to track - * @param action A string that is uniquely paired with each category - * @param property Describes the object of the conversion or the action performed on it - * @param initialValue Revenue attributable to the conversion at time of conversion - * @param advertiserId Identifier for the advertiser - * @param campaignId Identifier for the campaign which the banner belongs to - * @param context Custom contexts relating to the event - * @param tstamp TrackerTimestamp of the event - * @return object Payload - * - * @todo make costModel enum - */ - trackAdConversion: function ( - conversionId: string, - costModel: string, - cost: number, - category: string, - action: string, - property: string, - initialValue: number, - advertiserId: string, - campaignId: string, - context?: Array, - tstamp?: Timestamp): PayloadData { - - var eventJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/ad_conversion/jsonschema/1-0-0', - data: removeEmptyProperties({ - conversionId: conversionId, - costModel: costModel, - cost: cost, - category: category, - action: action, - property: property, - initialValue: initialValue, - advertiserId: advertiserId, - campaignId: campaignId - }) - }; - - return trackSelfDescribingEvent(eventJson, context, tstamp); - }, - - /** - * Track a social event - * - * @param action Social action performed - * @param network Social network - * @param target Object of the social action e.g. the video liked, the tweet retweeted - * @param context Custom contexts relating to the event - * @param tstamp TrackerTimestamp of the event - * @return Payload - */ - trackSocialInteraction: function ( - action: string, - network: string, - target: string, - context?: Array, - tstamp?: Timestamp): PayloadData { - - var eventJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/social_interaction/jsonschema/1-0-0', - data: removeEmptyProperties({ - action: action, - network: network, - target: target - }) - }; - - return trackSelfDescribingEvent(eventJson, context, tstamp); - }, - - /** - * Track an add-to-cart event - * - * @param sku Required. Item's SKU code. - * @param name Optional. Product name. - * @param category Optional. Product category. - * @param unitPrice Optional. Product price. - * @param quantity Required. Quantity added. - * @param currency Optional. Product price currency. - * @param context Optional. Context relating to the event. - * @param tstamp Optional. TrackerTimestamp of the event - * @return Payload - */ - trackAddToCart: function ( - sku: string, - name: string, - category: string, - unitPrice: string, - quantity: string, - currency?: string, - context?: Array, - tstamp?: Timestamp): PayloadData { - - return trackSelfDescribingEvent({ - schema: 'iglu:com.snowplowanalytics.snowplow/add_to_cart/jsonschema/1-0-0', - data: removeEmptyProperties({ - sku: sku, - name: name, - category: category, - unitPrice: unitPrice, - quantity: quantity, - currency: currency - }) - }, context, tstamp); - }, - - /** - * Track a remove-from-cart event - * - * @param sku Required. Item's SKU code. - * @param name Optional. Product name. - * @param category Optional. Product category. - * @param unitPrice Optional. Product price. - * @param quantity Required. Quantity removed. - * @param currency Optional. Product price currency. - * @param context Optional. Context relating to the event. - * @param tstamp Optional. TrackerTimestamp of the event - * @return Payload - */ - trackRemoveFromCart: function ( - sku: string, - name: string, - category: string, - unitPrice: string, - quantity: string, - currency?: string, - context?: Array, - tstamp?: Timestamp): PayloadData { - - return trackSelfDescribingEvent({ - schema: 'iglu:com.snowplowanalytics.snowplow/remove_from_cart/jsonschema/1-0-0', - data: removeEmptyProperties({ - sku: sku, - name: name, - category: category, - unitPrice: unitPrice, - quantity: quantity, - currency: currency - }) - }, context, tstamp); - }, - - /** - * Track the value of a form field changing or receiving focus - * - * @param schema The schema type of the event - * @param formId The parent form ID - * @param elementId ID of the changed element - * @param nodeName "INPUT", "TEXTAREA", or "SELECT" - * @param type Type of the changed element if its type is "INPUT" - * @param elementClasses List of classes of the changed element - * @param value The new value of the changed element - * @param context Optional. Context relating to the event. - * @param tstamp Optional. TrackerTimestamp of the event - * @return Payload - * - * @todo make `nodeName` enum - */ - trackFormFocusOrChange: function ( - schema: string, - formId: string, - elementId: string, - nodeName: string, - type: string, - elementClasses: Array, - value: string, - context?: Array, - tstamp?: Timestamp): PayloadData { - - let event_schema = ''; - let event_data:any = {formId, elementId, nodeName, elementClasses, value}; - if (schema === 'change_form'){ - event_schema = 'iglu:com.snowplowanalytics.snowplow/change_form/jsonschema/1-0-0'; - event_data.type = type - } else if (schema === 'focus_form') { - event_schema = 'iglu:com.snowplowanalytics.snowplow/focus_form/jsonschema/1-0-0'; - event_data.elementType = type - } - return trackSelfDescribingEvent({ - schema: event_schema, - data: removeEmptyProperties(event_data, {value: true}) - }, context, tstamp); - }, - - /** - * Track a form submission event - * - * @param formId ID of the form - * @param formClasses Classes of the form - * @param elements Mutable elements within the form - * @param context Optional. Context relating to the event. - * @param tstamp Optional. TrackerTimestamp of the event - * @return Payload - */ - trackFormSubmission: function( - formId: string, - formClasses: Array, - elements: Array, - context?: Array, - tstamp?: Timestamp): PayloadData { - - return trackSelfDescribingEvent({ - schema: 'iglu:com.snowplowanalytics.snowplow/submit_form/jsonschema/1-0-0', - data: removeEmptyProperties({ - formId: formId, - formClasses: formClasses, - elements: elements - }) - }, context, tstamp); - }, - - /** - * Track an internal search event - * - * @param terms Search terms - * @param filters Search filters - * @param totalResults Number of results - * @param pageResults Number of results displayed on page - * @param context Optional. Context relating to the event. - * @param tstamp Optional. TrackerTimestamp of the event - * @return Payload - */ - trackSiteSearch: function( - terms: Array, - filters: Object, - totalResults: number, - pageResults: number, - context?: Array, - tstamp?: Timestamp): PayloadData { - - return trackSelfDescribingEvent({ - schema: 'iglu:com.snowplowanalytics.snowplow/site_search/jsonschema/1-0-0', - data: removeEmptyProperties({ - terms: terms, - filters: filters, - totalResults: totalResults, - pageResults: pageResults - }) - }, context, tstamp); - }, - - /** - * Track a consent withdrawn event - * - * @param {boolean} all - Indicates user withdraws consent for all documents. - * @param {string} [id] - ID number associated with document. - * @param {string} [version] - Version number of document. - * @param {string} [name] - Name of document. - * @param {string} [description] - Description of document. - * @param {Array} [context] - Context relating to the event. - * @param {Timestamp} [tstamp] - TrackerTimestamp of the event. - * @return Payload - */ - trackConsentWithdrawn: function( - all: boolean, - id?: string, - version?: string, - name?: string, - description?: string, - context?: Array, - tstamp?: Timestamp): PayloadData { - - let documentJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/consent_document/jsonschema/1-0-0', - data: removeEmptyProperties({ - id: id, - version: version, - name: name, - description: description - }) - }; - - return trackSelfDescribingEvent({ - schema: 'iglu:com.snowplowanalytics.snowplow/consent_withdrawn/jsonschema/1-0-0', - data: removeEmptyProperties({ - all: all - }) - }, documentJson.data && context ? context.concat([documentJson]) : context, tstamp); - }, - - /** - * Track a consent granted event - * - * @param {string} id - ID number associated with document. - * @param {string} version - Version number of document. - * @param {string} [name] - Name of document. - * @param {string} [description] - Description of document. - * @param {string} [expiry] - Date-time when consent expires. - * @param {Array} [context] - Context relating to the event. - * @param {Timestamp} [tstamp] - TrackerTimestamp of the event. - * @return Payload - */ - trackConsentGranted: function( - id: string, - version: string, - name?: string, - description?: string, - expiry?: string, - context?: Array, - tstamp?: Timestamp): PayloadData { - - let documentJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/consent_document/jsonschema/1-0-0', - data: removeEmptyProperties({ - id: id, - version: version, - name: name, - description: description, - }) - }; - - return trackSelfDescribingEvent({ - schema: 'iglu:com.snowplowanalytics.snowplow/consent_granted/jsonschema/1-0-0', - data: removeEmptyProperties({ - expiry: expiry, - }) - }, context ? context.concat([documentJson]) : [documentJson], tstamp); - }, - - addGlobalContexts: function(contexts: Array) { - contextModule.addGlobalContexts(contexts); - }, - - clearGlobalContexts: function() { - contextModule.clearGlobalContexts(); - }, - - removeGlobalContexts: function(contexts: Array) { - contextModule.removeGlobalContexts(contexts); - } - }; -} diff --git a/core/lib/payload.ts b/core/lib/payload.ts deleted file mode 100644 index 92dec70de..000000000 --- a/core/lib/payload.ts +++ /dev/null @@ -1,112 +0,0 @@ -/* - * JavaScript tracker core for Snowplow: payload.js - * - * Copyright (c) 2014-2016 Snowplow Analytics Ltd. All rights reserved. - * - * This program is licensed to you under the Apache License Version 2.0, - * and you may not use this file except in compliance with the Apache License Version 2.0. - * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the Apache License Version 2.0 is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. - */ - -import * as base64 from './base64'; - -/** - * Interface for mutable object encapsulating tracker payload - */ -export interface PayloadData { - add: (key: string, value?: string) => void, - addDict: (dict: Object) => void, - addJson: (keyIfEncoded: string, keyIfNotEncoded: string, json: Object) => void, - build: () => Object; -} - -/** - * Bas64 encode data with URL and Filename Safe Alphabet (base64url) - * - * See: http://tools.ietf.org/html/rfc4648#page-7 - */ -function base64urlencode(data: string): string { - if (!data) { - return data; - } - - var enc = base64.base64encode(data); - return enc.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); -} - -/** - * Is property a non-empty JSON? - */ -export function isNonEmptyJson(property): boolean { - if (!isJson(property)) { - return false; - } - for (var key in property) { - if (property.hasOwnProperty(key)) { - return true; - } - } - return false; -} - -/** - * Is property a JSON? - */ -export function isJson(property: Object): boolean { - return (typeof property !== 'undefined' && property !== null && - (property.constructor === {}.constructor || property.constructor === [].constructor)); -} - - -/** - * A helper to build a Snowplow request string from an - * an optional initial value plus a set of individual - * name-value pairs, provided using the add method. - * - * @param base64Encode boolean Whether or not JSONs should be - * Base64-URL-safe-encoded - * - * @return object The request string builder, with add, addRaw and build methods - */ -export function payloadBuilder(base64Encode: boolean): PayloadData { - var dict = {}; - - var add = function (key: string, value?: string): void { - if (value != null && value !== '') { // null also checks undefined - dict[key] = value; - } - }; - - var addDict = function (dict: Object) { - for (var key in dict) { - if (dict.hasOwnProperty(key)) { - add(key, dict[key]); - } - } - }; - - var addJson = function (keyIfEncoded: string, keyIfNotEncoded: string, json?: Object) { - if (isNonEmptyJson(json)) { - var str = JSON.stringify(json); - if (base64Encode) { - add(keyIfEncoded, base64urlencode(str)); - } else { - add(keyIfNotEncoded, str); - } - } - }; - - return { - add: add, - addDict: addDict, - addJson: addJson, - build: function () { - return dict; - } - }; -} diff --git a/core/license.txt b/core/license.txt deleted file mode 100644 index 7a4a3ea24..000000000 --- a/core/license.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/core/package.json b/core/package.json deleted file mode 100644 index d705f96ef..000000000 --- a/core/package.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "snowplow-tracker-core", - "version": "0.7.2", - "devDependencies": { - "@types/es6-shim": "0.31.34", - "@types/node": "^9.6.7", - "dts-generator": "^2.0.0", - "grunt": "0.4.5", - "grunt-ts": "5.5.1", - "intern": "3.3.2", - "typescript": "2.2.2" - }, - "dependencies": { - "@types/uuid": "^2.0.29", - "lodash": "^4.17.11", - "uuid": "2.0.3" - }, - "contributors": [ - "Alex Dean", - "Simon Andersson", - "Fred Blundun" - ], - "types": "./main.d.ts", - "description": "Core functionality for the Snowplow JavaScript trackers (browser JavaScript; Node.js; Segment.io server-side)", - "repository": { - "type": "git", - "url": "https://github.com/snowplow/snowplow-javascript-tracker.git" - }, - "bugs": "https://github.com/snowplow/snowplow-javascript-tracker/issues", - "keywords": [ - "tracking", - "web analytics", - "events", - "open source" - ], - "license": "Apache-2.0" -} diff --git a/core/tests/intern.js b/core/tests/intern.js deleted file mode 100644 index b0ebd23ff..000000000 --- a/core/tests/intern.js +++ /dev/null @@ -1,20 +0,0 @@ -/* - * JavaScript tracker core for Snowplow: tests/intern.js - * - * Copyright (c) 2014-2016 Snowplow Analytics Ltd. All rights reserved. - * - * This program is licensed to you under the Apache License Version 2.0, - * and you may not use this file except in compliance with the Apache License Version 2.0. - * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the Apache License Version 2.0 is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. - */ - -define({ - - excludeInstrumentation: /^(?:tests|node_modules)\// - -}); diff --git a/core/tests/unit/base64.js b/core/tests/unit/base64.js deleted file mode 100644 index ddedce0bf..000000000 --- a/core/tests/unit/base64.js +++ /dev/null @@ -1,32 +0,0 @@ -/* - * JavaScript tracker core for Snowplow: tests/base64.js - * - * Copyright (c) 2014 Snowplow Analytics Ltd. All rights reserved. - * - * This program is licensed to you under the Apache License Version 2.0, - * and you may not use this file except in compliance with the Apache License Version 2.0. - * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the Apache License Version 2.0 is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. - */ - -define([ - "intern!object", - "intern/chai!assert", - "intern/dojo/node!../../lib/base64.js" -], function (registerSuite, assert, base64) { - - registerSuite({ - name: "Base 64 encoding test", - "Encode a string": function () { - assert.strictEqual(base64.base64encode('my_string'), 'bXlfc3RyaW5n', 'Base64-encode a string'); - }, - - "Encode a string containing special characters": function () { - assert.strictEqual(base64.base64encode('™®字'), '4oSiwq7lrZc=', 'Base64-encode a containing TM, Registered Trademark, and Chinese characters'); - } - }); -}); diff --git a/core/tests/unit/contexts.js b/core/tests/unit/contexts.js deleted file mode 100644 index b35307169..000000000 --- a/core/tests/unit/contexts.js +++ /dev/null @@ -1,327 +0,0 @@ -/* - * JavaScript tracker core for Snowplow: tests/integration.js - * - * Copyright (c) 2014-2016 Snowplow Analytics Ltd. All rights reserved. - * - * This program is licensed to you under the Apache License Version 2.0, - * and you may not use this file except in compliance with the Apache License Version 2.0. - * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the Apache License Version 2.0 is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. - */ - -define([ - "intern!object", - "intern/chai!assert", - "intern/chai!expect", - "intern/dojo/node!../../lib/contexts.js", - "intern/dojo/node!../../lib/payload.js" -], function (registerSuite, assert, expect, contexts, payload) { - registerSuite({ - name: "Global context tests", - - "Identify context primitives": function () { - let geolocationContext = { - schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0', - data: { - 'latitude': 40.0, - 'longitude' : 55.1 - } - }; - - function eventTypeContextGenerator(args) { - let context = {}; - context['schema'] = 'iglu:com.snowplowanalytics.snowplow/mobile_context/jsonschema/1-0-1'; - context['data']['osType'] = 'ubuntu'; - context['data']['osVersion'] = '2018.04'; - context['data']['deviceManufacturer'] = 'ASUS'; - context['data']['deviceModel'] = String(args[eventType]); - return context; - } - - assert.isTrue(contexts.isContextPrimitive(geolocationContext), 'A context primitive should be identified'); - assert.isTrue(contexts.isContextPrimitive(eventTypeContextGenerator), 'A context primitive should be identified'); - }, - - "Validating vendors": function () { - // Vendor validation - assert.isTrue(contexts.validateVendor('com.acme.marketing'), 'A valid vendor without wildcard is accepted'); - assert.isTrue(contexts.validateVendor('com.acme.*'), 'A valid vendor with wildcard is accepted'); - assert.isFalse(contexts.validateVendor('*.acme.*'), 'A vendor starting with asterisk is rejected'); - assert.isFalse(contexts.validateVendor('com.acme.*.marketing'), 'A vendor with asterisk out of order is rejected'); - }, - - "Identify rule sets": function () { - const acceptRuleSet = { - accept: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'] - }; - - const rejectRuleSet = { - reject: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/1-0-1'] - }; - - const bothRuleSet = { - accept: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/1-*-1'], - reject: ['iglu:com.snowplowanalytics.snowplow/some_event/jsonschema/1-*-*'] - }; - - const pageview_schema = 'iglu:com.snowplowanalytics.snowplow/pageview/jsonschema/1-0-1'; - - - - assert.isTrue(contexts.isValidRule(acceptRuleSet.accept[0]), 'All rule elements are correctly identified as valid rules'); - assert.isTrue(contexts.isValidRuleSetArg(acceptRuleSet.accept), 'A rule set arg is correctly identified'); - assert.isTrue(contexts.isRuleSet(acceptRuleSet), 'An accept rule set is identified'); - assert.isTrue(contexts.isRuleSet(rejectRuleSet), 'A reject rule set is identified'); - assert.isTrue(contexts.isRuleSet(bothRuleSet), 'A rule set with both elements is identified'); - assert.deepEqual(contexts.getSchemaParts(pageview_schema), ['com.snowplowanalytics.snowplow', 'pageview', '1', '0', '1'], 'Gets correct parts for schema'); - assert.isTrue(contexts.matchSchemaAgainstRule('iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*', pageview_schema), 'Matches schema against wildcarded rule'); - assert.isTrue(contexts.matchSchemaAgainstRuleSet(acceptRuleSet, pageview_schema), 'Accept rule set accepts matching schema'); - assert.isFalse(contexts.matchSchemaAgainstRuleSet(rejectRuleSet, pageview_schema), 'Reject rule set rejects matching schema'); - }, - - "Identify filter function": function () { - let filterFunction = function (args) { - return args['eventType'] === 'ue'; - }; - - assert.isTrue(contexts.isContextFilter(filterFunction), 'A valid filter function is identified'); - }, - - "Identify rule set provider": function () { - let bothRuleSet = { - accept: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'], - reject: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'] - }; - - let geolocationContext = { - schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0', - data: { - 'latitude': 40.0, - 'longitude' : 55.1 - } - }; - - function eventTypeContextGenerator(args) { - let context = {}; - context['schema'] = 'iglu:com.snowplowanalytics.snowplow/mobile_context/jsonschema/1-0-1'; - context['data']['osType'] = 'ubuntu'; - context['data']['osVersion'] = '2018.04'; - context['data']['deviceManufacturer'] = 'ASUS'; - context['data']['deviceModel'] = String(args[eventType]); - return context; - } - - let ruleSetProvider = [bothRuleSet, [geolocationContext, eventTypeContextGenerator]]; - assert.isTrue(contexts.isRuleSetProvider(ruleSetProvider), 'Valid rule set provider is correctly identified'); - }, - - "Identify filter provider": function () { - let filterFunction = function (args) { - return args['eventType'] === 'ue'; - }; - - let geolocationContext = { - schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0', - data: { - 'latitude': 40.0, - 'longitude' : 55.1 - } - }; - - function eventTypeContextGenerator(args) { - let context = {}; - context['schema'] = 'iglu:com.snowplowanalytics.snowplow/mobile_context/jsonschema/1-0-1'; - context['data']['osType'] = 'ubuntu'; - context['data']['osVersion'] = '2018.04'; - context['data']['deviceManufacturer'] = 'ASUS'; - context['data']['deviceModel'] = String(args[eventType]); - return context; - } - - let filterProvider = [filterFunction, [geolocationContext, eventTypeContextGenerator]]; - assert.isTrue(contexts.isFilterProvider(filterProvider), 'A valid filter provider is identified'); - }, - - "Add global contexts": function () { - let geolocationContext = { - schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0', - data: { - 'latitude': 40.0, - 'longitude' : 55.1 - } - }; - - function eventTypeContextGenerator(args) { - let context = {}; - context['schema'] = 'iglu:com.snowplowanalytics.snowplow/mobile_context/jsonschema/1-0-1'; - context['data']['osType'] = 'ubuntu'; - context['data']['osVersion'] = '2018.04'; - context['data']['deviceManufacturer'] = 'ASUS'; - context['data']['deviceModel'] = String(args[eventType]); - return context; - } - - let bothRuleSet = { - accept: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'], - reject: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'] - }; - - let filterFunction = function (args) { - return args['eventType'] === 'ue'; - }; - - let filterProvider = [filterFunction, [geolocationContext, eventTypeContextGenerator]]; - let ruleSetProvider = [bothRuleSet, [geolocationContext, eventTypeContextGenerator]]; - - let contextArray = [filterProvider, ruleSetProvider, geolocationContext, eventTypeContextGenerator]; - let module = contexts.contextModule(); - - module.addGlobalContexts(contextArray); - assert.strictEqual(module.getGlobalPrimitives().length, 2, - 'Correct number of primitives added'); - assert.strictEqual(module.getConditionalProviders().length, 2, - 'Correct number of conditional providers added'); - }, - - "Remove global contexts": function () { - let geolocationContext = { - schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0', - data: { - 'latitude': 40.0, - 'longitude' : 55.1 - } - }; - - function eventTypeContextGenerator(args) { - let context = {}; - context['schema'] = 'iglu:com.snowplowanalytics.snowplow/mobile_context/jsonschema/1-0-1'; - context['data']['osType'] = 'ubuntu'; - context['data']['osVersion'] = '2018.04'; - context['data']['deviceManufacturer'] = 'ASUS'; - context['data']['deviceModel'] = String(args[eventType]); - return context; - } - - let bothRuleSet = { - accept: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'], - reject: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'] - }; - - let filterFunction = function (args) { - return args['eventType'] === 'ue'; - }; - - let filterProvider = [filterFunction, [geolocationContext, eventTypeContextGenerator]]; - let ruleSetProvider = [bothRuleSet, [geolocationContext, eventTypeContextGenerator]]; - let module = contexts.contextModule(); - - module.addGlobalContexts([filterProvider, ruleSetProvider, geolocationContext, eventTypeContextGenerator]); - module.removeGlobalContexts([filterProvider, geolocationContext, eventTypeContextGenerator]); - assert.strictEqual(module.getGlobalPrimitives().length, 0, - 'Correct number of primitives added'); - assert.strictEqual(module.getConditionalProviders().length, 1, - 'Correct number of conditional providers added'); - }, - - "Clear global contexts": function () { - let geolocationContext = { - schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0', - data: { - 'latitude': 40.0, - 'longitude' : 55.1 - } - }; - - function eventTypeContextGenerator(args) { - let context = {}; - context['schema'] = 'iglu:com.snowplowanalytics.snowplow/mobile_context/jsonschema/1-0-1'; - context['data']['osType'] = 'ubuntu'; - context['data']['osVersion'] = '2018.04'; - context['data']['deviceManufacturer'] = 'ASUS'; - context['data']['deviceModel'] = String(args[eventType]); - return context; - } - - let bothRuleSet = { - accept: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'], - reject: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'] - }; - - let filterFunction = function (args) { - return args['eventType'] === 'ue'; - }; - - let filterProvider = [filterFunction, [geolocationContext, eventTypeContextGenerator]]; - let ruleSetProvider = [bothRuleSet, [geolocationContext, eventTypeContextGenerator]]; - - let contextArray = [filterProvider, ruleSetProvider, geolocationContext, eventTypeContextGenerator]; - let module = contexts.contextModule(); - module.addGlobalContexts(contextArray); - module.clearGlobalContexts(); - assert.strictEqual(module.getGlobalPrimitives().length, 0, - 'Correct number of primitives added'); - assert.strictEqual(module.getConditionalProviders().length, 0, - 'Correct number of conditional providers added'); - }, - - "Get applicable contexts": function () { - let geolocationContext = { - schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0', - data: { - 'latitude': 40.0, - 'longitude' : 55.1 - } - }; - - function eventTypeContextGenerator(args) { - let context = {}; - context['schema'] = 'iglu:com.snowplowanalytics.snowplow/some_context/jsonschema/1-0-1'; - context['data'] = {}; - context['data']['osType'] = 'ubuntu'; - context['data']['osVersion'] = '2018.04'; - context['data']['deviceManufacturer'] = 'ASUS'; - context['data']['eventType'] = String(args['eventType']); - return context; - } - - let unstructuredEventRuleset = { - accept: ['iglu:com.acme_company/*/jsonschema/*-*-*'] - }; - - let filterFunction = function (args) { - return args['eventType'] === 'ue'; - }; - - let filterProvider = [filterFunction, [geolocationContext, eventTypeContextGenerator]]; - let ruleSetProvider = [unstructuredEventRuleset, [geolocationContext, eventTypeContextGenerator]]; - - let eventJson = { - e: 'ue', - ue_px: { - schema: 'iglu:com.snowplowanalytics.snowplow/unstructured_event/jsonschema/1-0-0', - data: { - schema: 'iglu:com.acme_company/some_event/jsonschema/1-0-0', - data: {} - } - } - }; - let contextArray = [filterProvider, ruleSetProvider, geolocationContext, eventTypeContextGenerator]; - let module = contexts.contextModule(); - let event = payload.payloadBuilder(false); - for (let property in eventJson) { - if (eventJson.hasOwnProperty(property)) { - event.add(property, eventJson[property]); - } - } - - module.addGlobalContexts(contextArray); - assert.strictEqual(module.getApplicableContexts(event).length, 6, - 'Correct number of contexts returned'); - } - }); - -}); diff --git a/core/tests/unit/core.js b/core/tests/unit/core.js deleted file mode 100644 index 12f60fc8b..000000000 --- a/core/tests/unit/core.js +++ /dev/null @@ -1,749 +0,0 @@ -/* - * JavaScript tracker core for Snowplow: tests/integration.js - * - * Copyright (c) 2014-2016 Snowplow Analytics Ltd. All rights reserved. - * - * This program is licensed to you under the Apache License Version 2.0, - * and you may not use this file except in compliance with the Apache License Version 2.0. - * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the Apache License Version 2.0 is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. - */ - -define([ - "intern!object", - "intern/chai!assert", - "intern/chai!expect", - "intern/dojo/node!../../lib/core.js" -], function (registerSuite, assert, expect, core) { - - var unstructEventSchema = 'iglu:com.snowplowanalytics.snowplow/unstruct_event/jsonschema/1-0-0'; - var tracker = core.trackerCore(false); - - // Doesn't check true timestamp - function compare(result, expected, message) { - result = result.build(); - assert.ok(result['eid'], 'A UUID should be attached to all events'); - delete result['eid']; - assert.ok(result['dtm'], 'A timestamp should be attached to all events'); - delete result['dtm']; - assert.deepEqual(result, expected, message); - } - - registerSuite({ - name: "Tracking events", - - "Track a page view": function () { - var url = 'http://www.example.com'; - var page = 'title page'; - var expected = { - e: 'pv', - url: url, - page: page - }; - compare(tracker.trackPageView(url, page), expected, 'A page view should be tracked correctly'); - }, - - "Track a page ping": function () { - var url = 'http://www.example.com'; - var referer = 'http://www.google.com'; - var expected = { - e: 'pp', - url: url, - refr: referer, - pp_mix: '1', - pp_max: '2', - pp_miy: '3', - pp_may: '4' - }; - - compare(tracker.trackPagePing(url, null, referer, 1, 2, 3, 4), expected, 'A page ping should be tracked correctly'); - }, - - "Track a structured event": function () { - var expected = { - e: 'se', - se_ca: 'cat', - se_ac: 'act', - se_la: 'lab', - se_pr: 'prop', - se_va: 'val' - }; - - compare(tracker.trackStructEvent('cat', 'act', 'lab', 'prop', 'val'), expected, 'A structured event should be tracked correctly'); - }, - - "Track an ecommerce transaction event": function () { - var orderId = 'ak0008'; - var totalValue = 50; - var taxValue = 6; - var shipping = 0; - var city = 'Phoenix'; - var state = 'Arizona'; - var country = 'USA'; - var currency = 'USD'; - var expected = { - e: 'tr', - tr_id: orderId, - tr_tt: totalValue, - tr_tx: taxValue, - tr_sh: shipping, - tr_ci: city, - tr_st: state, - tr_co: country, - tr_cu: currency - }; - - compare(tracker.trackEcommerceTransaction(orderId, null, totalValue, taxValue, shipping, city, state, country, currency), expected, 'A transaction event should be tracked correctly'); - }, - - "Track an ecommerce transaction item event": function () { - var orderId = 'ak0008'; - var sku = '4q345'; - var price = 17; - var quantity = 2; - var name = 'red shoes'; - var category = 'clothing'; - var currency = 'USD'; - var expected = { - e: 'ti', - ti_id: orderId, - ti_sk: sku, - ti_nm: name, - ti_ca: category, - ti_pr: price, - ti_qu: quantity, - ti_cu: currency - }; - - compare(tracker.trackEcommerceTransactionItem(orderId, sku, name, category, price, quantity, currency), expected, 'A transaction item event should be tracked correctly'); - }, - - "Track an unstructured event": function () { - var inputJson = { - schema: 'iglu:com.acme/user/jsonschema/1-0-1', - data: { - name: 'Eric' - } - }; - var expected = { - e: 'ue', - ue_pr: JSON.stringify({ - schema: unstructEventSchema, - data: inputJson - }) - }; - - compare(tracker.trackUnstructEvent(inputJson), expected, 'An unstructured event should be tracked correctly'); - }, - - "Track a self-describing event": function () { - var inputJson = { - schema: 'iglu:com.acme/user/jsonschema/1-0-1', - data: { - name: 'Eric' - } - }; - var expected = { - e: 'ue', - ue_pr: JSON.stringify({ - schema: unstructEventSchema, - data: inputJson - }) - }; - - compare(tracker.trackSelfDescribingEvent(inputJson), expected, 'A self-describing event should be tracked correctly'); - }, - - "Track a link click": function () { - var targetUrl = 'http://www.example.com'; - var elementId = 'first header'; - var elementClasses = ['header']; - var elementContent = 'link'; - - var inputJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1', - data: { - targetUrl: targetUrl, - elementId: elementId, - elementClasses: elementClasses, - elementContent: elementContent - } - }; - var expected = { - e: 'ue', - ue_pr: JSON.stringify({ - schema: unstructEventSchema, - data: inputJson - }) - }; - - compare(tracker.trackLinkClick(targetUrl, elementId, elementClasses, null, elementContent), expected, 'A link click should be tracked correctly'); - }, - - "Track a screen view": function () { - var name = 'intro'; - var id = '7398-4352-5345-1950'; - - var inputJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/screen_view/jsonschema/1-0-0', - data: { - name: name, - id: id - } - }; - var expected = { - e: 'ue', - ue_pr: JSON.stringify({ - schema: unstructEventSchema, - data: inputJson - }) - }; - - compare(tracker.trackScreenView(name, id), expected, 'A screen view should be tracked correctly'); - }, - - "Track an ad impression": function () { - var impressionId = 'a0e8f8780ab3'; - var costModel = 'cpc'; - var cost = 0.5; - var targetUrl = 'http://adsite.com'; - var bannerId = '123'; - var zoneId = 'zone-14'; - var advertiserId = 'ad-company'; - var campaignId = 'campaign-7592'; - - var inputJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/ad_impression/jsonschema/1-0-0', - data: { - impressionId: impressionId, - costModel: costModel, - cost: cost, - targetUrl: targetUrl, - bannerId: bannerId, - zoneId: zoneId, - advertiserId: advertiserId, - campaignId: campaignId - } - }; - var expected = { - e: 'ue', - ue_pr: JSON.stringify({ - schema: unstructEventSchema, - data: inputJson - }) - }; - - compare(tracker.trackAdImpression(impressionId, costModel, cost, targetUrl, bannerId, zoneId, advertiserId, campaignId), expected, 'An ad impression should be tracked correctly'); - }, - - "Track an ad click": function () { - var targetUrl = 'http://adsite.com'; - var clickId = 'click-321'; - var costModel = 'cpc'; - var cost = 0.5; - var bannerId = '123'; - var zoneId = 'zone-14'; - var impressionId = 'a0e8f8780ab3'; - var advertiserId = 'ad-company'; - var campaignId = 'campaign-7592'; - - var inputJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/ad_click/jsonschema/1-0-0', - data: { - targetUrl: targetUrl, - clickId: clickId, - costModel: costModel, - cost: cost, - bannerId: bannerId, - zoneId: zoneId, - impressionId: impressionId, - advertiserId: advertiserId, - campaignId: campaignId - } - }; - var expected = { - e: 'ue', - ue_pr: JSON.stringify({ - schema: unstructEventSchema, - data: inputJson - }) - }; - - compare(tracker.trackAdClick(targetUrl, clickId, costModel, cost, bannerId, zoneId, impressionId, advertiserId, campaignId), expected, 'An ad click should be tracked correctly'); - }, - - "Track an ad conversion": function () { - var conversionId = 'conversion-59'; - var costModel = 'cpc'; - var cost = 0.5; - var category = 'cat'; - var action = 'act'; - var property = 'prop'; - var initialValue = 7; - var advertiserId = 'ad-company'; - var campaignId = 'campaign-7592'; - - var inputJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/ad_conversion/jsonschema/1-0-0', - data: { - conversionId: conversionId, - costModel: costModel, - cost: cost, - category: category, - action: action, - property: property, - initialValue: initialValue, - advertiserId: advertiserId, - campaignId: campaignId - } - }; - var expected = { - e: 'ue', - ue_pr: JSON.stringify({ - schema: unstructEventSchema, - data: inputJson - }) - }; - - compare(tracker.trackAdConversion(conversionId, costModel, cost, category, action, property, initialValue, advertiserId, campaignId), expected, 'An ad conversion should be tracked correctly'); - }, - - "Track a social interaction": function () { - var action = 'like'; - var network = 'facebook'; - var target = 'status-0000345345'; - - var inputJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/social_interaction/jsonschema/1-0-0', - data: { - action: action, - network: network, - target: target - } - }; - - var expected = { - e: 'ue', - ue_pr: JSON.stringify({ - schema: unstructEventSchema, - data: inputJson - }) - }; - - compare(tracker.trackSocialInteraction(action, network, target), expected); - }, - - - "Track an add-to-cart event": function () { - var sku = '4q345'; - var unitPrice = 17; - var quantity = 2; - var name = 'red shoes'; - var category = 'clothing'; - var currency = 'USD'; - - var inputJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/add_to_cart/jsonschema/1-0-0', - data: { - sku: sku, - name: name, - category: category, - unitPrice: unitPrice, - quantity: quantity, - currency: currency - } - }; - - var expected = { - e: 'ue', - ue_pr: JSON.stringify({ - schema: unstructEventSchema, - data: inputJson - }) - }; - - compare(tracker.trackAddToCart(sku, name, category, unitPrice, quantity, currency), expected); - }, - - "Track a remove-from-cart event": function () { - var sku = '4q345'; - var unitPrice = 17; - var quantity = 2; - var name = 'red shoes'; - var category = 'clothing'; - var currency = 'USD'; - - var inputJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/remove_from_cart/jsonschema/1-0-0', - data: { - sku: sku, - name: name, - category: category, - unitPrice: unitPrice, - quantity: quantity, - currency: currency - } - }; - - var expected = { - e: 'ue', - ue_pr: JSON.stringify({ - schema: unstructEventSchema, - data: inputJson - }) - }; - - compare(tracker.trackRemoveFromCart(sku, name, category, unitPrice, quantity, currency), expected); - }, - - "Track a form focus event": function () { - var formId = "parent"; - var elementId = "child"; - var nodeName = "INPUT"; - var type = "text"; - var elementClasses = ["important"]; - var value = "male"; - - var inputJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/focus_form/jsonschema/1-0-0', - data: { - formId: formId, - elementId: elementId, - nodeName: nodeName, - elementClasses: elementClasses, - value: value, - elementType: type - } - }; - - var expected = { - e: 'ue', - ue_pr: JSON.stringify({ - schema: unstructEventSchema, - data: inputJson - }) - }; - - compare(tracker.trackFormFocusOrChange('focus_form', formId, elementId, nodeName, type, elementClasses, value), expected); - }, - - "Track a form change event": function () { - var formId = "parent"; - var elementId = "child"; - var nodeName = "INPUT"; - var type = "text"; - var elementClasses = ["important"]; - var value = "male"; - - var inputJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/change_form/jsonschema/1-0-0', - data: { - formId: formId, - elementId: elementId, - nodeName: nodeName, - elementClasses: elementClasses, - value: value, - type: type - } - }; - - var expected = { - e: 'ue', - ue_pr: JSON.stringify({ - schema: unstructEventSchema, - data: inputJson - }) - }; - - compare(tracker.trackFormFocusOrChange('change_form', formId, elementId, nodeName, type, elementClasses, value), expected); - }, - - "Track a form submission event": function () { - var formId = "parent"; - var formClasses = ["formclass"]; - var elements = [{ - name: "gender", - value: "male", - nodeName: "INPUT", - type: "text" - }]; - - var inputJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/submit_form/jsonschema/1-0-0', - data: { - formId: formId, - formClasses: formClasses, - elements: elements - } - }; - - var expected = { - e: 'ue', - ue_pr: JSON.stringify({ - schema: unstructEventSchema, - data: inputJson - }) - }; - - compare(tracker.trackFormSubmission(formId, formClasses, elements), expected); - }, - - "Track a site seach event": function () { - var terms = ["javascript", "development"]; - var filters = { - "safeSearch": true, - "category": "books" - }; - var totalResults = 35; - var pageResults = 10; - - var inputJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/site_search/jsonschema/1-0-0', - data: { - terms: terms, - filters: filters, - totalResults: totalResults, - pageResults: pageResults - } - }; - - var expected = { - e: 'ue', - ue_pr: JSON.stringify({ - schema: unstructEventSchema, - data: inputJson - }) - }; - - compare(tracker.trackSiteSearch(terms, filters, totalResults, pageResults), expected); - }, - - "Track a consent withdrawn event": function () { - var all = false; - var id = 1234; - var version = 2; - var name = "consent_form"; - var description = "user withdraws consent for form"; - var tstamp = 1000000000000; - var inputContext = [{ - schema: 'iglu:com.snowplowanalytics.snowplow/consent_document/jsonschema/1-0-0', - data: { - id: id, - version: version, - name: name, - description: description - } - }]; - var inputJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/consent_withdrawn/jsonschema/1-0-0', - data: { - all: all - } - }; - var expected = { - e: 'ue', - ue_pr: JSON.stringify({ - schema: unstructEventSchema, - data: inputJson - }), - co: JSON.stringify({ - schema: 'iglu:com.snowplowanalytics.snowplow/contexts/jsonschema/1-0-0', - data: inputContext - }) - }; - compare(tracker.trackConsentWithdrawn(all, id, version, name, description, [], tstamp), expected); - }, - - "Track a consent granted event": function () { - var id = 1234; - var version = 2; - var name = "consent_form"; - var description = "user grants consent for form"; - var tstamp = 1000000000000; - var expiry = "01 January, 1970 00:00:00 Universal Time (UTC)"; - var inputContext = [{ - schema: 'iglu:com.snowplowanalytics.snowplow/consent_document/jsonschema/1-0-0', - data: { - id: id, - version: version, - name: name, - description: description - } - }]; - var inputJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/consent_granted/jsonschema/1-0-0', - data: { - expiry: expiry - } - }; - var expected = { - e: 'ue', - ue_pr: JSON.stringify({ - schema: unstructEventSchema, - data: inputJson - }), - co: JSON.stringify({ - schema: 'iglu:com.snowplowanalytics.snowplow/contexts/jsonschema/1-0-0', - data: inputContext - }) - }; - compare(tracker.trackConsentGranted(id, version, name, description, expiry, [], tstamp), expected); - }, - - "Track a page view with custom context": function () { - var url = 'http://www.example.com'; - var page = 'title page'; - var inputContext = [{ - schema: 'iglu:com.acme/user/jsonschema/1-0-0', - data: { - userType: 'tester', - userName: 'Jon' - } - }]; - var expected = { - e: 'pv', - url: url, - page: page, - co: JSON.stringify({ - schema: 'iglu:com.snowplowanalytics.snowplow/contexts/jsonschema/1-0-0', - data: inputContext - }) - }; - compare(tracker.trackPageView(url, page, null, inputContext), expected, 'A custom context should be attached correctly'); - }, - - "Track a page view with a timestamp": function () { - var tstamp = 1000000000000; - - assert.strictEqual(tracker.trackPageView('http://www.example.com', null, null, null, tstamp).build()['dtm'], '1000000000000', 'A timestamp should be attached correctly'); - }, - - "Add individual name-value pairs to the payload": function () { - var tracker = core.trackerCore(false); - var url = 'http://www.example.com'; - var expected = { - e: 'pv', - url: url, - tna: 'cf', - tv: 'js-2.0.0' - }; - tracker.addPayloadPair('tna', 'cf'); - tracker.addPayloadPair('tv', 'js-2.0.0'); - - compare(tracker.trackPageView(url), expected, 'Payload name-value pairs should be set correctly'); - }, - - "Add a dictionary of name-value pairs to the payload": function () { - var tracker = core.trackerCore(false); - var url = 'http://www.example.com'; - var expected = { - e: 'pv', - url: url, - tv: 'js-2.0.0', - tna: 'cf', - aid: 'cf325' - }; - tracker.addPayloadPair('tv', 'js-2.0.0'); - tracker.addPayloadDict({ - tna: 'cf', - aid: 'cf325' - }); - - compare(tracker.trackPageView(url), expected, 'Payload name-value pairs should be set correctly'); - }, - - "Reset payload name-value pairs": function () { - var tracker = core.trackerCore(false); - var url = 'http://www.example.com'; - var expected = { - e: 'pv', - url: url, - tna: 'cf' - }; - tracker.addPayloadPair('tna', 'mistake'); - tracker.resetPayloadPairs({'tna': 'cf'}); - - compare(tracker.trackPageView(url), expected, 'Payload name-value pairs should be reset correctly'); - }, - - "Execute a callback": function () { - var callbackTarget; - var tracker = core.trackerCore(false, function (payload) { - callbackTarget = payload; - }); - var url = 'http://www.example.com'; - var expected = { - e: 'pv', - url: url - }; - tracker.trackPageView(url); - - compare(callbackTarget, expected, 'The callback should be executed correctly'); - }, - - "Use setter methods": function () { - var tracker = core.trackerCore(false); - tracker.setTrackerVersion('js-3.0.0'); - tracker.setTrackerNamespace('cf1'); - tracker.setAppId('my-app'); - tracker.setPlatform('web'); - tracker.setUserId('jacob'); - tracker.setScreenResolution(400, 200); - tracker.setViewport(500, 800); - tracker.setColorDepth(24); - tracker.setTimezone('Europe London'); - tracker.setIpAddress('37.151.33.154'); - tracker.setUseragent('SnowplowJavascript/0.0.1'); - var url = 'http://www.example.com'; - var page = 'title page'; - var expected = { - e: 'pv', - url: url, - page: page, - tna: 'cf1', - tv: 'js-3.0.0', - aid: 'my-app', - p: 'web', - uid: 'jacob', - res: '400x200', - vp: '500x800', - cd: 24, - tz: 'Europe London', - ip: '37.151.33.154', - ua: 'SnowplowJavascript/0.0.1' - }; - - compare(tracker.trackPageView(url, page), expected, 'setXXX methods should work correctly'); - }, - - "Set true timestamp": function () { - var url = 'http://www.example.com'; - var page = 'title page'; - var result = tracker.trackPageView(url, page, null, null, { type: 'ttm', value: 1477403862 }).build(); - assert('ttm' in result, 'ttm should be attached'); - assert.strictEqual(result['ttm'] , '1477403862', 'ttm should be attached as is'); - assert(!('dtm' in result), 'dtm should absent'); - }, - - "Set device timestamp as ADT": function () { - - var inputJson = { - schema: 'iglu:com.acme/user/jsonschema/1-0-1', - data: { - name: 'Eric' - } - }; - - // Object structure should be enforced by typesystem - var result = tracker.trackSelfDescribingEvent(inputJson, [inputJson], {type: 'dtm', value: 1477403869}).build(); - assert('dtm' in result, 'dtm should be attached'); - assert.strictEqual(result['dtm'] , '1477403869', 'dtm should be attached as is'); - assert(!('ttm' in result), 'ttm should absent'); - } - }); - -}); diff --git a/core/tests/unit/payload.js b/core/tests/unit/payload.js deleted file mode 100644 index 6b2a654a0..000000000 --- a/core/tests/unit/payload.js +++ /dev/null @@ -1,121 +0,0 @@ -/* - * JavaScript tracker for Snowplow: tests/payload.js - * - * Copyright (c) 2014-2016 Snowplow Analytics Ltd. All rights reserved. - * - * This program is licensed to you under the Apache License Version 2.0, - * and you may not use this file except in compliance with the Apache License Version 2.0. - * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the Apache License Version 2.0 is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. - */ - -define([ - 'intern!object', - 'intern/chai!assert', - 'intern/dojo/node!../../lib/payload.js' -], function (registerSuite, assert, payload) { - - - var sampleJson = { - schema: 'iglu:com.snowplowanalytics.snowplow/contexts/jsonschema/1-0-0', - data: [ - { - schema: "iglu:com.example_company/page/jsonschema/1-2-1", - data: { - pageType: 'test', - lastUpdated: new Date(Date.UTC(2014, 1, 26)) - } - }, - { - schema: "iglu:com.example_company/user/jsonschema/2-0-0", - data: { - userType: 'tester' - } - } - ] - }; - - var expectedPayloads = [ - {co: '{"schema":"iglu:com.snowplowanalytics.snowplow/contexts/jsonschema/1-0-0","data":[{"schema":"iglu:com.example_company/page/jsonschema/1-2-1","data":{"pageType":"test","lastUpdated":"2014-02-26T00:00:00.000Z"}},{"schema":"iglu:com.example_company/user/jsonschema/2-0-0","data":{"userType":"tester"}}]}'}, - {cx: 'eyJzY2hlbWEiOiJpZ2x1OmNvbS5zbm93cGxvd2FuYWx5dGljcy5zbm93cGxvdy9jb250ZXh0cy9qc29uc2NoZW1hLzEtMC0wIiwiZGF0YSI6W3sic2NoZW1hIjoiaWdsdTpjb20uZXhhbXBsZV9jb21wYW55L3BhZ2UvanNvbnNjaGVtYS8xLTItMSIsImRhdGEiOnsicGFnZVR5cGUiOiJ0ZXN0IiwibGFzdFVwZGF0ZWQiOiIyMDE0LTAyLTI2VDAwOjAwOjAwLjAwMFoifX0seyJzY2hlbWEiOiJpZ2x1OmNvbS5leGFtcGxlX2NvbXBhbnkvdXNlci9qc29uc2NoZW1hLzItMC0wIiwiZGF0YSI6eyJ1c2VyVHlwZSI6InRlc3RlciJ9fV19'} - ]; - - registerSuite({ - - name: 'Payload test', - - 'Identify a JSON': function () { - var json = { - 'name': 'john', - 'properties': { - 'age': 30, - 'languages': ['English', 'French'] - } - }; - - assert.strictEqual(payload.isJson(json), true, 'JSON should be identified'); - }, - - 'Identify a non-JSON': function () { - var nonJson = function () {}; - - assert.strictEqual(payload.isJson(nonJson), false, 'Non-JSON should be rejected'); - }, - - 'Identify an empty JSON': function () { - var emptyJson = {}; - - assert.strictEqual(payload.isNonEmptyJson(emptyJson), false, '{} should be identified as empty'); - }, - - 'Build a payload': function () { - var sb = payload.payloadBuilder(false); - sb.add('e', 'pv'); - sb.add('tv', 'js-2.0.0'); - - assert.deepEqual(sb.build(), {e: 'pv', tv: 'js-2.0.0'}, 'Individual name-value pairs should be added to the payload'); - }, - - 'Do not add undefined values to a payload': function () { - var sb = payload.payloadBuilder(false); - sb.add('e', undefined); - - assert.deepEqual(sb.build(), {}, 'Undefined values should not be added to the payload'); - }, - - 'Do not add null values to a payload': function () { - var sb = payload.payloadBuilder(false); - sb.add('e', null); - - assert.deepEqual(sb.build(), {}, 'Null values should not be added to the payload'); - }, - - 'Add a dictionary of name-value pairs to the payload': function () { - var sb = payload.payloadBuilder(false); - sb.addDict({ - 'e': 'pv', - 'tv': 'js-2.0.0' - }); - - assert.deepEqual(sb.build(), {e: 'pv', tv: 'js-2.0.0'}, 'A dictionary of name-value pairs should be added to the payload'); - }, - - 'Add a JSON to the payload': function () { - var sb = payload.payloadBuilder(false); - sb.addJson('cx', 'co', sampleJson); - - assert.deepEqual(sb.build(), expectedPayloads[0], 'JSON should be added correctly'); - }, - - 'Add a base 64 encoded JSON to the payload': function () { - var sb = payload.payloadBuilder(true); - sb.addJson('cx', 'co', sampleJson); - - assert.deepEqual(sb.build(), expectedPayloads[1], 'JSON should be encoded correctly'); - } - }); -}); diff --git a/core/tsconfig.json b/core/tsconfig.json deleted file mode 100644 index 5269c9392..000000000 --- a/core/tsconfig.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "target": "es5", - "module": "commonjs", - "moduleResolution": "node", - "isolatedModules": false, - "experimentalDecorators": true, - "emitDecoratorMetadata": true, - "declaration": false, - "noImplicitAny": false, - "noImplicitUseStrict": false, - "strictNullChecks": true, - "removeComments": true, - "noLib": false, - "preserveConstEnums": true, - "suppressImplicitAnyIndexErrors": true - }, - "exclude": [ - "node_modules" - ], - "compileOnSave": true, - "buildOnSave": false, - "atom": { - "rewriteTsconfig": false - } -} diff --git a/core/tslint.json b/core/tslint.json deleted file mode 100644 index 61b62f2a3..000000000 --- a/core/tslint.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rules": { - "indent": [true, "tabs"] - } -} diff --git a/dist/.gitignore b/dist/.gitignore deleted file mode 100644 index 772552e83..000000000 --- a/dist/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# Assembled files -bundle.js -snowplow.js -sp.js -bundle-postbabel.js diff --git a/examples/ads/async.html b/examples/ads/async.html deleted file mode 100644 index c82b90419..000000000 --- a/examples/ads/async.html +++ /dev/null @@ -1,164 +0,0 @@ - - - - - Asynchronous ad tracking examples for snowplow.js - - -

For each banner, viewing that banner fires an ad impression event and clicking it fires an ad click event.

- -

Click the first banner and on the button that appears to fire an ad conversion event.

- - -

Asynchronous ad tracking examples for snowplow.js

- -

- - Banner ID 23, zone ID 7, campaign ID 12, advertiser ID 201 - - - -

- -

- - Banner ID 127, no campaign or advertiser ID set - - - -

- -

- - Banner ID 56ea2819ffc7da75f7e, no campaign, advertiser or user ID set - - - -

- - - diff --git a/examples/ads/images/banner-1.png b/examples/ads/images/banner-1.png deleted file mode 100644 index 897cdfdbe..000000000 Binary files a/examples/ads/images/banner-1.png and /dev/null differ diff --git a/examples/ads/images/banner-2.png b/examples/ads/images/banner-2.png deleted file mode 100644 index 689d0ee06..000000000 Binary files a/examples/ads/images/banner-2.png and /dev/null differ diff --git a/examples/ads/images/banner-3.png b/examples/ads/images/banner-3.png deleted file mode 100644 index 6c235173b..000000000 Binary files a/examples/ads/images/banner-3.png and /dev/null differ diff --git a/examples/sp.js b/examples/sp.js deleted file mode 100644 index dda81fc4f..000000000 --- a/examples/sp.js +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Snowplow - The world's most powerful web analytics platform - * - * @description JavaScript tracker for Snowplow - * @version 2.14.0 - * @author Alex Dean, Simon Andersson, Anthon Pang, Fred Blundun, Joshua Beemster, Michael Hadam, Paul Boocock - * @copyright Anthon Pang, Snowplow Analytics Ltd - * @license Simplified BSD - * - * For technical documentation: - * https://github.com/snowplow/snowplow/wiki/javascript-tracker - * - * For the setup guide: - * https://github.com/snowplow/snowplow/wiki/javascript-tracker-setup - * - * Minimum supported browsers: - * - Firefox 27 - * - Chrome 32 - * - IE 9 - * - Safari 8 - */ - -"use strict";function ownKeys(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,r)}return n}function _objectSpread(t){for(var e=1;e>>32-t},rotr:function(e,t){return e<<32-t|e>>>t},endian:function(e){if(e.constructor==Number)return 16711935&r.rotl(e,8)|4278255360&r.rotl(e,24);for(var t=0;t>>5]|=e[n]<<24-r%32;return t},wordsToBytes:function(e){for(var t=[],n=0;n<32*e.length;n+=8)t.push(e[n>>>5]>>>24-n%32&255);return t},bytesToHex:function(e){for(var t=[],n=0;n>>4).toString(16)),t.push((15&e[n]).toString(16));return t.join("")},hexToBytes:function(e){for(var t=[],n=0;n>>6*(3-a)&63)):t.push("=");return t.join("")},base64ToBytes:function(e){e=e.replace(/[^A-Z0-9+\/]/gi,"");for(var t=[],n=0,r=0;n>>6-2*r);return t}},t.exports=r},{}],3:[function(e,t,n){function a(e){var t=-e.getTimezoneOffset();return null!==t?t:0}function r(e,t,n){var r=new Date;return void 0!==e&&r.setFullYear(e),r.setMonth(t),r.setDate(n),r}function o(e){return a(r(e,0,2))}function i(e){return a(r(e,5,2))}var c,s;c=this,(s={determine:function(){var e=function(){var e=o(),t=i(),n=e-t;return n<0?e+",1":0>5]|=128<<24-n%32,t[15+(64+n>>>9<<4)]=n;for(var u=0;u>>31}var g=(a<<5|a>>>27)+s+(r[v]>>>0)+(v<20?1518500249+(o&i|~o&c):v<40?1859775393+(o^i^c):v<60?(o&i|o&c|i&c)-1894007588:(o^i^c)-899497514);s=c,c=i,i=o<<30|o>>>2,o=a,a=g}a+=l,o+=f,i+=d,c+=p,s+=m}return[a,o,i,c,s]}(e));return t&&t.asBytes?n:t&&t.asString?a.bytesToString(n):y.bytesToHex(n)}var y,_,a;y=e("crypt"),_=e("charenc").utf8,a=e("charenc").bin,r._blocksize=16,r._digestsize=20,t.exports=r},{charenc:1,crypt:2}],153:[function(e,t,n){Object.defineProperty(n,"__esModule",{value:!0});var r=e("./lib/core");n.trackerCore=r.trackerCore},{"./lib/core":156}],154:[function(e,t,n){function r(e){var t,n,r,a,o,i,c,s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",u=0,l=0,f="",d=[];if(!e)return e;for(e+="";t=(i=s.indexOf(e.charAt(u++))<<18|s.indexOf(e.charAt(u++))<<12|(a=s.indexOf(e.charAt(u++)))<<6|(o=s.indexOf(e.charAt(u++))))>>16&255,n=i>>8&255,r=255&i,d[l++]=64===a?String.fromCharCode(t):64===o?String.fromCharCode(t,n):String.fromCharCode(t,n,r),u>18&63,n=o>>12&63,r=o>>6&63,a=63&o,l[u++]=c.charAt(t)+c.charAt(n)+c.charAt(r)+c.charAt(a),s>>((3&t)<<3)&255;return a}}o.exports=t}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],159:[function(e,t,n){for(var i=e("./rng"),a=[],o={},r=0;r<256;r++)a[r]=(r+256).toString(16).substr(1),o[a[r]]=r;function p(e,t){var n=t||0,r=a;return r[e[n++]]+r[e[n++]]+r[e[n++]]+r[e[n++]]+"-"+r[e[n++]]+r[e[n++]]+"-"+r[e[n++]]+r[e[n++]]+"-"+r[e[n++]]+r[e[n++]]+"-"+r[e[n++]]+r[e[n++]]+r[e[n++]]+r[e[n++]]+r[e[n++]]+r[e[n++]]}var c=i(),m=[1|c[0],c[1],c[2],c[3],c[4],c[5]],v=16383&(c[6]<<8|c[7]),h=0,g=0;function s(e,t,n){var r=t&&n||0;"string"==typeof e&&(t="binary"==e?new Array(16):null,e=null);var a=(e=e||{}).random||(e.rng||i)();if(a[6]=15&a[6]|64,a[8]=63&a[8]|128,t)for(var o=0;o<16;o++)t[r+o]=a[o];return t||p(a)}var u=s;u.v1=function(e,t,n){var r=t&&n||0,a=t||[],o=void 0!==(e=e||{}).clockseq?e.clockseq:v,i=void 0!==e.msecs?e.msecs:(new Date).getTime(),c=void 0!==e.nsecs?e.nsecs:g+1,s=i-h+(c-g)/1e4;if(s<0&&void 0===e.clockseq&&(o=o+1&16383),(s<0||h>>24&255,a[r++]=u>>>16&255,a[r++]=u>>>8&255,a[r++]=255&u;var l=i/4294967296*1e4&268435455;a[r++]=l>>>8&255,a[r++]=255&l,a[r++]=l>>>24&15|16,a[r++]=l>>>16&255,a[r++]=o>>>8|128,a[r++]=255&o;for(var f=e.node||m,d=0;d<6;d++)a[r+d]=f[d];return t||p(a)},u.v4=s,u.parse=function(e,t,n){var r=t&&n||0,a=0;for(t=t||[],e.toLowerCase().replace(/[0-9a-f]{2}/g,function(e){a<16&&(t[r+a++]=o[e])});a<16;)t[r+a++]=0;return t},u.unparse=p,t.exports=u},{"./rng":158}],160:[function(e,t,n){var r=e("./v1"),a=e("./v4"),o=a;o.v1=r,o.v4=a,t.exports=o},{"./v1":163,"./v4":164}],161:[function(e,t,n){for(var a=[],r=0;r<256;++r)a[r]=(r+256).toString(16).substr(1);t.exports=function(e,t){var n=t||0,r=a;return[r[e[n++]],r[e[n++]],r[e[n++]],r[e[n++]],"-",r[e[n++]],r[e[n++]],"-",r[e[n++]],r[e[n++]],"-",r[e[n++]],r[e[n++]],"-",r[e[n++]],r[e[n++]],r[e[n++]],r[e[n++]],r[e[n++]],r[e[n++]]].join("")}},{}],162:[function(e,t,n){var r="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||"undefined"!=typeof msCrypto&&"function"==typeof window.msCrypto.getRandomValues&&msCrypto.getRandomValues.bind(msCrypto);if(r){var a=new Uint8Array(16);t.exports=function(){return r(a),a}}else{var o=new Array(16);t.exports=function(){for(var e,t=0;t<16;t++)0==(3&t)&&(e=4294967296*Math.random()),o[t]=e>>>((3&t)<<3)&255;return o}}},{}],163:[function(e,t,n){var m,v,h=e("./lib/rng"),g=e("./lib/bytesToUuid"),y=0,_=0;t.exports=function(e,t,n){var r=t&&n||0,a=t||[],o=(e=e||{}).node||m,i=void 0!==e.clockseq?e.clockseq:v;if(null==o||null==i){var c=h();null==o&&(o=m=[1|c[0],c[1],c[2],c[3],c[4],c[5]]),null==i&&(i=v=16383&(c[6]<<8|c[7]))}var s=void 0!==e.msecs?e.msecs:(new Date).getTime(),u=void 0!==e.nsecs?e.nsecs:_+1,l=s-y+(u-_)/1e4;if(l<0&&void 0===e.clockseq&&(i=i+1&16383),(l<0||y>>24&255,a[r++]=f>>>16&255,a[r++]=f>>>8&255,a[r++]=255&f;var d=s/4294967296*1e4&268435455;a[r++]=d>>>8&255,a[r++]=255&d,a[r++]=d>>>24&15|16,a[r++]=d>>>16&255,a[r++]=i>>>8|128,a[r++]=255&i;for(var p=0;p<6;++p)a[r+p]=o[p];return t||g(a)}},{"./lib/bytesToUuid":161,"./lib/rng":162}],164:[function(e,t,n){var i=e("./lib/rng"),c=e("./lib/bytesToUuid");t.exports=function(e,t,n){var r=t&&n||0;"string"==typeof e&&(t="binary"===e?new Array(16):null,e=null);var a=(e=e||{}).random||(e.rng||i)();if(a[6]=15&a[6]|64,a[8]=63&a[8]|128,t)for(var o=0;o<16;++o)t[r+o]=a[o];return t||c(a)}},{"./lib/bytesToUuid":161,"./lib/rng":162}],165:[function(e,t,n){var o=e("lodash/isFunction"),i=e("./lib/helpers"),s=window;(void 0!==n?n:this).errorManager=function(c){function a(e,t,n,r,a,o){var i=a&&a.stack?a.stack:null;c.trackSelfDescribingEvent({schema:"iglu:com.snowplowanalytics.snowplow/application_error/jsonschema/1-0-1",data:{programmingLanguage:"JAVASCRIPT",message:e||"JS Exception. Browser doesn't support ErrorEvent API",stackTrace:i,lineNumber:n,lineColumn:r,fileName:t}},o)}return{trackError:a,enableErrorTracking:function(t,n,r){i.addEventListener(s,"error",function(e){(o(t)&&t(e)||null==t)&&function(e,t,n){var r;r=o(n)?t.concat(n(e)):t,a(e.message,e.filename,e.lineno,e.colno,e.error,r)}(e,r,n)},!0)}}}},{"./lib/helpers":171,"lodash/isFunction":132}],166:[function(e,t,n){var p=e("lodash/forEach"),m=e("lodash/filter"),v=e("lodash/find"),h=e("./lib/helpers");(void 0!==n?n:this).getFormTrackingManager=function(i,e,c){var a=["textarea","input","select"],o=e+"form",r=function(){return!0},s=function(){return!0},u=function(e){return e};function l(t){return t[v(["name","id","type","nodeName"],function(e){return t[e]&&"string"==typeof t[e]})]}function f(a,o){return function(e){var t=e.target,n=t.nodeName&&"INPUT"===t.nodeName.toUpperCase()?t.type:null,r="checkbox"!==t.type||t.checked?u(t.value):null;("change_form"===a||"checkbox"!==n&&"radio"!==n)&&i.trackFormFocusOrChange(a,function(e){for(;e&&e.nodeName&&"HTML"!==e.nodeName.toUpperCase()&&"FORM"!==e.nodeName.toUpperCase();)e=e.parentNode;if(e&&e.nodeName&&"FORM"===e.nodeName.toUpperCase())return l(e)}(t),l(t),t.nodeName,n,h.getCssClasses(t),r,c(h.resolveDynamicContexts(o,t,n,r)))}}function d(r){return function(e){var t=e.target,n=function(n){var r=[];return p(a,function(e){var t=m(n.getElementsByTagName(e),function(e){return e.hasOwnProperty(o)});p(t,function(e){if("submit"!==e.type){var t={name:l(e),value:e.value,nodeName:e.nodeName};e.type&&"INPUT"===e.nodeName.toUpperCase()&&(t.type=e.type),"checkbox"!==e.type&&"radio"!==e.type||e.checked||(t.value=null),r.push(t)}})}),r}(t);p(n,function(e){e.value=u(e.value)}),i.trackFormSubmission(l(t),h.getCssClasses(t),n,c(h.resolveDynamicContexts(r,t,n)))}}return{configureFormTracking:function(e){e&&(r=h.getFilter(e.forms,!0),s=h.getFilter(e.fields,!1),u=h.getTransform(e.fields))},addFormListeners:function(n){p(document.getElementsByTagName("form"),function(t){r(t)&&!t[o]&&(p(a,function(e){p(t.getElementsByTagName(e),function(e){s(e)&&!e[o]&&"password"!==e.type.toLowerCase()&&(h.addEventListener(e,"focus",f("focus_form",n),!1),h.addEventListener(e,"change",f("change_form",n),!1),e[o]=!0)})}),h.addEventListener(t,"submit",d(n)),t[o]=!0)})}}}},{"./lib/helpers":171,"lodash/filter":119,"lodash/find":120,"lodash/forEach":122}],167:[function(e,t,n){n.productionize=function(r){var a={};return"object"===_typeof(r)&&null!==r&&Object.getOwnPropertyNames(r).forEach(function(e,t,n){"function"==typeof r[e]&&(a[e]=function(e){return function(){try{return e.apply(this,arguments)}catch(e){}}}(r[e]))}),a}},{}],168:[function(e,t,n){!function(){var c=e("lodash/map"),h=e("lodash/isUndefined"),g=e("lodash/isFunction"),y=e("./lib/helpers");(void 0!==n?n:this).InQueueManager=function(r,a,o,e,i){var p={};function m(e){var t=[];if(e&&0!==e.length)for(var n=0;nDate.now()?localStorage.getItem(e):(localStorage.removeItem(e),void localStorage.removeItem(e+".expires"))}catch(e){}},s.attemptWriteLocalStorage=function(e,t){var n=2=l)return T.warn("Event of size "+n.bytes+" is too long - the maximum size is "+l),void k(m).send(A(x([n.evt])));v.push(n)}else v.push(function(e){var t="?",n={co:!0,cx:!0},r=!0;for(var a in e)e.hasOwnProperty(a)&&!n.hasOwnProperty(a)&&(r?r=!1:t+="&",t+=encodeURIComponent(a)+"="+encodeURIComponent(e[a]));for(var o in n)e.hasOwnProperty(o)&&n.hasOwnProperty(o)&&(t+="&"+o+"="+encodeURIComponent(e[o]));return t}(e));var r=!1;u&&(r=T.attemptWriteLocalStorage(p,JSON.stringify(v.slice(0,d)))),y||r&&!(v.length>=o)||w()},executeQueue:w}}}()},{"./lib/detectors":170,"./lib/helpers":171,"lodash/isString":137,"lodash/map":142,"lodash/mapValues":143}],175:[function(e,t,n){!function(){e("uuid");var s=e("lodash/forEach"),u=e("lodash/filter"),l=e("./lib/helpers"),f=e("./in_queue"),d=e("./tracker");(void 0!==n?n:this).Snowplow=function(e,n){var t,r=document,a=window,o="js-2.14.0",i={outQueues:[],bufferFlushers:[],expireDateTime:null,hasLoaded:!1,registeredOnLoadHandlers:[],pageViewId:null};function c(){var e;if(!i.hasLoaded)for(i.hasLoaded=!0,e=0;e1e3*X&&(b=ht.v4(),le++);e.add("vp",st.detectViewport()),e.add("ds",st.detectDocumentSize()),e.add("vid",le),e.add("sid",b),e.add("duid",s),e.add("uid",w),Se(),e.add("refr",Oe(m||F)),e.add("url",Oe(v||N)),"none"!=ae&&(Ue(s,u,le,n,d,b),ze());se=(new Date).getTime()}(e),function(e,t){var n,r=new Date;n=!!h&&!!it.cookie(h);Q||n||(ve.enqueueRequest(e.build(),a),f.expireDateTime=r.getTime()+t)}(e,R)}),j=!1,O={},T={},P={},I=document,E=window,D=navigator,L=ct.fixupUrl(I.domain,E.location.href,it.getReferrer()),M=it.fixupDomain(L[0]),N=L[1],F=L[2],z=r.hasOwnProperty("platform")?r.platform:"web",U=r.hasOwnProperty("postPath")?r.postPath:"/com.snowplowanalytics.snowplow/tp2",B=r.hasOwnProperty("appId")?r.appId:"",G=I.title,R=r.hasOwnProperty("pageUnloadTimer")?r.pageUnloadTimer:500,q=!r.hasOwnProperty("resetActivityTrackingOnPageView")||r.resetActivityTrackingOnPageView,V=r.hasOwnProperty("cookieName")?r.cookieName:"_sp_",H=r.hasOwnProperty("cookieDomain")?r.cookieDomain:null,K="/",W=r.hasOwnProperty("cookieSameSite")?r.cookieSameSite:"None",J=!r.hasOwnProperty("cookieSecure")||r.cookieSecure,Y=D.doNotTrack||D.msDoNotTrack||E.doNotTrack,Q=!!r.hasOwnProperty("respectDoNotTrack")&&(r.respectDoNotTrack&&("yes"===Y||"1"===Y)),$=r.hasOwnProperty("cookieLifetime")?r.cookieLifetime:63072e3,X=r.hasOwnProperty("sessionCookieTimeout")?r.sessionCookieTimeout:1800,Z=I.characterSet||I.charset,ee=!!r.hasOwnProperty("forceSecureTracker")&&!0===r.forceSecureTracker,te=!(ee||!r.hasOwnProperty("forceUnsecureTracker"))&&!0===r.forceUnsecureTracker,ne=!r.hasOwnProperty("useLocalStorage")||(it.warn("argmap.useLocalStorage is deprecated. Use argmap.stateStorageStrategy instead."),r.useLocalStorage),re=!r.hasOwnProperty("useCookies")||(it.warn("argmap.useCookies is deprecated. Use argmap.stateStorageStrategy instead."),r.useCookies),ae=r.hasOwnProperty("stateStorageStrategy")?r.stateStorageStrategy:re||ne?re&&ne?"cookieAndLocalStorage":re?"cookie":"localStorage":"none",oe=D.userLanguage||D.language,ie=st.detectBrowserFeatures("cookie"==ae||"cookieAndLocalStorage"==ae,Pe("testcookie")),ce=e+"_"+t,se=(new Date).getTime(),ue=ut,le=1,fe={transaction:{},items:[]},de=lt.getLinkTrackingManager(C,ce,qe),pe=ft.getFormTrackingManager(C,ce,qe),me=dt.errorManager(C),ve=new pt.OutQueueManager(e,t,f,"localStorage"==ae||"cookieAndLocalStorage"==ae,r.eventMethod,U,r.bufferSize,r.maxPostBytes||4e4,r.useStm,r.maxLocalStorageQueueSize||1e3),he=!1,ge=r.contexts||{},ye=[],_e=[],be=!1,we=!1,ke={enabled:!1,installed:!1,configurations:{}},Ae={};for(var xe in r.hasOwnProperty("discoverRootDomain")&&r.discoverRootDomain&&(H=it.findRootDomain()),ge.gaCookies&&ye.push((k={},at(["__utma","__utmb","__utmc","__utmv","__utmz","_ga"],function(e){var t=it.cookie(e);t&&(k[e]=t)}),{schema:"iglu:com.google.analytics/cookies/jsonschema/1-0-0",data:k})),ge.geolocation&&We(),C.setBase64Encoding(!r.hasOwnProperty("encodeBase64")||r.encodeBase64),C.setTrackerVersion(n),C.setTrackerNamespace(t),C.setAppId(B),C.setPlatform(z),C.setTimezone(st.detectTimezone()),C.addPayloadPair("lang",oe),C.addPayloadPair("cs",Z),ie)Object.prototype.hasOwnProperty.call(ie,xe)&&("res"===xe||"cd"===xe||"cookie"===xe?C.addPayloadPair(xe,ie[xe]):C.addPayloadPair("f_"+xe,ie[xe]));function Se(){(L=ct.fixupUrl(I.domain,E.location.href,it.getReferrer()))[1]!==N&&(F=it.getReferrer(N)),M=it.fixupDomain(L[0]),N=L[1]}function Ce(){var e=(new Date).getTime();this.href&&(this.href=it.decorateQuerystring(this.href,"_sp",_+"."+e))}function je(e){for(var t=0;te.getTime()&&r+1e3*n - - - - Small asynchronous website/webapp examples for snowplow.js - - - - - - - - - - - - - -
-

Collected events

- - - - - - - - - - -
PageIdY minY maxEvents
- -
- -
-

Small asynchronous examples for snowplow

- -

- This page provides examples of using - enableActivityTrackingCallback. -

-

Scroll to trigger activity events.

-

- Trigger a page visibility event (select another tab in your browser then - come back) for data collection examples. -

-
- -
- - - -

Setup

-

-// Assuming only one trackPageView per page load we can track
-// values as globals. View page source for an example allowing for multiple trackPageView calls
-var aggregatedEvents = {
-	pageViewId: null,
-	minXOffset: null,
-	maxXOffset: null,
-	minYOffset: null,
-	maxYOffset: null,
-	numEvents: 0
-};
-window.snowplow('enableActivityTrackingCallback', 5, 5, function (event) {
-	aggregatedEvents = {
-		pageViewId: event.pageViewId,
-		minXOffset: aggregatedEvents.minXOffset < event.minXOffset ? aggregatedEvents.minXOffset : event.minXOffset,
-		maxYOffset: aggregatedEvents.maxYOffset > event.maxYOffset ? aggregatedEvents.maxYOffset : event.maxYOffset,
-		minYOffset: aggregatedEvents.minYOffset < event.minYOffset ? aggregatedEvents.minYOffset : event.minYOffset,
-		maxYOffset: aggregatedEvents.maxYOffset > event.maxYOffset ? aggregatedEvents.maxYOffset : event.maxYOffset,
-		numEvents: event.numEvents + 1
-	};
-}) // Call callback every 5 seconds after 5 seconds
-
-// Must call trackPageView to start tracking
-window.snowplow('trackPageView')
-		
- -

- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod - tempor incididunt ut labore et dolore magna aliqua. Eget arcu dictum - varius duis at consectetur lorem donec. Posuere urna nec tincidunt - praesent semper feugiat. Lacus sed turpis tincidunt id aliquet risus. - Augue lacus viverra vitae congue eu consequat. Viverra aliquet eget sit - amet tellus cras adipiscing enim. Diam sit amet nisl suscipit adipiscing - bibendum est ultricies. Elementum curabitur vitae nunc sed velit - dignissim. Ipsum nunc aliquet bibendum enim facilisis gravida. Id donec - ultrices tincidunt arcu non sodales neque. Neque gravida in fermentum et - sollicitudin ac orci phasellus egestas. In egestas erat imperdiet sed - euismod nisi porta lorem mollis. Tristique senectus et netus et. Accumsan - tortor posuere ac ut consequat semper. Rhoncus urna neque viverra justo - nec ultrices dui sapien. Proin nibh nisl condimentum id. Ultricies leo - integer malesuada nunc. Amet nisl suscipit adipiscing bibendum. Tristique - senectus et netus et malesuada fames ac turpis. Rutrum quisque non tellus - orci ac auctor augue. -

- -

- Ornare arcu dui vivamus arcu felis bibendum ut. Nunc congue nisi vitae - suscipit tellus mauris a. Iaculis urna id volutpat lacus laoreet non. - Sagittis id consectetur purus ut faucibus. Vestibulum lorem sed risus - ultricies tristique nulla aliquet. Eget lorem dolor sed viverra ipsum nunc - aliquet bibendum. Vitae congue mauris rhoncus aenean. Sit amet nisl - suscipit adipiscing bibendum est ultricies integer. Elit eget gravida cum - sociis natoque. Tempus iaculis urna id volutpat lacus laoreet non - curabitur gravida. Senectus et netus et malesuada. -

- -

- Cras sed felis eget velit. Sed viverra ipsum nunc aliquet bibendum enim - facilisis gravida neque. Mattis enim ut tellus elementum sagittis vitae - et. Velit sed ullamcorper morbi tincidunt ornare massa eget egestas. Nec - nam aliquam sem et tortor consequat. Curabitur vitae nunc sed velit - dignissim sodales ut. Id cursus metus aliquam eleifend mi in nulla. Et - sollicitudin ac orci phasellus egestas tellus. Nullam eget felis eget nunc - lobortis mattis aliquam faucibus. Placerat orci nulla pellentesque - dignissim enim sit. -

- -

- Congue eu consequat ac felis donec et odio. Imperdiet massa tincidunt nunc - pulvinar sapien et ligula. Eu ultrices vitae auctor eu augue ut. Cursus - metus aliquam eleifend mi in nulla. Est velit egestas dui id ornare arcu - odio ut sem. Est pellentesque elit ullamcorper dignissim cras tincidunt - lobortis feugiat. Tempor orci dapibus ultrices in iaculis nunc. Tincidunt - tortor aliquam nulla facilisi. Faucibus pulvinar elementum integer enim - neque. Commodo quis imperdiet massa tincidunt nunc. Nec dui nunc mattis - enim ut tellus elementum sagittis vitae. Diam in arcu cursus euismod quis - viverra nibh cras pulvinar. Morbi tempus iaculis urna id volutpat lacus - laoreet. Pulvinar elementum integer enim neque volutpat ac. Diam sit amet - nisl suscipit adipiscing bibendum est ultricies. Ut aliquam purus sit amet - luctus venenatis lectus. Turpis tincidunt id aliquet risus feugiat in ante - metus. Sit amet volutpat consequat mauris nunc congue nisi. Quam vulputate - dignissim suspendisse in est. Est ullamcorper eget nulla facilisi etiam - dignissim diam quis enim. -

- -

- Amet mattis vulputate enim nulla aliquet porttitor lacus luctus. Amet - mauris commodo quis imperdiet massa tincidunt. Maecenas ultricies mi eget - mauris pharetra et ultrices. Egestas fringilla phasellus faucibus - scelerisque eleifend donec pretium vulputate. Egestas quis ipsum - suspendisse ultrices gravida dictum fusce ut. Facilisi nullam vehicula - ipsum a arcu cursus vitae congue. Nunc congue nisi vitae suscipit. Pretium - lectus quam id leo in vitae. In est ante in nibh mauris cursus mattis. - Tellus in metus vulputate eu scelerisque felis imperdiet. Hac habitasse - platea dictumst vestibulum rhoncus est pellentesque. -

- -

- Erat pellentesque adipiscing commodo elit at imperdiet dui accumsan sit. - Nibh praesent tristique magna sit amet purus gravida. Metus vulputate eu - scelerisque felis imperdiet proin fermentum. Sed vulputate mi sit amet - mauris. Egestas purus viverra accumsan in nisl nisi scelerisque eu. - Viverra vitae congue eu consequat ac felis donec et. Et netus et malesuada - fames ac turpis egestas maecenas pharetra. Nibh cras pulvinar mattis nunc - sed blandit libero. Pulvinar mattis nunc sed blandit libero volutpat sed - cras. Id aliquet risus feugiat in ante metus. Penatibus et magnis dis - parturient montes nascetur ridiculus. Faucibus purus in massa tempor nec - feugiat nisl. Sit amet volutpat consequat mauris. Sodales ut etiam sit - amet. -

- -

- Cursus eget nunc scelerisque viverra mauris in aliquam. Est ante in nibh - mauris cursus mattis molestie a iaculis. Amet nisl purus in mollis nunc - sed id. Ultricies mi quis hendrerit dolor magna eget est lorem. Feugiat - nisl pretium fusce id velit ut tortor pretium. Sed risus pretium quam - vulputate dignissim suspendisse in est. Sodales neque sodales ut etiam sit - amet nisl purus in. Tristique sollicitudin nibh sit amet commodo nulla. - Iaculis eu non diam phasellus vestibulum lorem sed risus. Risus pretium - quam vulputate dignissim suspendisse in est ante. Justo eget magna - fermentum iaculis eu non diam phasellus vestibulum. -

- -

- Cursus vitae congue mauris rhoncus aenean vel. Donec et odio pellentesque - diam volutpat commodo. Id semper risus in hendrerit gravida rutrum - quisque. Cras sed felis eget velit. Pharetra et ultrices neque ornare. - Felis eget velit aliquet sagittis id consectetur purus ut. Metus aliquam - eleifend mi in nulla posuere sollicitudin aliquam ultrices. Mauris cursus - mattis molestie a iaculis. Sodales ut eu sem integer vitae justo eget - magna fermentum. Amet volutpat consequat mauris nunc congue nisi. Interdum - posuere lorem ipsum dolor sit amet consectetur adipiscing elit. Mauris - commodo quis imperdiet massa tincidunt nunc pulvinar sapien et. Id - consectetur purus ut faucibus pulvinar elementum integer enim. Sed viverra - tellus in hac habitasse platea dictumst vestibulum. Quisque egestas diam - in arcu cursus euismod quis viverra. Sit amet venenatis urna cursus eget - nunc scelerisque. Tempus quam pellentesque nec nam. -

- -

- Ornare quam viverra orci sagittis eu. Ut faucibus pulvinar elementum - integer enim neque volutpat ac tincidunt. Sapien et ligula ullamcorper - malesuada proin libero. Morbi blandit cursus risus at ultrices mi tempus - imperdiet. Vulputate mi sit amet mauris commodo quis imperdiet massa - tincidunt. Vitae ultricies leo integer malesuada nunc vel risus commodo - viverra. Ipsum nunc aliquet bibendum enim facilisis gravida neque - convallis a. Id semper risus in hendrerit gravida rutrum quisque non. Orci - dapibus ultrices in iaculis nunc sed. Pulvinar mattis nunc sed blandit - libero volutpat sed. Purus faucibus ornare suspendisse sed nisi lacus. - Tristique senectus et netus et malesuada fames ac turpis egestas. Ac ut - consequat semper viverra nam libero. Mauris pharetra et ultrices neque - ornare aenean. Tincidunt praesent semper feugiat nibh sed pulvinar. Sed - tempus urna et pharetra pharetra massa massa ultricies. -

- -

- Ut tellus elementum sagittis vitae et leo duis. Vivamus arcu felis - bibendum ut tristique et egestas quis ipsum. Ut lectus arcu bibendum at - varius vel pharetra vel. Laoreet sit amet cursus sit amet. Sollicitudin - nibh sit amet commodo nulla. Ullamcorper velit sed ullamcorper morbi - tincidunt ornare. Sit amet consectetur adipiscing elit duis tristique - sollicitudin. Morbi blandit cursus risus at ultrices mi tempus imperdiet - nulla. Duis convallis convallis tellus id interdum velit laoreet id donec. - Massa vitae tortor condimentum lacinia. -

- - diff --git a/examples/web/async-large.html b/examples/web/async-large.html deleted file mode 100644 index f872ea5b9..000000000 --- a/examples/web/async-large.html +++ /dev/null @@ -1,277 +0,0 @@ - - - - - Large asynchronous website/webapp examples for snowplow.js - - - - - - - - - - - - - - - -

Large_asynchronous_examples_for_snowplow.js

-

This shows how two users can simultaneously use Snowplow on the same page without any clash

-

Warning: if your browser's Do Not Track feature is enabled and respectDoNotTrack is enabled, all tracking will be prevented.

-

If you are viewing the page using a file URL, you must edit the script URL in the Snowplow tag to include an http scheme. Otherwise a file scheme will be inferred and the page will attempt to load sp.js from the local filesystem..

-

Press the buttons below to trigger individual tracking events:
-
-
-
-
-
-
-
- -

-

- Middle click the links to trigger link click tracking:
- - Link -
- Link ignored by one user -

- -

- Fill in the form fields and click the button to trigger form tracking: -

-
- Male
- Female
-
-
-
-
- Add me to the mailing list -
- -
-

- - - - diff --git a/examples/web/async-medium.html b/examples/web/async-medium.html deleted file mode 100644 index cbf808c6d..000000000 --- a/examples/web/async-medium.html +++ /dev/null @@ -1,191 +0,0 @@ - - - - - Medium asynchronous website/webapp examples for snowplow.js - - - - - - - - - - - -

Medium_asynchronous_examples_for_snowplow.js

-

Two tracker namespaces are instantiated on this page.

-

Warning: if your browser's Do Not Track feature is enabled and respectDoNotTrack is enabled, all tracking will be prevented.

-

If you are viewing the page using a file URL, you must edit the script URL in the Snowplow tag to include an http scheme. Otherwise a file scheme will be inferred and the page will attempt to load sp.js from the local filesystem..

-

Press the buttons below to trigger individual tracking events:
-
-
-
- -

- Both trackers will track this link -
- Only the cf tracker will track this link -
- Neither tracker will track this link - - - - diff --git a/examples/web/async-small.html b/examples/web/async-small.html deleted file mode 100644 index b4dd8ac15..000000000 --- a/examples/web/async-small.html +++ /dev/null @@ -1,168 +0,0 @@ - - - - - Small asynchronous website/webapp examples for snowplow.js - - - - - - - - - - - -

Small_asynchronous_examples_for_snowplow.js

- -

Warning: if your browser's Do Not Track feature is enabled and respectDoNotTrack is enabled, all tracking will be prevented.

-

If you are viewing the page using a file URL, you must edit the script URL in the Snowplow tag to include an http scheme. Otherwise a file scheme will be inferred and the page will attempt to load sp.js from the local filesystem..

- -

Press the buttons below to trigger individual tracking events:
-
-
-
- -

- Link -
- Ignored link - - - - diff --git a/examples/web/sync.html b/examples/web/sync.html deleted file mode 100644 index 87da068f6..000000000 --- a/examples/web/sync.html +++ /dev/null @@ -1,73 +0,0 @@ - - - - - Synchronous website/webapp examples for snowplow.js - - - - - - - - - - - - -

Synchronous examples for snowplow.js

-

Warning: if your browser's Do Not Track feature is enabled and respectDoNotTrack is enabled, all tracking will be prevented.

-

If you are viewing the page using a file URL, you must edit the script URL in the Snowplow tag to include an http scheme. Otherwise a file scheme will be inferred and the page will attempt to load sp.js from the local filesystem..

-

Press the buttons below to trigger individual tracking events:
-
-
- -

- - - diff --git a/libraries/browser-tracker-core/CHANGELOG.json b/libraries/browser-tracker-core/CHANGELOG.json new file mode 100644 index 000000000..f68a4ad1c --- /dev/null +++ b/libraries/browser-tracker-core/CHANGELOG.json @@ -0,0 +1,930 @@ +{ + "name": "@snowplow/browser-tracker-core", + "entries": [ + { + "version": "4.10.0", + "tag": "@snowplow/browser-tracker-core_v4.10.0", + "date": "Mon, 27 Jul 2026 13:52:14 GMT", + "comments": { + "minor": [ + { + "comment": "Add disableSessionContextWithinWebView option to suppress client_session entity in hybrid native+WebView deployments" + } + ], + "none": [ + { + "comment": "Add preserveOriginalReferrer tracker configuration option for SPA referrer tracking" + } + ], + "patch": [ + { + "comment": "Remove forced layout read from tracker initialization: replace init-time getBrowserProperties() call with direct non-layout reads; defer the first readBrowserProperties() to first event build time." + } + ] + } + }, + { + "version": "4.9.0", + "tag": "@snowplow/browser-tracker-core_v4.9.0", + "date": "Tue, 21 Jul 2026 14:53:08 GMT", + "comments": { + "patch": [ + { + "comment": "Support non-alphabetic characters in URL scheme detection and keep the detected scheme within the atomic schema length limit (close #1238)" + } + ] + } + }, + { + "version": "4.8.4", + "tag": "@snowplow/browser-tracker-core_v4.8.4", + "date": "Thu, 02 Jul 2026 10:07:52 GMT", + "comments": {} + }, + { + "version": "4.8.3", + "tag": "@snowplow/browser-tracker-core_v4.8.3", + "date": "Tue, 30 Jun 2026 14:22:03 GMT", + "comments": { + "none": [ + { + "comment": "Update uuid to v11 and remove closure-compiler from the build pipeline" + } + ] + } + }, + { + "version": "4.8.2", + "tag": "@snowplow/browser-tracker-core_v4.8.2", + "date": "Wed, 17 Jun 2026 12:30:12 GMT", + "comments": {} + }, + { + "version": "4.8.1", + "tag": "@snowplow/browser-tracker-core_v4.8.1", + "date": "Wed, 13 May 2026 09:26:05 GMT", + "comments": {} + }, + { + "version": "4.8.0", + "tag": "@snowplow/browser-tracker-core_v4.8.0", + "date": "Tue, 28 Apr 2026 07:56:22 GMT", + "comments": { + "none": [ + { + "comment": "Add opt-in activity metrics tracking with activity_metrics entity" + } + ] + } + }, + { + "version": "4.7.0", + "tag": "@snowplow/browser-tracker-core_v4.7.0", + "date": "Wed, 01 Apr 2026 12:59:29 GMT", + "comments": { + "none": [ + { + "comment": "Replace SHA1 buffer polyfill with lightweight implementation" + } + ] + } + }, + { + "version": "4.6.9", + "tag": "@snowplow/browser-tracker-core_v4.6.9", + "date": "Mon, 16 Mar 2026 15:43:06 GMT", + "comments": {} + }, + { + "version": "4.6.8", + "tag": "@snowplow/browser-tracker-core_v4.6.8", + "date": "Tue, 28 Oct 2025 09:46:42 GMT", + "comments": {} + }, + { + "version": "4.6.7", + "tag": "@snowplow/browser-tracker-core_v4.6.7", + "date": "Tue, 07 Oct 2025 14:53:36 GMT", + "comments": { + "none": [ + { + "comment": "Fix SecurityError when accessing localStorage in restricted browser environments" + } + ] + } + }, + { + "version": "4.6.6", + "tag": "@snowplow/browser-tracker-core_v4.6.6", + "date": "Tue, 26 Aug 2025 08:42:28 GMT", + "comments": { + "none": [ + { + "comment": "Unify browser dimension checks to avoid including NaN values" + }, + { + "comment": "Truncate browser context hardwareConcurrency value to prevent invalid events" + } + ] + } + }, + { + "version": "4.6.5", + "tag": "@snowplow/browser-tracker-core_v4.6.5", + "date": "Wed, 25 Jun 2025 21:16:46 GMT", + "comments": {} + }, + { + "version": "4.6.4", + "tag": "@snowplow/browser-tracker-core_v4.6.4", + "date": "Wed, 25 Jun 2025 12:08:50 GMT", + "comments": {} + }, + { + "version": "4.6.3", + "tag": "@snowplow/browser-tracker-core_v4.6.3", + "date": "Thu, 29 May 2025 19:52:07 GMT", + "comments": { + "none": [ + { + "comment": "Resume sessions when disabling anonymous tracking that was already tracking session state" + } + ] + } + }, + { + "version": "4.6.2", + "tag": "@snowplow/browser-tracker-core_v4.6.2", + "date": "Tue, 20 May 2025 07:39:05 GMT", + "comments": {} + }, + { + "version": "4.6.1", + "tag": "@snowplow/browser-tracker-core_v4.6.1", + "date": "Tue, 06 May 2025 13:10:51 GMT", + "comments": {} + }, + { + "version": "4.6.0", + "tag": "@snowplow/browser-tracker-core_v4.6.0", + "date": "Thu, 01 May 2025 09:58:59 GMT", + "comments": { + "none": [ + { + "comment": "Add `cookieExtensionService` argument as replacement for `idService`, deprecated `idService`" + } + ] + } + }, + { + "version": "4.5.0", + "tag": "@snowplow/browser-tracker-core_v4.5.0", + "date": "Fri, 04 Apr 2025 09:21:23 GMT", + "comments": { + "none": [ + { + "comment": "Avoid undelivered notifications error (#1335)" + } + ] + } + }, + { + "version": "4.4.0", + "tag": "@snowplow/browser-tracker-core_v4.4.0", + "date": "Thu, 20 Mar 2025 12:14:34 GMT", + "comments": {} + }, + { + "version": "4.3.1", + "tag": "@snowplow/browser-tracker-core_v4.3.1", + "date": "Tue, 21 Jan 2025 11:09:42 GMT", + "comments": {} + }, + { + "version": "4.3.0", + "tag": "@snowplow/browser-tracker-core_v4.3.0", + "date": "Mon, 20 Jan 2025 11:45:13 GMT", + "comments": {} + }, + { + "version": "4.2.0", + "tag": "@snowplow/browser-tracker-core_v4.2.0", + "date": "Mon, 13 Jan 2025 08:30:05 GMT", + "comments": {} + }, + { + "version": "4.1.0", + "tag": "@snowplow/browser-tracker-core_v4.1.0", + "date": "Thu, 28 Nov 2024 10:57:30 GMT", + "comments": { + "none": [ + { + "comment": "Add appVersion configuration option to track a context entity with the application version" + } + ] + } + }, + { + "version": "4.0.4", + "tag": "@snowplow/browser-tracker-core_v4.0.4", + "date": "Thu, 21 Nov 2024 09:06:36 GMT", + "comments": {} + }, + { + "version": "4.0.3", + "tag": "@snowplow/browser-tracker-core_v4.0.3", + "date": "Wed, 20 Nov 2024 09:30:31 GMT", + "comments": { + "none": [ + { + "comment": "Serialize new session cookie synchronously to avoid overlapping sessions (#1381)" + } + ] + } + }, + { + "version": "4.0.2", + "tag": "@snowplow/browser-tracker-core_v4.0.2", + "date": "Mon, 11 Nov 2024 15:46:34 GMT", + "comments": {} + }, + { + "version": "4.0.1", + "tag": "@snowplow/browser-tracker-core_v4.0.1", + "date": "Fri, 01 Nov 2024 10:35:07 GMT", + "comments": {} + }, + { + "version": "4.0.0", + "tag": "@snowplow/browser-tracker-core_v4.0.0", + "date": "Mon, 28 Oct 2024 11:48:53 GMT", + "comments": { + "none": [ + { + "comment": "Re-allow unspecified cookies domains" + }, + { + "comment": "Upgrade UUID to 8.3.2 (close #1138)" + }, + { + "comment": "Change default tracker initialization params (discoverRootDomain, cookieSameSite)" + }, + { + "comment": "Make cookie writes async by default to improve tracker performance (#1340)" + }, + { + "comment": "Add an emitter and event store interface in the tracker core to be used both by the browser and node trackers and use fetch for making requests" + }, + { + "comment": "Add a filter function to plugins to filter out events so that they are not tracked (#1326)" + }, + { + "comment": "Add browser-tracker-core default for os_timezone" + } + ] + } + }, + { + "version": "3.24.6", + "tag": "@snowplow/browser-tracker-core_v3.24.6", + "date": "Mon, 28 Oct 2024 10:23:28 GMT", + "comments": { + "none": [ + { + "comment": "Allow 0x0 viewport in browser context to avoid schema validation errors" + } + ] + } + }, + { + "version": "3.24.5", + "tag": "@snowplow/browser-tracker-core_v3.24.5", + "date": "Fri, 25 Oct 2024 08:53:04 GMT", + "comments": {} + }, + { + "version": "3.24.4", + "tag": "@snowplow/browser-tracker-core_v3.24.4", + "date": "Thu, 26 Sep 2024 06:10:22 GMT", + "comments": {} + }, + { + "version": "3.24.3", + "tag": "@snowplow/browser-tracker-core_v3.24.3", + "date": "Tue, 03 Sep 2024 08:15:14 GMT", + "comments": { + "none": [ + { + "comment": "Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush" + } + ] + } + }, + { + "version": "3.24.2", + "tag": "@snowplow/browser-tracker-core_v3.24.2", + "date": "Wed, 24 Jul 2024 08:59:00 GMT", + "comments": { + "none": [ + { + "comment": "Fix tracking a page view with a custom title sets the title for future page views as well (#1332)" + } + ] + } + }, + { + "version": "3.24.1", + "tag": "@snowplow/browser-tracker-core_v3.24.1", + "date": "Tue, 02 Jul 2024 07:08:17 GMT", + "comments": { + "none": [ + { + "comment": "Fix ResizeObserver initialization if document.body does not exist yet (#1311)" + } + ] + } + }, + { + "version": "3.24.0", + "tag": "@snowplow/browser-tracker-core_v3.24.0", + "date": "Tue, 25 Jun 2024 08:31:05 GMT", + "comments": { + "none": [ + { + "comment": "Add an option to generate the page view ID according to changes in the page URL to account for events tracked before page views in SPAs (#1307 and #1125)" + }, + { + "comment": "Fix custom document title override using setDocumentTitle (#1317)" + } + ] + } + }, + { + "version": "3.23.1", + "tag": "@snowplow/browser-tracker-core_v3.23.1", + "date": "Tue, 04 Jun 2024 13:34:45 GMT", + "comments": {} + }, + { + "version": "3.23.0", + "tag": "@snowplow/browser-tracker-core_v3.23.0", + "date": "Thu, 28 Mar 2024 11:28:45 GMT", + "comments": { + "none": [ + { + "comment": "Cache browser properties and use the ResizeObserver to update when changed (#1295) thanks to @rvetere" + } + ] + } + }, + { + "version": "3.22.1", + "tag": "@snowplow/browser-tracker-core_v3.22.1", + "date": "Wed, 13 Mar 2024 08:39:48 GMT", + "comments": {} + }, + { + "version": "3.22.0", + "tag": "@snowplow/browser-tracker-core_v3.22.0", + "date": "Fri, 08 Mar 2024 08:13:04 GMT", + "comments": { + "none": [ + { + "comment": "Update method signatures for BrowserTracker" + } + ] + } + }, + { + "version": "3.21.0", + "tag": "@snowplow/browser-tracker-core_v3.21.0", + "date": "Mon, 29 Jan 2024 08:34:06 GMT", + "comments": { + "none": [ + { + "comment": "Consistently access navigator via window.navigator" + } + ] + } + }, + { + "version": "3.20.0", + "tag": "@snowplow/browser-tracker-core_v3.20.0", + "date": "Mon, 15 Jan 2024 14:41:16 GMT", + "comments": { + "none": [ + { + "comment": "Allow for extended cross domain linking information using the useExtendedCrossDomainLinker option" + } + ] + } + }, + { + "version": "3.19.0", + "tag": "@snowplow/browser-tracker-core_v3.19.0", + "date": "Thu, 14 Dec 2023 10:45:23 GMT", + "comments": { + "none": [ + { + "comment": "Do not set the previous session ID reference in cookies if anonymous tracking is enabled (#1268)" + }, + { + "comment": "Fix config for callbacks" + } + ] + } + }, + { + "version": "3.18.0", + "tag": "@snowplow/browser-tracker-core_v3.18.0", + "date": "Mon, 04 Dec 2023 13:44:02 GMT", + "comments": { + "none": [ + { + "comment": "Add onRequestSuccess and onRequestFailure callbacks" + } + ] + } + }, + { + "version": "3.17.0", + "tag": "@snowplow/browser-tracker-core_v3.17.0", + "date": "Tue, 14 Nov 2023 17:58:26 GMT", + "comments": { + "none": [ + { + "comment": "Consider status codes <200" + }, + { + "comment": "Bump browser_context schema to 2-0-0" + } + ] + } + }, + { + "version": "3.16.0", + "tag": "@snowplow/browser-tracker-core_v3.16.0", + "date": "Mon, 16 Oct 2023 14:58:08 GMT", + "comments": {} + }, + { + "version": "3.15.0", + "tag": "@snowplow/browser-tracker-core_v3.15.0", + "date": "Mon, 28 Aug 2023 14:25:14 GMT", + "comments": { + "none": [ + { + "comment": "Add idService option" + } + ] + } + }, + { + "version": "3.14.0", + "tag": "@snowplow/browser-tracker-core_v3.14.0", + "date": "Thu, 10 Aug 2023 13:56:44 GMT", + "comments": { + "none": [ + { + "comment": "Allow disabling activity tracking actions with disableActivityTracking and disableActivityTrackingCallback APIs" + } + ] + } + }, + { + "version": "3.13.1", + "tag": "@snowplow/browser-tracker-core_v3.13.1", + "date": "Thu, 29 Jun 2023 14:20:06 GMT", + "comments": { + "none": [ + { + "comment": "Allow events to be tracked on the onSessionUpdate callback" + } + ] + } + }, + { + "version": "3.13.0", + "tag": "@snowplow/browser-tracker-core_v3.13.0", + "date": "Tue, 20 Jun 2023 07:44:23 GMT", + "comments": {} + }, + { + "version": "3.12.1", + "tag": "@snowplow/browser-tracker-core_v3.12.1", + "date": "Thu, 15 Jun 2023 10:05:37 GMT", + "comments": {} + }, + { + "version": "3.12.0", + "tag": "@snowplow/browser-tracker-core_v3.12.0", + "date": "Mon, 05 Jun 2023 11:51:22 GMT", + "comments": {} + }, + { + "version": "3.11.0", + "tag": "@snowplow/browser-tracker-core_v3.11.0", + "date": "Wed, 24 May 2023 15:56:17 GMT", + "comments": { + "none": [ + { + "comment": "Add onSessionUpdate callback configuration option" + }, + { + "comment": "Round dimension type values on payload" + } + ] + } + }, + { + "version": "3.10.1", + "tag": "@snowplow/browser-tracker-core_v3.10.1", + "date": "Fri, 12 May 2023 06:59:31 GMT", + "comments": {} + }, + { + "version": "3.10.0", + "tag": "@snowplow/browser-tracker-core_v3.10.0", + "date": "Thu, 11 May 2023 08:29:15 GMT", + "comments": {} + }, + { + "version": "3.9.0", + "tag": "@snowplow/browser-tracker-core_v3.9.0", + "date": "Thu, 30 Mar 2023 13:46:56 GMT", + "comments": { + "none": [ + { + "comment": "Add touchmove and touchstart events on page ping calculation" + }, + { + "comment": "Add client_session context entity if anonymous tracking with session tracking is enabled (#1124)" + }, + { + "comment": "Fix root domain algorithm initial attempt" + }, + { + "comment": "Fix generating domain user ID when clearing user data with anonymous tracking (#1164)" + }, + { + "comment": "Add browser context and ability to generate tab identifier." + } + ] + } + }, + { + "version": "3.8.0", + "tag": "@snowplow/browser-tracker-core_v3.8.0", + "date": "Tue, 03 Jan 2023 15:36:33 GMT", + "comments": {} + }, + { + "version": "3.7.0", + "tag": "@snowplow/browser-tracker-core_v3.7.0", + "date": "Mon, 31 Oct 2022 06:26:28 GMT", + "comments": {} + }, + { + "version": "3.6.0", + "tag": "@snowplow/browser-tracker-core_v3.6.0", + "date": "Thu, 15 Sep 2022 07:55:20 GMT", + "comments": { + "none": [ + { + "comment": "Fix newTracker built-in context typing" + }, + { + "comment": "Added BuiltInContexts type" + }, + { + "comment": "Correct initial session_index value and after clearUserData (closes #1106 #1107)" + } + ] + } + }, + { + "version": "3.5.0", + "tag": "@snowplow/browser-tracker-core_v3.5.0", + "date": "Fri, 10 Jun 2022 18:57:46 GMT", + "comments": { + "none": [ + { + "comment": "Add client session context entity (#1077)" + }, + { + "comment": "Add a customizable set of failure HTTP status codes for which collector requests should not be retried (#1079)" + } + ] + } + }, + { + "version": "3.4.0", + "tag": "@snowplow/browser-tracker-core_v3.4.0", + "date": "Thu, 07 Apr 2022 11:56:26 GMT", + "comments": { + "none": [ + { + "comment": "Bump dependencies (#1067)" + }, + { + "comment": "Add configurable max GET request size in bytes attribute (#449)" + } + ] + } + }, + { + "version": "3.3.1", + "tag": "@snowplow/browser-tracker-core_v3.3.1", + "date": "Wed, 23 Feb 2022 19:27:40 GMT", + "comments": {} + }, + { + "version": "3.3.0", + "tag": "@snowplow/browser-tracker-core_v3.3.0", + "date": "Mon, 31 Jan 2022 15:58:10 GMT", + "comments": {} + }, + { + "version": "3.2.3", + "tag": "@snowplow/browser-tracker-core_v3.2.3", + "date": "Tue, 18 Jan 2022 16:23:52 GMT", + "comments": { + "none": [ + { + "comment": "Bump Copyright to 2022 (#1040)" + } + ] + } + }, + { + "version": "3.2.2", + "tag": "@snowplow/browser-tracker-core_v3.2.2", + "date": "Fri, 14 Jan 2022 10:17:59 GMT", + "comments": {} + }, + { + "version": "3.2.1", + "tag": "@snowplow/browser-tracker-core_v3.2.1", + "date": "Wed, 12 Jan 2022 09:50:29 GMT", + "comments": {} + }, + { + "version": "3.2.0", + "tag": "@snowplow/browser-tracker-core_v3.2.0", + "date": "Tue, 11 Jan 2022 12:53:22 GMT", + "comments": { + "none": [ + { + "comment": "Add support for custom headers (#1010)" + }, + { + "comment": "Allow alternative Access-Control-Allow-Credentials values (#808)" + }, + { + "comment": "Ensure Browser Data is added to Payload before plugin beforeTrack fires (#1025)" + } + ] + } + }, + { + "version": "3.1.6", + "tag": "@snowplow/browser-tracker-core_v3.1.6", + "date": "Tue, 19 Oct 2021 09:17:22 GMT", + "comments": { + "none": [ + { + "comment": "Fix failing build on ARM Macs (#1012)" + } + ] + } + }, + { + "version": "3.1.5", + "tag": "@snowplow/browser-tracker-core_v3.1.5", + "date": "Fri, 01 Oct 2021 08:09:21 GMT", + "comments": { + "none": [ + { + "comment": "Fix removeGlobalContexts not removing expected context (#1006)" + } + ] + } + }, + { + "version": "3.1.4", + "tag": "@snowplow/browser-tracker-core_v3.1.4", + "date": "Tue, 21 Sep 2021 14:59:36 GMT", + "comments": { + "none": [ + { + "comment": "Fix linkDecorationHandler targeting (#1002)" + } + ] + } + }, + { + "version": "3.1.3", + "tag": "@snowplow/browser-tracker-core_v3.1.3", + "date": "Mon, 23 Aug 2021 10:13:18 GMT", + "comments": { + "none": [ + { + "comment": "Add missing setter to detectPassiveEvents (#995)" + } + ] + } + }, + { + "version": "3.1.2", + "tag": "@snowplow/browser-tracker-core_v3.1.2", + "date": "Mon, 16 Aug 2021 12:59:59 GMT", + "comments": { + "none": [ + { + "comment": "Fix undefined argument regression in setUserId and setOptOutCookie (#991)" + }, + { + "comment": "Update READMEs with correct Node requirements (#994)" + } + ] + } + }, + { + "version": "3.1.1", + "tag": "@snowplow/browser-tracker-core_v3.1.1", + "date": "Wed, 04 Aug 2021 10:12:25 GMT", + "comments": { + "none": [ + { + "comment": "Automate api-extractor on release (#972)" + }, + { + "comment": "Allow tracker to load in fully sandboxes iframes (#981)" + }, + { + "comment": "Allow options: false when calling enableAnonymousTracking (#977)" + }, + { + "comment": "Prevent the Activity Tracking timer being enabled twice with duplicate enableActivityTracking calls (#975)" + }, + { + "comment": "Bump tslib to 2.3.0 (#986)" + }, + { + "comment": "Prevent the Activity Tracking timer being enabled twice with duplicate enableActivityTracking calls (#975)" + }, + { + "comment": "Protect against invalid domain_sessionid values being used by the tracker (#978)" + }, + { + "comment": "Bump typescript to 4.3.5 (#987)" + }, + { + "comment": "Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988)" + } + ] + } + }, + { + "version": "3.1.0", + "tag": "@snowplow/browser-tracker-core_v3.1.0", + "date": "Fri, 14 May 2021 10:45:32 GMT", + "comments": { + "none": [ + { + "comment": "Clear in memory identifiers in clearUserData() (#968)" + }, + { + "comment": "Allow stateStorageStrategy to be changed on enableAnonymousTracking (#969)" + } + ] + } + }, + { + "version": "3.0.3", + "tag": "@snowplow/browser-tracker-core_v3.0.3", + "date": "Wed, 21 Apr 2021 12:35:06 GMT", + "comments": { + "none": [ + { + "comment": "Fix race condition when using Form and Link Click tracking (#962)" + } + ] + } + }, + { + "version": "3.0.2", + "tag": "@snowplow/browser-tracker-core_v3.0.2", + "date": "Thu, 15 Apr 2021 21:07:39 GMT", + "comments": { + "none": [ + { + "comment": "Remove compatMode check in activity tracking page offsets (#958)" + } + ] + } + }, + { + "version": "3.0.1", + "tag": "@snowplow/browser-tracker-core_v3.0.1", + "date": "Wed, 14 Apr 2021 16:30:05 GMT", + "comments": { + "none": [ + { + "comment": "Mark packages as sideEffect: false (#951)" + }, + { + "comment": "Add unit tests to plugin track* functions (#954)" + } + ] + } + }, + { + "version": "3.0.0", + "tag": "@snowplow/browser-tracker-core_v3.0.0", + "date": "Wed, 31 Mar 2021 14:46:47 GMT", + "comments": { + "none": [ + { + "comment": "Allow plugins to be dynamically loaded when using tracker (#918)" + }, + { + "comment": "Add debug mode (#381)" + }, + { + "comment": "Remove forceSecureTracker and forceUnsecureTracker properties (#913)" + }, + { + "comment": "Bump uuid to 3.4.0 (close #915)" + }, + { + "comment": "Bump rollup to 2.41 (#916)" + }, + { + "comment": "Remove module level references to window and document (close #928)" + }, + { + "comment": "Ensure browser-tracker API methods catch exceptions (#919)" + }, + { + "comment": "Introduce TSDoc comments and extract interfaces where appropriate (#906)" + }, + { + "comment": "Bump major version to v3 and update READMEs (#904)" + }, + { + "comment": "Improve Core API for module bundlers which support treeshaking (#903)" + }, + { + "comment": "Rename @snowplow/browser-core to @snowplow/browser-tracker-core (#901)" + }, + { + "comment": "Publish lite version of sp.js (#900)" + }, + { + "comment": "Ensure correct 3-Clause BSD License notices are being used (#316)" + }, + { + "comment": "Improve API for module bundlers which support treeshaking (#899)" + }, + { + "comment": "Bump rush to 5.39 (#895)" + }, + { + "comment": "Port to TypeScript (#72)" + }, + { + "comment": "Make sp.js build process modular (#450)" + }, + { + "comment": "Create @snowplow/browser-tracker package for npm distribution (#541)" + }, + { + "comment": "Split auto contexts into plugins (#880)" + }, + { + "comment": "Add rush to manage monorepo (#883)" + }, + { + "comment": "Add ES Module builds (#882)" + }, + { + "comment": "Cleanup deprecated methods (#557)" + }, + { + "comment": "Update publishing process for rush (#907)" + }, + { + "comment": "Change white and black lists to allow and deny lists (#908)" + }, + { + "comment": "Create rush change files for major version 3 release (#909)" + }, + { + "comment": "Improve event flushing options and remove pageUnloadTimer (#719)" + } + ] + } + } + ] +} diff --git a/libraries/browser-tracker-core/CHANGELOG.md b/libraries/browser-tracker-core/CHANGELOG.md new file mode 100644 index 000000000..fd87ade61 --- /dev/null +++ b/libraries/browser-tracker-core/CHANGELOG.md @@ -0,0 +1,551 @@ +# Change Log - @snowplow/browser-tracker-core + +This log was last generated on Mon, 27 Jul 2026 13:52:14 GMT and should not be manually modified. + +## 4.10.0 +Mon, 27 Jul 2026 13:52:14 GMT + +### Minor changes + +- Add disableSessionContextWithinWebView option to suppress client_session entity in hybrid native+WebView deployments + +### Patches + +- Remove forced layout read from tracker initialization: replace init-time getBrowserProperties() call with direct non-layout reads; defer the first readBrowserProperties() to first event build time. + +### Updates + +- Add preserveOriginalReferrer tracker configuration option for SPA referrer tracking + +## 4.9.0 +Tue, 21 Jul 2026 14:53:08 GMT + +### Patches + +- Support non-alphabetic characters in URL scheme detection and keep the detected scheme within the atomic schema length limit (close #1238) + +## 4.8.4 +Thu, 02 Jul 2026 10:07:52 GMT + +_Version update only_ + +## 4.8.3 +Tue, 30 Jun 2026 14:22:03 GMT + +### Updates + +- Update uuid to v11 and remove closure-compiler from the build pipeline + +## 4.8.2 +Wed, 17 Jun 2026 12:30:12 GMT + +_Version update only_ + +## 4.8.1 +Wed, 13 May 2026 09:26:05 GMT + +_Version update only_ + +## 4.8.0 +Tue, 28 Apr 2026 07:56:22 GMT + +### Updates + +- Add opt-in activity metrics tracking with activity_metrics entity + +## 4.7.0 +Wed, 01 Apr 2026 12:59:29 GMT + +### Updates + +- Replace SHA1 buffer polyfill with lightweight implementation + +## 4.6.9 +Mon, 16 Mar 2026 15:43:06 GMT + +_Version update only_ + +## 4.6.8 +Tue, 28 Oct 2025 09:46:42 GMT + +_Version update only_ + +## 4.6.7 +Tue, 07 Oct 2025 14:53:36 GMT + +### Updates + +- Fix SecurityError when accessing localStorage in restricted browser environments + +## 4.6.6 +Tue, 26 Aug 2025 08:42:28 GMT + +### Updates + +- Unify browser dimension checks to avoid including NaN values +- Truncate browser context hardwareConcurrency value to prevent invalid events + +## 4.6.5 +Wed, 25 Jun 2025 21:16:46 GMT + +_Version update only_ + +## 4.6.4 +Wed, 25 Jun 2025 12:08:50 GMT + +_Version update only_ + +## 4.6.3 +Thu, 29 May 2025 19:52:07 GMT + +### Updates + +- Resume sessions when disabling anonymous tracking that was already tracking session state + +## 4.6.2 +Tue, 20 May 2025 07:39:05 GMT + +_Version update only_ + +## 4.6.1 +Tue, 06 May 2025 13:10:51 GMT + +_Version update only_ + +## 4.6.0 +Thu, 01 May 2025 09:58:59 GMT + +### Updates + +- Add `cookieExtensionService` argument as replacement for `idService`, deprecated `idService` + +## 4.5.0 +Fri, 04 Apr 2025 09:21:23 GMT + +### Updates + +- Avoid undelivered notifications error (#1335) + +## 4.4.0 +Thu, 20 Mar 2025 12:14:34 GMT + +_Version update only_ + +## 4.3.1 +Tue, 21 Jan 2025 11:09:42 GMT + +_Version update only_ + +## 4.3.0 +Mon, 20 Jan 2025 11:45:13 GMT + +_Version update only_ + +## 4.2.0 +Mon, 13 Jan 2025 08:30:05 GMT + +_Version update only_ + +## 4.1.0 +Thu, 28 Nov 2024 10:57:30 GMT + +### Updates + +- Add appVersion configuration option to track a context entity with the application version + +## 4.0.4 +Thu, 21 Nov 2024 09:06:36 GMT + +_Version update only_ + +## 4.0.3 +Wed, 20 Nov 2024 09:30:31 GMT + +### Updates + +- Serialize new session cookie synchronously to avoid overlapping sessions (#1381) + +## 4.0.2 +Mon, 11 Nov 2024 15:46:34 GMT + +_Version update only_ + +## 4.0.1 +Fri, 01 Nov 2024 10:35:07 GMT + +_Version update only_ + +## 4.0.0 +Mon, 28 Oct 2024 11:48:53 GMT + +### Updates + +- Re-allow unspecified cookies domains +- Upgrade UUID to 8.3.2 (close #1138) +- Change default tracker initialization params (discoverRootDomain, cookieSameSite) +- Make cookie writes async by default to improve tracker performance (#1340) +- Add an emitter and event store interface in the tracker core to be used both by the browser and node trackers and use fetch for making requests +- Add a filter function to plugins to filter out events so that they are not tracked (#1326) +- Add browser-tracker-core default for os_timezone + +## 3.24.6 +Mon, 28 Oct 2024 10:23:28 GMT + +### Updates + +- Allow 0x0 viewport in browser context to avoid schema validation errors + +## 3.24.5 +Fri, 25 Oct 2024 08:53:04 GMT + +_Version update only_ + +## 3.24.4 +Thu, 26 Sep 2024 06:10:22 GMT + +_Version update only_ + +## 3.24.3 +Tue, 03 Sep 2024 08:15:14 GMT + +### Updates + +- Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush + +## 3.24.2 +Wed, 24 Jul 2024 08:59:00 GMT + +### Updates + +- Fix tracking a page view with a custom title sets the title for future page views as well (#1332) + +## 3.24.1 +Tue, 02 Jul 2024 07:08:17 GMT + +### Updates + +- Fix ResizeObserver initialization if document.body does not exist yet (#1311) + +## 3.24.0 +Tue, 25 Jun 2024 08:31:05 GMT + +### Updates + +- Add an option to generate the page view ID according to changes in the page URL to account for events tracked before page views in SPAs (#1307 and #1125) +- Fix custom document title override using setDocumentTitle (#1317) + +## 3.23.1 +Tue, 04 Jun 2024 13:34:45 GMT + +_Version update only_ + +## 3.23.0 +Thu, 28 Mar 2024 11:28:45 GMT + +### Updates + +- Cache browser properties and use the ResizeObserver to update when changed (#1295) thanks to @rvetere + +## 3.22.1 +Wed, 13 Mar 2024 08:39:48 GMT + +_Version update only_ + +## 3.22.0 +Fri, 08 Mar 2024 08:13:04 GMT + +### Updates + +- Update method signatures for BrowserTracker + +## 3.21.0 +Mon, 29 Jan 2024 08:34:06 GMT + +### Updates + +- Consistently access navigator via window.navigator + +## 3.20.0 +Mon, 15 Jan 2024 14:41:16 GMT + +### Updates + +- Allow for extended cross domain linking information using the useExtendedCrossDomainLinker option + +## 3.19.0 +Thu, 14 Dec 2023 10:45:23 GMT + +### Updates + +- Do not set the previous session ID reference in cookies if anonymous tracking is enabled (#1268) +- Fix config for callbacks + +## 3.18.0 +Mon, 04 Dec 2023 13:44:02 GMT + +### Updates + +- Add onRequestSuccess and onRequestFailure callbacks + +## 3.17.0 +Tue, 14 Nov 2023 17:58:26 GMT + +### Updates + +- Consider status codes <200 +- Bump browser_context schema to 2-0-0 + +## 3.16.0 +Mon, 16 Oct 2023 14:58:08 GMT + +_Version update only_ + +## 3.15.0 +Mon, 28 Aug 2023 14:25:14 GMT + +### Updates + +- Add idService option + +## 3.14.0 +Thu, 10 Aug 2023 13:56:44 GMT + +### Updates + +- Allow disabling activity tracking actions with disableActivityTracking and disableActivityTrackingCallback APIs + +## 3.13.1 +Thu, 29 Jun 2023 14:20:06 GMT + +### Updates + +- Allow events to be tracked on the onSessionUpdate callback + +## 3.13.0 +Tue, 20 Jun 2023 07:44:23 GMT + +_Version update only_ + +## 3.12.1 +Thu, 15 Jun 2023 10:05:37 GMT + +_Version update only_ + +## 3.12.0 +Mon, 05 Jun 2023 11:51:22 GMT + +_Version update only_ + +## 3.11.0 +Wed, 24 May 2023 15:56:17 GMT + +### Updates + +- Add onSessionUpdate callback configuration option +- Round dimension type values on payload + +## 3.10.1 +Fri, 12 May 2023 06:59:31 GMT + +_Version update only_ + +## 3.10.0 +Thu, 11 May 2023 08:29:15 GMT + +_Version update only_ + +## 3.9.0 +Thu, 30 Mar 2023 13:46:56 GMT + +### Updates + +- Add touchmove and touchstart events on page ping calculation +- Add client_session context entity if anonymous tracking with session tracking is enabled (#1124) +- Fix root domain algorithm initial attempt +- Fix generating domain user ID when clearing user data with anonymous tracking (#1164) +- Add browser context and ability to generate tab identifier. + +## 3.8.0 +Tue, 03 Jan 2023 15:36:33 GMT + +_Version update only_ + +## 3.7.0 +Mon, 31 Oct 2022 06:26:28 GMT + +_Version update only_ + +## 3.6.0 +Thu, 15 Sep 2022 07:55:20 GMT + +### Updates + +- Fix newTracker built-in context typing +- Added BuiltInContexts type +- Correct initial session_index value and after clearUserData (closes #1106 #1107) + +## 3.5.0 +Fri, 10 Jun 2022 18:57:46 GMT + +### Updates + +- Add client session context entity (#1077) +- Add a customizable set of failure HTTP status codes for which collector requests should not be retried (#1079) + +## 3.4.0 +Thu, 07 Apr 2022 11:56:26 GMT + +### Updates + +- Bump dependencies (#1067) +- Add configurable max GET request size in bytes attribute (#449) + +## 3.3.1 +Wed, 23 Feb 2022 19:27:40 GMT + +_Version update only_ + +## 3.3.0 +Mon, 31 Jan 2022 15:58:10 GMT + +_Version update only_ + +## 3.2.3 +Tue, 18 Jan 2022 16:23:52 GMT + +### Updates + +- Bump Copyright to 2022 (#1040) + +## 3.2.2 +Fri, 14 Jan 2022 10:17:59 GMT + +_Version update only_ + +## 3.2.1 +Wed, 12 Jan 2022 09:50:29 GMT + +_Version update only_ + +## 3.2.0 +Tue, 11 Jan 2022 12:53:22 GMT + +### Updates + +- Add support for custom headers (#1010) +- Allow alternative Access-Control-Allow-Credentials values (#808) +- Ensure Browser Data is added to Payload before plugin beforeTrack fires (#1025) + +## 3.1.6 +Tue, 19 Oct 2021 09:17:22 GMT + +### Updates + +- Fix failing build on ARM Macs (#1012) + +## 3.1.5 +Fri, 01 Oct 2021 08:09:21 GMT + +### Updates + +- Fix removeGlobalContexts not removing expected context (#1006) + +## 3.1.4 +Tue, 21 Sep 2021 14:59:36 GMT + +### Updates + +- Fix linkDecorationHandler targeting (#1002) + +## 3.1.3 +Mon, 23 Aug 2021 10:13:18 GMT + +### Updates + +- Add missing setter to detectPassiveEvents (#995) + +## 3.1.2 +Mon, 16 Aug 2021 12:59:59 GMT + +### Updates + +- Fix undefined argument regression in setUserId and setOptOutCookie (#991) +- Update READMEs with correct Node requirements (#994) + +## 3.1.1 +Wed, 04 Aug 2021 10:12:25 GMT + +### Updates + +- Automate api-extractor on release (#972) +- Allow tracker to load in fully sandboxes iframes (#981) +- Allow options: false when calling enableAnonymousTracking (#977) +- Prevent the Activity Tracking timer being enabled twice with duplicate enableActivityTracking calls (#975) +- Bump tslib to 2.3.0 (#986) +- Prevent the Activity Tracking timer being enabled twice with duplicate enableActivityTracking calls (#975) +- Protect against invalid domain_sessionid values being used by the tracker (#978) +- Bump typescript to 4.3.5 (#987) +- Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988) + +## 3.1.0 +Fri, 14 May 2021 10:45:32 GMT + +### Updates + +- Clear in memory identifiers in clearUserData() (#968) +- Allow stateStorageStrategy to be changed on enableAnonymousTracking (#969) + +## 3.0.3 +Wed, 21 Apr 2021 12:35:06 GMT + +### Updates + +- Fix race condition when using Form and Link Click tracking (#962) + +## 3.0.2 +Thu, 15 Apr 2021 21:07:39 GMT + +### Updates + +- Remove compatMode check in activity tracking page offsets (#958) + +## 3.0.1 +Wed, 14 Apr 2021 16:30:05 GMT + +### Updates + +- Mark packages as sideEffect: false (#951) +- Add unit tests to plugin track* functions (#954) + +## 3.0.0 +Wed, 31 Mar 2021 14:46:47 GMT + +### Updates + +- Allow plugins to be dynamically loaded when using tracker (#918) +- Add debug mode (#381) +- Remove forceSecureTracker and forceUnsecureTracker properties (#913) +- Bump uuid to 3.4.0 (close #915) +- Bump rollup to 2.41 (#916) +- Remove module level references to window and document (close #928) +- Ensure browser-tracker API methods catch exceptions (#919) +- Introduce TSDoc comments and extract interfaces where appropriate (#906) +- Bump major version to v3 and update READMEs (#904) +- Improve Core API for module bundlers which support treeshaking (#903) +- Rename @snowplow/browser-core to @snowplow/browser-tracker-core (#901) +- Publish lite version of sp.js (#900) +- Ensure correct 3-Clause BSD License notices are being used (#316) +- Improve API for module bundlers which support treeshaking (#899) +- Bump rush to 5.39 (#895) +- Port to TypeScript (#72) +- Make sp.js build process modular (#450) +- Create @snowplow/browser-tracker package for npm distribution (#541) +- Split auto contexts into plugins (#880) +- Add rush to manage monorepo (#883) +- Add ES Module builds (#882) +- Cleanup deprecated methods (#557) +- Update publishing process for rush (#907) +- Change white and black lists to allow and deny lists (#908) +- Create rush change files for major version 3 release (#909) +- Improve event flushing options and remove pageUnloadTimer (#719) + diff --git a/libraries/browser-tracker-core/CLAUDE.md b/libraries/browser-tracker-core/CLAUDE.md new file mode 100644 index 000000000..d77dbccd0 --- /dev/null +++ b/libraries/browser-tracker-core/CLAUDE.md @@ -0,0 +1,452 @@ +# Browser Tracker Core Library - CLAUDE.md + +## Module Overview + +The `@snowplow/browser-tracker-core` library provides browser-specific tracking functionality built on top of tracker-core. It handles DOM interactions, browser storage, cookies, and browser-specific event tracking features. + +## Core Responsibilities + +- **Browser Detection**: User agent, viewport, screen detection +- **Storage Management**: Cookies, localStorage, sessionStorage +- **DOM Helpers**: Cross-domain linking, form tracking utilities +- **Session Management**: Session tracking and storage +- **Page View Tracking**: Page view IDs and activity tracking +- **Browser Plugins**: Plugin system for browser features + +## Architecture Patterns + +### Browser Plugin Pattern +```typescript +// ✅ Correct: Typed plugin interface +export interface BrowserPlugin { + activateBrowserPlugin?: (tracker: BrowserTracker) => void; + contexts?: () => Array; + logger?: (logger: Logger) => void; + beforeTrack?: (payloadBuilder: PayloadBuilder) => void; + afterTrack?: (payload: Payload) => void; +} + +// ❌ Wrong: Untyped plugin +const plugin = { activate: (t: any) => {} }; +``` + +### Tracker State Management +```typescript +// ✅ Correct: Shared state pattern +export interface SharedState { + bufferFlushers: Array<(sync?: boolean) => void>; + hasLoaded: boolean; + registeredOnLoadHandlers: Array; + contextProviders: Array; +} + +// ❌ Wrong: Global variables +let trackerState = {}; // Avoid global state +``` + +### Storage Abstraction Pattern +```typescript +// ✅ Correct: Storage interface +export interface Storage { + getItem(key: string): string | null; + setItem(key: string, value: string): void; + removeItem(key: string): void; +} + +// ❌ Wrong: Direct localStorage access +localStorage.setItem('key', 'value'); // Use abstraction +``` + +## Critical Import Patterns + +### Browser-Specific Exports +```typescript +// index.ts - Browser features +export * from './tracker/types'; +export * from './helpers'; +export * from './detectors'; +export * from './proxies'; +export * from './plugins'; +export * from './state'; +export { Tracker } from './tracker'; +``` + +### Helper Utilities +```typescript +// ✅ Correct: Import from helpers +import { getCookieValue, setCookie } from './helpers'; + +// ❌ Wrong: Reimplementing browser utils +function getCookie(name: string) { /* custom */ } +``` + +## Cookie Management + +### Cookie Storage Pattern +```typescript +// ✅ Correct: Use cookie storage abstraction +export class CookieStorage implements Storage { + constructor( + private cookieName: string, + private cookieDomain?: string, + private cookieLifetime?: number + ) {} + + setItem(key: string, value: string): void { + setCookie(this.cookieName, value, this.cookieLifetime); + } +} + +// ❌ Wrong: Direct document.cookie manipulation +document.cookie = `name=value; domain=.example.com`; +``` + +### ID Cookie Pattern +```typescript +// Standard ID cookie structure +interface IdCookie { + userId: string; // Domain user ID + sessionId: string; // Session ID + sessionIndex: number; // Session count + eventIndex: number; // Event count in session + lastActivity: number; // Last activity timestamp +} +``` + +## Session Management + +### Session Storage Pattern +```typescript +// ✅ Correct: Session data structure +export interface SessionData { + sessionId: string; + previousSessionId?: string; + sessionIndex: number; + userId: string; + firstEventId?: string; + firstEventTimestamp?: number; +} + +// ❌ Wrong: Unstructured session data +const session = { id: '123', data: {} }; +``` + +### Activity Tracking +```typescript +// Activity callback configuration +export interface ActivityTrackingConfiguration { + minimumVisitLength: number; + heartbeatDelay: number; + callback?: ActivityCallback; +} +``` + +## DOM Interaction Patterns + +### Cross-Domain Linking +```typescript +// ✅ Correct: Decorator pattern +export function decorateQuerystring( + url: string, + name: string, + value: string +): string { + const [urlPath, anchor] = url.split('#'); + const [basePath, queries] = urlPath.split('?'); + // ... decoration logic + return decorated; +} + +// ❌ Wrong: String concatenation +url += '?_sp=' + value; // Fragile +``` + +### Form Element Helpers +```typescript +// Get form element values safely +export function getElementValue(element: HTMLElement): string | null { + if (element instanceof HTMLInputElement) { + return element.value; + } + if (element instanceof HTMLTextAreaElement) { + return element.value; + } + return null; +} +``` + +## Browser Detection + +### Detector Functions +```typescript +// ✅ Correct: Feature detection +export function hasLocalStorage(): boolean { + try { + const test = 'localStorage'; + localStorage.setItem(test, test); + localStorage.removeItem(test); + return true; + } catch (e) { + return false; + } +} + +// ❌ Wrong: Assume availability +if (localStorage) { /* use it */ } // May throw +``` + +### Browser Properties +```typescript +// Standard browser context +export interface BrowserProperties { + viewport: [number, number]; + documentSize: [number, number]; + resolution: [number, number]; + colorDepth: number; + devicePixelRatio: number; + cookieEnabled: boolean; + online: boolean; + browserLanguage: string; + documentLanguage: string; + webdriver: boolean; +} +``` + +## Event Queue Management + +### Out Queue Pattern +```typescript +// ✅ Correct: Managed queue with retry +export class OutQueue { + constructor( + private readonly maxQueueSize: number, + private readonly eventStore: EventStore + ) {} + + enqueue(event: Payload): void { + if (this.queue.length >= this.maxQueueSize) { + this.flush(); + } + this.queue.push(event); + } +} + +// ❌ Wrong: Unbounded array +const events = []; // No size management +``` + +## Common Patterns + +### Page View ID Generation +```typescript +// ✅ Correct: UUID per page view +import { v4 as uuid } from 'uuid'; +export function generatePageViewId(): string { + return uuid(); +} + +// ❌ Wrong: Sequential IDs +let pvId = 0; +function getPageViewId() { return ++pvId; } +``` + +### Local Storage Event Store +```typescript +// Event persistence pattern +export class LocalStorageEventStore implements EventStore { + constructor(private readonly key: string) {} + + async add(event: EventStorePayload): Promise { + const events = this.getAll(); + events.push(event); + localStorage.setItem(this.key, JSON.stringify(events)); + return events.length; + } +} +``` + +## Testing Patterns + +### Test Directory Structure +``` +test/ +├── tracker/ # Tracker-specific tests +│ ├── cookie_storage.test.ts +│ ├── page_view.test.ts +│ └── session_data.test.ts +├── helpers/ # Helper function tests +├── detectors.test.ts # Browser detection tests +└── __snapshots__/ # Jest snapshots +``` + +### Mock Browser APIs +```typescript +// Mock storage for tests +class MockStorage implements Storage { + private store: Record = {}; + + getItem(key: string): string | null { + return this.store[key] || null; + } + + setItem(key: string, value: string): void { + this.store[key] = value; + } + + clear(): void { + this.store = {}; + } +} + +// Mock document properties +jest.spyOn(document, 'title', 'get').mockReturnValue('Test Page'); +jest.spyOn(document, 'referrer', 'get').mockReturnValue('https://referrer.com'); +``` + +### DOM Testing +```typescript +// ✅ Correct: Setup and teardown DOM +beforeEach(() => { + document.body.innerHTML = ` +
+ + +
+ `; +}); + +afterEach(() => { + document.body.innerHTML = ''; + jest.clearAllMocks(); +}); + +// ❌ Wrong: Leave DOM dirty +beforeEach(() => { + document.body.innerHTML += '
test
'; // Accumulates +}); +``` + +### Testing Browser Detection +```typescript +// ✅ Correct: Mock browser features +describe('Browser detection', () => { + it('detects localStorage support', () => { + const mockSetItem = jest.fn(); + Object.defineProperty(window, 'localStorage', { + value: { setItem: mockSetItem, removeItem: jest.fn() }, + writable: true + }); + + expect(hasLocalStorage()).toBe(true); + }); + + it('handles localStorage errors', () => { + Object.defineProperty(window, 'localStorage', { + value: { + setItem: () => { throw new Error('Quota exceeded'); } + }, + writable: true + }); + + expect(hasLocalStorage()).toBe(false); + }); +}); +``` + +### Cookie Testing +```typescript +// ✅ Correct: Test cookie operations +describe('Cookie management', () => { + beforeEach(() => { + // Clear cookies + document.cookie.split(';').forEach(c => { + document.cookie = c.replace(/^ +/, '') + .replace(/=.*/, '=;expires=' + new Date().toUTCString()); + }); + }); + + it('sets and retrieves cookies', () => { + setCookie('test', 'value', 86400); + expect(getCookieValue('test')).toBe('value'); + }); +}); +``` + +### Testing Helper Pattern +```typescript +// Common test helper in test/helpers.ts +export function createTracker(config?: Partial) { + const eventStore = newInMemoryEventStore(); + return addTracker('sp', 'sp', 'js-test', '', new SharedState(), { + eventStore, + ...config + }); +} + +// Usage in tests +it('tracks page view', () => { + const tracker = createTracker(); + tracker.trackPageView(); + // Assert... +}); +``` + +## File Organization + +``` +browser-tracker-core/ +├── src/ +│ ├── index.ts # Public exports +│ ├── snowplow.ts # Main tracker factory +│ ├── state.ts # Shared state +│ ├── plugins.ts # Plugin system +│ ├── proxies.ts # Proxy tracking +│ ├── detectors.ts # Browser detection +│ ├── helpers/ +│ │ ├── index.ts # Helper exports +│ │ ├── browser_props.ts +│ │ ├── cross_domain.ts +│ │ └── storage.ts +│ └── tracker/ +│ ├── index.ts # Tracker implementation +│ ├── types.ts # TypeScript types +│ ├── cookie_storage.ts +│ ├── id_cookie.ts +│ ├── out_queue.ts +│ └── local_storage_event_store.ts +└── test/ + └── [module].test.ts +``` + +## Quick Reference + +### Essential Imports +```typescript +import { + BrowserTracker, + BrowserPlugin, + SharedState, + ActivityTrackingConfiguration, + PageViewEvent, + getCookieValue, + decorateQuerystring, + hasLocalStorage +} from '@snowplow/browser-tracker-core'; +``` + +### Plugin Development Checklist +- [ ] Implement `BrowserPlugin` interface +- [ ] Store tracker reference in `activateBrowserPlugin` +- [ ] Clean up resources in cleanup hooks +- [ ] Handle browser API failures gracefully +- [ ] Test with different storage configurations + +## Contributing to CLAUDE.md + +When modifying browser-tracker-core: + +1. **Test browser compatibility** across major browsers +2. **Handle storage failures** gracefully +3. **Respect privacy settings** (cookies, storage) +4. **Maintain IE11 compatibility** if required +5. **Document browser-specific behavior** \ No newline at end of file diff --git a/libraries/browser-tracker-core/LICENSE b/libraries/browser-tracker-core/LICENSE new file mode 100644 index 000000000..76f1946ea --- /dev/null +++ b/libraries/browser-tracker-core/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/libraries/browser-tracker-core/README.md b/libraries/browser-tracker-core/README.md new file mode 100644 index 000000000..59f6e0cd9 --- /dev/null +++ b/libraries/browser-tracker-core/README.md @@ -0,0 +1,76 @@ +# Snowplow Browser Tracker Core + +[![npm version][npm-image]][npm-url] +[![License][license-image]](LICENSE) + +Browser Core module to be used by Snowplow Browser based trackers. + +It should rarely be used alone, you probably want `@snowplow/browser-tracker`. + +## Maintainer quick start + +Part of the Snowplow JavaScript Tracker monorepo. +Build with [Node.js](https://nodejs.org/en/) (18 - 20) and [Rush](https://rushjs.io/). + +### Setup repository + +```bash +npm install -g @microsoft/rush +git clone https://github.com/snowplow/snowplow-javascript-tracker.git +rush update +``` + +### Building Browser Tracker Core + +```bash +cd libraries/browser-tracker-core +rushx build +``` + +### Running tests + +```bash +rushx test +``` + +## Package Installation + +With npm: + +```bash +npm install @snowplow/browser-tracker-core +``` + +## Usage + +```js +import { addTracker, createSharedState, getTracker } from '@snowplow/browser-tracker-core'; + +const sharedState = createSharedState(); +const tracker = addTracker('snowplow_sp1', 'sp1', 'js-3.0.0', '{{collector}}', sharedState, {}); // Also stores reference at module level +const sameTracker = getTracker('snowplow_sp1'); +``` + +### Example + +```js +const domainUserId = tracker.getDomainUserId(); +``` + +## Other features + +This package contains a number of helper functions for tracking events in the browser as well as the core functionality of the Snowplow JavaScript Tracker. + +## Copyright and license + +Licensed and distributed under the [BSD 3-Clause License](LICENSE) ([An OSI Approved License][osi]). + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang. + +All rights reserved. + +[npm-url]: https://www.npmjs.com/package/@snowplow/tracker-core +[npm-image]: https://img.shields.io/npm/v/@snowplow/tracker-core +[docs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-tracker/ +[osi]: https://opensource.org/licenses/BSD-3-Clause +[license-image]: https://img.shields.io/npm/l/@snowplow/browser-tracker-core diff --git a/libraries/browser-tracker-core/jest.config.js b/libraries/browser-tracker-core/jest.config.js new file mode 100644 index 000000000..71b642154 --- /dev/null +++ b/libraries/browser-tracker-core/jest.config.js @@ -0,0 +1,10 @@ +module.exports = { + preset: 'ts-jest', + reporters: ['jest-standard-reporter'], + testEnvironment: 'jest-environment-jsdom-global', + setupFilesAfterEnv: ['../../setupTestGlobals.ts'], + testEnvironmentOptions: { + url: 'https://snowplow-js-tracker.local/test/page.html', + referrer: 'https://example.com/', + }, +}; diff --git a/libraries/browser-tracker-core/package.json b/libraries/browser-tracker-core/package.json new file mode 100644 index 000000000..4300af6c6 --- /dev/null +++ b/libraries/browser-tracker-core/package.json @@ -0,0 +1,51 @@ +{ + "name": "@snowplow/browser-tracker-core", + "version": "4.10.0", + "description": "Core functionality for Snowplow Browser trackers", + "homepage": "http://bit.ly/sp-js", + "bugs": "https://github.com/snowplow/snowplow-javascript-tracker/issues", + "repository": { + "type": "git", + "url": "https://github.com/snowplow/snowplow-javascript-tracker.git" + }, + "license": "BSD-3-Clause", + "author": "Paul Boocock", + "sideEffects": false, + "main": "./dist/index.umd.js", + "module": "./dist/index.module.js", + "types": "./dist/index.module.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "rollup -c --silent --failAfterWarnings", + "test": "jest" + }, + "dependencies": { + "@snowplow/tracker-core": "workspace:*", + "tslib": "^2.3.1", + "uuid": "^11.1.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "~21.0.2", + "@rollup/plugin-node-resolve": "~13.1.3", + "@types/jest": "~28.1.1", + "@types/jsdom": "~16.2.14", + "@typescript-eslint/eslint-plugin": "~5.15.0", + "@typescript-eslint/parser": "~5.15.0", + "eslint": "~8.11.0", + "jest": "~28.1.3", + "jest-environment-jsdom": "~28.1.3", + "jest-environment-jsdom-global": "~4.0.0", + "jest-standard-reporter": "~2.0.0", + "rollup": "~2.70.1", + "rollup-plugin-cleanup": "~3.2.1", + "rollup-plugin-license": "~2.6.1", + "rollup-plugin-terser": "~7.0.2", + "rollup-plugin-ts": "~2.0.5", + "ts-jest": "~28.0.8", + "typescript": "~4.6.2", + "@testing-library/dom": "~9.3.1", + "whatwg-fetch": "~3.6.20" + } +} diff --git a/libraries/browser-tracker-core/rollup.config.js b/libraries/browser-tracker-core/rollup.config.js new file mode 100644 index 000000000..3f02fc230 --- /dev/null +++ b/libraries/browser-tracker-core/rollup.config.js @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import ts from 'rollup-plugin-ts'; // Prefered over @rollup/plugin-typescript as it bundles .d.ts files +import { banner } from '../../banner'; +import { terser } from 'rollup-plugin-terser'; +import cleanup from 'rollup-plugin-cleanup'; +import pkg from './package.json'; +import { builtinModules } from 'module'; + +const umdPlugins = [nodeResolve({ browser: true }), commonjs(), ts()]; +const umdName = 'snowplowBrowserTrackerCore'; + +export default [ + // CommonJS (for Node) and ES module (for bundlers) build. + { + input: './src/index.ts', + plugins: [...umdPlugins, banner()], + output: [{ file: pkg.main, format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + plugins: [...umdPlugins, terser(), cleanup({ comments: 'none' }), banner()], + output: [{ file: pkg.main.replace('.js', '.min.js'), format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + external: [...builtinModules, ...Object.keys(pkg.dependencies), ...Object.keys(pkg.devDependencies)], + plugins: [ + ts(), // so Rollup can convert TypeScript to JavaScript + banner(), + ], + output: [{ file: pkg.module, format: 'es', sourcemap: true }], + }, +]; diff --git a/libraries/browser-tracker-core/src/detectors.ts b/libraries/browser-tracker-core/src/detectors.ts new file mode 100644 index 000000000..8a2d9eb46 --- /dev/null +++ b/libraries/browser-tracker-core/src/detectors.ts @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Checks whether sessionStorage is available, in a way that + * does not throw a SecurityError in Firefox if "always ask" + * is enabled for cookies (https://github.com/snowplow/snowplow/issues/163). + */ +export function hasSessionStorage() { + try { + return !!window.sessionStorage; + } catch (e) { + return true; // SecurityError when referencing it means it exists + } +} + +/* + * Checks whether localStorage is available, in a way that + * does not throw a SecurityError in Firefox if "always ask" + * is enabled for cookies (https://github.com/snowplow/snowplow/issues/163). + */ +export function hasLocalStorage() { + try { + return !!window.localStorage; + } catch (e) { + return true; // SecurityError when referencing it means it exists + } +} + +/* + * Checks whether localStorage is accessible + * sets and removes an item to handle private IOS5 browsing + * (http://git.io/jFB2Xw) + */ +export function localStorageAccessible() { + var mod = 'modernizr'; + if (!hasLocalStorage()) { + return false; + } + try { + const ls = window.localStorage; + ls.setItem(mod, mod); + ls.removeItem(mod); + return true; + } catch (e) { + return false; + } +} diff --git a/libraries/browser-tracker-core/src/helpers/browser_props.ts b/libraries/browser-tracker-core/src/helpers/browser_props.ts new file mode 100644 index 000000000..6af2b45d7 --- /dev/null +++ b/libraries/browser-tracker-core/src/helpers/browser_props.ts @@ -0,0 +1,154 @@ +interface BrowserProperties { + viewport?: string | null; + documentSize?: string | null; + resolution?: string | null; + colorDepth: number; + devicePixelRatio: number; + cookiesEnabled: boolean; + online: boolean; + browserLanguage: string; + documentLanguage: string; + webdriver: boolean; + deviceMemory?: number; // Optional because it's not supported in all browsers + hardwareConcurrency?: number; +} + +function useResizeObserver(): boolean { + return 'ResizeObserver' in window; +} + +let resizeObserverInitialized = false; +let readBrowserPropertiesTask: number | null = null; +function initializeResizeObserver() { + if (resizeObserverInitialized) { + return; + } + if (!document || !document.body || !document.documentElement) { + return; + } + resizeObserverInitialized = true; + + const resizeObserver = new ResizeObserver(() => { + if (!readBrowserPropertiesTask) { + // The browser property lookup causes a forced synchronous layout when offsets/sizes are + // queried. It's possible that the forced synchronous layout causes the ResizeObserver + // to be fired again, leading to an infinite loop and the "ResizeObserver loop completed + // with undelivered notifications" error. + readBrowserPropertiesTask = requestAnimationFrame(() => { + readBrowserPropertiesTask = null; + cachedProperties = readBrowserProperties(); + }); + } + }); + resizeObserver.observe(document.body); + resizeObserver.observe(document.documentElement); +} + +let cachedProperties: BrowserProperties; + +/** + * Resets module-level browser property state. Used in tests to prevent state bleed between test cases. + * @internal + */ +export function resetBrowserPropertiesState() { + cachedProperties = undefined as any; + resizeObserverInitialized = false; + readBrowserPropertiesTask = null; +} + +/** + * Gets various browser properties (that are expensive to read!) + * - Will use a "ResizeObserver" approach in modern browsers to update cached properties only on change + * - Will fallback to a direct read approach without cache in old browsers + * + * @returns BrowserProperties + */ +export function getBrowserProperties() { + if (!useResizeObserver()) { + // TODO: per-event forced reflow — each call re-reads layout geometry (offsetWidth, scrollHeight, + // etc.) for browsers without ResizeObserver. ResizeObserver has been in all major browsers since + // 2020 so this is an edge-case path. File a separate ticket to address if needed. + return readBrowserProperties(); + } + + if (!cachedProperties) { + cachedProperties = readBrowserProperties(); + } + initializeResizeObserver(); + return cachedProperties; +} + +/** + * Reads the browser properties - expensive call! + * + * @returns BrowserProperties + */ +function readBrowserProperties(): BrowserProperties { + return { + viewport: detectViewport(), + documentSize: detectDocumentSize(), + resolution: detectScreenResolution(), + colorDepth: screen.colorDepth, + devicePixelRatio: window.devicePixelRatio, + cookiesEnabled: window.navigator.cookieEnabled, + online: window.navigator.onLine, + browserLanguage: window.navigator.language || (window.navigator as any).userLanguage, + documentLanguage: document.documentElement.lang, + webdriver: window.navigator.webdriver, + deviceMemory: (window.navigator as any).deviceMemory, + hardwareConcurrency: Math.floor(window.navigator.hardwareConcurrency) || undefined, + }; +} + +/** + * Gets the current viewport. + * + * Code based on: + * - http://andylangton.co.uk/articles/javascript/get-viewport-size-javascript/ + * - http://responsejs.com/labs/dimensions/ + */ +function detectViewport() { + var width, height; + + if ('innerWidth' in window) { + width = window['innerWidth']; + height = window['innerHeight']; + } else { + const e = document.documentElement || document.body; + width = e['clientWidth']; + height = e['clientHeight']; + } + + return makeDimension(Math.max(0, width), Math.max(0, height)); +} + +/** + * Gets the dimensions of the current + * document. + * + * Code based on: + * - http://andylangton.co.uk/articles/javascript/get-viewport-size-javascript/ + */ +function detectDocumentSize() { + var de = document.documentElement, // Alias + be = document.body, + // document.body may not have rendered, so check whether be.offsetHeight is null + bodyHeight = be ? Math.max(be.offsetHeight, be.scrollHeight) : 0; + + return makeDimension( + Math.max(de.clientWidth, de.offsetWidth, de.scrollWidth), + Math.max(de.clientHeight, de.offsetHeight, de.scrollHeight, bodyHeight) + ); +} + +function detectScreenResolution() { + return makeDimension(screen.width, screen.height); +} + +export function makeDimension(width: number, height: number): string | null { + if (isNaN(width) || isNaN(height)) { + return null; + } + + return Math.floor(width) + 'x' + Math.floor(height); +} diff --git a/libraries/browser-tracker-core/src/helpers/cross_domain.ts b/libraries/browser-tracker-core/src/helpers/cross_domain.ts new file mode 100644 index 000000000..75fc8c088 --- /dev/null +++ b/libraries/browser-tracker-core/src/helpers/cross_domain.ts @@ -0,0 +1,72 @@ +import { ExtendedCrossDomainLinkerAttributes, Platform } from '../tracker/types'; + +const DEFAULT_CROSS_DOMAIN_LINKER_PARAMS: ExtendedCrossDomainLinkerAttributes = { + sessionId: true, + sourceId: true, + sourcePlatform: false, + userId: false, + reason: false, +}; + +interface ExtendedCrossDomainLinkerValues { + domainUserId?: string; + /* Timestamp of the cross-domain link click. */ + timestamp?: number; + /* Current user ID as set with setUserId(). */ + userId?: string; + /* Visitor ID. */ + sessionId?: string; + /* The app ID. */ + sourceId?: string; + sourcePlatform?: Platform; + /* Link text of the cross-domain link. */ + reason?: string; +} + +export function createCrossDomainParameterValue( + isExtendedFormat: boolean, + attributeConfiguration: ExtendedCrossDomainLinkerAttributes | undefined, + attributeValues: ExtendedCrossDomainLinkerValues & { + /* As `reason` might be a callback, we also need to pass the event to calculate the reason value. */ + event: Event; + } +): string { + let crossDomainParameterValue; + const timestamp = new Date().getTime(); + const config = { ...DEFAULT_CROSS_DOMAIN_LINKER_PARAMS, ...attributeConfiguration }; + const { domainUserId, userId, sessionId, sourceId, sourcePlatform, event } = attributeValues; + + const eventTarget = event.currentTarget as HTMLAnchorElement | HTMLAreaElement | null; + const reason = typeof config.reason === 'function' ? config.reason(event) : eventTarget?.textContent?.trim(); + + if (isExtendedFormat) { + /* Index is used by Enrich, so it should not be changed. */ + crossDomainParameterValue = [ + domainUserId, + timestamp, + config.sessionId && sessionId, + config.userId && urlSafeBase64Encode(userId || ''), + config.sourceId && urlSafeBase64Encode(sourceId || ''), + config.sourcePlatform && sourcePlatform, + config.reason && urlSafeBase64Encode(reason || ''), + ] + .map((attribute) => attribute || '') + .join('.') + // Remove trailing dots + .replace(/([.]*$)/, ''); + } else { + crossDomainParameterValue = attributeValues.domainUserId + '.' + timestamp; + } + + return crossDomainParameterValue; +} + +/** + * + * The url-safe variation emits - and _ instead of + and / characters. Also removes = sign padding. + * @param {string} str The string to encode in a URL safe manner + * @return {string} + */ +export function urlSafeBase64Encode(str: string) { + return btoa(str).replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, ''); +} diff --git a/libraries/browser-tracker-core/src/helpers/index.ts b/libraries/browser-tracker-core/src/helpers/index.ts new file mode 100755 index 000000000..b21da64df --- /dev/null +++ b/libraries/browser-tracker-core/src/helpers/index.ts @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +export * from './storage'; +export * from './cross_domain'; + +declare global { + interface EventTarget { + attachEvent?: (type: string, fn: EventListenerOrEventListenerObject) => void; + } +} + +/** + * The criteria which will be used to filter results to specific classes or elements + */ +export interface FilterCriterion { + /** A collection of class names to include */ + allowlist?: string[]; + /** A collector of class names to exclude */ + denylist?: string[]; + /** A callback which returns a boolean as to whether the element should be included */ + filter?: (elt: T) => boolean; +} + +/** + * Checks if an object is a string + * @param str - The object to check + */ +export function isString(str: Object): str is string { + if (str && typeof str.valueOf() === 'string') { + return true; + } + return false; +} + +/** + * Checks if an object is an integer + * @param int - The object to check + */ +export function isInteger(int: Object): int is number { + return ( + (Number.isInteger && Number.isInteger(int)) || (typeof int === 'number' && isFinite(int) && Math.floor(int) === int) + ); +} + +/** + * Checks if the input parameter is a function + * @param func - The object to check + */ +export function isFunction(func: unknown) { + if (func && typeof func === 'function') { + return true; + } + return false; +} + +/** + * Lightweight configured runtime timezone detection + * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/resolvedOptions#getting_the_users_time_zone_and_locale_preferences + * @returns IANA timezone name of current runtime preference + */ +export function getTimeZone(): string | void { + if (typeof Intl === 'object' && typeof Intl.DateTimeFormat === 'function') { + const systemPreferences = new Intl.DateTimeFormat().resolvedOptions(); + return systemPreferences.timeZone; + } +} + +/** + * Cleans up the page title + */ +export function fixupTitle(title: string | { text: string }) { + if (!isString(title)) { + title = title.text || ''; + + var tmp = document.getElementsByTagName('title'); + if (tmp && tmp[0] != null) { + title = tmp[0].text; + } + } + return title; +} + +/** + * Extract hostname from URL + */ +export function getHostName(url: string) { + // scheme : // [username [: password] @] hostname [: port] [/ [path] [? query] [# fragment]] + var e = new RegExp('^(?:(?:https?|ftp):)/*(?:[^@]+@)?([^:/#]+)'), + matches = e.exec(url); + + return matches ? matches[1] : url; +} + +/** + * Fix-up domain + */ +export function fixupDomain(domain: string) { + var dl = domain.length; + + // remove trailing '.' + if (domain.charAt(--dl) === '.') { + domain = domain.slice(0, dl); + } + // remove leading '*' + if (domain.slice(0, 2) === '*.') { + domain = domain.slice(1); + } + return domain; +} + +/** + * Get page referrer. In the case of a single-page app, + * if the URL changes without the page reloading, pass + * in the old URL. It will be returned unless overriden + * by a "refer(r)er" parameter in the querystring. + * + * @param string - oldLocation Optional. + * @returns string The referrer + */ +export function getReferrer(oldLocation?: string) { + let windowAlias = window, + fromQs = + fromQuerystring('referrer', windowAlias.location.href) || fromQuerystring('referer', windowAlias.location.href); + + // Short-circuit + if (fromQs) { + return fromQs; + } + + // In the case of a single-page app, return the old URL + if (oldLocation) { + return oldLocation; + } + + try { + if (windowAlias.top) { + return windowAlias.top.document.referrer; + } else if (windowAlias.parent) { + return windowAlias.parent.document.referrer; + } + } catch {} + + return document.referrer; +} + +/** + * Cross-browser helper function to add event handler + */ +export function addEventListener( + element: HTMLElement | EventTarget, + eventType: string, + eventHandler: EventListenerOrEventListenerObject, + options?: boolean | AddEventListenerOptions +) { + if (element.addEventListener) { + element.addEventListener(eventType, eventHandler, options); + return true; + } + + // IE Support + if (element.attachEvent) { + return element.attachEvent('on' + eventType, eventHandler); + } + (element as any)['on' + eventType] = eventHandler; +} + +/** + * Return value from name-value pair in querystring + */ +export function fromQuerystring(field: string, url: string) { + var match = new RegExp('^[^#]*[?&]' + field + '=([^&#]*)').exec(url); + if (!match) { + return null; + } + return decodeURIComponent(match[1].replace(/\+/g, ' ')); +} + +/** + * Add a name-value pair to the querystring of a URL + * + * @param string - url URL to decorate + * @param string - name Name of the querystring pair + * @param string - value Value of the querystring pair + */ +export function decorateQuerystring(url: string, name: string, value: string) { + var initialQsParams = name + '=' + value; + var hashSplit = url.split('#'); + var qsSplit = hashSplit[0].split('?'); + var beforeQuerystring = qsSplit.shift(); + // Necessary because a querystring may contain multiple question marks + var querystring = qsSplit.join('?'); + if (!querystring) { + querystring = initialQsParams; + } else { + // Whether this is the first time the link has been decorated + var initialDecoration = true; + var qsFields = querystring.split('&'); + for (var i = 0; i < qsFields.length; i++) { + if (qsFields[i].substr(0, name.length + 1) === name + '=') { + initialDecoration = false; + qsFields[i] = initialQsParams; + querystring = qsFields.join('&'); + break; + } + } + if (initialDecoration) { + querystring = initialQsParams + '&' + querystring; + } + } + hashSplit[0] = beforeQuerystring + '?' + querystring; + return hashSplit.join('#'); +} + +/** + * Finds the root domain + */ +export function findRootDomain(sameSite: string, secure: boolean) { + const windowLocationHostnameAlias = window.location.hostname, + cookiePrefix = '_sp_root_domain_test_', + cookieName = cookiePrefix + new Date().getTime(), + cookieValue = '_test_value_' + new Date().getTime(); + + const locationParts = windowLocationHostnameAlias.split('.'); + for (let idx = locationParts.length - 2; idx >= 0; idx--) { + const currentDomain = locationParts.slice(idx).join('.'); + cookie(cookieName, cookieValue, 0, '/', currentDomain, sameSite, secure); + if (cookie(cookieName) === cookieValue) { + // Clean up created cookie(s) + deleteCookie(cookieName, '/', currentDomain, sameSite, secure); + const cookieNames = getCookiesWithPrefix(cookiePrefix); + for (let i = 0; i < cookieNames.length; i++) { + deleteCookie(cookieNames[i], '/', currentDomain, sameSite, secure); + } + + return currentDomain; + } + } + + // Cookies cannot be read + return windowLocationHostnameAlias; +} + +/** + * Checks whether a value is present within an array + * + * @param val - The value to check for + * @param array - The array to check within + * @returns boolean Whether it exists + */ +export function isValueInArray(val: T, array: T[]) { + for (var i = 0; i < array.length; i++) { + if (array[i] === val) { + return true; + } + } + return false; +} + +/** + * Deletes an arbitrary cookie by setting the expiration date to the past + * + * @param cookieName - The name of the cookie to delete + * @param domainName - The domain the cookie is in + */ +export function deleteCookie(cookieName: string, path?: string, domainName?: string, sameSite?: string, secure?: boolean) { + cookie(cookieName, '', -1, path, domainName, sameSite, secure); +} + +/** + * Fetches the name of all cookies beginning with a certain prefix + * + * @param cookiePrefix - The prefix to check for + * @returns array The cookies that begin with the prefix + */ +export function getCookiesWithPrefix(cookiePrefix: string) { + var cookies = document.cookie.split('; '); + var cookieNames = []; + for (var i = 0; i < cookies.length; i++) { + if (cookies[i].substring(0, cookiePrefix.length) === cookiePrefix) { + cookieNames.push(cookies[i]); + } + } + return cookieNames; +} + +/** + * Get and set the cookies associated with the current document in browser + * This implementation always returns a string, returns the cookie value if only name is specified + * + * @param name - The cookie name (required) + * @param value - The cookie value + * @param ttl - The cookie Time To Live (seconds) + * @param path - The cookies path + * @param domain - The cookies domain + * @param samesite - The cookies samesite attribute + * @param secure - Boolean to specify if cookie should be secure + * @returns string The cookies value + */ +export function cookie( + name: string, + value?: string, + ttl?: number, + path?: string, + domain?: string, + samesite?: string, + secure?: boolean +) { + if (arguments.length > 1) { + return (document.cookie = + name + + '=' + + encodeURIComponent(value ?? '') + + (ttl ? '; Expires=' + new Date(+new Date() + ttl * 1000).toUTCString() : '') + + (path ? '; Path=' + path : '') + + (domain ? '; Domain=' + domain : '') + + (samesite ? '; SameSite=' + samesite : '') + + (secure ? '; Secure' : '')); + } + + return decodeURIComponent((('; ' + document.cookie).split('; ' + name + '=')[1] || '').split(';')[0]); +} + +/** + * Parses an object and returns either the + * integer or undefined. + * + * @param obj - The object to parse + * @returns the result of the parse operation + */ +export function parseAndValidateInt(obj: unknown) { + var result = parseInt(obj as string); + return isNaN(result) ? undefined : result; +} + +/** + * Parses an object and returns either the + * number or undefined. + * + * @param obj - The object to parse + * @returns the result of the parse operation + */ +export function parseAndValidateFloat(obj: unknown) { + var result = parseFloat(obj as string); + return isNaN(result) ? undefined : result; +} + +/** + * Convert a criterion object to a filter function + * + * @param object - criterion Either {allowlist: [array of allowable strings]} + * or {denylist: [array of allowable strings]} + * or {filter: function (elt) {return whether to track the element} + * @param boolean - byClass Whether to allowlist/denylist based on an element's classes (for forms) + * or name attribute (for fields) + */ +export function getFilterByClass(criterion?: FilterCriterion | null): (elt: HTMLElement) => boolean { + // If the criterion argument is not an object, add listeners to all elements + if (criterion == null || typeof criterion !== 'object' || Array.isArray(criterion)) { + return function () { + return true; + }; + } + + const inclusive = Object.prototype.hasOwnProperty.call(criterion, 'allowlist'); + const specifiedClassesSet = getSpecifiedClassesSet(criterion); + + return getFilter(criterion, function (elt: HTMLElement) { + return checkClass(elt, specifiedClassesSet) === inclusive; + }); +} + +/** + * Convert a criterion object to a filter function + * + * @param object - criterion Either {allowlist: [array of allowable strings]} + * or {denylist: [array of allowable strings]} + * or {filter: function (elt) {return whether to track the element} + */ +export function getFilterByName(criterion?: FilterCriterion): (elt: T) => boolean { + // If the criterion argument is not an object, add listeners to all elements + if (criterion == null || typeof criterion !== 'object' || Array.isArray(criterion)) { + return function () { + return true; + }; + } + + const inclusive = criterion.hasOwnProperty('allowlist'); + const specifiedClassesSet = getSpecifiedClassesSet(criterion); + + return getFilter(criterion, function (elt: T) { + return elt.name in specifiedClassesSet === inclusive; + }); +} + +/** + * List the classes of a DOM element without using elt.classList (for compatibility with IE 9) + */ +export function getCssClasses(elt: Element) { + return elt.className.match(/\S+/g) || []; +} + +/** + * Check whether an element has at least one class from a given list + */ +function checkClass(elt: Element, classList: Record) { + var classes = getCssClasses(elt); + + for (const className of classes) { + if (classList[className]) { + return true; + } + } + + return false; +} + +function getFilter(criterion: FilterCriterion, fallbackFilter: (elt: T) => boolean) { + if (criterion.hasOwnProperty('filter') && criterion.filter) { + return criterion.filter; + } + + return fallbackFilter; +} + +function getSpecifiedClassesSet(criterion: FilterCriterion) { + // Convert the array of classes to an object of the form {class1: true, class2: true, ...} + var specifiedClassesSet: Record = {}; + var specifiedClasses = criterion.allowlist || criterion.denylist; + + if (specifiedClasses) { + if (!Array.isArray(specifiedClasses)) { + specifiedClasses = [specifiedClasses]; + } + + for (var i = 0; i < specifiedClasses.length; i++) { + specifiedClassesSet[specifiedClasses[i]] = true; + } + } + + return specifiedClassesSet; +} diff --git a/libraries/browser-tracker-core/src/helpers/sha1.ts b/libraries/browser-tracker-core/src/helpers/sha1.ts new file mode 100644 index 000000000..af6a8c5ea --- /dev/null +++ b/libraries/browser-tracker-core/src/helpers/sha1.ts @@ -0,0 +1,98 @@ +/** + * Pure-JS SHA-1 implementation (FIPS 180-4). + * Replaces the `sha1` npm package to avoid pulling in a Node.js `Buffer` + * polyfill (~28 KB) when bundled for the browser. + */ +/** Compute SHA-1 hex digest of a UTF-8 string (FIPS 180-4). */ +export function sha1(message: string): string { + // Encode UTF-8 + const bytes: number[] = []; + for (let i = 0; i < message.length; i++) { + let c = message.charCodeAt(i); + if (c < 0x80) { + bytes.push(c); + } else if (c < 0x800) { + bytes.push(0xc0 | (c >> 6), 0x80 | (c & 0x3f)); + } else if (c >= 0xd800 && c <= 0xdbff && i + 1 < message.length) { + const next = message.charCodeAt(++i); + c = 0x10000 + ((c & 0x3ff) << 10) + (next & 0x3ff); + bytes.push(0xf0 | (c >> 18), 0x80 | ((c >> 12) & 0x3f), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f)); + } else { + bytes.push(0xe0 | (c >> 12), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f)); + } + } + + // Pre-processing: pad to 512-bit blocks + const bitLen = bytes.length * 8; + bytes.push(0x80); + while (bytes.length % 64 !== 56) bytes.push(0); + // Append length as 64-bit big-endian (high 32 bits always 0 for strings < 512 MB) + bytes.push(0, 0, 0, 0); + bytes.push((bitLen >>> 24) & 0xff, (bitLen >>> 16) & 0xff, (bitLen >>> 8) & 0xff, bitLen & 0xff); + + // Initialize hash values + let h0 = 0x67452301; + let h1 = 0xefcdab89; + let h2 = 0x98badcfe; + let h3 = 0x10325476; + let h4 = 0xc3d2e1f0; + + // Process each 512-bit block + const w = new Array(80); + for (let offset = 0; offset < bytes.length; offset += 64) { + for (let i = 0; i < 16; i++) { + w[i] = + (bytes[offset + i * 4] << 24) | + (bytes[offset + i * 4 + 1] << 16) | + (bytes[offset + i * 4 + 2] << 8) | + bytes[offset + i * 4 + 3]; + } + for (let i = 16; i < 80; i++) { + const n = w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]; + w[i] = (n << 1) | (n >>> 31); + } + + let a = h0, + b = h1, + c = h2, + d = h3, + e = h4; + + for (let i = 0; i < 80; i++) { + let f: number, k: number; + if (i < 20) { + f = (b & c) | (~b & d); + k = 0x5a827999; + } else if (i < 40) { + f = b ^ c ^ d; + k = 0x6ed9eba1; + } else if (i < 60) { + f = (b & c) | (b & d) | (c & d); + k = 0x8f1bbcdc; + } else { + f = b ^ c ^ d; + k = 0xca62c1d6; + } + const temp = (((a << 5) | (a >>> 27)) + f + e + k + w[i]) | 0; + e = d; + d = c; + c = (b << 30) | (b >>> 2); + b = a; + a = temp; + } + + h0 = (h0 + a) | 0; + h1 = (h1 + b) | 0; + h2 = (h2 + c) | 0; + h3 = (h3 + d) | 0; + h4 = (h4 + e) | 0; + } + + // Produce hex digest + let hex = ''; + for (const h of [h0, h1, h2, h3, h4]) { + const part = (h >>> 0).toString(16); + hex += (part.length < 8 ? '00000000'.slice(part.length) : '') + part; + } + return hex; +} diff --git a/libraries/browser-tracker-core/src/helpers/storage.ts b/libraries/browser-tracker-core/src/helpers/storage.ts new file mode 100644 index 000000000..c5e897695 --- /dev/null +++ b/libraries/browser-tracker-core/src/helpers/storage.ts @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Attempt to get a value from localStorage + * + * @param string - key + * @returns string The value obtained from localStorage, or + * undefined if localStorage is inaccessible + */ +export function attemptGetLocalStorage(key: string) { + try { + const localStorageAlias = window.localStorage, + exp = localStorageAlias.getItem(key + '.expires'); + if (exp === null || +exp > Date.now()) { + return localStorageAlias.getItem(key); + } else { + localStorageAlias.removeItem(key); + localStorageAlias.removeItem(key + '.expires'); + } + return undefined; + } catch (e) { + return undefined; + } +} + +/** + * Attempt to write a value to localStorage + * + * @param string - key + * @param string - value + * @param number - ttl Time to live in seconds, defaults to 2 years from Date.now() + * @returns boolean Whether the operation succeeded + */ +export function attemptWriteLocalStorage(key: string, value: string, ttl = 63072000) { + try { + const localStorageAlias = window.localStorage, + t = Date.now() + ttl * 1000; + localStorageAlias.setItem(`${key}.expires`, t.toString()); + localStorageAlias.setItem(key, value); + return true; + } catch (e) { + return false; + } +} + +/** + * Attempt to delete a value from localStorage + * + * @param string - key + * @returns boolean Whether the operation succeeded + */ +export function attemptDeleteLocalStorage(key: string) { + try { + const localStorageAlias = window.localStorage; + localStorageAlias.removeItem(key); + localStorageAlias.removeItem(key + '.expires'); + return true; + } catch (e) { + return false; + } +} + +/** + * Attempt to get a value from sessionStorage + * + * @param string - key + * @returns string The value obtained from sessionStorage, or + * undefined if sessionStorage is inaccessible + */ +export function attemptGetSessionStorage(key: string) { + try { + return window.sessionStorage.getItem(key); + } catch (e) { + return undefined; + } +} + +/** + * Attempt to write a value to sessionStorage + * + * @param string - key + * @param string - value + * @returns boolean Whether the operation succeeded + */ +export function attemptWriteSessionStorage(key: string, value: string) { + try { + window.sessionStorage.setItem(key, value); + return true; + } catch (e) { + return false; + } +} diff --git a/libraries/browser-tracker-core/src/index.ts b/libraries/browser-tracker-core/src/index.ts new file mode 100644 index 000000000..8cff15c16 --- /dev/null +++ b/libraries/browser-tracker-core/src/index.ts @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * The core for the Snowplow Browser Tracker + * Contains the {@Link BrowserTracker} and a collection of helper methods + * + * @packageDocumentation + */ + +export * from './snowplow'; +export * from './tracker/types'; +export * from './helpers'; +export * from './detectors'; +export * from './proxies'; +export * from './plugins'; +export * from './state'; diff --git a/libraries/browser-tracker-core/src/plugins.ts b/libraries/browser-tracker-core/src/plugins.ts new file mode 100644 index 000000000..f66b2dd7c --- /dev/null +++ b/libraries/browser-tracker-core/src/plugins.ts @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { CorePlugin } from '@snowplow/tracker-core'; +import { BrowserTracker } from './tracker/types'; + +/** + * Interface which defines Core Plugins + */ +export interface BrowserPlugin extends CorePlugin { + /** + * Called when the plugin is initialised during the Tracker construction + * + * @remarks + * Use to capture the specific Tracker instance for each instance of a Browser Plugin + */ + activateBrowserPlugin?: (tracker: BrowserTracker) => void; +} diff --git a/libraries/browser-tracker-core/src/proxies.ts b/libraries/browser-tracker-core/src/proxies.ts new file mode 100644 index 000000000..90a976d21 --- /dev/null +++ b/libraries/browser-tracker-core/src/proxies.ts @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { fromQuerystring, getHostName } from './helpers'; + +/* + * Extract parameter from URL + */ +function getParameter(url: string, name: string) { + // scheme : // [username [: password] @] hostname [: port] [/ [path] [? query] [# fragment]] + var e = new RegExp('^(?:https?|ftp)(?::/*(?:[^?]+))([?][^#]+)'), + matches = e.exec(url); + + if (matches && matches?.length > 1) { + return fromQuerystring(name, matches[1]); + } + return null; +} + +/* + * Fix-up URL when page rendered from search engine cache or translated page. + */ +export function fixupUrl(hostName: string, href: string, referrer: string) { + if (hostName === 'translate.googleusercontent.com') { + // Google + if (referrer === '') { + referrer = href; + } + href = getParameter(href, 'u') ?? ''; + hostName = getHostName(href); + } else if ( + hostName === 'cc.bingj.com' || // Bing & Yahoo + hostName === 'webcache.googleusercontent.com' // Google + ) { + href = document.links[0].href; + hostName = getHostName(href); + } + return [hostName, href, referrer]; +} diff --git a/libraries/browser-tracker-core/src/snowplow.ts b/libraries/browser-tracker-core/src/snowplow.ts new file mode 100644 index 000000000..3161f50e8 --- /dev/null +++ b/libraries/browser-tracker-core/src/snowplow.ts @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { LOG } from '@snowplow/tracker-core'; +import { SharedState } from './state'; +import { Tracker } from './tracker'; +import { BrowserTracker, TrackerConfiguration } from './tracker/types'; +import { asyncCookieStorage } from './tracker/cookie_storage'; + +const namedTrackers: Record = {}; + +/** + * Dispatch function to all specified trackers + * + * @param trackers - An optional list of trackers to send the event to, or will send to all trackers + * @param fn - The function which will run against each tracker + */ +export function dispatchToTrackers(trackers: Array | undefined, fn: (t: BrowserTracker) => void) { + try { + getTrackers(trackers ?? allTrackerNames()).forEach(fn); + } catch (ex) { + LOG.error('Function failed', ex); + } +} + +/** + * Dispatch function to all specified trackers from the supplied collection + * + * @param trackers - An optional list of trackers to send the event to, or will send to all trackers + * @param trackerCollection - The collection which the trackers will be selected from + * @param fn - The function which will run against each tracker + */ +export function dispatchToTrackersInCollection( + trackers: Array | undefined, + trackerCollection: Record, + fn: (t: BrowserTracker) => void +) { + try { + getTrackersFromCollection(trackers ?? Object.keys(trackerCollection), trackerCollection).forEach(fn); + } catch (ex) { + LOG.error('Function failed', ex); + } +} + +/** + * Checks if a tracker has been created for a particular identifier + * @param trackerId - The unique identifier of the tracker + */ +export function trackerExists(trackerId: string) { + return namedTrackers.hasOwnProperty(trackerId); +} + +/** + * Creates a Tracker and adds it to the internal collection + * @param trackerId - The unique identifier of the tracker + * @param namespace - The namespace of the tracker, tracked with each event as `tna` + * @param version - The current version of the tracker library + * @param endpoint - The endpoint to send events to + * @param sharedState - The instance of shared state to use for this tracker + * @param configuration - The configuration to use for this tracker instance + */ +export function addTracker( + trackerId: string, + namespace: string, + version: string, + endpoint: string, + sharedState: SharedState, + configuration?: TrackerConfiguration +) { + if (!namedTrackers.hasOwnProperty(trackerId)) { + namedTrackers[trackerId] = Tracker(trackerId, namespace, version, endpoint, sharedState, configuration); + return namedTrackers[trackerId]; + } + return null; +} + +/** + * Gets a single instance of the internal tracker object + * @param trackerId - The unique identifier of the tracker + * @returns The tracker instance, or null if not found + */ +export function getTracker(trackerId: string) { + if (namedTrackers.hasOwnProperty(trackerId)) { + return namedTrackers[trackerId]; + } + + LOG.warn(trackerId + ' not configured'); + return null; +} + +/** + * Gets an array of tracker instances based on the list of identifiers + * @param trackerIds - An array of unique identifiers of the trackers + * @returns The tracker instances, or empty list if none found + */ +export function getTrackers(trackerIds: Array): Array { + return getTrackersFromCollection(trackerIds, namedTrackers); +} + +/** + * Gets all the trackers as a object, keyed by their unique identifiers + */ +export function allTrackers() { + return namedTrackers; +} + +/** + * Returns all the unique tracker identifiers + */ +export function allTrackerNames() { + return Object.keys(namedTrackers); +} + +function getTrackersFromCollection( + trackerIds: Array, + trackerCollection: Record +): Array { + const trackers: Array = []; + for (const id of trackerIds) { + if (trackerCollection.hasOwnProperty(id)) { + trackers.push(trackerCollection[id]); + } else { + LOG.warn(id + ' not configured'); + } + } + return trackers; +} + +/** + * Write all pending cookies to the browser. + * Useful if you track events just before the page is unloaded. + * This call is not necessary if `synchronousCookieWrite` is set to `true`. + */ +export function flushPendingCookies() { + asyncCookieStorage.flush(); +} diff --git a/libraries/browser-tracker-core/src/state.ts b/libraries/browser-tracker-core/src/state.ts new file mode 100644 index 000000000..6aca815a4 --- /dev/null +++ b/libraries/browser-tracker-core/src/state.ts @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { addEventListener } from './helpers'; + +declare global { + interface Document { + attachEvent: (type: string, fn: EventListenerOrEventListenerObject) => void; + detachEvent: (type: string, fn: EventListenerOrEventListenerObject) => void; + } +} + +/** + * A set of variables which are shared among all initialised trackers + */ +export class SharedState { + bufferFlushers: Array<(sync: boolean) => void> = []; + + /* DOM Ready */ + hasLoaded: boolean = false; + registeredOnLoadHandlers: Array<() => void> = []; + + /* pageViewId, which can changed by other trackers on page; + * initialized by tracker sent first event */ + pageViewId?: string; + /* URL of the page view which the `pageViewId` was generated for */ + pageViewUrl?: string; +} + +export function createSharedState(): SharedState { + const sharedState = new SharedState(), + documentAlias = document, + windowAlias = window; + + /* + * Handle page visibility event + * Works everywhere except IE9 + */ + function visibilityChangeHandler() { + if (documentAlias.visibilityState == 'hidden') { + // Flush all POST queues + sharedState.bufferFlushers.forEach(function (flusher) { + flusher(false); + }); + } + } + + function flushBuffers() { + // Flush all POST queues + sharedState.bufferFlushers.forEach(function (flusher) { + flusher(false); + }); + } + + /* + * Handler for onload event + */ + function loadHandler() { + var i; + + if (!sharedState.hasLoaded) { + sharedState.hasLoaded = true; + for (i = 0; i < sharedState.registeredOnLoadHandlers.length; i++) { + sharedState.registeredOnLoadHandlers[i](); + } + } + return true; + } + + /* + * Add onload or DOM ready handler + */ + function addReadyListener() { + if (documentAlias.addEventListener) { + documentAlias.addEventListener('DOMContentLoaded', function ready() { + documentAlias.removeEventListener('DOMContentLoaded', ready, false); + loadHandler(); + }); + } else if (documentAlias.attachEvent) { + documentAlias.attachEvent('onreadystatechange', function ready() { + if (documentAlias.readyState === 'complete') { + documentAlias.detachEvent('onreadystatechange', ready); + loadHandler(); + } + }); + } + + // fallback + addEventListener(windowAlias, 'load', loadHandler, false); + } + + /************************************************************ + * Constructor + ************************************************************/ + + // initialize the Snowplow singleton + if (documentAlias.visibilityState) { + // Flush for mobile and modern browsers + addEventListener(documentAlias, 'visibilitychange', visibilityChangeHandler, false); + } + // Last attempt at flushing in beforeunload + addEventListener(windowAlias, 'beforeunload', flushBuffers, false); + + if (document.readyState === 'loading') { + addReadyListener(); + } else { + loadHandler(); + } + + return sharedState; +} diff --git a/libraries/browser-tracker-core/src/tracker/cookie_storage.ts b/libraries/browser-tracker-core/src/tracker/cookie_storage.ts new file mode 100644 index 000000000..8e329ae62 --- /dev/null +++ b/libraries/browser-tracker-core/src/tracker/cookie_storage.ts @@ -0,0 +1,208 @@ +import { cookie, deleteCookie } from '../helpers'; + + +/** + * Cookie storage interface for reading and writing cookies. + */ +export interface CookieStorage { + /** + * Get the value of a cookie + * + * @param name - The name of the cookie + * @returns The cookie value + */ + getCookie(name: string): string; + + /** + * Set a cookie + * + * @param name - The cookie name (required) + * @param value - The cookie value + * @param ttl - The cookie Time To Live (seconds) + * @param path - The cookies path + * @param domain - The cookies domain + * @param samesite - The cookies samesite attribute + * @param secure - Boolean to specify if cookie should be secure + * @returns true if the cookie was set, false otherwise + */ + setCookie( + name: string, + value?: string, + ttl?: number, + path?: string, + domain?: string, + samesite?: string, + secure?: boolean + ): boolean; + + /** + * Delete a cookie + * + * @param name - The cookie name + * @param domainName - The cookie domain name + * @param sameSite - The cookie same site attribute + * @param secure - Boolean to specify if cookie should be secure + */ + deleteCookie(name: string, path?: string, domainName?: string, sameSite?: string, secure?: boolean): void; + + /** + * Write all pending cookies. + */ + flush(): void; +} + +export interface AsyncCookieStorage extends CookieStorage { + /** + * Clear the cookie storage cache (does not delete any cookies) + */ + clearCache(): void; +} + +interface Cookie { + getValue: () => string; + setValue: (value?: string, ttl?: number, path?: string, domain?: string, samesite?: string, secure?: boolean) => boolean; + deleteValue: (path?: string, domainName?: string, sameSite?: string, secure?: boolean) => void; + flush: () => void; +} + +function newCookie(name: string): Cookie { + let flushTimer: ReturnType | undefined; + let lastSetValueArgs: Parameters | undefined; + let cacheExpireAt: Date | undefined; + let flushed = true; + const flushTimeout = 10; // milliseconds + const maxCacheTtl = 0.05; // seconds + + function getValue(): string { + // Note: we can't cache the cookie value as we don't know the expiration date + if (lastSetValueArgs && (!cacheExpireAt || cacheExpireAt > new Date())) { + return lastSetValueArgs[0] ?? cookie(name); + } + return cookie(name); + } + + function setValue(value?: string, ttl?: number, path?: string, domain?: string, samesite?: string, secure?: boolean): boolean { + lastSetValueArgs = [value, ttl, path, domain, samesite, secure]; + flushed = false; + + // throttle setting the cookie + if (flushTimer === undefined) { + flushTimer = setTimeout(() => { + flushTimer = undefined; + flush(); + }, flushTimeout); + } + + cacheExpireAt = new Date(Date.now() + Math.min(maxCacheTtl, ttl ?? maxCacheTtl) * 1000); + return true; + } + + function deleteValue(path?: string, domainName?: string, sameSite?: string, secure?: boolean): void { + lastSetValueArgs = undefined; + flushed = true; + + // cancel setting the cookie + if (flushTimer !== undefined) { + clearTimeout(flushTimer); + flushTimer = undefined; + } + + deleteCookie(name, path, domainName, sameSite, secure); + } + + function flush(): void { + if (flushTimer !== undefined) { + clearTimeout(flushTimer); + flushTimer = undefined; + } + + if (flushed) { + return; + } + flushed = true; + + if (lastSetValueArgs !== undefined) { + const [value, ttl, path, domain, samesite, secure] = lastSetValueArgs; + cookie(name, value, ttl, path, domain, samesite, secure); + } + } + + return { + getValue, + setValue, + deleteValue, + flush, + }; +} + +/** + * Create a new async cookie storage + * + * @returns A new cookie storage + */ +export function newCookieStorage(): AsyncCookieStorage { + let cache: Record = {}; + + function getOrInitCookie(name: string): Cookie { + if (!cache[name]) { + cache[name] = newCookie(name); + } + return cache[name]; + } + + function getCookie(name: string): string { + return getOrInitCookie(name).getValue(); + } + + function setCookie( + name: string, + value?: string, + ttl?: number, + path?: string, + domain?: string, + samesite?: string, + secure?: boolean + ): boolean { + return getOrInitCookie(name).setValue(value, ttl, path, domain, samesite, secure); + } + + function deleteCookie(name: string, path?: string, domainName?: string, sameSite?: string, secure?: boolean): void { + getOrInitCookie(name).deleteValue(path, domainName, sameSite, secure); + } + + function clearCache(): void { + cache = {}; + } + + function flush(): void { + for (const cookie of Object.values(cache)) { + cookie.flush(); + } + } + + return { + getCookie, + setCookie, + deleteCookie, + clearCache, + flush, + }; +} + +/** + * Cookie storage instance with asynchronous cookie writes + */ +export const asyncCookieStorage = newCookieStorage(); + +/** + * Cookie storage instance with synchronous cookie writes + */ +export const syncCookieStorage: CookieStorage = { + getCookie: cookie, + setCookie: (name, value, ttl, path, domain, samesite, secure) => { + cookie(name, value, ttl, path, domain, samesite, secure); + return document.cookie.indexOf(`${name}=`) !== -1; + }, + deleteCookie, + flush: () => {}, +}; diff --git a/libraries/browser-tracker-core/src/tracker/id_cookie.ts b/libraries/browser-tracker-core/src/tracker/id_cookie.ts new file mode 100644 index 000000000..853721dc7 --- /dev/null +++ b/libraries/browser-tracker-core/src/tracker/id_cookie.ts @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { PayloadBuilder } from '@snowplow/tracker-core'; +import { v4 as uuid } from 'uuid'; +import { ClientSession, ParsedIdCookie } from './types'; + +/** + * Indices of cookie values + */ +const cookieDisabledIndex = 0, + domainUserIdIndex = 1, + createTsIndex = 2, + visitCountIndex = 3, + nowTsIndex = 4, + lastVisitTsIndex = 5, + sessionIdIndex = 6, + previousSessionIdIndex = 7, + firstEventIdIndex = 8, + firstEventTsInMsIndex = 9, + eventIndexIndex = 10; + +export function emptyIdCookie() { + const idCookie: ParsedIdCookie = ['1', '', 0, 0, 0, undefined, '', '', '', undefined, 0]; + return idCookie; +} + +/** + * Parses the cookie values from its string representation. + * + * @param id Cookie value as string + * @param domainUserId Domain user ID to be used in case of empty cookie string + * @returns Parsed ID cookie tuple + */ +export function parseIdCookie( + id: string | undefined, + domainUserId: string, + memorizedSessionId: string, + memorizedVisitCount: number +) { + let now = new Date(), + nowTs = Math.round(now.getTime() / 1000), + tmpContainer; + + if (id) { + tmpContainer = id.split('.'); + // cookies enabled + tmpContainer.unshift('0'); + } else { + tmpContainer = [ + // cookies disabled + '1', + // Domain user ID + domainUserId, + // Creation timestamp - seconds since Unix epoch + nowTs, + // visitCount - 0 = no previous visit + memorizedVisitCount, + // Current visit timestamp + nowTs, + // Last visit timestamp - blank meaning no previous visit + '', + // Session ID + memorizedSessionId, + ]; + } + + if (!tmpContainer[sessionIdIndex] || tmpContainer[sessionIdIndex] === 'undefined') { + // session id + tmpContainer[sessionIdIndex] = uuid(); + } + if (!tmpContainer[previousSessionIdIndex] || tmpContainer[previousSessionIdIndex] === 'undefined') { + // previous session id + tmpContainer[previousSessionIdIndex] = ''; + } + if (!tmpContainer[firstEventIdIndex] || tmpContainer[firstEventIdIndex] === 'undefined') { + // firstEventId - blank meaning no previous event + tmpContainer[firstEventIdIndex] = ''; + } + if (!tmpContainer[firstEventTsInMsIndex] || tmpContainer[firstEventTsInMsIndex] === 'undefined') { + // firstEventTs - blank meaning no previous event + tmpContainer[firstEventTsInMsIndex] = ''; + } + if (!tmpContainer[eventIndexIndex] || tmpContainer[eventIndexIndex] === 'undefined') { + // eventIndex – 0 = no previous event + tmpContainer[eventIndexIndex] = 0; + } + + const parseIntOr = (value: any, defaultValue: any) => { + let parsed = parseInt(value as string); + return isNaN(parsed) ? defaultValue : parsed; + }; + const parseIntOrUndefined = (value: any) => (value ? parseIntOr(value, undefined) : undefined); + + const parsed: ParsedIdCookie = [ + tmpContainer[cookieDisabledIndex] as string, + tmpContainer[domainUserIdIndex] as string, + parseIntOr(tmpContainer[createTsIndex], nowTs), + parseIntOr(tmpContainer[visitCountIndex], memorizedVisitCount), + parseIntOr(tmpContainer[nowTsIndex], nowTs), + parseIntOrUndefined(tmpContainer[lastVisitTsIndex]), + tmpContainer[sessionIdIndex] as string, + tmpContainer[previousSessionIdIndex] as string, + tmpContainer[firstEventIdIndex] as string, + parseIntOrUndefined(tmpContainer[firstEventTsInMsIndex]), + parseIntOr(tmpContainer[eventIndexIndex], 0), + ]; + return parsed; +} + +/** + * Initializes the domain user ID if not already present in the cookie. Sets an empty string if anonymous tracking. + * + * @param idCookie Parsed cookie + * @param configAnonymousTracking Whether anonymous tracking is enabled + * @returns Domain user ID + */ +export function initializeDomainUserId(idCookie: ParsedIdCookie, configAnonymousTracking: boolean) { + let domainUserId; + if (idCookie[domainUserIdIndex]) { + domainUserId = idCookie[domainUserIdIndex]; + } else if (!configAnonymousTracking) { + domainUserId = uuid(); + idCookie[domainUserIdIndex] = domainUserId; + } else { + domainUserId = ''; + idCookie[domainUserIdIndex] = domainUserId; + } + return domainUserId; +} + +type NewSessionOptions = { + memorizedVisitCount: number; +}; + +/** + * Starts a new session with a new ID. + * Sets the previous session, last visit timestamp, and increments visit count if cookies enabled. + * First event references are reset and will be updated in `updateFirstEventInIdCookie`. + * + * @param idCookie Parsed cookie + * @param options.configStateStorageStrategy Cookie storage strategy + * @param options.configAnonymousTracking If anonymous tracking is enabled + * @param options.memorizedVisitCount Visit count to be used if cookies not enabled + * @param options.onSessionUpdateCallback Session callback triggered on every session update + * @returns New session ID + */ +export function startNewIdCookieSession( + idCookie: ParsedIdCookie, + options: NewSessionOptions = { memorizedVisitCount: 1 } +) { + const { memorizedVisitCount } = options; + + // If cookies are enabled, base visit count and session ID on the cookies + if (cookiesEnabledInIdCookie(idCookie)) { + // Store the previous session ID + idCookie[previousSessionIdIndex] = idCookie[sessionIdIndex]; + // Set lastVisitTs to currentVisitTs + idCookie[lastVisitTsIndex] = idCookie[nowTsIndex]; + // Increment the session ID + idCookie[visitCountIndex]++; + } else { + idCookie[visitCountIndex] = memorizedVisitCount; + } + + // Create a new sessionId + const sessionId = uuid(); + idCookie[sessionIdIndex] = sessionId; + + // Reset event index and first event references + idCookie[eventIndexIndex] = 0; + idCookie[firstEventIdIndex] = ''; + idCookie[firstEventTsInMsIndex] = undefined; + + return sessionId; +} + +/** + * Update now timestamp in cookie. + * + * @param idCookie Parsed cookie + */ +export function updateNowTsInIdCookie(idCookie: ParsedIdCookie) { + idCookie[nowTsIndex] = Math.round(new Date().getTime() / 1000); +} + +/** + * Updates the first event references according to the event payload if first event in session. + * + * @param idCookie - Parsed cookie + * @param payloadBuilder - Event payload builder + */ +export function updateFirstEventInIdCookie(idCookie: ParsedIdCookie, payloadBuilder: PayloadBuilder) { + // Update first event references if new session or not present + if (idCookie[eventIndexIndex] === 0) { + const payload = payloadBuilder.build(); + idCookie[firstEventIdIndex] = payload['eid'] as string; + const ts = (payload['dtm'] || payload['ttm']) as string; + idCookie[firstEventTsInMsIndex] = ts ? parseInt(ts) : undefined; + } +} + +/** + * Increments event index counter. + * + * @param idCookie Parsed cookie + */ +export function incrementEventIndexInIdCookie(idCookie: ParsedIdCookie) { + idCookie[eventIndexIndex] += 1; +} + +/** + * Serializes parsed cookie to string representation. + * + * @param idCookie Parsed cookie + * @returns String cookie value + */ +export function serializeIdCookie(idCookie: ParsedIdCookie, configAnonymousTracking: boolean) { + const anonymizedIdCookie: (string | number | undefined)[] = [...idCookie]; + if (configAnonymousTracking) { + anonymizedIdCookie[domainUserIdIndex] = ''; + anonymizedIdCookie[previousSessionIdIndex] = ''; + } + anonymizedIdCookie.shift(); + return anonymizedIdCookie.join('.'); +} + +/** + * Transforms the parsed cookie into a client session context entity. + * + * @param idCookie Parsed cookie + * @param configStateStorageStrategy Cookie storage strategy + * @param configAnonymousTracking If anonymous tracking is enabled + * @returns Client session context entity + */ +export function clientSessionFromIdCookie( + idCookie: ParsedIdCookie, + configStateStorageStrategy: string, + configAnonymousTracking: boolean +) { + const firstEventTsInMs = idCookie[firstEventTsInMsIndex]; + const clientSession: ClientSession = { + userId: configAnonymousTracking + ? '00000000-0000-0000-0000-000000000000' // TODO: use uuid.NIL when we upgrade to uuid v8.3 + : idCookie[domainUserIdIndex], + sessionId: idCookie[sessionIdIndex], + eventIndex: idCookie[eventIndexIndex], + sessionIndex: idCookie[visitCountIndex], + previousSessionId: configAnonymousTracking ? null : idCookie[previousSessionIdIndex] || null, + storageMechanism: configStateStorageStrategy == 'localStorage' ? 'LOCAL_STORAGE' : 'COOKIE_1', + firstEventId: idCookie[firstEventIdIndex] || null, + firstEventTimestamp: firstEventTsInMs ? new Date(firstEventTsInMs).toISOString() : null, + }; + + return clientSession; +} + +export function sessionIdFromIdCookie(idCookie: ParsedIdCookie) { + return idCookie[sessionIdIndex]; +} + +export function domainUserIdFromIdCookie(idCookie: ParsedIdCookie) { + return idCookie[domainUserIdIndex]; +} + +export function visitCountFromIdCookie(idCookie: ParsedIdCookie) { + return idCookie[visitCountIndex]; +} + +export function cookiesEnabledInIdCookie(idCookie: ParsedIdCookie) { + return idCookie[cookieDisabledIndex] === '0'; +} + +export function createTsFromIdCookie(idCookie: ParsedIdCookie) { + return idCookie[createTsIndex]; +} + +export function nowTsFromIdCookie(idCookie: ParsedIdCookie) { + return idCookie[nowTsIndex]; +} + +export function lastVisitTsFromIdCookie(idCookie: ParsedIdCookie) { + return idCookie[lastVisitTsIndex]; +} + +export function previousSessionIdFromIdCookie(idCookie: ParsedIdCookie) { + return idCookie[previousSessionIdIndex]; +} + +export function firstEventIdFromIdCookie(idCookie: ParsedIdCookie) { + return idCookie[firstEventIdIndex]; +} + +export function firstEventTsInMsFromIdCookie(idCookie: ParsedIdCookie) { + return idCookie[firstEventTsInMsIndex]; +} + +export function eventIndexFromIdCookie(idCookie: ParsedIdCookie) { + return idCookie[eventIndexIndex]; +} diff --git a/libraries/browser-tracker-core/src/tracker/index.ts b/libraries/browser-tracker-core/src/tracker/index.ts new file mode 100755 index 000000000..5521ea9a6 --- /dev/null +++ b/libraries/browser-tracker-core/src/tracker/index.ts @@ -0,0 +1,1577 @@ +import { + trackerCore, + buildPagePing, + buildPageView, + CommonEventProperties, + PayloadBuilder, + SelfDescribingJson, + LOG, +} from '@snowplow/tracker-core'; +import { sha1 as hash } from '../helpers/sha1'; +import { v4 as uuid } from 'uuid'; +import { + decorateQuerystring, + findRootDomain, + fixupDomain, + getReferrer, + addEventListener, + getHostName, + attemptGetLocalStorage, + attemptWriteLocalStorage, + attemptDeleteLocalStorage, + fixupTitle, + fromQuerystring, + isInteger, + attemptGetSessionStorage, + attemptWriteSessionStorage, + createCrossDomainParameterValue, + getTimeZone, +} from '../helpers'; +import { BrowserPlugin } from '../plugins'; +import { newOutQueue } from './out_queue'; +import { fixupUrl } from '../proxies'; +import { SharedState } from '../state'; +import { + PageViewEvent, + ActivityCallback, + ActivityCallbackData, + ActivityMetrics, + TrackerConfiguration, + BrowserTracker, + ActivityTrackingConfiguration, + ActivityTrackingConfigurationCallback, + DisableAnonymousTrackingConfiguration, + EnableAnonymousTrackingConfiguration, + FlushBufferConfiguration, + BrowserPluginConfiguration, + ClearUserDataConfiguration, + ClientSession, + ExtendedCrossDomainLinkerOptions, + ParsedIdCookie, + PreservePageViewIdForUrl, +} from './types'; +import { + parseIdCookie, + initializeDomainUserId, + startNewIdCookieSession, + updateNowTsInIdCookie, + serializeIdCookie, + sessionIdFromIdCookie, + domainUserIdFromIdCookie, + updateFirstEventInIdCookie, + visitCountFromIdCookie, + cookiesEnabledInIdCookie, + clientSessionFromIdCookie, + incrementEventIndexInIdCookie, + emptyIdCookie, + eventIndexFromIdCookie, +} from './id_cookie'; +import { + CLIENT_SESSION_SCHEMA, + WEB_PAGE_SCHEMA, + BROWSER_CONTEXT_SCHEMA, + APPLICATION_CONTEXT_SCHEMA, + ACTIVITY_METRICS_SCHEMA, +} from './schemata'; +import { getBrowserProperties, makeDimension } from '../helpers/browser_props'; +import { asyncCookieStorage, syncCookieStorage } from './cookie_storage'; + +declare global { + interface Navigator { + msDoNotTrack: boolean; + } + interface Window { + doNotTrack: boolean; + } +} + +/** Represents an instance of an activity tracking configuration */ +type ActivityConfig = { + /** The callback to fire based on heart beat */ + callback: ActivityCallback; + /** The minimum time that must have elapsed before first heartbeat */ + configMinimumVisitLength: number; + /** The interval at which the callback will be fired */ + configHeartBeatTimer: number; + /** The setInterval identifier */ + activityInterval?: number; + /** Whether activity metrics tracking is enabled for this configuration */ + activityMetrics?: boolean; +}; + +/** The configurations for the two types of Activity Tracking */ +type ActivityConfigurations = { + /** The configuration for enableActivityTrackingCallback */ + callback?: ActivityConfig; + /** The configuration for enableActivityTracking */ + pagePing?: ActivityConfig; +}; + +/** The configuration for if either activity tracking system is enable */ +type ActivityTrackingConfig = { + /** Tracks if activity tracking is enabled */ + enabled: boolean; + /** Tracks if activity tracking hooks have been installed */ + installed: boolean; + /** Stores the configuration for each type of activity tracking */ + configurations: ActivityConfigurations; +}; + +/** + * The Snowplow Tracker + * + * @param trackerId - The unique identifier of the tracker + * @param namespace - The namespace of the tracker object + * @param version - The current version of the JavaScript Tracker + * @param endpoint - The collector endpoint to send events to, with or without protocol + * @param sharedState - An object containing state which is shared across tracker instances + * @param trackerConfiguration - Dictionary of configuration options + */ +export function Tracker( + trackerId: string, + namespace: string, + version: string, + endpoint: string, + sharedState: SharedState, + trackerConfiguration: TrackerConfiguration = {} +): BrowserTracker { + const browserPlugins: Array = []; + + const newTracker = ( + trackerId: string, + namespace: string, + version: string, + endpoint: string, + state: SharedState, + trackerConfiguration: TrackerConfiguration + ) => { + /************************************************************ + * Private members + ************************************************************/ + + //use POST if eventMethod isn't present on the newTrackerConfiguration + trackerConfiguration.eventMethod = trackerConfiguration.eventMethod ?? 'post'; + + const getStateStorageStrategy = (config: TrackerConfiguration) => + config.stateStorageStrategy ?? 'cookieAndLocalStorage', + getAnonymousSessionTracking = (config: TrackerConfiguration) => { + if (typeof config.anonymousTracking === 'boolean') { + return false; + } + return config.anonymousTracking?.withSessionTracking === true; + }, + getAnonymousServerTracking = (config: TrackerConfiguration) => { + if (typeof config.anonymousTracking === 'boolean') { + return false; + } + return config.anonymousTracking?.withServerAnonymisation === true; + }, + getAnonymousTracking = (config: TrackerConfiguration) => !!config.anonymousTracking, + isBrowserContextAvailable = trackerConfiguration?.contexts?.browser ?? false, + isWebPageContextAvailable = trackerConfiguration?.contexts?.webPage ?? true, + getExtendedCrossDomainTrackingConfiguration = (crossDomainTrackingConfig: ExtendedCrossDomainLinkerOptions) => { + if (typeof crossDomainTrackingConfig === 'boolean') { + return { useExtendedCrossDomainLinker: crossDomainTrackingConfig }; + } + + return { + useExtendedCrossDomainLinker: true, + collectCrossDomainAttributes: crossDomainTrackingConfig, + }; + }; + + // Create a new cookie storage instance with synchronous cookie write if configured + const cookieStorage = trackerConfiguration.synchronousCookieWrite ? syncCookieStorage : asyncCookieStorage; + + // Get all injected plugins + browserPlugins.push(getBrowserDataPlugin()); + /* When including the Web Page context, we add the relevant internal plugins */ + if (isWebPageContextAvailable) { + browserPlugins.push(getWebPagePlugin()); + } + if (isBrowserContextAvailable) { + browserPlugins.push(getBrowserContextPlugin()); + } + browserPlugins.push(...(trackerConfiguration.plugins ?? [])); + + let // Tracker core + core = trackerCore({ + base64: trackerConfiguration.encodeBase64 ?? trackerConfiguration.eventMethod !== 'post', + corePlugins: browserPlugins, + callback: sendRequest, + }), + // Aliases + documentCharset = document.characterSet || document.charset, + // Current URL and Referrer URL + locationArray = fixupUrl(window.location.hostname, window.location.href, getReferrer()), + domainAlias = fixupDomain(locationArray[0]), + locationHrefAlias = locationArray[1], + configReferrerUrl = locationArray[2], + customReferrer: string, + // Platform defaults to web for this tracker + configPlatform = trackerConfiguration.platform ?? 'web', + // Site ID + configTrackerSiteId = trackerConfiguration.appId ?? '', + // Application version + configAppVersion = trackerConfiguration.appVersion, + // Document URL + configCustomUrl: string, + // Document title + lastDocumentTitle = document.title, + // Custom title + lastConfigTitle: string | null | undefined, + // Indicates that the lastConfigTitle was set from a trackPageView call + // Custom title configured this way has a shorter lifespan than when set using setDocumentTitle. + // It only lasts until the next trackPageView call. + lastConfigTitleFromTrackPageView: boolean = false, + // Controls whether activity tracking page ping event timers are reset on page view events + resetActivityTrackingOnPageView = trackerConfiguration.resetActivityTrackingOnPageView ?? true, + // Disallow hash tags in URL. TODO: Should this be set to true by default? + configDiscardHashTag: boolean, + // Disallow brace in URL. + configDiscardBrace: boolean, + // First-party cookie name prefix + configCookieNamePrefix = trackerConfiguration.cookieName ?? '_sp_', + // First-party cookie domain + // User agent defaults to origin hostname + configCookieDomain = trackerConfiguration.cookieDomain ?? undefined, + discoverRootDomain = trackerConfiguration.discoverRootDomain ?? configCookieDomain === undefined, + // First-party cookie path + // Default is user agent defined. + configCookiePath = '/', + // First-party cookie samesite attribute + configCookieSameSite = trackerConfiguration.cookieSameSite ?? 'Lax', + // First-party cookie secure attribute + configCookieSecure = trackerConfiguration.cookieSecure ?? true, + // Do Not Track browser feature + dnt = window.navigator.doNotTrack || window.navigator.msDoNotTrack || window.doNotTrack, + // Do Not Track + configDoNotTrack = + typeof trackerConfiguration.respectDoNotTrack !== 'undefined' + ? trackerConfiguration.respectDoNotTrack && (dnt === 'yes' || dnt === '1') + : false, + // Opt out of cookie tracking + configOptOutCookie: string | null | undefined, + // Life of the visitor cookie (in seconds) + configVisitorCookieTimeout = trackerConfiguration.cookieLifetime ?? 63072000, // 2 years + // Life of the session cookie (in seconds) + configSessionCookieTimeout = trackerConfiguration.sessionCookieTimeout ?? 1800, // 30 minutes + // Allows tracking user session (using cookies or local storage), can only be used with anonymousTracking + configAnonymousSessionTracking = getAnonymousSessionTracking(trackerConfiguration), + // Will send a header to server to prevent returning cookie and capturing IP + configAnonymousServerTracking = getAnonymousServerTracking(trackerConfiguration), + // Sets tracker to work in anonymous mode without accessing client storage + configAnonymousTracking = getAnonymousTracking(trackerConfiguration), + // Strategy defining how to store the state: cookie, localStorage, cookieAndLocalStorage or none + configStateStorageStrategy = getStateStorageStrategy(trackerConfiguration), + // Last activity timestamp + lastActivityTime: number, + // The last time an event was fired on the page - used to invalidate session if cookies are disabled + lastEventTime = new Date().getTime(), + // How are we scrolling? + minXOffset: number, + maxXOffset: number, + minYOffset: number, + maxYOffset: number, + // Activity metrics tracking state + activityMetricsState = { + metrics: { mouseDistance: 0, scrollDistance: 0, keyPresses: 0, clicks: 0, touches: 0 } as ActivityMetrics, + lastMouseX: undefined as number | undefined, + lastMouseY: undefined as number | undefined, + lastScrollX: undefined as number | undefined, + lastScrollY: undefined as number | undefined, + }, + // Domain hash value + domainHash: string, + // Domain unique user ID + domainUserId: string, + // ID for the current session + memorizedSessionId: string, + // Index for the current session - kept in memory in case cookies are disabled + memorizedVisitCount = 1, + // Business-defined unique user ID + businessUserId: string | null | undefined, + // Manager for local storage queue + outQueue = newOutQueue( + { + trackerId, + endpoint: asCollectorUrl(endpoint), + serverAnonymization: configAnonymousServerTracking, + useLocalStorage: + configStateStorageStrategy == 'localStorage' || configStateStorageStrategy == 'cookieAndLocalStorage', + ...trackerConfiguration, + }, + state + ), + // Whether pageViewId should be regenerated after each trackPageView. Affect web_page context + preservePageViewId = false, + // Whether pageViewId should be kept the same until the page URL changes. Affects web_page context + preservePageViewIdForUrl = trackerConfiguration.preservePageViewIdForUrl ?? false, + // The pageViewId of the last page view event or undefined if no page view tracked yet. Used to determine if pageViewId should be regenerated for a new page view. + lastSentPageViewId: string | undefined = undefined, + // Activity tracking config for callback and page ping variants + activityTrackingConfig: ActivityTrackingConfig = { + enabled: false, + installed: false, // Guard against installing the activity tracker more than once per Tracker instance + configurations: {}, + }, + configSessionContext = trackerConfiguration.contexts?.session ?? false, + configDisableSessionInWebView = trackerConfiguration.disableSessionContextWithinWebView ?? false, + toOptoutByCookie: string | boolean, + onSessionUpdateCallback = trackerConfiguration.onSessionUpdateCallback, + manualSessionUpdateCalled = false, + { useExtendedCrossDomainLinker, collectCrossDomainAttributes } = getExtendedCrossDomainTrackingConfiguration( + trackerConfiguration.useExtendedCrossDomainLinker || false + ); + + if (discoverRootDomain && !configCookieDomain) { + configCookieDomain = findRootDomain(configCookieSameSite, configCookieSecure); + } + + const cookiesEnabled = window.navigator.cookieEnabled; + const colorDepth = screen.colorDepth; + const browserLanguage = window.navigator.language || (window.navigator as any).userLanguage; + const resolution = makeDimension(screen.width, screen.height); + const timeZone = getTimeZone(); + + // Set up unchanging name-value pairs + core.setTrackerVersion(version); + core.setTrackerNamespace(namespace); + core.setAppId(configTrackerSiteId); + core.setPlatform(configPlatform); + core.addPayloadPair('cookie', cookiesEnabled ? '1' : '0'); + core.addPayloadPair('cs', documentCharset); + core.addPayloadPair('lang', browserLanguage); + core.addPayloadPair('res', resolution); + core.addPayloadPair('cd', colorDepth); + if (timeZone) core.addPayloadPair('tz', timeZone); + + // Add the application version context entity + if (configAppVersion) { + core.addPlugin({ + plugin: { + contexts: () => [ + { + schema: APPLICATION_CONTEXT_SCHEMA, + data: { version: configAppVersion }, + }, + ], + }, + }); + } + + /* + * Initialize tracker + */ + updateDomainHash(); + + initializeIdsAndCookies(); + + if (trackerConfiguration.preserveOriginalReferrer && configReferrerUrl) { + customReferrer = configReferrerUrl; + } + + if (trackerConfiguration.crossDomainLinker) { + decorateLinks(trackerConfiguration.crossDomainLinker); + } + + /** + * Recalculate the domain, URL, and referrer + */ + function refreshUrl() { + locationArray = fixupUrl(window.location.hostname, window.location.href, getReferrer()); + + // If this is a single-page app and the page URL has changed, then: + // - if the new URL's querystring contains a "refer(r)er" parameter, use it as the referrer + // - otherwise use the old URL as the referer + if (locationArray[1] !== locationHrefAlias) { + configReferrerUrl = getReferrer(locationHrefAlias); + } + + domainAlias = fixupDomain(locationArray[0]); + locationHrefAlias = locationArray[1]; + } + + /** + * Create link handler to decorate the querystring of a link (onClick/onMouseDown) + * + * @param event - e The event targeting the link + */ + function addLinkDecorationHandler(extended: boolean): (evt: Event) => void { + const CROSS_DOMAIN_PARAMETER_NAME = '_sp'; + + return (evt) => { + const elt = evt.currentTarget as HTMLAnchorElement | HTMLAreaElement | null; + + const crossDomainParameterValue = createCrossDomainParameterValue(extended, collectCrossDomainAttributes, { + domainUserId, + userId: businessUserId || undefined, + sessionId: memorizedSessionId, + sourceId: configTrackerSiteId, + sourcePlatform: configPlatform, + event: evt, + }); + + if (elt?.href) { + elt.href = decorateQuerystring(elt.href, CROSS_DOMAIN_PARAMETER_NAME, crossDomainParameterValue); + } + }; + } + + /** + * Enable querystring decoration for links passing a filter + * Whenever such a link is clicked on or navigated to via the keyboard, + * add "_sp={{duid}}.{{timestamp}}" to its querystring + * + * @param crossDomainLinker - Function used to determine which links to decorate + */ + function decorateLinks(crossDomainLinker: (elt: HTMLAnchorElement | HTMLAreaElement) => boolean) { + const crossDomainLinkHandler = addLinkDecorationHandler(useExtendedCrossDomainLinker); + for (let i = 0; i < document.links.length; i++) { + const elt = document.links[i]; + if (!(elt as any).spDecorationEnabled && crossDomainLinker(elt)) { + elt.addEventListener('click', crossDomainLinkHandler, true); + elt.addEventListener('mousedown', crossDomainLinkHandler, true); + + // Don't add event listeners more than once + (elt as any).spDecorationEnabled = true; + } + } + } + + /* + * Removes hash tag from the URL + * + * URLs are purified before being recorded in the cookie, + * or before being sent as GET parameters + */ + function purify(url: string) { + let targetPattern; + + if (configDiscardHashTag) { + targetPattern = new RegExp('#.*'); + url = url.replace(targetPattern, ''); + } + + if (configDiscardBrace) { + targetPattern = new RegExp('[{}]', 'g'); + url = url.replace(targetPattern, ''); + } + return url; + } + + /* + * Extract scheme/protocol from URL + */ + function getProtocolScheme(url: string) { + // RFC 3986: scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ), case-insensitive. + // A stricter [a-z]+ pattern misclassifies schemes such as chrome-extension as + // relative references, which then get appended to the base URL. + const e = new RegExp('^([a-z][a-z0-9+\\-.]*):', 'i'), + matches = e.exec(url); + + // The atomic event schema caps the url scheme at 16 characters + // (page_urlscheme / refr_urlscheme, maxLength 16). A longer scheme would only + // produce an event that fails validation downstream, so treat such URLs as + // relative references (the prior behaviour) rather than absolute URLs. + // Ref: com.snowplowanalytics.snowplow/atomic/jsonschema/1-0-0 + const MAX_SCHEME_LENGTH = 16; + + return matches && matches[1].length <= MAX_SCHEME_LENGTH ? matches[1] : null; + } + + /* + * Resolve relative reference + * + * Note: not as described in rfc3986 section 5.2 + */ + function resolveRelativeReference(baseUrl: string, url: string) { + let protocol = getProtocolScheme(url), + i; + + if (protocol) { + return url; + } + + if (url.slice(0, 1) === '/') { + return getProtocolScheme(baseUrl) + '://' + getHostName(baseUrl) + url; + } + + baseUrl = purify(baseUrl); + if ((i = baseUrl.indexOf('?')) >= 0) { + baseUrl = baseUrl.slice(0, i); + } + if ((i = baseUrl.lastIndexOf('/')) !== baseUrl.length - 1) { + baseUrl = baseUrl.slice(0, i + 1); + } + + return baseUrl + url; + } + + /* + * Send request + */ + function sendRequest(request: PayloadBuilder) { + if (!(configDoNotTrack || toOptoutByCookie)) { + outQueue.enqueueRequest(request.build()); + } + } + + /* + * Get cookie name with prefix and domain hash + */ + function getSnowplowCookieName(baseName: string) { + return configCookieNamePrefix + baseName + '.' + domainHash; + } + + /* + * Cookie getter. + */ + function getSnowplowCookieValue(cookieName: string) { + const fullName = getSnowplowCookieName(cookieName); + if (configStateStorageStrategy == 'localStorage') { + return attemptGetLocalStorage(fullName); + } else if (configStateStorageStrategy == 'cookie' || configStateStorageStrategy == 'cookieAndLocalStorage') { + return cookieStorage.getCookie(fullName); + } + return undefined; + } + + /* + * Update domain hash + */ + function updateDomainHash() { + refreshUrl(); + domainHash = hash((configCookieDomain || domainAlias) + (configCookiePath || '/')).slice(0, 4); // 4 hexits = 16 bits + } + + /* + * Process all "activity" events. + * For performance, this function must have low overhead. + */ + function activityHandler(event?: Event) { + const now = new Date(); + lastActivityTime = now.getTime(); + + if (isActivityMetricsEnabled() && event) { + switch (event.type) { + case 'mousemove': { + const me = event as MouseEvent; + if (activityMetricsState.lastMouseX !== undefined && activityMetricsState.lastMouseY !== undefined) { + const dx = me.clientX - activityMetricsState.lastMouseX; + const dy = me.clientY - activityMetricsState.lastMouseY; + activityMetricsState.metrics.mouseDistance += Math.sqrt(dx * dx + dy * dy); + } + activityMetricsState.lastMouseX = me.clientX; + activityMetricsState.lastMouseY = me.clientY; + break; + } + case 'click': + activityMetricsState.metrics.clicks++; + break; + case 'keydown': + activityMetricsState.metrics.keyPresses++; + break; + case 'touchstart': + activityMetricsState.metrics.touches++; + break; + // scroll handled in scrollHandler + } + } + } + + /* + * Process all "scroll" events. + */ + function scrollHandler() { + activityHandler(); + + const offsets = getPageOffsets(); + + const x = offsets[0]; + if (x < minXOffset) { + minXOffset = x; + } else if (x > maxXOffset) { + maxXOffset = x; + } + + const y = offsets[1]; + if (y < minYOffset) { + minYOffset = y; + } else if (y > maxYOffset) { + maxYOffset = y; + } + + if (isActivityMetricsEnabled()) { + if (activityMetricsState.lastScrollX !== undefined && activityMetricsState.lastScrollY !== undefined) { + activityMetricsState.metrics.scrollDistance += + Math.abs(x - activityMetricsState.lastScrollX) + Math.abs(y - activityMetricsState.lastScrollY); + } + activityMetricsState.lastScrollX = x; + activityMetricsState.lastScrollY = y; + } + } + + /* + * Returns [pageXOffset, pageYOffset] + */ + function getPageOffsets() { + const documentElement = document.documentElement; + if (documentElement) { + return [documentElement.scrollLeft || window.pageXOffset, documentElement.scrollTop || window.pageYOffset]; + } + + return [0, 0]; + } + + /* + * Quick initialization/reset of max scroll levels + */ + function resetMaxScrolls() { + const offsets = getPageOffsets(); + + const x = offsets[0]; + minXOffset = x; + maxXOffset = x; + + const y = offsets[1]; + minYOffset = y; + maxYOffset = y; + } + + /* + * Whether activity metrics tracking is enabled for any active configuration + */ + function isActivityMetricsEnabled(): boolean { + return !!( + activityTrackingConfig.configurations.pagePing?.activityMetrics || + activityTrackingConfig.configurations.callback?.activityMetrics + ); + } + + /* + * Reset activity metrics accumulators and position trackers + */ + function resetActivityMetricsState() { + activityMetricsState.metrics = { mouseDistance: 0, scrollDistance: 0, keyPresses: 0, clicks: 0, touches: 0 }; + activityMetricsState.lastMouseX = undefined; + activityMetricsState.lastMouseY = undefined; + activityMetricsState.lastScrollX = undefined; + activityMetricsState.lastScrollY = undefined; + } + + /* + * Return a snapshot of current activity metrics + */ + function getActivityMetrics(): ActivityMetrics { + return { + ...activityMetricsState.metrics, + mouseDistance: Math.round(activityMetricsState.metrics.mouseDistance), + scrollDistance: Math.round(activityMetricsState.metrics.scrollDistance), + }; + } + + /* + * Prevents offsets from being decimal or NaN + * See https://github.com/snowplow/snowplow-javascript-tracker/issues/324 + */ + function cleanOffset(offset: number) { + return Math.round(offset); + } + + /** + * Sets or renews the session cookie. + * Responsible for calling the `onSessionUpdateCallback` callback. + * @returns {boolean} If the value persisted in cookies or LocalStorage + */ + function setSessionCookie() { + const cookieName = getSnowplowCookieName('ses'); + const cookieValue = '*'; + return persistValue(cookieName, cookieValue, configSessionCookieTimeout); + } + + /** + * @mutates idCookie + * @param {ParsedIdCookie} idCookie + * @returns {boolean} If the value persisted in cookies or LocalStorage + */ + function setDomainUserIdCookie(idCookie: ParsedIdCookie) { + const cookieName = getSnowplowCookieName('id'); + const cookieValue = serializeIdCookie(idCookie, configAnonymousTracking); + return persistValue(cookieName, cookieValue, configVisitorCookieTimeout); + } + + /** + * no-op if anonymousTracking enabled, will still set cookies if anonymousSessionTracking is enabled + * Sets a cookie based on the storage strategy: + * - if 'localStorage': attempts to write to local storage + * - if 'cookie' or 'cookieAndLocalStorage': writes to cookies + * - otherwise: no-op + * @param {string} name Name/key of the value to persist + * @param {string} value + * @param {number} timeout Used as the expiration date for cookies or as a TTL to be checked on LocalStorage + * @returns {boolean} If the operation was successful or not + */ + function persistValue(name: string, value: string, timeout: number): boolean { + if (configAnonymousTracking && !configAnonymousSessionTracking) { + return false; + } + + if (configStateStorageStrategy == 'localStorage') { + return attemptWriteLocalStorage(name, value, timeout); + } else if (configStateStorageStrategy == 'cookie' || configStateStorageStrategy == 'cookieAndLocalStorage') { + return cookieStorage.setCookie( + name, + value, + timeout, + configCookiePath, + configCookieDomain, + configCookieSameSite, + configCookieSecure + ); + } + return false; + } + + /** + * Clears all cookie and local storage for id and ses values + */ + function clearUserDataAndCookies(configuration?: ClearUserDataConfiguration) { + const idname = getSnowplowCookieName('id'); + const sesname = getSnowplowCookieName('ses'); + attemptDeleteLocalStorage(idname); + attemptDeleteLocalStorage(sesname); + cookieStorage.deleteCookie( + idname, + configCookiePath, + configCookieDomain, + configCookieSameSite, + configCookieSecure + ); + cookieStorage.deleteCookie( + sesname, + configCookiePath, + configCookieDomain, + configCookieSameSite, + configCookieSecure + ); + if (!configuration?.preserveSession) { + memorizedSessionId = uuid(); + memorizedVisitCount = 1; + } + if (!configuration?.preserveUser) { + domainUserId = configAnonymousTracking ? '' : uuid(); + businessUserId = null; + } + } + + /** + * Toggle Anonymous Tracking + */ + function toggleAnonymousTracking( + configuration?: EnableAnonymousTrackingConfiguration | DisableAnonymousTrackingConfiguration + ) { + if (configuration && configuration.stateStorageStrategy) { + trackerConfiguration.stateStorageStrategy = configuration.stateStorageStrategy; + configStateStorageStrategy = getStateStorageStrategy(trackerConfiguration); + } + + configAnonymousTracking = getAnonymousTracking(trackerConfiguration); + configAnonymousSessionTracking = getAnonymousSessionTracking(trackerConfiguration); + configAnonymousServerTracking = getAnonymousServerTracking(trackerConfiguration); + + outQueue.setUseLocalStorage( + configStateStorageStrategy == 'localStorage' || configStateStorageStrategy == 'cookieAndLocalStorage' + ); + outQueue.setAnonymousTracking(configAnonymousServerTracking); + } + + /* + * Load the domain user ID and the session ID + * Set the cookies (if cookies are enabled) + */ + function initializeIdsAndCookies() { + if (configAnonymousTracking && !configAnonymousSessionTracking) { + return; + } + + const sesCookieSet = configStateStorageStrategy != 'none' && !!getSnowplowCookieValue('ses'); + const idCookie = loadDomainUserIdCookie(); + + domainUserId = initializeDomainUserId(idCookie, configAnonymousTracking); + + if (!sesCookieSet) { + memorizedSessionId = startNewIdCookieSession(idCookie); + } else { + memorizedSessionId = sessionIdFromIdCookie(idCookie); + } + + memorizedVisitCount = visitCountFromIdCookie(idCookie); + + if (configStateStorageStrategy != 'none') { + setSessionCookie(); + // Update currentVisitTs + updateNowTsInIdCookie(idCookie); + setDomainUserIdCookie(idCookie); + + if (!eventIndexFromIdCookie(idCookie)) { + // Synchronously update the cookies to persist the new session ASAP + cookieStorage.flush(); + } + } + } + + /* + * Load visitor ID cookie + */ + function loadDomainUserIdCookie() { + if (configStateStorageStrategy == 'none') { + return emptyIdCookie(); + } + const id = getSnowplowCookieValue('id') || undefined; + return parseIdCookie(id, domainUserId, memorizedSessionId, memorizedVisitCount); + } + + /** + * Adds the protocol in front of our collector URL + * + * @param string - collectorUrl The collector URL with or without protocol + * @returns string collectorUrl The tracker URL with protocol + */ + function asCollectorUrl(collectorUrl: string) { + if (collectorUrl.indexOf('http') === 0) { + return collectorUrl; + } + + return ('https:' === document.location.protocol ? 'https' : 'http') + '://' + collectorUrl; + } + + /** + * Initialize new `pageViewId` if it shouldn't be preserved. + * Should be called when `trackPageView` is invoked + */ + function resetPageView() { + if (!preservePageViewId || state.pageViewId == null) { + state.pageViewId = uuid(); + state.pageViewUrl = configCustomUrl || locationHrefAlias; + } + } + + /** + * Safe function to get `pageViewId`. + * Generates it if it wasn't initialized by other tracker + */ + function getPageViewId() { + if (shouldGenerateNewPageViewId()) { + state.pageViewId = uuid(); + state.pageViewUrl = configCustomUrl || locationHrefAlias; + } + return state.pageViewId!; + } + + function shouldGenerateNewPageViewId() { + // If pageViewId is not initialized, generate it + if (state.pageViewId == null) { + return true; + } + // If pageViewId should be preserved regardless of the URL, don't generate a new one + if (preservePageViewId || !preservePageViewIdForUrl) { + return false; + } + // If doesn't have previous URL in state, generate a new pageViewId + if (state.pageViewUrl === undefined) { + return true; + } + const current = configCustomUrl || locationHrefAlias; + // If full preserve is enabled, compare the full URL + if (preservePageViewIdForUrl === true || preservePageViewIdForUrl == 'full' || !('URL' in window)) { + return state.pageViewUrl != current; + } + const currentUrl = new URL(current); + const previousUrl = new URL(state.pageViewUrl); + // If pathname preserve is enabled, compare the pathname + if (preservePageViewIdForUrl == 'pathname') { + return currentUrl.pathname != previousUrl.pathname; + } + // If pathname and search preserve is enabled, compare the pathname and search + if (preservePageViewIdForUrl == 'pathnameAndSearch') { + return currentUrl.pathname != previousUrl.pathname || currentUrl.search != previousUrl.search; + } + return false; + } + + /** + * Safe function to get `tabId`. + * Generates it if it is not yet initialized. Shared between trackers. + */ + function getTabId() { + if (configStateStorageStrategy === 'none' || configAnonymousTracking || !isWebPageContextAvailable) { + return null; + } + const SESSION_STORAGE_TAB_ID = '_sp_tab_id'; + let tabId = attemptGetSessionStorage(SESSION_STORAGE_TAB_ID); + if (!tabId) { + attemptWriteSessionStorage(SESSION_STORAGE_TAB_ID, uuid()); + tabId = attemptGetSessionStorage(SESSION_STORAGE_TAB_ID); + } + return tabId || null; + } + + /** + * Put together a web page context with a unique UUID for the page view + * + * @returns web_page context + */ + function getWebPagePlugin() { + return { + contexts: () => { + return [ + { + schema: WEB_PAGE_SCHEMA, + data: { + id: getPageViewId(), + }, + }, + ]; + }, + }; + } + + function getBrowserContextPlugin() { + return { + contexts: () => { + return [ + { + schema: BROWSER_CONTEXT_SCHEMA, + data: { + ...getBrowserProperties(), + tabId: getTabId(), + }, + }, + ]; + }, + }; + } + + /* + * Attaches common web fields to every request (resolution, url, referrer, etc.) + * Also sets the required cookies. + */ + function getBrowserDataPlugin() { + const anonymizeOr = (value?: string | number | null) => (configAnonymousTracking ? null : value); + const anonymizeSessionOr = (value?: string | number | null) => + configAnonymousSessionTracking ? value : anonymizeOr(value); + + return { + beforeTrack: (payloadBuilder: PayloadBuilder) => { + const existingSession = getSnowplowCookieValue('ses'), + idCookie = loadDomainUserIdCookie(); + + const isFirstEventInSession = eventIndexFromIdCookie(idCookie) === 0; + + if (configOptOutCookie) { + toOptoutByCookie = !!cookieStorage.getCookie(configOptOutCookie); + } else { + toOptoutByCookie = false; + } + + if (configDoNotTrack || toOptoutByCookie) { + clearUserDataAndCookies(); + return; + } + + // If cookies are enabled, base visit count and session ID on the cookies + if (cookiesEnabledInIdCookie(idCookie)) { + // New session? + if (!existingSession && configStateStorageStrategy != 'none') { + memorizedSessionId = startNewIdCookieSession(idCookie); + } else { + memorizedSessionId = sessionIdFromIdCookie(idCookie); + } + + memorizedVisitCount = visitCountFromIdCookie(idCookie); + } else if (new Date().getTime() - lastEventTime > configSessionCookieTimeout * 1000) { + memorizedVisitCount++; + memorizedSessionId = startNewIdCookieSession(idCookie, { + memorizedVisitCount, + }); + } + + // Update cookie + updateNowTsInIdCookie(idCookie); + updateFirstEventInIdCookie(idCookie, payloadBuilder); + incrementEventIndexInIdCookie(idCookie); + + const { viewport, documentSize } = getBrowserProperties(); + + payloadBuilder.add('vp', viewport); + payloadBuilder.add('ds', documentSize); + payloadBuilder.add('vid', anonymizeSessionOr(memorizedVisitCount)); + payloadBuilder.add('sid', anonymizeSessionOr(memorizedSessionId)); + payloadBuilder.add('duid', anonymizeOr(domainUserIdFromIdCookie(idCookie))); // Always load from cookie as this is better etiquette than in-memory values + payloadBuilder.add('uid', anonymizeOr(businessUserId)); + + refreshUrl(); + + payloadBuilder.add('refr', purify(customReferrer || configReferrerUrl)); + + // Add the page URL last as it may take us over the IE limit (and we don't always need it) + payloadBuilder.add('url', purify(configCustomUrl || locationHrefAlias)); + + const clientSession = clientSessionFromIdCookie( + idCookie, + configStateStorageStrategy, + configAnonymousTracking + ); + if ( + configSessionContext && + (!configAnonymousTracking || configAnonymousSessionTracking) && + !(configDisableSessionInWebView && isInWebView()) + ) { + addSessionContextToPayload(payloadBuilder, clientSession); + } + + // Update cookies + if (configStateStorageStrategy != 'none') { + setDomainUserIdCookie(idCookie); + const sessionIdentifierPersisted = setSessionCookie(); + if ( + (!existingSession || isFirstEventInSession) && + sessionIdentifierPersisted && + onSessionUpdateCallback && + !manualSessionUpdateCalled + ) { + // Synchronously update the cookies to persist the new session ASAP + cookieStorage.flush(); + + onSessionUpdateCallback(clientSession); + manualSessionUpdateCalled = false; + } + } + + lastEventTime = new Date().getTime(); + }, + }; + } + + /** + * Returns true when the page is running inside a Snowplow V2 WebView interface. + * Mirrors the three-interface check in @snowplow/webview-tracker without introducing + * a package dependency on browser-tracker-core. + */ + function isInWebView(): boolean { + return !!( + (window as any).SnowplowWebInterfaceV2 || + ((window as any).webkit && + (window as any).webkit.messageHandlers && + (window as any).webkit.messageHandlers.snowplowV2) || + (window as any).ReactNativeWebView + ); + } + + function addSessionContextToPayload(payloadBuilder: PayloadBuilder, clientSession: ClientSession) { + let sessionContext: SelfDescribingJson = { + schema: CLIENT_SESSION_SCHEMA, + data: clientSession, + }; + payloadBuilder.addContextEntity(sessionContext); + } + + /** + * Expires current session and starts a new session. + */ + function newSession() { + // If cookies are enabled, base visit count and session ID on the cookies + let idCookie = loadDomainUserIdCookie(); + + // When cookies are enabled + if (cookiesEnabledInIdCookie(idCookie)) { + // When cookie/local storage is enabled - make a new session + if (configStateStorageStrategy != 'none') { + memorizedSessionId = startNewIdCookieSession(idCookie); + } else { + memorizedSessionId = sessionIdFromIdCookie(idCookie); + } + + memorizedVisitCount = visitCountFromIdCookie(idCookie); + } else { + memorizedVisitCount++; + memorizedSessionId = startNewIdCookieSession(idCookie, { + memorizedVisitCount, + }); + } + + updateNowTsInIdCookie(idCookie); + + // Update cookies + if (configStateStorageStrategy != 'none') { + const clientSession = clientSessionFromIdCookie(idCookie, configStateStorageStrategy, configAnonymousTracking); + setDomainUserIdCookie(idCookie); + const sessionIdentifierPersisted = setSessionCookie(); + + // Synchronously update the cookies to persist the new session ASAP + cookieStorage.flush(); + + if (sessionIdentifierPersisted && onSessionUpdateCallback) { + manualSessionUpdateCalled = true; + onSessionUpdateCallback(clientSession); + } + } + + lastEventTime = new Date().getTime(); + } + + /** + * Combine an array of unchanging contexts with the result of a context-creating function + * + * @param staticContexts - Array of custom contexts + * @param contextCallback - Function returning an array of contexts + */ + function finalizeContexts( + staticContexts?: Array | null, + contextCallback?: (() => Array) | null + ) { + return (staticContexts || []).concat(contextCallback ? contextCallback() : []); + } + + function logPageView({ title, context, timestamp, contextCallback }: PageViewEvent & CommonEventProperties) { + refreshUrl(); + if (lastSentPageViewId && lastSentPageViewId == getPageViewId()) { + // Do not reset pageViewId if a page view was not tracked yet or a different page view ID was used (in order to support multiple trackers with shared state) + resetPageView(); + } + lastSentPageViewId = getPageViewId(); + + // So we know what document.title was at the time of trackPageView + lastDocumentTitle = document.title; + if (title) { + lastConfigTitle = title; + lastConfigTitleFromTrackPageView = true; + } else if (lastConfigTitleFromTrackPageView) { + lastConfigTitle = null; + } + + // Fixup page title + const pageTitle = fixupTitle(lastConfigTitle || lastDocumentTitle); + + // Log page view + core.track( + buildPageView({ + pageUrl: purify(configCustomUrl || locationHrefAlias), + pageTitle, + referrer: purify(customReferrer || configReferrerUrl), + }), + finalizeContexts(context, contextCallback), + timestamp + ); + + // Send ping (to log that user has stayed on page) + const now = new Date(); + let installingActivityTracking = false; + + if (activityTrackingConfig.enabled && !activityTrackingConfig.installed) { + activityTrackingConfig.installed = true; + installingActivityTracking = true; + + // Add mousewheel event handler, detect passive event listeners for performance + const detectPassiveEvents: { update: () => void; hasSupport?: boolean } = { + update: function update() { + if (typeof window !== 'undefined' && typeof window.addEventListener === 'function') { + let passive = false; + const options = Object.defineProperty({}, 'passive', { + get: function get() { + passive = true; + }, + set: function set() {}, + }); + // note: have to set and remove a no-op listener instead of null + // (which was used previously), because Edge v15 throws an error + // when providing a null callback. + // https://github.com/rafrex/detect-passive-events/pull/3 + const noop = function noop() {}; + window.addEventListener('testPassiveEventSupport', noop, options); + window.removeEventListener('testPassiveEventSupport', noop, options); + detectPassiveEvents.hasSupport = passive; + } + }, + }; + detectPassiveEvents.update(); + + // Detect available wheel event + const wheelEvent = + 'onwheel' in document.createElement('div') + ? 'wheel' // Modern browsers support "wheel" + : (document as any).onmousewheel !== undefined + ? 'mousewheel' // Webkit and IE support at least "mousewheel" + : 'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox + + if (Object.prototype.hasOwnProperty.call(detectPassiveEvents, 'hasSupport')) { + addEventListener(document, wheelEvent, activityHandler, { passive: true }); + } else { + addEventListener(document, wheelEvent, activityHandler); + } + + // Capture our initial scroll points + resetMaxScrolls(); + resetActivityMetricsState(); + + // Add event handlers; cross-browser compatibility here varies significantly + // @see http://quirksmode.org/dom/events + const documentHandlers = [ + 'click', + 'mouseup', + 'mousedown', + 'mousemove', + 'keypress', + 'keydown', + 'keyup', + 'touchend', + 'touchstart', + ]; + const windowHandlers = ['resize', 'focus', 'blur']; + const listener = + (_: Document | Window, handler = activityHandler) => + (ev: string) => + addEventListener(document, ev, handler); + + documentHandlers.forEach(listener(document)); + windowHandlers.forEach(listener(window)); + listener(window, scrollHandler)('scroll'); + } + + if (activityTrackingConfig.enabled && (resetActivityTrackingOnPageView || installingActivityTracking)) { + // Periodic check for activity. + lastActivityTime = now.getTime(); + resetActivityMetricsState(); + + let key: keyof ActivityConfigurations; + for (key in activityTrackingConfig.configurations) { + const config = activityTrackingConfig.configurations[key]; + if (config) { + //Clear page ping heartbeat on new page view + window.clearInterval(config.activityInterval); + + scheduleActivityInterval(config, context, contextCallback); + } + } + } + } + + function scheduleActivityInterval( + config: ActivityConfig, + context?: Array | null, + contextCallback?: (() => Array) | null + ) { + const executePagePing = (cb: ActivityCallback, context: Array) => { + refreshUrl(); + let activityMetrics: ActivityMetrics | undefined; + if (isActivityMetricsEnabled()) { + activityMetrics = getActivityMetrics(); + context = context.concat([{ schema: ACTIVITY_METRICS_SCHEMA, data: activityMetrics }]); + } + cb({ context, pageViewId: getPageViewId(), minXOffset, minYOffset, maxXOffset, maxYOffset, activityMetrics }); + resetMaxScrolls(); + if (isActivityMetricsEnabled()) { + resetActivityMetricsState(); + } + }; + + const timeout = () => { + const now = new Date(); + + // There was activity during the heart beat period; + // on average, this is going to overstate the visitDuration by configHeartBeatTimer/2 + if (lastActivityTime + config.configMinimumVisitLength > now.getTime()) { + executePagePing(config.callback, finalizeContexts(context, contextCallback)); + } + + config.activityInterval = window.setInterval(heartbeat, config.configHeartBeatTimer); + }; + + const heartbeat = () => { + const now = new Date(); + + // There was activity during the heart beat period; + // on average, this is going to overstate the visitDuration by configHeartBeatTimer/2 + if (lastActivityTime + config.configHeartBeatTimer > now.getTime()) { + executePagePing(config.callback, finalizeContexts(context, contextCallback)); + } + }; + + if (config.configMinimumVisitLength === 0) { + config.activityInterval = window.setInterval(heartbeat, config.configHeartBeatTimer); + } else { + config.activityInterval = window.setTimeout(timeout, config.configMinimumVisitLength); + } + } + + /** + * Configure the activity tracking and ensures integer values for min visit and heartbeat + */ + function configureActivityTracking( + configuration: ActivityTrackingConfiguration & ActivityTrackingConfigurationCallback + ): ActivityConfig | undefined { + const { minimumVisitLength, heartbeatDelay, callback } = configuration; + if (isInteger(minimumVisitLength) && isInteger(heartbeatDelay)) { + return { + configMinimumVisitLength: minimumVisitLength * 1000, + configHeartBeatTimer: heartbeatDelay * 1000, + callback, + activityMetrics: configuration.activityMetrics, + }; + } + + LOG.error('Activity tracking minimumVisitLength & heartbeatDelay must be integers'); + return undefined; + } + + /** + * Log that a user is still viewing a given page by sending a page ping. + * Not part of the public API - only called from logPageView() above. + */ + function logPagePing({ context, minXOffset, minYOffset, maxXOffset, maxYOffset }: ActivityCallbackData) { + const newDocumentTitle = document.title; + if (newDocumentTitle !== lastDocumentTitle) { + lastDocumentTitle = newDocumentTitle; + lastConfigTitle = undefined; + } + core.track( + buildPagePing({ + pageUrl: purify(configCustomUrl || locationHrefAlias), + pageTitle: fixupTitle(lastConfigTitle || lastDocumentTitle), + referrer: purify(customReferrer || configReferrerUrl), + minXOffset: cleanOffset(minXOffset), + maxXOffset: cleanOffset(maxXOffset), + minYOffset: cleanOffset(minYOffset), + maxYOffset: cleanOffset(maxYOffset), + }), + context + ); + } + + function disableActivityTrackingAction(actionKey: keyof ActivityConfigurations) { + const callbackConfiguration = activityTrackingConfig.configurations[actionKey]; + if (callbackConfiguration?.configMinimumVisitLength === 0) { + window.clearTimeout(callbackConfiguration?.activityInterval); + } else { + window.clearInterval(callbackConfiguration?.activityInterval); + } + + activityTrackingConfig.configurations[actionKey] = undefined; + + if (!activityTrackingConfig.configurations.pagePing && !activityTrackingConfig.configurations.callback) { + resetActivityMetricsState(); + } + } + + const apiMethods = { + getDomainSessionIndex: function () { + return memorizedVisitCount; + }, + + getPageViewId, + + getTabId, + + newSession, + + getCookieName: function (basename: string) { + return getSnowplowCookieName(basename); + }, + + getUserId: function () { + return businessUserId; + }, + + getDomainUserId: function () { + return loadDomainUserIdCookie()[1]; + }, + + getDomainUserInfo: function () { + return loadDomainUserIdCookie(); + }, + + getDomainSessionId: function () { + return memorizedSessionId || sessionIdFromIdCookie(loadDomainUserIdCookie()); + }, + + setReferrerUrl: function (url: string) { + customReferrer = url; + }, + + setCustomUrl: function (url: string) { + refreshUrl(); + configCustomUrl = resolveRelativeReference(locationHrefAlias, url); + }, + + setDocumentTitle: function (title: string) { + // So we know what document.title was at the time of trackPageView + lastDocumentTitle = document.title; + lastConfigTitle = title; + lastConfigTitleFromTrackPageView = false; + }, + + discardHashTag: function (enableFilter: boolean) { + configDiscardHashTag = enableFilter; + }, + + discardBrace: function (enableFilter: boolean) { + configDiscardBrace = enableFilter; + }, + + setCookiePath: function (path: string) { + configCookiePath = path; + updateDomainHash(); + }, + + setVisitorCookieTimeout: function (timeout: number) { + configVisitorCookieTimeout = timeout; + }, + + crossDomainLinker: function (crossDomainLinkerCriterion: (elt: HTMLAnchorElement | HTMLAreaElement) => boolean) { + decorateLinks(crossDomainLinkerCriterion); + }, + + enableActivityTracking: function (configuration: ActivityTrackingConfiguration) { + if (!activityTrackingConfig.configurations.pagePing) { + activityTrackingConfig.enabled = true; + activityTrackingConfig.configurations.pagePing = configureActivityTracking({ + ...configuration, + callback: logPagePing, + }); + } + }, + + enableActivityTrackingCallback: function ( + configuration: ActivityTrackingConfiguration & ActivityTrackingConfigurationCallback + ) { + if (!activityTrackingConfig.configurations.callback) { + activityTrackingConfig.enabled = true; + activityTrackingConfig.configurations.callback = configureActivityTracking(configuration); + } + }, + + disableActivityTracking: function () { + disableActivityTrackingAction('pagePing'); + }, + + disableActivityTrackingCallback: function () { + disableActivityTrackingAction('callback'); + }, + + updatePageActivity: function () { + activityHandler(); + }, + + setOptOutCookie: function (name?: string | null) { + configOptOutCookie = name; + }, + + setUserId: function (userId?: string | null) { + businessUserId = userId; + }, + + setUserIdFromLocation: function (querystringField: string) { + refreshUrl(); + businessUserId = fromQuerystring(querystringField, locationHrefAlias); + }, + + setUserIdFromReferrer: function (querystringField: string) { + refreshUrl(); + businessUserId = fromQuerystring(querystringField, configReferrerUrl); + }, + + setUserIdFromCookie: function (cookieName: string) { + businessUserId = cookieStorage.getCookie(cookieName); + }, + + setCollectorUrl: function (collectorUrl: string) { + outQueue.setCollectorUrl(asCollectorUrl(collectorUrl)); + }, + + setBufferSize: function (newBufferSize: number) { + outQueue.setBufferSize(newBufferSize); + }, + + flushBuffer: function (configuration: FlushBufferConfiguration = {}) { + outQueue.executeQueue(); + if (configuration.newBufferSize) { + outQueue.setBufferSize(configuration.newBufferSize); + } + }, + + trackPageView: function (event: PageViewEvent & CommonEventProperties = {}) { + logPageView(event); + }, + + preservePageViewId: function () { + preservePageViewId = true; + }, + + preservePageViewIdForUrl: function (preserve: PreservePageViewIdForUrl) { + preservePageViewIdForUrl = preserve; + }, + + disableAnonymousTracking: function (configuration?: DisableAnonymousTrackingConfiguration) { + /* + Flag for if the state storage strategy has changed and we are currently storing session state (anonymously or not). + Because the strategy changes, the below call to initializeIdsAndCookies will fail to see that a session is currently in progress and start a new one. + Detect this state, and once we've updated settings, bump the session cookie with the new strategy to ensure it exists before loading the ID cookie, which will resume the session. + */ + const shouldResumeSession = + configuration?.stateStorageStrategy && // a new strategy was defined (otherwise will already resume) + configuration.stateStorageStrategy !== configStateStorageStrategy && // new strategy is different to old one (otherwise will already resume) + (!configAnonymousTracking || configAnonymousSessionTracking) && // we were previously tracking session IDs (otherwise nothing to resume) + getSnowplowCookieValue('ses'); // and we currently have a session in progress (otherwise we want a new session anyway) + + trackerConfiguration.anonymousTracking = false; + + toggleAnonymousTracking(configuration); + + if (shouldResumeSession) setSessionCookie(); // ensure session cookie exists with new strategy + + initializeIdsAndCookies(); + + outQueue.executeQueue(); // There might be some events in the queue we've been unable to send in anonymous mode + }, + + enableAnonymousTracking: function (configuration?: EnableAnonymousTrackingConfiguration) { + trackerConfiguration.anonymousTracking = (configuration && configuration?.options) ?? true; + + toggleAnonymousTracking(configuration); + + // Reset the page view, if not tracking the session, so can't stitch user into new events on the page view id + if (!configAnonymousSessionTracking) { + resetPageView(); + } + }, + + clearUserData: clearUserDataAndCookies, + }; + + return { + ...apiMethods, + id: trackerId, + namespace, + core: core, + sharedState: state, + }; + }; + + // Initialise the tracker + const partialTracker = newTracker(trackerId, namespace, version, endpoint, sharedState, trackerConfiguration), + tracker = { + ...partialTracker, + addPlugin: (configuration: BrowserPluginConfiguration) => { + tracker.core.addPlugin(configuration); + configuration.plugin.activateBrowserPlugin?.(tracker); + }, + }; + + // Initialise each plugin with the tracker + browserPlugins.forEach((p) => { + p.activateBrowserPlugin?.(tracker); + }); + + return tracker; +} diff --git a/libraries/browser-tracker-core/src/tracker/local_storage_event_store.ts b/libraries/browser-tracker-core/src/tracker/local_storage_event_store.ts new file mode 100644 index 000000000..b6e554aa4 --- /dev/null +++ b/libraries/browser-tracker-core/src/tracker/local_storage_event_store.ts @@ -0,0 +1,70 @@ +import { EventStore, newInMemoryEventStore, EventStorePayload } from '@snowplow/tracker-core'; +import { LocalStorageEventStoreConfigurationBase } from './types'; + +export interface LocalStorageEventStoreConfiguration extends LocalStorageEventStoreConfigurationBase { + /** + * The unique identifier for the event store + */ + trackerId: string; +} + +export interface LocalStorageEventStore extends EventStore { + setUseLocalStorage: (localStorage: boolean) => void; +} + +export function newLocalStorageEventStore({ + trackerId, + maxLocalStorageQueueSize = 1000, + useLocalStorage = true, +}: LocalStorageEventStoreConfiguration): LocalStorageEventStore { + const queueName = `snowplowOutQueue_${trackerId}`; + + function newInMemoryEventStoreFromLocalStorage() { + if (useLocalStorage) { + try { + const localStorageQueue = window.localStorage.getItem(queueName); + const events: EventStorePayload[] = localStorageQueue ? JSON.parse(localStorageQueue) : []; + return newInMemoryEventStore({ maxSize: maxLocalStorageQueueSize, events }); + } catch (e) { + console.error('Failed to access localStorage when initializing event store:', e); + return newInMemoryEventStore({ maxSize: maxLocalStorageQueueSize }); + } + } else { + return newInMemoryEventStore({ maxSize: maxLocalStorageQueueSize }); + } + } + + const { getAll, getAllPayloads, add, count, iterator, removeHead } = newInMemoryEventStoreFromLocalStorage(); + + function sync(): Promise { + if (useLocalStorage) { + return getAll().then((events) => { + try { + window.localStorage.setItem(queueName, JSON.stringify(events)); + } catch (e) { + console.error('Failed to persist events to localStorage:', e); + } + }); + } else { + return Promise.resolve(); + } + } + + return { + count, + add: (payload: EventStorePayload) => { + add(payload); + return sync().then(count); + }, + removeHead: (count: number) => { + removeHead(count); + return sync(); + }, + iterator, + getAll, + getAllPayloads, + setUseLocalStorage: (use: boolean) => { + useLocalStorage = use; + }, + }; +} diff --git a/libraries/browser-tracker-core/src/tracker/out_queue.ts b/libraries/browser-tracker-core/src/tracker/out_queue.ts new file mode 100644 index 000000000..37327b0ec --- /dev/null +++ b/libraries/browser-tracker-core/src/tracker/out_queue.ts @@ -0,0 +1,42 @@ +import { newEmitter, EmitterConfiguration } from '@snowplow/tracker-core'; +import { + newLocalStorageEventStore, + LocalStorageEventStoreConfiguration, + LocalStorageEventStore, +} from './local_storage_event_store'; +import { Payload } from '@snowplow/tracker-core'; +import { SharedState } from '../state'; + +export interface OutQueue { + enqueueRequest: (request: Payload) => Promise; + executeQueue: () => Promise; + setUseLocalStorage: (localStorage: boolean) => void; + setAnonymousTracking: (anonymous: boolean) => void; + setCollectorUrl: (url: string) => void; + setBufferSize: (bufferSize: number) => void; +} + +export function newOutQueue( + configuration: EmitterConfiguration & LocalStorageEventStoreConfiguration, + sharedState: SharedState +): OutQueue { + const eventStore = configuration.eventStore ?? newLocalStorageEventStore(configuration); + configuration.eventStore = eventStore; + const emitter = newEmitter(configuration); + + sharedState.bufferFlushers.push(emitter.flush); + + return { + enqueueRequest: emitter.input, + executeQueue: emitter.flush, + setAnonymousTracking: emitter.setAnonymousTracking, + setCollectorUrl: emitter.setCollectorUrl, + setBufferSize: emitter.setBufferSize, + setUseLocalStorage: (localStorage: boolean) => { + if (eventStore.hasOwnProperty('setUseLocalStorage')) { + const localStorageStore = eventStore as LocalStorageEventStore; + localStorageStore.setUseLocalStorage(localStorage); + } + }, + }; +} diff --git a/libraries/browser-tracker-core/src/tracker/schemata.ts b/libraries/browser-tracker-core/src/tracker/schemata.ts new file mode 100644 index 000000000..2d6019f42 --- /dev/null +++ b/libraries/browser-tracker-core/src/tracker/schemata.ts @@ -0,0 +1,5 @@ +export const WEB_PAGE_SCHEMA = 'iglu:com.snowplowanalytics.snowplow/web_page/jsonschema/1-0-0'; +export const BROWSER_CONTEXT_SCHEMA = 'iglu:com.snowplowanalytics.snowplow/browser_context/jsonschema/2-0-0'; +export const CLIENT_SESSION_SCHEMA = 'iglu:com.snowplowanalytics.snowplow/client_session/jsonschema/1-0-2'; +export const APPLICATION_CONTEXT_SCHEMA = 'iglu:com.snowplowanalytics.snowplow/application/jsonschema/1-0-0'; +export const ACTIVITY_METRICS_SCHEMA = 'iglu:com.snowplowanalytics.snowplow/activity_metrics/jsonschema/1-0-0'; diff --git a/libraries/browser-tracker-core/src/tracker/types.ts b/libraries/browser-tracker-core/src/tracker/types.ts new file mode 100755 index 000000000..f2a83b297 --- /dev/null +++ b/libraries/browser-tracker-core/src/tracker/types.ts @@ -0,0 +1,710 @@ +import { BrowserPlugin } from '../plugins'; +import { + CommonEventProperties, + SelfDescribingJson, + TrackerCore, + CorePluginConfiguration, +} from '@snowplow/tracker-core'; +import { SharedState } from '../state'; +import { EmitterConfigurationBase, EventStoreConfiguration } from '@snowplow/tracker-core'; + +type RequireAtLeastOne = { [K in keyof T]-?: Required> & Partial>> }[keyof T]; + +/* Available built-in contexts */ +export type BuiltInContexts = + | RequireAtLeastOne<{ + /* Toggles the web_page context */ + webPage: boolean; + /* Toggles the session context */ + session: boolean; + /* Toggles the browser context */ + browser: boolean; + }> + | Record; + +/* Configuration for Anonymous Tracking */ +export type AnonymousTrackingOptions = boolean | { withSessionTracking?: boolean; withServerAnonymisation?: boolean }; +/* Available configurations for different storage strategies */ +export type StateStorageStrategy = 'cookieAndLocalStorage' | 'cookie' | 'localStorage' | 'none'; +/* The supported platform values */ +export type Platform = 'web' | 'mob' | 'pc' | 'srv' | 'app' | 'tv' | 'cnsl' | 'iot'; +/* The supported Cookie SameSite values */ +export type CookieSameSite = 'None' | 'Lax' | 'Strict'; + +/* Available configuration for the extended cross domain linker */ +export type ExtendedCrossDomainLinkerAttributes = { + userId?: boolean; + sessionId?: boolean; + sourceId?: boolean; + sourcePlatform?: boolean; + /** + * Allow for the collection of the link text when a cross-domain link is clicked. Can also accept a callback for customizing information collection. + */ + reason?: boolean | ((evt: Event) => string); +}; + +export type ExtendedCrossDomainLinkerOptions = boolean | ExtendedCrossDomainLinkerAttributes; + +/* Setting for the `preservePageViewIdForUrl` configuration that decides how to preserve the pageViewId on URL changes. */ +export type PreservePageViewIdForUrl = boolean | 'full' | 'pathname' | 'pathnameAndSearch'; + +export interface LocalStorageEventStoreConfigurationBase extends EventStoreConfiguration { + /** + * The maximum amount of events that will be buffered in local storage + * + * This is useful to ensure the Tracker doesn't fill the 5MB or 10MB available to + * each website should the collector be unavailable due to lost connectivity. + * Will drop events once the limit is hit + * @defaultValue 1000 + */ + maxLocalStorageQueueSize?: number; + + /** + * Whether to use localStorage at all + * Default is true + */ + useLocalStorage?: boolean; +} + +/** + * The configuration object for initialising the tracker + * @example + * ``` + * newTracker('sp1', 'collector.my-website.com', { + * appId: 'my-app-id', + * platform: 'web', + * plugins: [ PerformanceTimingPlugin(), AdTrackingPlugin() ], + * stateStorageStrategy: 'cookieAndLocalStorage' + * }); + * ``` + */ +export type TrackerConfiguration = { + /** + * Should event properties be base64 encoded where supported + * @defaultValue false unless {@link EmitterConfigurationBase.eventMethod | eventMethod} is `get` + */ + encodeBase64?: boolean; + /** + * The domain all cookies will be set on + * @defaultValue The current domain + */ + cookieDomain?: string; + /** + * The name of the _sp_.id cookie, will rename the _sp_ section + * @defaultValue _sp_ + */ + cookieName?: string; + /** + * The SameSite value for the cookie + * {@link https://snowplowanalytics.com/blog/2020/09/07/pipeline-configuration-for-complete-and-accurate-data/} + * @defaultValue Lax + */ + cookieSameSite?: CookieSameSite; + /** + * Set the Secure flag on the cookie + * @defaultValue true + */ + cookieSecure?: boolean; + /** + * How long the cookie will be set for + * @defaultValue 63072000 (2 years) + */ + cookieLifetime?: number; + /** + * How long until a session expires + * @defaultValue 1800 (30 minutes) + */ + sessionCookieTimeout?: number; + /** The app id to send with each event */ + appId?: string; + /** + * Version of the application tracked as a context entity with all events. + * Can be a semver-like structure (e.g 1.1.0) or a Git commit SHA hash. + * Entity schema: iglu:com.snowplowanalytics.snowplow/application/jsonschema/1-0-0 + */ + appVersion?: string; + /** + * The platform the event is being sent from + * @defaultValue web + */ + platform?: Platform; + /** + * Whether the doNotTracK flag should be respected + * @defaultValue false + */ + respectDoNotTrack?: boolean; + /** + * Configure the cross domain linker which will add user identifiers to + * links on the callback + */ + crossDomainLinker?: (elt: HTMLAnchorElement | HTMLAreaElement) => boolean; + /** + * Configure the cross domain linker to use the extended format, allowing for + * more user/session information to pass to the cross domain navigation. + */ + useExtendedCrossDomainLinker?: ExtendedCrossDomainLinkerOptions; + /** + * Whether the tracker should attempt to figure out what the root + * domain is to store cookies on + * + * This sets cookies to try to determine the root domain, and some cookies may + * fail to save. This is expected behavior. + * @defaultValue true + */ + discoverRootDomain?: boolean; + /** + * The storage strategy which the tracker will use for storing user and session identifiers + * and if local storage is allowed for buffering the events + * @defaultValue cookieAndLocalStorage + */ + stateStorageStrategy?: StateStorageStrategy; + /** + * Whether to reset the Activity Tracking counters on a new page view. + * Disabling this leads to legacy behavior due to a "bug". + * Recommended to leave enabled, particularly on SPAs. + * @defaultValue true + */ + resetActivityTrackingOnPageView?: boolean; + /** + * Configuration for Anonymous Tracking + * @defaultValue false + */ + anonymousTracking?: AnonymousTrackingOptions; + /** + * Use to configure built in contexts + * @defaultValue `{ webPage: true, session: false, browser: false }` + */ + contexts?: BuiltInContexts; + /** + * Inject plugins which will be evaluated for each event + * @defaultValue [] + */ + plugins?: Array; + /** + * Callback fired whenever the session identifier is updated. + * @param updatedSession - On session update, the new session information plus the previous session id. + */ + onSessionUpdateCallback?: (updatedSession: ClientSession) => void; + + /** + * Decide how the `pageViewId` should be preserved based on the URL. + * If set to `false`, the `pageViewId` will be regenerated on the second and each following page view event (first page view doesn't change the page view ID since tracker initialization). + * If set to `true` or `'full'`, the `pageViewId` will be kept the same for all page views with that exact URL (even for events tracked before the page view event). + * If set to `'pathname'`, the `pageViewId` will be kept the same for all page views with the same pathname (search params or fragment may change). + * If set to `'pathnameAndSearch'`, the `pageViewId` will be kept the same for all page views with the same pathname and search params (fragment may change). + * If `preservePageViewId` is enabled, the `preservePageViewIdForUrl` setting is ignored. + * Defaults to `false`. + */ + preservePageViewIdForUrl?: PreservePageViewIdForUrl; + + /** + * When enabled, the original external referrer captured at tracker initialisation is frozen and + * used as the referrer for all subsequent page view events in the same session, including + * client-side navigations in single-page applications (SPAs). + * + * Without this option, each SPA navigation sets the referrer to the previous internal route, + * making it difficult to determine how the user originally arrived at the site across their + * session. Enable this option to preserve the original external referrer (e.g. google.com) + * across all `trackPageView` calls. + * + * If `document.referrer` is empty at initialisation (e.g. direct navigation), this option + * has no effect and the default per-navigation referrer chain behaviour applies. + * + * Setting `setReferrerUrl` after initialisation will override this value, as `customReferrer` + * always takes precedence. + * + * @defaultValue false + */ + preserveOriginalReferrer?: boolean; + + /** + * Whether to write the cookies synchronously. + * This can be useful for testing purposes to ensure that the cookies are written before the test continues. + * It also has the benefit of making sure that the cookie is correctly set before session information is used in events. + * The downside is that it is slower and blocks the main thread. + * @defaultValue false + */ + synchronousCookieWrite?: boolean; + /** + * When set to `true`, the tracker will not attach the `client_session` context entity to events + * when running inside a mobile WebView (i.e. when a Snowplow V2 WebView interface is detected). + * + * In hybrid native+WebView deployments the mobile SDK already contributes its own `client_session` + * entity. Allowing a second one from the JavaScript tracker causes duplicate-session problems in + * downstream modelling (e.g. dbt-snowplow-unified). Setting this option suppresses the JavaScript + * tracker's copy while the `contexts.session` flag can remain `true`. + * + * Detection uses the same three V2 interface checks as `@snowplow/webview-tracker`: + * `window.SnowplowWebInterfaceV2`, `window.webkit?.messageHandlers?.snowplowV2`, and + * `window.ReactNativeWebView`. + * + * @defaultValue false + */ + disableSessionContextWithinWebView?: boolean; +} & EmitterConfigurationBase & + LocalStorageEventStoreConfigurationBase; + +/** + * The data which is passed to the Activity Tracking callback + */ +export type ActivityCallbackData = { + /** + * All context for the activity tracking + * Often generated by the page view events context callback + */ + context: Array; + /** The current page view id */ + pageViewId: string; + /** The minimum X scroll position for the current page view */ + minXOffset: number; + /** The maximum X scroll position for the current page view */ + minYOffset: number; + /** The minimum Y scroll position for the current page view */ + maxXOffset: number; + /** The maximum Y scroll position for the current page view */ + maxYOffset: number; + /** Activity metrics accumulated since the last ping (only when activityMetrics is enabled) */ + activityMetrics?: ActivityMetrics; +}; + +/** The callback for enableActivityTrackingCallback */ +export type ActivityCallback = (data: ActivityCallbackData) => void; + +/** + * Quantitative activity metrics accumulated between page pings. + * Attached as a context entity when activityMetrics is enabled. + */ +export type ActivityMetrics = { + /** Cumulative Euclidean mouse distance in pixels from mousemove events */ + mouseDistance: number; + /** Cumulative |deltaX|+|deltaY| scroll distance in pixels */ + scrollDistance: number; + /** Count of keydown events */ + keyPresses: number; + /** Count of click events */ + clicks: number; + /** Count of touchstart events */ + touches: number; +}; + +/** + * The base configuration for activity tracking + */ +export interface ActivityTrackingConfiguration { + /** The minimum time that must have elapsed before first heartbeat */ + minimumVisitLength: number; + /** The interval at which the callback will be fired */ + heartbeatDelay: number; + /** Enable activity metrics to attach an activity_metrics entity to each page ping */ + activityMetrics?: boolean; +} + +/** + * The callback for enableActivityTrackingCallback + */ +export interface ActivityTrackingConfigurationCallback { + /** The callback to fire based on heart beat */ + callback: ActivityCallback; +} + +/** + * A Page View event + * Used for tracking a page view + */ +export interface PageViewEvent { + /** Override the page title */ + title?: string | null; + /** A callback which will fire on the page view and each subsequent activity tracking event for this page view */ + contextCallback?: (() => Array) | null; +} + +/** + * The configuration that can be changed when disabling anonymous tracking + */ +export interface DisableAnonymousTrackingConfiguration { + /* Available configurations for different storage strategies */ + stateStorageStrategy?: StateStorageStrategy; +} + +/** + * The configuration that can be changed when enabling anonymous tracking + */ +export interface EnableAnonymousTrackingConfiguration { + /* Configuration for Anonymous Tracking */ + options?: AnonymousTrackingOptions; + /* Available configurations for different storage strategies */ + stateStorageStrategy?: StateStorageStrategy; +} + +/** + * The configuration that can be changed when enabling anonymous tracking + */ +export interface ClearUserDataConfiguration { + /* Store session information in memory for subsequent events */ + preserveSession: boolean; + /* Store user information in memory for subsequent events */ + preserveUser: boolean; +} + +/** + * The configuration that can be changed when flushing the buffer + */ +export interface FlushBufferConfiguration { + /* The size of the buffer after this flush */ + newBufferSize?: number; +} + +/** + * The configuration of the plugin to add + */ +export interface BrowserPluginConfiguration extends CorePluginConfiguration { + /* The plugin to add */ + plugin: BrowserPlugin; +} + +/** + * The format of state elements stored in the `id` cookie. + */ +export type ParsedIdCookie = [ + cookieDisabled: string, + domainUserId: string, + cookieCreateTs: number, + visitCount: number, + nowTs: number, + lastVisitTs: number | undefined, + sessionId: string, + previousSessionId: string, + firstEventId: string, + firstEventTs: number | undefined, + eventIndex: number +]; + +/** + * The Browser Tracker + */ +export interface BrowserTracker { + /** The unique identifier of this tracker */ + id: string; + /** The tracker namespace */ + namespace: string; + /** The instance of the core library which this tracker has initialised */ + core: TrackerCore; + /** The instance of shared state this tracker is using */ + sharedState: SharedState; + + /** + * Get the domain session index also known as current memorized visit count. + * + * @returns Domain session index + */ + getDomainSessionIndex: () => number; + + /** + * Get the current page view ID + * + * @returns Page view ID + */ + getPageViewId: () => string; + + /** + * Get the current browser tab ID + * + * @returns Browser tab ID + */ + getTabId: () => string | null; + + /** + * Get the cookie name as cookieNamePrefix + basename + . + domain. + * + * @returns Cookie name + */ + getCookieName: (basename: string) => string; + + /** + * Get the current user ID (as set previously with setUserId()). + * + * @returns Business-defined user ID + */ + getUserId: () => string | null | undefined; + + /** + * Get visitor ID (from first party cookie) + * + * @returns Visitor ID (or null, if not yet known) + */ + getDomainUserId: () => string; + + /** + * Get the visitor information (from first party cookie) + * + * @returns The domain user information array + */ + getDomainUserInfo: () => ParsedIdCookie; + + /** + * Get the current domain session ID (from first party cookie) + * + * @returns Domain session ID + */ + getDomainSessionId: () => string; + + /** + * Override referrer + * + * @param url - the custom referrer + */ + setReferrerUrl: (url: string) => void; + + /** + * Override url + * + * @param url - The custom url + */ + setCustomUrl: (url: string) => void; + + /** + * Override document.title + * + * @param title - The document title + */ + setDocumentTitle: (title: string) => void; + + /** + * Strip hash tag (or anchor) from URL + * + * @param enableFilter - whether to enable this feature + */ + discardHashTag: (enableFilter: boolean) => void; + + /** + * Strip braces from URL + * + * @param enableFilter - whether to enable this feature + */ + discardBrace: (enableFilter: boolean) => void; + + /** + * Set first-party cookie path + * + * @param path - The path for cookies + */ + setCookiePath: (path: string) => void; + + /** + * Set visitor cookie timeout (in seconds) + * + * @param timeout - The timeout for the user identifier cookie + */ + setVisitorCookieTimeout: (timeout: number) => void; + + /** + * Expires current session and starts a new session. + */ + newSession: () => void; + + /** + * Enable querystring decoration for links passing a filter + * + * @param crossDomainLinkerCriterion - Function used to determine which links to decorate + */ + crossDomainLinker: (crossDomainLinkerCriterion: (elt: HTMLAnchorElement | HTMLAreaElement) => boolean) => void; + + /** + * Enables page activity tracking (sends page + * pings to the Collector regularly). + * + * @param configuration - The activity tracking configuration + */ + enableActivityTracking: (configuration: ActivityTrackingConfiguration) => void; + + /** + * Enables page activity tracking (replaces collector ping with callback). + * + * @param configuration - The activity tracking configuration + */ + enableActivityTrackingCallback: ( + configuration: ActivityTrackingConfiguration & ActivityTrackingConfigurationCallback + ) => void; + + /** + * Disables page activity tracking. + */ + disableActivityTracking: () => void; + + /** + * Disables page activity tracking callback. + */ + disableActivityTrackingCallback: () => void; + + /** + * Triggers the activityHandler manually to allow external user defined + * activity. i.e. While watching a video + */ + updatePageActivity: () => void; + + /** + * Sets the opt out cookie. + * + * @param name - of the opt out cookie + */ + setOptOutCookie: (name?: string | null) => void; + + /** + * Set the business-defined user ID for this user. + * + * @param userId - The business-defined user ID + */ + setUserId: (userId?: string | null) => void; + + /** + * Set the business-defined user ID for this user using the location querystring. + * + * @param querystringField - Name of a querystring name-value pair + */ + setUserIdFromLocation: (querystringField: string) => void; + + /** + * Set the business-defined user ID for this user using the referrer querystring. + * + * @param querystringField - Name of a querystring name-value pair + */ + setUserIdFromReferrer: (querystringField: string) => void; + + /** + * Set the business-defined user ID for this user to the value of a cookie. + * + * @param cookieName - Name of the cookie whose value will be assigned to businessUserId + */ + setUserIdFromCookie: (cookieName: string) => void; + + /** + * Specify the Snowplow collector URL. Specific http or https to force it + * or leave it off to match the website protocol. + * + * @param collectorUrl - The collector URL, with or without protocol + */ + setCollectorUrl: (collectorUrl: string) => void; + + /** + * Alter buffer size + * Can be useful if you want to stop batching requests to ensure events start + * sending closer to event creation + * + * @param newBufferSize - The new buffer size that will be used for all future tracking + */ + setBufferSize: (newBufferSize: number) => void; + + /** + * Send all events in the outQueue + * Only need to use this when sending events with a bufferSize of at least 2 + * + * @param configuration - The configuration to use following flushing the buffer + */ + flushBuffer: (configuration?: FlushBufferConfiguration) => void; + + /** + * Stop regenerating `pageViewId` (available from `web_page` context) + */ + preservePageViewId: () => void; + + /** + * Decide how the `pageViewId` should be preserved based on the URL. + * If set to `false`, the `pageViewId` will be regenerated on the second and each following page view event (first page view doesn't change the page view ID since tracker initialization). + * If set to `true` or `'full'`, the `pageViewId` will be kept the same for all page views with that exact URL (even for events tracked before the page view event). + * If set to `'pathname'`, the `pageViewId` will be kept the same for all page views with the same pathname (search params or fragment may change). + * If set to `'pathnameAndSearch'`, the `pageViewId` will be kept the same for all page views with the same pathname and search params (fragment may change). + * If `preservePageViewId` is enabled, the `preservePageViewIdForUrl` setting is ignored. + * Defaults to `false`. + */ + preservePageViewIdForUrl: (preserve: PreservePageViewIdForUrl) => void; + + /** + * Log visit to this page + * + * @param event - The Page View Event properties + */ + trackPageView: (event?: PageViewEvent & CommonEventProperties) => void; + + /** + * Disables anonymous tracking if active (ie. tracker initialized with `anonymousTracking`) + * For stateStorageStrategy override, uses supplied value first, + * falls back to one defined in initial config, otherwise uses cookieAndLocalStorage. + * + * @param configuration - The configuration to use following disabling anonymous tracking + */ + disableAnonymousTracking: (configuration?: DisableAnonymousTrackingConfiguration) => void; + + /** + * Enables anonymous tracking (ie. tracker initialized without `anonymousTracking`) + * + * @param configuration - The configuration to use following activating anonymous tracking + */ + enableAnonymousTracking: (configuration?: EnableAnonymousTrackingConfiguration) => void; + + /** + * Clears all cookies and local storage containing user and session identifiers + */ + clearUserData: (configuration?: ClearUserDataConfiguration) => void; + + /** + * Add a plugin into the plugin collection after Tracker has already been initialised + * @param configuration - The plugin to add + */ + addPlugin: (configuration: BrowserPluginConfiguration) => void; +} + +/** + * Schema for client client session context entity + */ +export interface ClientSession extends Record { + /** + * An identifier for the user of the session (same as domain_userid) + */ + userId: string; + + /** + * An identifier for the session (same as domain_sessionid) + */ + sessionId: string; + + /** + * The index of the current session for this user (same as domain_sessionidx) + */ + sessionIndex: number; + + /** + * Index of the current event in the session + */ + eventIndex: number; + + /** + * The previous session identifier for this user + */ + previousSessionId: string | null; + + /** + * The mechanism that the session information has been stored on the device + */ + storageMechanism: string; + + /** + * Identifier of the first event for this session + */ + firstEventId: string | null; + + /** + * Date-time timestamp of when the first event in the session was tracked + */ + firstEventTimestamp: string | null; +} + +export { + RequestFailure, + EventBatch, + EventMethod, + EventStore, + EventStoreIterator, + EventStorePayload, + EventStoreConfiguration, + Payload, +} from '@snowplow/tracker-core'; diff --git a/libraries/browser-tracker-core/test/browser_props.test.ts b/libraries/browser-tracker-core/test/browser_props.test.ts new file mode 100644 index 000000000..8e300eed8 --- /dev/null +++ b/libraries/browser-tracker-core/test/browser_props.test.ts @@ -0,0 +1,152 @@ +import { makeDimension, getBrowserProperties, resetBrowserPropertiesState } from '../src/helpers/browser_props'; + +describe('Browser props', () => { + it('makeDimension correctly floors dimension type values', () => { + const testDimensions = '100x100'; + expect(makeDimension(100, 100)).toEqual(testDimensions); + }); + + it('makeDimension correctly floors dimension type values with fractional numbers', () => { + expect(makeDimension(100.2, 100.1)).toEqual('100x100'); + }); + + it('makeDimension correctly drops invalid values', () => { + expect(makeDimension(undefined as any, 100.1)).toEqual(null); + expect(makeDimension(NaN, 1)).toEqual(null); + }); + + describe('#getBrowserProperties', () => { + describe('caching behavior (modern browsers with ResizeObserver)', () => { + let savedResizeObserver: any; + + beforeEach(() => { + savedResizeObserver = (window as any).ResizeObserver; + // Provide a minimal ResizeObserver so the caching path is exercised + (window as any).ResizeObserver = class MockResizeObserver { + constructor(_cb: ResizeObserverCallback) {} + observe() {} + unobserve() {} + disconnect() {} + }; + resetBrowserPropertiesState(); + }); + + afterEach(() => { + (window as any).ResizeObserver = savedResizeObserver; + resetBrowserPropertiesState(); + jest.restoreAllMocks(); + }); + + it('returns the same cached reference on successive calls', () => { + const first = getBrowserProperties(); + const second = getBrowserProperties(); + expect(second).toBe(first); + }); + + it('reset clears the cache so the next call re-reads browser properties', () => { + getBrowserProperties(); + resetBrowserPropertiesState(); + const fresh = getBrowserProperties(); + expect(fresh).toBeDefined(); + expect(fresh.cookiesEnabled).toBeDefined(); + }); + + it('rAF callback triggered by ResizeObserver updates cachedProperties', () => { + let capturedResizeCallback: ResizeObserverCallback | undefined; + let capturedRafCallback: FrameRequestCallback | undefined; + + // Override the mock to capture the ResizeObserver callback so we can trigger it manually + (window as any).ResizeObserver = class CaptureResizeObserver { + constructor(cb: ResizeObserverCallback) { + capturedResizeCallback = cb; + } + observe() {} + unobserve() {} + disconnect() {} + }; + resetBrowserPropertiesState(); + + jest.spyOn(window, 'requestAnimationFrame').mockImplementation((cb) => { + capturedRafCallback = cb; + return 1; + }); + + const first = getBrowserProperties(); // populates cache + wires up ResizeObserver + + // Trigger the ResizeObserver callback to schedule a rAF + expect(capturedResizeCallback).toBeDefined(); + capturedResizeCallback!([], {} as ResizeObserver); + expect(capturedRafCallback).toBeDefined(); + + // rAF has been scheduled but not yet fired — cache still holds the original value + const beforeRaf = getBrowserProperties(); + expect(beforeRaf).toBe(first); + + // Fire the rAF callback to simulate the cache update + capturedRafCallback!(performance.now()); + + // Cache was refreshed by the rAF callback + const afterRaf = getBrowserProperties(); + expect(afterRaf).toBeDefined(); + }); + }); + + describe('old-browser fallback (no ResizeObserver)', () => { + let savedResizeObserver: any; + + beforeEach(() => { + savedResizeObserver = (window as any).ResizeObserver; + delete (window as any).ResizeObserver; + resetBrowserPropertiesState(); + }); + + afterEach(() => { + (window as any).ResizeObserver = savedResizeObserver; + resetBrowserPropertiesState(); + }); + + it('calls readBrowserProperties on every invocation — no caching', () => { + const first = getBrowserProperties(); + const second = getBrowserProperties(); + // Without ResizeObserver caching each call returns a fresh object + expect(second).not.toBe(first); + }); + }); + + describe('with undefined document', () => { + let originalDocument: typeof document; + let savedResizeObserver: any; + + beforeAll(() => { + originalDocument = document; + savedResizeObserver = (window as any).ResizeObserver; + + // Ensure the caching path is taken so initializeResizeObserver() guards against undefined document + (window as any).ResizeObserver = class MockResizeObserver { + constructor(_cb: ResizeObserverCallback) {} + observe() {} + unobserve() {} + disconnect() {} + }; + + // Pre-populate cache while document is still available + resetBrowserPropertiesState(); + getBrowserProperties(); + + // @ts-expect-error + document = undefined; + }); + + afterAll(() => { + document = originalDocument; + (window as any).ResizeObserver = savedResizeObserver; + resetBrowserPropertiesState(); + }); + + it('does not invoke the resize observer if the document is null', () => { + const browserProperties = getBrowserProperties(); + expect(browserProperties).not.toEqual(null); + }); + }); + }); +}); diff --git a/libraries/browser-tracker-core/test/detectors.test.ts b/libraries/browser-tracker-core/test/detectors.test.ts new file mode 100644 index 000000000..5d61e2e6f --- /dev/null +++ b/libraries/browser-tracker-core/test/detectors.test.ts @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { localStorageAccessible, hasLocalStorage, hasSessionStorage } from '../src/detectors'; + +describe('Detectors', () => { + it('Checks for local storage accessibility', () => { + const result = localStorageAccessible(); + expect(result).toBeTruthy(); + }); + + it('Checks for local storage', () => { + const result = hasLocalStorage(); + expect(result).toBeTruthy(); + }); + + it('Checks for session storage', () => { + const result = hasSessionStorage(); + expect(result).toBeTruthy(); + }); +}); diff --git a/libraries/browser-tracker-core/test/dom_helpers.test.ts b/libraries/browser-tracker-core/test/dom_helpers.test.ts new file mode 100644 index 000000000..eec401c65 --- /dev/null +++ b/libraries/browser-tracker-core/test/dom_helpers.test.ts @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { JSDOM } from 'jsdom'; +import { fixupTitle, getHostName, getReferrer, addEventListener } from '../src/helpers'; + +declare var jsdom: JSDOM; + +describe('Helpers', () => { + beforeAll(() => { + document.head.innerHTML = 'Helpers test page'; + document.body.innerHTML = '

Click here

'; + }); + + it('Gets page title from document', () => { + const title = fixupTitle({ text: '' }); + expect(title).toBe('Helpers test page'); + }); + + it('Prefers page title from parameter', () => { + const title = fixupTitle('Title param'); + expect(title).toBe('Title param'); + }); + + it('Prefers page title from object parameter', () => { + document.head.innerHTML = ''; + const title = fixupTitle({ text: 'Title param 2' }); + expect(title).toBe('Title param 2'); + }); + + it('Gets host name', () => { + const hostName = getHostName(location.href); + expect(hostName).toBe('snowplow-js-tracker.local'); + }); + + it('Gets referrer from document', () => { + const referer = getReferrer(); + expect(referer).toBe('https://example.com/'); // From jest.config.js + }); + + it('Gets referrer from querystring', () => { + jsdom.reconfigure({ + url: window.location.href + '?name=value&referrer=previous#fragment', + }); + const referer = getReferrer(); + expect(referer).toBe('previous'); + }); + + it('Can add an event listener', (done) => { + const element = document.getElementById('click'); + if (element !== null) { + addEventListener(element, 'click', function () { + done(); + }); + + var evt = new Event('click', { bubbles: false, cancelable: false, composed: false }); + element.dispatchEvent(evt); + } + }); +}); diff --git a/libraries/browser-tracker-core/test/helpers.test.ts b/libraries/browser-tracker-core/test/helpers.test.ts new file mode 100644 index 000000000..ecd8cdfbd --- /dev/null +++ b/libraries/browser-tracker-core/test/helpers.test.ts @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { + cookie, + decorateQuerystring, + deleteCookie, + findRootDomain, + getCookiesWithPrefix, + getCssClasses, +} from '../src/helpers'; + +describe('decorateQuerystring', () => { + it('Decorate a URL with no querystring or fragment', () => { + const url = 'http://www.example.com'; + const expected = 'http://www.example.com?_sp=a.b'; + const actual = decorateQuerystring(url, '_sp', 'a.b'); + expect(actual).toEqual(expected); + }); + + it('Decorate a URL with a fragment but no querystring', () => { + const url = 'http://www.example.com#fragment'; + const expected = 'http://www.example.com?_sp=a.b#fragment'; + const actual = decorateQuerystring(url, '_sp', 'a.b'); + expect(actual).toEqual(expected); + }); + + it('Decorate a URL with an empty querystring', () => { + const url = 'http://www.example.com?'; + const expected = 'http://www.example.com?_sp=a.b'; + const actual = decorateQuerystring(url, '_sp', 'a.b'); + expect(actual).toEqual(expected); + }); + + it('Decorate a URL with a nonempty querystring', () => { + const url = 'http://www.example.com?name=value'; + const expected = 'http://www.example.com?_sp=a.b&name=value'; + const actual = decorateQuerystring(url, '_sp', 'a.b'); + expect(actual).toEqual(expected); + }); + + it('Override an existing field', () => { + const url = 'http://www.example.com?_sp=outdated'; + const expected = 'http://www.example.com?_sp=a.b'; + const actual = decorateQuerystring(url, '_sp', 'a.b'); + expect(actual).toEqual(expected); + }); + + it('Decorate a URL whose querystring contains multiple question marks', () => { + const url = 'http://www.example.com?test=working?&name=value'; + const expected = 'http://www.example.com?_sp=a.b&test=working?&name=value'; + const actual = decorateQuerystring(url, '_sp', 'a.b'); + expect(actual).toEqual(expected); + }); + + it('Override a field in a querystring containing a question mark', () => { + const url = 'http://www.example.com?test=working?&_sp=outdated'; + const expected = 'http://www.example.com?test=working?&_sp=a.b'; + const actual = decorateQuerystring(url, '_sp', 'a.b'); + expect(actual).toEqual(expected); + }); + + it('Decorate a querystring with multiple ?s and #s', () => { + const url = 'http://www.example.com?test=working?&_sp=outdated?&?name=value#fragment?#?#'; + const expected = 'http://www.example.com?test=working?&_sp=a.b&?name=value#fragment?#?#'; + const actual = decorateQuerystring(url, '_sp', 'a.b'); + expect(actual).toEqual(expected); + }); +}); + +describe('getCssClasses', () => { + it("Tokenize a DOM element's className field", () => { + const element = { + className: ' the quick brown_fox-jumps/over\nthe\t\tlazy dog ', + } as Element; + const expected = ['the', 'quick', 'brown_fox-jumps/over', 'the', 'lazy', 'dog']; + const actual = getCssClasses(element); + expect(actual).toEqual(expected); + }); +}); + +describe('cookie helpers', () => { + let cookieJar: string; + + beforeAll(() => { + cookieJar = ''; + jest.spyOn(document, 'cookie', 'set').mockImplementation((cookieValue) => { + // disallow TLD('com') cookie domains + const isRootCookie = cookieValue.match(/Domain=([^.]+?);/); + if (isRootCookie) { + return; + } + + const cookies = cookieJar.split(' '); + const cookieName = cookieValue.split('=').shift(); + //@ts-ignore + const cookieNameLength = cookieName.length; + let cookieIndex = -1; + cookies.forEach((value, index) => { + if (`${value.substr(0, cookieNameLength)}=` === `${cookieName}=`) { + cookieIndex = index; + } + }); + if (cookieIndex > -1) { + cookies[cookieIndex] = `${cookieValue};`; + } else { + cookies.push(`${cookieValue};`); + } + cookieJar = cookies.join(' ').slice(0, -1).trim(); + }); + jest.spyOn(document, 'cookie', 'get').mockImplementation(() => cookieJar); + }); + + afterEach(() => { + cookieJar = ''; + }); + + afterAll(() => { + jest.clearAllMocks(); + }); + + it('getCookiesWithPrefix', () => { + // Random cookie value from a snowplow initialization + const gaCookie = '_ga=GA1.2.XXX.YYY'; + const spIdCookie = + '_sp_id.83fc=e8be487a-01f2-4355-9f54-a0b0a9eb25a4.1673957921.1.1673959786..65134acc-3374-4efb-bf6f-dc891e804248..df52bd6b-14d5-475e-977a-082f27ff54a0.1673957921210.38'; + document.cookie = `${gaCookie}; ${spIdCookie}`; + const snowplowPrefixedCookies = getCookiesWithPrefix('_sp'); + expect(snowplowPrefixedCookies).toEqual(expect.not.arrayContaining([gaCookie])); + expect(snowplowPrefixedCookies).toEqual(expect.arrayContaining([spIdCookie])); + }); + + it('reads cookie using cookie with single argument', () => { + const gaCookie = '_ga=GA1.2.XXX.YYY'; + document.cookie = `${gaCookie}`; + expect(cookie('_ga')).toEqual('GA1.2.XXX.YYY'); + }); + + it('sets cookie using cookie with multiple arguments', () => { + expect(document.cookie).toEqual(''); + cookie('_ga', 'GA1.2.XXX.YYY'); + expect(document.cookie).toEqual('_ga=GA1.2.XXX.YYY'); + }); + + it('deleteCookie', () => { + const gaCookie = '_ga=GA1.2.XXX.YYY'; + document.cookie = `${gaCookie}`; + deleteCookie('_ga'); + // Value is deleted + expect(document.cookie).toMatch('_ga=;'); + }); + + describe('findRootDomain', () => { + let location: Location; + + beforeAll(() => { + location = window.location; + }); + + afterEach(() => { + window.location = location; + }); + + it('findRootDomain https://www.example.com', () => { + const url = 'https://www.example.com'; + const mockLocation = new URL(url); + // @ts-expect-error + delete window.location; + // @ts-expect-error + window.location = mockLocation; + + const domain = findRootDomain('Strict', true); + expect(domain).toEqual('example.com'); + + window.location = location; + }); + + it('findRootDomain https://sub.example.com', () => { + const url = 'https://sub.example.com'; + const mockLocation = new URL(url); + // @ts-expect-error + delete window.location; + // @ts-expect-error + window.location = mockLocation; + + const domain = findRootDomain('Strict', true); + expect(domain).toEqual('example.com'); + + window.location = location; + }); + }); +}); diff --git a/libraries/browser-tracker-core/test/helpers/index.ts b/libraries/browser-tracker-core/test/helpers/index.ts new file mode 100644 index 000000000..e59a175b0 --- /dev/null +++ b/libraries/browser-tracker-core/test/helpers/index.ts @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { TrackerConfiguration, addTracker, SharedState } from '../../src'; + +// Default Domain alias is snowplow-js-tracker.local & configCookiepath is / +const DEFAULT_DOMAIN_HASH = '7f01'; + +interface CreateTestIdCookie { + domainHash: string; + domainUserId: string; + createTs: number; + visitCount: number; + nowTs: number; + lastVisitTs: number; + sessionId: string; +} +/** + * Create a sp_id (id) cookie for testing purposes. + */ +export function createTestIdCookie(params: Partial) { + const now = Date.now(); + const DEFAULT_PARAMS: CreateTestIdCookie = { + domainHash: DEFAULT_DOMAIN_HASH, + domainUserId: '', + createTs: now, + visitCount: 1, + nowTs: now, + lastVisitTs: now, + sessionId: '', + }; + const cookieParams = { ...DEFAULT_PARAMS, ...params }; + const { domainHash } = cookieParams; + // @ts-expect-error + delete cookieParams.domainHash; + return `_sp_id.${domainHash}=${Object.values(cookieParams).join('.')}; Expires=; Path=/; SameSite=Lax; Secure;`; +} + +interface CreateTestSessionIdCookie { + domainHash: string; +} + +/** + * Create a sp_ses (session) cookie for testing purposes. + */ +export function createTestSessionIdCookie(params?: CreateTestSessionIdCookie) { + const domainHash = DEFAULT_DOMAIN_HASH || params?.domainHash; + return `_sp_ses.${domainHash}=*; Expires=; Path=/; SameSite=Lax; Secure;`; +} + +export function createTracker( + configuration?: TrackerConfiguration, + sharedState?: SharedState, + syncCookieWrite: boolean = true +) { + let id = 'sp-' + Math.random(); + configuration = { ...configuration, synchronousCookieWrite: syncCookieWrite }; + return addTracker(id, id, '', '', sharedState ?? new SharedState(), configuration); +} diff --git a/libraries/browser-tracker-core/test/helpers/sha1.test.ts b/libraries/browser-tracker-core/test/helpers/sha1.test.ts new file mode 100644 index 000000000..291ee99a5 --- /dev/null +++ b/libraries/browser-tracker-core/test/helpers/sha1.test.ts @@ -0,0 +1,37 @@ +import { sha1 } from '../../src/helpers/sha1'; + +describe('sha1', () => { + // RFC 3174 test vectors + test('empty string', () => { + expect(sha1('')).toBe('da39a3ee5e6b4b0d3255bfef95601890afd80709'); + }); + + test('"abc"', () => { + expect(sha1('abc')).toBe('a9993e364706816aba3e25717850c26c9cd0d89d'); + }); + + test('"The quick brown fox jumps over the lazy dog"', () => { + expect(sha1('The quick brown fox jumps over the lazy dog')).toBe('2fd4e1c67a2d28fced849ee1bb76e7391b93eb12'); + }); + + test('multi-block message', () => { + expect(sha1('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')).toBe( + '84983e441c3bd26ebaae4aa1f95129e5e54670f1' + ); + }); + + // Domain hash use case — must match output of sha1 npm package v1.1.1 + test('domain hash: "example.com/"', () => { + expect(sha1('example.com/')).toBe('880970443b82bdca0439e34c62e6c667277c2b39'); + expect(sha1('example.com/').slice(0, 4)).toBe('8809'); + }); + + test('domain hash: "localhost/"', () => { + expect(sha1('localhost/')).toBe('1fffd42e9a20211889ebfae87a84665b392c19a4'); + expect(sha1('localhost/').slice(0, 4)).toBe('1fff'); + }); + + test('returns 40-char lowercase hex string', () => { + expect(sha1('anything')).toMatch(/^[0-9a-f]{40}$/); + }); +}); diff --git a/libraries/browser-tracker-core/test/id_cookie.test.ts b/libraries/browser-tracker-core/test/id_cookie.test.ts new file mode 100644 index 000000000..0638f4b50 --- /dev/null +++ b/libraries/browser-tracker-core/test/id_cookie.test.ts @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import * as uuid from 'uuid'; +jest.mock('uuid'); +const MOCK_UUID = '123456789'; +(jest.spyOn(uuid, 'v4') as jest.SpyInstance).mockReturnValue(MOCK_UUID); + +import { payloadBuilder } from '@snowplow/tracker-core'; +import { + clientSessionFromIdCookie, + cookiesEnabledInIdCookie, + createTsFromIdCookie, + domainUserIdFromIdCookie, + eventIndexFromIdCookie, + firstEventIdFromIdCookie, + firstEventTsInMsFromIdCookie, + incrementEventIndexInIdCookie, + initializeDomainUserId, + lastVisitTsFromIdCookie, + nowTsFromIdCookie, + parseIdCookie, + previousSessionIdFromIdCookie, + serializeIdCookie, + sessionIdFromIdCookie, + startNewIdCookieSession, + updateFirstEventInIdCookie, + updateNowTsInIdCookie, + visitCountFromIdCookie, +} from '../src/tracker/id_cookie'; + +describe('parseIdCookie', () => { + it('Initializes a new ID cookie using memorized values given empty string', () => { + let before = Math.round(new Date().getTime() / 1000); + let idCookie = parseIdCookie('', 'xyz', 'ses', 10); + let after = Math.round(new Date().getTime() / 1000); + + expect(cookiesEnabledInIdCookie(idCookie)).not.toBeTruthy(); + expect(domainUserIdFromIdCookie(idCookie)).toBe('xyz'); + expect(sessionIdFromIdCookie(idCookie)).toBe('ses'); + expect(visitCountFromIdCookie(idCookie)).toBe(10); + expect(previousSessionIdFromIdCookie(idCookie)).toBeFalsy(); + expect(createTsFromIdCookie(idCookie)).toBeGreaterThanOrEqual(before); + expect(createTsFromIdCookie(idCookie)).toBeLessThanOrEqual(after); + expect(nowTsFromIdCookie(idCookie)).toBeGreaterThanOrEqual(before); + expect(nowTsFromIdCookie(idCookie)).toBeLessThanOrEqual(after); + expect(lastVisitTsFromIdCookie(idCookie)).toBeUndefined(); + expect(firstEventIdFromIdCookie(idCookie)).toBe(''); + expect(firstEventTsInMsFromIdCookie(idCookie)).toBeUndefined(); + expect(eventIndexFromIdCookie(idCookie)).toBe(0); + }); + + it('Initializes from a partial version of the cookie', () => { + let ts = Math.round(new Date().getTime() / 1000); + let idCookie = parseIdCookie(`abc.${ts}.10.${ts + 10}.${ts - 10}`, '', '', 0); + + expect(domainUserIdFromIdCookie(idCookie)).toBe('abc'); + expect(visitCountFromIdCookie(idCookie)).toBe(10); + expect(nowTsFromIdCookie(idCookie)).toBe(ts + 10); + expect(lastVisitTsFromIdCookie(idCookie)).toBe(ts - 10); + expect(sessionIdFromIdCookie(idCookie)).toBeTruthy(); + expect(createTsFromIdCookie(idCookie)).toBe(ts); + expect(firstEventIdFromIdCookie(idCookie)).toBe(''); + expect(firstEventTsInMsFromIdCookie(idCookie)).toBeUndefined(); + expect(eventIndexFromIdCookie(idCookie)).toBe(0); + }); + + it('Initializes from a partial version of the cookie including session id', () => { + let ts = Math.round(new Date().getTime() / 1000); + let idCookie = parseIdCookie(`abc.${ts}.10.${ts + 10}.${ts - 10}.ses`, '', '', 0); + + expect(sessionIdFromIdCookie(idCookie)).toBe('ses'); + }); + + it('Initializes from a complete cookie', () => { + let idCookie = parseIdCookie(`def.1653632272.10.1653632282.1653632262.ses.previous.fid.1653632252.9`, '', '', 0); + + expect(domainUserIdFromIdCookie(idCookie)).toBe('def'); + expect(visitCountFromIdCookie(idCookie)).toBe(10); + expect(sessionIdFromIdCookie(idCookie)).toBe('ses'); + expect(previousSessionIdFromIdCookie(idCookie)).toBe('previous'); + expect(firstEventIdFromIdCookie(idCookie)).toBe('fid'); + expect(firstEventTsInMsFromIdCookie(idCookie)).toBe(1653632252); + expect(eventIndexFromIdCookie(idCookie)).toBe(9); + }); +}); + +describe('initializeDomainUserId', () => { + it('Uses existing ID if present', () => { + let idCookie = parseIdCookie(`abc.1653632272.10.1653632272.1653632272`, '', '', 0); + + let duidAnonymous = initializeDomainUserId(idCookie, true); + expect(duidAnonymous).toBe('abc'); + + let duidNonAnonymous = initializeDomainUserId(idCookie, false); + expect(duidNonAnonymous).toBe('abc'); + }); + + it('Generates a new ID', () => { + let duid = initializeDomainUserId(parseIdCookie('', '', '', 0), false); + + expect(duid).toBeTruthy(); + }); + + it('Is empty in case of anonymous tracking', () => { + let duid = initializeDomainUserId(parseIdCookie('', '', '', 0), true); + + expect(duid).toBeFalsy(); + }); +}); + +describe('startNewIdCookieSession', () => { + it('Resets the first event references and event index', () => { + let idCookie = parseIdCookie('def.1653632272.10.1653632282.1653632262.ses.previous.fid.1653632252.9', '', '', 0); + startNewIdCookieSession(idCookie); + + expect(firstEventIdFromIdCookie(idCookie)).toBeFalsy(); + expect(firstEventTsInMsFromIdCookie(idCookie)).toBeUndefined(); + expect(eventIndexFromIdCookie(idCookie)).toBe(0); + }); + + it('Increments the visit count', () => { + let idCookie = parseIdCookie('def.1653632272.10.1653632282.1653632262', '', '', 0); + + expect(visitCountFromIdCookie(idCookie)).toBe(10); + startNewIdCookieSession(idCookie); + expect(visitCountFromIdCookie(idCookie)).toBe(11); + }); + + it('Uses the passed visit count in case of disabled cookies', () => { + let idCookie = parseIdCookie('', '', '', 0); + startNewIdCookieSession(idCookie, { memorizedVisitCount: 100 }); + expect(visitCountFromIdCookie(idCookie)).toBe(100); + }); + + it("Doesn't set the last visit timestamp if disabled cookies and keeps now timestamp", () => { + let idCookie = parseIdCookie('', '', '', 0); + let nowTs = nowTsFromIdCookie(idCookie); + startNewIdCookieSession(idCookie); + expect(lastVisitTsFromIdCookie(idCookie)).toBeUndefined(); + expect(nowTsFromIdCookie(idCookie)).toBe(nowTs); + }); + + it('Generates a new session ID', () => { + let idCookie = parseIdCookie('def.1653632272.10.1653632282.1653632262', '', '', 0); + + let before = sessionIdFromIdCookie(idCookie); + + (jest.spyOn(uuid, 'v4') as jest.SpyInstance).mockReturnValueOnce('another_random_uuid'); + startNewIdCookieSession(idCookie); + let after = sessionIdFromIdCookie(idCookie); + + expect(before).not.toBe(after); + }); + + it('Moves current visit to last visit timestamp', () => { + let idCookie = parseIdCookie(`def.1653632100.10.1653632200.1653632300`, '', '', 0); + + startNewIdCookieSession(idCookie); + expect(lastVisitTsFromIdCookie(idCookie)).toBe(1653632200); + }); + + it('Sets the previous session ID', () => { + let idCookie = parseIdCookie('def.1653632100.10.1653632200.1653632300.ses', '', '', 0); + + startNewIdCookieSession(idCookie); + expect(previousSessionIdFromIdCookie(idCookie)).toBe('ses'); + }); +}); + +describe('updateNowTsInIdCookie', () => { + it('Sets the timestamp to current time', () => { + let idCookie = parseIdCookie('def.1653632100.10.1653632200.1653632300.ses', '', '', 0); + + let before = Math.round(new Date().getTime() / 1000); + updateNowTsInIdCookie(idCookie); + let after = Math.round(new Date().getTime() / 1000); + + expect(nowTsFromIdCookie(idCookie)).toBeGreaterThanOrEqual(before); + expect(nowTsFromIdCookie(idCookie)).toBeLessThanOrEqual(after); + }); +}); + +describe('updateFirstEventInIdCookie', () => { + it('Sets the first event references if first event in session', () => { + let pb = payloadBuilder(); + let timestamp = new Date().getTime(); + pb.add('eid', 'xyz'); + pb.add('dtm', timestamp); + + let idCookie = parseIdCookie('', '', '', 0); + updateFirstEventInIdCookie(idCookie, pb); + + expect(firstEventIdFromIdCookie(idCookie)).toBe('xyz'); + expect(firstEventTsInMsFromIdCookie(idCookie)).toBe(timestamp); + }); + + it('Sets the first event timestamp from true timestamp if device timestamp not available', () => { + let pb = payloadBuilder(); + let timestamp = new Date().getTime(); + pb.add('eid', 'xyz'); + pb.add('ttm', timestamp); + + let idCookie = parseIdCookie('', '', '', 0); + updateFirstEventInIdCookie(idCookie, pb); + + expect(firstEventTsInMsFromIdCookie(idCookie)).toBe(timestamp); + }); + + it("Doesn't change first event references if not first event in session", () => { + let idCookie = parseIdCookie('def.1653632272.10.1653632282.1653632262.ses.previous.fid.1653632252.9', '', '', 0); + + let pb = payloadBuilder(); + pb.add('eid', 'xyz'); + pb.add('dtm', new Date().getTime()); + + updateFirstEventInIdCookie(idCookie, pb); + + expect(firstEventIdFromIdCookie(idCookie)).toBe('fid'); + expect(firstEventTsInMsFromIdCookie(idCookie)).toBe(1653632252); + }); +}); + +describe('incrementEventIndexInIdCookie', () => { + it('Increments the event index', () => { + let idCookie = parseIdCookie('', '', '', 0); + expect(eventIndexFromIdCookie(idCookie)).toBe(0); + incrementEventIndexInIdCookie(idCookie); + expect(eventIndexFromIdCookie(idCookie)).toBe(1); + incrementEventIndexInIdCookie(idCookie); + expect(eventIndexFromIdCookie(idCookie)).toBe(2); + }); +}); + +describe('serializeIdCookie', () => { + it("Doesn't change the original cookie", () => { + let cookie = `def.1653632272.10.1653632282.1653632262.ses.previous.fid.1653632252.9`; + expect(serializeIdCookie(parseIdCookie(cookie, '', '', 0), false)).toBe(cookie); + }); + + it("Doesn't include domain user ID and previous session ID in case of anonymous tracking", () => { + let idCookie = parseIdCookie('def.1653632272.10.1653632282.1653632262.ses.previous.fid.1653632252.9', '', '', 0); + expect(serializeIdCookie(idCookie, true)).toBe('.1653632272.10.1653632282.1653632262.ses..fid.1653632252.9'); + }); +}); + +describe('clientSessionFromIdCookie', () => { + it('Correctly fills out the properties', () => { + let idCookie = parseIdCookie('def.1653632272.10.1653632282.1653632262.ses.previous.fid.1653638673483.9', '', '', 0); + let clientSession = clientSessionFromIdCookie(idCookie, 'cookieAndLocalStorage', false); + + expect(clientSession.userId).toBe('def'); + expect(clientSession.sessionId).toBe('ses'); + expect(clientSession.previousSessionId).toBe('previous'); + expect(clientSession.eventIndex).toBe(9); + expect(clientSession.sessionIndex).toBe(10); + expect(clientSession.storageMechanism).toBe('COOKIE_1'); + expect(clientSession.firstEventId).toBe('fid'); + expect(clientSession.firstEventTimestamp).toBe('2022-05-27T08:04:33.483Z'); + }); + + it('Anonymises userId and previousSessionId when anonymous tracking', () => { + let idCookie = parseIdCookie('def.1653632272.10.1653632282.1653632262.ses.previous.fid.1653638673483.9', '', '', 0); + let clientSession = clientSessionFromIdCookie(idCookie, 'cookieAndLocalStorage', true); + + expect(clientSession.userId).toBe('00000000-0000-0000-0000-000000000000'); + expect(clientSession.sessionId).toBe('ses'); + expect(clientSession.previousSessionId).toBeNull; + expect(clientSession.eventIndex).toBe(9); + expect(clientSession.sessionIndex).toBe(10); + expect(clientSession.storageMechanism).toBe('COOKIE_1'); + expect(clientSession.firstEventId).toBe('fid'); + expect(clientSession.firstEventTimestamp).toBe('2022-05-27T08:04:33.483Z'); + }); +}); diff --git a/libraries/browser-tracker-core/test/out_queue.test.ts b/libraries/browser-tracker-core/test/out_queue.test.ts new file mode 100644 index 000000000..dfc2081ae --- /dev/null +++ b/libraries/browser-tracker-core/test/out_queue.test.ts @@ -0,0 +1,576 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { newOutQueue, OutQueue } from '../src/tracker/out_queue'; +import { SharedState } from '../src/state'; +import { EventStore, newInMemoryEventStore, EventBatch, RequestFailure } from '@snowplow/tracker-core'; + +function newMockEventStore({ maxSize }: { maxSize: number }): EventStore & { addCount: () => number } { + let eventStore = newInMemoryEventStore({ maxSize }); + let addCount = 0; + + return { + add: (payload) => { + addCount++; + return eventStore.add(payload); + }, + removeHead: eventStore.removeHead, + count: eventStore.count, + iterator: eventStore.iterator, + getAll: eventStore.getAll, + getAllPayloads: eventStore.getAllPayloads, + addCount: () => addCount, + }; +} + +describe('OutQueueManager', () => { + const maxQueueSize = 2; + + let eventStore: EventStore & { addCount: () => number }; + let responseStatusCode: number; + let requests: Request[]; + const customFetch = async (request: Request) => { + requests.push(request); + return new Response(null, { status: responseStatusCode }); + }; + + beforeEach(() => { + requests = []; + responseStatusCode = 200; + eventStore = newMockEventStore({ maxSize: maxQueueSize }); + }); + + describe('POST requests', () => { + let outQueue: OutQueue; + + beforeEach(() => { + outQueue = newOutQueue( + { + endpoint: 'http://example.com', + trackerId: 'sp', + useStm: false, + retryStatusCodes: [401], // retry status codes - override don't retry ones + dontRetryStatusCodes: [401, 505], // don't retry status codes + eventStore, + customFetch, + }, + new SharedState() + ); + }); + + it('should add event to outQueue and store event in local storage', async () => { + const expected = { e: 'pv', eid: '20269f92-f07c-44a6-87ef-43e171305076' }; + outQueue.setBufferSize(5); + await outQueue.enqueueRequest(expected); + + expect(await eventStore.count()).toEqual(1); + const events = await eventStore.getAllPayloads(); + expect(events[0]).toMatchObject(expected); + }); + + it('should add event to outQueue and store only events up to max local storage queue size in local storage', async () => { + const expected1 = { e: 'pv', eid: '65cb78de-470c-4764-8c10-02bd79477a3a' }; + const expected2 = { e: 'pv', eid: '6000c7bd-08a6-49c2-b61c-9531d3d46200' }; + const unexpected = { e: 'pv', eid: '7a3391a8-622b-4ce4-80ed-c941aa05baf5' }; + + outQueue.setBufferSize(5); + await outQueue.enqueueRequest(unexpected); + await outQueue.enqueueRequest(expected1); + await outQueue.enqueueRequest(expected2); + + expect(await eventStore.count()).toEqual(maxQueueSize); + const events = await eventStore.getAllPayloads(); + expect(events[0]).toMatchObject(expected1); + expect(events[1]).toMatchObject(expected2); + }); + + it('should remove events from event queue on success', async () => { + const request = { e: 'pv', eid: '65cb78de-470c-4764-8c10-02bd79477a3a' }; + await outQueue.enqueueRequest(request); + + expect(await eventStore.count()).toEqual(0); + expect(requests).toHaveLength(1); + }); + + it('should keep events in queue on failure', async () => { + const request = { e: 'pv', eid: '65cb78de-470c-4764-8c10-02bd79477a3a' }; + responseStatusCode = 500; + await outQueue.enqueueRequest(request); + + expect(await eventStore.count()).toEqual(1); + expect(requests).toHaveLength(1); + }); + + it('should retry on custom retry status code', async () => { + const request = { e: 'pv', eid: '65cb78de-470c-4764-8c10-02bd79477a3a' }; + responseStatusCode = 401; + await outQueue.enqueueRequest(request); + + expect(requests).toHaveLength(1); + expect(await eventStore.count()).toEqual(1); + }); + + it("should not retry on custom don't retry status code", async () => { + const request = { e: 'pv', eid: '65cb78de-470c-4764-8c10-02bd79477a3a' }; + responseStatusCode = 505; + await outQueue.enqueueRequest(request); + + expect(requests).toHaveLength(1); + expect(await eventStore.count()).toEqual(0); + }); + }); + + describe('GET requests', () => { + let getOutQueue: (maxGetBytes?: number) => OutQueue; + + beforeEach(() => { + getOutQueue = (maxGetBytes) => + newOutQueue( + { + endpoint: 'http://example.com', + trackerId: 'sp', + eventMethod: 'get', + maxGetBytes, + useStm: false, + maxLocalStorageQueueSize: maxQueueSize, + eventStore, + customFetch, + }, + new SharedState() + ); + }); + + it('should add large event to out queue without bytes limit', async () => { + let outQueue = getOutQueue(undefined); + + const expected = { e: 'pv', eid: '20269f92-f07c-44a6-87ef-43e171305076', aid: 'x'.repeat(1000) }; + await outQueue.enqueueRequest(expected); + + expect(eventStore.addCount()).toEqual(1); + expect(await eventStore.count()).toEqual(0); + expect(requests).toHaveLength(1); + }); + + it('should not add event larger than max bytes limit to queue but should try to send it as POST', async () => { + let outQueue = getOutQueue(100); + const consoleWarn = jest.fn(); + global.console.warn = consoleWarn; + + const expected = { e: 'pv', eid: '20269f92-f07c-44a6-87ef-43e171305076', aid: 'x'.repeat(1000) }; + outQueue.enqueueRequest(expected); + + expect(eventStore.addCount()).toEqual(0); + expect(await eventStore.count()).toEqual(0); + expect(consoleWarn.mock.calls.length).toEqual(1); // should log a warning message + expect(requests).toHaveLength(1); + }); + }); + + describe('cookieExtensionService requests', () => { + const cookieExtensionServiceEndpoint = 'http://example.com/id'; + + const getQuerystring = (p: object) => + '?' + + Object.entries(p) + .map(([k, v]) => k + '=' + encodeURIComponent(v)) + .join('&'); + + describe('GET requests', () => { + let createGetQueue = () => + newOutQueue( + { + endpoint: 'http://example.com', + trackerId: 'sp', + eventMethod: 'get', + useStm: false, + maxLocalStorageQueueSize: maxQueueSize, + eventStore, + customFetch, + cookieExtensionService: cookieExtensionServiceEndpoint, + }, + new SharedState() + ); + + it('should first execute the cookieExtensionService request and in the same `enqueueRequest` the tracking request', async () => { + const request = { e: 'pv', eid: '65cb78de-470c-4764-8c10-02bd79477a3a' }; + const getQueue = createGetQueue(); + + await getQueue.enqueueRequest(request); + + expect(requests).toHaveLength(2); + expect(requests[0].url).toEqual(cookieExtensionServiceEndpoint); + expect(requests[1].url).toEqual('http://example.com/i' + getQuerystring(request)); + }); + + it('should first execute the cookieExtensionService request and in the same `enqueueRequest` the tracking request irregardless of failure of the cookieExtensionService endpoint', async () => { + const request = { e: 'pv', eid: '65cb78de-470c-4764-8c10-02bd79477a3a' }; + const getQueue = createGetQueue(); + + responseStatusCode = 500; + await getQueue.enqueueRequest(request); + + expect(requests).toHaveLength(2); + expect(requests[0].url).toEqual(cookieExtensionServiceEndpoint); + expect(requests[1].url).toEqual('http://example.com/i' + getQuerystring(request)); + expect(await eventStore.count()).toEqual(1); + }); + }); + + describe('POST requests', () => { + let createPostQueue = () => + newOutQueue( + { + endpoint: 'http://example.com', + trackerId: 'sp', + eventMethod: 'post', + eventStore, + customFetch, + cookieExtensionService: cookieExtensionServiceEndpoint, + }, + new SharedState() + ); + + it('should first execute the cookieExtensionService request and in the same `enqueueRequest` the tracking request irregardless of failure of the cookieExtensionService endpoint', async () => { + const request = { e: 'pv', eid: '65cb78de-470c-4764-8c10-02bd79477a3a' }; + const postQueue = createPostQueue(); + + await postQueue.enqueueRequest(request); + + expect(requests).toHaveLength(2); + expect(requests[0].url).toEqual(cookieExtensionServiceEndpoint); + expect(requests[1].url).toEqual('http://example.com/com.snowplowanalytics.snowplow/tp2'); + }); + }); + }); + + describe('retryFailures = true', () => { + const request = { e: 'pv', eid: '65cb78de-470c-4764-8c10-02bd79477a3a' }; + let createOutQueue = () => + newOutQueue( + { + endpoint: 'http://example.com', + trackerId: 'sp', + eventMethod: 'post', + retryFailedRequests: true, + eventStore, + customFetch, + }, + new SharedState() + ); + + it('should remain in queue on failure', async () => { + let outQueue = createOutQueue(); + responseStatusCode = 500; + await outQueue.enqueueRequest(request); + + expect(requests).toHaveLength(1); + expect(await eventStore.count()).toEqual(1); + }); + }); + + describe('retryFailures = false', () => { + const request = { e: 'pv', eid: '65cb78de-470c-4764-8c10-02bd79477a3a' }; + let createOutQueue = () => + newOutQueue( + { + endpoint: 'http://example.com', + trackerId: 'sp', + eventMethod: 'post', + retryFailedRequests: false, + eventStore, + customFetch, + }, + new SharedState() + ); + + it('should remove from queue on failure', async () => { + let outQueue = createOutQueue(); + responseStatusCode = 500; + await outQueue.enqueueRequest(request); + + expect(requests).toHaveLength(1); + expect(await eventStore.count()).toEqual(0); + }); + }); + + type createQueueArgs = { + method: 'get' | 'post'; + onSuccess?: (data: EventBatch) => void; + onFailure?: (data: RequestFailure) => void; + maxPostBytes?: number; + maxGetBytes?: number; + }; + + const createQueue = (args: createQueueArgs) => + newOutQueue( + { + endpoint: 'http://example.com', + trackerId: 'sp', + eventMethod: args.method, + maxPostBytes: args.maxPostBytes, + maxGetBytes: args.maxGetBytes, + maxLocalStorageQueueSize: maxQueueSize, + onRequestSuccess: args.onSuccess, + onRequestFailure: args.onFailure, + customFetch, + eventStore, + }, + new SharedState() + ); + + describe('onRequestSuccess', () => { + const request = { e: 'pv', eid: '65cb78de-470c-4764-8c10-02bd79477a3a' }; + + describe('POST requests', () => { + const method = 'post'; + + it('should fire on a successful request', async () => { + const callbacks: EventBatch[] = []; + + await new Promise(async (resolve) => { + const onSuccess = (e: EventBatch) => { + callbacks.push(e); + resolve(null); + }; + + const postQueue = createQueue({ method, onSuccess }); + await postQueue.enqueueRequest(request); + }); + + expect(requests).toHaveLength(1); + expect(eventStore.addCount()).toEqual(1); + expect(callbacks).toHaveLength(1); + expect(callbacks[0]).toHaveLength(1); + + let dataFromCallback = callbacks[0][0]; + expect(dataFromCallback).toEqual(request); + }); + + // Oversized events don't get placed in the queue, but the callback should still fire + it('should fire on a successful oversized request', async () => { + const callbackStorage: EventBatch[] = []; + await new Promise(async (resolve) => { + const onSuccess = (e: EventBatch) => { + callbackStorage.push(e); + resolve(null); + }; + + const postQueue = createQueue({ method, onSuccess, maxPostBytes: 1 }); + await postQueue.enqueueRequest(request); + }); + + expect(requests).toHaveLength(1); + expect(eventStore.addCount()).toEqual(0); + let dataFromCallback = callbackStorage[0][0]; + expect(dataFromCallback).toEqual(request); + }); + }); + + describe('GET requests', () => { + const method = 'get'; + + it('should fire on a successful request', async () => { + let callbackStorage: EventBatch[] = []; + await new Promise(async (resolve) => { + const onSuccess = (e: EventBatch) => { + callbackStorage.push(e); + resolve(null); + }; + + const getQueue = createQueue({ method, onSuccess }); + await getQueue.enqueueRequest(request); + }); + + expect(requests).toHaveLength(1); + expect(eventStore.addCount()).toEqual(1); + expect(callbackStorage).toHaveLength(1); + expect(callbackStorage[0]).toHaveLength(1); + + let dataFromCallback = callbackStorage[0][0]; + expect(dataFromCallback).toEqual(request); + }); + + // A single oversized events means no queue, but the callback should still fire + it('should fire the onRequestSuccess on a successful oversized request', async () => { + let callbackStorage: EventBatch[] = []; + await new Promise(async (resolve) => { + const onSuccess = (e: EventBatch) => { + callbackStorage.push(e); + resolve(null); + }; + + const getQueue = createQueue({ method, onSuccess, maxGetBytes: 1 }); + await getQueue.enqueueRequest(request); + }); + + expect(requests).toHaveLength(1); + expect(eventStore.addCount()).toEqual(0); + expect(callbackStorage).toHaveLength(1); + expect(callbackStorage[0]).toHaveLength(1); + + let dataFromCallback = callbackStorage[0][0]; + expect(dataFromCallback).toEqual(request); + }); + }); + }); + + describe('onRequestFailure', () => { + const request = { e: 'pv', eid: '65cb78de-470c-4764-8c10-02bd79477a3a' }; + + const createQueue = (args: createQueueArgs) => + newOutQueue( + { + endpoint: 'http://example.com', + trackerId: 'sp', + eventMethod: args.method, + maxPostBytes: args.maxPostBytes, + maxGetBytes: args.maxGetBytes, + maxLocalStorageQueueSize: maxQueueSize, + onRequestSuccess: args.onSuccess, + onRequestFailure: args.onFailure, + dontRetryStatusCodes: [500], + customFetch, + eventStore, + }, + new SharedState() + ); + + describe('POST requests', () => { + const method = 'post'; + + it('should fire on a failed request', async () => { + const callbackStorage: RequestFailure[] = []; + await new Promise(async (resolve) => { + const onFailure = (e: RequestFailure) => { + callbackStorage.push(e); + resolve(null); + }; + + responseStatusCode = 500; + + const postQueue = createQueue({ method, onFailure }); + await postQueue.enqueueRequest(request); + }); + + expect(requests).toHaveLength(1); + expect(callbackStorage).toHaveLength(1); + expect(await eventStore.count()).toEqual(0); + + let dataFromCallback = callbackStorage[0] as RequestFailure; + + const event = dataFromCallback.events[0]; + expect(event).toEqual(request); + + expect(dataFromCallback.status).toEqual(500); + expect(dataFromCallback.willRetry).toEqual(false); + }); + + // A single oversized events means no queue, but the callback should still fire + it('should fire on a failed oversized request', async () => { + const callbackStorage: RequestFailure[] = []; + await new Promise(async (resolve) => { + const onFailure = (e: RequestFailure) => { + callbackStorage.push(e); + resolve(null); + }; + + responseStatusCode = 501; + + const postQueue = createQueue({ method, onFailure, maxPostBytes: 1 }); + await postQueue.enqueueRequest(request); + }); + + expect(requests).toHaveLength(1); + expect(callbackStorage).toHaveLength(1); + expect(eventStore.addCount()).toEqual(0); + expect(await eventStore.count()).toEqual(0); + + let dataFromCallback = callbackStorage[0].events[0]; + expect(dataFromCallback).toEqual(request); + expect(callbackStorage[0].status).toEqual(501); + }); + }); + + describe('GET requests', () => { + const method = 'get'; + + it('should fire on a failed request', async () => { + let callbackStorage: RequestFailure[] = []; + await new Promise(async (resolve) => { + const onFailure = (e: RequestFailure) => { + callbackStorage.push(e); + resolve(null); + }; + + responseStatusCode = 500; + + const getQueue = createQueue({ method, onFailure }); + await getQueue.enqueueRequest(request); + }); + + expect(requests).toHaveLength(1); + expect(callbackStorage).toHaveLength(1); + expect(await eventStore.count()).toEqual(0); + + let dataFromCallback = callbackStorage[0] as RequestFailure; + + expect(dataFromCallback.events[0]).toEqual(request); + expect(dataFromCallback.status).toEqual(500); + expect(dataFromCallback.willRetry).toEqual(false); + }); + + // A single oversized events means no queue, but the callback should still fire + it('should fire on a failed oversized request', async () => { + let callbackStorage: RequestFailure[] = []; + await new Promise(async (resolve) => { + const onFailure = (e: RequestFailure) => { + callbackStorage.push(e); + resolve(null); + }; + + responseStatusCode = 500; + + const getQueue = createQueue({ method, onFailure, maxGetBytes: 1 }); + await getQueue.enqueueRequest(request); + }); + + expect(requests).toHaveLength(1); + expect(callbackStorage).toHaveLength(1); + expect(eventStore.addCount()).toEqual(0); + + let dataFromCallback = callbackStorage[0]; + + expect(dataFromCallback.events[0]).toEqual(request); + expect(dataFromCallback.status).toEqual(500); + expect(dataFromCallback.willRetry).toEqual(false); + }); + }); + }); +}); diff --git a/libraries/browser-tracker-core/test/proxies.test.ts b/libraries/browser-tracker-core/test/proxies.test.ts new file mode 100644 index 000000000..77c0f4956 --- /dev/null +++ b/libraries/browser-tracker-core/test/proxies.test.ts @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { fixupUrl } from '../src/proxies'; + +describe('Proxies', () => { + beforeAll(() => { + document.body.innerHTML = '
You have reached the cached page for
'; + }); + + it('Host name is not a special case, Except in special cases, fixupUrl changes nothing', () => { + const expectedLocationArray = ['normalhostname', 'href', 'http://referrer.com']; + const fixedupLocationArray = fixupUrl('normalhostname', 'href', 'http://referrer.com'); + + for (let i = 0; i < 3; i++) { + expect(fixedupLocationArray[i]).toEqual(expectedLocationArray[i]); + } + }); + + it("Host name = 'translate.googleusercontent.com', Get the URL for the untranslated page from the querystring and make the translated page the referrer", () => { + const fixedupLocationArray = fixupUrl( + 'translate.googleusercontent.com', + 'http://translate.googleusercontent.com/translate?hl=en&sl=fr&u=http:www.francais.fr/path', + '' + ); + const expectedLocationArray = [ + 'www.francais.fr', + 'http:www.francais.fr/path', + 'http://translate.googleusercontent.com/translate?hl=en&sl=fr&u=http:www.francais.fr/path', + ]; + + for (let i = 0; i < 3; i++) { + expect(fixedupLocationArray[i]).toEqual(expectedLocationArray[i]); + } + }); + + it("Host name = 'ccj.bingj.com', On a page cached by Bing, get the original URL from the first link", () => { + const fixedupLocationArray = fixupUrl( + 'cc.bingj.com', + 'http://cc.bingj.com/cache.aspx?q=example.com&d=4870936571937837&mkt=en-GB&setlang=en-GB&w=QyOPD1fo3C2nC9sXMLmUUs81Jt78MYIp', + 'http://referrer.com' + ); + const expectedLocationArray = ['www.example.com', 'http://www.example.com/', 'http://referrer.com']; + + for (let i = 0; i < 3; i++) { + expect(fixedupLocationArray[i]).toEqual(expectedLocationArray[i]); + } + }); + + it("Host name = 'webcache.googleusercontent.com', On a page cached by Google, get the original URL from the first link", () => { + const fixedupLocationArray = fixupUrl( + 'webcache.googleusercontent.com', + 'http://webcache.googleusercontent.com/search?q=cache:http://example.com/#fragment', + 'http://referrer.com' + ); + const expectedLocationArray = ['www.example.com', 'http://www.example.com/', 'http://referrer.com']; + + for (let i = 0; i < 3; i++) { + expect(fixedupLocationArray[i]).toEqual(expectedLocationArray[i]); + } + }); +}); diff --git a/libraries/browser-tracker-core/test/storage.test.ts b/libraries/browser-tracker-core/test/storage.test.ts new file mode 100644 index 000000000..e20662b97 --- /dev/null +++ b/libraries/browser-tracker-core/test/storage.test.ts @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { attemptGetLocalStorage, attemptWriteLocalStorage } from '../src/helpers'; + +describe('local storage', () => { + beforeAll(() => { + localStorage.clear(); + }); + + it('should work for pre existing values with no expiry', () => { + const value = 'value'; + localStorage.setItem('key', value); + const retrieved = attemptGetLocalStorage('key'); + expect(retrieved).toBe(value); + }); + + it('should return values', () => { + const value = 'value'; + const ttl = 1; + attemptWriteLocalStorage('key', value, ttl); + const retrieved = attemptGetLocalStorage('key'); + expect(retrieved).toBe(value); + }); + + it('should not return expired values', () => { + const value = 'value'; + const ttl = -1; + attemptWriteLocalStorage('key', value, ttl); + const retrieved = attemptGetLocalStorage('key'); + expect(retrieved).toBeUndefined(); + }); +}); diff --git a/libraries/browser-tracker-core/test/tracker/__snapshots__/browser_context.test.ts.snap b/libraries/browser-tracker-core/test/tracker/__snapshots__/browser_context.test.ts.snap new file mode 100644 index 000000000..c30ef5537 --- /dev/null +++ b/libraries/browser-tracker-core/test/tracker/__snapshots__/browser_context.test.ts.snap @@ -0,0 +1,16 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Browser context: Adds the browser context entity when \`contexts: { browser: true }\` is passed 1`] = ` +Object { + "browserLanguage": "en-US", + "colorDepth": 24, + "cookiesEnabled": true, + "devicePixelRatio": 1, + "documentLanguage": "", + "documentSize": "0x0", + "hardwareConcurrency": 1, + "online": true, + "resolution": "0x0", + "viewport": "1024x768", +} +`; diff --git a/libraries/browser-tracker-core/test/tracker/__snapshots__/session_data.test.ts.snap b/libraries/browser-tracker-core/test/tracker/__snapshots__/session_data.test.ts.snap new file mode 100644 index 000000000..ea8714fe4 --- /dev/null +++ b/libraries/browser-tracker-core/test/tracker/__snapshots__/session_data.test.ts.snap @@ -0,0 +1,40 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Tracker API: onSessionUpdateCallback functionality properly calls onSessionUpdateCallback 1`] = ` +Object { + "eventIndex": 1, + "firstEventId": "123456789", + "firstEventTimestamp": "2023-01-01T00:00:00.000Z", + "previousSessionId": null, + "sessionId": "123456789", + "sessionIndex": 1, + "storageMechanism": "COOKIE_1", + "userId": "123456789", +} +`; + +exports[`Tracker API: onSessionUpdateCallback functionality properly calls onSessionUpdateCallback with anonymousTracking and withSessionTracking 1`] = ` +Object { + "eventIndex": 1, + "firstEventId": "123456789", + "firstEventTimestamp": "2023-01-01T00:00:00.000Z", + "previousSessionId": null, + "sessionId": "123456789", + "sessionIndex": 1, + "storageMechanism": "COOKIE_1", + "userId": "00000000-0000-0000-0000-000000000000", +} +`; + +exports[`Tracker API: onSessionUpdateCallback functionality properly calls onSessionUpdateCallback with correct storage strategy 1`] = ` +Object { + "eventIndex": 1, + "firstEventId": "123456789", + "firstEventTimestamp": "2023-01-01T00:00:00.000Z", + "previousSessionId": null, + "sessionId": "123456789", + "sessionIndex": 1, + "storageMechanism": "LOCAL_STORAGE", + "userId": "123456789", +} +`; diff --git a/libraries/browser-tracker-core/test/tracker/activity_metrics.test.ts b/libraries/browser-tracker-core/test/tracker/activity_metrics.test.ts new file mode 100644 index 000000000..ccf3beb36 --- /dev/null +++ b/libraries/browser-tracker-core/test/tracker/activity_metrics.test.ts @@ -0,0 +1,335 @@ +import { createTracker } from '../helpers'; +import { Payload } from '@snowplow/tracker-core'; +import { ActivityCallbackData } from '../../src'; + +jest.useFakeTimers(); + +describe('Activity metrics', () => { + const ACTIVITY_METRICS_SCHEMA = 'iglu:com.snowplowanalytics.snowplow/activity_metrics/jsonschema/1-0-0'; + + beforeAll(() => { + jest.spyOn(document, 'title', 'get').mockReturnValue('Test Page'); + }); + + afterEach(() => { + jest.clearAllTimers(); + }); + + afterAll(() => { + jest.restoreAllMocks(); + }); + + function getTrackedPayloads() { + const payloads: Payload[] = []; + const tracker = createTracker({ + plugins: [ + { + afterTrack: (payload) => { + payloads.push(payload); + }, + }, + ], + }); + return { tracker: tracker!, payloads }; + } + + function getPagePings(payloads: Payload[]) { + return payloads.filter((p) => p.e === 'pp'); + } + + function getContextEntities(payload: Payload): Array<{ schema: string; data: unknown }> { + const co = payload.co as string | undefined; + if (!co) return []; + return JSON.parse(co).data ?? []; + } + + /** + * The heartbeat check is `lastActivityTime + configHeartBeatTimer > now`. + * Activity must happen strictly within the heartbeat window (not at its start). + * We advance 1s, dispatch events (so lastActivityTime is now+1s), then advance the rest. + */ + function simulateActivityInWindow(events: Event[], heartbeatMs: number) { + jest.advanceTimersByTime(1000); + events.forEach((e) => document.dispatchEvent(e)); + jest.advanceTimersByTime(heartbeatMs - 1000); + } + + it('accumulates metrics from simulated DOM events', () => { + const { tracker, payloads } = getTrackedPayloads(); + tracker.enableActivityTracking({ + minimumVisitLength: 0, + heartbeatDelay: 10, + activityMetrics: true, + }); + tracker.trackPageView(); + + simulateActivityInWindow( + [ + new MouseEvent('mousemove', { clientX: 0, clientY: 0 }), + new MouseEvent('mousemove', { clientX: 3, clientY: 4 }), + new MouseEvent('click'), + new MouseEvent('click'), + new KeyboardEvent('keydown'), + new KeyboardEvent('keydown'), + new KeyboardEvent('keydown'), + new Event('touchstart'), + ], + 10_000 + ); + + const pings = getPagePings(payloads); + expect(pings.length).toBe(1); + + const entities = getContextEntities(pings[0]); + const metricsEntity = entities.find((e) => e.schema === ACTIVITY_METRICS_SCHEMA); + expect(metricsEntity).toBeDefined(); + + const data = metricsEntity!.data as Record; + expect(data.mouseDistance).toBe(5); // sqrt(9+16)=5 + expect(data.clicks).toBe(2); + expect(data.keyPresses).toBe(3); + expect(data.touches).toBe(1); + }); + + it('resets metrics after each ping', () => { + const { tracker, payloads } = getTrackedPayloads(); + tracker.enableActivityTracking({ + minimumVisitLength: 0, + heartbeatDelay: 10, + activityMetrics: true, + }); + tracker.trackPageView(); + + // First heartbeat + simulateActivityInWindow([new MouseEvent('click'), new MouseEvent('click')], 10_000); + + // Second heartbeat + simulateActivityInWindow([new MouseEvent('click')], 10_000); + + const pings = getPagePings(payloads); + expect(pings.length).toBe(2); + + const data1 = getContextEntities(pings[0]).find((e) => e.schema === ACTIVITY_METRICS_SCHEMA)!.data as Record< + string, + number + >; + const data2 = getContextEntities(pings[1]).find((e) => e.schema === ACTIVITY_METRICS_SCHEMA)!.data as Record< + string, + number + >; + + expect(data1.clicks).toBe(2); + expect(data2.clicks).toBe(1); + }); + + it('does not attach entity when activityMetrics is not set', () => { + const { tracker, payloads } = getTrackedPayloads(); + tracker.enableActivityTracking({ + minimumVisitLength: 0, + heartbeatDelay: 10, + }); + tracker.trackPageView(); + + simulateActivityInWindow([new MouseEvent('click')], 10_000); + + const pings = getPagePings(payloads); + expect(pings.length).toBe(1); + + const entities = getContextEntities(pings[0]); + const metricsEntity = entities.find((e) => e.schema === ACTIVITY_METRICS_SCHEMA); + expect(metricsEntity).toBeUndefined(); + }); + + it('calculates mouse distance as Euclidean sum', () => { + const { tracker, payloads } = getTrackedPayloads(); + tracker.enableActivityTracking({ + minimumVisitLength: 0, + heartbeatDelay: 10, + activityMetrics: true, + }); + tracker.trackPageView(); + + // Move from (0,0) to (3,4) then to (3,14) + simulateActivityInWindow( + [ + new MouseEvent('mousemove', { clientX: 0, clientY: 0 }), + new MouseEvent('mousemove', { clientX: 3, clientY: 4 }), // distance 5 + new MouseEvent('mousemove', { clientX: 3, clientY: 14 }), // distance 10 + ], + 10_000 + ); + + const pings = getPagePings(payloads); + expect(pings.length).toBe(1); + + const data = getContextEntities(pings[0]).find((e) => e.schema === ACTIVITY_METRICS_SCHEMA)!.data as Record< + string, + number + >; + expect(data.mouseDistance).toBe(15); // 5 + 10 + }); + + it('populates activityMetrics in callback data', () => { + let callbackData: ActivityCallbackData | undefined; + const tracker = createTracker({ + plugins: [{ afterTrack: () => {} }], + }); + + tracker!.enableActivityTrackingCallback({ + minimumVisitLength: 0, + heartbeatDelay: 10, + activityMetrics: true, + callback: (data) => { + callbackData = data; + }, + }); + tracker!.trackPageView(); + + simulateActivityInWindow([new MouseEvent('click'), new MouseEvent('click')], 10_000); + + expect(callbackData).toBeDefined(); + expect(callbackData!.activityMetrics).toBeDefined(); + expect(callbackData!.activityMetrics!.clicks).toBe(2); + }); + + it('resets metrics on new trackPageView', () => { + const { tracker, payloads } = getTrackedPayloads(); + tracker.enableActivityTracking({ + minimumVisitLength: 0, + heartbeatDelay: 10, + activityMetrics: true, + }); + tracker.trackPageView(); + + // Accumulate some clicks (advance a bit so they register in heartbeat) + jest.advanceTimersByTime(1000); + document.dispatchEvent(new MouseEvent('click')); + document.dispatchEvent(new MouseEvent('click')); + + // New page view resets metrics and restarts intervals + tracker.trackPageView(); + + // Only one new click after the new page view + simulateActivityInWindow([new MouseEvent('click')], 10_000); + + const pings = getPagePings(payloads); + expect(pings.length).toBe(1); + + const data = getContextEntities(pings[0]).find((e) => e.schema === ACTIVITY_METRICS_SCHEMA)!.data as Record< + string, + number + >; + expect(data.clicks).toBe(1); + }); + + it('first mousemove sets position but does not add distance', () => { + const { tracker, payloads } = getTrackedPayloads(); + tracker.enableActivityTracking({ + minimumVisitLength: 0, + heartbeatDelay: 10, + activityMetrics: true, + }); + tracker.trackPageView(); + + // Only one mousemove — should set position but not add distance + simulateActivityInWindow([new MouseEvent('mousemove', { clientX: 100, clientY: 200 })], 10_000); + + const pings = getPagePings(payloads); + expect(pings.length).toBe(1); + + const data = getContextEntities(pings[0]).find((e) => e.schema === ACTIVITY_METRICS_SCHEMA)!.data as Record< + string, + number + >; + expect(data.mouseDistance).toBe(0); + }); + + it('updatePageActivity does not fabricate metrics', () => { + const { tracker, payloads } = getTrackedPayloads(); + tracker.enableActivityTracking({ + minimumVisitLength: 0, + heartbeatDelay: 10, + activityMetrics: true, + }); + tracker.trackPageView(); + + // updatePageActivity without a real event — advance partially so heartbeat detects it + jest.advanceTimersByTime(1000); + tracker.updatePageActivity(); + jest.advanceTimersByTime(9000); + + const pings = getPagePings(payloads); + expect(pings.length).toBe(1); + + const data = getContextEntities(pings[0]).find((e) => e.schema === ACTIVITY_METRICS_SCHEMA)!.data as Record< + string, + number + >; + expect(data.mouseDistance).toBe(0); + expect(data.clicks).toBe(0); + expect(data.keyPresses).toBe(0); + expect(data.touches).toBe(0); + expect(data.scrollDistance).toBe(0); + }); + + it('attaches activity_metrics entity to callback context when using activityMetrics', () => { + let callbackData: ActivityCallbackData | undefined; + const tracker = createTracker({ + plugins: [{ afterTrack: () => {} }], + }); + + tracker!.enableActivityTrackingCallback({ + minimumVisitLength: 0, + heartbeatDelay: 10, + activityMetrics: true, + callback: (data) => { + callbackData = data; + }, + }); + tracker!.trackPageView(); + + jest.advanceTimersByTime(1000); + document.dispatchEvent(new MouseEvent('click')); + document.dispatchEvent(new MouseEvent('click')); + jest.advanceTimersByTime(9000); + + expect(callbackData).toBeDefined(); + const metricsEntity = callbackData!.context.find( + (e) => e.schema === ACTIVITY_METRICS_SCHEMA + ); + expect(metricsEntity).toBeDefined(); + expect((metricsEntity!.data as Record).clicks).toBe(2); + }); + + it('does not overcount mouse distance across ping windows', () => { + let callbackData: ActivityCallbackData[] = []; + const tracker = createTracker({ + plugins: [{ afterTrack: () => {} }], + }); + + tracker!.enableActivityTrackingCallback({ + minimumVisitLength: 0, + heartbeatDelay: 10, + activityMetrics: true, + callback: (data) => { + callbackData.push(data); + }, + }); + tracker!.trackPageView(); + + // First window: move from 0 to 10 + jest.advanceTimersByTime(1000); + document.dispatchEvent(new MouseEvent('mousemove', { clientX: 0, clientY: 0 })); + document.dispatchEvent(new MouseEvent('mousemove', { clientX: 10, clientY: 0 })); + jest.advanceTimersByTime(9000); + + // Second window: single move to 20 — after position reset, this sets baseline only + jest.advanceTimersByTime(1000); + document.dispatchEvent(new MouseEvent('mousemove', { clientX: 20, clientY: 0 })); + jest.advanceTimersByTime(9000); + + expect(callbackData.length).toBe(2); + expect(callbackData[0].activityMetrics!.mouseDistance).toBe(10); + expect(callbackData[1].activityMetrics!.mouseDistance).toBe(0); + }); +}); diff --git a/libraries/browser-tracker-core/test/tracker/application_context.test.ts b/libraries/browser-tracker-core/test/tracker/application_context.test.ts new file mode 100644 index 000000000..f490dd262 --- /dev/null +++ b/libraries/browser-tracker-core/test/tracker/application_context.test.ts @@ -0,0 +1,44 @@ +import { APPLICATION_CONTEXT_SCHEMA } from '../../src/tracker/schemata'; +import { createTracker } from '../helpers'; + +describe('Application context:', () => { + it('Adds the entity when the appVersion option is configured', (done) => { + const tracker = createTracker({ + appVersion: '1.0.2-beta.2', + plugins: [ + { + filter: (payload) => { + const { data: payloadData } = JSON.parse(payload.co as string); + const appContext = payloadData.find((context: any) => context.schema.match(APPLICATION_CONTEXT_SCHEMA)); + expect(appContext).toBeTruthy(); + expect(appContext.data.version).toBe('1.0.2-beta.2'); + done(); + return false; + }, + }, + ], + }); + + tracker?.trackPageView(); + }); + + it('Does not attach the entity if not configured', (done) => { + const tracker = createTracker({ + plugins: [ + { + filter: (payload) => { + const { data: payloadData } = JSON.parse(payload.co as string); + const applicationContext = payloadData.find((context: any) => + context.schema.match(APPLICATION_CONTEXT_SCHEMA) + ); + expect(applicationContext).toBeUndefined(); + done(); + return false + }, + }, + ], + }); + + tracker?.trackPageView(); + }); +}); diff --git a/libraries/browser-tracker-core/test/tracker/browser_context.test.ts b/libraries/browser-tracker-core/test/tracker/browser_context.test.ts new file mode 100644 index 000000000..2a831f1dd --- /dev/null +++ b/libraries/browser-tracker-core/test/tracker/browser_context.test.ts @@ -0,0 +1,63 @@ +import { BROWSER_CONTEXT_SCHEMA } from '../../src/tracker/schemata'; +import { createTracker } from '../helpers'; + +const UUID_REGEX = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/; + +describe('Browser context:', () => { + let navigatorSpy: jest.SpyInstance; + + // JSDOM values observed are based on: + // https://github.com/jsdom/jsdom/blob/04f6c13f4a4d387c7fc979b8f62c6f68d8a0c639/lib/jsdom/living/window/Screen-impl.js + // https://github.com/jsdom/jsdom/blob/a5204dfb3853120c0460dd0ad89237acfaf650ca/lib/jsdom/browser/Window.js + // https://github.com/jsdom/jsdom/tree/04f6c13f4a4d387c7fc979b8f62c6f68d8a0c639/lib/jsdom/living/navigator + beforeEach(() => { + // We mock the hardwareConcurrency explicitly as it may vary between test environments + navigatorSpy = jest.spyOn(window.navigator, 'hardwareConcurrency', 'get'); + navigatorSpy.mockReturnValue(1); + }); + + afterEach(() => { + navigatorSpy.mockRestore(); + }); + + it('Adds the browser context entity when `contexts: { browser: true }` is passed', (done) => { + const tracker = createTracker({ + encodeBase64: false, + contexts: { browser: true }, + plugins: [ + { + afterTrack: (payload) => { + const { data: payloadData } = JSON.parse(payload.co as string); + const browserContext = payloadData.find((context: any) => context.schema.match(BROWSER_CONTEXT_SCHEMA)); + expect(browserContext).toBeTruthy(); + expect(browserContext.data.tabId).toMatch(UUID_REGEX); + // We remove tabId before the snapshot to make it more straightforward + delete browserContext.data.tabId; + expect(browserContext.data).toMatchSnapshot(); + done(); + }, + }, + ], + }); + + tracker?.trackPageView(); + }); + + it('Does not send the browser context entity by default', (done) => { + const tracker = createTracker({ + encodeBase64: false, + plugins: [ + { + afterTrack: (payload) => { + const { data: payloadData } = JSON.parse(payload.co as string); + const browserContext = payloadData.find((context: any) => context.schema.match(BROWSER_CONTEXT_SCHEMA)); + expect(browserContext).toBeUndefined(); + done(); + }, + }, + ], + }); + + tracker?.trackPageView(); + }); +}); diff --git a/libraries/browser-tracker-core/test/tracker/cookie_storage.test.ts b/libraries/browser-tracker-core/test/tracker/cookie_storage.test.ts new file mode 100644 index 000000000..ce48e9bee --- /dev/null +++ b/libraries/browser-tracker-core/test/tracker/cookie_storage.test.ts @@ -0,0 +1,69 @@ +import { asyncCookieStorage, newCookieStorage, syncCookieStorage } from "../../src/tracker/cookie_storage"; + +test("cookieStorage sets, gets, and deletes value", () => { + const cookieStorage = newCookieStorage(); + cookieStorage.setCookie("test", "value"); + expect(cookieStorage.getCookie("test")).toBe("value"); + + cookieStorage.deleteCookie("test"); + expect(cookieStorage.getCookie("test")).toBeFalsy(); +}); + +test("cookieStorage sets value with ttl and clears cache after ttl", (done) => { + const cookieStorage = newCookieStorage(); + const ttl = 1; + cookieStorage.setCookie("test", "value", ttl); + + expect(cookieStorage.getCookie("test")).toBe("value"); + + setTimeout(() => { + expect(cookieStorage.getCookie("test")).toBeFalsy(); + done(); + }, ttl * 1000 + 100); +}); + +test("cookieStorage sets value with path, domain, samesite, and secure", () => { + const cookieStorage = newCookieStorage(); + const path = "/"; + const domain = "example.com"; + const samesite = "Strict"; + const secure = true; + + cookieStorage.setCookie("test", "value", undefined, path, domain, samesite, secure); + expect(cookieStorage.getCookie("test")).toBe("value"); +}); + +test("cookieStorage sets value with synchronous cookie write", () => { + const cookieStorage = syncCookieStorage; + cookieStorage.setCookie("test", "value"); + expect(cookieStorage.getCookie("test")).toBe("value"); +}); + +test("asyncCookieStorage flushes pending cookies", () => { + let cookieJar = ''; + + jest.spyOn(document, 'cookie', 'set').mockImplementation((cookieValue) => { + cookieJar = cookieValue; + }); + + asyncCookieStorage.setCookie("test", "value"); + expect(cookieJar).toBe(""); + asyncCookieStorage.flush(); + expect(cookieJar).toBe("test=value"); +}); + +test('writes the latest cookie value', (done) => { + let cookieJar = ''; + + jest.spyOn(document, 'cookie', 'set').mockImplementation((cookieValue) => { + cookieJar = cookieValue; + }); + + for (let i = 0; i < 100; i++) { + asyncCookieStorage.setCookie("test", `value${i}`); + } + setTimeout(() => { + expect(cookieJar).toBe('test=value99'); + done(); + }, 100); +}); diff --git a/libraries/browser-tracker-core/test/tracker/cross_domain.test.ts b/libraries/browser-tracker-core/test/tracker/cross_domain.test.ts new file mode 100644 index 000000000..68e76fdc6 --- /dev/null +++ b/libraries/browser-tracker-core/test/tracker/cross_domain.test.ts @@ -0,0 +1,147 @@ +import * as uuid from 'uuid'; +jest.mock('uuid'); +const MOCK_UUID = '123456789'; +(jest.spyOn(uuid, 'v4') as jest.SpyInstance).mockReturnValue(MOCK_UUID); + +import { createTracker } from '../helpers'; +import { getByText, queryByText, waitFor } from '@testing-library/dom'; +import { urlSafeBase64Encode } from '../../src'; + +function getCrossDomainURLParam(url: string) { + const CROSS_DOMAIN_PARAMETER_NAME = '_sp'; + const urlParams = new URLSearchParams(new URL(url).search); + return urlParams.get(CROSS_DOMAIN_PARAMETER_NAME); +} + +function decodeExtendedCrossDomainLinkParam(crossDomainLinkValue: string) { + return crossDomainLinkValue.split('.'); +} + +describe('Cross-domain linking: ', () => { + const CROSS_DOMAIN_LINK_PARAMETERS_LENGTH = 7; + const standardDate = new Date(2023, 1, 1); + + beforeAll(() => { + jest.useFakeTimers(); + jest.setSystemTime(standardDate); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + afterAll(() => { + jest.useRealTimers(); + }); + + const CROSS_DOMAIN_LINK_TEXT = 'Cross-domain link'; + const appId = 'my-app'; + const userId = 'U1234'; + function getLinkDom() { + const div = document.createElement('div'); + div.innerHTML = ` + ${CROSS_DOMAIN_LINK_TEXT} + `; + return div; + } + + it('Adds the correct link decoration', async () => { + const container = getLinkDom(); + + const elem = getByText(container, CROSS_DOMAIN_LINK_TEXT); + // @ts-ignore + jest.spyOn(document, 'links', 'get').mockReturnValue([elem]); + createTracker({ crossDomainLinker: () => true }); + elem.click(); + await waitFor(() => { + const clickedLink = queryByText(container, CROSS_DOMAIN_LINK_TEXT)?.getAttribute('href') as string; + const crossDomainLinkParam = getCrossDomainURLParam(clickedLink); + const crossDomainParamParts = crossDomainLinkParam?.split('.') as string[]; + expect(crossDomainParamParts?.length).toEqual(2); + expect(crossDomainParamParts[0]).toEqual(MOCK_UUID); + expect(crossDomainParamParts[1]).toEqual(String(standardDate.getTime())); + }); + }); + + it('Adds the correct link decoration with default extended format', async () => { + const container = getLinkDom(); + const elem = getByText(container, CROSS_DOMAIN_LINK_TEXT); + // @ts-ignore + jest.spyOn(document, 'links', 'get').mockReturnValue([elem]); + const t = createTracker({ appId, crossDomainLinker: () => true, useExtendedCrossDomainLinker: true }); + t?.setUserId(userId); + elem.click(); + await waitFor(() => { + const clickedLink = queryByText(container, CROSS_DOMAIN_LINK_TEXT)?.getAttribute('href') as string; + const crossDomainLinkParam = getCrossDomainURLParam(clickedLink) as string; + const decodedCrossDomainLinkParam = decodeExtendedCrossDomainLinkParam(crossDomainLinkParam); + expect(decodedCrossDomainLinkParam.length).toBe(CROSS_DOMAIN_LINK_PARAMETERS_LENGTH - 2); + expect(decodedCrossDomainLinkParam).toStrictEqual([ + MOCK_UUID, + String(standardDate.getTime()), + MOCK_UUID, + '', + urlSafeBase64Encode(appId), + ]); + }); + }); + + it('Adds the correct link decoration with configurable extended format and link text collection', async () => { + const container = getLinkDom(); + + const elem = getByText(container, CROSS_DOMAIN_LINK_TEXT); + // @ts-ignore + jest.spyOn(document, 'links', 'get').mockReturnValue([elem]); + const t = createTracker({ + appId, + crossDomainLinker: () => true, + useExtendedCrossDomainLinker: { userId: true, reason: true, sourcePlatform: true }, + }); + t?.setUserId(userId); + elem.click(); + await waitFor(() => { + const clickedLink = queryByText(container, CROSS_DOMAIN_LINK_TEXT)?.getAttribute('href') as string; + const crossDomainLinkParam = getCrossDomainURLParam(clickedLink) as string; + const decodedCrossDomainLinkParam = decodeExtendedCrossDomainLinkParam(crossDomainLinkParam); + expect(decodedCrossDomainLinkParam.length).toBe(CROSS_DOMAIN_LINK_PARAMETERS_LENGTH); + expect(decodedCrossDomainLinkParam).toStrictEqual([ + MOCK_UUID, + String(standardDate.getTime()), + MOCK_UUID, + urlSafeBase64Encode(userId), + urlSafeBase64Encode(appId), + 'web', + urlSafeBase64Encode(CROSS_DOMAIN_LINK_TEXT), + ]); + }); + }); + + it('Adds the correct link decoration with configurable extended format and event callback', async () => { + const container = getLinkDom(); + + const elem = getByText(container, CROSS_DOMAIN_LINK_TEXT); + // @ts-ignore + jest.spyOn(document, 'links', 'get').mockReturnValue([elem]); + createTracker({ + appId, + crossDomainLinker: () => true, + useExtendedCrossDomainLinker: { reason: (evt) => evt.type }, + }); + elem.click(); + await waitFor(() => { + const clickedLink = queryByText(container, CROSS_DOMAIN_LINK_TEXT)?.getAttribute('href') as string; + const crossDomainLinkParam = getCrossDomainURLParam(clickedLink) as string; + const decodedCrossDomainLinkParam = decodeExtendedCrossDomainLinkParam(crossDomainLinkParam); + expect(decodedCrossDomainLinkParam.length).toBe(CROSS_DOMAIN_LINK_PARAMETERS_LENGTH); + expect(decodedCrossDomainLinkParam).toStrictEqual([ + MOCK_UUID, + String(standardDate.getTime()), + MOCK_UUID, + '', + urlSafeBase64Encode(appId), + '', + urlSafeBase64Encode('click'), + ]); + }); + }); +}); diff --git a/libraries/browser-tracker-core/test/tracker/local_storage_event_store.test.ts b/libraries/browser-tracker-core/test/tracker/local_storage_event_store.test.ts new file mode 100644 index 000000000..2c1ceebcf --- /dev/null +++ b/libraries/browser-tracker-core/test/tracker/local_storage_event_store.test.ts @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { newLocalStorageEventStore } from '../../src/tracker/local_storage_event_store'; + +describe('LocalStorageEventStore', () => { + const trackerId = 'test-tracker'; + + beforeEach(() => { + localStorage.clear(); + }); + + it('should create an event store with useLocalStorage enabled', async () => { + const eventStore = newLocalStorageEventStore({ + trackerId, + useLocalStorage: true, + }); + + expect(await eventStore.count()).toBe(0); + }); + + it('should create an event store with useLocalStorage disabled', async () => { + const eventStore = newLocalStorageEventStore({ + trackerId, + useLocalStorage: false, + }); + + expect(await eventStore.count()).toBe(0); + }); + + it('should add and retrieve events when localStorage is accessible', async () => { + const eventStore = newLocalStorageEventStore({ + trackerId, + useLocalStorage: true, + }); + + const event = { payload: { e: 'pv', eid: 'test-event-id' } }; + await eventStore.add(event); + + expect(await eventStore.count()).toBe(1); + const events = await eventStore.getAllPayloads(); + expect(events[0]).toMatchObject(event.payload); + }); + + it('should handle SecurityError when accessing localStorage.getItem', () => { + const originalGetItem = Storage.prototype.getItem; + Storage.prototype.getItem = jest.fn(() => { + throw new DOMException('The operation is insecure.', 'SecurityError'); + }); + + // Should not throw an error, but should create an empty in-memory store + const eventStore = newLocalStorageEventStore({ + trackerId, + useLocalStorage: true, + }); + + expect(eventStore).toBeDefined(); + expect(eventStore.count).toBeDefined(); + + Storage.prototype.getItem = originalGetItem; + }); + + it('should handle SecurityError when accessing localStorage.setItem', async () => { + const originalSetItem = Storage.prototype.setItem; + Storage.prototype.setItem = jest.fn(() => { + throw new DOMException('The operation is insecure.', 'SecurityError'); + }); + + const eventStore = newLocalStorageEventStore({ + trackerId, + useLocalStorage: true, + }); + + const event = { payload: { e: 'pv', eid: 'test-event-id' } }; + + // Should not throw an error, even though setItem fails + await expect(eventStore.add(event)).resolves.toBeDefined(); + + // Event should still be in the in-memory store + expect(await eventStore.count()).toBe(1); + + Storage.prototype.setItem = originalSetItem; + }); + + it('should gracefully handle errors when both getItem and setItem throw SecurityError', async () => { + const originalGetItem = Storage.prototype.getItem; + const originalSetItem = Storage.prototype.setItem; + + Storage.prototype.getItem = jest.fn(() => { + throw new DOMException('The operation is insecure.', 'SecurityError'); + }); + Storage.prototype.setItem = jest.fn(() => { + throw new DOMException('The operation is insecure.', 'SecurityError'); + }); + + const eventStore = newLocalStorageEventStore({ + trackerId, + useLocalStorage: true, + }); + + const event = { payload: { e: 'pv', eid: 'test-event-id' } }; + await eventStore.add(event); + + // Event should be in the in-memory store + expect(await eventStore.count()).toBe(1); + const events = await eventStore.getAllPayloads(); + expect(events[0]).toMatchObject(event.payload); + + Storage.prototype.getItem = originalGetItem; + Storage.prototype.setItem = originalSetItem; + }); + + it('should persist events to localStorage when accessible', async () => { + const eventStore = newLocalStorageEventStore({ + trackerId, + useLocalStorage: true, + }); + + const event = { payload: { e: 'pv', eid: 'test-event-id' } }; + await eventStore.add(event); + + // Check that the event was persisted to localStorage + const queueName = `snowplowOutQueue_${trackerId}`; + const stored = localStorage.getItem(queueName); + expect(stored).toBeDefined(); + expect(JSON.parse(stored!)).toHaveLength(1); + }); + + it('should load events from localStorage on initialization', () => { + const queueName = `snowplowOutQueue_${trackerId}`; + const events = [{ payload: { e: 'pv', eid: 'event-1' } }, { payload: { e: 'pv', eid: 'event-2' } }]; + localStorage.setItem(queueName, JSON.stringify(events)); + + const eventStore = newLocalStorageEventStore({ + trackerId, + useLocalStorage: true, + }); + + expect(eventStore.count()).resolves.toBe(2); + }); + + it('should not load from localStorage when useLocalStorage is false', () => { + const queueName = `snowplowOutQueue_${trackerId}`; + const events = [{ payload: { e: 'pv', eid: 'event-1' } }, { payload: { e: 'pv', eid: 'event-2' } }]; + localStorage.setItem(queueName, JSON.stringify(events)); + + const eventStore = newLocalStorageEventStore({ + trackerId, + useLocalStorage: false, + }); + + expect(eventStore.count()).resolves.toBe(0); + }); +}); diff --git a/libraries/browser-tracker-core/test/tracker/page_view.test.ts b/libraries/browser-tracker-core/test/tracker/page_view.test.ts new file mode 100644 index 000000000..0a56c5e97 --- /dev/null +++ b/libraries/browser-tracker-core/test/tracker/page_view.test.ts @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import * as browserProps from '../../src/helpers/browser_props'; +import { createTracker } from '../helpers'; + +describe('Tracker API: page views', () => { + beforeEach(() => { + jest.spyOn(document, 'title', 'get').mockReturnValue('Page title 1'); + }); + + it('Uses custom page title for only a single page view', () => { + let titles: string[] = []; + const tracker = createTracker({ + plugins: [ + { + afterTrack: (payload) => { + titles.push(payload.page as string); + }, + }, + ], + }); + + tracker?.trackPageView({ + title: 'Title override', + }); + tracker?.trackPageView(); + + expect(titles).toEqual(['Title override', 'Page title 1']); + }); + + it('setCustomUrl keeps a URL whose scheme contains a hyphen (e.g. a browser extension)', () => { + let urls: string[] = []; + const tracker = createTracker({ + plugins: [ + { + afterTrack: (payload) => { + urls.push(payload.url as string); + }, + }, + ], + }); + + // chrome-extension is 16 chars, which is within the atomic event schema's + // 16-char scheme limit, so it is a real, schema-valid scheme the tracker + // must preserve as an absolute URL rather than resolve against the page. + tracker?.setCustomUrl('chrome-extension://abcdefg/index.html'); + tracker?.trackPageView(); + + expect(urls[0]).toBe('chrome-extension://abcdefg/index.html'); + }); + + it('setCustomUrl does not treat an over-length scheme as absolute (schema caps scheme at 16 chars)', () => { + let urls: string[] = []; + const tracker = createTracker({ + plugins: [ + { + afterTrack: (payload) => { + urls.push(payload.url as string); + }, + }, + ], + }); + + // safari-web-extension is 20 chars, exceeding the atomic event schema's + // 16-char scheme limit. Treating it as absolute would only produce an event + // that fails validation downstream, so it must be handled as a relative + // reference (resolved against the page) instead of preserved verbatim. + tracker?.setCustomUrl('safari-web-extension://abcdefg/index.html'); + tracker?.trackPageView(); + + expect(urls[0]).not.toBe('safari-web-extension://abcdefg/index.html'); + }); + + it('Uses custom page title set using setDocumentTitle until overriden again', () => { + let titles: string[] = []; + const tracker = createTracker({ + plugins: [ + { + afterTrack: (payload) => { + titles.push(payload.page as string); + }, + }, + ], + }); + + tracker?.setDocumentTitle('Title override'); + tracker?.trackPageView(); + tracker?.trackPageView(); + + jest.spyOn(document, 'title', 'get').mockReturnValue('Page title 2'); + tracker?.trackPageView(); + + tracker?.setDocumentTitle('Title override 2'); + tracker?.trackPageView(); + + expect(titles).toEqual(['Title override', 'Title override', 'Title override', 'Title override 2']); + }); + + it('Explicit title in trackPageView overrides setDocumentTitle', () => { + let titles: string[] = []; + const tracker = createTracker({ + plugins: [ + { + afterTrack: (payload) => { + titles.push(payload.page as string); + }, + }, + ], + }); + + tracker?.setDocumentTitle('Title override'); + tracker?.trackPageView({ + title: 'Explicit title', + }); + tracker?.trackPageView(); + + expect(titles).toEqual(['Explicit title', 'Page title 1']); + }); + + describe('getBrowserProperties deferred init', () => { + let getBrowserPropertiesSpy: jest.SpyInstance; + + beforeEach(() => { + browserProps.resetBrowserPropertiesState(); + getBrowserPropertiesSpy = jest.spyOn(browserProps, 'getBrowserProperties'); + }); + + afterEach(() => { + jest.restoreAllMocks(); + browserProps.resetBrowserPropertiesState(); + }); + + it('does not call getBrowserProperties during tracker construction', () => { + createTracker(); + expect(getBrowserPropertiesSpy).not.toHaveBeenCalled(); + }); + + it('calls getBrowserProperties exactly once on the first trackPageView (default config)', () => { + const tracker = createTracker(); + getBrowserPropertiesSpy.mockClear(); + + tracker?.trackPageView(); + expect(getBrowserPropertiesSpy).toHaveBeenCalledTimes(1); + }); + }); +}); diff --git a/libraries/browser-tracker-core/test/tracker/page_view_id.test.ts b/libraries/browser-tracker-core/test/tracker/page_view_id.test.ts new file mode 100644 index 000000000..e573a5fd2 --- /dev/null +++ b/libraries/browser-tracker-core/test/tracker/page_view_id.test.ts @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { createTracker } from '../helpers'; + +describe('Tracker API: page view IDs', () => { + it('Keeps the page view ID when URL changes', () => { + const tracker = createTracker(); + tracker?.setCustomUrl('http://example.com/1'); + const pageView1 = tracker?.getPageViewId(); + tracker?.setCustomUrl('http://example.com/2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + }); + + describe('preservePageViewIdForUrl: false', () => { + it('Generates new page view ID on second page view', () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl(false); + + const pageView1 = tracker?.getPageViewId(); + + tracker?.trackPageView(); + const pageView2 = tracker?.getPageViewId(); + const pageView3 = tracker?.getPageViewId(); + + tracker?.trackPageView(); + const pageView4 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + expect(pageView2).toEqual(pageView3); + expect(pageView3).not.toEqual(pageView4); + }); + + it("Doesn't generate new page view ID when URL is changed", () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl(false); + + tracker?.setCustomUrl('http://example.com/1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + }); + }); + + describe('preservePageViewIdForUrl: full', () => { + it("Generates new page view ID on second page view on the same URL", () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('full'); + + const pageView1 = tracker?.getPageViewId(); + + tracker?.trackPageView(); + const pageView2 = tracker?.getPageViewId(); + + tracker?.trackPageView(); + const pageView3 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + expect(pageView2).not.toEqual(pageView3); + }); + + it("Doesn't generate new page view ID for the same URL", () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('full'); + + tracker?.setCustomUrl('http://example.com/1'); + const pageView1 = tracker?.getPageViewId(); + + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + }); + + it('Generates new page view ID when URL changes', () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('full'); + + tracker?.setCustomUrl('http://example.com/1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).not.toEqual(pageView2); + }); + + it('Generates new page view ID when hash param changes', () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('full'); + + tracker?.setCustomUrl('http://example.com/#1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/#2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).not.toEqual(pageView2); + }); + + it('Generates new page view ID when search param changes', () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('full'); + + tracker?.setCustomUrl('http://example.com/?test=1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/?test=2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).not.toEqual(pageView2); + }); + + it('Works the same way if set to true', () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl(true); + + tracker?.setCustomUrl('http://example.com/#1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/#2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).not.toEqual(pageView2); + }); + + it('Works the same way if configured through createTracker', () => { + const tracker = createTracker({ preservePageViewIdForUrl: 'full' }); + + tracker?.setCustomUrl('http://example.com/?test=1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/?test=2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).not.toEqual(pageView2); + }); + }); + + describe('preservePageViewIdForUrl: pathname', () => { + it("Generates new page view ID on second page view on the same URL", () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('pathname'); + + const pageView1 = tracker?.getPageViewId(); + + tracker?.trackPageView(); + const pageView2 = tracker?.getPageViewId(); + + tracker?.trackPageView(); + const pageView3 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + expect(pageView2).not.toEqual(pageView3); + }); + + it("Doesn't generate new page view ID for the same URL", () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('pathname'); + + tracker?.setCustomUrl('http://example.com/1'); + const pageView1 = tracker?.getPageViewId(); + + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + }); + + it("Doesn't generate new page view ID when hash param changes", () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('pathname'); + + tracker?.setCustomUrl('http://example.com/#1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/#2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + }); + + it("Doesn't generate new page view ID when search param changes", () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('pathname'); + + tracker?.setCustomUrl('http://example.com/?test=1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/?test=2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + }); + + it('Generates a new page view ID when the path changes', () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('pathname'); + + tracker?.setCustomUrl('http://example.com/1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).not.toEqual(pageView2); + }); + }); + + describe('preservePageViewIdForUrl: pathnameAndSearch', () => { + it("Generates new page view ID on second page view on the same URL", () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('pathnameAndSearch'); + + const pageView1 = tracker?.getPageViewId(); + + tracker?.trackPageView(); + const pageView2 = tracker?.getPageViewId(); + + tracker?.trackPageView(); + const pageView3 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + expect(pageView2).not.toEqual(pageView3); + }); + + it("Doesn't generate new page view ID for the same URL", () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('pathnameAndSearch'); + + tracker?.setCustomUrl('http://example.com/1'); + const pageView1 = tracker?.getPageViewId(); + + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + }); + + it("Doesn't generate new page view ID when hash param changes", () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('pathnameAndSearch'); + + tracker?.setCustomUrl('http://example.com/#1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/#2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + }); + + it('Generates new page view ID when search param changes', () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('pathnameAndSearch'); + + tracker?.setCustomUrl('http://example.com/?test=1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/?test=2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).not.toEqual(pageView2); + }); + + it('Generates a new page view ID when the path changes', () => { + const tracker = createTracker(); + tracker?.preservePageViewIdForUrl('pathnameAndSearch'); + + tracker?.setCustomUrl('http://example.com/1'); + const pageView1 = tracker?.getPageViewId(); + + tracker?.setCustomUrl('http://example.com/2'); + const pageView2 = tracker?.getPageViewId(); + + expect(pageView1).not.toEqual(pageView2); + }); + }); + + describe('Multiple trackers with a shared state', () => { + it('Keeps the page view ID for each page view pairs', () => { + const tracker1 = createTracker(); + const tracker2 = createTracker(undefined, tracker1?.sharedState); + + tracker1?.setCustomUrl('http://example.com/1'); + tracker1?.trackPageView(); + const pageView1 = tracker1?.getPageViewId(); + + tracker2?.trackPageView(); + const pageView2 = tracker2?.getPageViewId(); + + expect(pageView1).toEqual(pageView2); + + tracker1?.trackPageView(); + const pageView3 = tracker1?.getPageViewId(); + + tracker2?.trackPageView(); + const pageView4 = tracker2?.getPageViewId(); + + expect(pageView1).not.toEqual(pageView3); + expect(pageView3).toEqual(pageView4); + }); + + it("Doesn't keep the page view ID for multiple calls to one tracker", () => { + const tracker1 = createTracker(); + const tracker2 = createTracker(undefined, tracker1?.sharedState); + + tracker1?.setCustomUrl('http://example.com/1'); + tracker1?.trackPageView(); + const pageView1 = tracker1?.getPageViewId(); + tracker1?.trackPageView(); + const pageView2 = tracker1?.getPageViewId(); + + tracker2?.trackPageView(); + const pageView3 = tracker2?.getPageViewId(); + + expect(pageView1).not.toEqual(pageView2); + expect(pageView2).toEqual(pageView3); + + tracker1?.trackPageView(); + const pageView4 = tracker1?.getPageViewId(); + + tracker2?.trackPageView(); + const pageView5 = tracker2?.getPageViewId(); + + expect(pageView3).not.toEqual(pageView4); + expect(pageView4).toEqual(pageView5); + }); + }); +}); diff --git a/libraries/browser-tracker-core/test/tracker/referrer.test.ts b/libraries/browser-tracker-core/test/tracker/referrer.test.ts new file mode 100644 index 000000000..732ae419b --- /dev/null +++ b/libraries/browser-tracker-core/test/tracker/referrer.test.ts @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { createTracker } from '../helpers'; + +const EXTERNAL_REFERRER = 'https://www.google.com/search?q=snowplow'; + +/** + * Simulate a SPA client-side navigation by updating window.location + * without a page reload, and advancing the tracker's internal URL state. + */ +function navigateTo(path: string) { + window.history.pushState({}, '', path); +} + +describe('Tracker API: preserveOriginalReferrer', () => { + let referrerSpy: jest.SpyInstance; + + beforeEach(() => { + // Reset URL to a known starting point before each test + window.history.pushState({}, '', '/test/page.html'); + referrerSpy = jest.spyOn(document, 'referrer', 'get').mockReturnValue(EXTERNAL_REFERRER); + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + + it('freezes the original external referrer across SPA navigations when enabled', () => { + const referrers: string[] = []; + const tracker = createTracker({ + preserveOriginalReferrer: true, + plugins: [ + { + afterTrack: (payload) => { + referrers.push(payload.refr as string); + }, + }, + ], + }); + + // First page view — referrer should be the external referrer + tracker?.trackPageView(); + + // Simulate SPA navigation to a different route + navigateTo('/test/about.html'); + tracker?.trackPageView(); + + // Simulate another SPA navigation + navigateTo('/test/contact.html'); + tracker?.trackPageView(); + + // All three page views should report the original external referrer + expect(referrers).toHaveLength(3); + expect(referrers[0]).toBe(EXTERNAL_REFERRER); + expect(referrers[1]).toBe(EXTERNAL_REFERRER); + expect(referrers[2]).toBe(EXTERNAL_REFERRER); + }); + + it('is a no-op when document.referrer is empty at init (direct navigation)', () => { + // Override the referrer spy to return empty string (direct navigation) + referrerSpy.mockReturnValue(''); + + const referrers: string[] = []; + const tracker = createTracker({ + preserveOriginalReferrer: true, + plugins: [ + { + afterTrack: (payload) => { + referrers.push((payload.refr as string) ?? ''); + }, + }, + ], + }); + + // First page view — no external referrer, so refr is empty + tracker?.trackPageView(); + const firstRefr = referrers[0]; + + // Navigate to a new route — now the previous internal URL becomes the referrer + navigateTo('/test/about.html'); + tracker?.trackPageView(); + + // The second page view should have the previous internal URL as referrer + // (not frozen to empty string), proving the no-op behaviour + expect(referrers).toHaveLength(2); + expect(firstRefr ?? '').toBe(''); + // The second referrer should be set to the previous page's URL (internal chain intact) + expect(referrers[1]).toContain('/test/page.html'); + }); + + it('allows setReferrerUrl to override the preserved referrer after init', () => { + const referrers: string[] = []; + const tracker = createTracker({ + preserveOriginalReferrer: true, + plugins: [ + { + afterTrack: (payload) => { + referrers.push(payload.refr as string); + }, + }, + ], + }); + + // Override with an explicit custom referrer after init + tracker?.setReferrerUrl('https://custom.com/landing'); + tracker?.trackPageView(); + + navigateTo('/test/about.html'); + tracker?.trackPageView(); + + // The explicit setReferrerUrl call wins (last-write-wins on customReferrer) + expect(referrers[0]).toBe('https://custom.com/landing'); + expect(referrers[1]).toBe('https://custom.com/landing'); + }); + + it('does not affect SPA referrer chain when option is absent', () => { + const referrers: string[] = []; + const tracker = createTracker({ + // preserveOriginalReferrer not set — default behaviour + plugins: [ + { + afterTrack: (payload) => { + referrers.push((payload.refr as string) ?? ''); + }, + }, + ], + }); + + // First page view uses document.referrer + tracker?.trackPageView(); + + // Navigate — second page view should use the previous internal URL as referrer + navigateTo('/test/about.html'); + tracker?.trackPageView(); + + expect(referrers).toHaveLength(2); + expect(referrers[0]).toBe(EXTERNAL_REFERRER); + // After SPA navigation the referrer becomes the previous internal URL + expect(referrers[1]).toContain('/test/page.html'); + }); +}); diff --git a/libraries/browser-tracker-core/test/tracker/session_data.test.ts b/libraries/browser-tracker-core/test/tracker/session_data.test.ts new file mode 100644 index 000000000..d4b7277db --- /dev/null +++ b/libraries/browser-tracker-core/test/tracker/session_data.test.ts @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import * as uuid from 'uuid'; +jest.mock('uuid'); +const MOCK_UUID = '123456789'; +(jest.spyOn(uuid, 'v4') as jest.SpyInstance).mockReturnValue(MOCK_UUID); + +import { createTestIdCookie, createTestSessionIdCookie, createTracker } from '../helpers'; + +jest.useFakeTimers(); + +describe('Tracker API: ', () => { + let cookieJar: string; + + beforeAll(() => { + cookieJar = ''; + jest.spyOn(document, 'cookie', 'set').mockImplementation((cookie) => { + cookieJar += cookie; + }); + jest.spyOn(document, 'cookie', 'get').mockImplementation(() => cookieJar); + }); + + afterEach(() => { + cookieJar = ''; + jest.clearAllTimers(); + }); + + afterAll(() => { + jest.clearAllMocks(); + }); + + it('Writes cookies synchronously on session change', () => { + const tracker = createTracker(undefined, undefined, false); // async cookie writes enabled + + expect(cookieJar).toContain('_sp_ses'); + + tracker?.newSession(); + expect(cookieJar).toContain(tracker?.getDomainUserInfo().slice(1).join('.')); + }); + + it('Sets initial domain session index on first session', () => { + const tracker = createTracker(); + + expect(tracker?.getDomainSessionIndex()).toEqual(1); + }); + + it('Sets correct domain session index on new session', () => { + const initialSessionIndex = 1; + document.cookie = createTestIdCookie({ visitCount: initialSessionIndex }); + const tracker = createTracker(); + + expect(tracker?.getDomainSessionIndex()).toEqual(initialSessionIndex + 1); + }); + + it('Sets correct domain session index on existing session', () => { + const initialSessionIndex = 2; + document.cookie = createTestIdCookie({ visitCount: initialSessionIndex }) + ' ' + createTestSessionIdCookie(); + const tracker = createTracker(); + + expect(tracker?.getDomainSessionIndex()).toEqual(initialSessionIndex); + }); + + it('Sets correct domain session index (1) after clearUserData() on existing session', () => { + const initialSessionIndex = 2; + document.cookie = createTestIdCookie({ visitCount: initialSessionIndex }) + ' ' + createTestSessionIdCookie(); + const tracker = createTracker(); + expect(tracker?.getDomainSessionIndex()).toEqual(initialSessionIndex); + + tracker?.clearUserData(); + expect(tracker?.getDomainSessionIndex()).toEqual(1); + }); + + it('Sets blank domain user id after clearUserData() if anonymous tracking', () => { + const tracker = createTracker({ + anonymousTracking: { withSessionTracking: true }, + }); + + tracker?.clearUserData(); + expect(tracker?.getDomainUserId()).toEqual(''); + }); + + it('Sets correct domain session index anonymous track', () => { + const tracker = createTracker({ anonymousTracking: true }); + expect(tracker?.getDomainSessionIndex()).toEqual(1); + }); + + it('Retains correct domain session index on opt-out cookie present', () => { + const optOutCookieName = 'optOut'; + const tracker = createTracker(); + tracker?.setOptOutCookie(optOutCookieName); + document.cookie = `${optOutCookieName}=1;`; + + tracker?.trackPageView({ title: 'my page' }); + expect(tracker?.getDomainSessionIndex()).toEqual(1); + }); + + it('Sets correct domain session index after session expiration', () => { + // Session timeout is in seconds + const tracker = createTracker({ sessionCookieTimeout: 1 }); + // Advance timer by more than one second + jest.advanceTimersByTime(1001); + tracker?.trackPageView({ title: 'my page' }); + expect(tracker?.getDomainSessionIndex()).toEqual(2); + }); + + it('Returns the current domain session id from an existing session', () => { + const sessionId = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'; + document.cookie = createTestIdCookie({ sessionId }) + ' ' + createTestSessionIdCookie(); + const tracker = createTracker(); + + expect(tracker?.getDomainSessionId()).toEqual(sessionId); + }); + + it('Returns a newly generated domain session id on a new session', () => { + const tracker = createTracker(); + + expect(tracker?.getDomainSessionId()).toEqual(MOCK_UUID); + }); + + it('Returns the updated domain session id after newSession()', () => { + const sessionId = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'; + document.cookie = createTestIdCookie({ sessionId }) + ' ' + createTestSessionIdCookie(); + const tracker = createTracker(); + expect(tracker?.getDomainSessionId()).toEqual(sessionId); + + tracker?.newSession(); + expect(tracker?.getDomainSessionId()).toEqual(MOCK_UUID); + }); + + it('Adds the client session context entity when enabled', (done) => { + const tracker = createTracker({ + contexts: { session: true }, + encodeBase64: false, + plugins: [ + { + afterTrack: (payload) => { + let context = payload.co as string; + expect(context).toContain('client_session'); + done(); + }, + }, + ], + }); + + tracker?.trackPageView(); + }); + + it('Adds the client session context entity when anonymous session tracking', (done) => { + const tracker = createTracker({ + contexts: { session: true }, + encodeBase64: false, + anonymousTracking: { withSessionTracking: true }, + plugins: [ + { + afterTrack: (payload) => { + let context = payload.co as string; + expect(context).toContain('client_session'); + expect(context).toContain('"userId":"00000000-0000-0000-0000-000000000000"'); + expect(context).toContain('"previousSessionId":null'); + done(); + }, + }, + ], + }); + + tracker?.trackPageView(); + }); + + it("Doesn't add the client session context entity when anonymous tracking without session tracking", (done) => { + const tracker = createTracker({ + contexts: { session: true }, + encodeBase64: false, + anonymousTracking: true, + plugins: [ + { + afterTrack: (payload) => { + let context = payload.co as string; + expect(context).not.toContain('client_session'); + done(); + }, + }, + ], + }); + + tracker?.trackPageView(); + }); + + describe('disableSessionContextWithinWebView', () => { + afterEach(() => { + delete (window as any).ReactNativeWebView; + }); + + it('Suppresses client_session entity when in WebView and option is enabled', (done) => { + (window as any).ReactNativeWebView = { postMessage: () => {} }; + const tracker = createTracker({ + contexts: { session: true }, + encodeBase64: false, + disableSessionContextWithinWebView: true, + plugins: [ + { + afterTrack: (payload) => { + let context = payload.co as string; + expect(context).not.toContain('client_session'); + done(); + }, + }, + ], + }); + + tracker?.trackPageView(); + }); + + it('Includes client_session entity when in WebView but option is explicitly false', (done) => { + (window as any).ReactNativeWebView = { postMessage: () => {} }; + const tracker = createTracker({ + contexts: { session: true }, + encodeBase64: false, + disableSessionContextWithinWebView: false, + plugins: [ + { + afterTrack: (payload) => { + let context = payload.co as string; + expect(context).toContain('client_session'); + done(); + }, + }, + ], + }); + + tracker?.trackPageView(); + }); + + it('Includes client_session entity when in WebView but option is absent (backward compat)', (done) => { + (window as any).ReactNativeWebView = { postMessage: () => {} }; + const tracker = createTracker({ + contexts: { session: true }, + encodeBase64: false, + plugins: [ + { + afterTrack: (payload) => { + let context = payload.co as string; + expect(context).toContain('client_session'); + done(); + }, + }, + ], + }); + + tracker?.trackPageView(); + }); + }); + + describe('onSessionUpdateCallback functionality', () => { + beforeEach(() => { + const standardDate = new Date('2023-01-01T00:00:00Z'); + jest.setSystemTime(standardDate); + }); + + it('properly calls onSessionUpdateCallback', (done) => { + const tracker = createTracker({ + contexts: { session: true }, + encodeBase64: false, + onSessionUpdateCallback(updatedSession) { + expect(updatedSession).toMatchSnapshot(); + done(); + }, + }); + + tracker?.trackPageView(); + }); + + it('properly calls onSessionUpdateCallback with correct storage strategy', (done) => { + const tracker = createTracker({ + contexts: { session: true }, + encodeBase64: false, + stateStorageStrategy: 'localStorage', + onSessionUpdateCallback(updatedSession) { + expect(updatedSession).toMatchSnapshot(); + done(); + }, + }); + + tracker?.trackPageView(); + }); + + it('properly calls onSessionUpdateCallback with anonymousTracking and withSessionTracking', (done) => { + const tracker = createTracker({ + contexts: { session: true }, + encodeBase64: false, + anonymousTracking: { withSessionTracking: true }, + onSessionUpdateCallback(updatedSession) { + expect(updatedSession).toMatchSnapshot(); + done(); + }, + }); + + tracker?.trackPageView(); + }); + + it('does not call onSessionUpdateCallback with anonymousTracking', () => { + const mockOnSessionUpdateCallback = jest.fn(); + const tracker = createTracker({ + contexts: { session: true }, + encodeBase64: false, + anonymousTracking: true, + onSessionUpdateCallback: mockOnSessionUpdateCallback, + }); + + tracker?.trackPageView(); + expect(mockOnSessionUpdateCallback).not.toHaveBeenCalled(); + }); + + it('properly calls onSessionUpdateCallback when newSession API is called', () => { + const mockOnSessionUpdateCallback = jest.fn(); + + const tracker = createTracker({ + contexts: { session: true }, + encodeBase64: false, + anonymousTracking: { withSessionTracking: true }, + onSessionUpdateCallback: mockOnSessionUpdateCallback, + }); + + tracker?.trackPageView(); + expect(mockOnSessionUpdateCallback).toHaveBeenCalledTimes(1); + tracker?.newSession(); + expect(mockOnSessionUpdateCallback).toHaveBeenCalledTimes(2); + }); + }); +}); diff --git a/libraries/browser-tracker-core/tsconfig.json b/libraries/browser-tracker-core/tsconfig.json new file mode 100644 index 000000000..3e6f62f51 --- /dev/null +++ b/libraries/browser-tracker-core/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "noImplicitThis": false /* Allows for guard to use 'this' */ + } +} diff --git a/libraries/tracker-core/CHANGELOG.json b/libraries/tracker-core/CHANGELOG.json new file mode 100644 index 000000000..c043608d9 --- /dev/null +++ b/libraries/tracker-core/CHANGELOG.json @@ -0,0 +1,725 @@ +{ + "name": "@snowplow/tracker-core", + "entries": [ + { + "version": "4.10.0", + "tag": "@snowplow/tracker-core_v4.10.0", + "date": "Mon, 27 Jul 2026 13:52:14 GMT", + "comments": {} + }, + { + "version": "4.9.0", + "tag": "@snowplow/tracker-core_v4.9.0", + "date": "Tue, 21 Jul 2026 14:53:08 GMT", + "comments": {} + }, + { + "version": "4.8.4", + "tag": "@snowplow/tracker-core_v4.8.4", + "date": "Thu, 02 Jul 2026 10:07:52 GMT", + "comments": {} + }, + { + "version": "4.8.3", + "tag": "@snowplow/tracker-core_v4.8.3", + "date": "Tue, 30 Jun 2026 14:22:03 GMT", + "comments": { + "none": [ + { + "comment": "Update uuid to v11 and remove closure-compiler from the build pipeline" + } + ] + } + }, + { + "version": "4.8.2", + "tag": "@snowplow/tracker-core_v4.8.2", + "date": "Wed, 17 Jun 2026 12:30:12 GMT", + "comments": {} + }, + { + "version": "4.8.1", + "tag": "@snowplow/tracker-core_v4.8.1", + "date": "Wed, 13 May 2026 09:26:05 GMT", + "comments": {} + }, + { + "version": "4.8.0", + "tag": "@snowplow/tracker-core_v4.8.0", + "date": "Tue, 28 Apr 2026 07:56:22 GMT", + "comments": {} + }, + { + "version": "4.7.0", + "tag": "@snowplow/tracker-core_v4.7.0", + "date": "Wed, 01 Apr 2026 12:59:29 GMT", + "comments": {} + }, + { + "version": "4.6.9", + "tag": "@snowplow/tracker-core_v4.6.9", + "date": "Mon, 16 Mar 2026 15:43:06 GMT", + "comments": {} + }, + { + "version": "4.6.8", + "tag": "@snowplow/tracker-core_v4.6.8", + "date": "Tue, 28 Oct 2025 09:46:42 GMT", + "comments": {} + }, + { + "version": "4.6.7", + "tag": "@snowplow/tracker-core_v4.6.7", + "date": "Tue, 07 Oct 2025 14:53:36 GMT", + "comments": {} + }, + { + "version": "4.6.6", + "tag": "@snowplow/tracker-core_v4.6.6", + "date": "Tue, 26 Aug 2025 08:42:28 GMT", + "comments": {} + }, + { + "version": "4.6.5", + "tag": "@snowplow/tracker-core_v4.6.5", + "date": "Wed, 25 Jun 2025 21:16:46 GMT", + "comments": {} + }, + { + "version": "4.6.4", + "tag": "@snowplow/tracker-core_v4.6.4", + "date": "Wed, 25 Jun 2025 12:08:50 GMT", + "comments": {} + }, + { + "version": "4.6.3", + "tag": "@snowplow/tracker-core_v4.6.3", + "date": "Thu, 29 May 2025 19:52:07 GMT", + "comments": {} + }, + { + "version": "4.6.2", + "tag": "@snowplow/tracker-core_v4.6.2", + "date": "Tue, 20 May 2025 07:39:05 GMT", + "comments": {} + }, + { + "version": "4.6.1", + "tag": "@snowplow/tracker-core_v4.6.1", + "date": "Tue, 06 May 2025 13:10:51 GMT", + "comments": {} + }, + { + "version": "4.6.0", + "tag": "@snowplow/tracker-core_v4.6.0", + "date": "Thu, 01 May 2025 09:58:59 GMT", + "comments": { + "none": [ + { + "comment": "Add `cookieExtensionService` argument as replacement for `idService`, deprecate `idService`" + } + ] + } + }, + { + "version": "4.5.0", + "tag": "@snowplow/tracker-core_v4.5.0", + "date": "Fri, 04 Apr 2025 09:21:23 GMT", + "comments": {} + }, + { + "version": "4.4.0", + "tag": "@snowplow/tracker-core_v4.4.0", + "date": "Thu, 20 Mar 2025 12:14:34 GMT", + "comments": {} + }, + { + "version": "4.3.1", + "tag": "@snowplow/tracker-core_v4.3.1", + "date": "Tue, 21 Jan 2025 11:09:42 GMT", + "comments": {} + }, + { + "version": "4.3.0", + "tag": "@snowplow/tracker-core_v4.3.0", + "date": "Mon, 20 Jan 2025 11:45:13 GMT", + "comments": {} + }, + { + "version": "4.2.0", + "tag": "@snowplow/tracker-core_v4.2.0", + "date": "Mon, 13 Jan 2025 08:30:05 GMT", + "comments": { + "none": [ + { + "comment": "Add new tracker for React Native (#1371)" + } + ] + } + }, + { + "version": "4.1.0", + "tag": "@snowplow/tracker-core_v4.1.0", + "date": "Thu, 28 Nov 2024 10:57:30 GMT", + "comments": {} + }, + { + "version": "4.0.4", + "tag": "@snowplow/tracker-core_v4.0.4", + "date": "Thu, 21 Nov 2024 09:06:36 GMT", + "comments": {} + }, + { + "version": "4.0.3", + "tag": "@snowplow/tracker-core_v4.0.3", + "date": "Wed, 20 Nov 2024 09:30:31 GMT", + "comments": {} + }, + { + "version": "4.0.2", + "tag": "@snowplow/tracker-core_v4.0.2", + "date": "Mon, 11 Nov 2024 15:46:34 GMT", + "comments": { + "none": [ + { + "comment": "Fix customPostPath configuration being ignored (close #1376)" + } + ] + } + }, + { + "version": "4.0.1", + "tag": "@snowplow/tracker-core_v4.0.1", + "date": "Fri, 01 Nov 2024 10:35:07 GMT", + "comments": { + "none": [ + { + "comment": "Fix broken API docs generation by adding explicit type for EventStoreIteratorNextResult" + } + ] + } + }, + { + "version": "4.0.0", + "tag": "@snowplow/tracker-core_v4.0.0", + "date": "Mon, 28 Oct 2024 11:48:53 GMT", + "comments": { + "none": [ + { + "comment": "Fix SelfDescribingJson type to allow optional keys in type parameter" + }, + { + "comment": "Add support for named global context" + }, + { + "comment": "Upgrade UUID to 8.3.2 (close #1138)" + }, + { + "comment": "Upgrade ava to @5" + }, + { + "comment": "Fix regression in SelfDescribingJson type from #1330" + }, + { + "comment": "Add an emitter and event store interface in the tracker core to be used both by the browser and node trackers and use fetch for making requests" + }, + { + "comment": "Add a filter function to plugins to filter out events so that they are not tracked (#1326)" + } + ] + } + }, + { + "version": "3.24.6", + "tag": "@snowplow/tracker-core_v3.24.6", + "date": "Mon, 28 Oct 2024 10:23:28 GMT", + "comments": {} + }, + { + "version": "3.24.5", + "tag": "@snowplow/tracker-core_v3.24.5", + "date": "Fri, 25 Oct 2024 08:53:04 GMT", + "comments": { + "none": [ + { + "comment": "Fix removal of global context generators" + } + ] + } + }, + { + "version": "3.24.4", + "tag": "@snowplow/tracker-core_v3.24.4", + "date": "Thu, 26 Sep 2024 06:10:22 GMT", + "comments": {} + }, + { + "version": "3.24.3", + "tag": "@snowplow/tracker-core_v3.24.3", + "date": "Tue, 03 Sep 2024 08:15:14 GMT", + "comments": { + "none": [ + { + "comment": "Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush" + } + ] + } + }, + { + "version": "3.24.2", + "tag": "@snowplow/tracker-core_v3.24.2", + "date": "Wed, 24 Jul 2024 08:59:00 GMT", + "comments": { + "none": [ + { + "comment": "Fix API docs CI action and update it's dependencies" + } + ] + } + }, + { + "version": "3.24.1", + "tag": "@snowplow/tracker-core_v3.24.1", + "date": "Tue, 02 Jul 2024 07:08:17 GMT", + "comments": {} + }, + { + "version": "3.24.0", + "tag": "@snowplow/tracker-core_v3.24.0", + "date": "Tue, 25 Jun 2024 08:31:05 GMT", + "comments": {} + }, + { + "version": "3.23.1", + "tag": "@snowplow/tracker-core_v3.23.1", + "date": "Tue, 04 Jun 2024 13:34:45 GMT", + "comments": {} + }, + { + "version": "3.23.0", + "tag": "@snowplow/tracker-core_v3.23.0", + "date": "Thu, 28 Mar 2024 11:28:45 GMT", + "comments": {} + }, + { + "version": "3.22.1", + "tag": "@snowplow/tracker-core_v3.22.1", + "date": "Wed, 13 Mar 2024 08:39:48 GMT", + "comments": {} + }, + { + "version": "3.22.0", + "tag": "@snowplow/tracker-core_v3.22.0", + "date": "Fri, 08 Mar 2024 08:13:04 GMT", + "comments": {} + }, + { + "version": "3.21.0", + "tag": "@snowplow/tracker-core_v3.21.0", + "date": "Mon, 29 Jan 2024 08:34:06 GMT", + "comments": {} + }, + { + "version": "3.20.0", + "tag": "@snowplow/tracker-core_v3.20.0", + "date": "Mon, 15 Jan 2024 14:41:16 GMT", + "comments": {} + }, + { + "version": "3.19.0", + "tag": "@snowplow/tracker-core_v3.19.0", + "date": "Thu, 14 Dec 2023 10:45:23 GMT", + "comments": {} + }, + { + "version": "3.18.0", + "tag": "@snowplow/tracker-core_v3.18.0", + "date": "Mon, 04 Dec 2023 13:44:02 GMT", + "comments": { + "none": [ + { + "comment": "Export 'removeEmptyProperties'" + } + ] + } + }, + { + "version": "3.17.0", + "tag": "@snowplow/tracker-core_v3.17.0", + "date": "Tue, 14 Nov 2023 17:58:26 GMT", + "comments": { + "none": [ + { + "comment": "Add CommonEventProperties type argument" + } + ] + } + }, + { + "version": "3.16.0", + "tag": "@snowplow/tracker-core_v3.16.0", + "date": "Mon, 16 Oct 2023 14:58:08 GMT", + "comments": {} + }, + { + "version": "3.15.0", + "tag": "@snowplow/tracker-core_v3.15.0", + "date": "Mon, 28 Aug 2023 14:25:14 GMT", + "comments": {} + }, + { + "version": "3.14.0", + "tag": "@snowplow/tracker-core_v3.14.0", + "date": "Thu, 10 Aug 2023 13:56:44 GMT", + "comments": {} + }, + { + "version": "3.13.1", + "tag": "@snowplow/tracker-core_v3.13.1", + "date": "Thu, 29 Jun 2023 14:20:06 GMT", + "comments": {} + }, + { + "version": "3.13.0", + "tag": "@snowplow/tracker-core_v3.13.0", + "date": "Tue, 20 Jun 2023 07:44:23 GMT", + "comments": {} + }, + { + "version": "3.12.1", + "tag": "@snowplow/tracker-core_v3.12.1", + "date": "Thu, 15 Jun 2023 10:05:37 GMT", + "comments": {} + }, + { + "version": "3.12.0", + "tag": "@snowplow/tracker-core_v3.12.0", + "date": "Mon, 05 Jun 2023 11:51:22 GMT", + "comments": {} + }, + { + "version": "3.11.0", + "tag": "@snowplow/tracker-core_v3.11.0", + "date": "Wed, 24 May 2023 15:56:17 GMT", + "comments": { + "none": [ + { + "comment": "Make addPayloadPair more lenient with 'uknown' type" + } + ] + } + }, + { + "version": "3.10.1", + "tag": "@snowplow/tracker-core_v3.10.1", + "date": "Fri, 12 May 2023 06:59:31 GMT", + "comments": {} + }, + { + "version": "3.10.0", + "tag": "@snowplow/tracker-core_v3.10.0", + "date": "Thu, 11 May 2023 08:29:15 GMT", + "comments": {} + }, + { + "version": "3.9.0", + "tag": "@snowplow/tracker-core_v3.9.0", + "date": "Thu, 30 Mar 2023 13:46:56 GMT", + "comments": { + "none": [ + { + "comment": "Fix flaky end-to-end tests (#1152)" + } + ] + } + }, + { + "version": "3.8.0", + "tag": "@snowplow/tracker-core_v3.8.0", + "date": "Tue, 03 Jan 2023 15:36:33 GMT", + "comments": {} + }, + { + "version": "3.7.0", + "tag": "@snowplow/tracker-core_v3.7.0", + "date": "Mon, 31 Oct 2022 06:26:28 GMT", + "comments": {} + }, + { + "version": "3.6.0", + "tag": "@snowplow/tracker-core_v3.6.0", + "date": "Thu, 15 Sep 2022 07:55:20 GMT", + "comments": { + "none": [ + { + "comment": "Add tests verifying that the track method returns event id (eid) in the payload (#1098)" + } + ] + } + }, + { + "version": "3.5.0", + "tag": "@snowplow/tracker-core_v3.5.0", + "date": "Fri, 10 Jun 2022 18:57:46 GMT", + "comments": { + "none": [ + { + "comment": "Add client session context entity (#1077)" + } + ] + } + }, + { + "version": "3.4.0", + "tag": "@snowplow/tracker-core_v3.4.0", + "date": "Thu, 07 Apr 2022 11:56:26 GMT", + "comments": { + "none": [ + { + "comment": "Bump dependencies (#1067)" + } + ] + } + }, + { + "version": "3.3.1", + "tag": "@snowplow/tracker-core_v3.3.1", + "date": "Wed, 23 Feb 2022 19:27:40 GMT", + "comments": { + "none": [ + { + "comment": "Stop mutating context array with additional plugin contexts (#1061)" + } + ] + } + }, + { + "version": "3.3.0", + "tag": "@snowplow/tracker-core_v3.3.0", + "date": "Mon, 31 Jan 2022 15:58:10 GMT", + "comments": {} + }, + { + "version": "3.2.3", + "tag": "@snowplow/tracker-core_v3.2.3", + "date": "Tue, 18 Jan 2022 16:23:52 GMT", + "comments": { + "none": [ + { + "comment": "Bump Copyright to 2022 (#1040)" + } + ] + } + }, + { + "version": "3.2.2", + "tag": "@snowplow/tracker-core_v3.2.2", + "date": "Fri, 14 Jan 2022 10:17:59 GMT", + "comments": {} + }, + { + "version": "3.2.1", + "tag": "@snowplow/tracker-core_v3.2.1", + "date": "Wed, 12 Jan 2022 09:50:29 GMT", + "comments": {} + }, + { + "version": "3.2.0", + "tag": "@snowplow/tracker-core_v3.2.0", + "date": "Tue, 11 Jan 2022 12:53:22 GMT", + "comments": {} + }, + { + "version": "3.1.6", + "tag": "@snowplow/tracker-core_v3.1.6", + "date": "Tue, 19 Oct 2021 09:17:22 GMT", + "comments": { + "none": [ + { + "comment": "Fix failing build on ARM Macs (#1012)" + } + ] + } + }, + { + "version": "3.1.5", + "tag": "@snowplow/tracker-core_v3.1.5", + "date": "Fri, 01 Oct 2021 08:09:21 GMT", + "comments": { + "none": [ + { + "comment": "Fix removeGlobalContexts not removing expected context (#1006)" + } + ] + } + }, + { + "version": "3.1.4", + "tag": "@snowplow/tracker-core_v3.1.4", + "date": "Tue, 21 Sep 2021 14:59:36 GMT", + "comments": {} + }, + { + "version": "3.1.3", + "tag": "@snowplow/tracker-core_v3.1.3", + "date": "Mon, 23 Aug 2021 10:13:18 GMT", + "comments": {} + }, + { + "version": "3.1.2", + "tag": "@snowplow/tracker-core_v3.1.2", + "date": "Mon, 16 Aug 2021 12:59:59 GMT", + "comments": { + "none": [ + { + "comment": "Update READMEs with correct Node requirements (#994)" + } + ] + } + }, + { + "version": "3.1.1", + "tag": "@snowplow/tracker-core_v3.1.1", + "date": "Wed, 04 Aug 2021 10:12:25 GMT", + "comments": { + "none": [ + { + "comment": "Automate api-extractor on release (#972)" + }, + { + "comment": "Bump tslib to 2.3.0 (#986)" + }, + { + "comment": "Bump typescript to 4.3.5 (#987)" + }, + { + "comment": "Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988)" + } + ] + } + }, + { + "version": "3.1.0", + "tag": "@snowplow/tracker-core_v3.1.0", + "date": "Fri, 14 May 2021 10:45:32 GMT", + "comments": {} + }, + { + "version": "3.0.3", + "tag": "@snowplow/tracker-core_v3.0.3", + "date": "Wed, 21 Apr 2021 12:35:06 GMT", + "comments": {} + }, + { + "version": "3.0.2", + "tag": "@snowplow/tracker-core_v3.0.2", + "date": "Thu, 15 Apr 2021 21:07:39 GMT", + "comments": {} + }, + { + "version": "3.0.1", + "tag": "@snowplow/tracker-core_v3.0.1", + "date": "Wed, 14 Apr 2021 16:30:05 GMT", + "comments": { + "none": [ + { + "comment": "Fix types on buildPageView in tracker-core (#947)" + }, + { + "comment": "Mark packages as sideEffect: false (#951)" + }, + { + "comment": "Add unit tests to plugin track* functions (#954)" + } + ] + } + }, + { + "version": "3.0.0", + "tag": "@snowplow/tracker-core_v3.0.0", + "date": "Wed, 31 Mar 2021 14:46:47 GMT", + "comments": { + "none": [ + { + "comment": "Allow plugins to be dynamically loaded when using tracker (#918)" + }, + { + "comment": "Add debug mode (#381)" + }, + { + "comment": "Include @snowplow/node-tracker in monorepo (close #931)" + }, + { + "comment": "Bump uuid to 3.4.0 (close #915)" + }, + { + "comment": "Bump rollup to 2.41 (#916)" + }, + { + "comment": "Prevent base64 encoder being bundled into each plugin (#921)" + }, + { + "comment": "Ensure browser-tracker API methods catch exceptions (#919)" + }, + { + "comment": "Introduce TSDoc comments and extract interfaces where appropriate (#906)" + }, + { + "comment": "Bump major version to v3 and update READMEs (#904)" + }, + { + "comment": "Improve Core API for module bundlers which support treeshaking (#903)" + }, + { + "comment": "Rename @snowplow/browser-core to @snowplow/browser-tracker-core (#901)" + }, + { + "comment": "Publish lite version of sp.js (#900)" + }, + { + "comment": "Ensure correct 3-Clause BSD License notices are being used (#316)" + }, + { + "comment": "Improve API for module bundlers which support treeshaking (#899)" + }, + { + "comment": "Bump rush to 5.39 (#895)" + }, + { + "comment": "Port to TypeScript (#72)" + }, + { + "comment": "Make sp.js build process modular (#450)" + }, + { + "comment": "Create @snowplow/browser-tracker package for npm distribution (#541)" + }, + { + "comment": "Split auto contexts into plugins (#880)" + }, + { + "comment": "Add rush to manage monorepo (#883)" + }, + { + "comment": "Add ES Module builds (#882)" + }, + { + "comment": "Cleanup deprecated methods (#557)" + }, + { + "comment": "Update publishing process for rush (#907)" + }, + { + "comment": "Change white and black lists to allow and deny lists (#908)" + }, + { + "comment": "Create rush change files for major version 3 release (#909)" + }, + { + "comment": "[tracker-core] Don't overwrite custom user defined event id (#911)" + } + ] + } + } + ] +} diff --git a/libraries/tracker-core/CHANGELOG.md b/libraries/tracker-core/CHANGELOG.md new file mode 100644 index 000000000..a129f02ef --- /dev/null +++ b/libraries/tracker-core/CHANGELOG.md @@ -0,0 +1,478 @@ +# Change Log - @snowplow/tracker-core + +This log was last generated on Mon, 27 Jul 2026 13:52:14 GMT and should not be manually modified. + +## 4.10.0 +Mon, 27 Jul 2026 13:52:14 GMT + +_Version update only_ + +## 4.9.0 +Tue, 21 Jul 2026 14:53:08 GMT + +_Version update only_ + +## 4.8.4 +Thu, 02 Jul 2026 10:07:52 GMT + +_Version update only_ + +## 4.8.3 +Tue, 30 Jun 2026 14:22:03 GMT + +### Updates + +- Update uuid to v11 and remove closure-compiler from the build pipeline + +## 4.8.2 +Wed, 17 Jun 2026 12:30:12 GMT + +_Version update only_ + +## 4.8.1 +Wed, 13 May 2026 09:26:05 GMT + +_Version update only_ + +## 4.8.0 +Tue, 28 Apr 2026 07:56:22 GMT + +_Version update only_ + +## 4.7.0 +Wed, 01 Apr 2026 12:59:29 GMT + +_Version update only_ + +## 4.6.9 +Mon, 16 Mar 2026 15:43:06 GMT + +_Version update only_ + +## 4.6.8 +Tue, 28 Oct 2025 09:46:42 GMT + +_Version update only_ + +## 4.6.7 +Tue, 07 Oct 2025 14:53:36 GMT + +_Version update only_ + +## 4.6.6 +Tue, 26 Aug 2025 08:42:28 GMT + +_Version update only_ + +## 4.6.5 +Wed, 25 Jun 2025 21:16:46 GMT + +_Version update only_ + +## 4.6.4 +Wed, 25 Jun 2025 12:08:50 GMT + +_Version update only_ + +## 4.6.3 +Thu, 29 May 2025 19:52:07 GMT + +_Version update only_ + +## 4.6.2 +Tue, 20 May 2025 07:39:05 GMT + +_Version update only_ + +## 4.6.1 +Tue, 06 May 2025 13:10:51 GMT + +_Version update only_ + +## 4.6.0 +Thu, 01 May 2025 09:58:59 GMT + +### Updates + +- Add `cookieExtensionService` argument as replacement for `idService`, deprecate `idService` + +## 4.5.0 +Fri, 04 Apr 2025 09:21:23 GMT + +_Version update only_ + +## 4.4.0 +Thu, 20 Mar 2025 12:14:34 GMT + +_Version update only_ + +## 4.3.1 +Tue, 21 Jan 2025 11:09:42 GMT + +_Version update only_ + +## 4.3.0 +Mon, 20 Jan 2025 11:45:13 GMT + +_Version update only_ + +## 4.2.0 +Mon, 13 Jan 2025 08:30:05 GMT + +### Updates + +- Add new tracker for React Native (#1371) + +## 4.1.0 +Thu, 28 Nov 2024 10:57:30 GMT + +_Version update only_ + +## 4.0.4 +Thu, 21 Nov 2024 09:06:36 GMT + +_Version update only_ + +## 4.0.3 +Wed, 20 Nov 2024 09:30:31 GMT + +_Version update only_ + +## 4.0.2 +Mon, 11 Nov 2024 15:46:34 GMT + +### Updates + +- Fix customPostPath configuration being ignored (close #1376) + +## 4.0.1 +Fri, 01 Nov 2024 10:35:07 GMT + +### Updates + +- Fix broken API docs generation by adding explicit type for EventStoreIteratorNextResult + +## 4.0.0 +Mon, 28 Oct 2024 11:48:53 GMT + +### Updates + +- Fix SelfDescribingJson type to allow optional keys in type parameter +- Add support for named global context +- Upgrade UUID to 8.3.2 (close #1138) +- Upgrade ava to @5 +- Fix regression in SelfDescribingJson type from #1330 +- Add an emitter and event store interface in the tracker core to be used both by the browser and node trackers and use fetch for making requests +- Add a filter function to plugins to filter out events so that they are not tracked (#1326) + +## 3.24.6 +Mon, 28 Oct 2024 10:23:28 GMT + +_Version update only_ + +## 3.24.5 +Fri, 25 Oct 2024 08:53:04 GMT + +### Updates + +- Fix removal of global context generators + +## 3.24.4 +Thu, 26 Sep 2024 06:10:22 GMT + +_Version update only_ + +## 3.24.3 +Tue, 03 Sep 2024 08:15:14 GMT + +### Updates + +- Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush + +## 3.24.2 +Wed, 24 Jul 2024 08:59:00 GMT + +### Updates + +- Fix API docs CI action and update it's dependencies + +## 3.24.1 +Tue, 02 Jul 2024 07:08:17 GMT + +_Version update only_ + +## 3.24.0 +Tue, 25 Jun 2024 08:31:05 GMT + +_Version update only_ + +## 3.23.1 +Tue, 04 Jun 2024 13:34:45 GMT + +_Version update only_ + +## 3.23.0 +Thu, 28 Mar 2024 11:28:45 GMT + +_Version update only_ + +## 3.22.1 +Wed, 13 Mar 2024 08:39:48 GMT + +_Version update only_ + +## 3.22.0 +Fri, 08 Mar 2024 08:13:04 GMT + +_Version update only_ + +## 3.21.0 +Mon, 29 Jan 2024 08:34:06 GMT + +_Version update only_ + +## 3.20.0 +Mon, 15 Jan 2024 14:41:16 GMT + +_Version update only_ + +## 3.19.0 +Thu, 14 Dec 2023 10:45:23 GMT + +_Version update only_ + +## 3.18.0 +Mon, 04 Dec 2023 13:44:02 GMT + +### Updates + +- Export 'removeEmptyProperties' + +## 3.17.0 +Tue, 14 Nov 2023 17:58:26 GMT + +### Updates + +- Add CommonEventProperties type argument + +## 3.16.0 +Mon, 16 Oct 2023 14:58:08 GMT + +_Version update only_ + +## 3.15.0 +Mon, 28 Aug 2023 14:25:14 GMT + +_Version update only_ + +## 3.14.0 +Thu, 10 Aug 2023 13:56:44 GMT + +_Version update only_ + +## 3.13.1 +Thu, 29 Jun 2023 14:20:06 GMT + +_Version update only_ + +## 3.13.0 +Tue, 20 Jun 2023 07:44:23 GMT + +_Version update only_ + +## 3.12.1 +Thu, 15 Jun 2023 10:05:37 GMT + +_Version update only_ + +## 3.12.0 +Mon, 05 Jun 2023 11:51:22 GMT + +_Version update only_ + +## 3.11.0 +Wed, 24 May 2023 15:56:17 GMT + +### Updates + +- Make addPayloadPair more lenient with 'uknown' type + +## 3.10.1 +Fri, 12 May 2023 06:59:31 GMT + +_Version update only_ + +## 3.10.0 +Thu, 11 May 2023 08:29:15 GMT + +_Version update only_ + +## 3.9.0 +Thu, 30 Mar 2023 13:46:56 GMT + +### Updates + +- Fix flaky end-to-end tests (#1152) + +## 3.8.0 +Tue, 03 Jan 2023 15:36:33 GMT + +_Version update only_ + +## 3.7.0 +Mon, 31 Oct 2022 06:26:28 GMT + +_Version update only_ + +## 3.6.0 +Thu, 15 Sep 2022 07:55:20 GMT + +### Updates + +- Add tests verifying that the track method returns event id (eid) in the payload (#1098) + +## 3.5.0 +Fri, 10 Jun 2022 18:57:46 GMT + +### Updates + +- Add client session context entity (#1077) + +## 3.4.0 +Thu, 07 Apr 2022 11:56:26 GMT + +### Updates + +- Bump dependencies (#1067) + +## 3.3.1 +Wed, 23 Feb 2022 19:27:40 GMT + +### Updates + +- Stop mutating context array with additional plugin contexts (#1061) + +## 3.3.0 +Mon, 31 Jan 2022 15:58:10 GMT + +_Version update only_ + +## 3.2.3 +Tue, 18 Jan 2022 16:23:52 GMT + +### Updates + +- Bump Copyright to 2022 (#1040) + +## 3.2.2 +Fri, 14 Jan 2022 10:17:59 GMT + +_Version update only_ + +## 3.2.1 +Wed, 12 Jan 2022 09:50:29 GMT + +_Version update only_ + +## 3.2.0 +Tue, 11 Jan 2022 12:53:22 GMT + +_Version update only_ + +## 3.1.6 +Tue, 19 Oct 2021 09:17:22 GMT + +### Updates + +- Fix failing build on ARM Macs (#1012) + +## 3.1.5 +Fri, 01 Oct 2021 08:09:21 GMT + +### Updates + +- Fix removeGlobalContexts not removing expected context (#1006) + +## 3.1.4 +Tue, 21 Sep 2021 14:59:36 GMT + +_Version update only_ + +## 3.1.3 +Mon, 23 Aug 2021 10:13:18 GMT + +_Version update only_ + +## 3.1.2 +Mon, 16 Aug 2021 12:59:59 GMT + +### Updates + +- Update READMEs with correct Node requirements (#994) + +## 3.1.1 +Wed, 04 Aug 2021 10:12:25 GMT + +### Updates + +- Automate api-extractor on release (#972) +- Bump tslib to 2.3.0 (#986) +- Bump typescript to 4.3.5 (#987) +- Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988) + +## 3.1.0 +Fri, 14 May 2021 10:45:32 GMT + +_Version update only_ + +## 3.0.3 +Wed, 21 Apr 2021 12:35:06 GMT + +_Version update only_ + +## 3.0.2 +Thu, 15 Apr 2021 21:07:39 GMT + +_Version update only_ + +## 3.0.1 +Wed, 14 Apr 2021 16:30:05 GMT + +### Updates + +- Fix types on buildPageView in tracker-core (#947) +- Mark packages as sideEffect: false (#951) +- Add unit tests to plugin track* functions (#954) + +## 3.0.0 +Wed, 31 Mar 2021 14:46:47 GMT + +### Updates + +- Allow plugins to be dynamically loaded when using tracker (#918) +- Add debug mode (#381) +- Include @snowplow/node-tracker in monorepo (close #931) +- Bump uuid to 3.4.0 (close #915) +- Bump rollup to 2.41 (#916) +- Prevent base64 encoder being bundled into each plugin (#921) +- Ensure browser-tracker API methods catch exceptions (#919) +- Introduce TSDoc comments and extract interfaces where appropriate (#906) +- Bump major version to v3 and update READMEs (#904) +- Improve Core API for module bundlers which support treeshaking (#903) +- Rename @snowplow/browser-core to @snowplow/browser-tracker-core (#901) +- Publish lite version of sp.js (#900) +- Ensure correct 3-Clause BSD License notices are being used (#316) +- Improve API for module bundlers which support treeshaking (#899) +- Bump rush to 5.39 (#895) +- Port to TypeScript (#72) +- Make sp.js build process modular (#450) +- Create @snowplow/browser-tracker package for npm distribution (#541) +- Split auto contexts into plugins (#880) +- Add rush to manage monorepo (#883) +- Add ES Module builds (#882) +- Cleanup deprecated methods (#557) +- Update publishing process for rush (#907) +- Change white and black lists to allow and deny lists (#908) +- Create rush change files for major version 3 release (#909) +- [tracker-core] Don't overwrite custom user defined event id (#911) + diff --git a/libraries/tracker-core/CLAUDE.md b/libraries/tracker-core/CLAUDE.md new file mode 100644 index 000000000..02de6dc77 --- /dev/null +++ b/libraries/tracker-core/CLAUDE.md @@ -0,0 +1,384 @@ +# Tracker Core Library - CLAUDE.md + +## Module Overview + +The `@snowplow/tracker-core` library provides platform-agnostic event tracking functionality. It contains the fundamental building blocks for constructing Snowplow events, managing contexts, and handling payloads. This is the foundation that all platform-specific trackers build upon. + +## Core Responsibilities + +- **Event Builders**: Functions to construct typed Snowplow events +- **Payload Management**: JSON and form-encoded payload construction +- **Context Handling**: Global and conditional context providers +- **Plugin System**: Core plugin architecture and lifecycle +- **Emitter Logic**: Event batching and request management + +## Architecture Patterns + +### Event Builder Pattern +All events follow a consistent builder pattern that returns a `PayloadBuilder`: + +```typescript +// ✅ Correct: Use typed builders +export function buildPageView(event: PageViewEvent): PayloadBuilder { + const { pageUrl, pageTitle, referrer } = event; + return payloadBuilder() + .add('e', 'pv') + .add('url', pageUrl) + .add('page', pageTitle) + .add('refr', referrer); +} + +// ❌ Wrong: Manual payload construction +function makePageView(url: string) { + return { e: 'pv', url }; // Don't build manually +} +``` + +### Self-Describing JSON Pattern +```typescript +// ✅ Correct: Strongly typed SDJ +export type SelfDescribingJson> = { + schema: string; + data: T extends any[] ? never : T; +}; + +// ❌ Wrong: Loose typing +type Event = { schema: any; data: any }; +``` + +### Timestamp ADT Pattern +```typescript +// ✅ Correct: Use discriminated union +export type Timestamp = TrueTimestamp | DeviceTimestamp | number; +export interface TrueTimestamp { + readonly type: 'ttm'; + readonly value: number; +} + +// ❌ Wrong: Ambiguous timestamp types +type Timestamp = number | { value: number }; +``` + +## Critical Import Patterns + +### Public API Exports +```typescript +// index.ts - Centralized exports +export * from './core'; +export * from './contexts'; +export * from './payload'; +export * from './emitter'; +export * from './plugins'; +export { buildPageView, buildStructEvent } from './events'; +``` + +### Internal Module Structure +```typescript +// ✅ Correct: Import from sibling modules +import { PayloadBuilder } from './payload'; +import { SelfDescribingJson } from './core'; + +// ❌ Wrong: Circular dependencies +import { something } from '../index'; // Avoid +``` + +## Event Building Standards + +### Standard Event Properties +```typescript +// Every event builder should accept CommonEventProperties +export interface CommonEventProperties> { + context?: Array> | null; + timestamp?: Timestamp | null; +} +``` + +### Event Factory Pattern +```typescript +// Standard event builder structure +export function buildCustomEvent( + event: CustomEventData +): PayloadBuilder { + return payloadBuilder() + .add('e', 'ue') // Event type + .addJson('ue_px', 'ue_pr', { + schema: EVENT_SCHEMA, + data: processEventData(event) + }); +} +``` + +## Context Management + +### Global Context Pattern +```typescript +// ✅ Correct: Conditional context provider +export type ConditionalContextProvider = + [ContextFilter, ContextPrimitive | ContextGenerator]; + +const globalContext: ConditionalContextProvider = [ + (event) => event.eventType === 'pv', // Filter + { schema: '...', data: {...} } // Context +]; + +// ❌ Wrong: Unfiltered global contexts +const context = { schema: '...', data: {...} }; // No filtering +``` + +### Plugin Context Integration +```typescript +// Plugin contexts are merged with global contexts +export function pluginContexts(): PluginContexts { + return { + addPluginContexts: (contexts: Array) => { + // Contexts added by plugins + } + }; +} +``` + +## Emitter Architecture + +### Event Store Pattern +```typescript +// Event storage abstraction +export interface EventStore { + add(payload: EventStorePayload): Promise; + count(): Promise; + getAll(): Promise; + removeHead(count: number): Promise; +} +``` + +### Request Building +```typescript +// Batch request construction +export class EmitterRequest { + constructor( + events: EmitterEvent[], + byteLimit: number + ) { + this.batch = this.buildBatch(events, byteLimit); + } +} +``` + +## Common Patterns + +### UUID Generation +```typescript +// ✅ Correct: Use uuid v4 +import { v4 as uuid } from 'uuid'; +const eventId = uuid(); + +// ❌ Wrong: Custom ID generation +const id = Math.random().toString(36); +``` + +### Base64 Encoding +```typescript +// Use the provided base64 utilities +import { base64urlencode } from './base64'; +const encoded = base64urlencode(jsonString); +``` + +### Logger Pattern +```typescript +// Conditional logging +import { LOG } from './logger'; +LOG.error('Error message', error); +LOG.warn('Warning message'); +``` + +## Testing Patterns + +### Mock Payload Builders +```typescript +// Test helper pattern +function createMockPayloadBuilder(): PayloadBuilder { + return payloadBuilder() + .add('aid', 'test-app') + .add('p', 'web'); +} +``` + +### Event Validation +```typescript +// Validate event structure in tests +expect(event.build()).toMatchObject({ + e: 'ue', + ue_pr: expect.stringContaining('schema') +}); +``` + +## Testing Patterns + +### Test Directory Structure +``` +test/ +├── core.test.ts # Core tracker tests +├── payload.test.ts # Payload builder tests +├── contexts.test.ts # Context management tests +├── emitter/ # Emitter-specific tests +└── __snapshots__/ # Jest snapshots +``` + +### In-Memory Event Store Pattern +```typescript +// ✅ Correct: Use in-memory store for testing +import { newInMemoryEventStore } from '@snowplow/tracker-core'; + +describe('Event tracking', () => { + let eventStore: EventStore; + + beforeEach(() => { + eventStore = newInMemoryEventStore(); + }); + + it('stores events correctly', () => { + const tracker = new TrackerCore({ eventStore }); + tracker.track(buildPageView({ pageUrl: 'test' })); + + const events = eventStore.getEvents(); + expect(events).toHaveLength(1); + expect(events[0].e).toBe('pv'); + }); +}); +``` + +### Payload Builder Testing +```typescript +// ✅ Correct: Test payload construction +describe('PayloadBuilder', () => { + it('builds valid Snowplow payload', () => { + const payload = new PayloadBuilder() + .add('e', 'pv') + .add('url', 'http://example.com') + .add('page', 'Home') + .build(); + + expect(payload).toEqual({ + e: 'pv', + url: 'http://example.com', + page: 'Home' + }); + }); + + it('encodes base64 for self-describing events', () => { + const payload = buildSelfDescribingEvent({ + event: { + schema: 'iglu:com.example/test/jsonschema/1-0-0', + data: { key: 'value' } + } + }); + + const built = payload.build(); + expect(built.ue_pr).toBeDefined(); + const decoded = JSON.parse(Buffer.from(built.ue_pr, 'base64').toString()); + expect(decoded.data.schema).toBe('iglu:com.example/test/jsonschema/1-0-0'); + }); +}); +``` + +### Context Testing +```typescript +// ✅ Correct: Test context providers +describe('Context management', () => { + it('adds global contexts to events', () => { + const contextProvider = () => [{ + schema: 'iglu:com.example/context/jsonschema/1-0-0', + data: { contextKey: 'contextValue' } + }]; + + const tracker = new TrackerCore({ + contextProviders: [contextProvider] + }); + + const payload = tracker.track(buildPageView({ pageUrl: 'test' })); + const contexts = JSON.parse(Buffer.from(payload.co, 'base64').toString()); + + expect(contexts.data).toContainEqual( + expect.objectContaining({ + data: { contextKey: 'contextValue' } + }) + ); + }); +}); +``` + +### Event Builder Testing Pattern +```typescript +// ✅ Correct: Test custom event builders +function buildCustomEvent(data: CustomEventData): PayloadBuilder { + return new PayloadBuilder() + .add('e', 'ue') + .add('ue_pr', buildSelfDescribingJson({ + schema: CUSTOM_EVENT_SCHEMA, + data + })); +} + +describe('Custom event builder', () => { + it('creates valid self-describing event', () => { + const event = buildCustomEvent({ field: 'value' }); + const payload = event.build(); + + expect(payload.e).toBe('ue'); + expect(JSON.parse(Buffer.from(payload.ue_pr, 'base64').toString())) + .toMatchSnapshot(); + }); +}); +``` + +## File Organization + +``` +tracker-core/ +├── src/ +│ ├── index.ts # Public API exports +│ ├── core.ts # Core types and tracker +│ ├── payload.ts # Payload builder +│ ├── contexts.ts # Context management +│ ├── plugins.ts # Plugin system +│ ├── base64.ts # Encoding utilities +│ ├── logger.ts # Logging +│ ├── schemata.ts # Schema constants +│ └── emitter/ +│ ├── index.ts # Emitter exports +│ ├── emitter_event.ts +│ └── emitter_request.ts +└── test/ + └── [module].test.ts +``` + +## Quick Reference + +### Essential Imports +```typescript +import { + PayloadBuilder, + SelfDescribingJson, + CommonEventProperties, + buildSelfDescribingEvent, + buildPageView, + buildStructEvent, + TrackerCore +} from '@snowplow/tracker-core'; +``` + +### Event Builder Checklist +- [ ] Accept event-specific data interface +- [ ] Return `PayloadBuilder` +- [ ] Add event type with `.add('e', 'type')` +- [ ] Handle optional CommonEventProperties +- [ ] Export from index.ts + +## Contributing to CLAUDE.md + +When modifying tracker-core patterns: + +1. **Maintain backward compatibility** - This is a core library +2. **Update type exports** when adding new interfaces +3. **Follow builder pattern** for new event types +4. **Test payload structure** thoroughly +5. **Document schema changes** in schemata.ts \ No newline at end of file diff --git a/libraries/tracker-core/LICENSE b/libraries/tracker-core/LICENSE new file mode 100644 index 000000000..76f1946ea --- /dev/null +++ b/libraries/tracker-core/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/libraries/tracker-core/README.md b/libraries/tracker-core/README.md new file mode 100644 index 000000000..962810fff --- /dev/null +++ b/libraries/tracker-core/README.md @@ -0,0 +1,179 @@ +# Snowplow Tracker Core + +[![npm version][npm-image]][npm-url] +[![License][license-image]](LICENSE) + +Core module to be used by Snowplow JavaScript based trackers. + +## Maintainer quick start + +Part of the Snowplow JavaScript Tracker monorepo. +Build with [Node.js](https://nodejs.org/en/) (18 - 20) and [Rush](https://rushjs.io/). + +### Setup repository + +```bash +npm install -g @microsoft/rush +git clone https://github.com/snowplow/snowplow-javascript-tracker.git +rush update +``` + +### Building Tracker Core + +```bash +cd libraries/tracker-core +rushx build +``` + +### Running tests + +```bash +rushx test +``` + +## Package Installation + +With npm: + +```bash +npm install @snowplow/tracker-core +``` + +## Usage + +### CommonJS Example + +```js +const trackerCore = require('@snowplow/tracker-core').trackerCore; + +// Create an instance with base 64 encoding set to false (it defaults to true) +const core = trackerCore({ + base64: false +}); +``` + +### ES Module Example + +```js +import { trackerCore } from '@snowplow/tracker-core'; + +// Create an instance with base 64 encoding set to false (it defaults to true) +const core = trackerCore({ + base64: false +}) +``` + +### Example + +```js +// Add a name-value pair to all payloads +core.addPayloadPair('vid', 2); + +// Add each name-value pair in a dictionary to all payloads +core.addPayloadDict({ + 'ds': '1160x620', + 'fp': 4070134789 +}); + +// Add name-value pairs to all payloads using convenience methods +core.setTrackerVersion('js-3.6.0'); +core.setPlatform('web'); +core.setUserId('user-321'); +core.setColorDepth('24'); +core.setViewport('600', '400'); +core.setUseragent('Snowplow/0.0.1'); + +// Track a page view with URL and title +const pageViewPayload = core.track( + buildPageView({ + pageUrl: 'http://www.example.com', + pageTitle: 'landing page', + }) +); + +console.log(pageViewPayload); +/* +{ + 'e': 'pv', + 'url': 'http://www.example.com', + 'page': 'landing page', + 'uid': 'user-321', + 'vid': 2, + 'ds': '1160x620', + 'fp': 4070134789, + 'tv': 'js-3.6.0', + 'p': 'web', + 'cd': '24', + 'vp': '600x400', + 'ua': 'Snowplow/0.0.1', + 'dtm': '1406879959702', // timestamp + 'eid': 'cd39f493-dd3c-4838-b096-6e6f31015409' // UUID +} +*/ + +// Stop automatically adding tv, p, and dtm to the payload. +core.resetPayloadPairs({}); + +// Track an unstructured event +const selfDescribingEventPayload = core.track( + buildSelfDescribingEvent({ + event: { + 'schema': 'iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-0', + 'data': { + 'targetUrl': 'http://www.destination.com', + 'elementId': 'bannerLink' + } + } + }) +); + +console.log(selfDescribingEventPayload); +/* +{ + 'e': 'ue', + 'eid': '4ed5da6b-7fff-4f24-a8a9-21bc749881c6', + 'dtm': '1659086693634', + 'ue_pr': "{\"schema\":\"iglu:com.snowplowanalytics.snowplow/unstruct_event/jsonschema/1-0-0\",\"data\":{\"schema\":\"iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-0\",\"data\":{\"targetUrl\":\"http://www.destination.com\",\"elementId\":\"bannerLink\"}}}" +} +*/ +``` + +## Other features + +Core instances can be initialized with a configuration object. `base64` Determines whether custom contexts and unstructured events will be base 64 encoded. `corePlugins` are used to intercept payload creation and add contexts on every event. `callback` is an optional callback function which gets applied to every payload created by the instance. + +```js +const core = trackerCore({ + base64: true, + corePlugins: [/* Your plugins here*/], + callback: console.log +}); +``` + +The above example would base 64 encode all unstructured events and custom contexts and would log each payload to the console. + +Use the `setBase64Encoding` method to turn base 64 encoding on or off after initializing a core instance: + +```js +const core = trackerCore(); // Base 64 encoding on by default + +core.setBase64Encoding(false); // Base 64 encoding is now off +``` + +## Documentation + +For more information on the Snowplow JavaScript Tracker Core's API, view its [docs page][docs]. + +## Copyright and license + +Licensed and distributed under the [BSD 3-Clause License](LICENSE) ([An OSI Approved License][osi]). + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang. + +All rights reserved. + +[npm-url]: https://www.npmjs.com/package/@snowplow/tracker-core +[npm-image]: https://img.shields.io/npm/v/@snowplow/tracker-core +[docs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/node-js-tracker/javascript-tracker-core/ +[osi]: https://opensource.org/licenses/BSD-3-Clause +[license-image]: https://img.shields.io/npm/l/@snowplow/tracker-core diff --git a/libraries/tracker-core/package.json b/libraries/tracker-core/package.json new file mode 100644 index 000000000..2144f8c4c --- /dev/null +++ b/libraries/tracker-core/package.json @@ -0,0 +1,68 @@ +{ + "name": "@snowplow/tracker-core", + "version": "4.10.0", + "description": "Core functionality for Snowplow JavaScript trackers", + "keywords": [ + "tracking", + "web analytics", + "events", + "open source" + ], + "homepage": "http://bit.ly/sp-js", + "bugs": "https://github.com/snowplow/snowplow-javascript-tracker/issues", + "repository": { + "type": "git", + "url": "https://github.com/snowplow/snowplow-javascript-tracker.git" + }, + "license": "BSD-3-Clause", + "contributors": [ + "Alex Dean", + "Simon Andersson", + "Fred Blundun", + "Paul Boocock" + ], + "sideEffects": false, + "main": "./dist/index.js", + "umd:main": "./dist/index.js", + "jsdelivr": "./dist/index.umd.js", + "unpkg": "./dist/index.umd.js", + "module": "./dist/index.module.js", + "types": "./dist/index.module.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "rollup -c --silent --failAfterWarnings", + "test": "ava" + }, + "ava": { + "extensions": [ + "ts" + ], + "require": [ + "ts-node/register" + ] + }, + "dependencies": { + "tslib": "^2.3.1", + "uuid": "^11.1.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "~21.0.2", + "@rollup/plugin-json": "~4.1.0", + "@rollup/plugin-node-resolve": "~13.1.3", + "@types/node": "~14.6.0", + "@typescript-eslint/eslint-plugin": "~5.15.0", + "@typescript-eslint/parser": "~5.15.0", + "ava": "~5.1.1", + "eslint": "~8.11.0", + "jest-standard-reporter": "~2.0.0", + "rollup": "~2.70.1", + "rollup-plugin-cleanup": "~3.2.1", + "rollup-plugin-license": "~2.6.1", + "rollup-plugin-terser": "~7.0.2", + "rollup-plugin-ts": "~2.0.5", + "ts-node": "~10.9.1", + "typescript": "~4.6.2" + } +} diff --git a/libraries/tracker-core/rollup.config.js b/libraries/tracker-core/rollup.config.js new file mode 100644 index 000000000..42c391285 --- /dev/null +++ b/libraries/tracker-core/rollup.config.js @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import json from '@rollup/plugin-json'; +import ts from 'rollup-plugin-ts'; // Prefered over @rollup/plugin-typescript as it bundles .d.ts files +import { banner } from '../../banner'; +import { terser } from 'rollup-plugin-terser'; +import cleanup from 'rollup-plugin-cleanup'; +import pkg from './package.json'; +import { builtinModules } from 'module'; + +const umdPlugins = [nodeResolve({ browser: true }), commonjs(), json(), ts()]; +const umdName = 'snowplowTrackerCore'; + +export default [ + // CommonJS (for Node) and ES module (for bundlers) build. + { + input: './src/index.ts', + plugins: [...umdPlugins, banner()], + output: [{ file: pkg['umd:main'], format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + plugins: [...umdPlugins, terser(), cleanup({ comments: 'none' }), banner()], + output: [{ file: pkg['umd:main'].replace('.js', '.min.js'), format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + external: [...builtinModules, ...Object.keys(pkg.dependencies), ...Object.keys(pkg.devDependencies)], + plugins: [ + json(), + ts(), // so Rollup can convert TypeScript to JavaScript + banner(), + ], + output: [{ file: pkg.main, format: 'cjs', sourcemap: true }], + }, + { + input: './src/index.ts', + external: [...builtinModules, ...Object.keys(pkg.dependencies), ...Object.keys(pkg.devDependencies)], + plugins: [ + json(), + ts(), // so Rollup can convert TypeScript to JavaScript + banner(), + ], + output: [{ file: pkg.module, format: 'es', sourcemap: true }], + }, +]; diff --git a/libraries/tracker-core/src/base64.ts b/libraries/tracker-core/src/base64.ts new file mode 100644 index 000000000..a427085eb --- /dev/null +++ b/libraries/tracker-core/src/base64.ts @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2013 Kevin van Zonneveld (http://kvz.io) + * and Contributors (http://phpjs.org/authors) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +// Deprecated and removed in TypeScript +declare function unescape(s: string): string; + +/** + * Decodes a url safe Base 64 encoded string + * @remarks See: {@link http://tools.ietf.org/html/rfc4648#page-7} + * @param data - String to decode + * @returns The decoded string + */ +export function base64urldecode(data: string): string { + if (!data) { + return data; + } + const padding = 4 - (data.length % 4); + switch (padding) { + case 2: + data += '=='; + break; + case 3: + data += '='; + break; + } + const b64Data = data.replace(/-/g, '+').replace(/_/g, '/'); + return base64decode(b64Data); +} + +/** + * Encodes a string into a url safe Base 64 encoded string + * @remarks See: {@link http://tools.ietf.org/html/rfc4648#page-7} + * @param data - String to encode + * @returns The url safe Base 64 string + */ +export function base64urlencode(data: string): string { + if (!data) { + return data; + } + + const enc = base64encode(data); + return enc.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); +} + +const b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + +/** + * Encode string as base64. + * Any type can be passed, but will be stringified + * + * @param data - string to encode + * @returns base64-encoded string + */ +export function base64encode(data: string): string { + // discuss at: http://phpjs.org/functions/base64_encode/ + // original by: Tyler Akins (http://rumkin.com) + // improved by: Bayron Guevara + // improved by: Thunder.m + // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // improved by: Rafał Kukawski (http://kukawski.pl) + // bugfixed by: Pellentesque Malesuada + // example 1: base64_encode('Kevin van Zonneveld'); + // returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA==' + // example 2: base64_encode('a'); + // returns 2: 'YQ==' + // example 3: base64_encode('✓ à la mode'); + // returns 3: '4pyTIMOgIGxhIG1vZGU=' + + let o1, + o2, + o3, + h1, + h2, + h3, + h4, + bits, + i = 0, + ac = 0; + const tmp_arr: Array = []; + + if (!data) { + return data; + } + + data = unescape(encodeURIComponent(data)); + + do { + // pack three octets into four hexets + o1 = data.charCodeAt(i++); + o2 = data.charCodeAt(i++); + o3 = data.charCodeAt(i++); + + bits = (o1 << 16) | (o2 << 8) | o3; + + h1 = (bits >> 18) & 0x3f; + h2 = (bits >> 12) & 0x3f; + h3 = (bits >> 6) & 0x3f; + h4 = bits & 0x3f; + + // use hexets to index into b64, and append result to encoded string + tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4); + } while (i < data.length); + + const enc = tmp_arr.join(''); + + const r = data.length % 3; + + return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3); +} + +/** + * Decode base64 to string + * + * @param data - base64 to string + * @returns decoded string + */ +export function base64decode(encodedData: string): string { + // discuss at: http://locutus.io/php/base64_decode/ + // original by: Tyler Akins (http://rumkin.com) + // improved by: Thunder.m + // improved by: Kevin van Zonneveld (http://kvz.io) + // improved by: Kevin van Zonneveld (http://kvz.io) + // input by: Aman Gupta + // input by: Brett Zamir (http://brett-zamir.me) + // bugfixed by: Onno Marsman (https://twitter.com/onnomarsman) + // bugfixed by: Pellentesque Malesuada + // bugfixed by: Kevin van Zonneveld (http://kvz.io) + // improved by: Indigo744 + // example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==') + // returns 1: 'Kevin van Zonneveld' + // example 2: base64_decode('YQ==') + // returns 2: 'a' + // example 3: base64_decode('4pyTIMOgIGxhIG1vZGU=') + // returns 3: '✓ à la mode' + + // decodeUTF8string() + // Internal function to decode properly UTF8 string + // Adapted from Solution #1 at https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding + const decodeUTF8string = function (str: string) { + // Going backwards: from bytestream, to percent-encoding, to original string. + return decodeURIComponent( + str + .split('') + .map(function (c) { + return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); + }) + .join('') + ); + }; + + let o1, + o2, + o3, + h1, + h2, + h3, + h4, + bits, + i = 0, + ac = 0, + dec = ''; + const tmpArr: Array = []; + + if (!encodedData) { + return encodedData; + } + + encodedData += ''; + + do { + // unpack four hexets into three octets using index points in b64 + h1 = b64.indexOf(encodedData.charAt(i++)); + h2 = b64.indexOf(encodedData.charAt(i++)); + h3 = b64.indexOf(encodedData.charAt(i++)); + h4 = b64.indexOf(encodedData.charAt(i++)); + + bits = (h1 << 18) | (h2 << 12) | (h3 << 6) | h4; + + o1 = (bits >> 16) & 0xff; + o2 = (bits >> 8) & 0xff; + o3 = bits & 0xff; + + if (h3 === 64) { + tmpArr[ac++] = String.fromCharCode(o1); + } else if (h4 === 64) { + tmpArr[ac++] = String.fromCharCode(o1, o2); + } else { + tmpArr[ac++] = String.fromCharCode(o1, o2, o3); + } + } while (i < encodedData.length); + + dec = tmpArr.join(''); + + return decodeUTF8string(dec.replace(/\0+$/, '')); +} diff --git a/libraries/tracker-core/src/contexts.ts b/libraries/tracker-core/src/contexts.ts new file mode 100644 index 000000000..71718b296 --- /dev/null +++ b/libraries/tracker-core/src/contexts.ts @@ -0,0 +1,768 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { PayloadBuilder, Payload, isNonEmptyJson } from './payload'; +import { SelfDescribingJson } from './core'; +import { CorePlugin } from './plugins'; +import { LOG } from './logger'; + +/** + * Argument for {@link ContextGenerator} and {@link ContextFilter} callback + */ +export interface ContextEvent { + /** The event payload */ + event: Payload; + /** The event type + * @example 'page_view' + */ + eventType: string; + /** The event schema where one is available, or empty string + * @example 'iglu:com.snowplowanalytics.snowplow/ad_impression/jsonschema/1-0-0' + */ + eventSchema: string; +} + +/** + * A context generator is a user-supplied callback that is evaluated for each event + * to allow an additional context to be dynamically attached to the event + * @param args - - Object which contains the event information to help decide what should be included in the returned Context + */ +export type ContextGenerator = (args?: ContextEvent) => SelfDescribingJson | SelfDescribingJson[] | undefined; + +/** + * A context filter is a user-supplied callback that is evaluated for each event + * to determine if the context associated with the filter should be attached to the event + * @param args - - Object that contains: event, eventType, eventSchema + */ +export type ContextFilter = (args?: ContextEvent) => boolean; + +/** + * A context primitive is either a self-describing JSON or a context generator + */ +export type ContextPrimitive = SelfDescribingJson | ContextGenerator; + +/** + * A filter provider is a tuple that has two parts: a context filter and the context primitive(s) + * If the context filter evaluates to true, the tracker will attach the context primitive(s) + */ +export type FilterProvider = [ContextFilter, Array | ContextPrimitive]; + +/** + * A ruleset has accept or reject properties that contain rules for matching Iglu schema URIs + */ +export interface RuleSet { + accept?: Array | string; + reject?: Array | string; +} + +/** + * A ruleset provider is aa tuple that has two parts: a ruleset and the context primitive(s) + * If the ruleset allows the current event schema URI, the tracker will attach the context primitive(s) + */ +export type RuleSetProvider = [RuleSet, Array | ContextPrimitive]; + +/** + * Conditional context providers are two element arrays used to decide when to attach contexts, where: + * - the first element is some conditional criterion + * - the second element is any number of context primitives + */ +export type ConditionalContextProvider = FilterProvider | RuleSetProvider; + +/** + * A Dynamic context is an array of Self Describing JSON contexts, or an array of callbacks which return Self Describing JSON contexts + * The array can be a mix of both contexts and callbacks which generate contexts + */ +export type DynamicContext = Array SelfDescribingJson | null)>; + +export interface GlobalContexts { + /** + * Returns all Context Primitives + */ + getGlobalPrimitives(): Array; + + /** + * Returns all Conditional Contexts + */ + getConditionalProviders(): Array; + + /** + * Adds conditional or primitive global contexts + * @param contexts - An Array of either Conditional Contexts or Primitive Contexts + */ + addGlobalContexts( + contexts: + | Array + | Record + ): void; + + /** + * Removes all global contexts + */ + clearGlobalContexts(): void; + + /** + * Removes previously added global context, performs a deep comparison of the contexts or conditional contexts + * @param contexts - An Array of either Condition Contexts or Primitive Contexts + */ + removeGlobalContexts(contexts: Array): void; + + /** + * Returns all applicable global contexts for a specified event + * @param event - The event to check for applicable global contexts for + */ + getApplicableContexts(event: PayloadBuilder): Array; +} + +/** + * Contains helper functions to aid in the addition and removal of Global Contexts + */ +export function globalContexts(): GlobalContexts { + let globalPrimitives: Array = []; + let conditionalProviders: Array = []; + let namedPrimitives: Record = {}; + let namedConditionalProviders: Record = {}; + + /** + * Returns all applicable global contexts for a specified event + * @param event - The event to check for applicable global contexts for + * @returns An array of contexts + */ + const assembleAllContexts = (event: PayloadBuilder): Array => { + const eventSchema = getUsefulSchema(event); + const eventType = getEventType(event); + const contexts: Array = []; + const generatedPrimitives = generatePrimitives( + globalPrimitives.concat(Object.values(namedPrimitives)), + event, + eventType, + eventSchema + ); + contexts.push(...generatedPrimitives); + + const generatedConditionals = generateConditionals( + conditionalProviders.concat(Object.values(namedConditionalProviders)), + event, + eventType, + eventSchema + ); + contexts.push(...generatedConditionals); + + return contexts; + }; + + return { + getGlobalPrimitives(): Array { + return globalPrimitives.concat(Object.values(namedPrimitives)); + }, + + getConditionalProviders(): Array { + return conditionalProviders.concat(Object.values(namedConditionalProviders)); + }, + + addGlobalContexts( + contexts: + | Array + | Record + ): void { + if (Array.isArray(contexts)) { + const acceptedConditionalContexts: ConditionalContextProvider[] = []; + const acceptedContextPrimitives: ContextPrimitive[] = []; + for (const context of contexts) { + if (isConditionalContextProvider(context)) { + acceptedConditionalContexts.push(context); + } else if (isContextPrimitive(context)) { + acceptedContextPrimitives.push(context); + } + } + globalPrimitives = globalPrimitives.concat(acceptedContextPrimitives); + conditionalProviders = conditionalProviders.concat(acceptedConditionalContexts); + } else { + for (const [name, context] of Object.entries(contexts)) { + if (isConditionalContextProvider(context)) { + namedConditionalProviders[name] = context; + } else if (isContextPrimitive(context)) { + namedPrimitives[name] = context; + } + } + } + }, + + clearGlobalContexts(): void { + conditionalProviders = []; + globalPrimitives = []; + namedConditionalProviders = {}; + namedPrimitives = {}; + }, + + removeGlobalContexts(contexts: Array): void { + for (const context of contexts) { + if (typeof context === 'string') { + delete namedConditionalProviders[context]; + delete namedPrimitives[context]; + } else if (isConditionalContextProvider(context)) { + conditionalProviders = conditionalProviders.filter((item) => !compareProvider(context, item)); + } else if (isContextPrimitive(context)) { + globalPrimitives = globalPrimitives.filter((item) => !compareProvider(context, item)); + } + } + }, + + getApplicableContexts(event: PayloadBuilder): Array { + return assembleAllContexts(event); + }, + }; +} + +export interface PluginContexts { + /** + * Returns list of contexts from all active plugins + */ + addPluginContexts: >( + additionalContexts?: SelfDescribingJson[] | null + ) => SelfDescribingJson[]; +} + +export function pluginContexts(plugins: Array): PluginContexts { + /** + * Add common contexts to every event + * + * @param array - additionalContexts List of user-defined contexts + * @returns userContexts combined with commonContexts + */ + return { + addPluginContexts: >(additionalContexts?: SelfDescribingJson[] | null) => { + const combinedContexts: SelfDescribingJson>[] = additionalContexts + ? [...additionalContexts] + : []; + + plugins.forEach((plugin) => { + try { + if (plugin.contexts) { + combinedContexts.push(...plugin.contexts()); + } + } catch (ex) { + LOG.error('Error adding plugin contexts', ex); + } + }); + + return combinedContexts as SelfDescribingJson[]; + }, + }; +} + +/** + * Find dynamic context generating functions and return their results to be merged into the static contexts + * Combine an array of unchanging contexts with the result of a context-creating function + * + * @param dynamicOrStaticContexts - Array of custom context Objects or custom context generating functions + * @param Parameters - to pass to dynamic context callbacks + * @returns An array of Self Describing JSON context + */ +export function resolveDynamicContext( + dynamicOrStaticContexts?: DynamicContext | null, + ...extraParams: any[] +): Array { + return ( + (dynamicOrStaticContexts + ?.map(function (context) { + if (typeof context === 'function') { + try { + return context(...extraParams); + } catch (e) { + //TODO: provide warning + return undefined; + } + } else { + return context; + } + }) + .filter(Boolean) as Array) ?? [] + ); +} + +/** + * Slices a schema into its composite parts. Useful for ruleset filtering. + * @param input - A schema string + * @returns The vendor, schema name, major, minor and patch information of a schema string + */ +export function getSchemaParts(input: string): Array | undefined { + const re = new RegExp( + '^iglu:([a-zA-Z0-9-_.]+)/([a-zA-Z0-9-_]+)/jsonschema/([1-9][0-9]*)-(0|[1-9][0-9]*)-(0|[1-9][0-9]*)$' + ); + const matches = re.exec(input); + if (matches !== null) return matches.slice(1, 6); + return undefined; +} + +/** + * Validates the vendor section of a schema string contains allowed wildcard values + * @param parts - Array of parts from a schema string + * @returns Whether the vendor validation parts are a valid combination + */ +export function validateVendorParts(parts: Array): boolean { + if (parts[0] === '*' || parts[1] === '*') { + return false; // no wildcard in first or second part + } + if (parts.slice(2).length > 0) { + let asterisk = false; + for (const part of parts.slice(2)) { + if (part === '*') + // mark when we've found a wildcard + asterisk = true; + else if (asterisk) + // invalid if alpha parts come after wildcard + return false; + } + return true; + } else if (parts.length == 2) return true; + + return false; +} + +/** + * Validates the vendor part of a schema string is valid for a rule set + * @param input - Vendor part of a schema string + * @returns Whether the vendor validation string is valid + */ +export function validateVendor(input: string): boolean { + const parts = input.split('.'); + if (parts && parts.length > 1) return validateVendorParts(parts); + return false; +} + +/** + * Checks for validity of input and returns all the sections of a schema string that are used to match rules in a ruleset + * @param input - A Schema string + * @returns The sections of a schema string that are used to match rules in a ruleset + */ +export function getRuleParts(input: string): Array | undefined { + const re = new RegExp( + '^iglu:((?:(?:[a-zA-Z0-9-_]+|\\*).)+(?:[a-zA-Z0-9-_]+|\\*))/([a-zA-Z0-9-_.]+|\\*)/jsonschema/([1-9][0-9]*|\\*)-(0|[1-9][0-9]*|\\*)-(0|[1-9][0-9]*|\\*)$' + ); + const matches = re.exec(input); + if (matches !== null && validateVendor(matches[1])) return matches.slice(1, 6); + return undefined; +} + +/** + * Ensures the rules specified in a schema string of a ruleset are valid + * @param input - A Schema string + * @returns if there rule is valid + */ +export function isValidRule(input: string): boolean { + const ruleParts = getRuleParts(input); + if (ruleParts) { + const vendor = ruleParts[0]; + return ruleParts.length === 5 && validateVendor(vendor); + } + return false; +} + +/** + * Check if a variable is an Array containing only strings + * @param input - The variable to validate + * @returns True if the input is an array containing only strings + */ +export function isStringArray(input: unknown): input is Array { + return ( + Array.isArray(input) && + input.every((x) => { + return typeof x === 'string'; + }) + ); +} + +/** + * Validates whether a rule set is an array of valid ruleset strings + * @param input - The Array of rule set arguments + * @returns True is the input is an array of valid rules + */ +export function isValidRuleSetArg(input: unknown): boolean { + if (isStringArray(input)) + return input.every((x: string) => { + return isValidRule(x); + }); + else if (typeof input === 'string') return isValidRule(input); + return false; +} + +/** + * Check if a variable is a valid, non-empty Self Describing JSON + * @param input - The variable to validate + * @returns True if a valid Self Describing JSON + */ +export function isSelfDescribingJson(input: unknown): input is SelfDescribingJson { + const sdj = input as SelfDescribingJson; + if (isNonEmptyJson(sdj)) + if ('schema' in sdj && 'data' in sdj) return typeof sdj.schema === 'string' && typeof sdj.data === 'object'; + return false; +} + +/** + * Validates if the input object contains the expected properties of a ruleset + * @param input - The object containing a rule set + * @returns True if a valid rule set + */ +export function isRuleSet(input: unknown): input is Record { + const ruleSet = input as Record; + let ruleCount = 0; + if (input != null && typeof input === 'object' && !Array.isArray(input)) { + if (Object.prototype.hasOwnProperty.call(ruleSet, 'accept')) { + if (isValidRuleSetArg(ruleSet['accept'])) { + ruleCount += 1; + } else { + return false; + } + } + if (Object.prototype.hasOwnProperty.call(ruleSet, 'reject')) { + if (isValidRuleSetArg(ruleSet['reject'])) { + ruleCount += 1; + } else { + return false; + } + } + // if either 'reject' or 'accept' or both exists, + // we have a valid ruleset + return ruleCount > 0 && ruleCount <= 2; + } + return false; +} + +/** + * Validates if the function can be a valid context generator function + * @param input - The function to be validated + */ +export function isContextCallbackFunction(input: unknown): boolean { + return typeof input === 'function' && input.length <= 1; +} + +/** + * Validates if the function can be a valid context primitive function or self describing json + * @param input - The function or orbject to be validated + * @returns True if either a Context Generator or Self Describing JSON + */ +export function isContextPrimitive(input: unknown): input is ContextPrimitive { + return isContextCallbackFunction(input) || isSelfDescribingJson(input); +} + +/** + * Validates if an array is a valid shape to be a Filter Provider + * @param input - The Array of Context filter callbacks + */ +export function isFilterProvider(input: unknown): boolean { + if (Array.isArray(input)) { + if (input.length === 2) { + if (Array.isArray(input[1])) { + return isContextCallbackFunction(input[0]) && input[1].every(isContextPrimitive); + } + return isContextCallbackFunction(input[0]) && isContextPrimitive(input[1]); + } + } + return false; +} + +/** + * Validates if an array is a valid shape to be an array of rule sets + * @param input - The Array of Rule Sets + */ +export function isRuleSetProvider(input: unknown): boolean { + if (Array.isArray(input) && input.length === 2) { + if (!isRuleSet(input[0])) return false; + if (Array.isArray(input[1])) return input[1].every(isContextPrimitive); + return isContextPrimitive(input[1]); + } + return false; +} + +/** + * Checks if an input array is either a filter provider or a rule set provider + * @param input - An array of filter providers or rule set providers + * @returns Whether the array is a valid {@link ConditionalContextProvider} + */ +export function isConditionalContextProvider(input: unknown): input is ConditionalContextProvider { + return isFilterProvider(input) || isRuleSetProvider(input); +} + +/** + * Checks if a given schema matches any rules within the provided rule set + * @param ruleSet - The rule set containing rules to match schema against + * @param schema - The schema to be matched against the rule set + */ +export function matchSchemaAgainstRuleSet(ruleSet: RuleSet, schema: string): boolean { + let rejectCount = 0; + let acceptCount = 0; + const acceptRules = ruleSet['accept']; + if (Array.isArray(acceptRules)) { + if ((ruleSet.accept as Array).some((rule) => matchSchemaAgainstRule(rule, schema))) { + acceptCount++; + } + } else if (typeof acceptRules === 'string') { + if (matchSchemaAgainstRule(acceptRules, schema)) { + acceptCount++; + } + } + + const rejectRules = ruleSet['reject']; + if (Array.isArray(rejectRules)) { + if ((ruleSet.reject as Array).some((rule) => matchSchemaAgainstRule(rule, schema))) { + rejectCount++; + } + } else if (typeof rejectRules === 'string') { + if (matchSchemaAgainstRule(rejectRules, schema)) { + rejectCount++; + } + } + + if (acceptCount > 0 && rejectCount === 0) { + return true; + } else if (acceptCount === 0 && rejectCount > 0) { + return false; + } + + return false; +} + +/** + * Checks if a given schema matches a specific rule from a rule set + * @param rule - The rule to match schema against + * @param schema - The schema to be matched against the rule + */ +export function matchSchemaAgainstRule(rule: string, schema: string): boolean { + if (!isValidRule(rule)) return false; + const ruleParts = getRuleParts(rule); + const schemaParts = getSchemaParts(schema); + if (ruleParts && schemaParts) { + if (!matchVendor(ruleParts[0], schemaParts[0])) return false; + for (let i = 1; i < 5; i++) { + if (!matchPart(ruleParts[i], schemaParts[i])) return false; + } + return true; // if it hasn't failed, it passes + } + return false; +} + +function matchVendor(rule: string, vendor: string): boolean { + // rule and vendor must have same number of elements + const vendorParts = vendor.split('.'); + const ruleParts = rule.split('.'); + if (vendorParts && ruleParts) { + if (vendorParts.length !== ruleParts.length) return false; + for (let i = 0; i < ruleParts.length; i++) { + if (!matchPart(vendorParts[i], ruleParts[i])) return false; + } + return true; + } + return false; +} + +function matchPart(rule: string, schema: string): boolean { + // parts should be the string nested between slashes in the URI: /example/ + return (rule && schema && rule === '*') || rule === schema; +} + +// Returns the "useful" schema, i.e. what would someone want to use to identify events. +// For some events this is the 'e' property but for unstructured events, this is the +// 'schema' from the 'ue_px' field. +function getUsefulSchema(sb: PayloadBuilder): string { + let eventJson = sb.getJson(); + for (const json of eventJson) { + if (json.keyIfEncoded === 'ue_px' && typeof json.json['data'] === 'object') { + const schema = (json.json['data'] as Record)['schema']; + if (typeof schema == 'string') { + return schema; + } + } + } + return ''; +} + +function getEventType(payloadBuilder: PayloadBuilder): string { + const eventType = payloadBuilder.getPayload()['e']; + return typeof eventType === 'string' ? eventType : ''; +} + +function buildGenerator( + generator: ContextGenerator, + event: PayloadBuilder, + eventType: string, + eventSchema: string +): SelfDescribingJson | Array | undefined { + let contextGeneratorResult: SelfDescribingJson | Array | undefined = undefined; + try { + // try to evaluate context generator + const args = { + event: event.getPayload(), + eventType: eventType, + eventSchema: eventSchema, + }; + contextGeneratorResult = generator(args); + // determine if the produced result is a valid SDJ + if (Array.isArray(contextGeneratorResult) && contextGeneratorResult.every(isSelfDescribingJson)) { + return contextGeneratorResult; + } else if (isSelfDescribingJson(contextGeneratorResult)) { + return contextGeneratorResult; + } else { + return undefined; + } + } catch (error) { + contextGeneratorResult = undefined; + } + return contextGeneratorResult; +} + +function normalizeToArray(input: Array | T): Array { + if (Array.isArray(input)) { + return input; + } + return Array.of(input); +} + +function generatePrimitives( + contextPrimitives: Array | ContextPrimitive, + event: PayloadBuilder, + eventType: string, + eventSchema: string +): Array { + const normalizedInputs: Array = normalizeToArray(contextPrimitives); + const partialEvaluate = (primitive: ContextPrimitive) => { + const result = evaluatePrimitive(primitive, event, eventType, eventSchema); + if (result && result.length !== 0) { + return result; + } + return undefined; + }; + const generatedContexts = normalizedInputs.map(partialEvaluate); + return ([] as Array).concat( + ...(generatedContexts.filter((c) => c != null && c.filter(Boolean)) as Array>) + ); +} + +function evaluatePrimitive( + contextPrimitive: ContextPrimitive, + event: PayloadBuilder, + eventType: string, + eventSchema: string +): Array | undefined { + if (isSelfDescribingJson(contextPrimitive)) { + return [contextPrimitive as SelfDescribingJson]; + } else if (isContextCallbackFunction(contextPrimitive)) { + const generatorOutput = buildGenerator(contextPrimitive as ContextGenerator, event, eventType, eventSchema); + if (isSelfDescribingJson(generatorOutput)) { + return [generatorOutput as SelfDescribingJson]; + } else if (Array.isArray(generatorOutput)) { + return generatorOutput; + } + } + return undefined; +} + +function evaluateProvider( + provider: ConditionalContextProvider, + event: PayloadBuilder, + eventType: string, + eventSchema: string +): Array { + if (isFilterProvider(provider)) { + const filter: ContextFilter = (provider as FilterProvider)[0]; + let filterResult = false; + try { + const args = { + event: event.getPayload(), + eventType: eventType, + eventSchema: eventSchema, + }; + filterResult = filter(args); + } catch (error) { + filterResult = false; + } + if (filterResult === true) { + return generatePrimitives((provider as FilterProvider)[1], event, eventType, eventSchema); + } + } else if (isRuleSetProvider(provider)) { + if (matchSchemaAgainstRuleSet((provider as RuleSetProvider)[0], eventSchema)) { + return generatePrimitives((provider as RuleSetProvider)[1], event, eventType, eventSchema); + } + } + return []; +} + +function compareProviderPart( + a: ContextFilter | RuleSet | ContextPrimitive, + b: ContextFilter | RuleSet | ContextPrimitive +): boolean { + if (typeof a === 'function') return a === b; + return JSON.stringify(a) === JSON.stringify(b); +} + +function compareProvider( + a: ConditionalContextProvider | ContextPrimitive, + b: ConditionalContextProvider | ContextPrimitive +): boolean { + if (isConditionalContextProvider(a)) { + if (!isConditionalContextProvider(b)) return false; + const [ruleA, primitivesA] = a; + const [ruleB, primitivesB] = b; + + if (!compareProviderPart(ruleA, ruleB)) return false; + if (Array.isArray(primitivesA)) { + if (!Array.isArray(primitivesB)) return false; + if (primitivesA.length !== primitivesB.length) return false; + return primitivesA.reduce((matches, a, i) => matches && compareProviderPart(a, primitivesB[i]), true); + } else { + if (Array.isArray(primitivesB)) return false; + return compareProviderPart(primitivesA, primitivesB); + } + } else if (isContextPrimitive(a)) { + if (!isContextPrimitive(b)) return false; + return compareProviderPart(a, b); + } + + return false; +} + +function generateConditionals( + providers: Array | ConditionalContextProvider, + event: PayloadBuilder, + eventType: string, + eventSchema: string +): Array { + const normalizedInput: Array = normalizeToArray(providers); + const partialEvaluate = (provider: ConditionalContextProvider) => { + const result = evaluateProvider(provider, event, eventType, eventSchema); + if (result && result.length !== 0) { + return result; + } + return undefined; + }; + const generatedContexts = normalizedInput.map(partialEvaluate); + return ([] as Array).concat( + ...(generatedContexts.filter((c) => c != null && c.filter(Boolean)) as Array>) + ); +} diff --git a/libraries/tracker-core/src/core.ts b/libraries/tracker-core/src/core.ts new file mode 100644 index 000000000..cbe78a044 --- /dev/null +++ b/libraries/tracker-core/src/core.ts @@ -0,0 +1,1427 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { v4 as uuid } from 'uuid'; +import { payloadBuilder, PayloadBuilder, Payload, isJson, payloadJsonProcessor } from './payload'; +import { + globalContexts, + ConditionalContextProvider, + ContextPrimitive, + GlobalContexts, + PluginContexts, + pluginContexts, +} from './contexts'; +import { CorePlugin } from './plugins'; +import { LOG } from './logger'; + +/** + * Export interface for any Self-Describing JSON such as context or Self Describing events + * @typeParam T - The type of the data object within a SelfDescribingJson + */ +export type SelfDescribingJson> = { + /** + * The schema string + * @example 'iglu:com.snowplowanalytics.snowplow/web_page/jsonschema/1-0-0' + */ + schema: string; + /** + * The data object which should conform to the supplied schema + */ + data: T extends any[] ? never : T extends {} ? T : never; +}; + +/** + * Export interface for any Self-Describing JSON which has the data attribute as an array + * @typeParam T - The type of the data object within the SelfDescribingJson data array + */ +export type SelfDescribingJsonArray> = { + /** + * The schema string + * @example 'iglu:com.snowplowanalytics.snowplow/contexts/jsonschema/1-0-1' + */ + schema: string; + /** + * The data array which should conform to the supplied schema + */ + data: (T extends SelfDescribingJson ? T : SelfDescribingJson)[]; +}; + +/** + * Algebraic datatype representing possible timestamp type choice + */ +export type Timestamp = TrueTimestamp | DeviceTimestamp | number; + +/** + * A representation of a True Timestamp (ttm) + */ +export interface TrueTimestamp { + readonly type: 'ttm'; + readonly value: number; +} + +/** + * A representation of a Device Timestamp (dtm) + */ +export interface DeviceTimestamp { + readonly type: 'dtm'; + readonly value: number; +} + +/** + * Pair of timestamp type ready to be included to payload + */ +type TimestampPayload = TrueTimestamp | DeviceTimestamp; + +/** + * Transform optional/old-behavior number timestamp into`Timestamp` ADT + * + * @param timestamp - optional number or timestamp object + * @returns correct timestamp object + */ +function getTimestamp(timestamp?: Timestamp | null): TimestampPayload { + if (timestamp == null) { + return { type: 'dtm', value: new Date().getTime() }; + } else if (typeof timestamp === 'number') { + return { type: 'dtm', value: timestamp }; + } else if (timestamp.type === 'ttm') { + // We can return timestamp here, but this is safer fallback + return { type: 'ttm', value: timestamp.value }; + } else { + return { type: 'dtm', value: timestamp.value || new Date().getTime() }; + } +} + +/** Additional data points to set when tracking an event */ +export interface CommonEventProperties> { + /** Add context to an event by setting an Array of Self Describing JSON */ + context?: Array> | null; + /** Set the true timestamp or overwrite the device sent timestamp on an event */ + timestamp?: Timestamp | null; +} + +/** + * Export interface containing all Core functions + */ +export interface TrackerCore { + /** + * Call with a payload from a buildX function + * Adds context and payloadPairs name-value pairs to the payload + * Applies the callback to the built payload + * + * @param pb - Payload + * @param context - Custom contexts relating to the event + * @param timestamp - Timestamp of the event + * @returns Payload after the callback is applied or undefined if the event is skipped + */ + track: ( + /** A PayloadBuilder created by one of the `buildX` functions */ + pb: PayloadBuilder, + /** The additional contextual information related to the event */ + context?: Array | null, + /** Timestamp override */ + timestamp?: Timestamp | null + ) => Payload | undefined; + + /** + * Set a persistent key-value pair to be added to every payload + * + * @param key - Field name + * @param value - Field value + */ + addPayloadPair: (key: string, value: unknown) => void; + + /** + * Deactivate tracker core including all plugins. + * This is useful for cleaning up resources or listeners that have been created. + * Once deactivated, the tracker won't be able to track any events. + */ + deactivate(): void; + + /** + * Get current base64 encoding state + */ + getBase64Encoding(): boolean; + + /** + * Turn base 64 encoding on or off + * + * @param encode - Whether to encode payload + */ + setBase64Encoding(encode: boolean): void; + + /** + * Merges a dictionary into payloadPairs + * + * @param dict - Adds a new payload dictionary to the existing one + */ + addPayloadDict(dict: Payload): void; + + /** + * Replace payloadPairs with a new dictionary + * + * @param dict - Resets all current payload pairs with a new dictionary of pairs + */ + resetPayloadPairs(dict: Payload): void; + + /** + * Set the tracker version + * + * @param version - The version of the current tracker + */ + setTrackerVersion(version: string): void; + + /** + * Set the tracker namespace + * + * @param name - The trackers namespace + */ + setTrackerNamespace(name: string): void; + + /** + * Set the application ID + * + * @param appId - An application ID which identifies the current application + */ + setAppId(appId: string): void; + + /** + * Set the platform + * + * @param value - A valid Snowplow platform value + */ + setPlatform(value: string): void; + + /** + * Set the user ID + * + * @param userId - The custom user id + */ + setUserId(userId: string): void; + + /** + * Set the screen resolution + * + * @param width - screen resolution width + * @param height - screen resolution height + */ + setScreenResolution(width: string, height: string): void; + + /** + * Set the viewport dimensions + * + * @param width - viewport width + * @param height - viewport height + */ + setViewport(width: string, height: string): void; + + /** + * Set the color depth + * + * @param depth - A color depth value as string + */ + setColorDepth(depth: string): void; + + /** + * Set the timezone + * + * @param timezone - A timezone string + */ + setTimezone(timezone: string): void; + + /** + * Set the language + * + * @param lang - A language string e.g. 'en-UK' + */ + setLang(lang: string): void; + + /** + * Set the IP address + * + * @param ip - An IP Address string + */ + setIpAddress(ip: string): void; + + /** + * Set the Useragent + * + * @param useragent - A useragent string + */ + setUseragent(useragent: string): void; + + /** + * Adds contexts globally, contexts added here will be attached to all applicable events + * @param contexts - An array containing either contexts or a conditional contexts + */ + addGlobalContexts( + contexts: + | Array + | Record + ): void; + + /** + * Removes all global contexts + */ + clearGlobalContexts(): void; + + /** + * Removes previously added global context, performs a deep comparison of the contexts or conditional contexts + * @param contexts - An array containing either contexts or a conditional contexts + */ + removeGlobalContexts(contexts: Array): void; + + /** + * Add a plugin into the plugin collection after Core has already been initialised + * @param configuration - The plugin to add + */ + addPlugin(configuration: CorePluginConfiguration): void; +} + +/** + * The configuration object for the tracker core library + */ +export interface CoreConfiguration { + /* Should payloads be base64 encoded when built */ + base64?: boolean; + /* A list of all the plugins to include at load */ + corePlugins?: Array; + /* The callback which will fire each time `track()` is called */ + callback?: (PayloadData: PayloadBuilder) => void; +} + +/** + * The configuration of the plugin to add + */ +export interface CorePluginConfiguration { + /* The plugin to add */ + plugin: CorePlugin; +} + +/** + * Create a tracker core object + * + * @param base64 - Whether to base 64 encode contexts and self describing event JSONs + * @param corePlugins - The core plugins to be processed with each event + * @param callback - Function applied to every payload dictionary object + * @returns Tracker core + */ +export function trackerCore(configuration: CoreConfiguration = {}): TrackerCore { + function newCore(base64: boolean, corePlugins: Array, callback?: (PayloadData: PayloadBuilder) => void) { + const pluginContextsHelper: PluginContexts = pluginContexts(corePlugins), + globalContextsHelper: GlobalContexts = globalContexts(); + + let encodeBase64 = base64, + payloadPairs: Payload = {}; // Dictionary of key-value pairs which get added to every payload, e.g. tracker version + + /** + * Wraps an array of custom contexts in a self-describing JSON + * + * @param contexts - Array of custom context self-describing JSONs + * @returns Outer JSON + */ + function completeContexts( + contexts?: Array + ): SelfDescribingJsonArray | undefined { + if (contexts && contexts.length) { + return { + schema: 'iglu:com.snowplowanalytics.snowplow/contexts/jsonschema/1-0-0', + data: contexts, + }; + } + return undefined; + } + + /** + * Adds all global contexts to a contexts array + * + * @param pb - PayloadData + * @param contexts - Custom contexts relating to the event + */ + function attachGlobalContexts( + pb: PayloadBuilder, + contexts?: Array | null + ): Array { + const applicableContexts: Array = globalContextsHelper.getApplicableContexts(pb); + const returnedContexts: Array = []; + if (contexts && contexts.length) { + returnedContexts.push(...contexts); + } + if (applicableContexts && applicableContexts.length) { + returnedContexts.push(...applicableContexts); + } + return returnedContexts; + } + + /** + * Gets called by every trackXXX method + * Adds context and payloadPairs name-value pairs to the payload + * Applies the callback to the built payload + * + * @param pb - Payload + * @param context - Custom contexts relating to the event + * @param timestamp - Timestamp of the event + * @returns Payload after the callback is applied or undefined if the event is skipped + */ + function track>( + pb: PayloadBuilder, + context?: Array> | null, + timestamp?: Timestamp | null + ): Payload | undefined { + if (!active) { + LOG.error('Track called on deactivated tracker'); + return undefined; + } + + pb.withJsonProcessor(payloadJsonProcessor(encodeBase64)); + pb.add('eid', uuid()); + pb.addDict(payloadPairs); + const tstamp = getTimestamp(timestamp); + pb.add(tstamp.type, tstamp.value.toString()); + const allContexts = attachGlobalContexts(pb, pluginContextsHelper.addPluginContexts(context)); + const wrappedContexts = completeContexts(allContexts); + if (wrappedContexts !== undefined) { + pb.addJson('cx', 'co', wrappedContexts); + } + + corePlugins.forEach((plugin) => { + try { + if (plugin.beforeTrack) { + plugin.beforeTrack(pb); + } + } catch (ex) { + LOG.error('Plugin beforeTrack', ex); + } + }); + + // Call the filter on plugins to determine if the event should be tracked + const skip = corePlugins.find((plugin) => { + try { + return plugin.filter && plugin.filter(pb.build()) === false; + } catch (ex) { + LOG.error('Plugin filter', ex); + return false; + } + }); + if (skip) { + return undefined; + } + + if (typeof callback === 'function') { + callback(pb); + } + + const finalPayload = pb.build(); + + corePlugins.forEach((plugin) => { + try { + if (plugin.afterTrack) { + plugin.afterTrack(finalPayload); + } + } catch (ex) { + LOG.error('Plugin afterTrack', ex); + } + }); + + return finalPayload; + } + + /** + * Set a persistent key-value pair to be added to every payload + * + * @param key - Field name + * @param value - Field value + */ + function addPayloadPair(key: string, value: unknown): void { + payloadPairs[key] = value; + } + + const core = { + track, + + addPayloadPair, + + getBase64Encoding() { + return encodeBase64; + }, + + setBase64Encoding(encode: boolean) { + encodeBase64 = encode; + }, + + addPayloadDict(dict: Payload) { + for (const key in dict) { + if (Object.prototype.hasOwnProperty.call(dict, key)) { + payloadPairs[key] = dict[key]; + } + } + }, + + resetPayloadPairs(dict: Payload) { + payloadPairs = isJson(dict) ? dict : {}; + }, + + setTrackerVersion(version: string) { + addPayloadPair('tv', version); + }, + + setTrackerNamespace(name: string) { + addPayloadPair('tna', name); + }, + + setAppId(appId: string) { + addPayloadPair('aid', appId); + }, + + setPlatform(value: string) { + addPayloadPair('p', value); + }, + + setUserId(userId: string) { + addPayloadPair('uid', userId); + }, + + setScreenResolution(width: string, height: string) { + addPayloadPair('res', width + 'x' + height); + }, + + setViewport(width: string, height: string) { + addPayloadPair('vp', width + 'x' + height); + }, + + setColorDepth(depth: string) { + addPayloadPair('cd', depth); + }, + + setTimezone(timezone: string) { + addPayloadPair('tz', timezone); + }, + + setLang(lang: string) { + addPayloadPair('lang', lang); + }, + + setIpAddress(ip: string) { + addPayloadPair('ip', ip); + }, + + setUseragent(useragent: string) { + addPayloadPair('ua', useragent); + }, + + addGlobalContexts(contexts: Array) { + globalContextsHelper.addGlobalContexts(contexts); + }, + + clearGlobalContexts(): void { + globalContextsHelper.clearGlobalContexts(); + }, + + removeGlobalContexts(contexts: Array) { + globalContextsHelper.removeGlobalContexts(contexts); + }, + }; + + return core; + } + + let active = true; + const { base64, corePlugins, callback } = configuration, + plugins = corePlugins ?? [], + partialCore = newCore(base64 ?? true, plugins, callback), + core = { + ...partialCore, + addPlugin: (configuration: CorePluginConfiguration) => { + const { plugin } = configuration; + plugins.push(plugin); + plugin.logger?.(LOG); + plugin.activateCorePlugin?.(core); + }, + deactivate: () => { + plugins.forEach((plugin) => { + plugin.deactivatePlugin?.(core); + }); + plugins.length = 0; + active = false; + } + }; + + plugins?.forEach((plugin) => { + plugin.logger?.(LOG); + plugin.activateCorePlugin?.(core); + }); + + return core; +} + +/** + * A Self Describing Event + * A custom event type, allowing for an event to be tracked using your own custom schema + * and a data object which conforms to the supplied schema + */ +export interface SelfDescribingEvent> { + /** The Self Describing JSON which describes the event */ + event: SelfDescribingJson; +} + +/** + * Build a self-describing event + * A custom event type, allowing for an event to be tracked using your own custom schema + * and a data object which conforms to the supplied schema + * + * @param event - Contains the properties and schema location for the event + * @returns PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track} + */ +export function buildSelfDescribingEvent>(event: SelfDescribingEvent): PayloadBuilder { + const { + event: { schema, data }, + } = event, + pb = payloadBuilder(); + const ueJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/unstruct_event/jsonschema/1-0-0', + data: { schema, data }, + }; + + pb.add('e', 'ue'); + pb.addJson('ue_px', 'ue_pr', ueJson); + + return pb; +} + +/** + * A Page View Event + * Represents a Page View, which is typically fired as soon as possible when a web page + * is loaded within the users browser. Often also fired on "virtual page views" within + * Single Page Applications (SPA). + */ +export interface PageViewEvent { + /** The current URL visible in the users browser */ + pageUrl?: string | null; + /** The current page title in the users browser */ + pageTitle?: string | null; + /** The URL of the referring page */ + referrer?: string | null; +} + +/** + * Build a Page View Event + * Represents a Page View, which is typically fired as soon as possible when a web page + * is loaded within the users browser. Often also fired on "virtual page views" within + * Single Page Applications (SPA). + * + * @param event - Contains the properties for the Page View event + * @returns PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track} + */ +export function buildPageView(event: PageViewEvent): PayloadBuilder { + const { pageUrl, pageTitle, referrer } = event, + pb = payloadBuilder(); + pb.add('e', 'pv'); // 'pv' for Page View + pb.add('url', pageUrl); + pb.add('page', pageTitle); + pb.add('refr', referrer); + + return pb; +} + +/** + * A Page Ping Event + * Fires when activity tracking is enabled in the browser. + * Tracks same information as the last tracked Page View and includes scroll + * information from the current page view + */ +export interface PagePingEvent extends PageViewEvent { + /** The minimum X scroll position for the current page view */ + minXOffset?: number; + /** The maximum X scroll position for the current page view */ + maxXOffset?: number; + /** The minimum Y scroll position for the current page view */ + minYOffset?: number; + /** The maximum Y scroll position for the current page view */ + maxYOffset?: number; +} + +/** + * Build a Page Ping Event + * Fires when activity tracking is enabled in the browser. + * Tracks same information as the last tracked Page View and includes scroll + * information from the current page view + * + * @param event - Contains the properties for the Page Ping event + * @returns PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track} + */ +export function buildPagePing(event: PagePingEvent): PayloadBuilder { + const { pageUrl, pageTitle, referrer, minXOffset, maxXOffset, minYOffset, maxYOffset } = event, + pb = payloadBuilder(); + pb.add('e', 'pp'); // 'pp' for Page Ping + pb.add('url', pageUrl); + pb.add('page', pageTitle); + pb.add('refr', referrer); + if (minXOffset && !isNaN(Number(minXOffset))) pb.add('pp_mix', minXOffset.toString()); + if (maxXOffset && !isNaN(Number(maxXOffset))) pb.add('pp_max', maxXOffset.toString()); + if (minYOffset && !isNaN(Number(minYOffset))) pb.add('pp_miy', minYOffset.toString()); + if (maxYOffset && !isNaN(Number(maxYOffset))) pb.add('pp_may', maxYOffset.toString()); + + return pb; +} + +/** + * A Structured Event + * A classic style of event tracking, allows for easier movement between analytics + * systems. A loosely typed event, creating a Self Describing event is preferred, but + * useful for interoperability. + */ +export interface StructuredEvent { + category: string; + action: string; + label?: string; + property?: string; + value?: number; +} + +/** + * Build a Structured Event + * A classic style of event tracking, allows for easier movement between analytics + * systems. A loosely typed event, creating a Self Describing event is preferred, but + * useful for interoperability. + * + * @param event - Contains the properties for the Structured event + * @returns PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track} + */ +export function buildStructEvent(event: StructuredEvent): PayloadBuilder { + const { category, action, label, property, value } = event, + pb = payloadBuilder(); + pb.add('e', 'se'); // 'se' for Structured Event + pb.add('se_ca', category); + pb.add('se_ac', action); + pb.add('se_la', label); + pb.add('se_pr', property); + pb.add('se_va', value == null ? undefined : value.toString()); + + return pb; +} + +/** + * An Ecommerce Transaction Event + * Allows for tracking common ecommerce events, this event is usually used when + * a customer completes a transaction. + */ +export interface EcommerceTransactionEvent { + /** An identifier for the order */ + orderId: string; + /** The total value of the order */ + total: number; + /** Transaction affiliation (e.g. store where sale took place) */ + affiliation?: string; + /** The amount of tax on the transaction */ + tax?: number; + /** The amount of shipping costs for this transaction */ + shipping?: number; + /** Delivery address, city */ + city?: string; + /** Delivery address, state */ + state?: string; + /** Delivery address, country */ + country?: string; + /** Currency of the transaction */ + currency?: string; +} + +/** + * Build an Ecommerce Transaction Event + * Allows for tracking common ecommerce events, this event is usually used when + * a consumer completes a transaction. + * + * @param event - Contains the properties for the Ecommerce Transactoion event + * @returns PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track} + */ +export function buildEcommerceTransaction(event: EcommerceTransactionEvent): PayloadBuilder { + const { orderId, total, affiliation, tax, shipping, city, state, country, currency } = event, + pb = payloadBuilder(); + pb.add('e', 'tr'); // 'tr' for Transaction + pb.add('tr_id', orderId); + pb.add('tr_af', affiliation); + pb.add('tr_tt', total); + pb.add('tr_tx', tax); + pb.add('tr_sh', shipping); + pb.add('tr_ci', city); + pb.add('tr_st', state); + pb.add('tr_co', country); + pb.add('tr_cu', currency); + + return pb; +} + +/** + * An Ecommerce Transaction Item + * Related to the {@link EcommerceTransactionEvent} + * Each Ecommerce Transaction may contain one or more EcommerceTransactionItem events + */ +export interface EcommerceTransactionItemEvent { + /** An identifier for the order */ + orderId: string; + /** A Product Stock Keeping Unit (SKU) */ + sku: string; + /** The price of the product */ + price: number; + /** The name of the product */ + name?: string; + /** The category the product belongs to */ + category?: string; + /** The quanity of this product within the transaction */ + quantity?: number; + /** The currency of the product for the transaction */ + currency?: string; +} + +/** + * Build an Ecommerce Transaction Item Event + * Related to the {@link buildEcommerceTransaction} + * Each Ecommerce Transaction may contain one or more EcommerceTransactionItem events + * + * @param event - Contains the properties for the Ecommerce Transaction Item event + * @returns PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track} + */ +export function buildEcommerceTransactionItem(event: EcommerceTransactionItemEvent): PayloadBuilder { + const { orderId, sku, price, name, category, quantity, currency } = event, + pb = payloadBuilder(); + pb.add('e', 'ti'); // 'tr' for Transaction Item + pb.add('ti_id', orderId); + pb.add('ti_sk', sku); + pb.add('ti_nm', name); + pb.add('ti_ca', category); + pb.add('ti_pr', price); + pb.add('ti_qu', quantity); + pb.add('ti_cu', currency); + + return pb; +} + +/** + * A Screen View Event + * Similar to a Page View but less focused on typical web properties + * Often used for mobile applications as the user is presented with + * new views as they performance navigation events + */ +export interface ScreenViewEvent { + /** The name of the screen */ + name?: string; + /** The identifier of the screen */ + id?: string; +} + +/** + * Build a Scren View Event + * Similar to a Page View but less focused on typical web properties + * Often used for mobile applications as the user is presented with + * new views as they performance navigation events + * + * @param event - Contains the properties for the Screen View event. One or more properties must be included. + * @returns PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track} + */ +export function buildScreenView(event: ScreenViewEvent): PayloadBuilder { + const { name, id } = event; + return buildSelfDescribingEvent({ + event: { + schema: 'iglu:com.snowplowanalytics.snowplow/screen_view/jsonschema/1-0-0', + data: removeEmptyProperties({ name, id }), + }, + }); +} + +/** + * A Link Click Event + * Used when a user clicks on a link on a webpage, typically an anchor tag `` + */ +export interface LinkClickEvent { + /** The target URL of the link */ + targetUrl: string; + /** The ID of the element clicked if present */ + elementId?: string; + /** An array of class names from the element clicked */ + elementClasses?: Array; + /** The target value of the element if present */ + elementTarget?: string; + /** The content of the element if present and enabled */ + elementContent?: string; +} + +/** + * Build a Link Click Event + * Used when a user clicks on a link on a webpage, typically an anchor tag `` + * + * @param event - Contains the properties for the Link Click event + * @returns PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track} + */ +export function buildLinkClick(event: LinkClickEvent): PayloadBuilder { + const { targetUrl, elementId, elementClasses, elementTarget, elementContent } = event; + const eventJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1', + data: removeEmptyProperties({ targetUrl, elementId, elementClasses, elementTarget, elementContent }), + }; + + return buildSelfDescribingEvent({ event: eventJson }); +} + +/** + * An Ad Impression Event + * Used to track an advertisement impression + * + * @remarks + * If you provide the cost field, you must also provide one of 'cpa', 'cpc', and 'cpm' for the costModel field. + */ +export interface AdImpressionEvent { + /** Identifier for the particular impression instance */ + impressionId?: string; + /** The cost model for the campaign */ + costModel?: 'cpa' | 'cpc' | 'cpm'; + /** Advertisement cost */ + cost?: number; + /** The destination URL of the advertisement */ + targetUrl?: string; + /** Identifier for the ad banner being displayed */ + bannerId?: string; + /** Identifier for the zone where the ad banner is located */ + zoneId?: string; + /** Identifier for the advertiser which the campaign belongs to */ + advertiserId?: string; + /** Identifier for the advertiser which the campaign belongs to */ + campaignId?: string; +} + +/** + * Build a Ad Impression Event + * Used to track an advertisement impression + * + * @remarks + * If you provide the cost field, you must also provide one of 'cpa', 'cpc', and 'cpm' for the costModel field. + * + * @param event - Contains the properties for the Ad Impression event + * @returns PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track} + */ +export function buildAdImpression(event: AdImpressionEvent): PayloadBuilder { + const { impressionId, costModel, cost, targetUrl, bannerId, zoneId, advertiserId, campaignId } = event; + const eventJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/ad_impression/jsonschema/1-0-0', + data: removeEmptyProperties({ + impressionId, + costModel, + cost, + targetUrl, + bannerId, + zoneId, + advertiserId, + campaignId, + }), + }; + + return buildSelfDescribingEvent({ event: eventJson }); +} + +/** + * An Ad Click Event + * Used to track an advertisement click + * + * @remarks + * If you provide the cost field, you must also provide one of 'cpa', 'cpc', and 'cpm' for the costModel field. + */ +export interface AdClickEvent { + /** The destination URL of the advertisement */ + targetUrl: string; + /** Identifier for the particular click instance */ + clickId?: string; + /** The cost model for the campaign */ + costModel?: 'cpa' | 'cpc' | 'cpm'; + /** Advertisement cost */ + cost?: number; + /** Identifier for the ad banner being displayed */ + bannerId?: string; + /** Identifier for the zone where the ad banner is located */ + zoneId?: string; + /** Identifier for the particular impression instance */ + impressionId?: string; + /** Identifier for the advertiser which the campaign belongs to */ + advertiserId?: string; + /** Identifier for the advertiser which the campaign belongs to */ + campaignId?: string; +} + +/** + * Build a Ad Click Event + * Used to track an advertisement click + * + * @remarks + * If you provide the cost field, you must also provide one of 'cpa', 'cpc', and 'cpm' for the costModel field. + * + * @param event - Contains the properties for the Ad Click event + * @returns PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track} + */ +export function buildAdClick(event: AdClickEvent): PayloadBuilder { + const { targetUrl, clickId, costModel, cost, bannerId, zoneId, impressionId, advertiserId, campaignId } = event; + const eventJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/ad_click/jsonschema/1-0-0', + data: removeEmptyProperties({ + targetUrl, + clickId, + costModel, + cost, + bannerId, + zoneId, + impressionId, + advertiserId, + campaignId, + }), + }; + + return buildSelfDescribingEvent({ event: eventJson }); +} + +/** + * An Ad Conversion Event + * Used to track an advertisement click + * + * @remarks + * If you provide the cost field, you must also provide one of 'cpa', 'cpc', and 'cpm' for the costModel field. + */ +export interface AdConversionEvent { + /** Identifier for the particular conversion instance */ + conversionId?: string; + /** The cost model for the campaign */ + costModel?: 'cpa' | 'cpc' | 'cpm'; + /** Advertisement cost */ + cost?: number; + /** Conversion category */ + category?: string; + /** The type of user interaction e.g. 'purchase' */ + action?: string; + /** Describes the object of the conversion */ + property?: string; + /** How much the conversion is initially worth */ + initialValue?: number; + /** Identifier for the advertiser which the campaign belongs to */ + advertiserId?: string; + /** Identifier for the advertiser which the campaign belongs to */ + campaignId?: string; +} + +/** + * Build a Ad Conversion Event + * Used to track an advertisement click + * + * @remarks + * If you provide the cost field, you must also provide one of 'cpa', 'cpc', and 'cpm' for the costModel field. + * + * @param event - Contains the properties for the Ad Conversion event + * @returns PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track} + */ +export function buildAdConversion(event: AdConversionEvent): PayloadBuilder { + const { conversionId, costModel, cost, category, action, property, initialValue, advertiserId, campaignId } = event; + const eventJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/ad_conversion/jsonschema/1-0-0', + data: removeEmptyProperties({ + conversionId, + costModel, + cost, + category, + action, + property, + initialValue, + advertiserId, + campaignId, + }), + }; + + return buildSelfDescribingEvent({ event: eventJson }); +} + +/** + * A Social Interaction Event + * Social tracking will be used to track the way users interact + * with Facebook, Twitter and Google + widgets + * e.g. to capture “like this” or “tweet this” events. + */ +export interface SocialInteractionEvent { + /** Social action performed */ + action: string; + /** Social network */ + network: string; + /** Object social action is performed on */ + target?: string; +} + +/** + * Build a Social Interaction Event + * Social tracking will be used to track the way users interact + * with Facebook, Twitter and Google + widgets + * e.g. to capture “like this” or “tweet this” events. + * + * @param event - Contains the properties for the Social Interaction event + * @returns PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track} + */ +export function buildSocialInteraction(event: SocialInteractionEvent): PayloadBuilder { + const { action, network, target } = event; + const eventJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/social_interaction/jsonschema/1-0-0', + data: removeEmptyProperties({ action, network, target }), + }; + + return buildSelfDescribingEvent({ event: eventJson }); +} + +/** + * An Add To Cart Event + * For tracking users adding items from a cart + * on an ecommerce site. + */ +export interface AddToCartEvent { + /** A Product Stock Keeping Unit (SKU) */ + sku: string; + /** The number added to the cart */ + quantity: number; + /** The name of the product */ + name?: string; + /** The category of the product */ + category?: string; + /** The price of the product */ + unitPrice?: number; + /** The currency of the product */ + currency?: string; +} + +/** + * Build a Add To Cart Event + * For tracking users adding items from a cart + * on an ecommerce site. + * + * @param event - Contains the properties for the Add To Cart event + * @returns PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track} + */ +export function buildAddToCart(event: AddToCartEvent): PayloadBuilder { + const { sku, quantity, name, category, unitPrice, currency } = event; + return buildSelfDescribingEvent({ + event: { + schema: 'iglu:com.snowplowanalytics.snowplow/add_to_cart/jsonschema/1-0-0', + data: removeEmptyProperties({ + sku, + quantity, + name, + category, + unitPrice, + currency, + }), + }, + }); +} + +/** + * An Remove To Cart Event + * For tracking users removing items from a cart + * on an ecommerce site. + */ +export interface RemoveFromCartEvent { + /** A Product Stock Keeping Unit (SKU) */ + sku: string; + /** The number removed from the cart */ + quantity: number; + /** The name of the product */ + name?: string; + /** The category of the product */ + category?: string; + /** The price of the product */ + unitPrice?: number; + /** The currency of the product */ + currency?: string; +} + +/** + * Build a Remove From Cart Event + * For tracking users removing items from a cart + * on an ecommerce site. + * + * @param event - Contains the properties for the Remove From Cart event + * @returns PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track} + */ +export function buildRemoveFromCart(event: RemoveFromCartEvent): PayloadBuilder { + const { sku, quantity, name, category, unitPrice, currency } = event; + return buildSelfDescribingEvent({ + event: { + schema: 'iglu:com.snowplowanalytics.snowplow/remove_from_cart/jsonschema/1-0-0', + data: removeEmptyProperties({ + sku, + quantity, + name, + category, + unitPrice, + currency, + }), + }, + }); +} + +/** + * Represents either a Form Focus or Form Change event + * When a user focuses on a form element or when a user makes a + * change to a form element. + */ +export interface FormFocusOrChangeEvent { + /** The schema which will be used for the event */ + schema: 'change_form' | 'focus_form'; + /** The ID of the form which the element belongs to */ + formId: string; + /** The element ID which the user is interacting with */ + elementId: string; + /** The name of the node ("INPUT", "TEXTAREA", "SELECT") */ + nodeName: string; + /** The value of the element at the time of the event firing */ + value: string | null; + /** The type of element (e.g. "datetime", "text", "radio", etc.) */ + type?: string | null; + /** The class names on the element */ + elementClasses?: Array | null; +} + +/** + * Build a Form Focus or Change Form Event based on schema property + * When a user focuses on a form element or when a user makes a + * change to a form element. + * + * @param event - Contains the properties for the Form Focus or Change Form event + * @returns PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track} + */ +export function buildFormFocusOrChange(event: FormFocusOrChangeEvent): PayloadBuilder { + let event_schema = ''; + const { schema, formId, elementId, nodeName, elementClasses, value, type } = event; + const event_data: Record = { formId, elementId, nodeName, elementClasses, value }; + if (schema === 'change_form') { + event_schema = 'iglu:com.snowplowanalytics.snowplow/change_form/jsonschema/1-0-0'; + event_data.type = type; + } else if (schema === 'focus_form') { + event_schema = 'iglu:com.snowplowanalytics.snowplow/focus_form/jsonschema/1-0-0'; + event_data.elementType = type; + } + return buildSelfDescribingEvent({ + event: { + schema: event_schema, + data: removeEmptyProperties(event_data, { value: true }), + }, + }); +} + +/** + * A representation of an element within a form + */ +export type FormElement = { + /** The name of the element */ + name: string; + /** The current value of the element */ + value: string | null; + /** The name of the node ("INPUT", "TEXTAREA", "SELECT") */ + nodeName: string; + /** The type of element (e.g. "datetime", "text", "radio", etc.) */ + type?: string | null; +}; + +/** + * A Form Submission Event + * Used to track when a user submits a form + */ +export interface FormSubmissionEvent { + /** The ID of the form */ + formId: string; + /** The class names on the form */ + formClasses?: Array; + /** The elements contained within the form */ + elements?: Array; +} + +/** + * Build a Form Submission Event + * Used to track when a user submits a form + * + * @param event - Contains the properties for the Form Submission event + * @returns PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track} + */ +export function buildFormSubmission(event: FormSubmissionEvent): PayloadBuilder { + const { formId, formClasses, elements } = event; + return buildSelfDescribingEvent({ + event: { + schema: 'iglu:com.snowplowanalytics.snowplow/submit_form/jsonschema/1-0-0', + data: removeEmptyProperties({ formId, formClasses, elements }), + }, + }); +} + +/** + * A Site Search Event + * Used when a user performs a search action on a page + */ +export interface SiteSearchEvent { + /** The terms of the search */ + terms: Array; + /** Any filters which have been applied to the search */ + filters?: Record; + /** The total number of results for this search */ + totalResults?: number; + /** The number of visible results on the page */ + pageResults?: number; +} + +/** + * Build a Site Search Event + * Used when a user performs a search action on a page + * + * @param event - Contains the properties for the Site Search event + * @returns PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track} + */ +export function buildSiteSearch(event: SiteSearchEvent): PayloadBuilder { + const { terms, filters, totalResults, pageResults } = event; + return buildSelfDescribingEvent({ + event: { + schema: 'iglu:com.snowplowanalytics.snowplow/site_search/jsonschema/1-0-0', + data: removeEmptyProperties({ terms, filters, totalResults, pageResults }), + }, + }); +} + +/** + * A Consent Withdrawn Event + * Used for tracking when a user withdraws their consent + */ +export interface ConsentWithdrawnEvent { + /** Specifies whether all consent should be withdrawn */ + all: boolean; + /** Identifier for the document withdrawing consent */ + id?: string; + /** Version of the document withdrawing consent */ + version?: string; + /** Name of the document withdrawing consent */ + name?: string; + /** Description of the document withdrawing consent */ + description?: string; +} + +/** + * Interface for returning a built event (PayloadBuilder) and context (Array of SelfDescribingJson). + */ +export interface EventPayloadAndContext { + /** Tracker payload for the event data */ + event: PayloadBuilder; + /** List of context entities to track along with the event */ + context: Array; +} + +/** + * Build a Consent Withdrawn Event + * Used for tracking when a user withdraws their consent + * + * @param event - Contains the properties for the Consent Withdrawn event + * @returns An object containing the PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track} and a 'consent_document' context + */ +export function buildConsentWithdrawn(event: ConsentWithdrawnEvent): EventPayloadAndContext { + const { all, id, version, name, description } = event; + const documentJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/consent_document/jsonschema/1-0-0', + data: removeEmptyProperties({ id, version, name, description }), + }; + + return { + event: buildSelfDescribingEvent({ + event: { + schema: 'iglu:com.snowplowanalytics.snowplow/consent_withdrawn/jsonschema/1-0-0', + data: removeEmptyProperties({ + all: all, + }), + }, + }), + context: [documentJson], + }; +} + +/** + * A Consent Granted Event + * Used for tracking when a user grants their consent + */ +export interface ConsentGrantedEvent { + /** Identifier for the document granting consent */ + id: string; + /** Version of the document granting consent */ + version: string; + /** Name of the document granting consent */ + name?: string; + /** Description of the document granting consent */ + description?: string; + /** When the consent expires */ + expiry?: string; +} + +/** + * Build a Consent Granted Event + * Used for tracking when a user grants their consent + * + * @param event - Contains the properties for the Consent Granted event + * @returns An object containing the PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track} and a 'consent_document' context + */ +export function buildConsentGranted(event: ConsentGrantedEvent): EventPayloadAndContext { + const { expiry, id, version, name, description } = event; + const documentJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/consent_document/jsonschema/1-0-0', + data: removeEmptyProperties({ id, version, name, description }), + }; + + return { + event: buildSelfDescribingEvent({ + event: { + schema: 'iglu:com.snowplowanalytics.snowplow/consent_granted/jsonschema/1-0-0', + data: removeEmptyProperties({ + expiry: expiry, + }), + }, + }), + context: [documentJson], + }; +} + +/** + * Returns a copy of a JSON with undefined and null properties removed + * + * @param event - JSON object to clean + * @param exemptFields - Set of fields which should not be removed even if empty + * @returns A cleaned copy of eventJson + */ +export function removeEmptyProperties( + event: Record, + exemptFields: Record = {} +): Record { + const ret: Record = {}; + for (const k in event) { + if (exemptFields[k] || (event[k] !== null && typeof event[k] !== 'undefined')) { + ret[k] = event[k]; + } + } + return ret; +} diff --git a/libraries/tracker-core/src/emitter/emitter_event.ts b/libraries/tracker-core/src/emitter/emitter_event.ts new file mode 100644 index 000000000..1f0db2899 --- /dev/null +++ b/libraries/tracker-core/src/emitter/emitter_event.ts @@ -0,0 +1,160 @@ +import { EventStorePayload } from "../event_store_payload"; +import { Payload } from "../payload"; + +/** + * Wraps a payload and provides methods to get the payload ready for a GET or POST request + */ +export interface EmitterEvent { + /** + * Get the original payload + */ + getPayload: () => Payload; + /** + * Get the server anonymization setting + * @returns true if the server should anonymize the IP address + */ + getServerAnonymization: () => boolean; + /** + * Prepare the payload for a POST request + */ + getPOSTRequestBody: () => Record; + /** + * Calculate the byte size of the payload when POSTed + */ + getPOSTRequestBytesCount: () => number; + /** + * Get the URL for a GET request + */ + getGETRequestURL: (collectorUrl: string, useStm: boolean) => string; + /** + * Calculate the byte size of the payload when sent via GET + */ + getGETRequestBytesCount: () => number; +} + +/** + * Count the number of bytes a string will occupy when UTF-8 encoded + * Taken from http://stackoverflow.com/questions/2848462/count-bytes-in-textarea-using-javascript/ + * + * @param s - The string + * @returns number Length of s in bytes when UTF-8 encoded + */ +function getUTF8Length(s: string) { + let len = 0; + for (let i = 0; i < s.length; i++) { + const code = s.charCodeAt(i); + if (code <= 0x7f) { + len += 1; + } else if (code <= 0x7ff) { + len += 2; + } else if (code >= 0xd800 && code <= 0xdfff) { + // Surrogate pair: These take 4 bytes in UTF-8 and 2 chars in UCS-2 + // (Assume next char is the other [valid] half and just skip it) + len += 4; + i++; + } else if (code < 0xffff) { + len += 3; + } else { + len += 4; + } + } + return len; +} + +/* + * Convert a dictionary to a querystring + * The context field is the last in the querystring + */ +function getQuerystring(request: Payload) { + let lowPriorityKeys: { [key: string]: boolean } = { co: true, cx: true }; + + let args: string[] = []; + + for (const key in request) { + if (request.hasOwnProperty(key) && !lowPriorityKeys[key]) { + args.push(key + '=' + encodeURIComponent(request[key] as string | number | boolean)); + } + } + + for (const contextKey in lowPriorityKeys) { + if (request.hasOwnProperty(contextKey) && lowPriorityKeys[contextKey]) { + args.push(contextKey + '=' + encodeURIComponent(request[contextKey] as string | number | boolean)); + } + } + + return '?' + args.join('&'); +} + +/* + * Convert numeric fields to strings to match payload_data schema + */ +function preparePostBody(request: Payload): Record { + const cleanedRequest = Object.keys(request) + .map<[string, unknown]>((k) => [k, request[k]]) + .reduce((acc, [key, value]) => { + acc[key] = (value as Object).toString(); + return acc; + }, {} as Record); + return cleanedRequest; +} + +export function newEmitterEvent(eventStorePayload: EventStorePayload): EmitterEvent { + let querystring: string | null = null; + let postBody: Record | null = null; + let byteCountGET: number | null = null; + let byteCountPOST: number | null = null; + + function getPayload(): Payload { + return eventStorePayload.payload; + } + + function getServerAnonymization(): boolean { + return eventStorePayload.svrAnon ?? false; + } + + function getCachedQuerystring(payload: Payload): string { + if (querystring === null) { + querystring = getQuerystring(payload); + } + return querystring; + } + + function getGETRequestURL(collectorUrl: string, useStm: boolean): string { + const querystring = getCachedQuerystring(getPayload()); + if (useStm) { + return collectorUrl + querystring.replace('?', '?stm=' + new Date().getTime() + '&'); + } + + return collectorUrl + querystring; + } + + function getGETRequestBytesCount(): number { + if (byteCountGET === null) { + const querystring = getCachedQuerystring(getPayload()); + byteCountGET = getUTF8Length(querystring); + } + return byteCountGET; + } + + function getPOSTRequestBody(): Record { + if (postBody === null) { + postBody = preparePostBody(getPayload()); + } + return postBody; + } + + function getPOSTRequestBytesCount(): number { + if (byteCountPOST === null) { + byteCountPOST = getUTF8Length(JSON.stringify(getPOSTRequestBody())); + } + return byteCountPOST; + } + return { + getPayload, + getServerAnonymization, + getGETRequestURL, + getGETRequestBytesCount, + getPOSTRequestBody, + getPOSTRequestBytesCount, + }; +} diff --git a/libraries/tracker-core/src/emitter/emitter_request.ts b/libraries/tracker-core/src/emitter/emitter_request.ts new file mode 100644 index 000000000..869dc9528 --- /dev/null +++ b/libraries/tracker-core/src/emitter/emitter_request.ts @@ -0,0 +1,251 @@ +import { PAYLOAD_DATA_SCHEMA } from '../schemata'; +import { EmitterEvent } from "./emitter_event"; + +/** + * Wrapper around a request with events to the collector. + * Provides helpers to manage the request and its events. + * Prepare the request to be sent to the collector. + */ +export interface EmitterRequest { + /** + * Add an event to the request + * @returns true if the event was added, false if the server anonymization setting does not match the existing events + */ + addEvent: (event: EmitterEvent) => boolean; + /** + * Get the events attached to the request + */ + getEvents: () => EmitterEvent[]; + /** + * Creates a fetch Request object from the events + */ + toRequest: () => Request | undefined; + /** + * Whether the request is full or events can still be added + */ + isFull: () => boolean; + /** + * Size of the request in bytes + */ + countBytes: () => number; + /** + * The number of events attached to the request + */ + countEvents: () => number; + /** + * Cancel timeout timer if it is still pending. + * If not successful, the request will be aborted. + * @param successful - Whether the request was successful + * @param reason - Reason for aborting the request + */ + closeRequest: (successful: boolean, reason?: string) => void; +} + +export interface EmitterRequestConfiguration { + endpoint: string; + port?: number; + protocol?: 'http' | 'https'; + eventMethod?: 'get' | 'post'; + customHeaders?: Record; + connectionTimeout?: number; + keepalive?: boolean; + postPath?: string; + useStm?: boolean; + maxPostBytes?: number, + credentials?: 'omit' | 'same-origin' | 'include'; +} + +/** + * Enclose an array of events in a self-describing payload_data JSON string + * + * @param array - events Batch of events + * @returns string payload_data self-describing JSON + */ +export function encloseInPayloadDataEnvelope(events: Array>) { + return JSON.stringify({ + schema: PAYLOAD_DATA_SCHEMA, + data: events, + }); +} + +/** + * Attaches the STM field to outbound POST events. + * + * @param events - the events to attach the STM to + */ +export function attachStmToEvent(events: Array>) { + const stm = new Date().getTime().toString(); + for (let i = 0; i < events.length; i++) { + events[i]['stm'] = stm; + } + return events; +} + +export function newEmitterRequest({ + endpoint, + protocol = 'https', + port, + eventMethod = 'post', + customHeaders, + connectionTimeout, + keepalive = false, + postPath = '/com.snowplowanalytics.snowplow/tp2', + useStm = true, + maxPostBytes = 40000, + credentials = 'include', +}: EmitterRequestConfiguration): EmitterRequest { + let events: EmitterEvent[] = []; + let usePost = eventMethod.toLowerCase() === 'post'; + let timer: ReturnType | undefined; + let abortController: AbortController | undefined; + + function countBytes(): number { + let count = events.reduce( + (acc, event) => acc + (usePost ? event.getPOSTRequestBytesCount() : event.getGETRequestBytesCount()), + 0 + ); + if (usePost) { + count += 88; // 88 bytes for the payload_data envelope + } + return count; + } + + function countEvents(): number { + return events.length; + } + + function getServerAnonymizationOfExistingEvents(): boolean | undefined { + return events.length > 0 ? events[0].getServerAnonymization() : undefined; + } + + function addEvent(event: EmitterEvent) { + if (events.length > 0 && getServerAnonymizationOfExistingEvents() !== event.getServerAnonymization()) { + return false; + } else { + events.push(event); + return true; + } + } + + function getEvents(): EmitterEvent[] { + return events; + } + + function isFull(): boolean { + if (usePost) { + return countBytes() >= maxPostBytes; + } else { + return events.length >= 1; + } + } + + function createHeaders(): Headers { + const headers = new Headers(); + if (usePost) { + headers.append('Content-Type', 'application/json; charset=UTF-8'); + } + if (customHeaders) { + Object.keys(customHeaders).forEach((key) => { + headers.append(key, customHeaders[key]); + }); + } + if (getServerAnonymizationOfExistingEvents()) { + headers.append('SP-Anonymous', '*'); + } + return headers; + } + + function getFullCollectorUrl(): string { + let collectorUrl = endpoint; + if (!endpoint.includes('://')) { + collectorUrl = `${protocol}://${endpoint}`; + } + if (port) { + collectorUrl = `${collectorUrl}:${port}`; + } + + const path = usePost ? postPath : '/i'; + return collectorUrl + path; + } + + function makeRequest(url: string, options: RequestInit): Request { + closeRequest(false); + + abortController = new AbortController(); + timer = setTimeout(() => { + const reason = 'Request timed out'; + console.error(reason); + timer = undefined; + closeRequest(false, reason); + }, connectionTimeout ?? 5000); + + const requestOptions: RequestInit = { + headers: createHeaders(), + signal: abortController.signal, + keepalive, + credentials, + ...options, + }; + + const request = new Request(url, requestOptions); + return request; + } + + function makePostRequest(): Request { + const batch = attachStmToEvent(events.map((event) => event.getPOSTRequestBody())); + + return makeRequest(getFullCollectorUrl(), { + method: 'POST', + body: encloseInPayloadDataEnvelope(batch), + }); + } + + function makeGetRequest(): Request { + if (events.length !== 1) { + throw new Error('Only one event can be sent in a GET request'); + } + + const event = events[0]; + const url = event.getGETRequestURL(getFullCollectorUrl(), useStm); + + return makeRequest(url, { + method: 'GET', + }); + } + + function toRequest(): Request | undefined { + if (events.length === 0) { + return undefined; + } + if (usePost) { + return makePostRequest(); + } else { + return makeGetRequest(); + } + } + + function closeRequest(successful: boolean, reason?: string) { + if (timer !== undefined) { + clearTimeout(timer); + timer = undefined; + } + + if (abortController !== undefined) { + const controller = abortController; + abortController = undefined; + if (!successful) { + controller.abort(reason); + } + } + } + + return { + addEvent, + getEvents, + toRequest, + countBytes, + countEvents, + isFull, + closeRequest, + }; +} diff --git a/libraries/tracker-core/src/emitter/index.ts b/libraries/tracker-core/src/emitter/index.ts new file mode 100644 index 000000000..35e3649e8 --- /dev/null +++ b/libraries/tracker-core/src/emitter/index.ts @@ -0,0 +1,456 @@ +import { EventStore, newInMemoryEventStore } from '../event_store'; +import { Payload } from '../payload'; +import { EmitterRequest, newEmitterRequest } from './emitter_request'; +import { EmitterEvent, newEmitterEvent } from './emitter_event'; +import { newEventStorePayload } from '../event_store_payload'; +import { LOG } from '../logger'; + +/** + * A collection of event payloads which are sent to the collector. + */ +export type EventBatch = Payload[]; + +/** + * The data that will be available to the `onRequestFailure` callback + */ +export type RequestFailure = { + /** The batch of events that failed to send */ + events: EventBatch; + /** The status code of the failed request */ + status?: number; + /** The error message of the failed request */ + message?: string; + /** Whether the tracker will retry the request */ + willRetry: boolean; +}; + +/* The supported methods which events can be sent with */ +export type EventMethod = 'post' | 'get'; + +export interface EmitterConfigurationBase { + /** + * The preferred technique to use to send events + * @defaultValue post + */ + eventMethod?: EventMethod; + /** + * The post path which events will be sent to. + * Ensure your collector is configured to accept events on this post path + * @defaultValue '/com.snowplowanalytics.snowplow/tp2' + */ + postPath?: string; + /** + * The amount of events that should be buffered before sending + * Recommended to leave as 1 to reduce change of losing events + * @defaultValue 1 on Web, 10 on Node + */ + bufferSize?: number; + /** + * The max size a POST request can be before the tracker will force send it + * Also dictates the max size of a POST request before a batch of events is split into multiple requests + * @defaultValue 40000 + */ + maxPostBytes?: number; + /** + * The max size a GET request (its complete URL) can be. Requests over this size will be tried as a POST request. + * @defaultValue unlimited + */ + maxGetBytes?: number; + /** + * Should the Sent Timestamp be attached to events. + * Only applies for GET events. + * @defaultValue true + */ + useStm?: boolean; + /** + * How long to wait before aborting requests to the collector + * @defaultValue 5000 (milliseconds) + */ + connectionTimeout?: number; + /** + * An object of key value pairs which represent headers to + * attach when sending a POST request, only works for POST + * @defaultValue `{}` + */ + customHeaders?: Record; + /** + * Controls whether or not the browser sends credentials (defaults to 'include') + * @defaultValue 'include' + */ + credentials?: 'omit' | 'same-origin' | 'include'; + /** + * Whether to retry failed requests to the collector. + * + * Failed requests are requests that failed due to + * [timeouts](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/timeout_event), + * [network errors](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/error_event), + * and [abort events](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/abort_event). + * + * Takes precedent over `retryStatusCodes` and `dontRetryStatusCodes`. + * + * @defaultValue true + */ + retryFailedRequests?: boolean; + /** + * List of HTTP response status codes for which events sent to Collector should be retried in future requests. + * Only non-success status codes are considered (greater or equal to 300). + * The retry codes are only considered for GET and POST requests. + * They take priority over the `dontRetryStatusCodes` option. + * By default, the tracker retries on all non-success status codes except for 400, 401, 403, 410, and 422. + */ + retryStatusCodes?: number[]; + /** + * List of HTTP response status codes for which events sent to Collector should not be retried in future request. + * Only non-success status codes are considered (greater or equal to 300). + * The don't retry codes are only considered for GET and POST requests. + * By default, the tracker retries on all non-success status codes except for 400, 401, 403, 410, and 422 (these don't retry codes will remain even if you set your own `dontRetryStatusCodes` but can be changed using the `retryStatusCodes`). + */ + dontRetryStatusCodes?: number[]; + /** + * Cookie extension service full URL. This URL will be added to the queue and will be called using a GET method. + * This option is there to allow the service URL to be called in order to set any required identifiers e.g. extra cookies. + * + * The request respects the `anonymousTracking` option, including the SP-Anonymous header if needed, and any additional custom headers from the customHeaders option. + */ + cookieExtensionService?: string; + /** + * @deprecated Use `cookieExtensionService` instead. + */ + idService?: string; + /** + * Indicates that the request should be allowed to outlive the webpage that initiated it. + * Enables collector requests to complete even if the page is closed or navigated away from. + * Note: Browsers put a limit on keepalive requests of 64KB. In case of multiple keepalive requests in parallel (may happen in case of multiple trackers), the limit is shared. + * @defaultValue false + */ + keepalive?: boolean; + /** + * Enables overriding the default fetch function with a custom implementation. + * @param input - Instance of Request + * @param options - Additional options for the request + * @returns A Promise that resolves to the Response. + */ + customFetch?: (input: Request, options?: RequestInit) => Promise; + /** + * A callback function to be executed whenever a request is successfully sent to the collector. + * In practice this means any request which returns a 2xx status code will trigger this callback. + * + * @param data - The event batch that was successfully sent + */ + onRequestSuccess?: (data: EventBatch, response: Response) => void; + /** + * A callback function to be executed whenever a request fails to be sent to the collector. + * This is the inverse of the onRequestSuccess callback, so any non 2xx status code will trigger this callback. + * + * @param data - The data associated with the event(s) that failed to send + */ + onRequestFailure?: (data: RequestFailure, response?: Response) => void; + /** + * Enables providing a custom EventStore implementation to store events before sending them to the collector. + */ + eventStore?: EventStore; +} + +export interface EmitterConfiguration extends EmitterConfigurationBase { + /* The collector URL to which events will be sent */ + endpoint: string; + /* http or https. Defaults to https */ + protocol?: 'http' | 'https'; + /* Collector port number */ + port?: number; + /* If the request should undergo server anonymization. */ + serverAnonymization?: boolean; +} + +/** + * Emitter is responsible for sending events to the collector. + * It manages the event queue and sends events in batches depending on configuration. + */ +export interface Emitter { + /** + * Forces the emitter to send all events in the event store to the collector. + * @returns A Promise that resolves when all events have been sent to the collector. + */ + flush: () => Promise; + /** + * Adds a payload to the event store or sends it to the collector. + * @param payload - A payload to be sent to the collector + * @returns Promise that resolves when the payload has been added to the event store or sent to the collector + */ + input: (payload: Payload) => Promise; + /** + * Updates the collector URL to which events will be sent. + * @param url - New collector URL + */ + setCollectorUrl: (url: string) => void; + /** + * Sets the server anonymization flag. + */ + setAnonymousTracking: (anonymous: boolean) => void; + /** + * Updates the buffer size of the emitter. + */ + setBufferSize: (bufferSize: number) => void; +} + +interface RequestResult { + success: boolean; + retry: boolean; + status?: number; +} + +export function newEmitter({ + endpoint, + eventMethod = 'post', + postPath, + protocol, + port, + maxPostBytes = 40000, + maxGetBytes, + bufferSize = 1, + customHeaders, + serverAnonymization, + connectionTimeout, + keepalive, + cookieExtensionService, + idService, + dontRetryStatusCodes = [], + retryStatusCodes = [], + retryFailedRequests = true, + onRequestFailure, + onRequestSuccess, + customFetch = fetch, + useStm, + eventStore = newInMemoryEventStore({}), + credentials, +}: EmitterConfiguration): Emitter { + /* `cookieExtensionService` gets priority until `idService` is completely removed. */ + cookieExtensionService = cookieExtensionService || idService; + + let cookieExtensionServiceCalled = false; + let flushInProgress = false; + const usePost = eventMethod.toLowerCase() === 'post'; + dontRetryStatusCodes = dontRetryStatusCodes.concat([400, 401, 403, 410, 422]); + + function shouldRetryForStatusCode(statusCode: number): boolean { + // success, don't retry + if (statusCode >= 200 && statusCode < 300) { + return false; + } + + if (!retryFailedRequests) { + return false; + } + + // retry if status code among custom user-supplied retry codes + if (retryStatusCodes.includes(statusCode)) { + return true; + } + + // retry if status code *not* among the don't retry codes + return !dontRetryStatusCodes.includes(statusCode); + } + + function callOnRequestSuccess(payloads: Payload[], response: Response) { + if (onRequestSuccess !== undefined) { + setTimeout(() => { + try { + onRequestSuccess?.(payloads, response); + } catch (e) { + LOG.error('Error in onRequestSuccess', e); + } + }, 0); + } + } + + function callOnRequestFailure(failure: RequestFailure, response?: Response) { + if (onRequestFailure !== undefined) { + setTimeout(() => { + try { + onRequestFailure?.(failure, response); + } catch (e) { + LOG.error('Error in onRequestFailure', e); + } + }, 0); + } + } + + async function executeRequest(request: EmitterRequest): Promise { + const fetchRequest = request.toRequest(); + if (fetchRequest === undefined) { + throw new Error('Empty batch'); + } + + const payloads = request.getEvents().map((event) => event.getPayload()); + try { + const response = await customFetch(fetchRequest); + await response.text(); // wait for the response to be fully read + + request.closeRequest(true); + + if (response.ok) { + callOnRequestSuccess(payloads, response); + return { success: true, retry: false, status: response.status }; + } else { + const willRetry = shouldRetryForStatusCode(response.status); + callOnRequestFailure( + { + events: payloads, + status: response.status, + message: response.statusText, + willRetry: willRetry, + }, + response + ); + return { success: false, retry: willRetry, status: response.status }; + } + } catch (e) { + request.closeRequest(false); + + const message = typeof e === 'string' ? e : e ? (e as Error).message : 'Unknown error'; + callOnRequestFailure({ + events: payloads, + message: message, + willRetry: true, + }); + return { success: false, retry: true }; + } + } + + function newEmitterRequestWithConfig(): EmitterRequest { + return newEmitterRequest({ + endpoint, + protocol, + port, + eventMethod, + customHeaders, + connectionTimeout, + keepalive, + maxPostBytes, + useStm, + credentials, + postPath, + }); + } + + function shouldSkipEventStore(emitterEvent: EmitterEvent): boolean { + const eventTooBigWarning = (bytes: number, maxBytes: number) => + LOG.warn('Event (' + bytes + 'B) too big, max is ' + maxBytes); + + if (usePost) { + const bytes = emitterEvent.getPOSTRequestBytesCount() + 88; // 88 bytes for the payload_data envelope + const tooBig = bytes > maxPostBytes; + if (tooBig) { + eventTooBigWarning(bytes, maxPostBytes); + } + return tooBig; + } else { + if (maxGetBytes === undefined) { + return false; + } + const bytes = emitterEvent.getGETRequestBytesCount(); + const tooBig = bytes > maxGetBytes; + if (tooBig) { + eventTooBigWarning(bytes, maxGetBytes); + } + return tooBig; + } + } + + async function callCookieExtensionService() { + if (cookieExtensionService && !cookieExtensionServiceCalled) { + cookieExtensionServiceCalled = true; + const request = new Request(cookieExtensionService, { method: 'GET' }); + await customFetch(request); + } + } + + async function flush() { + if (!flushInProgress) { + flushInProgress = true; + + try { + await continueFlush(); + } catch (e) { + LOG.error('Error sending events', e); + } finally { + flushInProgress = false; + } + } + } + + async function continueFlush() { + await callCookieExtensionService(); + + const request = newEmitterRequestWithConfig(); + const eventStoreIterator = eventStore.iterator(); + + while (true) { + if (request.isFull()) { + break; + } + + const { value, done } = await eventStoreIterator.next(); + if (done || value === undefined) { + break; + } + + const event = newEmitterEvent(value); + if (!request.addEvent(event)) { + break; + } + } + + if (request.countEvents() === 0) { + return; + } + + const { success, retry, status } = await executeRequest(request); + + if (success || !retry) { + if (!success) { + LOG.error(`Status ${status}, will not retry.`); + } + await eventStore.removeHead(request.countEvents()); + } + + if (success) { + await continueFlush(); + } + } + + async function input(payload: Payload) { + const eventStorePayload = newEventStorePayload({ payload, svrAnon: serverAnonymization }); + const event = newEmitterEvent(eventStorePayload); + if (shouldSkipEventStore(event)) { + const request = newEmitterRequestWithConfig(); + request.addEvent(event); + await executeRequest(request); + } else { + const count = await eventStore.add(eventStorePayload); + if (count >= bufferSize) { + await flush(); + } + } + } + + function setCollectorUrl(url: string) { + endpoint = url; + } + + function setAnonymousTracking(at: boolean) { + serverAnonymization = at; + } + + function setBufferSize(bs: number) { + bufferSize = bs; + } + + return { + flush, + input, + setCollectorUrl, + setAnonymousTracking, + setBufferSize, + }; +} diff --git a/libraries/tracker-core/src/event_store.ts b/libraries/tracker-core/src/event_store.ts new file mode 100644 index 000000000..36b8c5afb --- /dev/null +++ b/libraries/tracker-core/src/event_store.ts @@ -0,0 +1,116 @@ +import { EventStorePayload } from './event_store_payload'; +import { Payload } from './payload'; + +/** + * Result of the next operation on an EventStoreIterator. + */ +export interface EventStoreIteratorNextResult { + /** + * The next event in the store, or undefined if there are no more events. + */ + value: EventStorePayload | undefined; + /** + * True if there are no more events in the store. + */ + done: boolean; +} + +/** + * EventStoreIterator allows iterating over all events in the store. + */ +export interface EventStoreIterator { + /** + * Retrieve the next event in the store + */ + next: () => Promise; +} + +/** + * EventStore allows storing and retrieving events before they are sent to the collector + */ +export interface EventStore { + /** + * Count all events in the store + */ + count: () => Promise; + /** + * Add an event to the store + * @returns the number of events in the store after adding + */ + add: (payload: EventStorePayload) => Promise; + /** + * Remove the first `count` events from the store + */ + removeHead: (count: number) => Promise; + /** + * Get an iterator over all events in the store + */ + iterator: () => EventStoreIterator; + /** + * Retrieve all payloads including their meta configuration in the store + */ + getAll: () => Promise; + /** + * Retrieve all pure payloads in the store + */ + getAllPayloads: () => Promise; +} + +export interface EventStoreConfiguration { + /** + * The maximum amount of events that will be buffered in the event store + * + * This is useful to ensure the Tracker doesn't fill the 5MB or 10MB available to + * each website should the collector be unavailable due to lost connectivity. + * Will drop old events once the limit is hit + */ + maxSize?: number; +} + +export interface InMemoryEventStoreConfiguration { + /** + * Initial events to add to the store + */ + events?: EventStorePayload[]; +} + +export function newInMemoryEventStore({ + maxSize = 1000, + events = [], +}: EventStoreConfiguration & InMemoryEventStoreConfiguration): EventStore { + let store: EventStorePayload[] = [...events]; + + const count = () => Promise.resolve(store.length); + + return { + count, + add: (payload: EventStorePayload) => { + store.push(payload); + while (store.length > maxSize) { + store.shift(); + } + return count(); + }, + removeHead: (count: number) => { + for (let i = 0; i < count; i++) { + store.shift(); + } + return Promise.resolve(); + }, + iterator: () => { + let index = 0; + // copy the store to prevent mutation + let events = [...store]; + return { + next: () => { + if (index < events.length) { + return Promise.resolve({ value: events[index++], done: false }); + } + return Promise.resolve({ value: undefined, done: true }); + }, + }; + }, + getAll: () => Promise.resolve([...store]), + getAllPayloads: () => Promise.resolve(store.map((e) => e.payload)), + }; +} diff --git a/libraries/tracker-core/src/event_store_payload.ts b/libraries/tracker-core/src/event_store_payload.ts new file mode 100644 index 000000000..1a5c54a2a --- /dev/null +++ b/libraries/tracker-core/src/event_store_payload.ts @@ -0,0 +1,27 @@ +import { Payload } from "./payload"; + +export interface EventStorePayload { + /** + * The event payload to be stored + */ + payload: Payload; + + /** + * If the request should undergo server anonymization. + * @defaultValue false + */ + svrAnon?: boolean; +} + +/** + * Create a new EventStorePayload + */ +export function newEventStorePayload({ + payload, + svrAnon = false, +}: EventStorePayload): EventStorePayload { + return { + payload, + svrAnon, + }; +} diff --git a/libraries/tracker-core/src/index.ts b/libraries/tracker-core/src/index.ts new file mode 100644 index 000000000..5c0d702f3 --- /dev/null +++ b/libraries/tracker-core/src/index.ts @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * A library of helpful methods for Snowplow JavaScript Trackers + * Contains Context Generation, Event Payload Builders, and Core Plugins. + * + * @packageDocumentation + */ + +import { version as v } from '../package.json'; +export const version = v; + +export * from './contexts'; +export * from './plugins'; +export * from './payload'; +export * from './event_store_payload'; +export * from './core'; +export * from './logger'; +export * from './emitter'; +export * from './event_store'; diff --git a/libraries/tracker-core/src/logger.ts b/libraries/tracker-core/src/logger.ts new file mode 100644 index 000000000..030671936 --- /dev/null +++ b/libraries/tracker-core/src/logger.ts @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +const label = 'Snowplow: '; + +export enum LOG_LEVEL { + none = 0, + error = 1, + warn = 2, + debug = 3, + info = 4, +} + +export interface Logger { + setLogLevel: (level: LOG_LEVEL) => void; + info: (message: string, ...extraParams: unknown[]) => void; + debug: (message: string, ...extraParams: unknown[]) => void; + warn: (message: string, error?: unknown, ...extraParams: unknown[]) => void; + error: (message: string, error?: unknown, ...extraParams: unknown[]) => void; +} + +export const LOG = logger(); + +function logger(logLevel: LOG_LEVEL = LOG_LEVEL.warn): Logger { + function setLogLevel(level: LOG_LEVEL) { + if (LOG_LEVEL[level]) { + logLevel = level; + } else { + logLevel = LOG_LEVEL.warn; + } + } + + /** + * Log errors, with or without error object + */ + function error(message: string, error?: unknown, ...extraParams: unknown[]) { + if (logLevel >= LOG_LEVEL.error && typeof console !== 'undefined') { + const logMsg = label + message + '\n'; + if (error) { + console.error(logMsg + '\n', error, ...extraParams); + } else { + console.error(logMsg, ...extraParams); + } + } + } + + /** + * Log warnings, with or without error object + */ + function warn(message: string, error?: unknown, ...extraParams: unknown[]) { + if (logLevel >= LOG_LEVEL.warn && typeof console !== 'undefined') { + const logMsg = label + message; + if (error) { + console.warn(logMsg + '\n', error, ...extraParams); + } else { + console.warn(logMsg, ...extraParams); + } + } + } + + /** + * Log debug messages + */ + function debug(message: string, ...extraParams: unknown[]) { + if (logLevel >= LOG_LEVEL.debug && typeof console !== 'undefined') { + console.debug(label + message, ...extraParams); + } + } + + /** + * Log info messages + */ + function info(message: string, ...extraParams: unknown[]) { + if (logLevel >= LOG_LEVEL.info && typeof console !== 'undefined') { + console.info(label + message, ...extraParams); + } + } + + return { setLogLevel, warn, error, debug, info }; +} diff --git a/libraries/tracker-core/src/payload.ts b/libraries/tracker-core/src/payload.ts new file mode 100644 index 000000000..073e173ed --- /dev/null +++ b/libraries/tracker-core/src/payload.ts @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { base64urlencode, base64urldecode } from './base64'; +import type { SelfDescribingJson, SelfDescribingJsonArray } from './core'; + +/** + * Type for a Payload dictionary + */ +export type Payload = Record; + +/** + * A tuple which represents the unprocessed JSON to be added to the Payload + */ +export type EventJsonWithKeys = { keyIfEncoded: string; keyIfNotEncoded: string; json: Record }; + +/** + * An array of tuples which represents the unprocessed JSON to be added to the Payload + */ +export type EventJson = Array; + +/** + * A function which will processor the Json onto the injected PayloadBuilder + */ +export type JsonProcessor = ( + payloadBuilder: PayloadBuilder, + jsonForProcessing: EventJson, + contextEntitiesForProcessing: SelfDescribingJson[] +) => void; + +/** + * Interface for mutable object encapsulating tracker payload + */ +export interface PayloadBuilder { + /** + * Adds an entry to the Payload + * @param key - Key for Payload dictionary entry + * @param value - Value for Payload dictionaty entry + */ + add: (key: string, value: unknown) => void; + + /** + * Merges a payload into the existing payload + * @param dict - The payload to merge + */ + addDict: (dict: Payload) => void; + + /** + * Caches a JSON object to be added to payload on build + * @param keyIfEncoded - key if base64 encoding is enabled + * @param keyIfNotEncoded - key if base64 encoding is disabled + * @param json - The json to be stringified and added to the payload + */ + addJson: (keyIfEncoded: string, keyIfNotEncoded: string, json: Record) => void; + + /** + * Caches a context entity to be added to payload on build + * @param entity - Context entity to add to the event + */ + addContextEntity: (entity: SelfDescribingJson) => void; + + /** + * Gets the current payload, before cached JSON is processed + */ + getPayload: () => Payload; + + /** + * Gets all JSON objects added to payload + */ + getJson: () => EventJson; + + /** + * Adds a function which will be executed when building + * the payload to process the JSON which has been added to this payload + * @param jsonProcessor - The JsonProcessor function for this builder + */ + withJsonProcessor: (jsonProcessor: JsonProcessor) => void; + + /** + * Builds and returns the Payload + * @param base64Encode - configures if unprocessed, cached json should be encoded + */ + build: () => Payload; +} + +export function payloadBuilder(): PayloadBuilder { + const dict: Payload = {}, + allJson: EventJson = [], + jsonForProcessing: EventJson = [], + contextEntitiesForProcessing: SelfDescribingJson[] = []; + let processor: JsonProcessor | undefined; + + const add = (key: string, value: unknown): void => { + if (value != null && value !== '') { + // null also checks undefined + dict[key] = value; + } + }; + + const addDict = (dict: Payload): void => { + for (const key in dict) { + if (Object.prototype.hasOwnProperty.call(dict, key)) { + add(key, dict[key]); + } + } + }; + + const addJson = (keyIfEncoded: string, keyIfNotEncoded: string, json?: Record): void => { + if (json && isNonEmptyJson(json)) { + const jsonWithKeys = { keyIfEncoded, keyIfNotEncoded, json }; + jsonForProcessing.push(jsonWithKeys); + allJson.push(jsonWithKeys); + } + }; + + const addContextEntity = (entity: SelfDescribingJson): void => { + contextEntitiesForProcessing.push(entity); + }; + + return { + add, + addDict, + addJson, + addContextEntity, + getPayload: () => dict, + getJson: () => allJson, + withJsonProcessor: (jsonProcessor) => { + processor = jsonProcessor; + }, + build: function () { + processor?.(this, jsonForProcessing, contextEntitiesForProcessing); + return dict; + }, + }; +} + +/** + * A helper to build a Snowplow request from a set of name-value pairs, provided using the add methods. + * Will base64 encode JSON, if desired, on build + * + * @returns The request builder, with add and build methods + */ +export function payloadJsonProcessor(encodeBase64: boolean): JsonProcessor { + return ( + payloadBuilder: PayloadBuilder, + jsonForProcessing: EventJson, + contextEntitiesForProcessing: SelfDescribingJson[] + ) => { + const add = (json: any, keyIfEncoded: string, keyIfNotEncoded: string): void => { + const str = JSON.stringify(json); + if (encodeBase64) { + payloadBuilder.add(keyIfEncoded, base64urlencode(str)); + } else { + payloadBuilder.add(keyIfNotEncoded, str); + } + }; + + const getContextFromPayload = () => { + let payload = payloadBuilder.getPayload(); + if (encodeBase64 ? payload.cx : payload.co) { + return JSON.parse( + encodeBase64 ? base64urldecode(payload.cx as string) : (payload.co as string) + ) as SelfDescribingJsonArray; + } + return undefined; + }; + + const combineContexts = ( + originalContext: SelfDescribingJsonArray | undefined, + newContext: SelfDescribingJsonArray + ) => { + let context = originalContext || getContextFromPayload(); + if (context) { + context.data = context.data.concat(newContext.data); + } else { + context = newContext; + } + return context; + }; + + let context: SelfDescribingJsonArray | undefined = undefined; + for (const json of jsonForProcessing) { + if (json.keyIfEncoded === 'cx') { + context = combineContexts(context, json.json as SelfDescribingJsonArray); + } else { + add(json.json, json.keyIfEncoded, json.keyIfNotEncoded); + } + } + jsonForProcessing.length = 0; + + if (contextEntitiesForProcessing.length) { + let newContext = { + schema: 'iglu:com.snowplowanalytics.snowplow/contexts/jsonschema/1-0-0', + data: [...contextEntitiesForProcessing], + }; + context = combineContexts(context, newContext); + contextEntitiesForProcessing.length = 0; + } + + if (context) { + add(context, 'cx', 'co'); + } + }; +} + +/** + * Is property a non-empty JSON? + * @param property - Checks if object is non-empty json + */ +export function isNonEmptyJson(property?: Record): boolean { + if (!isJson(property)) { + return false; + } + for (const key in property) { + if (Object.prototype.hasOwnProperty.call(property, key)) { + return true; + } + } + return false; +} + +/** + * Is property a JSON? + * @param property - Checks if object is json + */ +export function isJson(property?: Record): boolean { + return ( + typeof property !== 'undefined' && + property !== null && + (property.constructor === {}.constructor || property.constructor === [].constructor) + ); +} diff --git a/libraries/tracker-core/src/plugins.ts b/libraries/tracker-core/src/plugins.ts new file mode 100644 index 000000000..7a8b11b52 --- /dev/null +++ b/libraries/tracker-core/src/plugins.ts @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { TrackerCore, SelfDescribingJson } from './core'; +import { Logger } from './logger'; +import { Payload, PayloadBuilder } from './payload'; + +/** + * Interface which defines Core Plugins + */ +export interface CorePlugin { + /** + * Called when the plugin is initialised during the trackerCore construction + * + * @remarks + * Use to capture the specific core instance for each instance of a core plugin + */ + activateCorePlugin?: (core: TrackerCore) => void; + /** + * Called when the tracker is being destroyed. + * Should be used to clean up any resources or listeners that the plugin has created. + */ + deactivatePlugin?: (core: TrackerCore) => void; + /** + * Called before the `filter` method is called and before the trackerCore callback fires (if the filter passes) + * @param payloadBuilder - The payloadBuilder which will be sent to the callback, can be modified + */ + beforeTrack?: (payloadBuilder: PayloadBuilder) => void; + /** + * Called just after the trackerCore callback fires + * @param payload - The final built payload + */ + afterTrack?: (payload: Payload) => void; + /** + * Called before the payload is sent to the callback to decide whether to send the payload or skip it + * @param payload - The final event payload, can't be modified. + * @returns True if the payload should be sent, false if it should be skipped + */ + filter?: (payload: Payload) => boolean; + /** + * Called when constructing the context for each event + * Useful for adding additional context to events + */ + contexts?: () => SelfDescribingJson[]; + /** + * Passed a logger instance which can be used to send log information + * to the active logger + */ + logger?: (logger: Logger) => void; +} diff --git a/libraries/tracker-core/src/schemata.ts b/libraries/tracker-core/src/schemata.ts new file mode 100644 index 000000000..26caf6e56 --- /dev/null +++ b/libraries/tracker-core/src/schemata.ts @@ -0,0 +1 @@ +export const PAYLOAD_DATA_SCHEMA = 'iglu:com.snowplowanalytics.snowplow/payload_data/jsonschema/1-0-4'; diff --git a/libraries/tracker-core/test/base64.ts b/libraries/tracker-core/test/base64.ts new file mode 100644 index 000000000..f9d037c0f --- /dev/null +++ b/libraries/tracker-core/test/base64.ts @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import test from 'ava'; +import { base64urlencode, base64urldecode } from '../src/base64'; + +test('Base 64 encode a string', (t) => { + t.is(base64urlencode('my_string'), 'bXlfc3RyaW5n'); +}); + +test('Base 64 decode a string', (t) => { + t.is(base64urldecode('bXlfc3RyaW5n'), 'my_string'); +}); + +test('Base 64 encode a string containing special characters', (t) => { + t.is(base64urlencode('™®字'), '4oSiwq7lrZc'); +}); + +test('Base 64 decode a string containing special characters', (t) => { + t.is(base64urldecode('4oSiwq7lrZc'), '™®字'); +}); + +test('Base 64 encode json', (t) => { + t.is( + base64urlencode( + JSON.stringify({ + string: 'this_is_json', + number: 12, + array: [1, 2, 3], + }) + ), + 'eyJzdHJpbmciOiJ0aGlzX2lzX2pzb24iLCJudW1iZXIiOjEyLCJhcnJheSI6WzEsMiwzXX0' + ); +}); + +test('Base 64 decode json', (t) => { + t.deepEqual(JSON.parse(base64urldecode('eyJzdHJpbmciOiJ0aGlzX2lzX2pzb24iLCJudW1iZXIiOjEyLCJhcnJheSI6WzEsMiwzXX0')), { + string: 'this_is_json', + number: 12, + array: [1, 2, 3], + }); +}); diff --git a/libraries/tracker-core/test/contexts.ts b/libraries/tracker-core/test/contexts.ts new file mode 100644 index 000000000..fe2d6a81a --- /dev/null +++ b/libraries/tracker-core/test/contexts.ts @@ -0,0 +1,615 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import test from 'ava'; +import * as contexts from '../src/contexts'; +import { payloadBuilder } from '../src/payload'; +import { SelfDescribingJson } from '../src/core'; + +test('Identify context primitives', (t) => { + const geolocationContext = { + schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0', + data: { + latitude: 40.0, + longitude: 55.1, + }, + }; + + function eventTypeContextGenerator(args?: contexts.ContextEvent) { + const context: SelfDescribingJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/mobile_context/jsonschema/1-0-1', + data: { + osType: 'ubuntu', + osVersion: '2018.04', + deviceManufacturer: 'ASUS', + deviceModel: args ? String(args['eventType']) : '', + }, + }; + return context; + } + + t.true(contexts.isContextPrimitive(geolocationContext), 'A context primitive should be identified'); + t.true(contexts.isContextPrimitive(eventTypeContextGenerator), 'A context primitive should be identified'); +}); + +test('Validating vendors', (t) => { + // Vendor validation + t.true(contexts.validateVendor('com.acme.marketing'), 'A valid vendor without wildcard is accepted'); + t.true(contexts.validateVendor('com.acme.*'), 'A valid vendor with wildcard is accepted'); + t.false(contexts.validateVendor('*.acme.*'), 'A vendor starting with asterisk is rejected'); + t.false(contexts.validateVendor('com.acme.*.marketing'), 'A vendor with asterisk out of order is rejected'); +}); + +test('Identify rule sets', (t) => { + const acceptRuleSet = { + accept: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'], + }; + + const rejectRuleSet = { + reject: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/1-0-1'], + }; + + const bothRuleSet = { + accept: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/1-*-1'], + reject: ['iglu:com.snowplowanalytics.snowplow/some_event/jsonschema/1-*-*'], + }; + + const pageview_schema = 'iglu:com.snowplowanalytics.snowplow/pageview/jsonschema/1-0-1'; + + t.true(contexts.isValidRule(acceptRuleSet.accept[0]), 'All rule elements are correctly identified as valid rules'); + t.true(contexts.isValidRuleSetArg(acceptRuleSet.accept), 'A rule set arg is correctly identified'); + t.true(contexts.isRuleSet(acceptRuleSet), 'An accept rule set is identified'); + t.true(contexts.isRuleSet(rejectRuleSet), 'A reject rule set is identified'); + t.true(contexts.isRuleSet(bothRuleSet), 'A rule set with both elements is identified'); + t.deepEqual( + contexts.getSchemaParts(pageview_schema), + ['com.snowplowanalytics.snowplow', 'pageview', '1', '0', '1'], + 'Gets correct parts for schema' + ); + t.true( + contexts.matchSchemaAgainstRule('iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*', pageview_schema), + 'Matches schema against wildcarded rule' + ); + t.true(contexts.matchSchemaAgainstRuleSet(acceptRuleSet, pageview_schema), 'Accept rule set accepts matching schema'); + t.false( + contexts.matchSchemaAgainstRuleSet(rejectRuleSet, pageview_schema), + 'Reject rule set rejects matching schema' + ); +}); + +test('Identify filter function', (t) => { + const filterFunction = function (args?: contexts.ContextEvent) { + return args?.eventType === 'ue'; + }; + + t.true(contexts.isContextCallbackFunction(filterFunction), 'A valid filter function is identified'); +}); + +test('Identify rule set provider', (t) => { + const bothRuleSet = { + accept: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'], + reject: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'], + }; + + const geolocationContext = { + schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0', + data: { + latitude: 40.0, + longitude: 55.1, + }, + }; + + function eventTypeContextGenerator(args?: contexts.ContextEvent) { + const context: SelfDescribingJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/mobile_context/jsonschema/1-0-1', + data: { + osType: 'ubuntu', + osVersion: '2018.04', + deviceManufacturer: 'ASUS', + deviceModel: args ? String(args['eventType']) : '', + }, + }; + return context; + } + + const ruleSetProvider = [bothRuleSet, [geolocationContext, eventTypeContextGenerator]]; + t.true(contexts.isRuleSetProvider(ruleSetProvider), 'Valid rule set provider is correctly identified'); +}); + +test('Identify filter provider', (t) => { + const filterFunction = function (args?: contexts.ContextEvent) { + return args?.eventType === 'ue'; + }; + + const geolocationContext = { + schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0', + data: { + latitude: 40.0, + longitude: 55.1, + }, + }; + + function eventTypeContextGenerator(args?: contexts.ContextEvent) { + const context: SelfDescribingJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/mobile_context/jsonschema/1-0-1', + data: { + osType: 'ubuntu', + osVersion: '2018.04', + deviceManufacturer: 'ASUS', + deviceModel: args ? String(args['eventType']) : '', + }, + }; + return context; + } + + const filterProvider = [filterFunction, [geolocationContext, eventTypeContextGenerator]]; + t.true(contexts.isFilterProvider(filterProvider), 'A valid filter provider is identified'); +}); + +test('Add global contexts', (t) => { + const geolocationContext = { + schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0', + data: { + latitude: 40.0, + longitude: 55.1, + }, + }; + + function eventTypeContextGenerator(args?: contexts.ContextEvent) { + const context: SelfDescribingJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/mobile_context/jsonschema/1-0-1', + data: { + osType: 'ubuntu', + osVersion: '2018.04', + deviceManufacturer: 'ASUS', + deviceModel: args ? String(args['eventType']) : '', + }, + }; + return context; + } + + const bothRuleSet = { + accept: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'], + reject: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'], + }; + + const filterFunction = function (args?: contexts.ContextEvent) { + return args?.eventType === 'ue'; + }; + + const filterProvider: contexts.FilterProvider = [filterFunction, [geolocationContext, eventTypeContextGenerator]]; + const ruleSetProvider: contexts.RuleSetProvider = [bothRuleSet, [geolocationContext, eventTypeContextGenerator]]; + + const contextArray = [filterProvider, ruleSetProvider, geolocationContext, eventTypeContextGenerator]; + const globalContexts = contexts.globalContexts(); + + globalContexts.addGlobalContexts(contextArray); + t.is(globalContexts.getGlobalPrimitives().length, 2, 'Correct number of primitives added'); + t.is(globalContexts.getConditionalProviders().length, 2, 'Correct number of conditional providers added'); +}); + +test('Handle named global contexts', (t) => { + const geolocationContext = { + schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0', + data: { + latitude: 40.0, + longitude: 55.1, + }, + }; + + function eventTypeContextGenerator(args?: contexts.ContextEvent) { + const context: SelfDescribingJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/mobile_context/jsonschema/1-0-1', + data: { + osType: 'ubuntu', + osVersion: '2018.04', + deviceManufacturer: 'ASUS', + deviceModel: args ? String(args['eventType']) : '', + }, + }; + return context; + } + + const bothRuleSet = { + accept: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'], + reject: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'], + }; + + const filterFunction = function (args?: contexts.ContextEvent) { + return args?.eventType === 'ue'; + }; + + const filterProvider: contexts.FilterProvider = [filterFunction, [geolocationContext, eventTypeContextGenerator]]; + const ruleSetProvider: contexts.RuleSetProvider = [bothRuleSet, [geolocationContext, eventTypeContextGenerator]]; + + const namedContexts = { + filters: filterProvider, + rules: ruleSetProvider, + static: geolocationContext, + generator: eventTypeContextGenerator, + }; + const globalContexts = contexts.globalContexts(); + + globalContexts.addGlobalContexts(namedContexts); + t.is(globalContexts.getGlobalPrimitives().length, 2, 'Correct number of primitives added'); + t.is(globalContexts.getConditionalProviders().length, 2, 'Correct number of conditional providers added'); + + globalContexts.removeGlobalContexts(['static', 'rules']); + t.is(globalContexts.getGlobalPrimitives().length, 1, 'Correct number of primitives removed'); + t.is(globalContexts.getConditionalProviders().length, 1, 'Correct number of conditional providers removed'); + + globalContexts.clearGlobalContexts(); + t.is(globalContexts.getGlobalPrimitives().length, 0, 'All primitives removed'); + t.is(globalContexts.getConditionalProviders().length, 0, 'All conditional providers removed'); + + globalContexts.addGlobalContexts([geolocationContext]); + globalContexts.addGlobalContexts({ geo: geolocationContext }); + t.is(globalContexts.getGlobalPrimitives().length, 2, 'Treats anonymous and named globals separately'); + + const mutatedGeolocationContext = JSON.parse(JSON.stringify(geolocationContext)); + mutatedGeolocationContext.data.latitude = 30; + + globalContexts.addGlobalContexts({ geo: mutatedGeolocationContext }); + t.deepEqual( + globalContexts.getGlobalPrimitives(), + [geolocationContext, mutatedGeolocationContext], + 'Upserts named globals' + ); +}); + +test('Remove one of two global context primitives', (t) => { + const geolocationContext = { + schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0', + data: { + latitude: 40.0, + longitude: 55.1, + }, + }; + + const webPageContext = { + schema: 'iglu:org.schema/WebPage/jsonschema/1-0-0', + data: { + genre: 'test', + }, + }; + + const globalContexts = contexts.globalContexts(); + globalContexts.addGlobalContexts([geolocationContext, webPageContext]); + globalContexts.removeGlobalContexts([geolocationContext]); + t.deepEqual(globalContexts.getGlobalPrimitives(), [webPageContext]); +}); + +test('Remove one of two global context generators', (t) => { + function a(): undefined { + return; + } + function b(): undefined { + return; + } + + const globalContexts = contexts.globalContexts(); + globalContexts.addGlobalContexts([a, b]); + t.deepEqual(globalContexts.getGlobalPrimitives(), [a, b]); + globalContexts.removeGlobalContexts([a]); + t.deepEqual(globalContexts.getGlobalPrimitives(), [b]); +}); + +test('Remove one of two global context conditional providers', (t) => { + const geolocationContext = { + schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0', + data: { + latitude: 40.0, + longitude: 55.1, + }, + }; + + function eventTypeContextGenerator(args?: contexts.ContextEvent) { + const context: SelfDescribingJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/mobile_context/jsonschema/1-0-1', + data: { + osType: 'ubuntu', + osVersion: '2018.04', + deviceManufacturer: 'ASUS', + deviceModel: args ? String(args['eventType']) : '', + }, + }; + return context; + } + + const bothRuleSet = { + accept: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'], + reject: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'], + }; + + const filterFunction = function (args?: contexts.ContextEvent) { + return args?.eventType === 'ue'; + }; + + const filterProvider: contexts.FilterProvider = [filterFunction, [geolocationContext, eventTypeContextGenerator]]; + const ruleSetProvider: contexts.RuleSetProvider = [bothRuleSet, [geolocationContext, eventTypeContextGenerator]]; + const globalContexts = contexts.globalContexts(); + + globalContexts.addGlobalContexts([filterProvider, ruleSetProvider]); + globalContexts.removeGlobalContexts([filterProvider]); + t.deepEqual(globalContexts.getConditionalProviders(), [ruleSetProvider]); +}); + +test('Remove global contexts', (t) => { + const geolocationContext = { + schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0', + data: { + latitude: 40.0, + longitude: 55.1, + }, + }; + + function eventTypeContextGenerator(args?: contexts.ContextEvent) { + const context: SelfDescribingJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/mobile_context/jsonschema/1-0-1', + data: { + osType: 'ubuntu', + osVersion: '2018.04', + deviceManufacturer: 'ASUS', + deviceModel: args ? String(args['eventType']) : '', + }, + }; + return context; + } + + const bothRuleSet = { + accept: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'], + reject: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'], + }; + + const filterFunction = function (args?: contexts.ContextEvent) { + return args?.eventType === 'ue'; + }; + + const filterProvider: contexts.FilterProvider = [filterFunction, [geolocationContext, eventTypeContextGenerator]]; + const ruleSetProvider: contexts.RuleSetProvider = [bothRuleSet, [geolocationContext, eventTypeContextGenerator]]; + const globalContexts = contexts.globalContexts(); + + globalContexts.addGlobalContexts([filterProvider, ruleSetProvider, geolocationContext, eventTypeContextGenerator]); + globalContexts.removeGlobalContexts([filterProvider, geolocationContext, eventTypeContextGenerator]); + t.is(globalContexts.getGlobalPrimitives().length, 0, 'Correct number of primitives added'); + t.is(globalContexts.getConditionalProviders().length, 1, 'Correct number of conditional providers added'); +}); + +test('Clear global contexts', (t) => { + const geolocationContext = { + schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0', + data: { + latitude: 40.0, + longitude: 55.1, + }, + }; + + function eventTypeContextGenerator(args?: contexts.ContextEvent) { + const context: SelfDescribingJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/mobile_context/jsonschema/1-0-1', + data: { + osType: 'ubuntu', + osVersion: '2018.04', + deviceManufacturer: 'ASUS', + deviceModel: args ? String(args['eventType']) : '', + }, + }; + return context; + } + + const bothRuleSet = { + accept: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'], + reject: ['iglu:com.snowplowanalytics.snowplow/*/jsonschema/*-*-*'], + }; + + const filterFunction = function (args?: contexts.ContextEvent) { + return args?.eventType === 'ue'; + }; + + const filterProvider: contexts.FilterProvider = [filterFunction, [geolocationContext, eventTypeContextGenerator]]; + const ruleSetProvider: contexts.RuleSetProvider = [bothRuleSet, [geolocationContext, eventTypeContextGenerator]]; + + const contextArray = [filterProvider, ruleSetProvider, geolocationContext, eventTypeContextGenerator]; + const globalContexts = contexts.globalContexts(); + globalContexts.addGlobalContexts(contextArray); + globalContexts.clearGlobalContexts(); + t.is(globalContexts.getGlobalPrimitives().length, 0, 'Correct number of primitives added'); + t.is(globalContexts.getConditionalProviders().length, 0, 'Correct number of conditional providers added'); +}); + +test('Get applicable contexts', (t) => { + const geolocationContext = { + schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0', + data: { + latitude: 40.0, + longitude: 55.1, + }, + }; + + function eventTypeContextGenerator(args?: contexts.ContextEvent) { + const context: SelfDescribingJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/some_context/jsonschema/1-0-1', + data: { + osType: 'ubuntu', + osVersion: '2018.04', + deviceManufacturer: 'ASUS', + eventType: args ? String(args['eventType']) : '', + }, + }; + return context; + } + + const selfDescribingEventRuleset = { + accept: ['iglu:com.acme_company/*/jsonschema/*-*-*'], + }; + + const filterFunction = function (args?: contexts.ContextEvent) { + return args?.eventType === 'ue'; + }; + + const filterProvider: contexts.FilterProvider = [filterFunction, [geolocationContext, eventTypeContextGenerator]]; + const ruleSetProvider: contexts.RuleSetProvider = [ + selfDescribingEventRuleset, + [geolocationContext, eventTypeContextGenerator], + ]; + + const contextArray = [filterProvider, ruleSetProvider, geolocationContext, eventTypeContextGenerator]; + const globalContexts = contexts.globalContexts(); + const event = payloadBuilder(); + event.add('e', 'ue'); + event.addJson('ue_px', 'ue_pr', { + schema: 'iglu:com.snowplowanalytics.snowplow/unstruct_event/jsonschema/1-0-0', + data: { + schema: 'iglu:com.acme_company/some_event/jsonschema/1-0-0', + data: {}, + }, + }); + + globalContexts.addGlobalContexts(contextArray); + t.is(globalContexts.getApplicableContexts(event).length, 6); +}); + +test('Resolves context generators and static contexts', (t) => { + const contextGenerator = () => { + return { + schema: 'iglu:com.acme.marketing/some_event/jsonschema/1-0-0', + data: { test: 1 }, + }; + }; + const staticContext = { + schema: 'iglu:com.acme.marketing/some_event/jsonschema/1-0-0', + data: { test: 1 }, + }; + const expected = [contextGenerator(), staticContext]; + const actual = contexts.resolveDynamicContext([contextGenerator, staticContext]); + t.deepEqual(actual, expected); +}); + +test('Resolves context generators with arguments', (t) => { + const contextGenerator = (argOne: string, argTwo: string) => ({ + schema: 'iglu:com.acme.marketing/some_event/jsonschema/1-0-0', + data: { + firstVal: argOne, + secondVal: argTwo, + }, + }); + const expected = [ + { + schema: 'iglu:com.acme.marketing/some_event/jsonschema/1-0-0', + data: { + firstVal: 1, + secondVal: 2, + }, + }, + ]; + const actual = contexts.resolveDynamicContext([contextGenerator], 1, 2); + t.deepEqual(actual, expected); +}); + +test('Context generators which return empty are ignored', (t) => { + const contextGenerator = () => null; + const staticContext = { + schema: 'iglu:com.acme.marketing/some_event/jsonschema/1-0-0', + data: { test: 1 }, + }; + const expected = [staticContext]; + const actual = contexts.resolveDynamicContext([contextGenerator, staticContext]); + t.deepEqual(actual, expected); +}); + +test('Plugins context should be combined with the passed context', (t) => { + const initialContextArray = [ + { + schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0', + data: { + latitude: 40.0, + longitude: 55.1, + }, + }, + ]; + + const webPageContext = { + schema: 'iglu:org.schema/WebPage/jsonschema/1-0-0', + data: { + genre: 'test', + }, + }; + + const webPagePlugin = { + contexts: () => { + return [webPageContext]; + }, + }; + + const pluginContexts = contexts.pluginContexts([webPagePlugin]); + const result = pluginContexts.addPluginContexts(initialContextArray); + + t.is(result.length, 2); + t.deepEqual(result, [...initialContextArray, webPageContext]); +}); + +test('Do not mutate context when adding plugin context', (t) => { + const initialContextArray = [ + { + schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0', + data: { + latitude: 40.0, + longitude: 55.1, + }, + }, + ]; + + const webPageContext = { + schema: 'iglu:org.schema/WebPage/jsonschema/1-0-0', + data: { + genre: 'test', + }, + }; + + const webPagePlugin = { + contexts: () => { + return [webPageContext]; + }, + }; + + const pluginContexts = contexts.pluginContexts([webPagePlugin]); + pluginContexts.addPluginContexts(initialContextArray); + + t.is(initialContextArray.length, 1); + t.deepEqual(initialContextArray, [ + { + schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0', + data: { + latitude: 40.0, + longitude: 55.1, + }, + }, + ]); +}); diff --git a/libraries/tracker-core/test/core.ts b/libraries/tracker-core/test/core.ts new file mode 100644 index 000000000..226e9dc7e --- /dev/null +++ b/libraries/tracker-core/test/core.ts @@ -0,0 +1,1084 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import test, { ExecutionContext } from 'ava'; +import { + buildAdClick, + buildAdConversion, + buildAddToCart, + buildAdImpression, + buildConsentGranted, + buildConsentWithdrawn, + buildEcommerceTransaction, + buildEcommerceTransactionItem, + buildFormFocusOrChange, + buildFormSubmission, + buildLinkClick, + buildPagePing, + buildPageView, + buildRemoveFromCart, + buildScreenView, + buildSelfDescribingEvent, + buildSiteSearch, + buildSocialInteraction, + buildStructEvent, + trackerCore, +} from '../src/core'; +import { Payload } from '../src/payload'; + +const UUID_REGEX = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/; + +const selfDescribingEventSchema = 'iglu:com.snowplowanalytics.snowplow/unstruct_event/jsonschema/1-0-0'; +let beforeCount = 0, + afterCount = 0; +const tracker = trackerCore({ + base64: false, + corePlugins: [{ beforeTrack: () => (beforeCount += 1), afterTrack: () => (afterCount += 1) }], +}); +function compare(result: Payload, expected: Payload, t: ExecutionContext) { + t.truthy(result['eid'], 'A UUID should be attached to all events'); + delete result['eid']; + t.truthy(result['dtm'], 'A timestamp should be attached to all events'); + delete result['dtm']; + t.deepEqual(result, expected); +} + +test.before(() => { + console.error = () => {}; // Silence console.error globally +}); + +test('tracker.track API should return the eid attribute', (t) => { + const pageUrl = 'http://www.example.com'; + const pageTitle = 'title page'; + const referrer = 'https://www.google.com'; + const expected = { + e: 'pv', + url: pageUrl, + page: pageTitle, + refr: referrer, + }; + const eventPayload = tracker.track(buildPageView({ pageUrl, pageTitle, referrer }))!; + t.truthy(eventPayload.eid); + t.regex(eventPayload.eid as string, UUID_REGEX); + compare(eventPayload, expected, t); +}); + +test('should track a page view', (t) => { + const pageUrl = 'http://www.example.com'; + const pageTitle = 'title page'; + const referrer = 'https://www.google.com'; + const expected = { + e: 'pv', + url: pageUrl, + page: pageTitle, + refr: referrer, + }; + compare(tracker.track(buildPageView({ pageUrl, pageTitle, referrer }))!, expected, t); +}); +test('should track a page ping', (t) => { + const pageUrl = 'http://www.example.com'; + const pageTitle = 'title page'; + const referrer = 'http://www.google.com'; + const expected = { + e: 'pp', + page: pageTitle, + url: pageUrl, + refr: referrer, + pp_mix: '1', + pp_max: '2', + pp_miy: '3', + pp_may: '4', + }; + compare( + tracker.track( + buildPagePing({ pageUrl, pageTitle, referrer, minXOffset: 1, maxXOffset: 2, minYOffset: 3, maxYOffset: 4 }) + )!, + expected, + t + ); +}); +test('should track a structured event', (t) => { + const expected = { + e: 'se', + se_ca: 'cat', + se_ac: 'act', + se_la: 'lab', + se_pr: 'prop', + se_va: '1', + }; + compare( + tracker.track(buildStructEvent({ category: 'cat', action: 'act', label: 'lab', property: 'prop', value: 1 }))!, + expected, + t + ); +}); +test('should track an ecommerce transaction event', (t) => { + const orderId = 'ak0008'; + const affiliation = '1234'; + const total = 50; + const tax = 6; + const shipping = 0; + const city = 'Phoenix'; + const state = 'Arizona'; + const country = 'USA'; + const currency = 'USD'; + const expected = { + e: 'tr', + tr_af: affiliation, + tr_id: orderId, + tr_tt: total, + tr_tx: tax, + tr_sh: shipping, + tr_ci: city, + tr_st: state, + tr_co: country, + tr_cu: currency, + }; + compare( + tracker.track( + buildEcommerceTransaction({ + orderId, + total, + affiliation, + tax, + shipping, + city, + state, + country, + currency, + }) + )!, + expected, + t + ); +}); +test('should track an ecommerce transaction item event', (t) => { + const orderId = 'ak0008'; + const sku = '4q345'; + const price = 17.0; + const quantity = 2; + const name = 'red shoes'; + const category = 'clothing'; + const currency = 'USD'; + const expected = { + e: 'ti', + ti_id: orderId, + ti_sk: sku, + ti_nm: name, + ti_ca: category, + ti_pr: price, + ti_qu: quantity, + ti_cu: currency, + }; + compare( + tracker.track(buildEcommerceTransactionItem({ orderId, sku, name, category, price, quantity, currency }))!, + expected, + t + ); +}); +test('should track a self-describing event', (t) => { + const inputJson = { + schema: 'iglu:com.acme/user/jsonschema/1-0-1', + data: { + name: 'Eric', + }, + }; + const expected = { + e: 'ue', + ue_pr: JSON.stringify({ + schema: selfDescribingEventSchema, + data: inputJson, + }), + }; + compare(tracker.track(buildSelfDescribingEvent({ event: inputJson }))!, expected, t); +}); +test('should track a link click', (t) => { + const targetUrl = 'http://www.example.com'; + const elementId = 'first header'; + const elementClasses = ['header']; + const elementContent = 'link'; + const elementTarget = 'target'; + const inputJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1', + data: { + targetUrl: targetUrl, + elementId: elementId, + elementClasses: elementClasses, + elementTarget: elementTarget, + elementContent: elementContent, + }, + }; + const expected = { + e: 'ue', + ue_pr: JSON.stringify({ + schema: selfDescribingEventSchema, + data: inputJson, + }), + }; + compare( + tracker.track(buildLinkClick({ targetUrl, elementId, elementClasses, elementTarget, elementContent }))!, + expected, + t + ); +}); +test('should track a screen view', (t) => { + const name = 'intro'; + const id = '7398-4352-5345-1950'; + const inputJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/screen_view/jsonschema/1-0-0', + data: { + name: name, + id: id, + }, + }; + const expected = { + e: 'ue', + ue_pr: JSON.stringify({ + schema: selfDescribingEventSchema, + data: inputJson, + }), + }; + compare(tracker.track(buildScreenView({ name, id }))!, expected, t); +}); +test('should track an ad impression', (t) => { + const impressionId = 'a0e8f8780ab3'; + const costModel = 'cpc'; + const cost = 0.5; + const targetUrl = 'http://adsite.com'; + const bannerId = '123'; + const zoneId = 'zone-14'; + const advertiserId = 'ad-company'; + const campaignId = 'campaign-7592'; + const inputJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/ad_impression/jsonschema/1-0-0', + data: { + impressionId: impressionId, + costModel: costModel, + cost: cost, + targetUrl: targetUrl, + bannerId: bannerId, + zoneId: zoneId, + advertiserId: advertiserId, + campaignId: campaignId, + }, + }; + const expected = { + e: 'ue', + ue_pr: JSON.stringify({ + schema: selfDescribingEventSchema, + data: inputJson, + }), + }; + compare( + tracker.track( + buildAdImpression({ impressionId, costModel, cost, targetUrl, bannerId, zoneId, advertiserId, campaignId }) + )!, + expected, + t + ); +}); +test('should track an ad click', (t) => { + const targetUrl = 'http://adsite.com'; + const clickId = 'click-321'; + const costModel = 'cpc'; + const cost = 0.5; + const bannerId = '123'; + const zoneId = 'zone-14'; + const impressionId = 'a0e8f8780ab3'; + const advertiserId = 'ad-company'; + const campaignId = 'campaign-7592'; + const inputJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/ad_click/jsonschema/1-0-0', + data: { + targetUrl: targetUrl, + clickId: clickId, + costModel: costModel, + cost: cost, + bannerId: bannerId, + zoneId: zoneId, + impressionId: impressionId, + advertiserId: advertiserId, + campaignId: campaignId, + }, + }; + const expected = { + e: 'ue', + ue_pr: JSON.stringify({ + schema: selfDescribingEventSchema, + data: inputJson, + }), + }; + compare( + tracker.track( + buildAdClick({ targetUrl, clickId, costModel, cost, bannerId, zoneId, impressionId, advertiserId, campaignId }) + )!, + expected, + t + ); +}); +test('should track an ad conversion', (t) => { + const conversionId = 'conversion-59'; + const costModel = 'cpc'; + const cost = 0.5; + const category = 'cat'; + const action = 'act'; + const property = 'prop'; + const initialValue = 7; + const advertiserId = 'ad-company'; + const campaignId = 'campaign-7592'; + const inputJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/ad_conversion/jsonschema/1-0-0', + data: { + conversionId: conversionId, + costModel: costModel, + cost: cost, + category: category, + action: action, + property: property, + initialValue: initialValue, + advertiserId: advertiserId, + campaignId: campaignId, + }, + }; + const expected = { + e: 'ue', + ue_pr: JSON.stringify({ + schema: selfDescribingEventSchema, + data: inputJson, + }), + }; + compare( + tracker.track( + buildAdConversion({ + conversionId, + costModel, + cost, + category, + action, + property, + initialValue, + advertiserId, + campaignId, + }) + )!, + expected, + t + ); +}); +test('should track a social interaction', (t) => { + const action = 'like'; + const network = 'facebook'; + const target = 'status-0000345345'; + const inputJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/social_interaction/jsonschema/1-0-0', + data: { + action: action, + network: network, + target: target, + }, + }; + const expected = { + e: 'ue', + ue_pr: JSON.stringify({ + schema: selfDescribingEventSchema, + data: inputJson, + }), + }; + compare(tracker.track(buildSocialInteraction({ action, network, target }))!, expected, t); +}); +test('should track an add-to-cart event', (t) => { + const sku = '4q345'; + const unitPrice = 17.0; + const quantity = 2; + const name = 'red shoes'; + const category = 'clothing'; + const currency = 'USD'; + const inputJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/add_to_cart/jsonschema/1-0-0', + data: { + sku: sku, + quantity: quantity, + name: name, + category: category, + unitPrice: unitPrice, + currency: currency, + }, + }; + const expected = { + e: 'ue', + ue_pr: JSON.stringify({ + schema: selfDescribingEventSchema, + data: inputJson, + }), + }; + compare(tracker.track(buildAddToCart({ sku, name, category, unitPrice, quantity, currency }))!, expected, t); +}); +test('should track a remove-from-cart event', (t) => { + const sku = '4q345'; + const unitPrice = 17.0; + const quantity = 2; + const name = 'red shoes'; + const category = 'clothing'; + const currency = 'USD'; + const inputJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/remove_from_cart/jsonschema/1-0-0', + data: { + sku: sku, + quantity: quantity, + name: name, + category: category, + unitPrice: unitPrice, + currency: currency, + }, + }; + const expected = { + e: 'ue', + ue_pr: JSON.stringify({ + schema: selfDescribingEventSchema, + data: inputJson, + }), + }; + compare(tracker.track(buildRemoveFromCart({ sku, name, category, unitPrice, quantity, currency }))!, expected, t); +}); +test('should track a form focus event', (t) => { + const formId = 'parent'; + const elementId = 'child'; + const nodeName = 'INPUT'; + const type = 'text'; + const elementClasses = ['important']; + const value = 'male'; + const inputJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/focus_form/jsonschema/1-0-0', + data: { + formId: formId, + elementId: elementId, + nodeName: nodeName, + elementClasses: elementClasses, + value: value, + elementType: type, + }, + }; + const expected = { + e: 'ue', + ue_pr: JSON.stringify({ + schema: selfDescribingEventSchema, + data: inputJson, + }), + }; + compare( + tracker.track( + buildFormFocusOrChange({ schema: 'focus_form', formId, elementId, nodeName, type, elementClasses, value }) + )!, + expected, + t + ); +}); +test('should track a form change event', (t) => { + const formId = 'parent'; + const elementId = 'child'; + const nodeName = 'INPUT'; + const type = 'text'; + const elementClasses = ['important']; + const value = 'male'; + const inputJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/change_form/jsonschema/1-0-0', + data: { + formId: formId, + elementId: elementId, + nodeName: nodeName, + elementClasses: elementClasses, + value: value, + type: type, + }, + }; + const expected = { + e: 'ue', + ue_pr: JSON.stringify({ + schema: selfDescribingEventSchema, + data: inputJson, + }), + }; + compare( + tracker.track( + buildFormFocusOrChange({ schema: 'change_form', formId, elementId, nodeName, type, elementClasses, value }) + )!, + expected, + t + ); +}); +test('should track a form submission event', (t) => { + const formId = 'parent'; + const formClasses = ['formclass']; + const elements = [ + { + name: 'gender', + value: 'male', + nodeName: 'INPUT', + type: 'text', + }, + ]; + const inputJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/submit_form/jsonschema/1-0-0', + data: { + formId: formId, + formClasses: formClasses, + elements: elements, + }, + }; + const expected = { + e: 'ue', + ue_pr: JSON.stringify({ + schema: selfDescribingEventSchema, + data: inputJson, + }), + }; + compare(tracker.track(buildFormSubmission({ formId, formClasses, elements }))!, expected, t); +}); +test('should track a site seach event', (t) => { + const terms = ['javascript', 'development']; + const filters = { + safeSearch: true, + category: 'books', + }; + const totalResults = 35; + const pageResults = 10; + const inputJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/site_search/jsonschema/1-0-0', + data: { + terms: terms, + filters: filters, + totalResults: totalResults, + pageResults: pageResults, + }, + }; + const expected = { + e: 'ue', + ue_pr: JSON.stringify({ + schema: selfDescribingEventSchema, + data: inputJson, + }), + }; + compare(tracker.track(buildSiteSearch({ terms, filters, totalResults, pageResults }))!, expected, t); +}); +test('should track a consent withdrawn event', (t) => { + const all = false; + const id = '1234'; + const version = '2'; + const name = 'consent_form'; + const description = 'user withdraws consent for form'; + const timestamp = 1000000000000; + const inputContext = [ + { + schema: 'iglu:com.snowplowanalytics.snowplow/consent_document/jsonschema/1-0-0', + data: { + id: id, + version: version, + name: name, + description: description, + }, + }, + ]; + const inputJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/consent_withdrawn/jsonschema/1-0-0', + data: { + all: all, + }, + }; + const expected = { + e: 'ue', + ue_pr: JSON.stringify({ + schema: selfDescribingEventSchema, + data: inputJson, + }), + co: JSON.stringify({ + schema: 'iglu:com.snowplowanalytics.snowplow/contexts/jsonschema/1-0-0', + data: inputContext, + }), + }; + const consentEvent = buildConsentWithdrawn({ all, id, version, name, description }); + compare(tracker.track(consentEvent.event, consentEvent.context, timestamp)!, expected, t); +}); +test('should track a consent granted event', (t) => { + const id = '1234'; + const version = '2'; + const name = 'consent_form'; + const description = 'user grants consent for form'; + const timestamp = 1000000000000; + const expiry = '01 January, 1970 00:00:00 Universal Time (UTC)'; + const inputContext = [ + { + schema: 'iglu:com.snowplowanalytics.snowplow/consent_document/jsonschema/1-0-0', + data: { + id: id, + version: version, + name: name, + description: description, + }, + }, + ]; + const inputJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/consent_granted/jsonschema/1-0-0', + data: { + expiry: expiry, + }, + }; + const expected = { + e: 'ue', + ue_pr: JSON.stringify({ + schema: selfDescribingEventSchema, + data: inputJson, + }), + co: JSON.stringify({ + schema: 'iglu:com.snowplowanalytics.snowplow/contexts/jsonschema/1-0-0', + data: inputContext, + }), + }; + const consentEvent = buildConsentGranted({ id, version, name, description, expiry }); + compare(tracker.track(consentEvent.event, consentEvent.context, timestamp)!, expected, t); +}); +test('should track a page view with custom context', (t) => { + const pageUrl = 'http://www.example.com'; + const pageTitle = 'title page'; + const referrer = 'https://www.google.com'; + const inputContext = [ + { + schema: 'iglu:com.acme/user/jsonschema/1-0-0', + data: { + userType: 'tester', + userName: 'Jon', + }, + }, + ]; + const expected = { + e: 'pv', + url: pageUrl, + page: pageTitle, + refr: referrer, + co: JSON.stringify({ + schema: 'iglu:com.snowplowanalytics.snowplow/contexts/jsonschema/1-0-0', + data: inputContext, + }), + }; + compare(tracker.track(buildPageView({ pageUrl, pageTitle, referrer }), inputContext)!, expected, t); +}); +test('should track a page view with a timestamp', (t) => { + const timestamp = 1000000000000; + t.is( + tracker.track( + buildPageView({ pageUrl: 'http://www.example.com', pageTitle: 'title', referrer: 'ref' }), + [], + timestamp + )!['dtm'], + '1000000000000' + ); +}); +test('should add individual name-value pairs to the payload', (t) => { + const tracker = trackerCore({ base64: false }); + const pageUrl = 'http://www.example.com'; + const pageTitle = 'title'; + const referrer = 'https://www.google.com'; + const expected = { + e: 'pv', + url: pageUrl, + tna: 'sp', + tv: 'js-2.0.0', + page: pageTitle, + refr: referrer, + }; + tracker.addPayloadPair('tna', 'sp'); + tracker.addPayloadPair('tv', 'js-2.0.0'); + compare(tracker.track(buildPageView({ pageUrl, pageTitle, referrer }))!, expected, t); +}); +test('should add a dictionary of name-value pairs to the payload', (t) => { + const tracker = trackerCore({ base64: false }); + const pageUrl = 'http://www.example.com'; + const pageTitle = 'title'; + const referrer = 'https://www.google.com'; + const expected = { + e: 'pv', + url: pageUrl, + tv: 'js-2.0.0', + tna: 'sp', + aid: 'sp325', + page: pageTitle, + refr: referrer, + }; + tracker.addPayloadPair('tv', 'js-2.0.0'); + tracker.addPayloadDict({ + tna: 'sp', + aid: 'sp325', + }); + compare(tracker.track(buildPageView({ pageUrl, pageTitle, referrer }))!, expected, t); +}); +test('should reset payload name-value pairs', (t) => { + const tracker = trackerCore({ base64: false }); + const pageUrl = 'http://www.example.com'; + const pageTitle = 'title'; + const referrer = 'https://www.google.com'; + const expected = { + e: 'pv', + url: pageUrl, + tna: 'sp', + page: pageTitle, + refr: referrer, + }; + tracker.addPayloadPair('tna', 'mistake'); + tracker.resetPayloadPairs({ tna: 'sp' }); + compare(tracker.track(buildPageView({ pageUrl, pageTitle, referrer }))!, expected, t); +}); +test('should execute a callback', (t) => { + const tracker = trackerCore({ + base64: false, + corePlugins: [], + callback: function (payload) { + const callbackTarget = payload; + compare(callbackTarget.build(), expected, t); + }, + }); + const pageUrl = 'http://www.example.com'; + const pageTitle = 'title'; + const referrer = 'https://www.google.com'; + const expected = { + e: 'pv', + url: pageUrl, + page: pageTitle, + refr: referrer, + }; + tracker.track(buildPageView({ pageUrl, pageTitle, referrer })); +}); +test('should use setter methods', (t) => { + const tracker = trackerCore({ base64: false }); + tracker.setTrackerVersion('js-3.0.0'); + tracker.setTrackerNamespace('sp1'); + tracker.setAppId('my-app'); + tracker.setPlatform('web'); + tracker.setUserId('jacob'); + tracker.setScreenResolution('400', '200'); + tracker.setViewport('500', '800'); + tracker.setColorDepth('24'); + tracker.setTimezone('Europe London'); + tracker.setIpAddress('37.151.33.154'); + tracker.setUseragent('SnowplowJavascript/0.0.1'); + const pageUrl = 'http://www.example.com'; + const pageTitle = 'title page'; + const referrer = 'https://www.google.com'; + const expected = { + e: 'pv', + url: pageUrl, + page: pageTitle, + tna: 'sp1', + tv: 'js-3.0.0', + aid: 'my-app', + p: 'web', + uid: 'jacob', + res: '400x200', + vp: '500x800', + cd: '24', + tz: 'Europe London', + ip: '37.151.33.154', + ua: 'SnowplowJavascript/0.0.1', + refr: referrer, + }; + compare(tracker.track(buildPageView({ pageUrl, pageTitle, referrer }))!, expected, t); +}); + +test('should set true timestamp', (t) => { + const pageUrl = 'http://www.example.com'; + const pageTitle = 'title page'; + const referrer = 'https://www.google.com'; + const result = tracker.track(buildPageView({ pageUrl, pageTitle, referrer }), undefined, { + type: 'ttm', + value: 1477403862, + })!; + t.true('ttm' in result); + t.is(result['ttm'], '1477403862'); + t.false('dtm' in result); +}); + +test('should set device timestamp as ADT', (t) => { + const inputJson = { + schema: 'iglu:com.acme/user/jsonschema/1-0-1', + data: { + name: 'Eric', + }, + }; + const result = tracker.track(buildSelfDescribingEvent({ event: inputJson }), [inputJson], { + type: 'dtm', + value: 1477403869, + })!; + t.true('dtm' in result); + t.is(result['dtm'], '1477403869'); + t.false('ttm' in result); +}); + +test('should run plugin before and after track callbacks on each track event', (t) => { + const url = 'http://www.example.com'; + const str = 'cccccckevjfiddbdjeikkdbkvvkdjcehggiutbkhnrfe'; + const num = 1; + const arr = [str]; + const filters = { + safeSearch: true, + category: str, + }; + const inputJson = { + schema: 'iglu:com.acme/user/jsonschema/1-0-1', + data: { + name: str, + }, + }; + (beforeCount = 0), (afterCount = 0); + const fs = [ + tracker.track( + buildPagePing({ + pageUrl: url, + pageTitle: str, + referrer: url, + maxXOffset: num, + maxYOffset: num, + minXOffset: num, + minYOffset: num, + }) + ), + tracker.track(buildPageView({ pageUrl: url, pageTitle: str, referrer: url })), + tracker.track(buildAddToCart({ category: str, name: str, quantity: num, sku: str, unitPrice: num })), + tracker.track(buildScreenView({ id: str, name: str })), + tracker.track(buildSiteSearch({ filters, pageResults: num, terms: arr, totalResults: num })), + tracker.track(buildStructEvent({ category: str, action: str })), + tracker.track( + buildAdConversion({ + conversionId: str, + costModel: 'cpm', + cost: num, + category: str, + action: str, + property: str, + initialValue: num, + advertiserId: str, + campaignId: str, + }) + ), + tracker.track( + buildAdImpression({ + impressionId: str, + costModel: 'cpm', + cost: num, + targetUrl: str, + bannerId: str, + zoneId: str, + advertiserId: str, + campaignId: str, + }) + ), + tracker.track(buildFormSubmission({ elements: [], formClasses: [], formId: str })), + tracker.track(buildRemoveFromCart({ category: str, name: str, quantity: num, sku: str, unitPrice: num })), + tracker.track(buildConsentGranted({ id: str, version: str }).event), + tracker.track(buildConsentWithdrawn({ all: true }).event), + tracker.track( + buildFormFocusOrChange({ + schema: 'focus_form', + formId: str, + elementId: str, + nodeName: str, + type: str, + elementClasses: arr, + value: str, + }) + ), + tracker.track(buildSocialInteraction({ action: str, network: str, target: str })), + tracker.track(buildSelfDescribingEvent({ event: inputJson })), + tracker.track(buildEcommerceTransaction({ orderId: str, total: num })), + tracker.track( + buildEcommerceTransactionItem({ orderId: str, sku: str, name: str, category: str, price: num, quantity: num }) + ), + tracker.track(buildLinkClick({ targetUrl: url })), + tracker.track( + buildAdClick({ + targetUrl: str, + clickId: str, + costModel: 'cpm', + cost: num, + bannerId: str, + zoneId: str, + impressionId: str, + advertiserId: str, + campaignId: str, + }) + ), + ]; + + t.is(beforeCount, fs.length); + t.is(afterCount, fs.length); +}); + +test('should skip events in case the plugin filter function returns false', (t) => { + let countTracked = 0; + const tracker = trackerCore({ + base64: false, + corePlugins: [ + { + filter: (payload) => { + return payload.e !== 'pv'; + }, + }, + { + filter: (payload) => { + return payload.e !== 'pp'; + }, + }, + { + afterTrack: () => { + countTracked += 1; + }, + }, + ], + }); + + t.falsy( + tracker.track( + buildPageView({ + pageUrl: 'http://www.example.com', + pageTitle: 'title page', + referrer: 'https://www.google.com', + }) + ) + ); + + t.falsy( + tracker.track( + buildPagePing({ + pageUrl: 'http://www.example.com', + pageTitle: 'title page', + referrer: 'https://www.google.com', + maxXOffset: 1, + maxYOffset: 1, + minXOffset: 1, + minYOffset: 1, + }) + ) + ); + + t.truthy( + tracker.track( + buildAddToCart({ + category: 'cat', + name: 'name', + quantity: 1, + sku: 'sku', + unitPrice: 1, + }) + ) + ); + + t.assert(countTracked === 1); +}); + +test('filter is passed full payload including dynamic context', (t) => { + let countTracked = 0; + const tracker = trackerCore({ + base64: false, + corePlugins: [ + { + contexts: () => { + return [ + { + schema: 'iglu:com.acme/user/jsonschema/1-0-0', + data: { + userType: 'tester', + userName: 'Jon', + }, + }, + ] + }, + filter: (payload) => { + return (payload.co as string).includes('com.acme'); + }, + afterTrack: () => { + countTracked += 1; + }, + }, + ], + }); + + t.truthy( + tracker.track( + buildPageView({ + pageUrl: 'http://www.example.com', + pageTitle: 'title page', + referrer: 'https://www.google.com', + }) + ) + ); + + t.assert(countTracked === 1); +}); + +test('doesnt track any events on deactivated tracker', (t) => { + let countTracked = 0; + const tracker = trackerCore({ + corePlugins: [ + { + afterTrack: () => { + countTracked += 1; + }, + }, + ], + }); + + tracker.deactivate(); + + t.falsy( + tracker.track( + buildPageView({ + pageUrl: 'http://www.example.com', + pageTitle: 'title page', + referrer: 'https://www.google.com', + }) + ) + ); + + t.assert(countTracked === 0); +}); + +test('deactivates plugins on deactivated tracker', (t) => { + let pluginDeactivated = false; + const tracker = trackerCore({ + corePlugins: [ + { + deactivatePlugin: () => { + pluginDeactivated = true; + } + }, + ], + }); + + tracker.deactivate(); + + t.assert(pluginDeactivated); +}); diff --git a/libraries/tracker-core/test/emitter/emitter_event.test.ts b/libraries/tracker-core/test/emitter/emitter_event.test.ts new file mode 100644 index 000000000..5d9520713 --- /dev/null +++ b/libraries/tracker-core/test/emitter/emitter_event.test.ts @@ -0,0 +1,66 @@ +import test from 'ava'; + +import { newEmitterEvent } from '../../src/emitter/emitter_event'; +import { newEventStorePayload } from '../../src/event_store_payload'; + +test('getGETRequestURL returns the correct URL with stm', (t) => { + const collectorUrl = 'https://example.com'; + const payload = { e: 'pv' }; + const event = newEmitterEvent(newEventStorePayload({ payload })); + const url = event.getGETRequestURL(collectorUrl, true); + t.regex(url, new RegExp(`${collectorUrl}\\?stm=\\d+&e=pv`)); +}); + +test('getGETRequestURL returns the correct URL without stm', (t) => { + const collectorUrl = 'https://example.com'; + const payload = { e: 'pv', p: 'web' }; + const event = newEmitterEvent(newEventStorePayload({ payload })); + const url = event.getGETRequestURL(collectorUrl, false); + t.is(url, `${collectorUrl}?e=pv&p=web`); +}); + +test('getGETRequestBytesCount returns the correct byte count', (t) => { + const payload = { e: 'pv', p: 'web' }; + const event = newEmitterEvent(newEventStorePayload({ payload })); + const count = event.getGETRequestBytesCount(); + t.is(count, 11); +}); + +test('getPOSTRequestBody processes integer into string values', (t) => { + const payload = { e: 'pv', x: 12 }; + const event = newEmitterEvent(newEventStorePayload({ payload })); + const body = event.getPOSTRequestBody(); + t.deepEqual(body, { e: 'pv', x: '12' }); +}); + +test('getPOSTRequestBytesCount returns the correct byte count', (t) => { + const payload = { e: 'pv', p: 'web' }; + const event = newEmitterEvent(newEventStorePayload({ payload })); + const count = event.getPOSTRequestBytesCount(); + t.is(count, 20); +}); + +test('getPOSTRequestBytesCount counts multibyte chars properly', (t) => { + const payload = { e: 'pv', p: '🍕' }; + const event = newEmitterEvent(newEventStorePayload({ payload })); + const count = event.getPOSTRequestBytesCount(); + t.is(count, 21); +}); + +test('getPayload returns the payload', (t) => { + const payload = { e: 'pv' }; + const event = newEmitterEvent(newEventStorePayload({ payload })); + t.deepEqual(event.getPayload(), payload); +}); + +test('getServerAnonymization returns the serverAnonymization value', (t) => { + const payload = { e: 'pv' }; + const event = newEmitterEvent(newEventStorePayload({ payload, svrAnon: true })); + t.true(event.getServerAnonymization()); +}); + +test('getServerAnonymization returns false by default', (t) => { + const payload = { e: 'pv' }; + const event = newEmitterEvent(newEventStorePayload({ payload })); + t.false(event.getServerAnonymization()); +}); diff --git a/libraries/tracker-core/test/emitter/emitter_request.test.ts b/libraries/tracker-core/test/emitter/emitter_request.test.ts new file mode 100644 index 000000000..15acb533a --- /dev/null +++ b/libraries/tracker-core/test/emitter/emitter_request.test.ts @@ -0,0 +1,302 @@ +import test from 'ava'; + +import { newEmitterRequest } from '../../src/emitter/emitter_request'; +import { newEmitterEvent } from '../../src/emitter/emitter_event'; +import { newEventStorePayload } from '../../src/event_store_payload'; + +const newEmitterEventFromPayload = (payload: Record) => { + return newEmitterEvent(newEventStorePayload({ payload })); +}; + +// MARK: - addEvent + +test('addEvent adds an event to the request', (t) => { + const request = newEmitterRequest({ + endpoint: 'https://example.com', + maxPostBytes: 1000, + }); + + const event = newEmitterEventFromPayload({ e: 'pv' }); + + t.true(request.addEvent(event)); + t.is(request.getEvents().length, 1); +}); + +test('addEvent returns false when server anonymization does not match previous events', (t) => { + const request = newEmitterRequest({ + endpoint: 'https://example.com', + maxPostBytes: 1000, + }); + + t.true( + request.addEvent( + newEmitterEvent( + newEventStorePayload({ + payload: { e: 'pv' }, + svrAnon: true, + }) + ) + ) + ); + t.false( + request.addEvent( + newEmitterEvent( + newEventStorePayload({ + payload: { e: 'pv' }, + svrAnon: false, + }) + ) + ) + ); + t.true( + request.addEvent( + newEmitterEvent( + newEventStorePayload({ + payload: { e: 'pv' }, + svrAnon: true, + }) + ) + ) + ); + t.is(request.getEvents().length, 2); +}); + +// MARK: - countBytes + +test('countBytes returns the correct byte count', (t) => { + const request = newEmitterRequest({ + endpoint: 'https://example.com', + maxPostBytes: 1000, + }); + + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'web' }))); + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'mob' }))); + t.is(request.countBytes(), 40 + 88); // 40 bytes for each event, 88 bytes for the payload_data envelope +}); + +// MARK: - countEvents + +test('countEvents returns the correct event count', (t) => { + const request = newEmitterRequest({ + endpoint: 'https://example.com', + maxPostBytes: 1000, + }); + + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'web' }))); + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'mob' }))); + t.is(request.countEvents(), 2); +}); + +// MARK: - isFull + +test('isFull returns false when not reached max post bytes', (t) => { + const request = newEmitterRequest({ + endpoint: 'https://example.com', + maxPostBytes: 1000, + }); + + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'web' }))); + t.false(request.isFull()); +}); + +test('isFull returns false when reached buffer size and not max post bytes', (t) => { + const request = newEmitterRequest({ + endpoint: 'https://example.com', + maxPostBytes: 1000, + }); + + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'web' }))); + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'mob' }))); + t.false(request.isFull()); +}); + +test('isFull returns true when reached max post bytes', (t) => { + const request = newEmitterRequest({ + endpoint: 'https://example.com', + maxPostBytes: 10, + }); + + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'web' }))); + t.true(request.isFull()); +}); + +// MARK: - toRequest + +test('toRequest returns a Request object with default settings', (t) => { + const request = newEmitterRequest({ + endpoint: 'https://example.com', + }); + + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'web' }))); + const req = request.toRequest()!; + t.is(req.url, 'https://example.com/com.snowplowanalytics.snowplow/tp2'); + t.is(req.method, 'POST'); + t.is(req.headers.get('Content-Type'), 'application/json; charset=UTF-8'); + t.is(req.headers.get('SP-Anonymous'), null); +}); + +test('toRequest builds a GET request when method is get', (t) => { + const request = newEmitterRequest({ + endpoint: 'https://example.com', + eventMethod: 'get', + useStm: false, + }); + + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'web' }))); + const req = request.toRequest()!; + t.is(req.url, 'https://example.com/i?e=pv&p=web'); + t.is(req.method, 'GET'); +}); + +test('toRequest includes stm when useStm is true', (t) => { + const request = newEmitterRequest({ + endpoint: 'https://example.com', + eventMethod: 'get', + useStm: true, + }); + + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'web' }))); + const req = request.toRequest()!; + t.regex(req.url, /stm=\d+/); +}); + +test('toRequest includes custom headers', (t) => { + const request = newEmitterRequest({ + endpoint: 'https://example.com', + customHeaders: { 'X-Test': 'test' }, + }); + + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'web' }))); + const req = request.toRequest()!; + t.is(req.headers.get('X-Test'), 'test'); +}); + +test('toRequest includes server anonymization header', (t) => { + const request = newEmitterRequest({ + endpoint: 'https://example.com', + }); + + t.true( + request.addEvent( + newEmitterEvent( + newEventStorePayload({ + payload: { e: 'pv', p: 'web' }, + svrAnon: true, + }) + ) + ) + ); + const req = request.toRequest()!; + t.is(req.headers.get('SP-Anonymous'), '*'); +}); + +test('toRequest contains keepalive', (t) => { + const request = newEmitterRequest({ + endpoint: 'https://example.com', + keepalive: true, + }); + + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'web' }))); + const req = request.toRequest()!; + t.is(req.keepalive, true); +}); + +test('toRequest URL contains custom POST path', (t) => { + const request = newEmitterRequest({ + endpoint: 'https://example.com', + postPath: '/custom', + }); + + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'web' }))); + const req = request.toRequest()!; + t.is(req.url, 'https://example.com/custom'); +}); + +test('toRequest URL adds default protocol when missing', (t) => { + const request = newEmitterRequest({ + endpoint: 'example.com', + }); + + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'web' }))); + const req = request.toRequest()!; + t.is(req.url, 'https://example.com/com.snowplowanalytics.snowplow/tp2'); +}); + +test('toRequest URL adds protocol and port', (t) => { + const request = newEmitterRequest({ + endpoint: 'example.com', + protocol: 'http', + port: 9090, + }); + + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'web' }))); + const req = request.toRequest()!; + t.is(req.url, 'http://example.com:9090/com.snowplowanalytics.snowplow/tp2'); +}); + +test('toRequest URL does not add protocol if already contains', (t) => { + const request = newEmitterRequest({ + endpoint: 'https://example.com', + protocol: 'http', + }); + + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'web' }))); + const req = request.toRequest()!; + t.is(req.url, 'https://example.com/com.snowplowanalytics.snowplow/tp2'); +}); + +test('toRequest returns undefined when no events', (t) => { + const request = newEmitterRequest({ + endpoint: 'https://example.com', + }); + + t.is(request.toRequest(), undefined); +}); + +test('toRequest contains default credentials', (t) => { + const request = newEmitterRequest({ + endpoint: 'https://example.com', + eventMethod: 'get', + }); + + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'web' }))); + const req = request.toRequest()!; + t.is(req.credentials, 'include'); +}); + +test('toRequest contains credentials', (t) => { + const request = newEmitterRequest({ + endpoint: 'https://example.com', + credentials: 'omit', + }); + + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'web' }))); + const req = request.toRequest()!; + t.is(req.credentials, 'omit'); +}); + +test('toRequest adds stm to POST request', async (t) => { + const request = newEmitterRequest({ + endpoint: 'https://example.com', + useStm: true, + }); + + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'web' }))); + const req = request.toRequest()!; + const data = await req.json(); + t.truthy(data.data[0].stm); +}); + +test('toRequest body has the correct structure', async (t) => { + const request = newEmitterRequest({ + endpoint: 'https://example.com', + }); + + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'web' }))); + t.true(request.addEvent(newEmitterEventFromPayload({ e: 'pv', p: 'web' }))); + + const req = request.toRequest()!; + const data = await req.json(); + t.is(data.schema, 'iglu:com.snowplowanalytics.snowplow/payload_data/jsonschema/1-0-4'); + t.is(data.data.length, 2); +}); diff --git a/libraries/tracker-core/test/emitter/index.test.ts b/libraries/tracker-core/test/emitter/index.test.ts new file mode 100644 index 000000000..0371224ef --- /dev/null +++ b/libraries/tracker-core/test/emitter/index.test.ts @@ -0,0 +1,353 @@ +import test from 'ava'; + +import { newEmitter, Emitter } from '../../src/emitter'; +import { newInMemoryEventStore } from '../../src/event_store'; + +function createMockFetch(status: number, requests: Request[]) { + return async (input: Request) => { + requests.push(input); + let response = new Response(null, { status }); + return response; + }; +} + +test.before(() => { + console.error = () => {}; // Silence console.error globally +}); + +test('input adds an event to the event store', async (t) => { + const requests: Request[] = []; + const mockFetch = createMockFetch(200, requests); + const eventStore = newInMemoryEventStore({}); + const emitter: Emitter = newEmitter({ + endpoint: 'https://example.com', + bufferSize: 2, + customFetch: mockFetch, + eventStore, + }); + + await emitter.input({ e: 'pv' }); + + t.is(await eventStore.count(), 1); + t.is(requests.length, 0); +}); + +test('input sends events to the collector when the buffer is full', async (t) => { + const requests: Request[] = []; + const mockFetch = createMockFetch(200, requests); + const eventStore = newInMemoryEventStore({}); + const emitter: Emitter = newEmitter({ + endpoint: 'https://example.com', + bufferSize: 2, + customFetch: mockFetch, + eventStore, + }); + + await emitter.input({ e: 'pv' }); + await emitter.input({ e: 'pv' }); + + t.is(requests.length, 1); + t.is(await eventStore.count(), 0); +}); + +test('flush sends events to the collector', async (t) => { + const requests: Request[] = []; + const mockFetch = createMockFetch(200, requests); + const eventStore = newInMemoryEventStore({}); + const emitter: Emitter = newEmitter({ + endpoint: 'https://example.com', + bufferSize: 5, + customFetch: mockFetch, + eventStore, + }); + + await emitter.input({ e: 'pv' }); + await emitter.input({ e: 'pv' }); + await emitter.flush(); + + t.is(requests.length, 1); + t.is(await eventStore.count(), 0); +}); + +test('flush does not make any request when the event store is empty', async (t) => { + const requests: Request[] = []; + const mockFetch = createMockFetch(200, requests); + const eventStore = newInMemoryEventStore({}); + const emitter: Emitter = newEmitter({ + endpoint: 'https://example.com', + bufferSize: 5, + customFetch: mockFetch, + eventStore, + }); + + await emitter.flush(); + + t.is(requests.length, 0); + t.is(await eventStore.count(), 0); +}); + +test('flush makes separate requests for server anonymization settings in events', async (t) => { + const requests: Request[] = []; + const mockFetch = createMockFetch(200, requests); + const eventStore = newInMemoryEventStore({}); + const emitter: Emitter = newEmitter({ + endpoint: 'https://example.com', + bufferSize: 5, + customFetch: mockFetch, + eventStore, + }); + + await emitter.input({ e: 'pv' }); + await emitter.input({ e: 'pv' }); + emitter.setAnonymousTracking(true); + await emitter.input({ e: 'pv' }); + await emitter.input({ e: 'pv' }); + await emitter.flush(); + + t.is(requests.length, 2); + t.is(requests[0].headers.get('SP-Anonymous'), null); + t.is(requests[1].headers.get('SP-Anonymous'), '*'); + t.is(await eventStore.count(), 0); +}); + +test('setCollectorUrl changes the collector URL', async (t) => { + const requests: Request[] = []; + const mockFetch = createMockFetch(200, requests); + const eventStore = newInMemoryEventStore({}); + const emitter: Emitter = newEmitter({ + endpoint: 'https://example.com', + bufferSize: 5, + customFetch: mockFetch, + eventStore, + }); + + emitter.setCollectorUrl('https://example2.com'); + await emitter.input({ e: 'pv' }); + await emitter.flush(); + + t.is(requests.length, 1); + t.is(await eventStore.count(), 0); + t.is(requests[0].url, 'https://example2.com/com.snowplowanalytics.snowplow/tp2'); +}); + +test('calls onRequestSuccess when the request is successful', async (t) => { + const requests: Request[] = []; + const mockFetch = createMockFetch(200, requests); + const eventStore = newInMemoryEventStore({}); + + await new Promise((resolve) => { + const emitter: Emitter = newEmitter({ + endpoint: 'https://example.com', + bufferSize: 5, + customFetch: mockFetch, + onRequestSuccess: (data) => { + t.is(data.length, 1); + resolve(null); + }, + eventStore, + }); + + emitter.input({ e: 'pv' }).then(() => emitter.flush()); + }); +}); + +test('handles errors when onRequestSuccess throws', async (t) => { + const requests: Request[] = []; + const mockFetch = createMockFetch(200, requests); + const eventStore = newInMemoryEventStore({}); + const emitter: Emitter = newEmitter({ + endpoint: 'https://example.com', + bufferSize: 5, + customFetch: mockFetch, + onRequestSuccess: () => { + throw new Error('error'); + }, + eventStore, + }); + + await emitter.input({ e: 'pv' }); + await emitter.flush(); + t.is(await eventStore.count(), 0); +}); + +test('calls onRequestFailure when the request fails', async (t) => { + const requests: Request[] = []; + const mockFetch = createMockFetch(500, requests); + const eventStore = newInMemoryEventStore({}); + + await new Promise((resolve) => { + const emitter: Emitter = newEmitter({ + endpoint: 'https://example.com', + bufferSize: 5, + customFetch: mockFetch, + onRequestFailure: (requestFailure, response) => { + t.is(requestFailure.events.length, 1); + t.is(requestFailure.status, 500); + t.is(response?.status, 500); + resolve(null); + }, + eventStore, + }); + + emitter.input({ e: 'pv' }).then(() => emitter.flush()); + }); +}); + +test('retries when the request fails', async (t) => { + const requests: Request[] = []; + const mockFetch = createMockFetch(500, requests); + const eventStore = newInMemoryEventStore({}); + const emitter: Emitter = newEmitter({ + endpoint: 'https://example.com', + bufferSize: 5, + customFetch: mockFetch, + retryFailedRequests: true, + eventStore, + }); + + await emitter.input({ e: 'pv' }); + await emitter.flush(); + t.is(requests.length, 1); + t.is(await eventStore.count(), 1); +}); + +test('does not retry when the request fails and retryFailedRequests is false', async (t) => { + const requests: Request[] = []; + const mockFetch = createMockFetch(500, requests); + const eventStore = newInMemoryEventStore({}); + const emitter: Emitter = newEmitter({ + endpoint: 'https://example.com', + bufferSize: 5, + customFetch: mockFetch, + retryFailedRequests: false, + eventStore, + }); + + await emitter.input({ e: 'pv' }); + await emitter.flush(); + t.is(requests.length, 1); + t.is(await eventStore.count(), 0); +}); + +test('does not retry certain status codes', async (t) => { + const requests: Request[] = []; + const mockFetch = createMockFetch(422, requests); + const eventStore = newInMemoryEventStore({}); + const emitter: Emitter = newEmitter({ + endpoint: 'https://example.com', + bufferSize: 5, + customFetch: mockFetch, + eventStore, + }); + + await emitter.input({ e: 'pv' }); + await emitter.flush(); + t.is(requests.length, 1); + t.is(await eventStore.count(), 0); +}); + +test('does not retry if the status code is in the dontRetry list', async (t) => { + const requests: Request[] = []; + const mockFetch = createMockFetch(500, requests); + const eventStore = newInMemoryEventStore({}); + const emitter: Emitter = newEmitter({ + endpoint: 'https://example.com', + bufferSize: 5, + customFetch: mockFetch, + dontRetryStatusCodes: [500], + eventStore, + }); + + await emitter.input({ e: 'pv' }); + await emitter.flush(); + t.is(requests.length, 1); + t.is(await eventStore.count(), 0); +}); + +test('retries if the status code is in the retry list', async (t) => { + const requests: Request[] = []; + const mockFetch = createMockFetch(422, requests); + const eventStore = newInMemoryEventStore({}); + const emitter: Emitter = newEmitter({ + endpoint: 'https://example.com', + bufferSize: 5, + customFetch: mockFetch, + retryStatusCodes: [422], + eventStore, + }); + + await emitter.input({ e: 'pv' }); + await emitter.flush(); + t.is(requests.length, 1); + t.is(await eventStore.count(), 1); +}); + +test('makes a request to the id service only once', async (t) => { + const requests: Request[] = []; + const mockFetch = createMockFetch(200, requests); + const emitter: Emitter = newEmitter({ + endpoint: 'https://example.com', + customFetch: mockFetch, + cookieExtensionService: 'https://id-example.com', + }); + + await emitter.input({ e: 'pv' }); + + t.is(requests.length, 2); + t.is(requests[0].url, 'https://id-example.com/'); + t.is(requests[1].url, 'https://example.com/com.snowplowanalytics.snowplow/tp2'); + + await emitter.input({ e: 'pv' }); + t.is(requests.length, 3); + t.is(requests[2].url, 'https://example.com/com.snowplowanalytics.snowplow/tp2'); +}); + +test('adds a timeout to the request', async (t) => { + const requests: Request[] = []; + let eventStore = newInMemoryEventStore({}); + + const mockFetch = (input: Request): Promise => { + requests.push(input); + + return new Promise((resolve, reject) => { + let timer = setTimeout(() => { + t.fail('Request should have timed out'); + resolve(new Response(null, { status: 200 })); + }, 500); + + input.signal?.addEventListener('abort', () => { + clearTimeout(timer); + reject(new Error('Request aborted')); + }); + }); + }; + const emitter: Emitter = newEmitter({ + endpoint: 'https://example.com', + customFetch: mockFetch, + connectionTimeout: 100, + eventStore, + }); + + await emitter.input({ e: 'pv' }); + + t.is(requests.length, 1); + t.is(await eventStore.count(), 1); +}); + +test('uses custom POST path configured in the emitter', async (t) => { + const requests: Request[] = []; + const mockFetch = createMockFetch(200, requests); + const eventStore = newInMemoryEventStore({}); + const emitter: Emitter = newEmitter({ + endpoint: 'https://example.com', + customFetch: mockFetch, + postPath: '/custom', + eventStore, + }); + + await emitter.input({ e: 'pv' }); + await emitter.flush(); + + t.is(requests.length, 1); + t.is(requests[0].url, 'https://example.com/custom'); +}); diff --git a/libraries/tracker-core/test/event_store.test.ts b/libraries/tracker-core/test/event_store.test.ts new file mode 100644 index 000000000..468d444d0 --- /dev/null +++ b/libraries/tracker-core/test/event_store.test.ts @@ -0,0 +1,92 @@ +import test from 'ava'; + +import { newInMemoryEventStore } from '../src/event_store'; +import { newEventStorePayload } from '../src/event_store_payload'; + +test('count returns the number of events', async (t) => { + const eventStore = newInMemoryEventStore({}); + + t.is(await eventStore.add(newEventStorePayload({ payload: { e: 'pv' } })), 1); + t.is(await eventStore.add(newEventStorePayload({ payload: { e: 'pv' } })), 2); + t.is(await eventStore.count(), 2); +}); + +test('iterator returns all events', async (t) => { + const eventStore = newInMemoryEventStore({}); + await eventStore.add(newEventStorePayload({ payload: { e: 'pv' } })); + await eventStore.add(newEventStorePayload({ payload: { e: 'pv' } })); + + const iterator = eventStore.iterator(); + const { value: first } = await iterator.next(); + const { value: second } = await iterator.next(); + const { done } = await iterator.next(); + + t.deepEqual(first?.payload, { e: 'pv' }); + t.deepEqual(second?.payload, { e: 'pv' }); + t.true(done); +}); + +test('removeHead removes the first n events', async (t) => { + const eventStore = newInMemoryEventStore({}); + await eventStore.add(newEventStorePayload({ payload: { e: 'pv' } })); + await eventStore.add(newEventStorePayload({ payload: { e: 'pv' } })); + + await eventStore.removeHead(1); + + t.is(await eventStore.count(), 1); +}); + +test('removeHead does nothing when there are no events', async (t) => { + const eventStore = newInMemoryEventStore({}); + await eventStore.removeHead(1); + + t.is(await eventStore.count(), 0); +}); + +test('does not exceed maxSize', async (t) => { + const eventStore = newInMemoryEventStore({ maxSize: 1 }); + await eventStore.add(newEventStorePayload({ payload: { e: 'pv1' } })); + await eventStore.add(newEventStorePayload({ payload: { e: 'pv2' } })); + + t.is(await eventStore.count(), 1); + t.is((await eventStore.iterator().next()).value?.payload.e, 'pv2'); +}); + +test('iterator does not consider mutations', async (t) => { + const eventStore = newInMemoryEventStore({}); + await eventStore.add(newEventStorePayload({ payload: { e: 'pv' } })); + + const iterator = eventStore.iterator(); + await iterator.next(); + + await eventStore.add(newEventStorePayload({ payload: { e: 'pv' } })); + + const { value } = await iterator.next(); + + t.is(value, undefined); +}); + +test('stores server anonymization setting', async (t) => { + const eventStore = newInMemoryEventStore({}); + await eventStore.add(newEventStorePayload({ payload: { e: 'pv' }, svrAnon: true })); + await eventStore.add(newEventStorePayload({ payload: { e: 'pv' }, svrAnon: false })); + await eventStore.add(newEventStorePayload({ payload: { e: 'pv' } })); + + t.is(await eventStore.count(), 3); + const iterator = eventStore.iterator(); + const first = await iterator.next(); + const second = await iterator.next(); + const third = await iterator.next(); + + t.true(first?.value?.svrAnon); + t.false(second?.value?.svrAnon); + t.false(third?.value?.svrAnon); +}); + +test('getAllPayloads returns all payloads', async (t) => { + const eventStore = newInMemoryEventStore({}); + await eventStore.add(newEventStorePayload({ payload: { e: 'pv' } })); + await eventStore.add(newEventStorePayload({ payload: { e: 'pv' } })); + + t.deepEqual(await eventStore.getAllPayloads(), [{ e: 'pv' }, { e: 'pv' }]); +}); diff --git a/libraries/tracker-core/test/payload.ts b/libraries/tracker-core/test/payload.ts new file mode 100644 index 000000000..a2025d7c2 --- /dev/null +++ b/libraries/tracker-core/test/payload.ts @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import test from 'ava'; +import { isJson, isNonEmptyJson, payloadBuilder, payloadJsonProcessor } from '../src/payload'; + +const sampleJson = { + schema: 'iglu:com.snowplowanalytics.snowplow/contexts/jsonschema/1-0-0', + data: [ + { + schema: 'iglu:com.example_company/page/jsonschema/1-2-1', + data: { + pageType: 'test', + lastUpdated: new Date(Date.UTC(2014, 1, 26)), + }, + }, + { + schema: 'iglu:com.example_company/user/jsonschema/2-0-0', + data: { + userType: 'tester', + }, + }, + ], +}; + +const expectedPayloads = [ + { + co: '{"schema":"iglu:com.snowplowanalytics.snowplow/contexts/jsonschema/1-0-0","data":[{"schema":"iglu:com.example_company/page/jsonschema/1-2-1","data":{"pageType":"test","lastUpdated":"2014-02-26T00:00:00.000Z"}},{"schema":"iglu:com.example_company/user/jsonschema/2-0-0","data":{"userType":"tester"}}]}', + }, + { + cx: 'eyJzY2hlbWEiOiJpZ2x1OmNvbS5zbm93cGxvd2FuYWx5dGljcy5zbm93cGxvdy9jb250ZXh0cy9qc29uc2NoZW1hLzEtMC0wIiwiZGF0YSI6W3sic2NoZW1hIjoiaWdsdTpjb20uZXhhbXBsZV9jb21wYW55L3BhZ2UvanNvbnNjaGVtYS8xLTItMSIsImRhdGEiOnsicGFnZVR5cGUiOiJ0ZXN0IiwibGFzdFVwZGF0ZWQiOiIyMDE0LTAyLTI2VDAwOjAwOjAwLjAwMFoifX0seyJzY2hlbWEiOiJpZ2x1OmNvbS5leGFtcGxlX2NvbXBhbnkvdXNlci9qc29uc2NoZW1hLzItMC0wIiwiZGF0YSI6eyJ1c2VyVHlwZSI6InRlc3RlciJ9fV19', + }, +]; + +test('JSON Payload identifies as JSON', (t) => { + const json = { + name: 'john', + properties: { + age: 30, + languages: ['English', 'French'], + }, + }; + + t.is(isJson(json), true); +}); + +test('non-JSON Payload doesnt identify as JSON', (t) => { + const nonJson = function () { + return {}; + }; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + t.is(isJson(nonJson as any), false); +}); + +test('Empty Payload identifies as an empty JSON', (t) => { + const emptyJson = {}; + t.is(isNonEmptyJson(emptyJson), false); +}); + +test('Build a payload', (t) => { + const sb = payloadBuilder(); + sb.add('e', 'pv'); + sb.add('tv', 'js-2.0.0'); + + t.deepEqual(sb.build(), { e: 'pv', tv: 'js-2.0.0' }); +}); + +test('Do not add undefined values to a payload', (t) => { + const sb = payloadBuilder(); + sb.add('e', undefined); + + t.deepEqual(sb.build(), {}, 'Undefined values should not be added to the payload'); +}); + +test('Do not add null values to a payload', (t) => { + const sb = payloadBuilder(); + sb.add('e', undefined); + + t.deepEqual(sb.build(), {}, 'Null values should not be added to the payload'); +}); + +test('Add a dictionary of name-value pairs to the payload', (t) => { + const sb = payloadBuilder(); + sb.addDict({ + e: 'pv', + tv: 'js-2.0.0', + }); + + t.deepEqual( + sb.build(), + { e: 'pv', tv: 'js-2.0.0' }, + 'A dictionary of name-value pairs should be added to the payload' + ); +}); + +test('Add a JSON to the payload', (t) => { + const sb = payloadBuilder(); + sb.withJsonProcessor(payloadJsonProcessor(false)); + sb.addJson('cx', 'co', sampleJson); + + t.deepEqual(sb.build(), expectedPayloads[0], 'JSON should be added correctly'); +}); + +test('Add a base 64 encoded JSON to the payload', (t) => { + const sb = payloadBuilder(); + sb.withJsonProcessor(payloadJsonProcessor(true)); + sb.addJson('cx', 'co', sampleJson); + + t.deepEqual(sb.build(), expectedPayloads[1], 'JSON should be encoded correctly'); +}); + +test('payloadBuilder with no json processor, processes no json', (t) => { + const sb = payloadBuilder(); + sb.addJson('cx', 'co', sampleJson); + + t.deepEqual(sb.build(), {}, 'JSON should be missing'); +}); + +test('Add a context entity', (t) => { + const sb = payloadBuilder(); + sb.withJsonProcessor(payloadJsonProcessor(false)); + sb.addContextEntity(sampleJson.data[0]); + sb.addContextEntity(sampleJson.data[1]); + let payload = sb.build(); + t.deepEqual(payload, expectedPayloads[0], 'JSON should be added correctly'); +}); + +test('Maintain context entities after subsequent builds', (t) => { + const sb = payloadBuilder(); + sb.withJsonProcessor(payloadJsonProcessor(true)); + sb.addContextEntity(sampleJson.data[0]); + sb.build(); + sb.addContextEntity(sampleJson.data[1]); + let payload = sb.build(); + t.deepEqual(payload, expectedPayloads[1], 'JSON should be added correctly'); +}); + +test('Add multiple context entities through addJson', (t) => { + const sb = payloadBuilder(); + sb.withJsonProcessor(payloadJsonProcessor(true)); + sb.addJson('cx', 'co', { schema: sampleJson.schema, data: [sampleJson.data[0]] }); + sb.addJson('cx', 'co', { schema: sampleJson.schema, data: [sampleJson.data[1]] }); + let payload = sb.build(); + t.deepEqual(payload, expectedPayloads[1], 'JSON should be added correctly'); +}); + +test('Combines context entities added through addJson and addContextEntity', (t) => { + const sb = payloadBuilder(); + sb.withJsonProcessor(payloadJsonProcessor(true)); + sb.addJson('cx', 'co', { schema: sampleJson.schema, data: [sampleJson.data[0]] }); + sb.addContextEntity(sampleJson.data[1]); + let payload = sb.build(); + t.deepEqual(payload, expectedPayloads[1], 'JSON should be added correctly'); +}); diff --git a/libraries/tracker-core/tsconfig.json b/libraries/tracker-core/tsconfig.json new file mode 100644 index 000000000..4082f16a5 --- /dev/null +++ b/libraries/tracker-core/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +} diff --git a/local_test.sh b/local_test.sh deleted file mode 100755 index 12839b537..000000000 --- a/local_test.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash -cd core -grunt -cd .. -grunt local -if [[ "$(uname)" == "Darwin" ]]; then - (sleep 1 && open http:127.0.0.1:8000/integration.html)& -elif [[ "$(expr substr $(uname -s) 1 5)" == "Linux" ]]; then - (sleep 1 && xdg-open http:127.0.0.1:8000/integration.html)& -elif [[ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]]; then - : -elif [[ "$(expr substr $(uname -s) 1 10)" == "MINGW64_NT" ]]; then - : -fi -python3 ./tests/local/http-server.py diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json deleted file mode 100644 index 127ca7115..000000000 --- a/npm-shrinkwrap.json +++ /dev/null @@ -1,13225 +0,0 @@ -{ - "name": "snowplow-tracker", - "version": "2.14.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", - "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, - "@babel/core": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.6.2.tgz", - "integrity": "sha512-l8zto/fuoZIbncm+01p8zPSDZu/VuuJhAfA7d/AbzM09WR7iVhavvfNDYCNpo1VvLk6E6xgAoP9P+/EMJHuRkQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.6.2", - "@babel/helpers": "^7.6.2", - "@babel/parser": "^7.6.2", - "@babel/template": "^7.6.0", - "@babel/traverse": "^7.6.2", - "@babel/types": "^7.6.0", - "convert-source-map": "^1.1.0", - "debug": "^4.1.0", - "json5": "^2.1.0", - "lodash": "^4.17.13", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.2.tgz", - "integrity": "sha512-j8iHaIW4gGPnViaIHI7e9t/Hl8qLjERI6DcV9kEpAIDJsAOrcnXqRS7t+QbhL76pwbtqP+QCQLL0z1CyVmtjjQ==", - "dev": true, - "requires": { - "@babel/types": "^7.6.0", - "jsesc": "^2.5.1", - "lodash": "^4.17.13", - "source-map": "^0.5.0" - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", - "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", - "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", - "dev": true, - "requires": { - "@babel/helper-explode-assignable-expression": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-call-delegate": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz", - "integrity": "sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==", - "dev": true, - "requires": { - "@babel/helper-hoist-variables": "^7.4.4", - "@babel/traverse": "^7.4.4", - "@babel/types": "^7.4.4" - } - }, - "@babel/helper-define-map": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.5.5.tgz", - "integrity": "sha512-fTfxx7i0B5NJqvUOBBGREnrqbTxRh7zinBANpZXAVDlsZxYdclDp467G1sQ8VZYMnAURY3RpBUAgOYT9GfzHBg==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/types": "^7.5.5", - "lodash": "^4.17.13" - } - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz", - "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", - "dev": true, - "requires": { - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-function-name": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", - "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", - "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz", - "integrity": "sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==", - "dev": true, - "requires": { - "@babel/types": "^7.4.4" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.5.5.tgz", - "integrity": "sha512-5qZ3D1uMclSNqYcXqiHoA0meVdv+xUEex9em2fqMnrk/scphGlGgg66zjMrPJESPwrFJ6sbfFQYUSa0Mz7FabA==", - "dev": true, - "requires": { - "@babel/types": "^7.5.5" - } - }, - "@babel/helper-module-imports": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", - "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-module-transforms": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.5.5.tgz", - "integrity": "sha512-jBeCvETKuJqeiaCdyaheF40aXnnU1+wkSiUs/IQg3tB85up1LyL8x77ClY8qJpuRJUcXQo+ZtdNESmZl4j56Pw==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/template": "^7.4.4", - "@babel/types": "^7.5.5", - "lodash": "^4.17.13" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz", - "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", - "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", - "dev": true - }, - "@babel/helper-regex": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.5.5.tgz", - "integrity": "sha512-CkCYQLkfkiugbRDO8eZn6lRuR8kzZoGXCg3149iTk5se7g6qykSpy3+hELSwquhu+TgHn8nkLiBwHvNX8Hofcw==", - "dev": true, - "requires": { - "lodash": "^4.17.13" - } - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", - "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-wrap-function": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-replace-supers": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.5.5.tgz", - "integrity": "sha512-XvRFWrNnlsow2u7jXDuH4jDDctkxbS7gXssrP4q2nUD606ukXHRvydj346wmNg+zAgpFx4MWf4+usfC93bElJg==", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.5.5", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/traverse": "^7.5.5", - "@babel/types": "^7.5.5" - } - }, - "@babel/helper-simple-access": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", - "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", - "dev": true, - "requires": { - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", - "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", - "dev": true, - "requires": { - "@babel/types": "^7.4.4" - } - }, - "@babel/helper-wrap-function": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz", - "integrity": "sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.2.0" - } - }, - "@babel/helpers": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.6.2.tgz", - "integrity": "sha512-3/bAUL8zZxYs1cdX2ilEE0WobqbCmKWr/889lf2SS0PpDcpEIY8pb1CCyz0pEcX3pEb+MCbks1jIokz2xLtGTA==", - "dev": true, - "requires": { - "@babel/template": "^7.6.0", - "@babel/traverse": "^7.6.2", - "@babel/types": "^7.6.0" - } - }, - "@babel/highlight": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", - "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", - "dev": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.2.tgz", - "integrity": "sha512-mdFqWrSPCmikBoaBYMuBulzTIKuXVPtEISFbRRVNwMWpCms/hmE2kRq0bblUHaNRKrjRlmVbx1sDHmjmRgD2Xg==", - "dev": true - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz", - "integrity": "sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.1.0", - "@babel/plugin-syntax-async-generators": "^7.2.0" - } - }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.5.0.tgz", - "integrity": "sha512-x/iMjggsKTFHYC6g11PL7Qy58IK8H5zqfm9e6hu4z1iH2IRyAp9u9dL80zA6R76yFovETFLKz2VJIC2iIPBuFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-dynamic-import": "^7.2.0" - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz", - "integrity": "sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-json-strings": "^7.2.0" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.6.2.tgz", - "integrity": "sha512-LDBXlmADCsMZV1Y9OQwMc0MyGZ8Ta/zlD9N67BfQT8uYwkRswiu2hU6nJKrjrt/58aH/vqfQlR/9yId/7A2gWw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.2.0" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz", - "integrity": "sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.2.0" - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.6.2.tgz", - "integrity": "sha512-NxHETdmpeSCtiatMRYWVJo7266rrvAC3DTeG5exQBIH/fMIUK7ejDNznBbn3HQl/o9peymRRg7Yqkx6PdUXmMw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.6.0" - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz", - "integrity": "sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz", - "integrity": "sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz", - "integrity": "sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", - "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz", - "integrity": "sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz", - "integrity": "sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz", - "integrity": "sha512-mqvkzwIGkq0bEF1zLRRiTdjfomZJDV33AH3oQzHVGkI2VzEmXLpKKOBvEVaFZBJdN0XTyH38s9j/Kiqr68dggg==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.1.0" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz", - "integrity": "sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.6.2.tgz", - "integrity": "sha512-zZT8ivau9LOQQaOGC7bQLQOT4XPkPXgN2ERfUgk1X8ql+mVkLc4E8eKk+FO3o0154kxzqenWCorfmEXpEZcrSQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "lodash": "^4.17.13" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.5.5.tgz", - "integrity": "sha512-U2htCNK/6e9K7jGyJ++1p5XRU+LJjrwtoiVn9SzRlDT2KubcZ11OOwy3s24TjHxPgxNwonCYP7U2K51uVYCMDg==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-define-map": "^7.5.5", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.5.5", - "@babel/helper-split-export-declaration": "^7.4.4", - "globals": "^11.1.0" - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz", - "integrity": "sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.6.0.tgz", - "integrity": "sha512-2bGIS5P1v4+sWTCnKNDZDxbGvEqi0ijeqM/YqHtVGrvG2y0ySgnEEhXErvE9dA0bnIzY9bIzdFK0jFA46ASIIQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.6.2.tgz", - "integrity": "sha512-KGKT9aqKV+9YMZSkowzYoYEiHqgaDhGmPNZlZxX6UeHC4z30nC1J9IrZuGqbYFB1jaIGdv91ujpze0exiVK8bA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.6.0" - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz", - "integrity": "sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz", - "integrity": "sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==", - "dev": true, - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz", - "integrity": "sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz", - "integrity": "sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-literals": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz", - "integrity": "sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz", - "integrity": "sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz", - "integrity": "sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0", - "babel-plugin-dynamic-import-node": "^2.3.0" - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.6.0.tgz", - "integrity": "sha512-Ma93Ix95PNSEngqomy5LSBMAQvYKVe3dy+JlVJSHEXZR5ASL9lQBedMiCyVtmTLraIDVRE3ZjTZvmXXD2Ozw3g==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.4.4", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0", - "babel-plugin-dynamic-import-node": "^2.3.0" - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.5.0.tgz", - "integrity": "sha512-Q2m56tyoQWmuNGxEtUyeEkm6qJYFqs4c+XyXH5RAuYxObRNz9Zgj/1g2GMnjYp2EUyEy7YTrxliGCXzecl/vJg==", - "dev": true, - "requires": { - "@babel/helper-hoist-variables": "^7.4.4", - "@babel/helper-plugin-utils": "^7.0.0", - "babel-plugin-dynamic-import-node": "^2.3.0" - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz", - "integrity": "sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.6.2.tgz", - "integrity": "sha512-xBdB+XOs+lgbZc2/4F5BVDVcDNS4tcSKQc96KmlqLEAwz6tpYPEvPdmDfvVG0Ssn8lAhronaRs6Z6KSexIpK5g==", - "dev": true, - "requires": { - "regexpu-core": "^4.6.0" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz", - "integrity": "sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.5.5.tgz", - "integrity": "sha512-un1zJQAhSosGFBduPgN/YFNvWVpRuHKU7IHBglLoLZsGmruJPOo6pbInneflUdmq7YvSVqhpPs5zdBvLnteltQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.5.5" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz", - "integrity": "sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw==", - "dev": true, - "requires": { - "@babel/helper-call-delegate": "^7.4.4", - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz", - "integrity": "sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz", - "integrity": "sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA==", - "dev": true, - "requires": { - "regenerator-transform": "^0.14.0" - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz", - "integrity": "sha512-fz43fqW8E1tAB3DKF19/vxbpib1fuyCwSPE418ge5ZxILnBhWyhtPgz8eh1RCGGJlwvksHkyxMxh0eenFi+kFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz", - "integrity": "sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.6.2.tgz", - "integrity": "sha512-DpSvPFryKdK1x+EDJYCy28nmAaIMdxmhot62jAXF/o99iA33Zj2Lmcp3vDmz+MUh0LNYVPvfj5iC3feb3/+PFg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz", - "integrity": "sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.0.0" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz", - "integrity": "sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz", - "integrity": "sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.6.2.tgz", - "integrity": "sha512-orZI6cWlR3nk2YmYdb0gImrgCUwb5cBUwjf6Ks6dvNVvXERkwtJWOQaEOjPiu0Gu1Tq6Yq/hruCZZOOi9F34Dw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.6.0" - } - }, - "@babel/preset-env": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.6.2.tgz", - "integrity": "sha512-Ru7+mfzy9M1/YTEtlDS8CD45jd22ngb9tXnn64DvQK3ooyqSw9K4K9DUWmYknTTVk4TqygL9dqCrZgm1HMea/Q==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-async-generator-functions": "^7.2.0", - "@babel/plugin-proposal-dynamic-import": "^7.5.0", - "@babel/plugin-proposal-json-strings": "^7.2.0", - "@babel/plugin-proposal-object-rest-spread": "^7.6.2", - "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.6.2", - "@babel/plugin-syntax-async-generators": "^7.2.0", - "@babel/plugin-syntax-dynamic-import": "^7.2.0", - "@babel/plugin-syntax-json-strings": "^7.2.0", - "@babel/plugin-syntax-object-rest-spread": "^7.2.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", - "@babel/plugin-transform-arrow-functions": "^7.2.0", - "@babel/plugin-transform-async-to-generator": "^7.5.0", - "@babel/plugin-transform-block-scoped-functions": "^7.2.0", - "@babel/plugin-transform-block-scoping": "^7.6.2", - "@babel/plugin-transform-classes": "^7.5.5", - "@babel/plugin-transform-computed-properties": "^7.2.0", - "@babel/plugin-transform-destructuring": "^7.6.0", - "@babel/plugin-transform-dotall-regex": "^7.6.2", - "@babel/plugin-transform-duplicate-keys": "^7.5.0", - "@babel/plugin-transform-exponentiation-operator": "^7.2.0", - "@babel/plugin-transform-for-of": "^7.4.4", - "@babel/plugin-transform-function-name": "^7.4.4", - "@babel/plugin-transform-literals": "^7.2.0", - "@babel/plugin-transform-member-expression-literals": "^7.2.0", - "@babel/plugin-transform-modules-amd": "^7.5.0", - "@babel/plugin-transform-modules-commonjs": "^7.6.0", - "@babel/plugin-transform-modules-systemjs": "^7.5.0", - "@babel/plugin-transform-modules-umd": "^7.2.0", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.6.2", - "@babel/plugin-transform-new-target": "^7.4.4", - "@babel/plugin-transform-object-super": "^7.5.5", - "@babel/plugin-transform-parameters": "^7.4.4", - "@babel/plugin-transform-property-literals": "^7.2.0", - "@babel/plugin-transform-regenerator": "^7.4.5", - "@babel/plugin-transform-reserved-words": "^7.2.0", - "@babel/plugin-transform-shorthand-properties": "^7.2.0", - "@babel/plugin-transform-spread": "^7.6.2", - "@babel/plugin-transform-sticky-regex": "^7.2.0", - "@babel/plugin-transform-template-literals": "^7.4.4", - "@babel/plugin-transform-typeof-symbol": "^7.2.0", - "@babel/plugin-transform-unicode-regex": "^7.6.2", - "@babel/types": "^7.6.0", - "browserslist": "^4.6.0", - "core-js-compat": "^3.1.1", - "invariant": "^2.2.2", - "js-levenshtein": "^1.1.3", - "semver": "^5.5.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "@babel/register": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.6.2.tgz", - "integrity": "sha512-xgZk2LRZvt6i2SAUWxc7ellk4+OYRgS3Zpsnr13nMS1Qo25w21Uu8o6vTOAqNaxiqrnv30KTYzh9YWY2k21CeQ==", - "dev": true, - "requires": { - "find-cache-dir": "^2.0.0", - "lodash": "^4.17.13", - "mkdirp": "^0.5.1", - "pirates": "^4.0.0", - "source-map-support": "^0.5.9" - } - }, - "@babel/template": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", - "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.6.0", - "@babel/types": "^7.6.0" - } - }, - "@babel/traverse": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.2.tgz", - "integrity": "sha512-8fRE76xNwNttVEF2TwxJDGBLWthUkHWSldmfuBzVRmEDWOtu4XdINTgN7TDWzuLg4bbeIMLvfMFD9we5YcWkRQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.6.2", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/parser": "^7.6.2", - "@babel/types": "^7.6.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.13" - } - }, - "@babel/types": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.1.tgz", - "integrity": "sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g==", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - } - }, - "@cnakazawa/watch": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz", - "integrity": "sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA==", - "dev": true, - "requires": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" - } - }, - "@hapi/address": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.2.tgz", - "integrity": "sha512-O4QDrx+JoGKZc6aN64L04vqa7e41tIiLU+OvKdcYaEMP97UttL0f9GIi9/0A4WAMx0uBd6SidDIhktZhgOcN8Q==", - "dev": true - }, - "@hapi/bourne": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-1.3.2.tgz", - "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==", - "dev": true - }, - "@hapi/hoek": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.3.0.tgz", - "integrity": "sha512-C0QL9bmgUXTSuf8nDeGrpMjtJG7tPUr8wG6/wxPbP62tGwCwQtdMSJYfESowmY4P3Hn593f+8OzNY5bckcu/LQ==", - "dev": true - }, - "@hapi/joi": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.1.tgz", - "integrity": "sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==", - "dev": true, - "requires": { - "@hapi/address": "2.x.x", - "@hapi/bourne": "1.x.x", - "@hapi/hoek": "8.x.x", - "@hapi/topo": "3.x.x" - } - }, - "@hapi/topo": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.5.tgz", - "integrity": "sha512-bi9m1jrui9LlvtVdLaHv0DqeOoe+I8dep+nEcTgW6XxJHL3xArQcilYz3tIp0cRC4gWlsVtABK7vNKg4jzEmAA==", - "dev": true, - "requires": { - "@hapi/hoek": "8.x.x" - } - }, - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "dev": true, - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - }, - "@jest/core": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.9.0.tgz", - "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/reporters": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "graceful-fs": "^4.1.15", - "jest-changed-files": "^24.9.0", - "jest-config": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-resolve-dependencies": "^24.9.0", - "jest-runner": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "jest-watcher": "^24.9.0", - "micromatch": "^3.1.10", - "p-each-series": "^1.0.0", - "realpath-native": "^1.1.0", - "rimraf": "^2.5.4", - "slash": "^2.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "@jest/environment": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz", - "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==", - "dev": true, - "requires": { - "@jest/fake-timers": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/reporters": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz", - "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==", - "dev": true, - "requires": { - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "glob": "^7.1.2", - "istanbul-lib-coverage": "^2.0.2", - "istanbul-lib-instrument": "^3.0.1", - "istanbul-lib-report": "^2.0.4", - "istanbul-lib-source-maps": "^3.0.1", - "istanbul-reports": "^2.2.6", - "jest-haste-map": "^24.9.0", - "jest-resolve": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.6.0", - "node-notifier": "^5.4.2", - "slash": "^2.0.0", - "source-map": "^0.6.0", - "string-length": "^2.0.0" - }, - "dependencies": { - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "dev": true, - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", - "dev": true, - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - } - }, - "@jest/test-sequencer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz", - "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==", - "dev": true, - "requires": { - "@jest/test-result": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-runner": "^24.9.0", - "jest-runtime": "^24.9.0" - } - }, - "@jest/transform": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz", - "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^24.9.0", - "babel-plugin-istanbul": "^5.1.0", - "chalk": "^2.0.1", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.1.15", - "jest-haste-map": "^24.9.0", - "jest-regex-util": "^24.9.0", - "jest-util": "^24.9.0", - "micromatch": "^3.1.10", - "pirates": "^4.0.1", - "realpath-native": "^1.1.0", - "slash": "^2.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "2.4.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "write-file-atomic": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", - "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - } - } - }, - "@jest/types": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", - "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^13.0.0" - } - }, - "@types/babel__core": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz", - "integrity": "sha512-8fBo0UR2CcwWxeX7WIIgJ7lXjasFxoYgRnFHUj+hRvKkpiBJbxhdAPTCY6/ZKM0uxANFVzt4yObSLuTiTnazDA==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.0.tgz", - "integrity": "sha512-c1mZUu4up5cp9KROs/QAw0gTeHrw/x7m52LcnvMxxOZ03DmLwPV0MlGmlgzV3cnSdjhJOZsj7E7FHeioai+egw==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz", - "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.7.tgz", - "integrity": "sha512-CeBpmX1J8kWLcDEnI3Cl2Eo6RfbGvzUctA+CjZUhOKDFbLfcr7fc4usEqLNWetrlJd7RhAkyYe2czXop4fICpw==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/events": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", - "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", - "dev": true - }, - "@types/glob": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", - "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", - "dev": true, - "requires": { - "@types/events": "*", - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", - "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz", - "integrity": "sha512-3BUTyMzbZa2DtDI2BkERNC6jJw2Mr2Y0oGI7mRxYNBPxppbtEK1F66u3bKwU2g+wxwWI7PAoRpJnOY1grJqzHg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz", - "integrity": "sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*", - "@types/istanbul-lib-report": "*" - } - }, - "@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", - "dev": true - }, - "@types/node": { - "version": "12.7.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.11.tgz", - "integrity": "sha512-Otxmr2rrZLKRYIybtdG/sgeO+tHY20GxeDjcGmUnmmlCWyEnv2a2x1ZXBo3BTec4OiTXMQCiazB8NMBf0iRlFw==" - }, - "@types/stack-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", - "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", - "dev": true - }, - "@types/uuid": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-2.0.30.tgz", - "integrity": "sha512-nmSJ0AL2mZAi68dYb7nKSIJ9YiM68eToP3Ugz66Ou7qkSatIptDM6CvOUmj4epMKWvO9gr9fFBxEEJkromp1Qg==", - "requires": { - "@types/node": "*" - } - }, - "@types/yargs": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.3.tgz", - "integrity": "sha512-K8/LfZq2duW33XW/tFwEAfnZlqIfVsoyRB3kfXdPXYhl0nfM8mmh7GS0jg7WrX2Dgq/0Ha/pR1PaR+BvmWwjiQ==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.1.0.tgz", - "integrity": "sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==", - "dev": true - }, - "@wdio/cli": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-5.15.0.tgz", - "integrity": "sha512-bG1PqrLCV//eO62oDoGw0yqn9+7ra43sWLhCfMbqoZAJlfLddV7wgep7wLaKlFB6XPrhNINBksPoaNWV2DxNnw==", - "dev": true, - "requires": { - "@wdio/config": "5.15.0", - "@wdio/logger": "5.13.2", - "@wdio/utils": "5.15.0", - "async-exit-hook": "^2.0.1", - "chalk": "^2.3.2", - "chokidar": "^3.0.0", - "cli-spinners": "^2.1.0", - "ejs": "^2.5.7", - "fs-extra": "^8.0.1", - "inquirer": "^7.0.0", - "lodash.flattendeep": "^4.4.0", - "lodash.pickby": "^4.6.0", - "lodash.union": "^4.6.0", - "log-update": "^3.2.0", - "webdriverio": "5.15.0", - "yargs": "^14.0.0", - "yarn-install": "^1.0.0" - }, - "dependencies": { - "ansi-escapes": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.2.1.tgz", - "integrity": "sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q==", - "dev": true, - "requires": { - "type-fest": "^0.5.2" - } - }, - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "binary-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", - "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", - "dev": true - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "chokidar": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.2.1.tgz", - "integrity": "sha512-/j5PPkb5Feyps9e+jo07jUZGvkB5Aj953NrI4s8xSVScrAo/RHeILrtdb4uzR7N6aaFFxxJ+gt8mA8HfNpw76w==", - "dev": true, - "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.1.0", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.1.3" - } - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "cli-spinners": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.2.0.tgz", - "integrity": "sha512-tgU3fKwzYjiLEQgPMD9Jt+JjHVL9kW93FiIMX/l7rivvOD4/LL0Mf7gda3+4U2KJBloybwgj5KEoQgGRioMiKQ==", - "dev": true - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - } - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "figures": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.0.0.tgz", - "integrity": "sha512-HKri+WoWoUgr83pehn/SIgLOMZ9nAWC6dcGj26RY2R4F50u4+RTUz0RCrUlOV3nKRAICW1UGzyb+kcX2qK1S/g==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "fsevents": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.0.tgz", - "integrity": "sha512-+iXhW3LuDQsno8dOIrCIT/CBjeBWuP7PXe8w9shnj9Lebny/Gx1ZjVBYwexLz36Ri2jKuXMNpV6CYNh8lHHgrQ==", - "dev": true, - "optional": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "glob-parent": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", - "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "inquirer": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.0.tgz", - "integrity": "sha512-rSdC7zelHdRQFkWnhsMu2+2SO41mpv2oF2zy4tMhmiLWkcKbOAs87fWAJhVXttKVwhdZvymvnuM95EyEXg2/tQ==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^2.4.2", - "cli-cursor": "^3.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.15", - "mute-stream": "0.0.8", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^4.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } - } - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "onetime": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", - "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "readdirp": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.1.3.tgz", - "integrity": "sha512-ZOsfTGkjO2kqeR5Mzr5RYDbTGYneSkdNKX2fOX2P5jF7vMrd/GNnIAUtDldeHHumHUCQ3V05YfWUdxMPAsRu9Q==", - "dev": true, - "requires": { - "picomatch": "^2.0.4" - } - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", - "dev": true, - "requires": { - "is-promise": "^2.1.0" - } - }, - "string-width": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.1.0.tgz", - "integrity": "sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^5.2.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - } - } - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - }, - "yargs": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.0.tgz", - "integrity": "sha512-/is78VKbKs70bVZH7w4YaZea6xcJWOAwkhbR0CFuZBmYtfTYF0xjGJF43AYd8g2Uii1yJwmS5GR2vBmrc32sbg==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "decamelize": "^1.2.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^15.0.0" - }, - "dependencies": { - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - } - } - }, - "yargs-parser": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.0.tgz", - "integrity": "sha512-xLTUnCMc4JhxrPEPUYD5IBR1mWCK/aT6+RJ/K29JY2y1vD+FhtgKK0AXRWvI262q3QSffAQuTouFIKUuHX89wQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "@wdio/config": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-5.15.0.tgz", - "integrity": "sha512-K9Q+avld8HcsgKMzX2ds16DJcUIeJQpoVD2zVhoIg7H/pxX7O7pxQZ+9Kl6EAnp0czgJSXyWns/y+lFvt0yBEw==", - "dev": true, - "requires": { - "@wdio/logger": "5.13.2", - "deepmerge": "^4.0.0", - "glob": "^7.1.2" - }, - "dependencies": { - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "@wdio/jasmine-framework": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@wdio/jasmine-framework/-/jasmine-framework-5.15.0.tgz", - "integrity": "sha512-lkfJVsBe038arIVRNM+KvA07J2PagymRGYswpfYcsNe1+HiEowzE+bxLIsN0hydxAguzm9AjSolFyJjaMDFprA==", - "dev": true, - "requires": { - "@wdio/logger": "5.13.2", - "@wdio/utils": "5.15.0", - "jasmine": "^3.3.0" - } - }, - "@wdio/local-runner": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-5.15.0.tgz", - "integrity": "sha512-MCuEWmVUtJnZ0NF7V8MtTsp/f0VhqhdEpog/hGzcw6+KEwDVZfTWY0s5jE+PJBthR8l3giJVWPiq/FYJUyCCQA==", - "dev": true, - "requires": { - "@wdio/logger": "5.13.2", - "@wdio/repl": "5.15.0", - "@wdio/runner": "5.15.0", - "async-exit-hook": "^2.0.1", - "stream-buffers": "^3.0.2" - } - }, - "@wdio/logger": { - "version": "5.13.2", - "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-5.13.2.tgz", - "integrity": "sha512-F8NlP+AoN0zKv8+0iDAJxdbb488kk5LlPA6U6XPgTT/1xxPgpM4MVQoiCGtLOU9UNPX9XLfgoCXyYWMxp96Ncg==", - "dev": true, - "requires": { - "chalk": "^2.3.0", - "loglevel": "^1.6.0", - "loglevel-plugin-prefix": "^0.8.4", - "strip-ansi": "^5.2.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "@wdio/protocols": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-5.14.0.tgz", - "integrity": "sha512-7jRxGkreibkqHKQV5jlQmAyqzIIU43lg9KSNGy0ThrUz8kLsOzClaTdL2qDlFUkLcplqMvRFcnmwFPjvCptmVg==", - "dev": true - }, - "@wdio/repl": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-5.15.0.tgz", - "integrity": "sha512-yiIa9AWUtWlzlR2+58v0FjHohRZ70aRrO+pDLTVqdTr9Puj0a6KbRLTl6BDpjUk2j3IljDaAb/HhMKnOV7AUcw==", - "dev": true, - "requires": { - "@wdio/utils": "5.15.0" - } - }, - "@wdio/reporter": { - "version": "5.14.5", - "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-5.14.5.tgz", - "integrity": "sha512-ySFUny5LBKIso1wZW5is5AyBU3Kje/7AzWok1Dz45kxr2vg0IfUyd3NIjiUxJf3TLm7YVRJvCDouaDr5betXPA==", - "dev": true, - "requires": { - "fs-extra": "^8.0.1" - } - }, - "@wdio/runner": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-5.15.0.tgz", - "integrity": "sha512-5TtLCnJZXqQBq/ADzfqYv+ouzzCPrKWXyjjpnvQyJhLmYj8mO10RdRBAzLDrLjftORnrROU1Pfii+yUeTREGmw==", - "dev": true, - "requires": { - "@wdio/config": "5.15.0", - "@wdio/logger": "5.13.2", - "@wdio/utils": "5.15.0", - "deepmerge": "^4.0.0", - "gaze": "^1.1.2", - "webdriverio": "5.15.0" - } - }, - "@wdio/sauce-service": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/@wdio/sauce-service/-/sauce-service-5.14.0.tgz", - "integrity": "sha512-vRboDkWVCYr1I+WqE67wuF4TownoeEBcxSnDNvHuOpBNoMScJ4HQE+pqkULdZTNNOwUG3n/JkL0aQskj7OaIzA==", - "dev": true, - "requires": { - "@wdio/logger": "5.13.2", - "sauce-connect-launcher": "^1.2.3", - "saucelabs": "^3.0.0" - } - }, - "@wdio/spec-reporter": { - "version": "5.14.5", - "resolved": "https://registry.npmjs.org/@wdio/spec-reporter/-/spec-reporter-5.14.5.tgz", - "integrity": "sha512-uMuE9+MfEmluYO+9gVbKCUXvLbHFmXBgDI/SJvTp/0VRbxFZRUcmqsq2DS4MY1PVXzz0K2tBV4dIv1/dBU2OuA==", - "dev": true, - "requires": { - "@wdio/reporter": "5.14.5", - "chalk": "^2.3.2", - "pretty-ms": "^5.0.0", - "table": "^5.4.2" - } - }, - "@wdio/static-server-service": { - "version": "5.14.4", - "resolved": "https://registry.npmjs.org/@wdio/static-server-service/-/static-server-service-5.14.4.tgz", - "integrity": "sha512-I1AWbXgauLZQ58qKvnLxcjM6yBxBdLj3OLQSquuq84PjWRIk5zqJyyftQ7ZZy2C8x2962Ya6UViYit+QEHxx/Q==", - "dev": true, - "requires": { - "@wdio/logger": "5.13.2", - "express": "^4.14.0", - "fs-extra": "^0.30.0", - "morgan": "^1.7.0" - }, - "dependencies": { - "fs-extra": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", - "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0", - "path-is-absolute": "^1.0.0", - "rimraf": "^2.2.8" - } - }, - "jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - } - } - }, - "@wdio/sync": { - "version": "5.14.4", - "resolved": "https://registry.npmjs.org/@wdio/sync/-/sync-5.14.4.tgz", - "integrity": "sha512-kDV+qI1CupIaIeKXJ66PH9rJMVdqoJ18SJkVbKAHTtAjjl2Dc40vhhpiO3KAR/Un5lbpupj1Sc11Cqc4wP2oWA==", - "dev": true, - "requires": { - "@wdio/logger": "5.13.2", - "fibers": "^4.0.1", - "fibers_node_v8": "^3.1.2" - } - }, - "@wdio/utils": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-5.15.0.tgz", - "integrity": "sha512-YNnKThnaykOu715Am+Xpqq5rBSIuobMqlE2r1rYUuhLqt8GAmiWFYjoue5uX8vXER4yGaIOtBD9fQNSb1b5pPQ==", - "dev": true, - "requires": { - "@wdio/logger": "5.13.2", - "deepmerge": "^4.0.0" - } - }, - "JSON": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/JSON/-/JSON-1.0.0.tgz", - "integrity": "sha1-hoFTHCj4Q4oHVYn/BySCRuqWDYw=", - "dev": true - }, - "JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "dev": true, - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - } - }, - "abab": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.2.tgz", - "integrity": "sha512-2scffjvioEmNz0OyDSLGWDfKCVwaKc6l9Pm9kOIREU13ClXZvHpg/nRL5xyjSSSLhOnXqft2HpsAzNEEA8cFFg==", - "dev": true - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "dev": true, - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - } - }, - "acorn": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.4.tgz", - "integrity": "sha512-VY4i5EKSKkofY2I+6QLTbTTN/UvEQPCo6eiwzzSaSWfpaDhOmStMCMod6wmuPciNq+XS0faCglFu2lHZpdHUtg==", - "dev": true - }, - "acorn-dynamic-import": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", - "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==", - "dev": true - }, - "acorn-globals": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", - "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", - "dev": true, - "requires": { - "acorn": "^6.0.1", - "acorn-walk": "^6.0.1" - } - }, - "acorn-node": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.6.2.tgz", - "integrity": "sha512-rIhNEZuNI8ibQcL7ANm/mGyPukIaZsRNX9psFNQURyJW0nu6k8wjSDld20z6v2mDBWqX13pIEnk9gGZJHIlEXg==", - "dev": true, - "requires": { - "acorn": "^6.0.2", - "acorn-dynamic-import": "^4.0.0", - "acorn-walk": "^6.1.0", - "xtend": "^4.0.1" - } - }, - "acorn-walk": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", - "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==", - "dev": true - }, - "adm-zip": { - "version": "0.4.13", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.13.tgz", - "integrity": "sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw==", - "dev": true - }, - "agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "dev": true, - "requires": { - "es6-promisify": "^5.0.0" - } - }, - "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-align": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", - "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", - "dev": true, - "requires": { - "string-width": "^2.0.0" - } - }, - "ansi-escapes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", - "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "archiver": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-3.1.1.tgz", - "integrity": "sha512-5Hxxcig7gw5Jod/8Gq0OneVgLYET+oNHcxgWItq4TbhOzRLKNAFUb9edAftiMKXvXfCB0vbGrJdZDNq0dWMsxg==", - "dev": true, - "requires": { - "archiver-utils": "^2.1.0", - "async": "^2.6.3", - "buffer-crc32": "^0.2.1", - "glob": "^7.1.4", - "readable-stream": "^3.4.0", - "tar-stream": "^2.1.0", - "zip-stream": "^2.1.2" - }, - "dependencies": { - "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } - }, - "bl": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-3.0.0.tgz", - "integrity": "sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==", - "dev": true, - "requires": { - "readable-stream": "^3.0.1" - } - }, - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "tar-stream": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.0.tgz", - "integrity": "sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==", - "dev": true, - "requires": { - "bl": "^3.0.0", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - } - } - } - }, - "archiver-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", - "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", - "dev": true, - "requires": { - "glob": "^7.1.4", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^2.0.0" - }, - "dependencies": { - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", - "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - } - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", - "dev": true - }, - "array-filter": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", - "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", - "dev": true - }, - "array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", - "dev": true - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", - "dev": true - }, - "array-map": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", - "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", - "dev": true - }, - "array-reduce": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", - "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", - "dev": true - }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "requires": { - "array-uniq": "^1.0.1" - } - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "assert": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", - "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", - "dev": true, - "requires": { - "util": "0.10.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", - "dev": true - }, - "util": { - "version": "0.10.3", - "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "dev": true, - "requires": { - "inherits": "2.0.1" - } - } - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true - }, - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true - }, - "async-exit-hook": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", - "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", - "dev": true - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, - "aws-sdk": { - "version": "2.544.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.544.0.tgz", - "integrity": "sha512-wwiBJgAUGKXY/xoCSrUXVZnNtefoH3YcPwGxQrQXOIDnLMQ32yh/SWc52qmwdxA7WJzpTcIj8y+5keH3P1LYaw==", - "dev": true, - "requires": { - "buffer": "4.9.1", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.3.2", - "xml2js": "0.4.19" - }, - "dependencies": { - "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", - "dev": true, - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", - "dev": true - }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", - "dev": true - }, - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true - }, - "url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", - "dev": true, - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "dev": true - } - } - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", - "dev": true - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "babel-jest": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz", - "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==", - "dev": true, - "requires": { - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/babel__core": "^7.1.0", - "babel-plugin-istanbul": "^5.1.0", - "babel-preset-jest": "^24.9.0", - "chalk": "^2.4.2", - "slash": "^2.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } - } - }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", - "integrity": "sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==", - "dev": true, - "requires": { - "object.assign": "^4.1.0" - } - }, - "babel-plugin-istanbul": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", - "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "find-up": "^3.0.0", - "istanbul-lib-instrument": "^3.3.0", - "test-exclude": "^5.2.3" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } - } - }, - "babel-plugin-jest-hoist": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz", - "integrity": "sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw==", - "dev": true, - "requires": { - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-preset-jest": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", - "integrity": "sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg==", - "dev": true, - "requires": { - "@babel/plugin-syntax-object-rest-spread": "^7.0.0", - "babel-plugin-jest-hoist": "^24.9.0" - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", - "dev": true, - "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - }, - "dependencies": { - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", - "dev": true - } - } - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", - "dev": true - }, - "basic-auth": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", - "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", - "dev": true, - "requires": { - "safe-buffer": "5.1.2" - } - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true - }, - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "dev": true - }, - "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "dev": true, - "requires": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "boxen": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", - "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", - "dev": true, - "requires": { - "ansi-align": "^2.0.0", - "camelcase": "^4.0.0", - "chalk": "^2.0.1", - "cli-boxes": "^1.0.0", - "string-width": "^2.0.0", - "term-size": "^1.2.0", - "widest-line": "^2.0.0" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - } - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true - }, - "browser-pack": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", - "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", - "dev": true, - "requires": { - "JSONStream": "^1.0.3", - "combine-source-map": "~0.8.0", - "defined": "^1.0.0", - "safe-buffer": "^5.1.1", - "through2": "^2.0.0", - "umd": "^3.0.0" - } - }, - "browser-process-hrtime": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", - "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==", - "dev": true - }, - "browser-resolve": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", - "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", - "dev": true, - "requires": { - "resolve": "1.1.7" - }, - "dependencies": { - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true - } - } - }, - "browserify": { - "version": "16.2.3", - "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.2.3.tgz", - "integrity": "sha512-zQt/Gd1+W+IY+h/xX2NYMW4orQWhqSwyV+xsblycTtpOuB27h1fZhhNQuipJ4t79ohw4P4mMem0jp/ZkISQtjQ==", - "dev": true, - "requires": { - "JSONStream": "^1.0.3", - "assert": "^1.4.0", - "browser-pack": "^6.0.1", - "browser-resolve": "^1.11.0", - "browserify-zlib": "~0.2.0", - "buffer": "^5.0.2", - "cached-path-relative": "^1.0.0", - "concat-stream": "^1.6.0", - "console-browserify": "^1.1.0", - "constants-browserify": "~1.0.0", - "crypto-browserify": "^3.0.0", - "defined": "^1.0.0", - "deps-sort": "^2.0.0", - "domain-browser": "^1.2.0", - "duplexer2": "~0.1.2", - "events": "^2.0.0", - "glob": "^7.1.0", - "has": "^1.0.0", - "htmlescape": "^1.1.0", - "https-browserify": "^1.0.0", - "inherits": "~2.0.1", - "insert-module-globals": "^7.0.0", - "labeled-stream-splicer": "^2.0.0", - "mkdirp": "^0.5.0", - "module-deps": "^6.0.0", - "os-browserify": "~0.3.0", - "parents": "^1.0.1", - "path-browserify": "~0.0.0", - "process": "~0.11.0", - "punycode": "^1.3.2", - "querystring-es3": "~0.2.0", - "read-only-stream": "^2.0.0", - "readable-stream": "^2.0.2", - "resolve": "^1.1.4", - "shasum": "^1.0.0", - "shell-quote": "^1.6.1", - "stream-browserify": "^2.0.0", - "stream-http": "^2.0.0", - "string_decoder": "^1.1.1", - "subarg": "^1.0.0", - "syntax-error": "^1.1.1", - "through2": "^2.0.0", - "timers-browserify": "^1.0.1", - "tty-browserify": "0.0.1", - "url": "~0.11.0", - "util": "~0.10.1", - "vm-browserify": "^1.0.0", - "xtend": "^4.0.0" - }, - "dependencies": { - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, - "browserify-aes": { - "version": "1.2.0", - "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dev": true, - "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "browserify-cache-api": { - "version": "3.0.1", - "resolved": "http://registry.npmjs.org/browserify-cache-api/-/browserify-cache-api-3.0.1.tgz", - "integrity": "sha1-liR+hT8Gj9bg1FzHPwuyzZd47wI=", - "dev": true, - "requires": { - "async": "^1.5.2", - "through2": "^2.0.0", - "xtend": "^4.0.0" - }, - "dependencies": { - "async": { - "version": "1.5.2", - "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - } - } - }, - "browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "dev": true, - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "browserify-incremental": { - "version": "3.1.1", - "resolved": "http://registry.npmjs.org/browserify-incremental/-/browserify-incremental-3.1.1.tgz", - "integrity": "sha1-BxPLdYckemMqnwjPG9FpuHi2Koo=", - "dev": true, - "requires": { - "JSONStream": "^0.10.0", - "browserify-cache-api": "^3.0.0", - "through2": "^2.0.0", - "xtend": "^4.0.0" - }, - "dependencies": { - "JSONStream": { - "version": "0.10.0", - "resolved": "http://registry.npmjs.org/JSONStream/-/JSONStream-0.10.0.tgz", - "integrity": "sha1-dDSdDYlSK3HzDwoD/5vSDKbxKsA=", - "dev": true, - "requires": { - "jsonparse": "0.0.5", - "through": ">=2.2.7 <3" - } - }, - "jsonparse": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-0.0.5.tgz", - "integrity": "sha1-MwVCrT8KZUZlt3jz6y2an6UHrGQ=", - "dev": true - } - } - }, - "browserify-rsa": { - "version": "4.0.1", - "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "randombytes": "^2.0.1" - } - }, - "browserify-sign": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", - "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", - "dev": true, - "requires": { - "bn.js": "^4.1.1", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.2", - "elliptic": "^6.0.0", - "inherits": "^2.0.1", - "parse-asn1": "^5.0.0" - } - }, - "browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "dev": true, - "requires": { - "pako": "~1.0.5" - } - }, - "browserslist": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.7.0.tgz", - "integrity": "sha512-9rGNDtnj+HaahxiVV38Gn8n8Lr8REKsel68v1sPFfIGEK6uSXTY3h9acgiT1dZVtOOUtifo/Dn8daDQ5dUgVsA==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30000989", - "electron-to-chromium": "^1.3.247", - "node-releases": "^1.1.29" - } - }, - "bser": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.0.tgz", - "integrity": "sha512-8zsjWrQkkBoLK6uxASk1nJ2SKv97ltiGDo6A3wA0/yRPz+CwmEyDo0hUrhIuukG2JHpAl3bvFIixw2/3Hi0DOg==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", - "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", - "dev": true, - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", - "dev": true - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, - "builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", - "dev": true - }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", - "dev": true - }, - "cac": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/cac/-/cac-3.0.4.tgz", - "integrity": "sha1-bSTO7Dcu/lybeYgIvH9JtHJCpO8=", - "dev": true, - "requires": { - "camelcase-keys": "^3.0.0", - "chalk": "^1.1.3", - "indent-string": "^3.0.0", - "minimist": "^1.2.0", - "read-pkg-up": "^1.0.1", - "suffix": "^0.1.0", - "text-table": "^0.2.0" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", - "dev": true - }, - "camelcase-keys": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-3.0.0.tgz", - "integrity": "sha1-/AxsNgNj9zd+N5O5oWvM8QcMHKQ=", - "dev": true, - "requires": { - "camelcase": "^3.0.0", - "map-obj": "^1.0.0" - } - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", - "dev": true - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "cached-path-relative": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.2.tgz", - "integrity": "sha512-5r2GqsoEb4qMTTN9J+WzXfjov+hjxT+j3u5K+kIVNIwAd99DLCJE9pBIMP1qVeybV6JiijL385Oz0DcYxfbOIg==", - "dev": true - }, - "callsite": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", - "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", - "dev": true - }, - "callsite-record": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/callsite-record/-/callsite-record-3.2.2.tgz", - "integrity": "sha1-mgOQZC5D/ou4I5ReUUZPafQWQ94=", - "dev": true, - "requires": { - "callsite": "^1.0.0", - "chalk": "^1.1.1", - "error-stack-parser": "^1.3.3", - "highlight-es": "^1.0.0", - "lodash": "4.6.1 || ^4.16.1", - "pinkie-promise": "^2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camel-case": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", - "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", - "dev": true, - "requires": { - "no-case": "^2.2.0", - "upper-case": "^1.1.1" - } - }, - "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", - "dev": true - }, - "camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", - "dev": true, - "requires": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" - } - }, - "caniuse-lite": { - "version": "1.0.30000999", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000999.tgz", - "integrity": "sha512-1CUyKyecPeksKwXZvYw0tEoaMCo/RwBlXmEtN5vVnabvO0KPd9RQLcaAuR9/1F+KDMv6esmOFWlsXuzDk+8rxg==", - "dev": true - }, - "capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", - "dev": true, - "requires": { - "rsvp": "^4.8.4" - } - }, - "capture-stack-trace": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", - "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "change-case": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/change-case/-/change-case-3.1.0.tgz", - "integrity": "sha512-2AZp7uJZbYEzRPsFoa+ijKdvp9zsrnnt6+yFokfwEpeJm0xuJDVoxiRCAaTzyJND8GJkofo2IcKWaUZ/OECVzw==", - "dev": true, - "requires": { - "camel-case": "^3.0.0", - "constant-case": "^2.0.0", - "dot-case": "^2.1.0", - "header-case": "^1.0.0", - "is-lower-case": "^1.1.0", - "is-upper-case": "^1.1.0", - "lower-case": "^1.1.1", - "lower-case-first": "^1.0.0", - "no-case": "^2.3.2", - "param-case": "^2.1.0", - "pascal-case": "^2.0.0", - "path-case": "^2.1.0", - "sentence-case": "^2.1.0", - "snake-case": "^2.1.0", - "swap-case": "^1.1.0", - "title-case": "^2.1.0", - "upper-case": "^1.1.1", - "upper-case-first": "^1.1.0" - } - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" - }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - } - } - }, - "chownr": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", - "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==", - "dev": true - }, - "chromedriver": { - "version": "77.0.0", - "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-77.0.0.tgz", - "integrity": "sha512-mZa1IVx4HD8rDaItWbnS470mmypgiWsDiu98r0NkiT4uLm3qrANl4vOU6no6vtWtLQiW5kt1POcIbjeNpsLbXA==", - "dev": true, - "requires": { - "del": "^4.1.1", - "extract-zip": "^1.6.7", - "mkdirp": "^0.5.1", - "request": "^2.88.0", - "tcp-port-used": "^1.0.1" - } - }, - "ci-info": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", - "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", - "dev": true - }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "cli-boxes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", - "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", - "dev": true - }, - "cli-cursor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", - "dev": true, - "requires": { - "restore-cursor": "^1.0.1" - } - }, - "cli-spinners": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-0.1.2.tgz", - "integrity": "sha1-u3ZNiOGF+54eaiofGXcjGPYF4xw=", - "dev": true - }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true - }, - "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" - }, - "dependencies": { - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "coffeescript": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.10.0.tgz", - "integrity": "sha1-56qDAZF+9iGzXYo580jc3R234z4=", - "dev": true - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "colors": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", - "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", - "dev": true - }, - "combine-source-map": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", - "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=", - "dev": true, - "requires": { - "convert-source-map": "~1.1.0", - "inline-source-map": "~0.6.0", - "lodash.memoize": "~3.0.3", - "source-map": "~0.5.3" - }, - "dependencies": { - "convert-source-map": { - "version": "1.1.3", - "resolved": "http://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", - "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=", - "dev": true - } - } - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", - "dev": true - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "compress-commons": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-2.1.1.tgz", - "integrity": "sha512-eVw6n7CnEMFzc3duyFVrQEuY1BlHR3rYsSztyG32ibGMW722i3C6IizEGMFmfMU+A+fALvBIwxN3czffTcdA+Q==", - "dev": true, - "requires": { - "buffer-crc32": "^0.2.13", - "crc32-stream": "^3.0.1", - "normalize-path": "^3.0.0", - "readable-stream": "^2.3.6" - }, - "dependencies": { - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - } - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "configstore": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", - "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", - "dev": true, - "requires": { - "dot-prop": "^4.1.0", - "graceful-fs": "^4.1.2", - "make-dir": "^1.0.0", - "unique-string": "^1.0.0", - "write-file-atomic": "^2.0.0", - "xdg-basedir": "^3.0.0" - } - }, - "console-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", - "dev": true, - "requires": { - "date-now": "^0.1.4" - } - }, - "constant-case": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-2.0.0.tgz", - "integrity": "sha1-QXV2TTidP6nI7NKRhu1gBSQ7akY=", - "dev": true, - "requires": { - "snake-case": "^2.1.0", - "upper-case": "^1.1.1" - } - }, - "constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", - "dev": true - }, - "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", - "dev": true, - "requires": { - "safe-buffer": "5.1.2" - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "dev": true - }, - "convert-source-map": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", - "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", - "dev": true - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", - "dev": true - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "core-js": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz", - "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==", - "dev": true - }, - "core-js-compat": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.2.1.tgz", - "integrity": "sha512-MwPZle5CF9dEaMYdDeWm73ao/IflDH+FjeJCWEADcEgFSE9TLimFKwJsfmkwzI8eC0Aj0mgvMDjeQjrElkz4/A==", - "dev": true, - "requires": { - "browserslist": "^4.6.6", - "semver": "^6.3.0" - } - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "crc": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", - "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", - "dev": true, - "requires": { - "buffer": "^5.1.0" - } - }, - "crc32-stream": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-3.0.1.tgz", - "integrity": "sha512-mctvpXlbzsvK+6z8kJwSJ5crm7yBwrQMTybJzMw1O4lLGJqjlDCXY2Zw7KheiA6XBEcBmfLx1D88mjRGVJtY9w==", - "dev": true, - "requires": { - "crc": "^3.4.4", - "readable-stream": "^3.4.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "create-ecdh": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", - "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.0.0" - } - }, - "create-error-class": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", - "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", - "dev": true, - "requires": { - "capture-stack-trace": "^1.0.0" - } - }, - "create-hash": { - "version": "1.2.0", - "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.7", - "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dev": true, - "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "cross-spawn-async": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz", - "integrity": "sha1-hF/wwINKPe2dFg2sptOQkGuyiMw=", - "dev": true, - "requires": { - "lru-cache": "^4.0.0", - "which": "^1.2.8" - } - }, - "crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" - }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "dev": true, - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - } - }, - "crypto-random-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", - "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", - "dev": true - }, - "css-value": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/css-value/-/css-value-0.0.1.tgz", - "integrity": "sha1-Xv1sLupeof1rasV+wEJ7GEUkJOo=", - "dev": true - }, - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "cssstyle": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", - "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", - "dev": true, - "requires": { - "cssom": "0.3.x" - } - }, - "currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", - "dev": true, - "requires": { - "array-find-index": "^1.0.1" - } - }, - "cwd": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/cwd/-/cwd-0.10.0.tgz", - "integrity": "sha1-FyQAaUBXwioTsM8WFix+S3p/5Wc=", - "dev": true, - "requires": { - "find-pkg": "^0.1.2", - "fs-exists-sync": "^0.1.0" - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "data-urls": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", - "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", - "dev": true, - "requires": { - "abab": "^2.0.0", - "whatwg-mimetype": "^2.2.0", - "whatwg-url": "^7.0.0" - }, - "dependencies": { - "whatwg-url": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", - "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - } - } - }, - "date-now": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", - "dev": true - }, - "dateformat": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", - "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", - "dev": true, - "requires": { - "get-stdin": "^4.0.1", - "meow": "^3.3.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "deepmerge": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.1.1.tgz", - "integrity": "sha512-+qO5WbNBKBaZez95TffdUDnGIo4+r5kmsX8aOb7PDHvXsTbghAmleuxjs6ytNaf5Eg4FGBXDS5vqO61TRi6BMg==", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", - "dev": true - }, - "del": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", - "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", - "dev": true, - "requires": { - "@types/glob": "^7.1.1", - "globby": "^6.1.0", - "is-path-cwd": "^2.0.0", - "is-path-in-cwd": "^2.0.0", - "p-map": "^2.0.0", - "pify": "^4.0.1", - "rimraf": "^2.6.3" - }, - "dependencies": { - "globby": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - } - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "depcheck": { - "version": "0.6.11", - "resolved": "https://registry.npmjs.org/depcheck/-/depcheck-0.6.11.tgz", - "integrity": "sha512-wTVJ8cNilB8NfkzoBblcYqsB8LRfbjqKEwAOLD3YXIRigktSM7/lS9xQfVkAVujhjstmiQMZR0hkdHSnQxzb9A==", - "dev": true, - "requires": { - "babel-traverse": "^6.7.3", - "babylon": "^6.1.21", - "builtin-modules": "^1.1.1", - "deprecate": "^1.0.0", - "deps-regex": "^0.1.4", - "js-yaml": "^3.4.2", - "lodash": "^4.5.1", - "minimatch": "^3.0.2", - "require-package-name": "^2.0.1", - "walkdir": "0.0.11", - "yargs": "^8.0.2" - } - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true - }, - "deprecate": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deprecate/-/deprecate-1.1.1.tgz", - "integrity": "sha512-ZGDXefq1xknT292LnorMY5s8UVU08/WKdzDZCUT6t9JzsiMSP4uzUhgpqugffNVcT5WC6wMBiSQ+LFjlv3v7iQ==", - "dev": true - }, - "deps-regex": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deps-regex/-/deps-regex-0.1.4.tgz", - "integrity": "sha1-UYZnt2kUYKXn4KNBvnbrfOgJAYQ=", - "dev": true - }, - "deps-sort": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.0.tgz", - "integrity": "sha1-CRckkC6EZYJg65EHSMzNGvbiH7U=", - "dev": true, - "requires": { - "JSONStream": "^1.0.3", - "shasum": "^1.0.0", - "subarg": "^1.0.0", - "through2": "^2.0.0" - } - }, - "des.js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", - "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true - }, - "detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", - "dev": true, - "optional": true - }, - "detect-newline": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", - "dev": true - }, - "detective": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.1.0.tgz", - "integrity": "sha512-TFHMqfOvxlgrfVzTEkNBSh9SvSNX/HfF4OFI2QFGCyPm02EsyILqnUeb5P6q7JZ3SFNTBL5t2sePRgrN4epUWQ==", - "dev": true, - "requires": { - "acorn-node": "^1.3.0", - "defined": "^1.0.0", - "minimist": "^1.1.1" - } - }, - "diff-sequences": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", - "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", - "dev": true - }, - "diffie-hellman": { - "version": "5.0.3", - "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "docker-modem": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-2.0.2.tgz", - "integrity": "sha512-Aq6NBJQm5najFlg4wRZtSrWXzQbQClh1kccAkUWIdVhuyHK6tYhmi9W9xtVaGmzBa0Nfuwi4AEbQzWtHZT+2Jw==", - "dev": true, - "requires": { - "JSONStream": "1.3.2", - "debug": "^3.2.6", - "readable-stream": "~1.0.26-4", - "split-ca": "^1.0.0", - "ssh2": "^0.8.5" - }, - "dependencies": { - "JSONStream": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.2.tgz", - "integrity": "sha1-wQI3G27Dp887hHygDCC7D85Mbeo=", - "dev": true, - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - } - }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } - } - }, - "dockerode": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/dockerode/-/dockerode-3.0.2.tgz", - "integrity": "sha512-jql7zwTQH2psjyevyeWOpe9XJ8x1WbXX/TwKHcWlJsq1jivxN2+1nVqT72HKE9xxNR/MGcuWcPxrCBHNu9GZpw==", - "dev": true, - "requires": { - "concat-stream": "~2.0.0", - "docker-modem": "^2.0.0", - "tar-fs": "~2.0.0" - }, - "dependencies": { - "concat-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.0.2", - "typedarray": "^0.0.6" - } - }, - "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", - "dev": true - }, - "domexception": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", - "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", - "dev": true, - "requires": { - "webidl-conversions": "^4.0.2" - } - }, - "dot-case": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-2.1.1.tgz", - "integrity": "sha1-NNzzf1Co6TwrO8qLt/uRVcfaO+4=", - "dev": true, - "requires": { - "no-case": "^2.2.0" - } - }, - "dot-prop": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", - "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", - "dev": true, - "requires": { - "is-obj": "^1.0.0" - } - }, - "duplexer": { - "version": "0.1.1", - "resolved": "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", - "dev": true - }, - "duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", - "dev": true, - "requires": { - "readable-stream": "^2.0.2" - } - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", - "dev": true - }, - "ejs": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.1.tgz", - "integrity": "sha512-kS/gEPzZs3Y1rRsbGX4UOSjtP/CeJP0CxSNZHYxGfVM/VgLcv0ZqM7C45YyTj2DI2g7+P9Dd24C+IMIg6D0nYQ==", - "dev": true - }, - "electron-to-chromium": { - "version": "1.3.277", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.277.tgz", - "integrity": "sha512-Czmsrgng89DOgJlIknnw9bn5431QdtnUwGp5YYiPwU1DbZQUxCLF+rc1ZC09VNAdalOPcvH6AE8BaA0H5HjI/w==", - "dev": true - }, - "elliptic": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", - "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", - "dev": true, - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - } - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "error-stack-parser": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-1.3.6.tgz", - "integrity": "sha1-4Oc7k+QXE40c18C3RrGkoUhUwpI=", - "dev": true, - "requires": { - "stackframe": "^0.3.1" - } - }, - "es-abstract": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.15.0.tgz", - "integrity": "sha512-bhkEqWJ2t2lMeaJDuk7okMkJWI/yqgH/EoGwpcvv0XW9RWQsRspI4wt6xuyuvMvvQE3gg/D9HXppgk21w78GyQ==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.0", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.0", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-inspect": "^1.6.0", - "object-keys": "^1.1.1", - "string.prototype.trimleft": "^2.1.0", - "string.prototype.trimright": "^2.1.0" - } - }, - "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "dev": true - }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", - "dev": true, - "requires": { - "es6-promise": "^4.0.3" - } - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "escodegen": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz", - "integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==", - "dev": true, - "requires": { - "esprima": "^3.1.3", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "esprima": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true - } - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "dev": true - }, - "eventemitter2": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", - "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", - "dev": true - }, - "events": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz", - "integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg==", - "dev": true - }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "dev": true, - "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "exec-sh": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.2.tgz", - "integrity": "sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg==", - "dev": true - }, - "execa": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.2.2.tgz", - "integrity": "sha1-4urUcsLDGq1vc/GslW7vReEjIMs=", - "dev": true, - "requires": { - "cross-spawn-async": "^2.1.1", - "npm-run-path": "^1.0.0", - "object-assign": "^4.0.1", - "path-key": "^1.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "npm-run-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-1.0.0.tgz", - "integrity": "sha1-9cMr9ZX+ga6Sfa7FLoL4sACsPI8=", - "dev": true, - "requires": { - "path-key": "^1.0.0" - } - }, - "path-key": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-1.0.0.tgz", - "integrity": "sha1-XVPVeAGWRsDWiADbThRua9wqx68=", - "dev": true - } - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "exit-hook": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", - "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", - "dev": true - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "expect": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", - "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "ansi-styles": "^3.2.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-regex-util": "^24.9.0" - } - }, - "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "dev": true, - "requires": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", - "content-type": "~1.0.4", - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "extract-zip": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz", - "integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=", - "dev": true, - "requires": { - "concat-stream": "1.6.2", - "debug": "2.6.9", - "mkdirp": "0.5.1", - "yauzl": "2.4.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "fd-slicer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", - "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", - "dev": true, - "requires": { - "pend": "~1.2.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "yauzl": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", - "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", - "dev": true, - "requires": { - "fd-slicer": "~1.0.1" - } - } - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fb-watchman": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", - "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", - "dev": true, - "requires": { - "bser": "^2.0.0" - } - }, - "fibers": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/fibers/-/fibers-4.0.1.tgz", - "integrity": "sha512-H79EJn7DMWXk48ygmC82bMP8KNcFBZF1CPfwBpYF6cO85hGWoIrlu7eyX9ayxfjP9Nsl0JXxdI6fpYU4DWVw2w==", - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.3" - } - }, - "fibers_node_v8": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/fibers_node_v8/-/fibers_node_v8-3.1.5.tgz", - "integrity": "sha512-jcut+gL68TclewWH/9si73yDhFOzu8LhmWg6SZRBw13rk4+7DCtqOMdsBhAyXaWRjI7c1XqcRp4AgebLJnvfCQ==", - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.3" - } - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dev": true, - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "find-file-up": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/find-file-up/-/find-file-up-0.1.3.tgz", - "integrity": "sha1-z2gJG8+fMApA2kEbN9pczlovvqA=", - "dev": true, - "requires": { - "fs-exists-sync": "^0.1.0", - "resolve-dir": "^0.1.0" - }, - "dependencies": { - "expand-tilde": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz", - "integrity": "sha1-C4HrqJflo9MdHD0QL48BRB5VlEk=", - "dev": true, - "requires": { - "os-homedir": "^1.0.1" - } - }, - "global-modules": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz", - "integrity": "sha1-6lo77ULG1s6ZWk+KEmm12uIjgo0=", - "dev": true, - "requires": { - "global-prefix": "^0.1.4", - "is-windows": "^0.2.0" - } - }, - "global-prefix": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz", - "integrity": "sha1-jTvGuNo8qBEqFg2NSW/wRiv+948=", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.0", - "ini": "^1.3.4", - "is-windows": "^0.2.0", - "which": "^1.2.12" - } - }, - "is-windows": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz", - "integrity": "sha1-3hqm1j6indJIc3tp8f+LgALSEIw=", - "dev": true - }, - "resolve-dir": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz", - "integrity": "sha1-shklmlYC+sXFxJatiUpujMQwJh4=", - "dev": true, - "requires": { - "expand-tilde": "^1.2.2", - "global-modules": "^0.2.3" - } - } - } - }, - "find-pkg": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/find-pkg/-/find-pkg-0.1.2.tgz", - "integrity": "sha1-G9wiwG42NlUy4qJIBGhUuXiNpVc=", - "dev": true, - "requires": { - "find-file-up": "^0.1.2" - } - }, - "find-process": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/find-process/-/find-process-1.4.2.tgz", - "integrity": "sha512-O83EVJr4dWvHJ7QpUzANNAMeQVKukRzRqRx4AIzdLYRrQorRdbqDwLPigkd9PYPhJRhmNPAoVjOm9bcwSmcZaw==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "commander": "^2.11.0", - "debug": "^2.6.8" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "findup-sync": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", - "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=", - "dev": true, - "requires": { - "glob": "~5.0.0" - }, - "dependencies": { - "glob": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", - "dev": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "dev": true - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true - }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "fs-exists-sync": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", - "integrity": "sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=", - "dev": true - }, - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", - "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", - "dev": true - } - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", - "dev": true, - "optional": true, - "requires": { - "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "debug": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true, - "optional": true - }, - "minipass": { - "version": "2.3.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.3.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^4.1.0", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.6.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "yallist": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "gaze": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", - "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", - "dev": true, - "requires": { - "globule": "^1.0.0" - } - }, - "get-assigned-identifiers": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", - "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==", - "dev": true - }, - "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true - }, - "get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, - "getobject": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", - "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=", - "dev": true - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "giturl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/giturl/-/giturl-1.0.1.tgz", - "integrity": "sha512-wQourBdI13n8tbjcZTDl6k+ZrCRMU6p9vfp9jknZq+zfWc8xXNztpZFM4XkPHVzHcMSUZxEMYYKZjIGkPlei6Q==", - "dev": true - }, - "glob": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", - "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.2", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", - "dev": true, - "requires": { - "ini": "^1.3.4" - } - }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, - "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - } - }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "dev": true, - "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "globby": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-4.1.0.tgz", - "integrity": "sha1-CA9UVJ7BuCpsYOYx/ILhIR2+lfg=", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^6.0.1", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "dependencies": { - "glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", - "dev": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "globule": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", - "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", - "dev": true, - "requires": { - "glob": "~7.1.1", - "lodash": "~4.17.10", - "minimatch": "~3.0.2" - }, - "dependencies": { - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "got": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", - "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", - "dev": true, - "requires": { - "create-error-class": "^3.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-redirect": "^1.0.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "unzip-response": "^2.0.1", - "url-parse-lax": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", - "dev": true - }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true - }, - "grunt": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.0.4.tgz", - "integrity": "sha512-PYsMOrOC+MsdGEkFVwMaMyc6Ob7pKmq+deg1Sjr+vvMWp35sztfwKE7qoN51V+UEtHsyNuMcGdgMLFkBHvMxHQ==", - "dev": true, - "requires": { - "coffeescript": "~1.10.0", - "dateformat": "~1.0.12", - "eventemitter2": "~0.4.13", - "exit": "~0.1.1", - "findup-sync": "~0.3.0", - "glob": "~7.0.0", - "grunt-cli": "~1.2.0", - "grunt-known-options": "~1.1.0", - "grunt-legacy-log": "~2.0.0", - "grunt-legacy-util": "~1.1.1", - "iconv-lite": "~0.4.13", - "js-yaml": "~3.13.0", - "minimatch": "~3.0.2", - "mkdirp": "~0.5.1", - "nopt": "~3.0.6", - "path-is-absolute": "~1.0.0", - "rimraf": "~2.6.2" - }, - "dependencies": { - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "grunt-cli": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz", - "integrity": "sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg=", - "dev": true, - "requires": { - "findup-sync": "~0.3.0", - "grunt-known-options": "~1.1.0", - "nopt": "~3.0.6", - "resolve": "~1.1.0" - } - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true - } - } - }, - "grunt-aws": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/grunt-aws/-/grunt-aws-0.7.1.tgz", - "integrity": "sha512-IQ/sGebsSeqpIiAjz4MqchWrJyZ6rwemrLf3OJ6GWSmDchkanXlQqHRPX0Uqud55qZRJ2xzD+e+dg4Ll+LB9jg==", - "dev": true, - "requires": { - "async": "~0.2.9", - "aws-sdk": "^2.1.50", - "lodash": "^4.17.11", - "mime": "^1.6.0" - }, - "dependencies": { - "async": { - "version": "0.2.10", - "resolved": "http://registry.npmjs.org/async/-/async-0.2.10.tgz", - "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", - "dev": true - } - } - }, - "grunt-babel": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/grunt-babel/-/grunt-babel-8.0.0.tgz", - "integrity": "sha512-WuiZFvGzcyzlEoPIcY1snI234ydDWeWWV5bpnB7PZsOLHcDsxWKnrR1rMWEUsbdVPPjvIirwFNsuo4CbJmsdFQ==", - "dev": true - }, - "grunt-browserify": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/grunt-browserify/-/grunt-browserify-5.3.0.tgz", - "integrity": "sha1-R/2M+LrFj+LeaDr9xX9/OoDKeS0=", - "dev": true, - "requires": { - "async": "^2.5.0", - "browserify": "^16.0.0", - "browserify-incremental": "^3.1.1", - "glob": "^7.1.2", - "lodash": "^4.17.4", - "resolve": "^1.1.6", - "watchify": "^3.6.1" - }, - "dependencies": { - "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", - "dev": true, - "requires": { - "lodash": "^4.17.10" - } - }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, - "grunt-contrib-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-1.0.1.tgz", - "integrity": "sha1-YVCYYwhOhx1+ht5IwBUlntl3Rb0=", - "dev": true, - "requires": { - "chalk": "^1.0.0", - "source-map": "^0.5.3" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "grunt-contrib-uglify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-4.0.1.tgz", - "integrity": "sha512-dwf8/+4uW1+7pH72WButOEnzErPGmtUvc8p08B0eQS/6ON0WdeQu0+WFeafaPTbbY1GqtS25lsHWaDeiTQNWPg==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "maxmin": "^2.1.0", - "uglify-js": "^3.5.0", - "uri-path": "^1.0.0" - } - }, - "grunt-known-options": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.1.tgz", - "integrity": "sha512-cHwsLqoighpu7TuYj5RonnEuxGVFnztcUqTqp5rXFGYL4OuPFofwC4Ycg7n9fYwvK6F5WbYgeVOwph9Crs2fsQ==", - "dev": true - }, - "grunt-legacy-log": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-2.0.0.tgz", - "integrity": "sha512-1m3+5QvDYfR1ltr8hjiaiNjddxGdQWcH0rw1iKKiQnF0+xtgTazirSTGu68RchPyh1OBng1bBUjLmX8q9NpoCw==", - "dev": true, - "requires": { - "colors": "~1.1.2", - "grunt-legacy-log-utils": "~2.0.0", - "hooker": "~0.2.3", - "lodash": "~4.17.5" - } - }, - "grunt-legacy-log-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.0.1.tgz", - "integrity": "sha512-o7uHyO/J+i2tXG8r2bZNlVk20vlIFJ9IEYyHMCQGfWYru8Jv3wTqKZzvV30YW9rWEjq0eP3cflQ1qWojIe9VFA==", - "dev": true, - "requires": { - "chalk": "~2.4.1", - "lodash": "~4.17.10" - } - }, - "grunt-legacy-util": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-1.1.1.tgz", - "integrity": "sha512-9zyA29w/fBe6BIfjGENndwoe1Uy31BIXxTH3s8mga0Z5Bz2Sp4UCjkeyv2tI449ymkx3x26B+46FV4fXEddl5A==", - "dev": true, - "requires": { - "async": "~1.5.2", - "exit": "~0.1.1", - "getobject": "~0.1.0", - "hooker": "~0.2.3", - "lodash": "~4.17.10", - "underscore.string": "~3.3.4", - "which": "~1.3.0" - } - }, - "gzip-size": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-3.0.0.tgz", - "integrity": "sha1-VGGI6b3DN/Zzdy+BZgRks4nc5SA=", - "dev": true, - "requires": { - "duplexer": "^0.1.1" - } - }, - "handlebars": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.4.2.tgz", - "integrity": "sha512-cIv17+GhL8pHHnRJzGu2wwcthL5sb8uDKBHvZ2Dtu5s1YNt0ljbzKbamnc+gr69y7bzwQiBdr5+hOpRd5pnOdg==", - "dev": true, - "requires": { - "neo-async": "^2.6.0", - "optimist": "^0.6.1", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "dev": true, - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", - "dev": true - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hash-base": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", - "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "hash.js": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.5.tgz", - "integrity": "sha512-eWI5HG9Np+eHV1KQhisXWwM+4EPPYe5dFX1UZZH7k/E3JzDEazVH+VGlZi6R94ZqImq+A3D1mCEtrFIfg/E7sA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "header-case": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz", - "integrity": "sha1-lTWXMZfBRLCWE81l0xfvGZY70C0=", - "dev": true, - "requires": { - "no-case": "^2.2.0", - "upper-case": "^1.1.3" - } - }, - "highlight-es": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/highlight-es/-/highlight-es-1.0.3.tgz", - "integrity": "sha512-s/SIX6yp/5S1p8aC/NRDC1fwEb+myGIfp8/TzZz0rtAv8fzsdX7vGl3Q1TrXCsczFq8DI3CBFBCySPClfBSdbg==", - "dev": true, - "requires": { - "chalk": "^2.4.0", - "is-es2016-keyword": "^1.0.0", - "js-tokens": "^3.0.0" - }, - "dependencies": { - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true - } - } - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "dev": true, - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "requires": { - "parse-passwd": "^1.0.0" - } - }, - "hooker": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", - "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", - "dev": true - }, - "hosted-git-info": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", - "dev": true - }, - "html-encoding-sniffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", - "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", - "dev": true, - "requires": { - "whatwg-encoding": "^1.0.1" - } - }, - "htmlescape": { - "version": "1.1.1", - "resolved": "http://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", - "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=", - "dev": true - }, - "http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "dependencies": { - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - } - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", - "dev": true - }, - "https-proxy-agent": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz", - "integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==", - "dev": true, - "requires": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ieee754": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", - "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==", - "dev": true - }, - "import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", - "dev": true - }, - "import-local": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", - "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", - "dev": true, - "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - } - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "dev": true, - "requires": { - "repeating": "^2.0.0" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true - }, - "inline-source-map": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", - "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=", - "dev": true, - "requires": { - "source-map": "~0.5.3" - } - }, - "inquirer": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", - "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", - "dev": true, - "requires": { - "ansi-escapes": "^1.1.0", - "ansi-regex": "^2.0.0", - "chalk": "^1.0.0", - "cli-cursor": "^1.0.1", - "cli-width": "^2.0.0", - "figures": "^1.3.5", - "lodash": "^4.3.0", - "readline2": "^1.0.1", - "run-async": "^0.1.0", - "rx-lite": "^3.1.2", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "insert-module-globals": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.0.tgz", - "integrity": "sha512-VE6NlW+WGn2/AeOMd496AHFYmE7eLKkUY6Ty31k4og5vmA3Fjuwe9v6ifH6Xx/Hz27QvdoMoviw1/pqWRB09Sw==", - "dev": true, - "requires": { - "JSONStream": "^1.0.3", - "acorn-node": "^1.5.2", - "combine-source-map": "^0.8.0", - "concat-stream": "^1.6.1", - "is-buffer": "^1.1.0", - "path-is-absolute": "^1.0.1", - "process": "~0.11.0", - "through2": "^2.0.0", - "undeclared-identifiers": "^1.1.2", - "xtend": "^4.0.0" - } - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, - "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", - "dev": true - }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true - }, - "ipaddr.js": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", - "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==", - "dev": true - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, - "requires": { - "builtin-modules": "^1.0.0" - } - }, - "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true - }, - "is-ci": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", - "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", - "dev": true, - "requires": { - "ci-info": "^1.5.0" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "is-es2016-keyword": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-es2016-keyword/-/is-es2016-keyword-1.0.0.tgz", - "integrity": "sha1-9uVOEQxeT40mXmnS7Q6vjPX0dxg=", - "dev": true - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-installed-globally": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", - "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", - "dev": true, - "requires": { - "global-dirs": "^0.1.0", - "is-path-inside": "^1.0.0" - } - }, - "is-lower-case": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-1.1.3.tgz", - "integrity": "sha1-fhR75HaNxGbbO/shzGCzHmrWk5M=", - "dev": true, - "requires": { - "lower-case": "^1.1.0" - } - }, - "is-npm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", - "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true - }, - "is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true - }, - "is-path-in-cwd": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", - "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", - "dev": true, - "requires": { - "is-path-inside": "^2.1.0" - }, - "dependencies": { - "is-path-inside": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", - "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", - "dev": true, - "requires": { - "path-is-inside": "^1.0.2" - } - } - } - }, - "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "dev": true, - "requires": { - "path-is-inside": "^1.0.1" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true - }, - "is-redirect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", - "dev": true - }, - "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "dev": true, - "requires": { - "has": "^1.0.1" - } - }, - "is-retry-allowed": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", - "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "dev": true, - "requires": { - "has-symbols": "^1.0.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-upper-case": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz", - "integrity": "sha1-jQsfp+eTOh5YSDYA7H2WYcuvdW8=", - "dev": true, - "requires": { - "upper-case": "^1.1.0" - } - }, - "is-url": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", - "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", - "dev": true - }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true - }, - "is2": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is2/-/is2-2.0.1.tgz", - "integrity": "sha512-+WaJvnaA7aJySz2q/8sLjMb2Mw14KTplHmSwcSpZ/fWJPkUmqw3YTzSWbPJ7OAwRvdYTWF2Wg+yYJ1AdP5Z8CA==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "ip-regex": "^2.1.0", - "is-url": "^1.2.2" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", - "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", - "dev": true, - "requires": { - "@babel/generator": "^7.4.0", - "@babel/parser": "^7.4.3", - "@babel/template": "^7.4.0", - "@babel/traverse": "^7.4.3", - "@babel/types": "^7.4.0", - "istanbul-lib-coverage": "^2.0.5", - "semver": "^6.0.0" - } - }, - "istanbul-lib-report": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", - "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "supports-color": "^6.1.0" - }, - "dependencies": { - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", - "source-map": "^0.6.1" - }, - "dependencies": { - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "istanbul-reports": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", - "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", - "dev": true, - "requires": { - "handlebars": "^4.1.2" - } - }, - "jasmine": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.5.0.tgz", - "integrity": "sha512-DYypSryORqzsGoMazemIHUfMkXM7I7easFaxAvNM3Mr6Xz3Fy36TupTrAOxZWN8MVKEU5xECv22J4tUQf3uBzQ==", - "dev": true, - "requires": { - "glob": "^7.1.4", - "jasmine-core": "~3.5.0" - }, - "dependencies": { - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "jasmine-core": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.5.0.tgz", - "integrity": "sha512-nCeAiw37MIMA9w9IXso7bRaLl+c/ef3wnxsoSAlYrzS+Ot0zTG6nU8G/cIfGkqpkjX2wNaIW9RFG0TwIFnG6bA==", - "dev": true - }, - "jest": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz", - "integrity": "sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw==", - "dev": true, - "requires": { - "import-local": "^2.0.0", - "jest-cli": "^24.9.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "jest-cli": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.9.0.tgz", - "integrity": "sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg==", - "dev": true, - "requires": { - "@jest/core": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "import-local": "^2.0.0", - "is-ci": "^2.0.0", - "jest-config": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "prompts": "^2.0.1", - "realpath-native": "^1.1.0", - "yargs": "^13.3.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - }, - "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" - } - }, - "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "jest-changed-files": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz", - "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "execa": "^1.0.0", - "throat": "^4.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "throat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", - "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", - "dev": true - } - } - }, - "jest-config": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", - "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^24.9.0", - "@jest/types": "^24.9.0", - "babel-jest": "^24.9.0", - "chalk": "^2.0.1", - "glob": "^7.1.1", - "jest-environment-jsdom": "^24.9.0", - "jest-environment-node": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-jasmine2": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "micromatch": "^3.1.10", - "pretty-format": "^24.9.0", - "realpath-native": "^1.1.0" - }, - "dependencies": { - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "jest-date-mock": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/jest-date-mock/-/jest-date-mock-1.0.7.tgz", - "integrity": "sha512-ZgbYlURRhVpf52Jho4tlyUgpJJ+nYvhxIWhIIEdarmsSuTxFZlC9DmKCyQXsuEljfxK+7HsqdBX/L6rxwWraYw==", - "dev": true - }, - "jest-dev-server": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/jest-dev-server/-/jest-dev-server-4.3.0.tgz", - "integrity": "sha512-bC9flKY2G1honQ/UI0gEhb0wFnDhpFr7xidC8Nk+evi7TgnNtfsGIzzF2dcIhF1G9BGF0n/M7CJrMAzwQhyTPA==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "cwd": "^0.10.0", - "find-process": "^1.4.2", - "prompts": "^2.1.0", - "spawnd": "^4.0.0", - "tree-kill": "^1.2.1", - "wait-on": "^3.3.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } - } - }, - "jest-diff": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", - "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "diff-sequences": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-docblock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz", - "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==", - "dev": true, - "requires": { - "detect-newline": "^2.1.0" - } - }, - "jest-each": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz", - "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "jest-get-type": "^24.9.0", - "jest-util": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-environment-jsdom": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz", - "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==", - "dev": true, - "requires": { - "@jest/environment": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-util": "^24.9.0", - "jsdom": "^11.5.1" - } - }, - "jest-environment-node": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.9.0.tgz", - "integrity": "sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==", - "dev": true, - "requires": { - "@jest/environment": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-util": "^24.9.0" - } - }, - "jest-get-type": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", - "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", - "dev": true - }, - "jest-haste-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", - "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "anymatch": "^2.0.0", - "fb-watchman": "^2.0.0", - "fsevents": "^1.2.7", - "graceful-fs": "^4.1.15", - "invariant": "^2.2.4", - "jest-serializer": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.9.0", - "micromatch": "^3.1.10", - "sane": "^4.0.3", - "walker": "^1.0.7" - } - }, - "jest-jasmine2": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz", - "integrity": "sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw==", - "dev": true, - "requires": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "co": "^4.6.0", - "expect": "^24.9.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "pretty-format": "^24.9.0", - "throat": "^4.0.0" - }, - "dependencies": { - "throat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", - "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", - "dev": true - } - } - }, - "jest-leak-detector": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", - "integrity": "sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==", - "dev": true, - "requires": { - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-matcher-utils": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", - "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" - } - }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0" - } - }, - "jest-pnp-resolver": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz", - "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==", - "dev": true - }, - "jest-regex-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", - "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", - "dev": true - }, - "jest-resolve": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", - "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "browser-resolve": "^1.11.3", - "chalk": "^2.0.1", - "jest-pnp-resolver": "^1.2.1", - "realpath-native": "^1.1.0" - } - }, - "jest-resolve-dependencies": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz", - "integrity": "sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-snapshot": "^24.9.0" - } - }, - "jest-runner": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.9.0.tgz", - "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.4.2", - "exit": "^0.1.2", - "graceful-fs": "^4.1.15", - "jest-config": "^24.9.0", - "jest-docblock": "^24.3.0", - "jest-haste-map": "^24.9.0", - "jest-jasmine2": "^24.9.0", - "jest-leak-detector": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-resolve": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.6.0", - "source-map-support": "^0.5.6", - "throat": "^4.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "throat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", - "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", - "dev": true - } - } - }, - "jest-runtime": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.9.0.tgz", - "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/environment": "^24.9.0", - "@jest/source-map": "^24.3.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/yargs": "^13.0.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.1.15", - "jest-config": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "realpath-native": "^1.1.0", - "slash": "^2.0.0", - "strip-bom": "^3.0.0", - "yargs": "^13.3.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - }, - "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" - } - }, - "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "jest-serializer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", - "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==", - "dev": true - }, - "jest-snapshot": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", - "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "expect": "^24.9.0", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-resolve": "^24.9.0", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^24.9.0", - "semver": "^6.2.0" - } - }, - "jest-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", - "dev": true, - "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "jest-validate": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", - "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "camelcase": "^5.3.1", - "chalk": "^2.0.1", - "jest-get-type": "^24.9.0", - "leven": "^3.1.0", - "pretty-format": "^24.9.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - } - } - }, - "jest-watcher": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.9.0.tgz", - "integrity": "sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw==", - "dev": true, - "requires": { - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/yargs": "^13.0.0", - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "jest-util": "^24.9.0", - "string-length": "^2.0.0" - }, - "dependencies": { - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - } - } - }, - "jest-worker": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", - "dev": true, - "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=", - "dev": true - }, - "js-base64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.1.tgz", - "integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==", - "dev": true - }, - "js-levenshtein": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "jsdom": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", - "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", - "dev": true, - "requires": { - "abab": "^2.0.0", - "acorn": "^5.5.3", - "acorn-globals": "^4.1.0", - "array-equal": "^1.0.0", - "cssom": ">= 0.3.2 < 0.4.0", - "cssstyle": "^1.0.0", - "data-urls": "^1.0.0", - "domexception": "^1.0.1", - "escodegen": "^1.9.1", - "html-encoding-sniffer": "^1.0.2", - "left-pad": "^1.3.0", - "nwsapi": "^2.0.7", - "parse5": "4.0.0", - "pn": "^1.1.0", - "request": "^2.87.0", - "request-promise-native": "^1.0.5", - "sax": "^1.2.4", - "symbol-tree": "^3.2.2", - "tough-cookie": "^2.3.4", - "w3c-hr-time": "^1.0.1", - "webidl-conversions": "^4.0.2", - "whatwg-encoding": "^1.0.3", - "whatwg-mimetype": "^2.1.0", - "whatwg-url": "^6.4.1", - "ws": "^5.2.0", - "xml-name-validator": "^3.0.0" - }, - "dependencies": { - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", - "dev": true - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "ws": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", - "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", - "dev": true, - "requires": { - "async-limiter": "~1.0.0" - } - } - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", - "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=", - "dev": true, - "requires": { - "jsonify": "~0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "json5": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", - "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "dev": true - }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", - "dev": true - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "jstimezonedetect": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/jstimezonedetect/-/jstimezonedetect-1.0.5.tgz", - "integrity": "sha1-k9A1zSDox9ZOsTdc9ap6EKAkRmo=" - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "klaw": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.9" - } - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "labeled-stream-splicer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.1.tgz", - "integrity": "sha512-MC94mHZRvJ3LfykJlTUipBqenZz1pacOZEMhhQ8dMGcDHs0SBE5GbsavUXV7YtP3icBW17W0Zy1I0lfASmo9Pg==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "isarray": "^2.0.4", - "stream-splicer": "^2.0.0" - }, - "dependencies": { - "isarray": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.4.tgz", - "integrity": "sha512-GMxXOiUirWg1xTKRipM0Ek07rX+ubx4nNVElTJdNLYmNO/2YrDkgJGw9CljXn+r4EWiDQg/8lsRdHyg2PJuUaA==", - "dev": true - } - } - }, - "latest-version": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", - "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", - "dev": true, - "requires": { - "package-json": "^4.0.0" - } - }, - "lazystream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", - "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", - "dev": true, - "requires": { - "readable-stream": "^2.0.5" - } - }, - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "dev": true, - "requires": { - "invert-kv": "^1.0.0" - } - }, - "left-pad": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", - "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", - "dev": true - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - } - }, - "load-yaml-file": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/load-yaml-file/-/load-yaml-file-0.1.1.tgz", - "integrity": "sha512-G910TofXH7u0NfslAzqv6c9pHpvBzObNOo2hMG0/KUDpdHeFY0wE/fTBMExt0Gb12gg5bXS7Hj6pb0e+xbBXLA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.5", - "js-yaml": "^3.13.0", - "pify": "^2.3.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - } - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } - } - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" - }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, - "lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", - "dev": true - }, - "lodash.difference": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=", - "dev": true - }, - "lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", - "dev": true - }, - "lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", - "dev": true - }, - "lodash.isobject": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz", - "integrity": "sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0=", - "dev": true - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", - "dev": true - }, - "lodash.memoize": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", - "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lodash.pickby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", - "integrity": "sha1-feoh2MGNdwOifHBMFdO4SmfjOv8=", - "dev": true - }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, - "lodash.toarray": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", - "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=", - "dev": true - }, - "lodash.union": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=", - "dev": true - }, - "lodash.zip": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz", - "integrity": "sha1-7GZi5IlkCO1KtsVCo5kLcswIACA=", - "dev": true - }, - "log-update": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-3.3.0.tgz", - "integrity": "sha512-YSKm5n+YjZoGZT5lfmOqasVH1fIH9xQA9A81Y48nZ99PxAP62vdCCtua+Gcu6oTn0nqtZd/LwRV+Vflo53ZDWA==", - "dev": true, - "requires": { - "ansi-escapes": "^3.2.0", - "cli-cursor": "^2.1.0", - "wrap-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } - } - } - }, - "loglevel": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.4.tgz", - "integrity": "sha512-p0b6mOGKcGa+7nnmKbpzR6qloPbrgLcnio++E+14Vo/XffOGwZtRpUhr8dTH/x2oCMmEoIU0Zwm3ZauhvYD17g==", - "dev": true - }, - "loglevel-plugin-prefix": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/loglevel-plugin-prefix/-/loglevel-plugin-prefix-0.8.4.tgz", - "integrity": "sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==", - "dev": true - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "loud-rejection": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", - "dev": true, - "requires": { - "currently-unhandled": "^0.4.1", - "signal-exit": "^3.0.0" - } - }, - "lower-case": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", - "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", - "dev": true - }, - "lower-case-first": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-1.0.2.tgz", - "integrity": "sha1-5dp8JvKacHO+AtUrrJmA5ZIq36E=", - "dev": true, - "requires": { - "lower-case": "^1.1.2" - } - }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "dev": true, - "requires": { - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, - "makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", - "dev": true, - "requires": { - "tmpl": "1.0.x" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "maxmin": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-2.1.0.tgz", - "integrity": "sha1-TTsiCQPZXu5+t6x/qGTnLcCaMWY=", - "dev": true, - "requires": { - "chalk": "^1.0.0", - "figures": "^1.0.1", - "gzip-size": "^3.0.0", - "pretty-bytes": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true - }, - "mem": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", - "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", - "dev": true, - "requires": { - "camelcase-keys": "^2.0.0", - "decamelize": "^1.1.2", - "loud-rejection": "^1.0.0", - "map-obj": "^1.0.1", - "minimist": "^1.1.3", - "normalize-package-data": "^2.3.4", - "object-assign": "^4.0.1", - "read-pkg-up": "^1.0.1", - "redent": "^1.0.0", - "trim-newlines": "^1.0.0" - } - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "dev": true, - "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true - }, - "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", - "dev": true - }, - "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", - "dev": true, - "requires": { - "mime-db": "1.40.0" - } - }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - } - } - }, - "module-deps": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.0.tgz", - "integrity": "sha512-hKPmO06so6bL/ZvqVNVqdTVO8UAYsi3tQWlCa+z9KuWhoN4KDQtb5hcqQQv58qYiDE21wIvnttZEPiDgEbpwbA==", - "dev": true, - "requires": { - "JSONStream": "^1.0.3", - "browser-resolve": "^1.7.0", - "cached-path-relative": "^1.0.0", - "concat-stream": "~1.6.0", - "defined": "^1.0.0", - "detective": "^5.0.2", - "duplexer2": "^0.1.2", - "inherits": "^2.0.1", - "parents": "^1.0.0", - "readable-stream": "^2.0.2", - "resolve": "^1.4.0", - "stream-combiner2": "^1.1.1", - "subarg": "^1.0.0", - "through2": "^2.0.0", - "xtend": "^4.0.0" - } - }, - "moment": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", - "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==", - "dev": true - }, - "moment-timezone": { - "version": "0.5.26", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.26.tgz", - "integrity": "sha512-sFP4cgEKTCymBBKgoxZjYzlSovC20Y6J7y3nanDc5RoBIXKlZhoYwBoZGe3flwU6A372AcRwScH8KiwV6zjy1g==", - "dev": true, - "requires": { - "moment": ">= 2.9.0" - } - }, - "morgan": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", - "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==", - "dev": true, - "requires": { - "basic-auth": "~2.0.0", - "debug": "2.6.9", - "depd": "~1.1.2", - "on-finished": "~2.3.0", - "on-headers": "~1.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "mute-stream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", - "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", - "dev": true - }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", - "dev": true, - "optional": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", - "dev": true - }, - "neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "no-case": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", - "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", - "dev": true, - "requires": { - "lower-case": "^1.1.1" - } - }, - "node-emoji": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz", - "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==", - "dev": true, - "requires": { - "lodash.toarray": "^4.4.0" - } - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, - "node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true - }, - "node-notifier": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", - "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", - "dev": true, - "requires": { - "growly": "^1.3.0", - "is-wsl": "^1.1.0", - "semver": "^5.5.0", - "shellwords": "^0.1.1", - "which": "^1.3.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "node-releases": { - "version": "1.1.34", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.34.tgz", - "integrity": "sha512-fNn12JTEfniTuCqo0r9jXgl44+KxRH/huV7zM/KAGOKxDKrHr6EbT7SSs4B+DNxyBE2mks28AD+Jw6PkfY5uwA==", - "dev": true, - "requires": { - "semver": "^6.3.0" - } - }, - "nopt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", - "dev": true, - "requires": { - "abbrev": "1" - } - }, - "normalize-package-data": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.2.tgz", - "integrity": "sha512-YcMnjqeoUckXTPKZSAsPjUPLxH85XotbpqK3w4RyCwdFQSU5FxxBys8buehkSfg0j9fKvV1hn7O0+8reEgkAiw==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "npm-check": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/npm-check/-/npm-check-5.9.0.tgz", - "integrity": "sha512-KLvT5tghIv7bsVhcF3yBCrFu075DpUZROYKXCQvLmOdQuu2gqWTjzrLBzZjtE6wcvzzu5bxb1RRRM8KVzKU0BQ==", - "dev": true, - "requires": { - "babel-runtime": "^6.6.1", - "callsite-record": "^3.0.0", - "chalk": "^1.1.3", - "co": "^4.6.0", - "depcheck": "^0.6.11", - "execa": "^0.2.2", - "giturl": "^1.0.0", - "global-modules": "^1.0.0", - "globby": "^4.0.0", - "inquirer": "^0.12.0", - "is-ci": "^1.0.8", - "lodash": "^4.7.0", - "meow": "^3.7.0", - "minimatch": "^3.0.2", - "node-emoji": "^1.0.3", - "ora": "^0.2.1", - "package-json": "^4.0.1", - "path-exists": "^2.1.0", - "pkg-dir": "^1.0.0", - "preferred-pm": "^1.0.1", - "semver": "^5.0.1", - "semver-diff": "^2.0.0", - "text-table": "^0.2.0", - "throat": "^2.0.2", - "update-notifier": "^2.1.0", - "xtend": "^4.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "nwsapi": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.4.tgz", - "integrity": "sha512-iGfd9Y6SFdTNldEy2L0GUhcarIutFmk+MPWIn9dmj8NMIup03G08uUF2KGbbmv/Ux4RT0VZJoP/sVbWA6d/VIw==", - "dev": true - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "object-inspect": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", - "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dev": true, - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", - "dev": true - }, - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "dev": true, - "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - }, - "dependencies": { - "minimist": { - "version": "0.0.10", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", - "dev": true - } - } - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" - }, - "dependencies": { - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - } - } - }, - "ora": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/ora/-/ora-0.2.3.tgz", - "integrity": "sha1-N1J9Igrc1Tw5tzVx11QVbV22V6Q=", - "dev": true, - "requires": { - "chalk": "^1.1.1", - "cli-cursor": "^1.0.2", - "cli-spinners": "^0.1.2", - "object-assign": "^4.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", - "dev": true - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, - "os-locale": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", - "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", - "dev": true, - "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" - }, - "dependencies": { - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - } - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "outpipe": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/outpipe/-/outpipe-1.1.1.tgz", - "integrity": "sha1-UM+GFjZeh+Ax4ppeyTOaPaRyX6I=", - "dev": true, - "requires": { - "shell-quote": "^1.4.2" - } - }, - "p-each-series": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", - "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", - "dev": true, - "requires": { - "p-reduce": "^1.0.0" - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true - }, - "p-reduce": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", - "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", - "dev": true - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "package-json": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", - "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", - "dev": true, - "requires": { - "got": "^6.7.1", - "registry-auth-token": "^3.0.1", - "registry-url": "^3.0.3", - "semver": "^5.1.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "pako": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", - "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", - "dev": true - }, - "param-case": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", - "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", - "dev": true, - "requires": { - "no-case": "^2.2.0" - } - }, - "parents": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", - "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", - "dev": true, - "requires": { - "path-platform": "~0.11.15" - } - }, - "parse-asn1": { - "version": "5.1.1", - "resolved": "http://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", - "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", - "dev": true, - "requires": { - "asn1.js": "^4.0.0", - "browserify-aes": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "parse-ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", - "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==", - "dev": true - }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true - }, - "parse5": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", - "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", - "dev": true - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true - }, - "pascal-case": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-2.0.1.tgz", - "integrity": "sha1-LVeNNFX2YNpl7KGO+VtODekSdh4=", - "dev": true, - "requires": { - "camel-case": "^3.0.0", - "upper-case-first": "^1.1.0" - } - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", - "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", - "dev": true - }, - "path-case": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/path-case/-/path-case-2.1.1.tgz", - "integrity": "sha1-lLgDfDctP+KQbkZbtF4l0ibo7qU=", - "dev": true, - "requires": { - "no-case": "^2.2.0" - } - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "path-platform": { - "version": "0.11.15", - "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", - "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=", - "dev": true - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", - "dev": true - }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "pbkdf2": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", - "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", - "dev": true, - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "picomatch": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz", - "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==", - "dev": true - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } - }, - "pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", - "dev": true, - "requires": { - "node-modules-regexp": "^1.0.0" - } - }, - "pkg-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", - "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", - "dev": true, - "requires": { - "find-up": "^1.0.0" - } - }, - "pn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", - "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", - "dev": true - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "preferred-pm": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/preferred-pm/-/preferred-pm-1.0.1.tgz", - "integrity": "sha512-9Uxgin5Xnsl67DBvlNFsmDIlBuG9/XKK2cVBTj//7/7wW6ZY+IC9/GlLqxyHABpoasAsJ1MARFOdYPxMUtndxA==", - "dev": true, - "requires": { - "path-exists": "^3.0.0", - "which-pm": "^1.0.1" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true - }, - "prettier": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", - "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", - "dev": true - }, - "pretty-bytes": { - "version": "3.0.1", - "resolved": "http://registry.npmjs.org/pretty-bytes/-/pretty-bytes-3.0.1.tgz", - "integrity": "sha1-J9AAjXeAY6C0gRuzXHnxvV1fvM8=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "pretty-format": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", - "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "ansi-regex": "^4.0.0", - "ansi-styles": "^3.2.0", - "react-is": "^16.8.4" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - } - } - }, - "pretty-ms": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-5.0.0.tgz", - "integrity": "sha512-94VRYjL9k33RzfKiGokPBPpsmloBYSf5Ri+Pq19zlsEcUKFob+admeXr5eFDRuPjFmEOcjJvPGdillYOJyvZ7Q==", - "dev": true, - "requires": { - "parse-ms": "^2.1.0" - } - }, - "private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", - "dev": true - }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true - }, - "prompts": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.2.1.tgz", - "integrity": "sha512-VObPvJiWPhpZI6C5m60XOzTfnYg/xc/an+r9VYymj9WJW3B/DIH+REzjpAACPf8brwPeP+7vz3bIim3S+AaMjw==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.3" - } - }, - "proxy-addr": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", - "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", - "dev": true, - "requires": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.9.0" - } - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, - "psl": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", - "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==", - "dev": true - }, - "public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", - "dev": true - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true - }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", - "dev": true - }, - "randombytes": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", - "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dev": true, - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true - }, - "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "dev": true, - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "dependencies": { - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - } - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, - "react-is": { - "version": "16.10.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.10.2.tgz", - "integrity": "sha512-INBT1QEgtcCCgvccr5/86CfD71fw9EPmDxgiJX4I2Ddr6ZsV6iFXsuby+qWJPtmNuMY0zByTsG4468P7nHuNWA==", - "dev": true - }, - "read-only-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", - "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=", - "dev": true, - "requires": { - "readable-stream": "^2.0.2" - } - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dev": true, - "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "dev": true, - "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "string_decoder": { - "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - } - }, - "readline2": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", - "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "mute-stream": "0.0.5" - } - }, - "realpath-native": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", - "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", - "dev": true, - "requires": { - "util.promisify": "^1.0.0" - } - }, - "redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", - "dev": true, - "requires": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" - } - }, - "regenerate": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", - "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", - "dev": true - }, - "regenerate-unicode-properties": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz", - "integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==", - "dev": true, - "requires": { - "regenerate": "^1.4.0" - } - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true - }, - "regenerator-transform": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.1.tgz", - "integrity": "sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ==", - "dev": true, - "requires": { - "private": "^0.1.6" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "regexpu-core": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz", - "integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==", - "dev": true, - "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.1.0", - "regjsgen": "^0.5.0", - "regjsparser": "^0.6.0", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.1.0" - } - }, - "registry-auth-token": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", - "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", - "dev": true, - "requires": { - "rc": "^1.1.6", - "safe-buffer": "^5.0.1" - } - }, - "registry-url": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", - "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", - "dev": true, - "requires": { - "rc": "^1.0.1" - } - }, - "regjsgen": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", - "integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==", - "dev": true - }, - "regjsparser": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", - "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", - "dev": true, - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - } - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dev": true, - "requires": { - "is-finite": "^1.0.0" - } - }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true - }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "dev": true, - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - } - } - } - }, - "request-promise-core": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", - "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", - "dev": true, - "requires": { - "lodash": "^4.17.11" - } - }, - "request-promise-native": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", - "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", - "dev": true, - "requires": { - "request-promise-core": "1.1.2", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true - }, - "require-package-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/require-package-name/-/require-package-name-2.0.1.tgz", - "integrity": "sha1-wR6XJ2tluOKSP3Xav1+y7ww4Qbk=", - "dev": true - }, - "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", - "dev": true, - "requires": { - "path-parse": "^1.0.5" - } - }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "dev": true, - "requires": { - "resolve-from": "^3.0.0" - } - }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "dev": true, - "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "resq": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/resq/-/resq-1.6.1.tgz", - "integrity": "sha512-+d0g7NXH0MWEi5Tc6zDvIOf2tnsgdMWTiLW4Du3pyAfAbwEQwxrbRgkCVcHGbAY0FqFFWtSevzFV5Bu2PmJSDA==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1" - } - }, - "restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", - "dev": true, - "requires": { - "exit-hook": "^1.0.0", - "onetime": "^1.0.0" - } - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "rgb2hex": { - "version": "0.1.9", - "resolved": "https://registry.npmjs.org/rgb2hex/-/rgb2hex-0.1.9.tgz", - "integrity": "sha512-32iuQzhOjyT+cv9aAFRBJ19JgHwzQwbjUhH3Fj2sWW2EEGAW8fpFrDFP5ndoKDxJaLO06x1hE3kyuIFrUQtybQ==", - "dev": true - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - }, - "dependencies": { - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", - "dev": true - }, - "run-async": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", - "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", - "dev": true, - "requires": { - "once": "^1.3.0" - } - }, - "rx": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", - "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=", - "dev": true - }, - "rx-lite": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", - "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", - "dev": true - }, - "rxjs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", - "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "sane": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", - "dev": true, - "requires": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "sauce-connect-launcher": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/sauce-connect-launcher/-/sauce-connect-launcher-1.2.7.tgz", - "integrity": "sha512-v07+QhFrxgz3seMFuRSonu3gW1s6DbcLQlFhjsRrmKUauzPbbudHdnn91WYgEwhoZVdPNzeZpAEJwcQyd9xnTA==", - "dev": true, - "requires": { - "adm-zip": "~0.4.3", - "async": "^2.1.2", - "https-proxy-agent": "^2.2.1", - "lodash": "^4.16.6", - "rimraf": "^2.5.4" - }, - "dependencies": { - "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } - } - } - }, - "saucelabs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-3.0.0.tgz", - "integrity": "sha512-JlfCcIjXbthtodnCVfjHAMBxSdFIoZWsBMs5J0tBkx1yxOKWZd/7fePUXu688Yj8Z4GpCxNDUQFJEKJmKrttBQ==", - "dev": true, - "requires": { - "change-case": "^3.1.0", - "hash.js": "^1.1.7", - "request": "^2.88.0", - "yargs": "^13.2.2" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - }, - "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" - } - }, - "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "semver-diff": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", - "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", - "dev": true, - "requires": { - "semver": "^5.0.3" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", - "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.7.2", - "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - } - } - }, - "sentence-case": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-2.1.1.tgz", - "integrity": "sha1-H24t2jnBaL+S0T+G1KkYkz9mftQ=", - "dev": true, - "requires": { - "no-case": "^2.2.0", - "upper-case-first": "^1.1.2" - } - }, - "serialize-error": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-5.0.0.tgz", - "integrity": "sha512-/VtpuyzYf82mHYTtI4QKtwHa79vAdU5OQpNPAmE/0UDdlGT0ZxHwC+J6gXkw29wwoVI8fMPsfcVHOwXtUQYYQA==", - "dev": true, - "requires": { - "type-fest": "^0.8.0" - }, - "dependencies": { - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - } - } - }, - "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", - "dev": true, - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.1" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", - "dev": true - }, - "sha.js": { - "version": "2.4.11", - "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "sha1": { - "version": "git://github.com/pvorb/node-sha1.git#910081c83f3661507d9d89e66e3f38d8b59d5559", - "from": "git://github.com/pvorb/node-sha1.git#910081c83f3661507d9d89e66e3f38d8b59d5559", - "requires": { - "charenc": ">= 0.0.0", - "crypt": ">= 0.0.0" - } - }, - "shasum": { - "version": "1.0.2", - "resolved": "http://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", - "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=", - "dev": true, - "requires": { - "json-stable-stringify": "~0.0.0", - "sha.js": "~2.4.4" - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "shell-quote": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", - "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", - "dev": true, - "requires": { - "array-filter": "~0.0.0", - "array-map": "~0.0.0", - "array-reduce": "~0.0.0", - "jsonify": "~0.0.0" - } - }, - "shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "simple-concat": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", - "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=", - "dev": true - }, - "sisteransi": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.3.tgz", - "integrity": "sha512-SbEG75TzH8G7eVXFSN5f9EExILKfly7SUvVY5DhhYLvfhKqhDFY0OzevWa/zwak0RLRfWS5AvfMWpd9gJvr5Yg==", - "dev": true - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true - }, - "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - } - } - }, - "snake-case": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz", - "integrity": "sha1-Qb2xtz8w7GagTU4srRt2OH1NbZ8=", - "dev": true, - "requires": { - "no-case": "^2.2.0" - } - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "snowplow-tracker-core": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/snowplow-tracker-core/-/snowplow-tracker-core-0.7.2.tgz", - "integrity": "sha512-Px3XudDNJb0v3a2tuUvKPgd0j9ROTc2koi3kyMHOO0hHrjimVNE1l1MTHQaeaIwsgQLWY6ao4P06wNdtgF88Dg==", - "requires": { - "@types/uuid": "^2.0.29", - "lodash": "^4.17.11", - "uuid": "2.0.3" - }, - "dependencies": { - "uuid": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", - "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=" - } - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", - "dev": true, - "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, - "spawnd": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/spawnd/-/spawnd-4.0.0.tgz", - "integrity": "sha512-ql3qhJnhAkvXpaqKBWOqou1rUTSQhFRaZkyOT+MTFB4xY3X+brgw6LTWV2wHuE9A6YPhrNe1cbg7S+jAYnbC0Q==", - "dev": true, - "requires": { - "exit": "^0.1.2", - "signal-exit": "^3.0.2", - "tree-kill": "^1.2.1", - "wait-port": "^0.2.2" - } - }, - "spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz", - "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==", - "dev": true - }, - "split-ca": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz", - "integrity": "sha1-bIOv82kvphJW4M0ZfgXp3hV2kaY=", - "dev": true - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "ssh2": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-0.8.5.tgz", - "integrity": "sha512-TkvzxSYYUSQ8jb//HbHnJVui4fVEW7yu/zwBxwro/QaK2EGYtwB+8gdEChwHHuj142c5+250poMC74aJiwApPw==", - "dev": true, - "requires": { - "ssh2-streams": "~0.4.4" - } - }, - "ssh2-streams": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/ssh2-streams/-/ssh2-streams-0.4.6.tgz", - "integrity": "sha512-jXq/nk2K82HuueO9CTCdas/a0ncX3fvYzEPKt1+ftKwE5RXTX25GyjcpjBh2lwVUYbk0c9yq6cBczZssWmU3Tw==", - "dev": true, - "requires": { - "asn1": "~0.2.0", - "bcrypt-pbkdf": "^1.0.2", - "streamsearch": "~0.1.2" - } - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "stack-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", - "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", - "dev": true - }, - "stackframe": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-0.3.1.tgz", - "integrity": "sha1-M6qE8Rd6VUjIk1Uzy/6zQgl19aQ=", - "dev": true - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true - }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true - }, - "stream-browserify": { - "version": "2.0.1", - "resolved": "http://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", - "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", - "dev": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - } - }, - "stream-buffers": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.2.tgz", - "integrity": "sha512-DQi1h8VEBA/lURbSwFtEHnSTb9s2/pwLEaFuNhXwy1Dx3Sa0lOuYT2yNUr4/j2fs8oCAMANtrZ5OrPZtyVs3MQ==", - "dev": true - }, - "stream-combiner2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", - "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", - "dev": true, - "requires": { - "duplexer2": "~0.1.0", - "readable-stream": "^2.0.2" - } - }, - "stream-http": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", - "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", - "dev": true, - "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" - } - }, - "stream-splicer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz", - "integrity": "sha1-G2O+Q4oTPktnHMGTUZdgAXWRDYM=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.2" - } - }, - "streamsearch": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", - "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=", - "dev": true - }, - "string-length": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", - "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", - "dev": true, - "requires": { - "astral-regex": "^1.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "string.prototype.trimleft": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", - "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" - } - }, - "string.prototype.trimright": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", - "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" - } - }, - "string_decoder": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", - "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "requires": { - "is-utf8": "^0.2.0" - } - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, - "strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", - "dev": true, - "requires": { - "get-stdin": "^4.0.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - }, - "subarg": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", - "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", - "dev": true, - "requires": { - "minimist": "^1.1.0" - } - }, - "suffix": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/suffix/-/suffix-0.1.1.tgz", - "integrity": "sha1-zFgjFkag7xEC95R47zqSSP2chC8=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "swap-case": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/swap-case/-/swap-case-1.1.2.tgz", - "integrity": "sha1-w5IDpFhzhfrTyFCgvRvK+ggZdOM=", - "dev": true, - "requires": { - "lower-case": "^1.1.1", - "upper-case": "^1.1.1" - } - }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "syntax-error": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", - "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", - "dev": true, - "requires": { - "acorn-node": "^1.2.0" - } - }, - "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", - "dev": true, - "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "tar-fs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.0.tgz", - "integrity": "sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA==", - "dev": true, - "requires": { - "chownr": "^1.1.1", - "mkdirp": "^0.5.1", - "pump": "^3.0.0", - "tar-stream": "^2.0.0" - }, - "dependencies": { - "bl": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-3.0.0.tgz", - "integrity": "sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==", - "dev": true, - "requires": { - "readable-stream": "^3.0.1" - } - }, - "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "tar-stream": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.0.tgz", - "integrity": "sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==", - "dev": true, - "requires": { - "bl": "^3.0.0", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - } - } - } - }, - "tcp-port-used": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.1.tgz", - "integrity": "sha512-rwi5xJeU6utXoEIiMvVBMc9eJ2/ofzB+7nLOdnZuFTmNCLqRiQh2sMG9MqCxHU/69VC/Fwp5dV9306Qd54ll1Q==", - "dev": true, - "requires": { - "debug": "4.1.0", - "is2": "2.0.1" - }, - "dependencies": { - "debug": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", - "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "term-size": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", - "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", - "dev": true, - "requires": { - "execa": "^0.7.0" - }, - "dependencies": { - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - } - } - }, - "test-exclude": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", - "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", - "dev": true, - "requires": { - "glob": "^7.1.3", - "minimatch": "^3.0.4", - "read-pkg-up": "^4.0.0", - "require-main-filename": "^2.0.0" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "read-pkg-up": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", - "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", - "dev": true, - "requires": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" - } - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - } - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "throat": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/throat/-/throat-2.0.2.tgz", - "integrity": "sha1-qfzoCLaeEzpjJZB4DzQsMKYkmwI=", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "timed-out": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", - "dev": true - }, - "timers-browserify": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", - "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=", - "dev": true, - "requires": { - "process": "~0.11.0" - } - }, - "title-case": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/title-case/-/title-case-2.1.1.tgz", - "integrity": "sha1-PhJyFtpY0rxb7PE3q5Ha46fNj6o=", - "dev": true, - "requires": { - "no-case": "^2.2.0", - "upper-case": "^1.0.3" - } - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", - "dev": true - }, - "to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", - "dev": true - }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - } - } - }, - "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "dev": true, - "requires": { - "punycode": "^2.1.0" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - } - } - }, - "tree-kill": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz", - "integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==", - "dev": true - }, - "trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", - "dev": true - }, - "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", - "dev": true - }, - "tty-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", - "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", - "dev": true - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "type-fest": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz", - "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==", - "dev": true - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "uglify-js": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.1.tgz", - "integrity": "sha512-+dSJLJpXBb6oMHP+Yvw8hUgElz4gLTh82XuX68QiJVTXaE5ibl6buzhNkQdYhBlIhozWOC9ge16wyRmjG4TwVQ==", - "dev": true, - "requires": { - "commander": "2.20.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "umd": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", - "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==", - "dev": true - }, - "undeclared-identifiers": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.2.tgz", - "integrity": "sha512-13EaeocO4edF/3JKime9rD7oB6QI8llAGhgn5fKOPyfkJbRb6NFv9pYV6dFEmpa4uRjKeBqLZP8GpuzqHlKDMQ==", - "dev": true, - "requires": { - "acorn-node": "^1.3.0", - "get-assigned-identifiers": "^1.2.0", - "simple-concat": "^1.0.0", - "xtend": "^4.0.1" - } - }, - "underscore.string": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz", - "integrity": "sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==", - "dev": true, - "requires": { - "sprintf-js": "^1.0.3", - "util-deprecate": "^1.0.2" - } - }, - "unicode-canonical-property-names-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", - "dev": true - }, - "unicode-match-property-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", - "dev": true, - "requires": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" - } - }, - "unicode-match-property-value-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz", - "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==", - "dev": true - }, - "unicode-property-aliases-ecmascript": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz", - "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==", - "dev": true - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, - "unique-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", - "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", - "dev": true, - "requires": { - "crypto-random-string": "^1.0.0" - } - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "dev": true - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } - }, - "unzip-response": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", - "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", - "dev": true - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true - }, - "update-notifier": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", - "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", - "dev": true, - "requires": { - "boxen": "^1.2.1", - "chalk": "^2.0.1", - "configstore": "^3.0.0", - "import-lazy": "^2.1.0", - "is-ci": "^1.0.10", - "is-installed-globally": "^0.1.0", - "is-npm": "^1.0.0", - "latest-version": "^3.0.0", - "semver-diff": "^2.0.0", - "xdg-basedir": "^3.0.0" - } - }, - "upper-case": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", - "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", - "dev": true - }, - "upper-case-first": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz", - "integrity": "sha1-XXm+3P8UQZUY/S7bCgUHybaFkRU=", - "dev": true, - "requires": { - "upper-case": "^1.1.1" - } - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - } - } - }, - "uri-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz", - "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=", - "dev": true - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "dev": true, - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true - } - } - }, - "url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", - "dev": true, - "requires": { - "prepend-http": "^1.0.1" - } - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, - "util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", - "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", - "dev": true, - "requires": { - "inherits": "2.0.3" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "util.promisify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" - } - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true - }, - "uuid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "vm-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz", - "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==", - "dev": true - }, - "w3c-hr-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", - "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", - "dev": true, - "requires": { - "browser-process-hrtime": "^0.1.2" - } - }, - "wait-on": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-3.3.0.tgz", - "integrity": "sha512-97dEuUapx4+Y12aknWZn7D25kkjMk16PbWoYzpSdA8bYpVfS6hpl2a2pOWZ3c+Tyt3/i4/pglyZctG3J4V1hWQ==", - "dev": true, - "requires": { - "@hapi/joi": "^15.0.3", - "core-js": "^2.6.5", - "minimist": "^1.2.0", - "request": "^2.88.0", - "rx": "^4.1.0" - } - }, - "wait-port": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/wait-port/-/wait-port-0.2.6.tgz", - "integrity": "sha512-nXE5Yp0Zs1obhFVc0Da7WVJc3y0LxoCq3j4mtV0NdI5P/ZvRdKp5yhuojvMOcOxSwpQL1hGbOgMNQ+4wpRpwCA==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "commander": "^3.0.2", - "debug": "^4.1.1" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "commander": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", - "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", - "dev": true - } - } - }, - "walkdir": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.0.11.tgz", - "integrity": "sha1-oW0CXrkxvQO1LzCMrtD0D86+lTI=", - "dev": true - }, - "walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", - "dev": true, - "requires": { - "makeerror": "1.0.x" - } - }, - "watchify": { - "version": "3.11.1", - "resolved": "https://registry.npmjs.org/watchify/-/watchify-3.11.1.tgz", - "integrity": "sha512-WwnUClyFNRMB2NIiHgJU9RQPQNqVeFk7OmZaWf5dC5EnNa0Mgr7imBydbaJ7tGTuPM2hz1Cb4uiBvK9NVxMfog==", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "browserify": "^16.1.0", - "chokidar": "^2.1.1", - "defined": "^1.0.0", - "outpipe": "^1.1.0", - "through2": "^2.0.0", - "xtend": "^4.0.0" - } - }, - "wdio-chromedriver-service": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/wdio-chromedriver-service/-/wdio-chromedriver-service-5.0.2.tgz", - "integrity": "sha512-EvdhHJhFpKXIMXph+g84ugSKlYSTiTqg85iu0fD6JzeK6Gg5ZuLeDgvyvvTdkCMq9q4dqwkA+1IikoGQvMOpEA==", - "dev": true, - "requires": { - "fs-extra": "^0.30.0" - }, - "dependencies": { - "fs-extra": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", - "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0", - "path-is-absolute": "^1.0.0", - "rimraf": "^2.2.8" - } - }, - "jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - } - } - }, - "webdriver": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-5.15.0.tgz", - "integrity": "sha512-BBzUYNHua3u8+cEfXXsrvnNZ+fmgVwgpf2EbqqVDZbJm/zKNy/R+V3qJDBtWkd2IkPW+j+5Fxb/Rxyf3clK4zQ==", - "dev": true, - "requires": { - "@wdio/config": "5.15.0", - "@wdio/logger": "5.13.2", - "@wdio/protocols": "5.14.0", - "@wdio/utils": "5.15.0", - "lodash.merge": "^4.6.1", - "request": "^2.83.0" - } - }, - "webdriverio": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-5.15.0.tgz", - "integrity": "sha512-X6K1TW/cA2K3VJFhz/HSm0gBDQGmUJuD55LN4gqcT3LNLeZ9VwCeAODuf5cMp1l5iNX2sGDVyRGh6VD4+F/RHQ==", - "dev": true, - "requires": { - "@wdio/config": "5.15.0", - "@wdio/logger": "5.13.2", - "@wdio/repl": "5.15.0", - "@wdio/utils": "5.15.0", - "archiver": "^3.0.0", - "css-value": "^0.0.1", - "grapheme-splitter": "^1.0.2", - "lodash.clonedeep": "^4.5.0", - "lodash.isobject": "^3.0.2", - "lodash.isplainobject": "^4.0.6", - "lodash.zip": "^4.2.0", - "resq": "^1.6.0", - "rgb2hex": "^0.1.0", - "serialize-error": "^5.0.0", - "webdriver": "5.15.0" - } - }, - "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, - "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "requires": { - "iconv-lite": "0.4.24" - } - }, - "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "whatwg-url": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", - "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "which-pm": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/which-pm/-/which-pm-1.1.0.tgz", - "integrity": "sha512-7GHHJQpALk7BWMD8I+xSILSbHyngvBlfSXlwGpdRFY2voFwVCx+eJAybXTzTnUYmt7zio6B9SEdI81T0fBjxNA==", - "dev": true, - "requires": { - "load-yaml-file": "^0.1.0", - "path-exists": "^3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } - } - }, - "widest-line": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", - "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", - "dev": true, - "requires": { - "string-width": "^2.1.1" - } - }, - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "write-file-atomic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "xdg-basedir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", - "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", - "dev": true - }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "dev": true, - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" - } - }, - "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", - "dev": true - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true - }, - "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", - "dev": true - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - }, - "yargs": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", - "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", - "dev": true, - "requires": { - "camelcase": "^4.1.0", - "cliui": "^3.2.0", - "decamelize": "^1.1.1", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "read-pkg-up": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^7.0.0" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - } - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "^2.0.0" - } - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - } - } - }, - "yargs-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", - "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", - "dev": true, - "requires": { - "camelcase": "^4.1.0" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - } - } - }, - "yarn-install": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yarn-install/-/yarn-install-1.0.0.tgz", - "integrity": "sha1-V/RQULgu/VcYKzlzxUqgXLXSUjA=", - "dev": true, - "requires": { - "cac": "^3.0.3", - "chalk": "^1.1.3", - "cross-spawn": "^4.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "cross-spawn": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", - "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "zip-stream": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-2.1.2.tgz", - "integrity": "sha512-ykebHGa2+uzth/R4HZLkZh3XFJzivhVsjJt8bN3GvBzLaqqrUdRacu+c4QtnUgjkkQfsOuNE1JgLKMCPNmkKgg==", - "dev": true, - "requires": { - "archiver-utils": "^2.1.0", - "compress-commons": "^2.1.1", - "readable-stream": "^3.4.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index 0c380b8af..000000000 --- a/package.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "name": "snowplow-tracker", - "version": "2.14.0", - "dependencies": { - "jstimezonedetect": "1.0.5", - "sha1": "git://github.com/pvorb/node-sha1.git#910081c83f3661507d9d89e66e3f38d8b59d5559", - "snowplow-tracker-core": "^0.7.2", - "uuid": "^3.3.3" - }, - "devDependencies": { - "@babel/core": "^7.6.2", - "@babel/preset-env": "^7.6.2", - "@babel/register": "^7.6.2", - "@wdio/cli": "^5.15.0", - "@wdio/jasmine-framework": "^5.15.0", - "@wdio/local-runner": "^5.15.0", - "@wdio/sauce-service": "^5.14.0", - "@wdio/spec-reporter": "^5.14.5", - "@wdio/static-server-service": "^5.14.4", - "@wdio/sync": "^5.14.4", - "JSON": "1.0.0", - "chromedriver": "^77.0.0", - "dockerode": "^3.0.2", - "grunt": "^1.0.4", - "grunt-aws": "^0.7.1", - "grunt-babel": "^8.0.0", - "grunt-browserify": "^5.3.0", - "grunt-contrib-concat": "^1.0.1", - "grunt-contrib-uglify": "^4.0.1", - "jest": "^24.9.0", - "jest-date-mock": "^1.0.7", - "jest-dev-server": "^4.3.0", - "js-base64": "^2.4.9", - "lodash": "^4.17.15", - "moment-timezone": "^0.5.26", - "npm-check": "^5.9.0", - "prettier": "^1.18.2", - "saucelabs": "^3.0.0", - "semver": "^6.3.0", - "wdio-chromedriver-service": "^5.0.2" - }, - "contributors": [ - "Alex Dean", - "Simon Andersson", - "Anthon Pang", - "Fred Blundun", - "Joshua Beemster", - "Michael Hadam", - "Paul Boocock" - ], - "description": "JavaScript tracker for Snowplow", - "repository": { - "type": "git", - "url": "https://github.com/snowplow/snowplow-javascript-tracker.git" - }, - "bugs": "https://github.com/snowplow/snowplow-javascript-tracker/issues", - "keywords": [ - "tracking", - "web analytics", - "events", - "open source" - ], - "license": "Simplified BSD", - "private": true, - "scripts": { - "test:unit": "jest tests/unit/*.spec.js", - "test:e2e:sauce": "docker pull snowplow/snowplow-micro && wdio tests/wdio.sauce.conf.js", - "test:e2e:local": "docker pull snowplow/snowplow-micro && wdio tests/wdio.local.conf.js" - }, - "jest": { - "setupFiles": [ - "jest-date-mock" - ] - } -} diff --git a/plugins/CLAUDE.md b/plugins/CLAUDE.md new file mode 100644 index 000000000..a78aba399 --- /dev/null +++ b/plugins/CLAUDE.md @@ -0,0 +1,413 @@ +# Browser Plugins - CLAUDE.md + +## Plugin Architecture Overview + +Browser plugins extend the core tracking functionality with feature-specific capabilities. Each plugin follows a consistent pattern for registration, state management, and API exposure. Plugins are self-contained modules that integrate seamlessly with the tracker lifecycle. + +## Core Plugin Pattern + +### Plugin Structure Template +```typescript +// ✅ Correct: Standard plugin structure +import { BrowserPlugin, BrowserTracker } from '@snowplow/browser-tracker-core'; + +const _trackers: Record = {}; + +export function MyPlugin(): BrowserPlugin { + return { + activateBrowserPlugin: (tracker) => { + _trackers[tracker.id] = tracker; + } + }; +} + +// ❌ Wrong: Global state without cleanup +let tracker: BrowserTracker; // Global leak +``` + +### API Function Pattern +```typescript +// ✅ Correct: Dispatch to registered trackers +export function trackMyEvent( + event: MyEvent & CommonEventProperties, + trackers: Array = Object.keys(_trackers) +) { + dispatchToTrackersInCollection(trackers, _trackers, (t) => { + t.core.track(buildMyEvent(event), event.context, event.timestamp); + }); +} + +// ❌ Wrong: Single tracker assumption +export function trackEvent(event: MyEvent) { + tracker.track(event); // Which tracker? +} +``` + +## Plugin Categories + +### 1. Event Tracking Plugins +Plugins that add new event types: +- `browser-plugin-ad-tracking`: Ad impressions, clicks, conversions +- `browser-plugin-media-tracking`: Video/audio player events +- `browser-plugin-ecommerce`: Transaction and item tracking +- `browser-plugin-error-tracking`: JavaScript error capture + +### 2. Context Enhancement Plugins +Plugins that add contextual data: +- `browser-plugin-client-hints`: Browser client hints +- `browser-plugin-timezone`: Timezone information +- `browser-plugin-geolocation`: Location data +- `browser-plugin-ga-cookies`: Google Analytics cookies + +### 3. Behavior Tracking Plugins +Plugins that track user interactions: +- `browser-plugin-form-tracking`: Form interactions +- `browser-plugin-link-click-tracking`: Link clicks +- `browser-plugin-button-click-tracking`: Button clicks +- `browser-plugin-element-tracking`: General element visibility + +### 4. Performance Plugins +Plugins for performance monitoring: +- `browser-plugin-performance-timing`: Page load performance +- `browser-plugin-web-vitals`: Core Web Vitals +- `browser-plugin-performance-navigation-timing`: Navigation timing + +## Common Plugin Patterns + +### Schema Definition +```typescript +// schemata.ts - Centralized schemas +export const AD_CLICK_SCHEMA = + 'iglu:com.snowplowanalytics.snowplow/ad_click/jsonschema/1-0-0'; +export const AD_IMPRESSION_SCHEMA = + 'iglu:com.snowplowanalytics.snowplow/ad_impression/jsonschema/1-0-0'; +``` + +### Event Builder Integration +```typescript +// ✅ Correct: Use core builders +import { buildSelfDescribingEvent } from '@snowplow/tracker-core'; + +function buildAdClick(event: AdClickEvent): PayloadBuilder { + return buildSelfDescribingEvent({ + event: { + schema: AD_CLICK_SCHEMA, + data: cleanAdClickData(event) + } + }); +} + +// ❌ Wrong: Custom payload construction +function buildAdClick(event: AdClickEvent) { + return { e: 'ue', data: event }; // Non-standard +} +``` + +### Configuration Options +```typescript +// ✅ Correct: Typed configuration +export interface MediaTrackingConfiguration { + captureEvents?: MediaEventType[]; + boundaries?: number[]; + volumeChangeTrackingInterval?: number; +} + +export function MediaTrackingPlugin( + config: MediaTrackingConfiguration = {} +): BrowserPlugin { + const settings = { ...defaultConfig, ...config }; + // Plugin implementation +} + +// ❌ Wrong: Untyped config +export function Plugin(config: any) { } +``` + +### DOM Observer Pattern +```typescript +// ✅ Correct: Managed observers +export function FormTrackingPlugin(): BrowserPlugin { + let observer: MutationObserver | null = null; + + return { + activateBrowserPlugin: (tracker) => { + observer = new MutationObserver(handleMutations); + observer.observe(document, { childList: true }); + }, + contexts: () => { + // Cleanup on context request if needed + observer?.disconnect(); + return []; + } + }; +} + +// ❌ Wrong: Unmanaged observers +new MutationObserver(callback).observe(document, {}); // Leak +``` + +## Plugin State Management + +### Tracker Registry +```typescript +// ✅ Correct: Scoped tracker storage +const _trackers: Record = {}; +const _configurations: WeakMap = new WeakMap(); + +// ❌ Wrong: Global configuration +let globalConfig: Config; // Affects all trackers +``` + +### Element Tracking State +```typescript +// ✅ Correct: WeakMap for DOM references +const elementStates = new WeakMap(); + +// ❌ Wrong: Memory leak potential +const elementStates: Map = new Map(); +``` + +## Event API Standards + +### Standard Event Interface +```typescript +// ✅ Correct: Consistent event structure +export interface MediaPlayerEvent { + currentTime: number; + duration?: number; + ended: boolean; + loop: boolean; + muted: boolean; + paused: boolean; + playbackRate: number; + volume: number; +} + +// ❌ Wrong: Inconsistent naming +export interface VideoData { + time: number; // Should be currentTime + length?: number; // Should be duration +} +``` + +### Optional Properties Pattern +```typescript +// ✅ Correct: Clear optionality +export interface AdClickEvent { + targetUrl: string; + clickId?: string; + costModel?: 'cpa' | 'cpc' | 'cpm'; + cost?: number; + bannerId?: string; + zoneId?: string; + impressionId?: string; + advertiserId?: string; + campaignId?: string; +} + +// ❌ Wrong: Everything optional +export interface AdEvent { + targetUrl?: string; // Required field as optional +} +``` + +## Context Building + +### Dynamic Context Pattern +```typescript +// ✅ Correct: Context from current state +export function getMediaContext(player: HTMLMediaElement): SelfDescribingJson { + return { + schema: MEDIA_PLAYER_SCHEMA, + data: { + currentTime: player.currentTime, + duration: player.duration || null, + ended: player.ended, + paused: player.paused + } + }; +} + +// ❌ Wrong: Stale context +const context = { /* captured once */ }; +``` + +## Testing Plugin Patterns + +### Test File Organization +``` +plugin/test/ +├── events.test.ts # Event tracking tests +├── contexts.test.ts # Context builder tests +├── api.test.ts # Public API tests +└── __snapshots__/ # Jest snapshot files +``` + +### Mock Tracker Setup +```typescript +// Standard test setup with event store +import { addTracker, SharedState } from '@snowplow/browser-tracker-core'; +import { newInMemoryEventStore } from '@snowplow/tracker-core'; + +describe('MyPlugin', () => { + let eventStore = newInMemoryEventStore(); + + beforeEach(() => { + SharedState.clear(); + eventStore = newInMemoryEventStore(); + addTracker('sp', 'sp', 'js-test', '', new SharedState(), { + eventStore, + plugins: [MyPlugin()] + }); + }); +}); +``` + +### Event Extraction Utilities +```typescript +// Common lodash/fp patterns for test assertions +import F from 'lodash/fp'; + +const getUEEvents = F.compose( + F.filter(F.compose(F.eq('ue'), F.get('e'))) +); + +const extractEventProperties = F.map( + F.compose( + F.get('data'), + (cx: string) => JSON.parse(cx), + F.get('ue_pr') + ) +); + +// Extract specific schema events +const extractUeEvent = (schema: string) => ({ + from: F.compose( + F.first, + F.filter(F.compose(F.eq(schema), F.get('schema'))), + F.flatten, + extractEventProperties, + getUEEvents + ) +}); +``` + +### Event Verification Patterns +```typescript +// ✅ Correct: Verify event schema and data +it('tracks ad click with correct schema', () => { + trackAdClick({ targetUrl: 'https://example.com' }); + + const events = eventStore.getEvents(); + const adClickEvent = extractUeEvent(AD_CLICK_SCHEMA).from(events); + + expect(adClickEvent).toMatchObject({ + targetUrl: 'https://example.com' + }); +}); + +// ❌ Wrong: Testing implementation details +it('calls internal function', () => { + expect(internalFunction).toHaveBeenCalled(); // Don't test internals +}); +``` + +### Context Testing +```typescript +// ✅ Correct: Test context generation +it('generates media player context', () => { + const player = document.createElement('video'); + player.currentTime = 30; + player.duration = 100; + + const context = buildMediaContext(player); + expect(context.data).toMatchObject({ + currentTime: 30, + duration: 100 + }); +}); +``` + +### Snapshot Testing for Complex Objects +```typescript +// ✅ Correct: Snapshot for schema validation +it('builds correct event structure', () => { + const event = buildAdClickEvent({ + targetUrl: 'https://example.com', + clickId: '123' + }); + expect(event).toMatchSnapshot(); +}); +``` + +## Plugin Development Checklist + +- [ ] Implement `BrowserPlugin` interface +- [ ] Create tracker registry with `_trackers` +- [ ] Define TypeScript interfaces for events +- [ ] Add schema constants to `schemata.ts` +- [ ] Implement tracking functions with `dispatchToTrackersInCollection` +- [ ] Export both plugin and API functions from index.ts +- [ ] Handle configuration options with defaults +- [ ] Clean up resources (observers, timers) properly +- [ ] Add comprehensive Jest tests +- [ ] Document usage in README.md + +## Common Pitfalls + +### 1. Forgetting Tracker Registration +```typescript +// ❌ Wrong: API without plugin +import { trackAdClick } from '@snowplow/browser-plugin-ad-tracking'; +trackAdClick(event); // Error: _trackers empty + +// ✅ Correct: Register plugin first +import { AdTrackingPlugin } from '@snowplow/browser-plugin-ad-tracking'; +newTracker('sp', 'collector', { plugins: [AdTrackingPlugin()] }); +``` + +### 2. Memory Leaks +```typescript +// ❌ Wrong: Unremoved listeners +element.addEventListener('click', handler); + +// ✅ Correct: Cleanup in plugin lifecycle +return { + activateBrowserPlugin: (tracker) => { + element.addEventListener('click', handler); + }, + contexts: () => { + element.removeEventListener('click', handler); + return []; + } +}; +``` + +## Quick Reference + +### Plugin File Structure +``` +browser-plugin-[name]/ +├── src/ +│ ├── index.ts # Plugin & API exports +│ ├── api.ts # Tracking functions +│ ├── types.ts # TypeScript interfaces +│ ├── schemata.ts # Schema constants +│ └── contexts.ts # Context builders +├── test/ +│ └── [name].test.ts # Jest tests +├── package.json +├── tsconfig.json +├── rollup.config.js +└── README.md +``` + +## Contributing to CLAUDE.md + +When creating or modifying plugins: + +1. **Follow the standard plugin pattern** for consistency +2. **Export all public types** from index.ts +3. **Use workspace protocol** for dependencies +4. **Test with multiple trackers** to ensure isolation +5. **Document configuration options** clearly \ No newline at end of file diff --git a/plugins/browser-plugin-ad-tracking/CHANGELOG.json b/plugins/browser-plugin-ad-tracking/CHANGELOG.json new file mode 100644 index 000000000..1ea047a89 --- /dev/null +++ b/plugins/browser-plugin-ad-tracking/CHANGELOG.json @@ -0,0 +1,599 @@ +{ + "name": "@snowplow/browser-plugin-ad-tracking", + "entries": [ + { + "version": "4.10.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.10.0", + "date": "Mon, 27 Jul 2026 13:52:14 GMT", + "comments": {} + }, + { + "version": "4.9.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.9.0", + "date": "Tue, 21 Jul 2026 14:53:08 GMT", + "comments": {} + }, + { + "version": "4.8.4", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.8.4", + "date": "Thu, 02 Jul 2026 10:07:52 GMT", + "comments": {} + }, + { + "version": "4.8.3", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.8.3", + "date": "Tue, 30 Jun 2026 14:22:03 GMT", + "comments": { + "none": [ + { + "comment": "Update uuid to v11 and remove closure-compiler from the build pipeline" + } + ] + } + }, + { + "version": "4.8.2", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.8.2", + "date": "Wed, 17 Jun 2026 12:30:12 GMT", + "comments": {} + }, + { + "version": "4.8.1", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.8.1", + "date": "Wed, 13 May 2026 09:26:05 GMT", + "comments": {} + }, + { + "version": "4.8.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.8.0", + "date": "Tue, 28 Apr 2026 07:56:22 GMT", + "comments": {} + }, + { + "version": "4.7.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.7.0", + "date": "Wed, 01 Apr 2026 12:59:29 GMT", + "comments": {} + }, + { + "version": "4.6.9", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.6.9", + "date": "Mon, 16 Mar 2026 15:43:06 GMT", + "comments": {} + }, + { + "version": "4.6.8", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.6.8", + "date": "Tue, 28 Oct 2025 09:46:42 GMT", + "comments": {} + }, + { + "version": "4.6.7", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.6.7", + "date": "Tue, 07 Oct 2025 14:53:36 GMT", + "comments": {} + }, + { + "version": "4.6.6", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.6.6", + "date": "Tue, 26 Aug 2025 08:42:27 GMT", + "comments": {} + }, + { + "version": "4.6.5", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.6.5", + "date": "Wed, 25 Jun 2025 21:16:46 GMT", + "comments": {} + }, + { + "version": "4.6.4", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.6.4", + "date": "Wed, 25 Jun 2025 12:08:50 GMT", + "comments": {} + }, + { + "version": "4.6.3", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.6.3", + "date": "Thu, 29 May 2025 19:52:07 GMT", + "comments": {} + }, + { + "version": "4.6.2", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.6.2", + "date": "Tue, 20 May 2025 07:39:05 GMT", + "comments": {} + }, + { + "version": "4.6.1", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.6.1", + "date": "Tue, 06 May 2025 13:10:51 GMT", + "comments": {} + }, + { + "version": "4.6.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.6.0", + "date": "Thu, 01 May 2025 09:58:59 GMT", + "comments": {} + }, + { + "version": "4.5.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.5.0", + "date": "Fri, 04 Apr 2025 09:21:23 GMT", + "comments": {} + }, + { + "version": "4.4.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.4.0", + "date": "Thu, 20 Mar 2025 12:14:34 GMT", + "comments": {} + }, + { + "version": "4.3.1", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.3.1", + "date": "Tue, 21 Jan 2025 11:09:42 GMT", + "comments": {} + }, + { + "version": "4.3.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.3.0", + "date": "Mon, 20 Jan 2025 11:45:13 GMT", + "comments": {} + }, + { + "version": "4.2.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.2.0", + "date": "Mon, 13 Jan 2025 08:30:05 GMT", + "comments": {} + }, + { + "version": "4.1.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.1.0", + "date": "Thu, 28 Nov 2024 10:57:30 GMT", + "comments": {} + }, + { + "version": "4.0.4", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.0.4", + "date": "Thu, 21 Nov 2024 09:06:36 GMT", + "comments": {} + }, + { + "version": "4.0.3", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.0.3", + "date": "Wed, 20 Nov 2024 09:30:31 GMT", + "comments": {} + }, + { + "version": "4.0.2", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.0.2", + "date": "Mon, 11 Nov 2024 15:46:33 GMT", + "comments": {} + }, + { + "version": "4.0.1", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.0.1", + "date": "Fri, 01 Nov 2024 10:35:07 GMT", + "comments": {} + }, + { + "version": "4.0.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v4.0.0", + "date": "Mon, 28 Oct 2024 11:48:53 GMT", + "comments": {} + }, + { + "version": "3.24.6", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.24.6", + "date": "Mon, 28 Oct 2024 10:23:28 GMT", + "comments": {} + }, + { + "version": "3.24.5", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.24.5", + "date": "Fri, 25 Oct 2024 08:53:04 GMT", + "comments": {} + }, + { + "version": "3.24.4", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.24.4", + "date": "Thu, 26 Sep 2024 06:10:22 GMT", + "comments": {} + }, + { + "version": "3.24.3", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.24.3", + "date": "Tue, 03 Sep 2024 08:15:14 GMT", + "comments": { + "none": [ + { + "comment": "Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush" + } + ] + } + }, + { + "version": "3.24.2", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.24.2", + "date": "Wed, 24 Jul 2024 08:59:00 GMT", + "comments": {} + }, + { + "version": "3.24.1", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.24.1", + "date": "Tue, 02 Jul 2024 07:08:17 GMT", + "comments": {} + }, + { + "version": "3.24.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.24.0", + "date": "Tue, 25 Jun 2024 08:31:05 GMT", + "comments": {} + }, + { + "version": "3.23.1", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.23.1", + "date": "Tue, 04 Jun 2024 13:34:45 GMT", + "comments": {} + }, + { + "version": "3.23.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.23.0", + "date": "Thu, 28 Mar 2024 11:28:45 GMT", + "comments": {} + }, + { + "version": "3.22.1", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.22.1", + "date": "Wed, 13 Mar 2024 08:39:48 GMT", + "comments": {} + }, + { + "version": "3.22.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.22.0", + "date": "Fri, 08 Mar 2024 08:13:04 GMT", + "comments": {} + }, + { + "version": "3.21.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.21.0", + "date": "Mon, 29 Jan 2024 08:34:06 GMT", + "comments": {} + }, + { + "version": "3.20.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.20.0", + "date": "Mon, 15 Jan 2024 14:41:16 GMT", + "comments": {} + }, + { + "version": "3.19.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.19.0", + "date": "Thu, 14 Dec 2023 10:45:22 GMT", + "comments": {} + }, + { + "version": "3.18.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.18.0", + "date": "Mon, 04 Dec 2023 13:44:02 GMT", + "comments": {} + }, + { + "version": "3.17.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.17.0", + "date": "Tue, 14 Nov 2023 17:58:26 GMT", + "comments": {} + }, + { + "version": "3.16.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.16.0", + "date": "Mon, 16 Oct 2023 14:58:08 GMT", + "comments": {} + }, + { + "version": "3.15.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.15.0", + "date": "Mon, 28 Aug 2023 14:25:14 GMT", + "comments": {} + }, + { + "version": "3.14.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.14.0", + "date": "Thu, 10 Aug 2023 13:56:44 GMT", + "comments": {} + }, + { + "version": "3.13.1", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.13.1", + "date": "Thu, 29 Jun 2023 14:20:06 GMT", + "comments": {} + }, + { + "version": "3.13.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.13.0", + "date": "Tue, 20 Jun 2023 07:44:23 GMT", + "comments": {} + }, + { + "version": "3.12.1", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.12.1", + "date": "Thu, 15 Jun 2023 10:05:37 GMT", + "comments": {} + }, + { + "version": "3.12.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.12.0", + "date": "Mon, 05 Jun 2023 11:51:22 GMT", + "comments": {} + }, + { + "version": "3.11.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.11.0", + "date": "Wed, 24 May 2023 15:56:17 GMT", + "comments": {} + }, + { + "version": "3.10.1", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.10.1", + "date": "Fri, 12 May 2023 06:59:31 GMT", + "comments": {} + }, + { + "version": "3.10.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.10.0", + "date": "Thu, 11 May 2023 08:29:15 GMT", + "comments": {} + }, + { + "version": "3.9.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.9.0", + "date": "Thu, 30 Mar 2023 13:46:56 GMT", + "comments": {} + }, + { + "version": "3.8.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.8.0", + "date": "Tue, 03 Jan 2023 15:36:33 GMT", + "comments": {} + }, + { + "version": "3.7.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.7.0", + "date": "Mon, 31 Oct 2022 06:26:28 GMT", + "comments": {} + }, + { + "version": "3.6.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.6.0", + "date": "Thu, 15 Sep 2022 07:55:20 GMT", + "comments": {} + }, + { + "version": "3.5.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.5.0", + "date": "Fri, 10 Jun 2022 18:57:46 GMT", + "comments": {} + }, + { + "version": "3.4.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.4.0", + "date": "Thu, 07 Apr 2022 11:56:26 GMT", + "comments": { + "none": [ + { + "comment": "Bump dependencies (#1067)" + } + ] + } + }, + { + "version": "3.3.1", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.3.1", + "date": "Wed, 23 Feb 2022 19:27:40 GMT", + "comments": {} + }, + { + "version": "3.3.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.3.0", + "date": "Mon, 31 Jan 2022 15:58:10 GMT", + "comments": {} + }, + { + "version": "3.2.3", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.2.3", + "date": "Tue, 18 Jan 2022 16:23:52 GMT", + "comments": { + "none": [ + { + "comment": "Bump Copyright to 2022 (#1040)" + } + ] + } + }, + { + "version": "3.2.2", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.2.2", + "date": "Fri, 14 Jan 2022 10:17:59 GMT", + "comments": {} + }, + { + "version": "3.2.1", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.2.1", + "date": "Wed, 12 Jan 2022 09:50:29 GMT", + "comments": {} + }, + { + "version": "3.2.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.2.0", + "date": "Tue, 11 Jan 2022 12:53:22 GMT", + "comments": {} + }, + { + "version": "3.1.6", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.1.6", + "date": "Tue, 19 Oct 2021 09:17:22 GMT", + "comments": { + "none": [ + { + "comment": "Fix failing build on ARM Macs (#1012)" + } + ] + } + }, + { + "version": "3.1.5", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.1.5", + "date": "Fri, 01 Oct 2021 08:09:20 GMT", + "comments": {} + }, + { + "version": "3.1.4", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.1.4", + "date": "Tue, 21 Sep 2021 14:59:36 GMT", + "comments": {} + }, + { + "version": "3.1.3", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.1.3", + "date": "Mon, 23 Aug 2021 10:13:18 GMT", + "comments": {} + }, + { + "version": "3.1.2", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.1.2", + "date": "Mon, 16 Aug 2021 12:59:59 GMT", + "comments": { + "none": [ + { + "comment": "Update READMEs with correct Node requirements (#994)" + } + ] + } + }, + { + "version": "3.1.1", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.1.1", + "date": "Wed, 04 Aug 2021 10:12:25 GMT", + "comments": { + "none": [ + { + "comment": "Bump tslib to 2.3.0 (#986)" + }, + { + "comment": "Bump typescript to 4.3.5 (#987)" + }, + { + "comment": "Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988)" + } + ] + } + }, + { + "version": "3.1.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.1.0", + "date": "Fri, 14 May 2021 10:45:32 GMT", + "comments": {} + }, + { + "version": "3.0.3", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.0.3", + "date": "Wed, 21 Apr 2021 12:35:06 GMT", + "comments": {} + }, + { + "version": "3.0.2", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.0.2", + "date": "Thu, 15 Apr 2021 21:07:39 GMT", + "comments": {} + }, + { + "version": "3.0.1", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.0.1", + "date": "Wed, 14 Apr 2021 16:30:05 GMT", + "comments": { + "none": [ + { + "comment": "Add peerDependencies to plugins (#950)" + }, + { + "comment": "Mark packages as sideEffect: false (#951)" + }, + { + "comment": "Add unit tests to plugin track* functions (#954)" + } + ] + } + }, + { + "version": "3.0.0", + "tag": "@snowplow/browser-plugin-ad-tracking_v3.0.0", + "date": "Wed, 31 Mar 2021 14:46:47 GMT", + "comments": { + "none": [ + { + "comment": "Bump rollup to 2.41 (#916)" + }, + { + "comment": "Publish UMD versions of plugins to GitHub release (#923)" + }, + { + "comment": "Ensure browser-tracker API methods catch exceptions (#919)" + }, + { + "comment": "Introduce TSDoc comments and extract interfaces where appropriate (#906)" + }, + { + "comment": "Bump major version to v3 and update READMEs (#904)" + }, + { + "comment": "Improve Core API for module bundlers which support treeshaking (#903)" + }, + { + "comment": "Rename @snowplow/browser-core to @snowplow/browser-tracker-core (#901)" + }, + { + "comment": "Publish lite version of sp.js (#900)" + }, + { + "comment": "Ensure correct 3-Clause BSD License notices are being used (#316)" + }, + { + "comment": "Improve API for module bundlers which support treeshaking (#899)" + }, + { + "comment": "Bump rush to 5.39 (#895)" + }, + { + "comment": "Port to TypeScript (#72)" + }, + { + "comment": "Make sp.js build process modular (#450)" + }, + { + "comment": "Create @snowplow/browser-tracker package for npm distribution (#541)" + }, + { + "comment": "Split auto contexts into plugins (#880)" + }, + { + "comment": "Add rush to manage monorepo (#883)" + }, + { + "comment": "Add ES Module builds (#882)" + }, + { + "comment": "Cleanup deprecated methods (#557)" + }, + { + "comment": "Update publishing process for rush (#907)" + }, + { + "comment": "Change white and black lists to allow and deny lists (#908)" + }, + { + "comment": "Create rush change files for major version 3 release (#909)" + } + ] + } + } + ] +} diff --git a/plugins/browser-plugin-ad-tracking/CHANGELOG.md b/plugins/browser-plugin-ad-tracking/CHANGELOG.md new file mode 100644 index 000000000..1d95c364a --- /dev/null +++ b/plugins/browser-plugin-ad-tracking/CHANGELOG.md @@ -0,0 +1,436 @@ +# Change Log - @snowplow/browser-plugin-ad-tracking + +This log was last generated on Mon, 27 Jul 2026 13:52:14 GMT and should not be manually modified. + +## 4.10.0 +Mon, 27 Jul 2026 13:52:14 GMT + +_Version update only_ + +## 4.9.0 +Tue, 21 Jul 2026 14:53:08 GMT + +_Version update only_ + +## 4.8.4 +Thu, 02 Jul 2026 10:07:52 GMT + +_Version update only_ + +## 4.8.3 +Tue, 30 Jun 2026 14:22:03 GMT + +### Updates + +- Update uuid to v11 and remove closure-compiler from the build pipeline + +## 4.8.2 +Wed, 17 Jun 2026 12:30:12 GMT + +_Version update only_ + +## 4.8.1 +Wed, 13 May 2026 09:26:05 GMT + +_Version update only_ + +## 4.8.0 +Tue, 28 Apr 2026 07:56:22 GMT + +_Version update only_ + +## 4.7.0 +Wed, 01 Apr 2026 12:59:29 GMT + +_Version update only_ + +## 4.6.9 +Mon, 16 Mar 2026 15:43:06 GMT + +_Version update only_ + +## 4.6.8 +Tue, 28 Oct 2025 09:46:42 GMT + +_Version update only_ + +## 4.6.7 +Tue, 07 Oct 2025 14:53:36 GMT + +_Version update only_ + +## 4.6.6 +Tue, 26 Aug 2025 08:42:27 GMT + +_Version update only_ + +## 4.6.5 +Wed, 25 Jun 2025 21:16:46 GMT + +_Version update only_ + +## 4.6.4 +Wed, 25 Jun 2025 12:08:50 GMT + +_Version update only_ + +## 4.6.3 +Thu, 29 May 2025 19:52:07 GMT + +_Version update only_ + +## 4.6.2 +Tue, 20 May 2025 07:39:05 GMT + +_Version update only_ + +## 4.6.1 +Tue, 06 May 2025 13:10:51 GMT + +_Version update only_ + +## 4.6.0 +Thu, 01 May 2025 09:58:59 GMT + +_Version update only_ + +## 4.5.0 +Fri, 04 Apr 2025 09:21:23 GMT + +_Version update only_ + +## 4.4.0 +Thu, 20 Mar 2025 12:14:34 GMT + +_Version update only_ + +## 4.3.1 +Tue, 21 Jan 2025 11:09:42 GMT + +_Version update only_ + +## 4.3.0 +Mon, 20 Jan 2025 11:45:13 GMT + +_Version update only_ + +## 4.2.0 +Mon, 13 Jan 2025 08:30:05 GMT + +_Version update only_ + +## 4.1.0 +Thu, 28 Nov 2024 10:57:30 GMT + +_Version update only_ + +## 4.0.4 +Thu, 21 Nov 2024 09:06:36 GMT + +_Version update only_ + +## 4.0.3 +Wed, 20 Nov 2024 09:30:31 GMT + +_Version update only_ + +## 4.0.2 +Mon, 11 Nov 2024 15:46:33 GMT + +_Version update only_ + +## 4.0.1 +Fri, 01 Nov 2024 10:35:07 GMT + +_Version update only_ + +## 4.0.0 +Mon, 28 Oct 2024 11:48:53 GMT + +_Version update only_ + +## 3.24.6 +Mon, 28 Oct 2024 10:23:28 GMT + +_Version update only_ + +## 3.24.5 +Fri, 25 Oct 2024 08:53:04 GMT + +_Version update only_ + +## 3.24.4 +Thu, 26 Sep 2024 06:10:22 GMT + +_Version update only_ + +## 3.24.3 +Tue, 03 Sep 2024 08:15:14 GMT + +### Updates + +- Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush + +## 3.24.2 +Wed, 24 Jul 2024 08:59:00 GMT + +_Version update only_ + +## 3.24.1 +Tue, 02 Jul 2024 07:08:17 GMT + +_Version update only_ + +## 3.24.0 +Tue, 25 Jun 2024 08:31:05 GMT + +_Version update only_ + +## 3.23.1 +Tue, 04 Jun 2024 13:34:45 GMT + +_Version update only_ + +## 3.23.0 +Thu, 28 Mar 2024 11:28:45 GMT + +_Version update only_ + +## 3.22.1 +Wed, 13 Mar 2024 08:39:48 GMT + +_Version update only_ + +## 3.22.0 +Fri, 08 Mar 2024 08:13:04 GMT + +_Version update only_ + +## 3.21.0 +Mon, 29 Jan 2024 08:34:06 GMT + +_Version update only_ + +## 3.20.0 +Mon, 15 Jan 2024 14:41:16 GMT + +_Version update only_ + +## 3.19.0 +Thu, 14 Dec 2023 10:45:22 GMT + +_Version update only_ + +## 3.18.0 +Mon, 04 Dec 2023 13:44:02 GMT + +_Version update only_ + +## 3.17.0 +Tue, 14 Nov 2023 17:58:26 GMT + +_Version update only_ + +## 3.16.0 +Mon, 16 Oct 2023 14:58:08 GMT + +_Version update only_ + +## 3.15.0 +Mon, 28 Aug 2023 14:25:14 GMT + +_Version update only_ + +## 3.14.0 +Thu, 10 Aug 2023 13:56:44 GMT + +_Version update only_ + +## 3.13.1 +Thu, 29 Jun 2023 14:20:06 GMT + +_Version update only_ + +## 3.13.0 +Tue, 20 Jun 2023 07:44:23 GMT + +_Version update only_ + +## 3.12.1 +Thu, 15 Jun 2023 10:05:37 GMT + +_Version update only_ + +## 3.12.0 +Mon, 05 Jun 2023 11:51:22 GMT + +_Version update only_ + +## 3.11.0 +Wed, 24 May 2023 15:56:17 GMT + +_Version update only_ + +## 3.10.1 +Fri, 12 May 2023 06:59:31 GMT + +_Version update only_ + +## 3.10.0 +Thu, 11 May 2023 08:29:15 GMT + +_Version update only_ + +## 3.9.0 +Thu, 30 Mar 2023 13:46:56 GMT + +_Version update only_ + +## 3.8.0 +Tue, 03 Jan 2023 15:36:33 GMT + +_Version update only_ + +## 3.7.0 +Mon, 31 Oct 2022 06:26:28 GMT + +_Version update only_ + +## 3.6.0 +Thu, 15 Sep 2022 07:55:20 GMT + +_Version update only_ + +## 3.5.0 +Fri, 10 Jun 2022 18:57:46 GMT + +_Version update only_ + +## 3.4.0 +Thu, 07 Apr 2022 11:56:26 GMT + +### Updates + +- Bump dependencies (#1067) + +## 3.3.1 +Wed, 23 Feb 2022 19:27:40 GMT + +_Version update only_ + +## 3.3.0 +Mon, 31 Jan 2022 15:58:10 GMT + +_Version update only_ + +## 3.2.3 +Tue, 18 Jan 2022 16:23:52 GMT + +### Updates + +- Bump Copyright to 2022 (#1040) + +## 3.2.2 +Fri, 14 Jan 2022 10:17:59 GMT + +_Version update only_ + +## 3.2.1 +Wed, 12 Jan 2022 09:50:29 GMT + +_Version update only_ + +## 3.2.0 +Tue, 11 Jan 2022 12:53:22 GMT + +_Version update only_ + +## 3.1.6 +Tue, 19 Oct 2021 09:17:22 GMT + +### Updates + +- Fix failing build on ARM Macs (#1012) + +## 3.1.5 +Fri, 01 Oct 2021 08:09:20 GMT + +_Version update only_ + +## 3.1.4 +Tue, 21 Sep 2021 14:59:36 GMT + +_Version update only_ + +## 3.1.3 +Mon, 23 Aug 2021 10:13:18 GMT + +_Version update only_ + +## 3.1.2 +Mon, 16 Aug 2021 12:59:59 GMT + +### Updates + +- Update READMEs with correct Node requirements (#994) + +## 3.1.1 +Wed, 04 Aug 2021 10:12:25 GMT + +### Updates + +- Bump tslib to 2.3.0 (#986) +- Bump typescript to 4.3.5 (#987) +- Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988) + +## 3.1.0 +Fri, 14 May 2021 10:45:32 GMT + +_Version update only_ + +## 3.0.3 +Wed, 21 Apr 2021 12:35:06 GMT + +_Version update only_ + +## 3.0.2 +Thu, 15 Apr 2021 21:07:39 GMT + +_Version update only_ + +## 3.0.1 +Wed, 14 Apr 2021 16:30:05 GMT + +### Updates + +- Add peerDependencies to plugins (#950) +- Mark packages as sideEffect: false (#951) +- Add unit tests to plugin track* functions (#954) + +## 3.0.0 +Wed, 31 Mar 2021 14:46:47 GMT + +### Updates + +- Bump rollup to 2.41 (#916) +- Publish UMD versions of plugins to GitHub release (#923) +- Ensure browser-tracker API methods catch exceptions (#919) +- Introduce TSDoc comments and extract interfaces where appropriate (#906) +- Bump major version to v3 and update READMEs (#904) +- Improve Core API for module bundlers which support treeshaking (#903) +- Rename @snowplow/browser-core to @snowplow/browser-tracker-core (#901) +- Publish lite version of sp.js (#900) +- Ensure correct 3-Clause BSD License notices are being used (#316) +- Improve API for module bundlers which support treeshaking (#899) +- Bump rush to 5.39 (#895) +- Port to TypeScript (#72) +- Make sp.js build process modular (#450) +- Create @snowplow/browser-tracker package for npm distribution (#541) +- Split auto contexts into plugins (#880) +- Add rush to manage monorepo (#883) +- Add ES Module builds (#882) +- Cleanup deprecated methods (#557) +- Update publishing process for rush (#907) +- Change white and black lists to allow and deny lists (#908) +- Create rush change files for major version 3 release (#909) + diff --git a/plugins/browser-plugin-ad-tracking/LICENSE b/plugins/browser-plugin-ad-tracking/LICENSE new file mode 100644 index 000000000..76f1946ea --- /dev/null +++ b/plugins/browser-plugin-ad-tracking/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/plugins/browser-plugin-ad-tracking/README.md b/plugins/browser-plugin-ad-tracking/README.md new file mode 100644 index 000000000..fc1c115e1 --- /dev/null +++ b/plugins/browser-plugin-ad-tracking/README.md @@ -0,0 +1,72 @@ +# Snowplow Advertising Tracking + +[![npm version][npm-image]][npm-url] +[![License][license-image]](LICENSE) + +Browser Plugin to be used with `@snowplow/browser-tracker`. + +Adds advertising based events to your Snowplow tracking. + +## Maintainer quick start + +Part of the Snowplow JavaScript Tracker monorepo. +Build with [Node.js](https://nodejs.org/en/) (18 - 20) and [Rush](https://rushjs.io/). + +### Setup repository + +```bash +npm install -g @microsoft/rush +git clone https://github.com/snowplow/snowplow-javascript-tracker.git +rush update +``` + +## Package Installation + +With npm: + +```bash +npm install @snowplow/browser-plugin-ad-tracking +``` + +## Usage + +Initialize your tracker with the AdTrackingPlugin: + +```js +import { newTracker } from '@snowplow/browser-tracker'; +import { AdTrackingPlugin } from '@snowplow/browser-plugin-ad-tracking'; + +newTracker('sp1', '{{collector}}', { plugins: [ AdTrackingPlugin() ] }); // Also stores reference at module level +``` + +Then use the `trackX` functions from this package to track to all trackers which have been initialized with this plugin: + +```js +import { trackAdClick } from '@snowplow/browser-plugin-ad-tracking'; + +trackAdClick({ + targetUrl: 'http://www.example.com', + clickId: '12243253', + costModel: 'cpm', + cost: 2.5, + bannerId: '23', + zoneId: '7', + impressionId: '67965967893', + advertiserId: '201', + campaignId: '12', +}); +``` + +## Copyright and license + +Licensed and distributed under the [BSD 3-Clause License](LICENSE) ([An OSI Approved License][osi]). + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang. + +All rights reserved. + +[npm-url]: https://www.npmjs.com/package/@snowplow/browser-plugin-ad-tracking +[npm-image]: https://img.shields.io/npm/v/@snowplow/browser-plugin-ad-tracking +[docs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-tracker/ +[osi]: https://opensource.org/licenses/BSD-3-Clause +[license-image]: https://img.shields.io/npm/l/@snowplow/browser-plugin-ad-tracking diff --git a/plugins/browser-plugin-ad-tracking/jest.config.js b/plugins/browser-plugin-ad-tracking/jest.config.js new file mode 100644 index 000000000..87d15da9b --- /dev/null +++ b/plugins/browser-plugin-ad-tracking/jest.config.js @@ -0,0 +1,6 @@ +module.exports = { + preset: 'ts-jest', + reporters: ['jest-standard-reporter'], + setupFilesAfterEnv: ['../../setupTestGlobals.ts'], + testEnvironment: 'jest-environment-jsdom-global', +}; diff --git a/plugins/browser-plugin-ad-tracking/package.json b/plugins/browser-plugin-ad-tracking/package.json new file mode 100644 index 000000000..b7c614b9b --- /dev/null +++ b/plugins/browser-plugin-ad-tracking/package.json @@ -0,0 +1,54 @@ +{ + "name": "@snowplow/browser-plugin-ad-tracking", + "version": "4.10.0", + "description": "Ad tracking for Snowplow", + "homepage": "http://bit.ly/sp-js", + "bugs": "https://github.com/snowplow/snowplow-javascript-tracker/issues", + "repository": { + "type": "git", + "url": "https://github.com/snowplow/snowplow-javascript-tracker.git" + }, + "license": "BSD-3-Clause", + "author": "Paul Boocock", + "sideEffects": false, + "main": "./dist/index.umd.js", + "module": "./dist/index.module.js", + "types": "./dist/index.module.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "rollup -c --silent --failAfterWarnings", + "test": "jest" + }, + "dependencies": { + "@snowplow/browser-tracker-core": "workspace:*", + "@snowplow/tracker-core": "workspace:*", + "tslib": "^2.3.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "~21.0.2", + "@rollup/plugin-node-resolve": "~13.1.3", + "@types/jest": "~28.1.1", + "@types/jsdom": "~16.2.14", + "@types/lodash": "~4.14.180", + "@typescript-eslint/eslint-plugin": "~5.15.0", + "@typescript-eslint/parser": "~5.15.0", + "eslint": "~8.11.0", + "jest": "~28.1.3", + "jest-environment-jsdom": "~28.1.3", + "jest-environment-jsdom-global": "~4.0.0", + "jest-standard-reporter": "~2.0.0", + "lodash": "~4.17.21", + "rollup": "~2.70.1", + "rollup-plugin-cleanup": "~3.2.1", + "rollup-plugin-license": "~2.6.1", + "rollup-plugin-terser": "~7.0.2", + "rollup-plugin-ts": "~2.0.5", + "ts-jest": "~28.0.8", + "typescript": "~4.6.2" + }, + "peerDependencies": { + "@snowplow/browser-tracker": "~4.10.0" + } +} diff --git a/plugins/browser-plugin-ad-tracking/rollup.config.js b/plugins/browser-plugin-ad-tracking/rollup.config.js new file mode 100644 index 000000000..ed975dc0b --- /dev/null +++ b/plugins/browser-plugin-ad-tracking/rollup.config.js @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import ts from 'rollup-plugin-ts'; // Prefered over @rollup/plugin-typescript as it bundles .d.ts files +import { banner } from '../../banner'; +import { terser } from 'rollup-plugin-terser'; +import cleanup from 'rollup-plugin-cleanup'; +import pkg from './package.json'; +import { builtinModules } from 'module'; + +const umdPlugins = [nodeResolve({ browser: true }), commonjs(), ts()]; +const umdName = 'snowplowAdTracking'; + +export default [ + // CommonJS (for Node) and ES module (for bundlers) build. + { + input: './src/index.ts', + plugins: [...umdPlugins, banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main, format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + plugins: [...umdPlugins, terser(), cleanup({ comments: 'none' }), banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main.replace('.js', '.min.js'), format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + external: [...builtinModules, ...Object.keys(pkg.dependencies), ...Object.keys(pkg.devDependencies)], + plugins: [ + ts(), // so Rollup can convert TypeScript to JavaScript + banner(), + ], + output: [{ file: pkg.module, format: 'es', sourcemap: true }], + }, +]; diff --git a/plugins/browser-plugin-ad-tracking/src/index.ts b/plugins/browser-plugin-ad-tracking/src/index.ts new file mode 100644 index 000000000..443a8e9c0 --- /dev/null +++ b/plugins/browser-plugin-ad-tracking/src/index.ts @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { BrowserPlugin, BrowserTracker, dispatchToTrackersInCollection } from '@snowplow/browser-tracker-core'; +import { + buildAdClick, + buildAdConversion, + buildAdImpression, + AdClickEvent, + AdImpressionEvent, + AdConversionEvent, + CommonEventProperties, +} from '@snowplow/tracker-core'; + +export { AdClickEvent, AdImpressionEvent, AdConversionEvent }; + +const _trackers: Record = {}; + +/** + * Adds advertisement tracking functions + */ +export function AdTrackingPlugin(): BrowserPlugin { + return { + activateBrowserPlugin: (tracker) => { + _trackers[tracker.id] = tracker; + }, + }; +} + +/** + * Track an ad being served + * + * @param event - The event information + * @param trackers - The tracker identifiers which the event will be sent to + */ +export function trackAdImpression( + event: AdImpressionEvent & CommonEventProperties, + trackers: Array = Object.keys(_trackers) +) { + dispatchToTrackersInCollection(trackers, _trackers, (t) => { + t.core.track(buildAdImpression(event), event.context, event.timestamp); + }); +} + +/** + * Track an ad being clicked + * + * @param event - The event information + * @param trackers - The tracker identifiers which the event will be sent to + */ +export function trackAdClick( + event: AdClickEvent & CommonEventProperties, + trackers: Array = Object.keys(_trackers) +) { + dispatchToTrackersInCollection(trackers, _trackers, (t) => { + t.core.track(buildAdClick(event), event.context, event.timestamp); + }); +} + +/** + * Track an ad conversion event + * + * @param event - The event information + * @param trackers - The tracker identifiers which the event will be sent to + */ +export function trackAdConversion( + event: AdConversionEvent & CommonEventProperties, + trackers: Array = Object.keys(_trackers) +) { + dispatchToTrackersInCollection(trackers, _trackers, (t) => { + t.core.track(buildAdConversion(event), event.context, event.timestamp); + }); +} diff --git a/plugins/browser-plugin-ad-tracking/test/events.test.ts b/plugins/browser-plugin-ad-tracking/test/events.test.ts new file mode 100644 index 000000000..98521c9fc --- /dev/null +++ b/plugins/browser-plugin-ad-tracking/test/events.test.ts @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { addTracker, SharedState } from '@snowplow/browser-tracker-core'; +import F from 'lodash/fp'; +import { AdTrackingPlugin, trackAdClick, trackAdConversion, trackAdImpression } from '../src'; +import { newInMemoryEventStore } from '@snowplow/tracker-core'; + +const getUEEvents = F.compose(F.filter(F.compose(F.eq('ue'), F.get('e')))); +const extractEventProperties = F.map(F.compose(F.get('data'), (cx: string) => JSON.parse(cx), F.get('ue_pr'))); +const extractUeEvent = (schema: string) => { + return { + from: F.compose( + F.first, + F.filter(F.compose(F.eq(schema), F.get('schema'))), + F.flatten, + extractEventProperties, + getUEEvents + ), + }; +}; + +describe('AdTrackingPlugin', () => { + const state = new SharedState(); + let eventStore = newInMemoryEventStore({}); + const customFetch = async () => new Response(null, { status: 500 }); + + addTracker('sp1', 'sp1', 'js-3.0.0', '', state, { + stateStorageStrategy: 'cookie', + encodeBase64: false, + plugins: [AdTrackingPlugin()], + eventStore, + customFetch, + }); + + it('trackAdClick adds the expected ad click event to the queue', async () => { + trackAdClick({ + targetUrl: 'https://www.snowplowanalytics.com', + bannerId: 'banner-1', + advertiserId: 'advertiser-1', + campaignId: 'campaign-1', + clickId: 'click-1', + impressionId: 'impression-1', + cost: 0.01, + costModel: 'cpa', + zoneId: 'zone-1', + }); + + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/ad_click/jsonschema/1-0-0').from( + await eventStore.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/ad_click/jsonschema/1-0-0', + data: { + targetUrl: 'https://www.snowplowanalytics.com', + bannerId: 'banner-1', + advertiserId: 'advertiser-1', + campaignId: 'campaign-1', + clickId: 'click-1', + impressionId: 'impression-1', + cost: 0.01, + costModel: 'cpa', + zoneId: 'zone-1', + }, + }); + }); + + it('trackAdConversion adds the expected ad conversion event to the queue', async () => { + trackAdConversion({ + action: 'action', + advertiserId: 'advertiser-1', + campaignId: 'campaign-1', + category: 'category', + conversionId: 'conversion-1', + cost: 0.02, + costModel: 'cpc', + initialValue: 10, + property: 'property', + }); + + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/ad_conversion/jsonschema/1-0-0').from( + await eventStore.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/ad_conversion/jsonschema/1-0-0', + data: { + action: 'action', + advertiserId: 'advertiser-1', + campaignId: 'campaign-1', + category: 'category', + conversionId: 'conversion-1', + cost: 0.02, + costModel: 'cpc', + initialValue: 10, + property: 'property', + }, + }); + }); + + it('trackAdImpression adds the expected ad impression event to the queue', async () => { + trackAdImpression({ + advertiserId: 'advrtiser-1', + bannerId: 'banner-1', + campaignId: 'campaign-1', + cost: 0.03, + costModel: 'cpm', + impressionId: 'impression-1', + targetUrl: 'https://snowplowanalytics.com', + zoneId: 'zone-1', + }); + + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/ad_impression/jsonschema/1-0-0').from( + await eventStore.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/ad_impression/jsonschema/1-0-0', + data: { + advertiserId: 'advrtiser-1', + bannerId: 'banner-1', + campaignId: 'campaign-1', + cost: 0.03, + costModel: 'cpm', + impressionId: 'impression-1', + targetUrl: 'https://snowplowanalytics.com', + zoneId: 'zone-1', + }, + }); + }); +}); diff --git a/plugins/browser-plugin-ad-tracking/tsconfig.json b/plugins/browser-plugin-ad-tracking/tsconfig.json new file mode 100644 index 000000000..4082f16a5 --- /dev/null +++ b/plugins/browser-plugin-ad-tracking/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +} diff --git a/plugins/browser-plugin-bot-detection/CHANGELOG.json b/plugins/browser-plugin-bot-detection/CHANGELOG.json new file mode 100644 index 000000000..fa527b37d --- /dev/null +++ b/plugins/browser-plugin-bot-detection/CHANGELOG.json @@ -0,0 +1,65 @@ +{ + "name": "@snowplow/browser-plugin-bot-detection", + "entries": [ + { + "version": "4.10.0", + "tag": "@snowplow/browser-plugin-bot-detection_v4.10.0", + "date": "Mon, 27 Jul 2026 13:52:14 GMT", + "comments": {} + }, + { + "version": "4.9.0", + "tag": "@snowplow/browser-plugin-bot-detection_v4.9.0", + "date": "Tue, 21 Jul 2026 14:53:08 GMT", + "comments": {} + }, + { + "version": "4.8.4", + "tag": "@snowplow/browser-plugin-bot-detection_v4.8.4", + "date": "Thu, 02 Jul 2026 10:07:52 GMT", + "comments": {} + }, + { + "version": "4.8.3", + "tag": "@snowplow/browser-plugin-bot-detection_v4.8.3", + "date": "Tue, 30 Jun 2026 14:22:03 GMT", + "comments": { + "none": [ + { + "comment": "Update uuid to v11 and remove closure-compiler from the build pipeline" + } + ] + } + }, + { + "version": "4.8.2", + "tag": "@snowplow/browser-plugin-bot-detection_v4.8.2", + "date": "Wed, 17 Jun 2026 12:30:12 GMT", + "comments": {} + }, + { + "version": "4.8.1", + "tag": "@snowplow/browser-plugin-bot-detection_v4.8.1", + "date": "Wed, 13 May 2026 09:26:05 GMT", + "comments": {} + }, + { + "version": "4.8.0", + "tag": "@snowplow/browser-plugin-bot-detection_v4.8.0", + "date": "Tue, 28 Apr 2026 07:56:22 GMT", + "comments": {} + }, + { + "version": "4.7.0", + "tag": "@snowplow/browser-plugin-bot-detection_v4.7.0", + "date": "Wed, 01 Apr 2026 12:59:29 GMT", + "comments": { + "minor": [ + { + "comment": "Add browser-plugin-bot-detection plugin wrapping FingerprintJS BotD for client-side bot detection" + } + ] + } + } + ] +} diff --git a/plugins/browser-plugin-bot-detection/CHANGELOG.md b/plugins/browser-plugin-bot-detection/CHANGELOG.md new file mode 100644 index 000000000..c39461923 --- /dev/null +++ b/plugins/browser-plugin-bot-detection/CHANGELOG.md @@ -0,0 +1,48 @@ +# Change Log - @snowplow/browser-plugin-bot-detection + +This log was last generated on Mon, 27 Jul 2026 13:52:14 GMT and should not be manually modified. + +## 4.10.0 +Mon, 27 Jul 2026 13:52:14 GMT + +_Version update only_ + +## 4.9.0 +Tue, 21 Jul 2026 14:53:08 GMT + +_Version update only_ + +## 4.8.4 +Thu, 02 Jul 2026 10:07:52 GMT + +_Version update only_ + +## 4.8.3 +Tue, 30 Jun 2026 14:22:03 GMT + +### Updates + +- Update uuid to v11 and remove closure-compiler from the build pipeline + +## 4.8.2 +Wed, 17 Jun 2026 12:30:12 GMT + +_Version update only_ + +## 4.8.1 +Wed, 13 May 2026 09:26:05 GMT + +_Version update only_ + +## 4.8.0 +Tue, 28 Apr 2026 07:56:22 GMT + +_Version update only_ + +## 4.7.0 +Wed, 01 Apr 2026 12:59:29 GMT + +### Minor changes + +- Add browser-plugin-bot-detection plugin wrapping FingerprintJS BotD for client-side bot detection + diff --git a/plugins/browser-plugin-bot-detection/LICENSE b/plugins/browser-plugin-bot-detection/LICENSE new file mode 100644 index 000000000..76f1946ea --- /dev/null +++ b/plugins/browser-plugin-bot-detection/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/plugins/browser-plugin-bot-detection/README.md b/plugins/browser-plugin-bot-detection/README.md new file mode 100644 index 000000000..6a30a4f0a --- /dev/null +++ b/plugins/browser-plugin-bot-detection/README.md @@ -0,0 +1,59 @@ +# Snowplow Bot Detection + +[![npm version][npm-image]][npm-url] +[![License][license-image]](LICENSE) + +Browser Plugin to be used with `@snowplow/browser-tracker`. + +Detects bots client-side using [FingerprintJS BotD](https://github.com/fingerprintjs/BotD) and attaches the result as a `client_side_bot_detection` context entity to all tracked events. + +## Maintainer quick start + +Part of the Snowplow JavaScript Tracker monorepo. +Build with [Node.js](https://nodejs.org/en/) (18 - 20) and [Rush](https://rushjs.io/). + +### Setup repository + +```bash +npm install -g @microsoft/rush +git clone https://github.com/snowplow/snowplow-javascript-tracker.git +rush update +``` + +## Package Installation + +With npm: + +```bash +npm install @snowplow/browser-plugin-bot-detection +``` + +## Usage + +Initialize your tracker with the BotDetectionPlugin: + +```js +import { newTracker } from '@snowplow/browser-tracker'; +import { BotDetectionPlugin } from '@snowplow/browser-plugin-bot-detection'; + +newTracker('sp1', '{{collector}}', { plugins: [ BotDetectionPlugin() ] }); +``` + +Once detection completes, a `client_side_bot_detection` context entity will be attached to all subsequent events with the following fields: + +- `bot` (boolean): Whether a bot was detected. +- `kind` (string | null): The type of bot detected (e.g. `"selenium"`, `"phantomjs"`), or `null` if no bot was found. + +## Copyright and license + +Licensed and distributed under the [BSD 3-Clause License](LICENSE) ([An OSI Approved License][osi]). + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang. + +All rights reserved. + +[npm-url]: https://www.npmjs.com/package/@snowplow/browser-plugin-bot-detection +[npm-image]: https://img.shields.io/npm/v/@snowplow/browser-plugin-bot-detection +[docs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-tracker/ +[osi]: https://opensource.org/licenses/BSD-3-Clause +[license-image]: https://img.shields.io/npm/l/@snowplow/browser-plugin-bot-detection diff --git a/plugins/browser-plugin-bot-detection/jest.config.js b/plugins/browser-plugin-bot-detection/jest.config.js new file mode 100644 index 000000000..87d15da9b --- /dev/null +++ b/plugins/browser-plugin-bot-detection/jest.config.js @@ -0,0 +1,6 @@ +module.exports = { + preset: 'ts-jest', + reporters: ['jest-standard-reporter'], + setupFilesAfterEnv: ['../../setupTestGlobals.ts'], + testEnvironment: 'jest-environment-jsdom-global', +}; diff --git a/plugins/browser-plugin-bot-detection/package.json b/plugins/browser-plugin-bot-detection/package.json new file mode 100644 index 000000000..2caced45d --- /dev/null +++ b/plugins/browser-plugin-bot-detection/package.json @@ -0,0 +1,53 @@ +{ + "name": "@snowplow/browser-plugin-bot-detection", + "version": "4.10.0", + "description": "Detects bots client-side using FingerprintJS BotD and attaches the result as a context entity.", + "homepage": "https://github.com/snowplow/snowplow-javascript-tracker", + "bugs": "https://github.com/snowplow/snowplow-javascript-tracker/issues", + "repository": { + "type": "git", + "url": "https://github.com/snowplow/snowplow-javascript-tracker.git" + }, + "license": "BSD-3-Clause", + "author": "Snowplow Analytics Ltd (https://snowplow.io/)", + "sideEffects": false, + "main": "./dist/index.umd.js", + "module": "./dist/index.module.js", + "types": "./dist/index.module.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "rollup -c --silent --failAfterWarnings", + "test": "jest" + }, + "dependencies": { + "@fingerprintjs/botd": "2.0.0", + "@snowplow/browser-tracker-core": "workspace:*", + "@snowplow/tracker-core": "workspace:*", + "tslib": "^2.3.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "~21.0.2", + "@rollup/plugin-node-resolve": "~13.1.3", + "@types/jest": "~28.1.1", + "@types/jsdom": "~16.2.14", + "@typescript-eslint/eslint-plugin": "~5.15.0", + "@typescript-eslint/parser": "~5.15.0", + "eslint": "~8.11.0", + "jest": "~28.1.3", + "jest-environment-jsdom": "~28.1.3", + "jest-environment-jsdom-global": "~4.0.0", + "jest-standard-reporter": "~2.0.0", + "rollup": "~2.70.1", + "rollup-plugin-cleanup": "~3.2.1", + "rollup-plugin-license": "~2.6.1", + "rollup-plugin-terser": "~7.0.2", + "rollup-plugin-ts": "~2.0.5", + "ts-jest": "~28.0.8", + "typescript": "~4.6.2" + }, + "peerDependencies": { + "@snowplow/browser-tracker": "~4.10.0" + } +} diff --git a/plugins/browser-plugin-bot-detection/rollup.config.js b/plugins/browser-plugin-bot-detection/rollup.config.js new file mode 100644 index 000000000..f9d815c79 --- /dev/null +++ b/plugins/browser-plugin-bot-detection/rollup.config.js @@ -0,0 +1,36 @@ +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import ts from 'rollup-plugin-ts'; // Preferred over @rollup/plugin-typescript as it bundles .d.ts files +import { banner } from '../../banner'; +import { terser } from 'rollup-plugin-terser'; +import cleanup from 'rollup-plugin-cleanup'; +import pkg from './package.json'; +import { builtinModules } from 'module'; + +const umdPlugins = [nodeResolve({ browser: true }), commonjs(), ts()]; +const umdName = 'snowplowBotDetection'; + +export default [ + // CommonJS (for Node) and ES module (for bundlers) build. + { + input: './src/index.ts', + plugins: [...umdPlugins, banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main, format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + plugins: [...umdPlugins, terser(), cleanup({ comments: 'none' }), banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main.replace('.js', '.min.js'), format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + external: [...builtinModules, ...Object.keys(pkg.dependencies), ...Object.keys(pkg.devDependencies)], + plugins: [ + ts(), // so Rollup can convert TypeScript to JavaScript + banner(), + ], + output: [{ file: pkg.module, format: 'es', sourcemap: true }], + }, +]; diff --git a/plugins/browser-plugin-bot-detection/src/index.ts b/plugins/browser-plugin-bot-detection/src/index.ts new file mode 100644 index 000000000..966c4f356 --- /dev/null +++ b/plugins/browser-plugin-bot-detection/src/index.ts @@ -0,0 +1,32 @@ +import { BrowserPlugin } from '@snowplow/browser-tracker-core'; +import { LOG } from '@snowplow/tracker-core'; +import { load } from '@fingerprintjs/botd'; +import { CLIENT_SIDE_BOT_DETECTION_SCHEMA } from './schemata'; +import { BotDetectionContextData } from './types'; + +export { BotDetectionContextData, BotKind } from './types'; + +let contextData: BotDetectionContextData | undefined; +let detectionStarted = false; + +export function BotDetectionPlugin(): BrowserPlugin { + return { + activateBrowserPlugin: () => { + if (!detectionStarted) { + detectionStarted = true; + load() + .then((detector) => detector.detect()) + .then((result) => { + contextData = result.bot ? { bot: true, kind: result.botKind } : { bot: false, kind: null }; + }) + .catch((err) => LOG.error('BotDetectionPlugin: BotD load/detect failed', err)); + } + }, + contexts: () => { + if (contextData) { + return [{ schema: CLIENT_SIDE_BOT_DETECTION_SCHEMA, data: contextData }]; + } + return []; + }, + }; +} diff --git a/plugins/browser-plugin-bot-detection/src/schemata.ts b/plugins/browser-plugin-bot-detection/src/schemata.ts new file mode 100644 index 000000000..af05d9f6a --- /dev/null +++ b/plugins/browser-plugin-bot-detection/src/schemata.ts @@ -0,0 +1,2 @@ +export const CLIENT_SIDE_BOT_DETECTION_SCHEMA = + 'iglu:com.snowplowanalytics.snowplow/client_side_bot_detection/jsonschema/1-0-0'; diff --git a/plugins/browser-plugin-bot-detection/src/types.ts b/plugins/browser-plugin-bot-detection/src/types.ts new file mode 100644 index 000000000..f374b478d --- /dev/null +++ b/plugins/browser-plugin-bot-detection/src/types.ts @@ -0,0 +1,25 @@ +export type BotKind = + | 'awesomium' + | 'cef' + | 'cefsharp' + | 'coachjs' + | 'electron' + | 'fminer' + | 'geb' + | 'nightmarejs' + | 'phantomas' + | 'phantomjs' + | 'rhino' + | 'selenium' + | 'sequentum' + | 'slimerjs' + | 'webdriverio' + | 'webdriver' + | 'headless_chrome' + | 'unknown'; + +export interface BotDetectionContextData { + [key: string]: unknown; + bot: boolean; + kind: BotKind | null; +} diff --git a/plugins/browser-plugin-bot-detection/test/bot-detection.test.ts b/plugins/browser-plugin-bot-detection/test/bot-detection.test.ts new file mode 100644 index 000000000..7b6885879 --- /dev/null +++ b/plugins/browser-plugin-bot-detection/test/bot-detection.test.ts @@ -0,0 +1,149 @@ +import { buildLinkClick, trackerCore } from '@snowplow/tracker-core'; +import { BrowserTracker } from '@snowplow/browser-tracker-core'; +import { setImmediate } from 'timers'; + +const flushPromises = () => new Promise(setImmediate); + +let mockDetectResult: any = { bot: false }; +let mockLoadReject: Error | null = null; +let mockDetectReject: Error | null = null; + +jest.mock('@fingerprintjs/botd', () => ({ + load: () => { + if (mockLoadReject) { + return Promise.reject(mockLoadReject); + } + return Promise.resolve({ + detect: () => { + if (mockDetectReject) { + return Promise.reject(mockDetectReject); + } + return Promise.resolve(mockDetectResult); + }, + }); + }, +})); + +describe('BotDetectionPlugin', () => { + beforeEach(() => { + jest.resetModules(); + mockDetectResult = { bot: false }; + mockLoadReject = null; + mockDetectReject = null; + }); + + it('attaches bot context when a bot is detected', async () => { + mockDetectResult = { bot: true, botKind: 'selenium' }; + + const { BotDetectionPlugin } = require('../src'); + const plugin = BotDetectionPlugin(); + + const core = trackerCore({ + corePlugins: [plugin], + callback: (payloadBuilder) => { + const json = payloadBuilder.getJson().filter((e) => e.keyIfEncoded === 'cx'); + const contexts = json[0]?.json; + expect(contexts).toEqual({ + schema: 'iglu:com.snowplowanalytics.snowplow/contexts/jsonschema/1-0-0', + data: [ + { + schema: 'iglu:com.snowplowanalytics.snowplow/client_side_bot_detection/jsonschema/1-0-0', + data: { bot: true, kind: 'selenium' }, + }, + ], + }); + }, + }); + + plugin.activateBrowserPlugin?.({ core } as BrowserTracker); + await flushPromises(); + + core.track(buildLinkClick({ targetUrl: 'https://example.com' })); + }); + + it('attaches no-bot context when no bot is detected', async () => { + mockDetectResult = { bot: false }; + + const { BotDetectionPlugin } = require('../src'); + const plugin = BotDetectionPlugin(); + + const core = trackerCore({ + corePlugins: [plugin], + callback: (payloadBuilder) => { + const json = payloadBuilder.getJson().filter((e) => e.keyIfEncoded === 'cx'); + const contexts = json[0]?.json; + expect(contexts).toEqual({ + schema: 'iglu:com.snowplowanalytics.snowplow/contexts/jsonschema/1-0-0', + data: [ + { + schema: 'iglu:com.snowplowanalytics.snowplow/client_side_bot_detection/jsonschema/1-0-0', + data: { bot: false, kind: null }, + }, + ], + }); + }, + }); + + plugin.activateBrowserPlugin?.({ core } as BrowserTracker); + await flushPromises(); + + core.track(buildLinkClick({ targetUrl: 'https://example.com' })); + }); + + it('returns empty contexts while detection is pending', () => { + const { BotDetectionPlugin } = require('../src'); + const plugin = BotDetectionPlugin(); + + const core = trackerCore({ + corePlugins: [plugin], + callback: (payloadBuilder) => { + const json = payloadBuilder.getJson().filter((e) => e.keyIfEncoded === 'cx'); + expect(json).toHaveLength(0); + }, + }); + + plugin.activateBrowserPlugin?.({ core } as BrowserTracker); + // Do NOT await — detection is still pending + core.track(buildLinkClick({ targetUrl: 'https://example.com' })); + }); + + it('returns empty contexts when load() fails', async () => { + mockLoadReject = new Error('load failed'); + + const { BotDetectionPlugin } = require('../src'); + const plugin = BotDetectionPlugin(); + + const core = trackerCore({ + corePlugins: [plugin], + callback: (payloadBuilder) => { + const json = payloadBuilder.getJson().filter((e) => e.keyIfEncoded === 'cx'); + expect(json).toHaveLength(0); + }, + }); + + plugin.activateBrowserPlugin?.({ core } as BrowserTracker); + await flushPromises(); + + core.track(buildLinkClick({ targetUrl: 'https://example.com' })); + }); + + it('returns empty contexts when detect() fails', async () => { + mockDetectReject = new Error('detect failed'); + + const { BotDetectionPlugin } = require('../src'); + const plugin = BotDetectionPlugin(); + + const core = trackerCore({ + corePlugins: [plugin], + callback: (payloadBuilder) => { + const json = payloadBuilder.getJson().filter((e) => e.keyIfEncoded === 'cx'); + expect(json).toHaveLength(0); + }, + }); + + plugin.activateBrowserPlugin?.({ core } as BrowserTracker); + await flushPromises(); + + core.track(buildLinkClick({ targetUrl: 'https://example.com' })); + }); +}); diff --git a/plugins/browser-plugin-bot-detection/tsconfig.json b/plugins/browser-plugin-bot-detection/tsconfig.json new file mode 100644 index 000000000..4082f16a5 --- /dev/null +++ b/plugins/browser-plugin-bot-detection/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +} diff --git a/plugins/browser-plugin-button-click-tracking/CHANGELOG.json b/plugins/browser-plugin-button-click-tracking/CHANGELOG.json new file mode 100644 index 000000000..ba033f0d0 --- /dev/null +++ b/plugins/browser-plugin-button-click-tracking/CHANGELOG.json @@ -0,0 +1,317 @@ +{ + "name": "@snowplow/browser-plugin-button-click-tracking", + "entries": [ + { + "version": "4.10.0", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.10.0", + "date": "Mon, 27 Jul 2026 13:52:14 GMT", + "comments": {} + }, + { + "version": "4.9.0", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.9.0", + "date": "Tue, 21 Jul 2026 14:53:08 GMT", + "comments": {} + }, + { + "version": "4.8.4", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.8.4", + "date": "Thu, 02 Jul 2026 10:07:52 GMT", + "comments": {} + }, + { + "version": "4.8.3", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.8.3", + "date": "Tue, 30 Jun 2026 14:22:03 GMT", + "comments": { + "none": [ + { + "comment": "Update uuid to v11 and remove closure-compiler from the build pipeline" + } + ] + } + }, + { + "version": "4.8.2", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.8.2", + "date": "Wed, 17 Jun 2026 12:30:12 GMT", + "comments": {} + }, + { + "version": "4.8.1", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.8.1", + "date": "Wed, 13 May 2026 09:26:05 GMT", + "comments": {} + }, + { + "version": "4.8.0", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.8.0", + "date": "Tue, 28 Apr 2026 07:56:22 GMT", + "comments": {} + }, + { + "version": "4.7.0", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.7.0", + "date": "Wed, 01 Apr 2026 12:59:29 GMT", + "comments": {} + }, + { + "version": "4.6.9", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.6.9", + "date": "Mon, 16 Mar 2026 15:43:06 GMT", + "comments": {} + }, + { + "version": "4.6.8", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.6.8", + "date": "Tue, 28 Oct 2025 09:46:42 GMT", + "comments": {} + }, + { + "version": "4.6.7", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.6.7", + "date": "Tue, 07 Oct 2025 14:53:36 GMT", + "comments": {} + }, + { + "version": "4.6.6", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.6.6", + "date": "Tue, 26 Aug 2025 08:42:27 GMT", + "comments": {} + }, + { + "version": "4.6.5", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.6.5", + "date": "Wed, 25 Jun 2025 21:16:46 GMT", + "comments": {} + }, + { + "version": "4.6.4", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.6.4", + "date": "Wed, 25 Jun 2025 12:08:50 GMT", + "comments": {} + }, + { + "version": "4.6.3", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.6.3", + "date": "Thu, 29 May 2025 19:52:07 GMT", + "comments": {} + }, + { + "version": "4.6.2", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.6.2", + "date": "Tue, 20 May 2025 07:39:05 GMT", + "comments": {} + }, + { + "version": "4.6.1", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.6.1", + "date": "Tue, 06 May 2025 13:10:51 GMT", + "comments": {} + }, + { + "version": "4.6.0", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.6.0", + "date": "Thu, 01 May 2025 09:58:59 GMT", + "comments": {} + }, + { + "version": "4.5.0", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.5.0", + "date": "Fri, 04 Apr 2025 09:21:23 GMT", + "comments": { + "none": [ + { + "comment": "Allow per-tracker disabling" + }, + { + "comment": "Add default label to avoid bad events" + } + ] + } + }, + { + "version": "4.4.0", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.4.0", + "date": "Thu, 20 Mar 2025 12:14:34 GMT", + "comments": {} + }, + { + "version": "4.3.1", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.3.1", + "date": "Tue, 21 Jan 2025 11:09:42 GMT", + "comments": {} + }, + { + "version": "4.3.0", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.3.0", + "date": "Mon, 20 Jan 2025 11:45:13 GMT", + "comments": {} + }, + { + "version": "4.2.0", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.2.0", + "date": "Mon, 13 Jan 2025 08:30:05 GMT", + "comments": {} + }, + { + "version": "4.1.0", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.1.0", + "date": "Thu, 28 Nov 2024 10:57:30 GMT", + "comments": { + "none": [ + { + "comment": "Pass clicked element to dynamic context functions for button click tracking plugin (#1368)" + } + ] + } + }, + { + "version": "4.0.4", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.0.4", + "date": "Thu, 21 Nov 2024 09:06:36 GMT", + "comments": {} + }, + { + "version": "4.0.3", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.0.3", + "date": "Wed, 20 Nov 2024 09:30:31 GMT", + "comments": {} + }, + { + "version": "4.0.2", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.0.2", + "date": "Mon, 11 Nov 2024 15:46:33 GMT", + "comments": {} + }, + { + "version": "4.0.1", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.0.1", + "date": "Fri, 01 Nov 2024 10:35:07 GMT", + "comments": {} + }, + { + "version": "4.0.0", + "tag": "@snowplow/browser-plugin-button-click-tracking_v4.0.0", + "date": "Mon, 28 Oct 2024 11:48:53 GMT", + "comments": { + "none": [ + { + "comment": "Use capture-phase event listeners" + }, + { + "comment": "Detect button clicks within ShadowRoots" + } + ] + } + }, + { + "version": "3.24.6", + "tag": "@snowplow/browser-plugin-button-click-tracking_v3.24.6", + "date": "Mon, 28 Oct 2024 10:23:28 GMT", + "comments": {} + }, + { + "version": "3.24.5", + "tag": "@snowplow/browser-plugin-button-click-tracking_v3.24.5", + "date": "Fri, 25 Oct 2024 08:53:04 GMT", + "comments": {} + }, + { + "version": "3.24.4", + "tag": "@snowplow/browser-plugin-button-click-tracking_v3.24.4", + "date": "Thu, 26 Sep 2024 06:10:22 GMT", + "comments": {} + }, + { + "version": "3.24.3", + "tag": "@snowplow/browser-plugin-button-click-tracking_v3.24.3", + "date": "Tue, 03 Sep 2024 08:15:14 GMT", + "comments": { + "none": [ + { + "comment": "Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush" + } + ] + } + }, + { + "version": "3.24.2", + "tag": "@snowplow/browser-plugin-button-click-tracking_v3.24.2", + "date": "Wed, 24 Jul 2024 08:59:00 GMT", + "comments": {} + }, + { + "version": "3.24.1", + "tag": "@snowplow/browser-plugin-button-click-tracking_v3.24.1", + "date": "Tue, 02 Jul 2024 07:08:17 GMT", + "comments": {} + }, + { + "version": "3.24.0", + "tag": "@snowplow/browser-plugin-button-click-tracking_v3.24.0", + "date": "Tue, 25 Jun 2024 08:31:05 GMT", + "comments": {} + }, + { + "version": "3.23.1", + "tag": "@snowplow/browser-plugin-button-click-tracking_v3.23.1", + "date": "Tue, 04 Jun 2024 13:34:45 GMT", + "comments": {} + }, + { + "version": "3.23.0", + "tag": "@snowplow/browser-plugin-button-click-tracking_v3.23.0", + "date": "Thu, 28 Mar 2024 11:28:45 GMT", + "comments": {} + }, + { + "version": "3.22.1", + "tag": "@snowplow/browser-plugin-button-click-tracking_v3.22.1", + "date": "Wed, 13 Mar 2024 08:39:48 GMT", + "comments": {} + }, + { + "version": "3.22.0", + "tag": "@snowplow/browser-plugin-button-click-tracking_v3.22.0", + "date": "Fri, 08 Mar 2024 08:13:04 GMT", + "comments": {} + }, + { + "version": "3.21.0", + "tag": "@snowplow/browser-plugin-button-click-tracking_v3.21.0", + "date": "Mon, 29 Jan 2024 08:34:06 GMT", + "comments": {} + }, + { + "version": "3.20.0", + "tag": "@snowplow/browser-plugin-button-click-tracking_v3.20.0", + "date": "Mon, 15 Jan 2024 14:41:16 GMT", + "comments": { + "none": [ + { + "comment": "Support clicks on child elements in button click tracking (#1280)" + } + ] + } + }, + { + "version": "3.19.0", + "tag": "@snowplow/browser-plugin-button-click-tracking_v3.19.0", + "date": "Thu, 14 Dec 2023 10:45:22 GMT", + "comments": {} + }, + { + "version": "3.18.0", + "tag": "@snowplow/browser-plugin-button-click-tracking_v3.18.0", + "date": "Mon, 04 Dec 2023 13:44:02 GMT", + "comments": { + "none": [ + { + "comment": "Add Button Click tracking plugin (close #1267)" + } + ] + } + } + ] +} diff --git a/plugins/browser-plugin-button-click-tracking/CHANGELOG.md b/plugins/browser-plugin-button-click-tracking/CHANGELOG.md new file mode 100644 index 000000000..1e4620f31 --- /dev/null +++ b/plugins/browser-plugin-button-click-tracking/CHANGELOG.md @@ -0,0 +1,240 @@ +# Change Log - @snowplow/browser-plugin-button-click-tracking + +This log was last generated on Mon, 27 Jul 2026 13:52:14 GMT and should not be manually modified. + +## 4.10.0 +Mon, 27 Jul 2026 13:52:14 GMT + +_Version update only_ + +## 4.9.0 +Tue, 21 Jul 2026 14:53:08 GMT + +_Version update only_ + +## 4.8.4 +Thu, 02 Jul 2026 10:07:52 GMT + +_Version update only_ + +## 4.8.3 +Tue, 30 Jun 2026 14:22:03 GMT + +### Updates + +- Update uuid to v11 and remove closure-compiler from the build pipeline + +## 4.8.2 +Wed, 17 Jun 2026 12:30:12 GMT + +_Version update only_ + +## 4.8.1 +Wed, 13 May 2026 09:26:05 GMT + +_Version update only_ + +## 4.8.0 +Tue, 28 Apr 2026 07:56:22 GMT + +_Version update only_ + +## 4.7.0 +Wed, 01 Apr 2026 12:59:29 GMT + +_Version update only_ + +## 4.6.9 +Mon, 16 Mar 2026 15:43:06 GMT + +_Version update only_ + +## 4.6.8 +Tue, 28 Oct 2025 09:46:42 GMT + +_Version update only_ + +## 4.6.7 +Tue, 07 Oct 2025 14:53:36 GMT + +_Version update only_ + +## 4.6.6 +Tue, 26 Aug 2025 08:42:27 GMT + +_Version update only_ + +## 4.6.5 +Wed, 25 Jun 2025 21:16:46 GMT + +_Version update only_ + +## 4.6.4 +Wed, 25 Jun 2025 12:08:50 GMT + +_Version update only_ + +## 4.6.3 +Thu, 29 May 2025 19:52:07 GMT + +_Version update only_ + +## 4.6.2 +Tue, 20 May 2025 07:39:05 GMT + +_Version update only_ + +## 4.6.1 +Tue, 06 May 2025 13:10:51 GMT + +_Version update only_ + +## 4.6.0 +Thu, 01 May 2025 09:58:59 GMT + +_Version update only_ + +## 4.5.0 +Fri, 04 Apr 2025 09:21:23 GMT + +### Updates + +- Allow per-tracker disabling +- Add default label to avoid bad events + +## 4.4.0 +Thu, 20 Mar 2025 12:14:34 GMT + +_Version update only_ + +## 4.3.1 +Tue, 21 Jan 2025 11:09:42 GMT + +_Version update only_ + +## 4.3.0 +Mon, 20 Jan 2025 11:45:13 GMT + +_Version update only_ + +## 4.2.0 +Mon, 13 Jan 2025 08:30:05 GMT + +_Version update only_ + +## 4.1.0 +Thu, 28 Nov 2024 10:57:30 GMT + +### Updates + +- Pass clicked element to dynamic context functions for button click tracking plugin (#1368) + +## 4.0.4 +Thu, 21 Nov 2024 09:06:36 GMT + +_Version update only_ + +## 4.0.3 +Wed, 20 Nov 2024 09:30:31 GMT + +_Version update only_ + +## 4.0.2 +Mon, 11 Nov 2024 15:46:33 GMT + +_Version update only_ + +## 4.0.1 +Fri, 01 Nov 2024 10:35:07 GMT + +_Version update only_ + +## 4.0.0 +Mon, 28 Oct 2024 11:48:53 GMT + +### Updates + +- Use capture-phase event listeners +- Detect button clicks within ShadowRoots + +## 3.24.6 +Mon, 28 Oct 2024 10:23:28 GMT + +_Version update only_ + +## 3.24.5 +Fri, 25 Oct 2024 08:53:04 GMT + +_Version update only_ + +## 3.24.4 +Thu, 26 Sep 2024 06:10:22 GMT + +_Version update only_ + +## 3.24.3 +Tue, 03 Sep 2024 08:15:14 GMT + +### Updates + +- Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush + +## 3.24.2 +Wed, 24 Jul 2024 08:59:00 GMT + +_Version update only_ + +## 3.24.1 +Tue, 02 Jul 2024 07:08:17 GMT + +_Version update only_ + +## 3.24.0 +Tue, 25 Jun 2024 08:31:05 GMT + +_Version update only_ + +## 3.23.1 +Tue, 04 Jun 2024 13:34:45 GMT + +_Version update only_ + +## 3.23.0 +Thu, 28 Mar 2024 11:28:45 GMT + +_Version update only_ + +## 3.22.1 +Wed, 13 Mar 2024 08:39:48 GMT + +_Version update only_ + +## 3.22.0 +Fri, 08 Mar 2024 08:13:04 GMT + +_Version update only_ + +## 3.21.0 +Mon, 29 Jan 2024 08:34:06 GMT + +_Version update only_ + +## 3.20.0 +Mon, 15 Jan 2024 14:41:16 GMT + +### Updates + +- Support clicks on child elements in button click tracking (#1280) + +## 3.19.0 +Thu, 14 Dec 2023 10:45:22 GMT + +_Version update only_ + +## 3.18.0 +Mon, 04 Dec 2023 13:44:02 GMT + +### Updates + +- Add Button Click tracking plugin (close #1267) + diff --git a/plugins/browser-plugin-button-click-tracking/LICENSE b/plugins/browser-plugin-button-click-tracking/LICENSE new file mode 100644 index 000000000..a311732d5 --- /dev/null +++ b/plugins/browser-plugin-button-click-tracking/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2023 Snowplow Analytics Ltd, 2010 Anthon Pang +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/plugins/browser-plugin-button-click-tracking/README.md b/plugins/browser-plugin-button-click-tracking/README.md new file mode 100644 index 000000000..1517ac2fa --- /dev/null +++ b/plugins/browser-plugin-button-click-tracking/README.md @@ -0,0 +1,63 @@ +# Snowplow Button Click Tracking + +[![npm version][npm-image]][npm-url] +[![License][license-image]](LICENSE) + +Browser Plugin to be used with `@snowplow/browser-tracker`. + +Adds button click tracking events to your Snowplow tracking. + +## Maintainer quick start + +Part of the Snowplow JavaScript Tracker monorepo. +Build with [Node.js](https://nodejs.org/en/) (18 - 20) and [Rush](https://rushjs.io/). + +### Setup repository + +```bash +npm install -g @microsoft/rush +git clone https://github.com/snowplow/snowplow-javascript-tracker.git +rush update +``` + +## Package Installation + +With npm: + +```bash +npm install @snowplow/browser-plugin-button-click-tracking +``` + +## Usage + +Initialize your tracker with the ButtonClickTrackingPlugin: + +```js +import { newTracker } from '@snowplow/browser-tracker'; +import { ButtonClickTrackingPlugin } from '@snowplow/browser-plugin-button-click-tracking'; + +newTracker('sp1', '{{collector}}', { plugins: [ ButtonClickTrackingPlugin() ] }); // Also stores reference at module level +``` + +Then use the available functions from this package to track to all trackers which have been initialized with this plugin: + +```js +import { enableButtonClickTracking } from '@snowplow/browser-plugin-button-click-tracking'; + +enableButtonClickTracking({ filter: { .. }, context: { .. } }); +``` + +For a full API reference, you can read the plugin [documentation page](https://docs.snowplow.io/docs/collecting-data/collecting-from-own-applications/javascript-trackers/browser-tracker/browser-tracker-v3-reference/plugins/button-click-tracking/). + +## Copyright and license + +Licensed and distributed under the [BSD 3-Clause License](LICENSE) ([An OSI Approved License][osi]). + +Copyright (c) 2023 Snowplow Analytics Ltd, 2010 Anthon Pang. + +All rights reserved. + +[npm-url]: https://www.npmjs.com/package/@snowplow/browser-plugin-form-tracking +[npm-image]: https://img.shields.io/npm/v/@snowplow/browser-plugin-form-tracking +[osi]: https://opensource.org/licenses/BSD-3-Clause +[license-image]: https://img.shields.io/npm/l/@snowplow/browser-plugin-form-tracking diff --git a/plugins/browser-plugin-button-click-tracking/jest.config.js b/plugins/browser-plugin-button-click-tracking/jest.config.js new file mode 100644 index 000000000..bd3ea4e2a --- /dev/null +++ b/plugins/browser-plugin-button-click-tracking/jest.config.js @@ -0,0 +1,5 @@ +module.exports = { + preset: 'ts-jest', + reporters: ['jest-standard-reporter'], + testEnvironment: 'jest-environment-jsdom-global', +}; diff --git a/plugins/browser-plugin-button-click-tracking/package.json b/plugins/browser-plugin-button-click-tracking/package.json new file mode 100644 index 000000000..a7528766b --- /dev/null +++ b/plugins/browser-plugin-button-click-tracking/package.json @@ -0,0 +1,54 @@ +{ + "name": "@snowplow/browser-plugin-button-click-tracking", + "version": "4.10.0", + "description": "Button Click tracking for Snowplow", + "homepage": "https://github.com/snowplow/snowplow-javascript-tracker", + "bugs": "https://github.com/snowplow/snowplow-javascript-tracker/issues", + "repository": { + "type": "git", + "url": "https://github.com/snowplow/snowplow-javascript-tracker.git" + }, + "license": "BSD-3-Clause", + "author": "Snowplow Analytics Ltd (https://snowplow.io/)", + "sideEffects": false, + "main": "./dist/index.umd.js", + "module": "./dist/index.module.js", + "types": "./dist/index.module.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "rollup -c --silent --failAfterWarnings", + "test": "jest" + }, + "dependencies": { + "@snowplow/browser-tracker-core": "workspace:*", + "@snowplow/tracker-core": "workspace:*", + "tslib": "^2.3.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "~21.0.2", + "@rollup/plugin-node-resolve": "~13.1.3", + "@types/jest": "~28.1.1", + "@types/jsdom": "~16.2.14", + "@types/lodash": "~4.14.180", + "@typescript-eslint/eslint-plugin": "~5.15.0", + "@typescript-eslint/parser": "~5.15.0", + "eslint": "~8.11.0", + "jest": "~28.1.3", + "jest-environment-jsdom": "~28.1.3", + "jest-environment-jsdom-global": "~4.0.0", + "jest-standard-reporter": "~2.0.0", + "lodash": "~4.17.21", + "rollup": "~2.70.1", + "rollup-plugin-cleanup": "~3.2.1", + "rollup-plugin-license": "~2.6.1", + "rollup-plugin-terser": "~7.0.2", + "rollup-plugin-ts": "~2.0.5", + "ts-jest": "~28.0.8", + "typescript": "~4.6.2" + }, + "peerDependencies": { + "@snowplow/browser-tracker": "~4.10.0" + } +} diff --git a/plugins/browser-plugin-button-click-tracking/rollup.config.js b/plugins/browser-plugin-button-click-tracking/rollup.config.js new file mode 100644 index 000000000..6680f04e5 --- /dev/null +++ b/plugins/browser-plugin-button-click-tracking/rollup.config.js @@ -0,0 +1,36 @@ +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import ts from 'rollup-plugin-ts'; // Prefered over @rollup/plugin-typescript as it bundles .d.ts files +import { banner } from '../../banner'; +import { terser } from 'rollup-plugin-terser'; +import cleanup from 'rollup-plugin-cleanup'; +import pkg from './package.json'; +import { builtinModules } from 'module'; + +const umdPlugins = [nodeResolve({ browser: true }), commonjs(), ts()]; +const umdName = 'snowplowButtonClickTracking'; + +export default [ + // CommonJS (for Node) and ES module (for bundlers) build. + { + input: './src/index.ts', + plugins: [...umdPlugins, banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main, format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + plugins: [...umdPlugins, terser(), cleanup({ comments: 'none' }), banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main.replace('.js', '.min.js'), format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + external: [...builtinModules, ...Object.keys(pkg.dependencies), ...Object.keys(pkg.devDependencies)], + plugins: [ + ts(), // so Rollup can convert TypeScript to JavaScript + banner(), + ], + output: [{ file: pkg.module, format: 'es', sourcemap: true }], + }, +]; diff --git a/plugins/browser-plugin-button-click-tracking/src/api.ts b/plugins/browser-plugin-button-click-tracking/src/api.ts new file mode 100644 index 000000000..a8aa1bd2c --- /dev/null +++ b/plugins/browser-plugin-button-click-tracking/src/api.ts @@ -0,0 +1,126 @@ +import { BrowserPlugin, BrowserTracker, dispatchToTrackersInCollection } from '@snowplow/browser-tracker-core'; +import { DynamicContext, CommonEventProperties, resolveDynamicContext } from '@snowplow/tracker-core'; + +import { createEventFromButton, filterFunctionFromFilter } from './util'; +import { buildButtonClick } from './core'; +import { ButtonClickEvent, ButtonClickTrackingConfiguration, FilterFunction } from './types'; + +const _trackers: Record = {}; + +// The event listeners added to the document, for each tracker +// This allows them to be removed with `removeEventListener` if button click tracking is disabled +const _listeners: Record void> = {}; + +/** + * Button click tracking + * + * Will automatically tracking button clicks once enabled with 'enableButtonClickTracking' + * or you can manually track button clicks with 'trackButtonClick' + */ +export function ButtonClickTrackingPlugin(): BrowserPlugin { + return { + activateBrowserPlugin: (tracker: BrowserTracker) => { + _trackers[tracker.id] = tracker; + }, + }; +} + +/** + * Manually log a click + * + * @param event - The event information + * @param trackers - The tracker identifiers which the event will be sent to + */ +export function trackButtonClick( + event: ButtonClickEvent & CommonEventProperties, + trackers: Array = Object.keys(_trackers) +) { + dispatchToTrackersInCollection(trackers, _trackers, (t) => { + t.core.track(buildButtonClick(event), event.context, event.timestamp); + }); +} + +/** + * Enable automatic click tracking for all `` + * + * will result in `{ label: 'show-modal' }` + */ + label: string; + /** The ID of the button clicked, if present */ + id?: string; + /** An array of class names from the button clicked */ + classes?: Array; + /** The name of the button, if present */ + name?: string; +} diff --git a/plugins/browser-plugin-button-click-tracking/src/util.ts b/plugins/browser-plugin-button-click-tracking/src/util.ts new file mode 100644 index 000000000..078674c2e --- /dev/null +++ b/plugins/browser-plugin-button-click-tracking/src/util.ts @@ -0,0 +1,65 @@ +import { CommonEventProperties } from '@snowplow/tracker-core'; +import { ButtonClickEvent, Filter, FilterFunction } from './types'; + +/** + * Convert any {@link Filter} or undefined into a {@link FilterFunction} + * + * @param filter - The filter to convert + * @returns The filter function + */ +export function filterFunctionFromFilter(filter?: Filter): FilterFunction { + // If a function is provided, return it as-is + if (typeof filter === 'function') { + return filter; + } + + if (typeof filter === 'object') { + // If an allowlist is provided, return a function which matches the allowlist + if ('allowlist' in filter) { + return (element) => { + const classes = Array.from(element?.classList || []); + return classes.some((className) => filter.allowlist.includes(className)); + }; + } + + // If a denylist is provided, return a function which matches the denylist + if ('denylist' in filter) { + return (element) => { + const classes = Array.from(element?.classList || []); + return !classes.some((className) => filter.denylist.includes(className)); + }; + } + } + + // Return a function that will match all buttons if no filter is provided + return () => true; +} + +/** + * Creates a {@link ButtonClickEvent} from a button element + * + * @param button - The button element to create the event from + * @returns The button click event + */ +export function createEventFromButton( + button: HTMLButtonElement | HTMLInputElement, + defaultLabel?: string | ((element: HTMLElement) => string) +): ButtonClickEvent & CommonEventProperties { + let ret = {} as ButtonClickEvent & CommonEventProperties; + + if (button.tagName === 'INPUT') { + ret.label = button.dataset.spButtonLabel || button.value; + } else { + ret.label = + button.dataset.spButtonLabel || + button.innerText || + (typeof defaultLabel === 'function' ? defaultLabel(button) : defaultLabel) || + '(empty)'; + } + + button.id && (ret.id = button.id); + button.name && (ret.name = button.name); + button.classList.length && (ret.classes = Array.from(button.classList)); + + return ret; +} diff --git a/plugins/browser-plugin-button-click-tracking/test/test.test.ts b/plugins/browser-plugin-button-click-tracking/test/test.test.ts new file mode 100644 index 000000000..29417dd73 --- /dev/null +++ b/plugins/browser-plugin-button-click-tracking/test/test.test.ts @@ -0,0 +1,210 @@ +import { filterFunctionFromFilter, createEventFromButton } from '../src/util'; + +describe('Button Click Tracking Plugin', () => { + describe('filterToFunction', () => { + const createDiv = (className: string): HTMLDivElement => { + const ret = document.createElement('div'); + ret.className = className; + return ret; + }; + + it('should return a function that returns true if no filter is provided', () => { + const filter = filterFunctionFromFilter(undefined); + expect(filter(createDiv(''))).toBe(true); + }); + + it('should turn an allowlist into a filter function', () => { + const filter = filterFunctionFromFilter({ allowlist: ['foo'] }); + expect(filter(createDiv('foo'))).toBe(true); + expect(filter(createDiv('bar'))).toBe(false); + }); + + it('should turn a denylist into a filter function', () => { + const filter = filterFunctionFromFilter({ denylist: ['foo'] }); + expect(filter(createDiv('foo'))).toBe(false); + expect(filter(createDiv('bar'))).toBe(true); + }); + }); + + describe('getFilterPassingButtons', () => { + type TestDocument = { + testDocument: Document; + include_btn: HTMLButtonElement | HTMLInputElement; + exclude_btn: HTMLButtonElement | HTMLInputElement; + }; + + describe('HTMLButtonElements', () => { + const getTestDocument = (): TestDocument => { + const testDocument = document.implementation.createHTMLDocument('test'); + const include_btn = testDocument.createElement('button'); + include_btn.className = 'include'; + testDocument.body.appendChild(include_btn); + const exclude_btn = testDocument.createElement('button'); + exclude_btn.className = 'exclude'; + testDocument.body.appendChild(exclude_btn); + + return { + testDocument, + include_btn, + exclude_btn, + }; + }; + + const { testDocument, include_btn, exclude_btn } = getTestDocument(); + const buttons = Array.from(testDocument.getElementsByTagName('button')); + + it('should return all elements if no filter is provided', () => { + const buttonFilter = filterFunctionFromFilter(undefined); + const filteredButtons = buttons.filter(buttonFilter); + expect(filteredButtons).toEqual([include_btn, exclude_btn]); + }); + + it('should only return elements that match the `filter` function', () => { + const filter = filterFunctionFromFilter((element?: HTMLElement) => element?.className === 'include'); + const filteredButtons = buttons.filter(filter); + expect(filteredButtons).toEqual([include_btn]); + }); + + it('should return all elements with the classes in `allowlist`', () => { + const filter = filterFunctionFromFilter({ allowlist: ['include'] }); + const filteredButtons = buttons.filter(filter); + expect(filteredButtons).toEqual([include_btn]); + }); + + it('should not return any elements with the classes in `denylist`', () => { + const filter = filterFunctionFromFilter({ denylist: ['exclude'] }); + const filteredButtons = buttons.filter(filter); + expect(filteredButtons).toEqual([include_btn]); + }); + }); + + describe('HTMLInputElement', () => { + const getTestDocument = (): TestDocument => { + const testDocument = document.implementation.createHTMLDocument('test'); + const include_btn = testDocument.createElement('input'); + include_btn.type = 'button'; + include_btn.className = 'include'; + testDocument.body.appendChild(include_btn); + const exclude_btn = testDocument.createElement('input'); + exclude_btn.type = 'button'; + exclude_btn.className = 'exclude'; + testDocument.body.appendChild(exclude_btn); + + return { + testDocument, + include_btn, + exclude_btn, + }; + }; + + const { testDocument, include_btn, exclude_btn } = getTestDocument(); + const buttons = Array.from(testDocument.getElementsByTagName('input')).filter((input) => input.type === 'button'); + + it('should return all elements if no filter is provided', () => { + const buttonFilter = filterFunctionFromFilter(undefined); + const filteredButtons = buttons.filter(buttonFilter); + expect(filteredButtons).toEqual([include_btn, exclude_btn]); + }); + + it('should only return elements that match the `filter` function', () => { + const filter = filterFunctionFromFilter((element?: HTMLElement) => element?.className === 'include'); + const filteredButtons = buttons.filter(filter); + expect(filteredButtons).toEqual([include_btn]); + }); + + it('should return all elements with the classes in `allowlist`', () => { + const filter = filterFunctionFromFilter({ allowlist: ['include'] }); + const filteredButtons = buttons.filter(filter); + expect(filteredButtons).toEqual([include_btn]); + }); + + it('should not return any elements with the classes in `denylist`', () => { + const filter = filterFunctionFromFilter({ denylist: ['exclude'] }); + const filteredButtons = buttons.filter(filter); + expect(filteredButtons).toEqual([include_btn]); + }); + }); + }); + + describe('createEventFromButton', () => { + describe('HTMLButtonElement', () => { + it('should create an event from a button', () => { + const button = document.createElement('button'); + button.innerText = 'testLabel'; + button.id = 'testId'; + button.className = 'testClass testClass2'; + button.name = 'testName'; + + const event = { + label: 'testLabel', + id: 'testId', + classes: ['testClass', 'testClass2'], + name: 'testName', + }; + + expect(createEventFromButton(button)).toEqual(event); + }); + + it('should use specified default label', () => { + const button = document.createElement('button'); + button.innerText = ''; + button.id = 'testId'; + button.className = 'testClass testClass2'; + button.name = 'testName'; + + const event1 = { + label: 'defaultLabel', + id: 'testId', + classes: ['testClass', 'testClass2'], + name: 'testName', + }; + + expect(createEventFromButton(button, 'defaultLabel')).toEqual(event1); + + const event2 = { + label: 'testClass testClass2', + id: 'testId', + classes: ['testClass', 'testClass2'], + name: 'testName', + }; + expect(createEventFromButton(button, (btn) => btn.className)).toEqual(event2); + }); + + it('should prefer the data-sp-button-label attribute over the innerText', () => { + const button = document.createElement('button'); + button.innerText = 'testLabel'; + + button.setAttribute('data-sp-button-label', 'testLabelFromAttribute'); + expect(createEventFromButton(button).label).toEqual('testLabelFromAttribute'); + }); + }); + describe('HTMLInputElement', () => { + it('should create an event from an input', () => { + const input = document.createElement('input'); + input.type = 'button'; + input.value = 'testLabel'; + input.id = 'testId'; + input.className = 'testClass testClass2'; + input.name = 'testName'; + + const event = { + label: 'testLabel', + id: 'testId', + classes: ['testClass', 'testClass2'], + name: 'testName', + }; + + expect(createEventFromButton(input)).toEqual(event); + }); + + it('should prefer the data-sp-button-label attribute over the value', () => { + const input = document.createElement('input'); + input.type = 'button'; + input.value = 'testLabel'; + + input.setAttribute('data-sp-button-label', 'testLabelFromAttribute'); + expect(createEventFromButton(input).label).toEqual('testLabelFromAttribute'); + }); + }); + }); +}); diff --git a/plugins/browser-plugin-button-click-tracking/tsconfig.json b/plugins/browser-plugin-button-click-tracking/tsconfig.json new file mode 100644 index 000000000..4082f16a5 --- /dev/null +++ b/plugins/browser-plugin-button-click-tracking/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +} diff --git a/plugins/browser-plugin-client-hints/CHANGELOG.json b/plugins/browser-plugin-client-hints/CHANGELOG.json new file mode 100644 index 000000000..85f3a6c68 --- /dev/null +++ b/plugins/browser-plugin-client-hints/CHANGELOG.json @@ -0,0 +1,614 @@ +{ + "name": "@snowplow/browser-plugin-client-hints", + "entries": [ + { + "version": "4.10.0", + "tag": "@snowplow/browser-plugin-client-hints_v4.10.0", + "date": "Mon, 27 Jul 2026 13:52:14 GMT", + "comments": {} + }, + { + "version": "4.9.0", + "tag": "@snowplow/browser-plugin-client-hints_v4.9.0", + "date": "Tue, 21 Jul 2026 14:53:08 GMT", + "comments": {} + }, + { + "version": "4.8.4", + "tag": "@snowplow/browser-plugin-client-hints_v4.8.4", + "date": "Thu, 02 Jul 2026 10:07:52 GMT", + "comments": {} + }, + { + "version": "4.8.3", + "tag": "@snowplow/browser-plugin-client-hints_v4.8.3", + "date": "Tue, 30 Jun 2026 14:22:03 GMT", + "comments": { + "none": [ + { + "comment": "Update uuid to v11 and remove closure-compiler from the build pipeline" + } + ] + } + }, + { + "version": "4.8.2", + "tag": "@snowplow/browser-plugin-client-hints_v4.8.2", + "date": "Wed, 17 Jun 2026 12:30:12 GMT", + "comments": {} + }, + { + "version": "4.8.1", + "tag": "@snowplow/browser-plugin-client-hints_v4.8.1", + "date": "Wed, 13 May 2026 09:26:05 GMT", + "comments": {} + }, + { + "version": "4.8.0", + "tag": "@snowplow/browser-plugin-client-hints_v4.8.0", + "date": "Tue, 28 Apr 2026 07:56:22 GMT", + "comments": {} + }, + { + "version": "4.7.0", + "tag": "@snowplow/browser-plugin-client-hints_v4.7.0", + "date": "Wed, 01 Apr 2026 12:59:29 GMT", + "comments": {} + }, + { + "version": "4.6.9", + "tag": "@snowplow/browser-plugin-client-hints_v4.6.9", + "date": "Mon, 16 Mar 2026 15:43:06 GMT", + "comments": {} + }, + { + "version": "4.6.8", + "tag": "@snowplow/browser-plugin-client-hints_v4.6.8", + "date": "Tue, 28 Oct 2025 09:46:42 GMT", + "comments": {} + }, + { + "version": "4.6.7", + "tag": "@snowplow/browser-plugin-client-hints_v4.6.7", + "date": "Tue, 07 Oct 2025 14:53:36 GMT", + "comments": {} + }, + { + "version": "4.6.6", + "tag": "@snowplow/browser-plugin-client-hints_v4.6.6", + "date": "Tue, 26 Aug 2025 08:42:27 GMT", + "comments": {} + }, + { + "version": "4.6.5", + "tag": "@snowplow/browser-plugin-client-hints_v4.6.5", + "date": "Wed, 25 Jun 2025 21:16:46 GMT", + "comments": {} + }, + { + "version": "4.6.4", + "tag": "@snowplow/browser-plugin-client-hints_v4.6.4", + "date": "Wed, 25 Jun 2025 12:08:50 GMT", + "comments": {} + }, + { + "version": "4.6.3", + "tag": "@snowplow/browser-plugin-client-hints_v4.6.3", + "date": "Thu, 29 May 2025 19:52:07 GMT", + "comments": {} + }, + { + "version": "4.6.2", + "tag": "@snowplow/browser-plugin-client-hints_v4.6.2", + "date": "Tue, 20 May 2025 07:39:05 GMT", + "comments": {} + }, + { + "version": "4.6.1", + "tag": "@snowplow/browser-plugin-client-hints_v4.6.1", + "date": "Tue, 06 May 2025 13:10:51 GMT", + "comments": {} + }, + { + "version": "4.6.0", + "tag": "@snowplow/browser-plugin-client-hints_v4.6.0", + "date": "Thu, 01 May 2025 09:58:59 GMT", + "comments": {} + }, + { + "version": "4.5.0", + "tag": "@snowplow/browser-plugin-client-hints_v4.5.0", + "date": "Fri, 04 Apr 2025 09:21:23 GMT", + "comments": {} + }, + { + "version": "4.4.0", + "tag": "@snowplow/browser-plugin-client-hints_v4.4.0", + "date": "Thu, 20 Mar 2025 12:14:34 GMT", + "comments": {} + }, + { + "version": "4.3.1", + "tag": "@snowplow/browser-plugin-client-hints_v4.3.1", + "date": "Tue, 21 Jan 2025 11:09:42 GMT", + "comments": {} + }, + { + "version": "4.3.0", + "tag": "@snowplow/browser-plugin-client-hints_v4.3.0", + "date": "Mon, 20 Jan 2025 11:45:13 GMT", + "comments": {} + }, + { + "version": "4.2.0", + "tag": "@snowplow/browser-plugin-client-hints_v4.2.0", + "date": "Mon, 13 Jan 2025 08:30:05 GMT", + "comments": {} + }, + { + "version": "4.1.0", + "tag": "@snowplow/browser-plugin-client-hints_v4.1.0", + "date": "Thu, 28 Nov 2024 10:57:30 GMT", + "comments": {} + }, + { + "version": "4.0.4", + "tag": "@snowplow/browser-plugin-client-hints_v4.0.4", + "date": "Thu, 21 Nov 2024 09:06:36 GMT", + "comments": {} + }, + { + "version": "4.0.3", + "tag": "@snowplow/browser-plugin-client-hints_v4.0.3", + "date": "Wed, 20 Nov 2024 09:30:31 GMT", + "comments": {} + }, + { + "version": "4.0.2", + "tag": "@snowplow/browser-plugin-client-hints_v4.0.2", + "date": "Mon, 11 Nov 2024 15:46:33 GMT", + "comments": {} + }, + { + "version": "4.0.1", + "tag": "@snowplow/browser-plugin-client-hints_v4.0.1", + "date": "Fri, 01 Nov 2024 10:35:07 GMT", + "comments": {} + }, + { + "version": "4.0.0", + "tag": "@snowplow/browser-plugin-client-hints_v4.0.0", + "date": "Mon, 28 Oct 2024 11:48:53 GMT", + "comments": {} + }, + { + "version": "3.24.6", + "tag": "@snowplow/browser-plugin-client-hints_v3.24.6", + "date": "Mon, 28 Oct 2024 10:23:28 GMT", + "comments": {} + }, + { + "version": "3.24.5", + "tag": "@snowplow/browser-plugin-client-hints_v3.24.5", + "date": "Fri, 25 Oct 2024 08:53:04 GMT", + "comments": {} + }, + { + "version": "3.24.4", + "tag": "@snowplow/browser-plugin-client-hints_v3.24.4", + "date": "Thu, 26 Sep 2024 06:10:22 GMT", + "comments": {} + }, + { + "version": "3.24.3", + "tag": "@snowplow/browser-plugin-client-hints_v3.24.3", + "date": "Tue, 03 Sep 2024 08:15:14 GMT", + "comments": { + "none": [ + { + "comment": "Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush" + } + ] + } + }, + { + "version": "3.24.2", + "tag": "@snowplow/browser-plugin-client-hints_v3.24.2", + "date": "Wed, 24 Jul 2024 08:59:00 GMT", + "comments": {} + }, + { + "version": "3.24.1", + "tag": "@snowplow/browser-plugin-client-hints_v3.24.1", + "date": "Tue, 02 Jul 2024 07:08:17 GMT", + "comments": {} + }, + { + "version": "3.24.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.24.0", + "date": "Tue, 25 Jun 2024 08:31:05 GMT", + "comments": {} + }, + { + "version": "3.23.1", + "tag": "@snowplow/browser-plugin-client-hints_v3.23.1", + "date": "Tue, 04 Jun 2024 13:34:45 GMT", + "comments": {} + }, + { + "version": "3.23.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.23.0", + "date": "Thu, 28 Mar 2024 11:28:45 GMT", + "comments": {} + }, + { + "version": "3.22.1", + "tag": "@snowplow/browser-plugin-client-hints_v3.22.1", + "date": "Wed, 13 Mar 2024 08:39:48 GMT", + "comments": {} + }, + { + "version": "3.22.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.22.0", + "date": "Fri, 08 Mar 2024 08:13:04 GMT", + "comments": {} + }, + { + "version": "3.21.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.21.0", + "date": "Mon, 29 Jan 2024 08:34:06 GMT", + "comments": {} + }, + { + "version": "3.20.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.20.0", + "date": "Mon, 15 Jan 2024 14:41:16 GMT", + "comments": {} + }, + { + "version": "3.19.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.19.0", + "date": "Thu, 14 Dec 2023 10:45:22 GMT", + "comments": {} + }, + { + "version": "3.18.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.18.0", + "date": "Mon, 04 Dec 2023 13:44:02 GMT", + "comments": {} + }, + { + "version": "3.17.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.17.0", + "date": "Tue, 14 Nov 2023 17:58:26 GMT", + "comments": { + "none": [ + { + "comment": "Drop invalid client hints" + } + ] + } + }, + { + "version": "3.16.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.16.0", + "date": "Mon, 16 Oct 2023 14:58:08 GMT", + "comments": {} + }, + { + "version": "3.15.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.15.0", + "date": "Mon, 28 Aug 2023 14:25:14 GMT", + "comments": {} + }, + { + "version": "3.14.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.14.0", + "date": "Thu, 10 Aug 2023 13:56:44 GMT", + "comments": {} + }, + { + "version": "3.13.1", + "tag": "@snowplow/browser-plugin-client-hints_v3.13.1", + "date": "Thu, 29 Jun 2023 14:20:06 GMT", + "comments": {} + }, + { + "version": "3.13.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.13.0", + "date": "Tue, 20 Jun 2023 07:44:23 GMT", + "comments": {} + }, + { + "version": "3.12.1", + "tag": "@snowplow/browser-plugin-client-hints_v3.12.1", + "date": "Thu, 15 Jun 2023 10:05:37 GMT", + "comments": {} + }, + { + "version": "3.12.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.12.0", + "date": "Mon, 05 Jun 2023 11:51:22 GMT", + "comments": {} + }, + { + "version": "3.11.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.11.0", + "date": "Wed, 24 May 2023 15:56:17 GMT", + "comments": {} + }, + { + "version": "3.10.1", + "tag": "@snowplow/browser-plugin-client-hints_v3.10.1", + "date": "Fri, 12 May 2023 06:59:31 GMT", + "comments": {} + }, + { + "version": "3.10.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.10.0", + "date": "Thu, 11 May 2023 08:29:15 GMT", + "comments": {} + }, + { + "version": "3.9.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.9.0", + "date": "Thu, 30 Mar 2023 13:46:56 GMT", + "comments": { + "none": [ + { + "comment": "Make sure brands array in client hints plugin is serialized as an array in context entity" + } + ] + } + }, + { + "version": "3.8.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.8.0", + "date": "Tue, 03 Jan 2023 15:36:33 GMT", + "comments": {} + }, + { + "version": "3.7.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.7.0", + "date": "Mon, 31 Oct 2022 06:26:28 GMT", + "comments": {} + }, + { + "version": "3.6.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.6.0", + "date": "Thu, 15 Sep 2022 07:55:20 GMT", + "comments": {} + }, + { + "version": "3.5.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.5.0", + "date": "Fri, 10 Jun 2022 18:57:46 GMT", + "comments": {} + }, + { + "version": "3.4.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.4.0", + "date": "Thu, 07 Apr 2022 11:56:26 GMT", + "comments": { + "none": [ + { + "comment": "Bump dependencies (#1067)" + } + ] + } + }, + { + "version": "3.3.1", + "tag": "@snowplow/browser-plugin-client-hints_v3.3.1", + "date": "Wed, 23 Feb 2022 19:27:40 GMT", + "comments": {} + }, + { + "version": "3.3.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.3.0", + "date": "Mon, 31 Jan 2022 15:58:10 GMT", + "comments": {} + }, + { + "version": "3.2.3", + "tag": "@snowplow/browser-plugin-client-hints_v3.2.3", + "date": "Tue, 18 Jan 2022 16:23:52 GMT", + "comments": { + "none": [ + { + "comment": "Bump Copyright to 2022 (#1040)" + } + ] + } + }, + { + "version": "3.2.2", + "tag": "@snowplow/browser-plugin-client-hints_v3.2.2", + "date": "Fri, 14 Jan 2022 10:17:59 GMT", + "comments": {} + }, + { + "version": "3.2.1", + "tag": "@snowplow/browser-plugin-client-hints_v3.2.1", + "date": "Wed, 12 Jan 2022 09:50:29 GMT", + "comments": {} + }, + { + "version": "3.2.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.2.0", + "date": "Tue, 11 Jan 2022 12:53:22 GMT", + "comments": {} + }, + { + "version": "3.1.6", + "tag": "@snowplow/browser-plugin-client-hints_v3.1.6", + "date": "Tue, 19 Oct 2021 09:17:22 GMT", + "comments": { + "none": [ + { + "comment": "Fix failing build on ARM Macs (#1012)" + }, + { + "comment": "Fix issues importing some plugins in Next SSR (#1015)" + } + ] + } + }, + { + "version": "3.1.5", + "tag": "@snowplow/browser-plugin-client-hints_v3.1.5", + "date": "Fri, 01 Oct 2021 08:09:20 GMT", + "comments": {} + }, + { + "version": "3.1.4", + "tag": "@snowplow/browser-plugin-client-hints_v3.1.4", + "date": "Tue, 21 Sep 2021 14:59:36 GMT", + "comments": {} + }, + { + "version": "3.1.3", + "tag": "@snowplow/browser-plugin-client-hints_v3.1.3", + "date": "Mon, 23 Aug 2021 10:13:18 GMT", + "comments": {} + }, + { + "version": "3.1.2", + "tag": "@snowplow/browser-plugin-client-hints_v3.1.2", + "date": "Mon, 16 Aug 2021 12:59:59 GMT", + "comments": { + "none": [ + { + "comment": "Update READMEs with correct Node requirements (#994)" + } + ] + } + }, + { + "version": "3.1.1", + "tag": "@snowplow/browser-plugin-client-hints_v3.1.1", + "date": "Wed, 04 Aug 2021 10:12:25 GMT", + "comments": { + "none": [ + { + "comment": "Bump tslib to 2.3.0 (#986)" + }, + { + "comment": "Bump typescript to 4.3.5 (#987)" + }, + { + "comment": "Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988)" + } + ] + } + }, + { + "version": "3.1.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.1.0", + "date": "Fri, 14 May 2021 10:45:32 GMT", + "comments": {} + }, + { + "version": "3.0.3", + "tag": "@snowplow/browser-plugin-client-hints_v3.0.3", + "date": "Wed, 21 Apr 2021 12:35:06 GMT", + "comments": {} + }, + { + "version": "3.0.2", + "tag": "@snowplow/browser-plugin-client-hints_v3.0.2", + "date": "Thu, 15 Apr 2021 21:07:39 GMT", + "comments": {} + }, + { + "version": "3.0.1", + "tag": "@snowplow/browser-plugin-client-hints_v3.0.1", + "date": "Wed, 14 Apr 2021 16:30:05 GMT", + "comments": { + "none": [ + { + "comment": "Add peerDependencies to plugins (#950)" + }, + { + "comment": "Mark packages as sideEffect: false (#951)" + }, + { + "comment": "Add unit tests to plugin track* functions (#954)" + } + ] + } + }, + { + "version": "3.0.0", + "tag": "@snowplow/browser-plugin-client-hints_v3.0.0", + "date": "Wed, 31 Mar 2021 14:46:47 GMT", + "comments": { + "none": [ + { + "comment": "Bump rollup to 2.41 (#916)" + }, + { + "comment": "Publish UMD versions of plugins to GitHub release (#923)" + }, + { + "comment": "Ensure browser-tracker API methods catch exceptions (#919)" + }, + { + "comment": "Introduce TSDoc comments and extract interfaces where appropriate (#906)" + }, + { + "comment": "Bump major version to v3 and update READMEs (#904)" + }, + { + "comment": "Improve Core API for module bundlers which support treeshaking (#903)" + }, + { + "comment": "Rename @snowplow/browser-core to @snowplow/browser-tracker-core (#901)" + }, + { + "comment": "Publish lite version of sp.js (#900)" + }, + { + "comment": "Ensure correct 3-Clause BSD License notices are being used (#316)" + }, + { + "comment": "Improve API for module bundlers which support treeshaking (#899)" + }, + { + "comment": "Bump rush to 5.39 (#895)" + }, + { + "comment": "Port to TypeScript (#72)" + }, + { + "comment": "Make sp.js build process modular (#450)" + }, + { + "comment": "Create @snowplow/browser-tracker package for npm distribution (#541)" + }, + { + "comment": "Split auto contexts into plugins (#880)" + }, + { + "comment": "Add rush to manage monorepo (#883)" + }, + { + "comment": "Add ES Module builds (#882)" + }, + { + "comment": "Cleanup deprecated methods (#557)" + }, + { + "comment": "Update publishing process for rush (#907)" + }, + { + "comment": "Change white and black lists to allow and deny lists (#908)" + }, + { + "comment": "Create rush change files for major version 3 release (#909)" + } + ] + } + } + ] +} diff --git a/plugins/browser-plugin-client-hints/CHANGELOG.md b/plugins/browser-plugin-client-hints/CHANGELOG.md new file mode 100644 index 000000000..eb8863eb2 --- /dev/null +++ b/plugins/browser-plugin-client-hints/CHANGELOG.md @@ -0,0 +1,441 @@ +# Change Log - @snowplow/browser-plugin-client-hints + +This log was last generated on Mon, 27 Jul 2026 13:52:14 GMT and should not be manually modified. + +## 4.10.0 +Mon, 27 Jul 2026 13:52:14 GMT + +_Version update only_ + +## 4.9.0 +Tue, 21 Jul 2026 14:53:08 GMT + +_Version update only_ + +## 4.8.4 +Thu, 02 Jul 2026 10:07:52 GMT + +_Version update only_ + +## 4.8.3 +Tue, 30 Jun 2026 14:22:03 GMT + +### Updates + +- Update uuid to v11 and remove closure-compiler from the build pipeline + +## 4.8.2 +Wed, 17 Jun 2026 12:30:12 GMT + +_Version update only_ + +## 4.8.1 +Wed, 13 May 2026 09:26:05 GMT + +_Version update only_ + +## 4.8.0 +Tue, 28 Apr 2026 07:56:22 GMT + +_Version update only_ + +## 4.7.0 +Wed, 01 Apr 2026 12:59:29 GMT + +_Version update only_ + +## 4.6.9 +Mon, 16 Mar 2026 15:43:06 GMT + +_Version update only_ + +## 4.6.8 +Tue, 28 Oct 2025 09:46:42 GMT + +_Version update only_ + +## 4.6.7 +Tue, 07 Oct 2025 14:53:36 GMT + +_Version update only_ + +## 4.6.6 +Tue, 26 Aug 2025 08:42:27 GMT + +_Version update only_ + +## 4.6.5 +Wed, 25 Jun 2025 21:16:46 GMT + +_Version update only_ + +## 4.6.4 +Wed, 25 Jun 2025 12:08:50 GMT + +_Version update only_ + +## 4.6.3 +Thu, 29 May 2025 19:52:07 GMT + +_Version update only_ + +## 4.6.2 +Tue, 20 May 2025 07:39:05 GMT + +_Version update only_ + +## 4.6.1 +Tue, 06 May 2025 13:10:51 GMT + +_Version update only_ + +## 4.6.0 +Thu, 01 May 2025 09:58:59 GMT + +_Version update only_ + +## 4.5.0 +Fri, 04 Apr 2025 09:21:23 GMT + +_Version update only_ + +## 4.4.0 +Thu, 20 Mar 2025 12:14:34 GMT + +_Version update only_ + +## 4.3.1 +Tue, 21 Jan 2025 11:09:42 GMT + +_Version update only_ + +## 4.3.0 +Mon, 20 Jan 2025 11:45:13 GMT + +_Version update only_ + +## 4.2.0 +Mon, 13 Jan 2025 08:30:05 GMT + +_Version update only_ + +## 4.1.0 +Thu, 28 Nov 2024 10:57:30 GMT + +_Version update only_ + +## 4.0.4 +Thu, 21 Nov 2024 09:06:36 GMT + +_Version update only_ + +## 4.0.3 +Wed, 20 Nov 2024 09:30:31 GMT + +_Version update only_ + +## 4.0.2 +Mon, 11 Nov 2024 15:46:33 GMT + +_Version update only_ + +## 4.0.1 +Fri, 01 Nov 2024 10:35:07 GMT + +_Version update only_ + +## 4.0.0 +Mon, 28 Oct 2024 11:48:53 GMT + +_Version update only_ + +## 3.24.6 +Mon, 28 Oct 2024 10:23:28 GMT + +_Version update only_ + +## 3.24.5 +Fri, 25 Oct 2024 08:53:04 GMT + +_Version update only_ + +## 3.24.4 +Thu, 26 Sep 2024 06:10:22 GMT + +_Version update only_ + +## 3.24.3 +Tue, 03 Sep 2024 08:15:14 GMT + +### Updates + +- Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush + +## 3.24.2 +Wed, 24 Jul 2024 08:59:00 GMT + +_Version update only_ + +## 3.24.1 +Tue, 02 Jul 2024 07:08:17 GMT + +_Version update only_ + +## 3.24.0 +Tue, 25 Jun 2024 08:31:05 GMT + +_Version update only_ + +## 3.23.1 +Tue, 04 Jun 2024 13:34:45 GMT + +_Version update only_ + +## 3.23.0 +Thu, 28 Mar 2024 11:28:45 GMT + +_Version update only_ + +## 3.22.1 +Wed, 13 Mar 2024 08:39:48 GMT + +_Version update only_ + +## 3.22.0 +Fri, 08 Mar 2024 08:13:04 GMT + +_Version update only_ + +## 3.21.0 +Mon, 29 Jan 2024 08:34:06 GMT + +_Version update only_ + +## 3.20.0 +Mon, 15 Jan 2024 14:41:16 GMT + +_Version update only_ + +## 3.19.0 +Thu, 14 Dec 2023 10:45:22 GMT + +_Version update only_ + +## 3.18.0 +Mon, 04 Dec 2023 13:44:02 GMT + +_Version update only_ + +## 3.17.0 +Tue, 14 Nov 2023 17:58:26 GMT + +### Updates + +- Drop invalid client hints + +## 3.16.0 +Mon, 16 Oct 2023 14:58:08 GMT + +_Version update only_ + +## 3.15.0 +Mon, 28 Aug 2023 14:25:14 GMT + +_Version update only_ + +## 3.14.0 +Thu, 10 Aug 2023 13:56:44 GMT + +_Version update only_ + +## 3.13.1 +Thu, 29 Jun 2023 14:20:06 GMT + +_Version update only_ + +## 3.13.0 +Tue, 20 Jun 2023 07:44:23 GMT + +_Version update only_ + +## 3.12.1 +Thu, 15 Jun 2023 10:05:37 GMT + +_Version update only_ + +## 3.12.0 +Mon, 05 Jun 2023 11:51:22 GMT + +_Version update only_ + +## 3.11.0 +Wed, 24 May 2023 15:56:17 GMT + +_Version update only_ + +## 3.10.1 +Fri, 12 May 2023 06:59:31 GMT + +_Version update only_ + +## 3.10.0 +Thu, 11 May 2023 08:29:15 GMT + +_Version update only_ + +## 3.9.0 +Thu, 30 Mar 2023 13:46:56 GMT + +### Updates + +- Make sure brands array in client hints plugin is serialized as an array in context entity + +## 3.8.0 +Tue, 03 Jan 2023 15:36:33 GMT + +_Version update only_ + +## 3.7.0 +Mon, 31 Oct 2022 06:26:28 GMT + +_Version update only_ + +## 3.6.0 +Thu, 15 Sep 2022 07:55:20 GMT + +_Version update only_ + +## 3.5.0 +Fri, 10 Jun 2022 18:57:46 GMT + +_Version update only_ + +## 3.4.0 +Thu, 07 Apr 2022 11:56:26 GMT + +### Updates + +- Bump dependencies (#1067) + +## 3.3.1 +Wed, 23 Feb 2022 19:27:40 GMT + +_Version update only_ + +## 3.3.0 +Mon, 31 Jan 2022 15:58:10 GMT + +_Version update only_ + +## 3.2.3 +Tue, 18 Jan 2022 16:23:52 GMT + +### Updates + +- Bump Copyright to 2022 (#1040) + +## 3.2.2 +Fri, 14 Jan 2022 10:17:59 GMT + +_Version update only_ + +## 3.2.1 +Wed, 12 Jan 2022 09:50:29 GMT + +_Version update only_ + +## 3.2.0 +Tue, 11 Jan 2022 12:53:22 GMT + +_Version update only_ + +## 3.1.6 +Tue, 19 Oct 2021 09:17:22 GMT + +### Updates + +- Fix failing build on ARM Macs (#1012) +- Fix issues importing some plugins in Next SSR (#1015) + +## 3.1.5 +Fri, 01 Oct 2021 08:09:20 GMT + +_Version update only_ + +## 3.1.4 +Tue, 21 Sep 2021 14:59:36 GMT + +_Version update only_ + +## 3.1.3 +Mon, 23 Aug 2021 10:13:18 GMT + +_Version update only_ + +## 3.1.2 +Mon, 16 Aug 2021 12:59:59 GMT + +### Updates + +- Update READMEs with correct Node requirements (#994) + +## 3.1.1 +Wed, 04 Aug 2021 10:12:25 GMT + +### Updates + +- Bump tslib to 2.3.0 (#986) +- Bump typescript to 4.3.5 (#987) +- Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988) + +## 3.1.0 +Fri, 14 May 2021 10:45:32 GMT + +_Version update only_ + +## 3.0.3 +Wed, 21 Apr 2021 12:35:06 GMT + +_Version update only_ + +## 3.0.2 +Thu, 15 Apr 2021 21:07:39 GMT + +_Version update only_ + +## 3.0.1 +Wed, 14 Apr 2021 16:30:05 GMT + +### Updates + +- Add peerDependencies to plugins (#950) +- Mark packages as sideEffect: false (#951) +- Add unit tests to plugin track* functions (#954) + +## 3.0.0 +Wed, 31 Mar 2021 14:46:47 GMT + +### Updates + +- Bump rollup to 2.41 (#916) +- Publish UMD versions of plugins to GitHub release (#923) +- Ensure browser-tracker API methods catch exceptions (#919) +- Introduce TSDoc comments and extract interfaces where appropriate (#906) +- Bump major version to v3 and update READMEs (#904) +- Improve Core API for module bundlers which support treeshaking (#903) +- Rename @snowplow/browser-core to @snowplow/browser-tracker-core (#901) +- Publish lite version of sp.js (#900) +- Ensure correct 3-Clause BSD License notices are being used (#316) +- Improve API for module bundlers which support treeshaking (#899) +- Bump rush to 5.39 (#895) +- Port to TypeScript (#72) +- Make sp.js build process modular (#450) +- Create @snowplow/browser-tracker package for npm distribution (#541) +- Split auto contexts into plugins (#880) +- Add rush to manage monorepo (#883) +- Add ES Module builds (#882) +- Cleanup deprecated methods (#557) +- Update publishing process for rush (#907) +- Change white and black lists to allow and deny lists (#908) +- Create rush change files for major version 3 release (#909) + diff --git a/plugins/browser-plugin-client-hints/LICENSE b/plugins/browser-plugin-client-hints/LICENSE new file mode 100644 index 000000000..76f1946ea --- /dev/null +++ b/plugins/browser-plugin-client-hints/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/plugins/browser-plugin-client-hints/README.md b/plugins/browser-plugin-client-hints/README.md new file mode 100644 index 000000000..851fbe898 --- /dev/null +++ b/plugins/browser-plugin-client-hints/README.md @@ -0,0 +1,54 @@ +# Snowplow Client Hint Tracking + +[![npm version][npm-image]][npm-url] +[![License][license-image]](LICENSE) + +Browser Plugin to be used with `@snowplow/browser-tracker`. + +Adds Client Hints to your Snowplow tracking. Captures Navigator Client Hint data. + +## Maintainer quick start + +Part of the Snowplow JavaScript Tracker monorepo. +Build with [Node.js](https://nodejs.org/en/) (18 - 20) and [Rush](https://rushjs.io/). + +### Setup repository + +```bash +npm install -g @microsoft/rush +git clone https://github.com/snowplow/snowplow-javascript-tracker.git +rush update +``` + +## Package Installation + +With npm: + +```bash +npm install @snowplow/browser-plugin-client-hints +``` + +## Usage + +Initialize your tracker with the BrowserFeaturesPlugin: + +```js +import { newTracker } from '@snowplow/browser-tracker'; +import { ClientHintsPlugin } from '@snowplow/browser-plugin-client-hints'; + +newTracker('sp1', '{{collector}}', { plugins: [ ClientHintsPlugin() ] }); // Also stores reference at module level +``` + +## Copyright and license + +Licensed and distributed under the [BSD 3-Clause License](LICENSE) ([An OSI Approved License][osi]). + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang. + +All rights reserved. + +[npm-url]: https://www.npmjs.com/package/@snowplow/browser-plugin-client-hints +[npm-image]: https://img.shields.io/npm/v/@snowplow/browser-plugin-client-hints +[docs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-tracker/ +[osi]: https://opensource.org/licenses/BSD-3-Clause +[license-image]: https://img.shields.io/npm/l/@snowplow/browser-plugin-client-hints diff --git a/plugins/browser-plugin-client-hints/jest.config.js b/plugins/browser-plugin-client-hints/jest.config.js new file mode 100644 index 000000000..87d15da9b --- /dev/null +++ b/plugins/browser-plugin-client-hints/jest.config.js @@ -0,0 +1,6 @@ +module.exports = { + preset: 'ts-jest', + reporters: ['jest-standard-reporter'], + setupFilesAfterEnv: ['../../setupTestGlobals.ts'], + testEnvironment: 'jest-environment-jsdom-global', +}; diff --git a/plugins/browser-plugin-client-hints/package.json b/plugins/browser-plugin-client-hints/package.json new file mode 100644 index 000000000..3c2ecb6cc --- /dev/null +++ b/plugins/browser-plugin-client-hints/package.json @@ -0,0 +1,52 @@ +{ + "name": "@snowplow/browser-plugin-client-hints", + "version": "4.10.0", + "description": "Attaches Client Hints to Snowplow events", + "homepage": "http://bit.ly/sp-js", + "bugs": "https://github.com/snowplow/snowplow-javascript-tracker/issues", + "repository": { + "type": "git", + "url": "https://github.com/snowplow/snowplow-javascript-tracker.git" + }, + "license": "BSD-3-Clause", + "author": "Paul Boocock", + "sideEffects": false, + "main": "./dist/index.umd.js", + "module": "./dist/index.module.js", + "types": "./dist/index.module.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "rollup -c --silent --failAfterWarnings", + "test": "jest" + }, + "dependencies": { + "@snowplow/browser-tracker-core": "workspace:*", + "tslib": "^2.3.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "~21.0.2", + "@rollup/plugin-node-resolve": "~13.1.3", + "@snowplow/tracker-core": "workspace:*", + "@types/jest": "~28.1.1", + "@types/jsdom": "~16.2.14", + "@typescript-eslint/eslint-plugin": "~5.15.0", + "@typescript-eslint/parser": "~5.15.0", + "eslint": "~8.11.0", + "jest": "~28.1.3", + "jest-environment-jsdom": "~28.1.3", + "jest-environment-jsdom-global": "~4.0.0", + "jest-standard-reporter": "~2.0.0", + "rollup": "~2.70.1", + "rollup-plugin-cleanup": "~3.2.1", + "rollup-plugin-license": "~2.6.1", + "rollup-plugin-terser": "~7.0.2", + "rollup-plugin-ts": "~2.0.5", + "ts-jest": "~28.0.8", + "typescript": "~4.6.2" + }, + "peerDependencies": { + "@snowplow/browser-tracker": "~4.10.0" + } +} diff --git a/plugins/browser-plugin-client-hints/rollup.config.js b/plugins/browser-plugin-client-hints/rollup.config.js new file mode 100644 index 000000000..f3aa0b7be --- /dev/null +++ b/plugins/browser-plugin-client-hints/rollup.config.js @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import ts from 'rollup-plugin-ts'; // Prefered over @rollup/plugin-typescript as it bundles .d.ts files +import { banner } from '../../banner'; +import { terser } from 'rollup-plugin-terser'; +import cleanup from 'rollup-plugin-cleanup'; +import pkg from './package.json'; +import { builtinModules } from 'module'; + +const umdPlugins = [nodeResolve({ browser: true }), commonjs(), ts()]; +const umdName = 'snowplowClientHints'; + +export default [ + // CommonJS (for Node) and ES module (for bundlers) build. + { + input: './src/index.ts', + plugins: [...umdPlugins, banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main, format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + plugins: [...umdPlugins, terser(), cleanup({ comments: 'none' }), banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main.replace('.js', '.min.js'), format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + external: [...builtinModules, ...Object.keys(pkg.dependencies), ...Object.keys(pkg.devDependencies)], + plugins: [ + ts(), // so Rollup can convert TypeScript to JavaScript + banner(), + ], + output: [{ file: pkg.module, format: 'es', sourcemap: true }], + }, +]; diff --git a/plugins/browser-plugin-client-hints/src/contexts.ts b/plugins/browser-plugin-client-hints/src/contexts.ts new file mode 100644 index 000000000..5d55b5c0f --- /dev/null +++ b/plugins/browser-plugin-client-hints/src/contexts.ts @@ -0,0 +1,43 @@ +/** + * Values based upon the user agents characteristics, typically requested via the ACCEPT-CH HTTP header, as defined in the HTTP Client Hint specification + */ +export interface HttpClientHints { + [key: string]: unknown; + /** + * A boolean indicating if the user agent's device is a mobile device. (for example: false or true) + */ + isMobile: boolean; + /** + * The collection of brands a user agent identifies as + */ + brands: { + /** + * The user agent's commercial name (for example: 'cURL', 'Edge', 'The World’s Best Web Browser') + */ + brand: string; + /** + * The user agent's marketing version, which includes distinguishable web-exposed features (for example: '72', '3', or '12.1') + */ + version: string; + }[]; + /** + * The user agent's underlying CPU architecture (for example: 'ARM64', or 'ia32') + */ + architecture?: string | null; + /** + * The user agent's device model (for example: '', or 'Pixel 2 XL') + */ + model?: string | null; + /** + * The user agent's operating system’s commercial name. (for example: 'Windows', 'iOS', or 'AmazingOS') + */ + platform?: string | null; + /** + * The user agent's operating system’s version. (for example: 'NT 6.0', '15', or '17G') + */ + platformVersion?: string | null; + /** + * The user agent's build version (for example: '72.0.3245.12', '3.14159', or '297.70E04154A') + */ + uaFullVersion?: string | null; +} diff --git a/plugins/browser-plugin-client-hints/src/index.ts b/plugins/browser-plugin-client-hints/src/index.ts new file mode 100644 index 000000000..02205cc7b --- /dev/null +++ b/plugins/browser-plugin-client-hints/src/index.ts @@ -0,0 +1,125 @@ +import { BrowserPlugin } from '@snowplow/browser-tracker-core'; +import { HttpClientHints } from './contexts'; + +interface NavigatorUABrandVersion { + brand: string; // "Google Chrome" + version: string; // "84" +} + +interface UADataValues { + platform: string; // "PhoneOS" + platformVersion: string; // "10A" + architecture: string; // "arm" + model: string; // "X644GTM" + uaFullVersion: string; // "73.32.AGX.5" +} + +declare global { + interface Navigator { + userAgentData: { + mobile: boolean; + brands: Array; + getHighEntropyValues: (hints: Array) => Promise; + }; + } +} + +let uaClientHints: HttpClientHints; + +/** + * This function makes sure that the expected array is returned as an array instead of an object. + * It handles a problem that in some cases the `navigator.userAgentData.brands` was returned as an object instead of array. + */ +function forceArray(array: T[] | Record): T[] { + if (Array.isArray(array)) return array; + + if (Object.prototype.toString.call(array) === '[object Object]') { + return Object.keys(array).map((e) => { + return array[e]; + }); + } + + return []; +} + +/** + * Returns the client-hints brands, ensuring no additional properties. + */ +function getBrands(brands: Array): Array { + return brands.map((b) => { + const { brand, version } = b; + return { brand, version }; + }); +} + +/** + * Validates whether userAgentData is compliant to the client-hints interface. + * https://wicg.github.io/ua-client-hints/#interface + */ +function validClientHints(hints: HttpClientHints): boolean { + if (!hints || typeof hints.isMobile !== 'boolean' || !Array.isArray(hints.brands)) { + return false; + } + + if ( + hints.brands.length === 0 || + hints.brands.some((brand) => typeof brand.brand !== 'string' || typeof brand.version !== 'string') + ) { + return false; + } + + return true; +} + +/** + * Attaches Client Hint information where available + * @param includeHighEntropy - Should high entropy values be included + */ +export function ClientHintsPlugin(includeHighEntropy?: boolean): BrowserPlugin { + const populateClientHints = () => { + const navigatorAlias = navigator; + const uaData = navigatorAlias.userAgentData; + + if (uaData) { + let candidateHints: HttpClientHints; + candidateHints = { + isMobile: uaData.mobile, + brands: getBrands(forceArray(uaData.brands)), + }; + if (includeHighEntropy && uaData.getHighEntropyValues) { + uaData + .getHighEntropyValues(['platform', 'platformVersion', 'architecture', 'model', 'uaFullVersion']) + .then((res) => { + candidateHints.architecture = res.architecture; + candidateHints.model = res.model; + candidateHints.platform = res.platform; + candidateHints.uaFullVersion = res.uaFullVersion; + candidateHints.platformVersion = res.platformVersion; + }); + } + + if (validClientHints(candidateHints)) { + uaClientHints = candidateHints; + } + } + }; + + return { + activateBrowserPlugin: () => { + if (!uaClientHints) { + populateClientHints(); + } + }, + contexts: () => { + if (uaClientHints) { + return [ + { + schema: 'iglu:org.ietf/http_client_hints/jsonschema/1-0-0', + data: uaClientHints, + }, + ]; + } + return []; + }, + }; +} diff --git a/plugins/browser-plugin-client-hints/test/client-hints.test.ts b/plugins/browser-plugin-client-hints/test/client-hints.test.ts new file mode 100644 index 000000000..4da682972 --- /dev/null +++ b/plugins/browser-plugin-client-hints/test/client-hints.test.ts @@ -0,0 +1,170 @@ +import { buildLinkClick, trackerCore } from '@snowplow/tracker-core'; +import { BrowserTracker } from '@snowplow/browser-tracker-core'; +import { JSDOM } from 'jsdom'; +import { setImmediate } from 'timers'; +import { ClientHintsPlugin } from '../src'; + +declare var jsdom: JSDOM; + +describe('Client Hints plugin', () => { + const ctxSchema = 'iglu:com.snowplowanalytics.snowplow/contexts/jsonschema/1-0-0'; + const hintsSchema = 'iglu:org.ietf/http_client_hints/jsonschema/1-0-0'; + + it('Attaches no context on undefined userAgentData', (done) => { + const plugin = ClientHintsPlugin(false); + const core = trackerCore({ + corePlugins: [plugin], + callback: (payloadBuilder) => { + const json = payloadBuilder.getJson().filter((e) => e.keyIfEncoded === 'cx'); + expect(json.length).toBe(0); + done(); + }, + }); + + plugin.activateBrowserPlugin?.({ core } as BrowserTracker); + core.track(buildLinkClick({ targetUrl: 'https://example.com' })); + }); + + it('Attaches no context on invalid userAgentData(no mobile)', (done) => { + const sampleUserAgentData = { + brands: [ + { + brand: 'Opera GX', + version: '98', + }, + ], + } as any; + + Object.defineProperty(jsdom.window.navigator, 'userAgentData', { + value: sampleUserAgentData, + configurable: true, + }); + + const plugin = ClientHintsPlugin(false); + const core = trackerCore({ + corePlugins: [plugin], + callback: (payloadBuilder) => { + const json = payloadBuilder.getJson().filter((e) => e.keyIfEncoded === 'cx'); + expect(json.length).toBe(0); + done(); + }, + }); + + plugin.activateBrowserPlugin?.({ core } as BrowserTracker); + core.track(buildLinkClick({ targetUrl: 'https://example.com' })); + }); + + it('Attaches no context on invalid userAgentData(no brands)', (done) => { + const sampleUserAgentData = { + mobile: true, + } as any; + + Object.defineProperty(jsdom.window.navigator, 'userAgentData', { + value: sampleUserAgentData, + configurable: true, + }); + + const plugin = ClientHintsPlugin(false); + const core = trackerCore({ + corePlugins: [plugin], + callback: (payloadBuilder) => { + const json = payloadBuilder.getJson().filter((e) => e.keyIfEncoded === 'cx'); + expect(json.length).toBe(0); + done(); + }, + }); + + plugin.activateBrowserPlugin?.({ core } as BrowserTracker); + core.track(buildLinkClick({ targetUrl: 'https://example.com' })); + }); + + it('Attaches no context on invalid userAgentData(no valid brands)', (done) => { + const sampleUserAgentData = { + mobile: false, + brands: [ + { + brand: 'Opera GX', + version: 98, + }, + ], + } as any; + + Object.defineProperty(jsdom.window.navigator, 'userAgentData', { + value: sampleUserAgentData, + configurable: true, + }); + + const plugin = ClientHintsPlugin(true); + const core = trackerCore({ + corePlugins: [plugin], + callback: (payloadBuilder) => { + const json = payloadBuilder.getJson().filter((e) => e.keyIfEncoded === 'cx'); + expect(json.length).toBe(0); + done(); + }, + }); + + plugin.activateBrowserPlugin?.({ core } as BrowserTracker); + core.track(buildLinkClick({ targetUrl: 'https://example.com' })); + }); + + it('Attaches context on valid userAgentData properties', async () => { + const highEntropyVals = { + platform: 'PhoneOS', + platformVersion: '10A', + architecture: 'arm', + model: 'X633GTM', + uaFullVersion: '73.32.AGX.5', + }; + const sampleUserAgentData = { + brands: [ + { + brand: 'Chromium', + version: '119', + }, + { + brand: 'Not?A_Brand', + version: '24', + }, + ], + mobile: false, + getHighEntropyValues: (_: any) => Promise.resolve(highEntropyVals), + }; + + const expected = { + schema: ctxSchema, + data: [ + { + schema: hintsSchema, + data: Object.assign( + { + isMobile: false, + brands: sampleUserAgentData.brands, + }, + highEntropyVals + ), + }, + ], + }; + + Object.defineProperty(jsdom.window.navigator, 'userAgentData', { + value: sampleUserAgentData, + configurable: true, + }); + + const plugin = ClientHintsPlugin(true); + const core = trackerCore({ + corePlugins: [plugin], + callback: (payloadBuilder) => { + const json = payloadBuilder.getJson().filter((e) => e.keyIfEncoded === 'cx'); + + expect(json[0].json).toMatchObject(expected); + }, + }); + + plugin.activateBrowserPlugin?.({ core } as BrowserTracker); + const flushPromises = () => Promise.resolve(setImmediate); + await flushPromises(); + core.track(buildLinkClick({ targetUrl: 'https://example.com' })); + }); +}); diff --git a/plugins/browser-plugin-client-hints/tsconfig.json b/plugins/browser-plugin-client-hints/tsconfig.json new file mode 100644 index 000000000..4082f16a5 --- /dev/null +++ b/plugins/browser-plugin-client-hints/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +} diff --git a/plugins/browser-plugin-debugger/CHANGELOG.json b/plugins/browser-plugin-debugger/CHANGELOG.json new file mode 100644 index 000000000..dbd76f9a1 --- /dev/null +++ b/plugins/browser-plugin-debugger/CHANGELOG.json @@ -0,0 +1,545 @@ +{ + "name": "@snowplow/browser-plugin-debugger", + "entries": [ + { + "version": "4.10.0", + "tag": "@snowplow/browser-plugin-debugger_v4.10.0", + "date": "Mon, 27 Jul 2026 13:52:14 GMT", + "comments": {} + }, + { + "version": "4.9.0", + "tag": "@snowplow/browser-plugin-debugger_v4.9.0", + "date": "Tue, 21 Jul 2026 14:53:08 GMT", + "comments": {} + }, + { + "version": "4.8.4", + "tag": "@snowplow/browser-plugin-debugger_v4.8.4", + "date": "Thu, 02 Jul 2026 10:07:52 GMT", + "comments": {} + }, + { + "version": "4.8.3", + "tag": "@snowplow/browser-plugin-debugger_v4.8.3", + "date": "Tue, 30 Jun 2026 14:22:03 GMT", + "comments": { + "none": [ + { + "comment": "Update uuid to v11 and remove closure-compiler from the build pipeline" + } + ] + } + }, + { + "version": "4.8.2", + "tag": "@snowplow/browser-plugin-debugger_v4.8.2", + "date": "Wed, 17 Jun 2026 12:30:12 GMT", + "comments": {} + }, + { + "version": "4.8.1", + "tag": "@snowplow/browser-plugin-debugger_v4.8.1", + "date": "Wed, 13 May 2026 09:26:05 GMT", + "comments": {} + }, + { + "version": "4.8.0", + "tag": "@snowplow/browser-plugin-debugger_v4.8.0", + "date": "Tue, 28 Apr 2026 07:56:22 GMT", + "comments": {} + }, + { + "version": "4.7.0", + "tag": "@snowplow/browser-plugin-debugger_v4.7.0", + "date": "Wed, 01 Apr 2026 12:59:29 GMT", + "comments": {} + }, + { + "version": "4.6.9", + "tag": "@snowplow/browser-plugin-debugger_v4.6.9", + "date": "Mon, 16 Mar 2026 15:43:06 GMT", + "comments": {} + }, + { + "version": "4.6.8", + "tag": "@snowplow/browser-plugin-debugger_v4.6.8", + "date": "Tue, 28 Oct 2025 09:46:42 GMT", + "comments": {} + }, + { + "version": "4.6.7", + "tag": "@snowplow/browser-plugin-debugger_v4.6.7", + "date": "Tue, 07 Oct 2025 14:53:36 GMT", + "comments": {} + }, + { + "version": "4.6.6", + "tag": "@snowplow/browser-plugin-debugger_v4.6.6", + "date": "Tue, 26 Aug 2025 08:42:27 GMT", + "comments": {} + }, + { + "version": "4.6.5", + "tag": "@snowplow/browser-plugin-debugger_v4.6.5", + "date": "Wed, 25 Jun 2025 21:16:46 GMT", + "comments": {} + }, + { + "version": "4.6.4", + "tag": "@snowplow/browser-plugin-debugger_v4.6.4", + "date": "Wed, 25 Jun 2025 12:08:50 GMT", + "comments": {} + }, + { + "version": "4.6.3", + "tag": "@snowplow/browser-plugin-debugger_v4.6.3", + "date": "Thu, 29 May 2025 19:52:07 GMT", + "comments": {} + }, + { + "version": "4.6.2", + "tag": "@snowplow/browser-plugin-debugger_v4.6.2", + "date": "Tue, 20 May 2025 07:39:05 GMT", + "comments": {} + }, + { + "version": "4.6.1", + "tag": "@snowplow/browser-plugin-debugger_v4.6.1", + "date": "Tue, 06 May 2025 13:10:51 GMT", + "comments": {} + }, + { + "version": "4.6.0", + "tag": "@snowplow/browser-plugin-debugger_v4.6.0", + "date": "Thu, 01 May 2025 09:58:59 GMT", + "comments": {} + }, + { + "version": "4.5.0", + "tag": "@snowplow/browser-plugin-debugger_v4.5.0", + "date": "Fri, 04 Apr 2025 09:21:23 GMT", + "comments": {} + }, + { + "version": "4.4.0", + "tag": "@snowplow/browser-plugin-debugger_v4.4.0", + "date": "Thu, 20 Mar 2025 12:14:34 GMT", + "comments": {} + }, + { + "version": "4.3.1", + "tag": "@snowplow/browser-plugin-debugger_v4.3.1", + "date": "Tue, 21 Jan 2025 11:09:42 GMT", + "comments": {} + }, + { + "version": "4.3.0", + "tag": "@snowplow/browser-plugin-debugger_v4.3.0", + "date": "Mon, 20 Jan 2025 11:45:13 GMT", + "comments": {} + }, + { + "version": "4.2.0", + "tag": "@snowplow/browser-plugin-debugger_v4.2.0", + "date": "Mon, 13 Jan 2025 08:30:05 GMT", + "comments": {} + }, + { + "version": "4.1.0", + "tag": "@snowplow/browser-plugin-debugger_v4.1.0", + "date": "Thu, 28 Nov 2024 10:57:30 GMT", + "comments": {} + }, + { + "version": "4.0.4", + "tag": "@snowplow/browser-plugin-debugger_v4.0.4", + "date": "Thu, 21 Nov 2024 09:06:36 GMT", + "comments": {} + }, + { + "version": "4.0.3", + "tag": "@snowplow/browser-plugin-debugger_v4.0.3", + "date": "Wed, 20 Nov 2024 09:30:31 GMT", + "comments": {} + }, + { + "version": "4.0.2", + "tag": "@snowplow/browser-plugin-debugger_v4.0.2", + "date": "Mon, 11 Nov 2024 15:46:33 GMT", + "comments": {} + }, + { + "version": "4.0.1", + "tag": "@snowplow/browser-plugin-debugger_v4.0.1", + "date": "Fri, 01 Nov 2024 10:35:07 GMT", + "comments": {} + }, + { + "version": "4.0.0", + "tag": "@snowplow/browser-plugin-debugger_v4.0.0", + "date": "Mon, 28 Oct 2024 11:48:53 GMT", + "comments": {} + }, + { + "version": "3.24.6", + "tag": "@snowplow/browser-plugin-debugger_v3.24.6", + "date": "Mon, 28 Oct 2024 10:23:28 GMT", + "comments": {} + }, + { + "version": "3.24.5", + "tag": "@snowplow/browser-plugin-debugger_v3.24.5", + "date": "Fri, 25 Oct 2024 08:53:04 GMT", + "comments": {} + }, + { + "version": "3.24.4", + "tag": "@snowplow/browser-plugin-debugger_v3.24.4", + "date": "Thu, 26 Sep 2024 06:10:22 GMT", + "comments": {} + }, + { + "version": "3.24.3", + "tag": "@snowplow/browser-plugin-debugger_v3.24.3", + "date": "Tue, 03 Sep 2024 08:15:14 GMT", + "comments": { + "none": [ + { + "comment": "Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush" + } + ] + } + }, + { + "version": "3.24.2", + "tag": "@snowplow/browser-plugin-debugger_v3.24.2", + "date": "Wed, 24 Jul 2024 08:59:00 GMT", + "comments": {} + }, + { + "version": "3.24.1", + "tag": "@snowplow/browser-plugin-debugger_v3.24.1", + "date": "Tue, 02 Jul 2024 07:08:17 GMT", + "comments": {} + }, + { + "version": "3.24.0", + "tag": "@snowplow/browser-plugin-debugger_v3.24.0", + "date": "Tue, 25 Jun 2024 08:31:05 GMT", + "comments": {} + }, + { + "version": "3.23.1", + "tag": "@snowplow/browser-plugin-debugger_v3.23.1", + "date": "Tue, 04 Jun 2024 13:34:45 GMT", + "comments": {} + }, + { + "version": "3.23.0", + "tag": "@snowplow/browser-plugin-debugger_v3.23.0", + "date": "Thu, 28 Mar 2024 11:28:45 GMT", + "comments": {} + }, + { + "version": "3.22.1", + "tag": "@snowplow/browser-plugin-debugger_v3.22.1", + "date": "Wed, 13 Mar 2024 08:39:48 GMT", + "comments": {} + }, + { + "version": "3.22.0", + "tag": "@snowplow/browser-plugin-debugger_v3.22.0", + "date": "Fri, 08 Mar 2024 08:13:04 GMT", + "comments": {} + }, + { + "version": "3.21.0", + "tag": "@snowplow/browser-plugin-debugger_v3.21.0", + "date": "Mon, 29 Jan 2024 08:34:06 GMT", + "comments": {} + }, + { + "version": "3.20.0", + "tag": "@snowplow/browser-plugin-debugger_v3.20.0", + "date": "Mon, 15 Jan 2024 14:41:16 GMT", + "comments": {} + }, + { + "version": "3.19.0", + "tag": "@snowplow/browser-plugin-debugger_v3.19.0", + "date": "Thu, 14 Dec 2023 10:45:22 GMT", + "comments": {} + }, + { + "version": "3.18.0", + "tag": "@snowplow/browser-plugin-debugger_v3.18.0", + "date": "Mon, 04 Dec 2023 13:44:02 GMT", + "comments": {} + }, + { + "version": "3.17.0", + "tag": "@snowplow/browser-plugin-debugger_v3.17.0", + "date": "Tue, 14 Nov 2023 17:58:26 GMT", + "comments": {} + }, + { + "version": "3.16.0", + "tag": "@snowplow/browser-plugin-debugger_v3.16.0", + "date": "Mon, 16 Oct 2023 14:58:08 GMT", + "comments": {} + }, + { + "version": "3.15.0", + "tag": "@snowplow/browser-plugin-debugger_v3.15.0", + "date": "Mon, 28 Aug 2023 14:25:14 GMT", + "comments": {} + }, + { + "version": "3.14.0", + "tag": "@snowplow/browser-plugin-debugger_v3.14.0", + "date": "Thu, 10 Aug 2023 13:56:44 GMT", + "comments": {} + }, + { + "version": "3.13.1", + "tag": "@snowplow/browser-plugin-debugger_v3.13.1", + "date": "Thu, 29 Jun 2023 14:20:06 GMT", + "comments": {} + }, + { + "version": "3.13.0", + "tag": "@snowplow/browser-plugin-debugger_v3.13.0", + "date": "Tue, 20 Jun 2023 07:44:23 GMT", + "comments": {} + }, + { + "version": "3.12.1", + "tag": "@snowplow/browser-plugin-debugger_v3.12.1", + "date": "Thu, 15 Jun 2023 10:05:37 GMT", + "comments": {} + }, + { + "version": "3.12.0", + "tag": "@snowplow/browser-plugin-debugger_v3.12.0", + "date": "Mon, 05 Jun 2023 11:51:22 GMT", + "comments": {} + }, + { + "version": "3.11.0", + "tag": "@snowplow/browser-plugin-debugger_v3.11.0", + "date": "Wed, 24 May 2023 15:56:17 GMT", + "comments": {} + }, + { + "version": "3.10.1", + "tag": "@snowplow/browser-plugin-debugger_v3.10.1", + "date": "Fri, 12 May 2023 06:59:31 GMT", + "comments": {} + }, + { + "version": "3.10.0", + "tag": "@snowplow/browser-plugin-debugger_v3.10.0", + "date": "Thu, 11 May 2023 08:29:15 GMT", + "comments": {} + }, + { + "version": "3.9.0", + "tag": "@snowplow/browser-plugin-debugger_v3.9.0", + "date": "Thu, 30 Mar 2023 13:46:56 GMT", + "comments": {} + }, + { + "version": "3.8.0", + "tag": "@snowplow/browser-plugin-debugger_v3.8.0", + "date": "Tue, 03 Jan 2023 15:36:33 GMT", + "comments": {} + }, + { + "version": "3.7.0", + "tag": "@snowplow/browser-plugin-debugger_v3.7.0", + "date": "Mon, 31 Oct 2022 06:26:28 GMT", + "comments": {} + }, + { + "version": "3.6.0", + "tag": "@snowplow/browser-plugin-debugger_v3.6.0", + "date": "Thu, 15 Sep 2022 07:55:20 GMT", + "comments": {} + }, + { + "version": "3.5.0", + "tag": "@snowplow/browser-plugin-debugger_v3.5.0", + "date": "Fri, 10 Jun 2022 18:57:46 GMT", + "comments": { + "none": [ + { + "comment": "Add client session context entity (#1077)" + } + ] + } + }, + { + "version": "3.4.0", + "tag": "@snowplow/browser-plugin-debugger_v3.4.0", + "date": "Thu, 07 Apr 2022 11:56:26 GMT", + "comments": { + "none": [ + { + "comment": "Bump dependencies (#1067)" + } + ] + } + }, + { + "version": "3.3.1", + "tag": "@snowplow/browser-plugin-debugger_v3.3.1", + "date": "Wed, 23 Feb 2022 19:27:40 GMT", + "comments": {} + }, + { + "version": "3.3.0", + "tag": "@snowplow/browser-plugin-debugger_v3.3.0", + "date": "Mon, 31 Jan 2022 15:58:10 GMT", + "comments": {} + }, + { + "version": "3.2.3", + "tag": "@snowplow/browser-plugin-debugger_v3.2.3", + "date": "Tue, 18 Jan 2022 16:23:52 GMT", + "comments": { + "none": [ + { + "comment": "Bump Copyright to 2022 (#1040)" + } + ] + } + }, + { + "version": "3.2.2", + "tag": "@snowplow/browser-plugin-debugger_v3.2.2", + "date": "Fri, 14 Jan 2022 10:17:59 GMT", + "comments": {} + }, + { + "version": "3.2.1", + "tag": "@snowplow/browser-plugin-debugger_v3.2.1", + "date": "Wed, 12 Jan 2022 09:50:29 GMT", + "comments": {} + }, + { + "version": "3.2.0", + "tag": "@snowplow/browser-plugin-debugger_v3.2.0", + "date": "Tue, 11 Jan 2022 12:53:22 GMT", + "comments": {} + }, + { + "version": "3.1.6", + "tag": "@snowplow/browser-plugin-debugger_v3.1.6", + "date": "Tue, 19 Oct 2021 09:17:22 GMT", + "comments": { + "none": [ + { + "comment": "Fix failing build on ARM Macs (#1012)" + } + ] + } + }, + { + "version": "3.1.5", + "tag": "@snowplow/browser-plugin-debugger_v3.1.5", + "date": "Fri, 01 Oct 2021 08:09:20 GMT", + "comments": {} + }, + { + "version": "3.1.4", + "tag": "@snowplow/browser-plugin-debugger_v3.1.4", + "date": "Tue, 21 Sep 2021 14:59:36 GMT", + "comments": {} + }, + { + "version": "3.1.3", + "tag": "@snowplow/browser-plugin-debugger_v3.1.3", + "date": "Mon, 23 Aug 2021 10:13:18 GMT", + "comments": {} + }, + { + "version": "3.1.2", + "tag": "@snowplow/browser-plugin-debugger_v3.1.2", + "date": "Mon, 16 Aug 2021 12:59:59 GMT", + "comments": { + "none": [ + { + "comment": "Update READMEs with correct Node requirements (#994)" + } + ] + } + }, + { + "version": "3.1.1", + "tag": "@snowplow/browser-plugin-debugger_v3.1.1", + "date": "Wed, 04 Aug 2021 10:12:25 GMT", + "comments": { + "none": [ + { + "comment": "Bump tslib to 2.3.0 (#986)" + }, + { + "comment": "Bump typescript to 4.3.5 (#987)" + }, + { + "comment": "Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988)" + } + ] + } + }, + { + "version": "3.1.0", + "tag": "@snowplow/browser-plugin-debugger_v3.1.0", + "date": "Fri, 14 May 2021 10:45:32 GMT", + "comments": {} + }, + { + "version": "3.0.3", + "tag": "@snowplow/browser-plugin-debugger_v3.0.3", + "date": "Wed, 21 Apr 2021 12:35:06 GMT", + "comments": {} + }, + { + "version": "3.0.2", + "tag": "@snowplow/browser-plugin-debugger_v3.0.2", + "date": "Thu, 15 Apr 2021 21:07:39 GMT", + "comments": {} + }, + { + "version": "3.0.1", + "tag": "@snowplow/browser-plugin-debugger_v3.0.1", + "date": "Wed, 14 Apr 2021 16:30:05 GMT", + "comments": { + "none": [ + { + "comment": "Add peerDependencies to plugins (#950)" + }, + { + "comment": "Mark packages as sideEffect: false (#951)" + }, + { + "comment": "Add unit tests to plugin track* functions (#954)" + } + ] + } + }, + { + "version": "3.0.0", + "tag": "@snowplow/browser-plugin-debugger_v3.0.0", + "date": "Wed, 31 Mar 2021 14:46:47 GMT", + "comments": { + "none": [ + { + "comment": "Add debug mode (#381)" + } + ] + } + } + ] +} diff --git a/plugins/browser-plugin-debugger/CHANGELOG.md b/plugins/browser-plugin-debugger/CHANGELOG.md new file mode 100644 index 000000000..fb63f5607 --- /dev/null +++ b/plugins/browser-plugin-debugger/CHANGELOG.md @@ -0,0 +1,418 @@ +# Change Log - @snowplow/browser-plugin-debugger + +This log was last generated on Mon, 27 Jul 2026 13:52:14 GMT and should not be manually modified. + +## 4.10.0 +Mon, 27 Jul 2026 13:52:14 GMT + +_Version update only_ + +## 4.9.0 +Tue, 21 Jul 2026 14:53:08 GMT + +_Version update only_ + +## 4.8.4 +Thu, 02 Jul 2026 10:07:52 GMT + +_Version update only_ + +## 4.8.3 +Tue, 30 Jun 2026 14:22:03 GMT + +### Updates + +- Update uuid to v11 and remove closure-compiler from the build pipeline + +## 4.8.2 +Wed, 17 Jun 2026 12:30:12 GMT + +_Version update only_ + +## 4.8.1 +Wed, 13 May 2026 09:26:05 GMT + +_Version update only_ + +## 4.8.0 +Tue, 28 Apr 2026 07:56:22 GMT + +_Version update only_ + +## 4.7.0 +Wed, 01 Apr 2026 12:59:29 GMT + +_Version update only_ + +## 4.6.9 +Mon, 16 Mar 2026 15:43:06 GMT + +_Version update only_ + +## 4.6.8 +Tue, 28 Oct 2025 09:46:42 GMT + +_Version update only_ + +## 4.6.7 +Tue, 07 Oct 2025 14:53:36 GMT + +_Version update only_ + +## 4.6.6 +Tue, 26 Aug 2025 08:42:27 GMT + +_Version update only_ + +## 4.6.5 +Wed, 25 Jun 2025 21:16:46 GMT + +_Version update only_ + +## 4.6.4 +Wed, 25 Jun 2025 12:08:50 GMT + +_Version update only_ + +## 4.6.3 +Thu, 29 May 2025 19:52:07 GMT + +_Version update only_ + +## 4.6.2 +Tue, 20 May 2025 07:39:05 GMT + +_Version update only_ + +## 4.6.1 +Tue, 06 May 2025 13:10:51 GMT + +_Version update only_ + +## 4.6.0 +Thu, 01 May 2025 09:58:59 GMT + +_Version update only_ + +## 4.5.0 +Fri, 04 Apr 2025 09:21:23 GMT + +_Version update only_ + +## 4.4.0 +Thu, 20 Mar 2025 12:14:34 GMT + +_Version update only_ + +## 4.3.1 +Tue, 21 Jan 2025 11:09:42 GMT + +_Version update only_ + +## 4.3.0 +Mon, 20 Jan 2025 11:45:13 GMT + +_Version update only_ + +## 4.2.0 +Mon, 13 Jan 2025 08:30:05 GMT + +_Version update only_ + +## 4.1.0 +Thu, 28 Nov 2024 10:57:30 GMT + +_Version update only_ + +## 4.0.4 +Thu, 21 Nov 2024 09:06:36 GMT + +_Version update only_ + +## 4.0.3 +Wed, 20 Nov 2024 09:30:31 GMT + +_Version update only_ + +## 4.0.2 +Mon, 11 Nov 2024 15:46:33 GMT + +_Version update only_ + +## 4.0.1 +Fri, 01 Nov 2024 10:35:07 GMT + +_Version update only_ + +## 4.0.0 +Mon, 28 Oct 2024 11:48:53 GMT + +_Version update only_ + +## 3.24.6 +Mon, 28 Oct 2024 10:23:28 GMT + +_Version update only_ + +## 3.24.5 +Fri, 25 Oct 2024 08:53:04 GMT + +_Version update only_ + +## 3.24.4 +Thu, 26 Sep 2024 06:10:22 GMT + +_Version update only_ + +## 3.24.3 +Tue, 03 Sep 2024 08:15:14 GMT + +### Updates + +- Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush + +## 3.24.2 +Wed, 24 Jul 2024 08:59:00 GMT + +_Version update only_ + +## 3.24.1 +Tue, 02 Jul 2024 07:08:17 GMT + +_Version update only_ + +## 3.24.0 +Tue, 25 Jun 2024 08:31:05 GMT + +_Version update only_ + +## 3.23.1 +Tue, 04 Jun 2024 13:34:45 GMT + +_Version update only_ + +## 3.23.0 +Thu, 28 Mar 2024 11:28:45 GMT + +_Version update only_ + +## 3.22.1 +Wed, 13 Mar 2024 08:39:48 GMT + +_Version update only_ + +## 3.22.0 +Fri, 08 Mar 2024 08:13:04 GMT + +_Version update only_ + +## 3.21.0 +Mon, 29 Jan 2024 08:34:06 GMT + +_Version update only_ + +## 3.20.0 +Mon, 15 Jan 2024 14:41:16 GMT + +_Version update only_ + +## 3.19.0 +Thu, 14 Dec 2023 10:45:22 GMT + +_Version update only_ + +## 3.18.0 +Mon, 04 Dec 2023 13:44:02 GMT + +_Version update only_ + +## 3.17.0 +Tue, 14 Nov 2023 17:58:26 GMT + +_Version update only_ + +## 3.16.0 +Mon, 16 Oct 2023 14:58:08 GMT + +_Version update only_ + +## 3.15.0 +Mon, 28 Aug 2023 14:25:14 GMT + +_Version update only_ + +## 3.14.0 +Thu, 10 Aug 2023 13:56:44 GMT + +_Version update only_ + +## 3.13.1 +Thu, 29 Jun 2023 14:20:06 GMT + +_Version update only_ + +## 3.13.0 +Tue, 20 Jun 2023 07:44:23 GMT + +_Version update only_ + +## 3.12.1 +Thu, 15 Jun 2023 10:05:37 GMT + +_Version update only_ + +## 3.12.0 +Mon, 05 Jun 2023 11:51:22 GMT + +_Version update only_ + +## 3.11.0 +Wed, 24 May 2023 15:56:17 GMT + +_Version update only_ + +## 3.10.1 +Fri, 12 May 2023 06:59:31 GMT + +_Version update only_ + +## 3.10.0 +Thu, 11 May 2023 08:29:15 GMT + +_Version update only_ + +## 3.9.0 +Thu, 30 Mar 2023 13:46:56 GMT + +_Version update only_ + +## 3.8.0 +Tue, 03 Jan 2023 15:36:33 GMT + +_Version update only_ + +## 3.7.0 +Mon, 31 Oct 2022 06:26:28 GMT + +_Version update only_ + +## 3.6.0 +Thu, 15 Sep 2022 07:55:20 GMT + +_Version update only_ + +## 3.5.0 +Fri, 10 Jun 2022 18:57:46 GMT + +### Updates + +- Add client session context entity (#1077) + +## 3.4.0 +Thu, 07 Apr 2022 11:56:26 GMT + +### Updates + +- Bump dependencies (#1067) + +## 3.3.1 +Wed, 23 Feb 2022 19:27:40 GMT + +_Version update only_ + +## 3.3.0 +Mon, 31 Jan 2022 15:58:10 GMT + +_Version update only_ + +## 3.2.3 +Tue, 18 Jan 2022 16:23:52 GMT + +### Updates + +- Bump Copyright to 2022 (#1040) + +## 3.2.2 +Fri, 14 Jan 2022 10:17:59 GMT + +_Version update only_ + +## 3.2.1 +Wed, 12 Jan 2022 09:50:29 GMT + +_Version update only_ + +## 3.2.0 +Tue, 11 Jan 2022 12:53:22 GMT + +_Version update only_ + +## 3.1.6 +Tue, 19 Oct 2021 09:17:22 GMT + +### Updates + +- Fix failing build on ARM Macs (#1012) + +## 3.1.5 +Fri, 01 Oct 2021 08:09:20 GMT + +_Version update only_ + +## 3.1.4 +Tue, 21 Sep 2021 14:59:36 GMT + +_Version update only_ + +## 3.1.3 +Mon, 23 Aug 2021 10:13:18 GMT + +_Version update only_ + +## 3.1.2 +Mon, 16 Aug 2021 12:59:59 GMT + +### Updates + +- Update READMEs with correct Node requirements (#994) + +## 3.1.1 +Wed, 04 Aug 2021 10:12:25 GMT + +### Updates + +- Bump tslib to 2.3.0 (#986) +- Bump typescript to 4.3.5 (#987) +- Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988) + +## 3.1.0 +Fri, 14 May 2021 10:45:32 GMT + +_Version update only_ + +## 3.0.3 +Wed, 21 Apr 2021 12:35:06 GMT + +_Version update only_ + +## 3.0.2 +Thu, 15 Apr 2021 21:07:39 GMT + +_Version update only_ + +## 3.0.1 +Wed, 14 Apr 2021 16:30:05 GMT + +### Updates + +- Add peerDependencies to plugins (#950) +- Mark packages as sideEffect: false (#951) +- Add unit tests to plugin track* functions (#954) + +## 3.0.0 +Wed, 31 Mar 2021 14:46:47 GMT + +### Updates + +- Add debug mode (#381) + diff --git a/plugins/browser-plugin-debugger/LICENSE b/plugins/browser-plugin-debugger/LICENSE new file mode 100644 index 000000000..76f1946ea --- /dev/null +++ b/plugins/browser-plugin-debugger/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/plugins/browser-plugin-debugger/README.md b/plugins/browser-plugin-debugger/README.md new file mode 100644 index 000000000..ee1901ab3 --- /dev/null +++ b/plugins/browser-plugin-debugger/README.md @@ -0,0 +1,56 @@ +# Snowplow Advertising Tracking + +[![npm version][npm-image]][npm-url] +[![License][license-image]](LICENSE) + +Browser Plugin to be used with `@snowplow/browser-tracker`. + +Adds debugging to your Snowplow tracking. + +## Maintainer quick start + +Part of the Snowplow JavaScript Tracker monorepo. +Build with [Node.js](https://nodejs.org/en/) (18 - 20) and [Rush](https://rushjs.io/). + +### Setup repository + +```bash +npm install -g @microsoft/rush +git clone https://github.com/snowplow/snowplow-javascript-tracker.git +rush update +``` + +## Package Installation + +With npm: + +```bash +npm install @snowplow/browser-plugin-debugger +``` + +## Usage + +Initialize your tracker with the DebuggerPlugin: + +```js +import { newTracker } from '@snowplow/browser-tracker'; +import { DebuggerPlugin } from '@snowplow/browser-plugin-debugger'; + +newTracker('sp1', '{{collector}}', { plugins: [ DebuggerPlugin() ] }); // Also stores reference at module level +``` + +Then additional debugging information will be available in your browsers Developer Tools. + +## Copyright and license + +Licensed and distributed under the [BSD 3-Clause License](LICENSE) ([An OSI Approved License][osi]). + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang. + +All rights reserved. + +[npm-url]: https://www.npmjs.com/package/@snowplow/browser-plugin-ad-tracking +[npm-image]: https://img.shields.io/npm/v/@snowplow/browser-plugin-ad-tracking +[docs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-tracker/ +[osi]: https://opensource.org/licenses/BSD-3-Clause +[license-image]: https://img.shields.io/npm/l/@snowplow/browser-plugin-ad-tracking diff --git a/plugins/browser-plugin-debugger/package.json b/plugins/browser-plugin-debugger/package.json new file mode 100644 index 000000000..be0c6c779 --- /dev/null +++ b/plugins/browser-plugin-debugger/package.json @@ -0,0 +1,54 @@ +{ + "name": "@snowplow/browser-plugin-debugger", + "version": "4.10.0", + "description": "Debugger for Snowplow", + "homepage": "http://bit.ly/sp-js", + "bugs": "https://github.com/snowplow/snowplow-javascript-tracker/issues", + "repository": { + "type": "git", + "url": "https://github.com/snowplow/snowplow-javascript-tracker.git" + }, + "license": "BSD-3-Clause", + "author": "Paul Boocock", + "sideEffects": false, + "main": "./dist/index.umd.js", + "module": "./dist/index.module.js", + "types": "./dist/index.module.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "rollup -c --silent --failAfterWarnings", + "test": "" + }, + "dependencies": { + "@snowplow/browser-tracker-core": "workspace:*", + "@snowplow/tracker-core": "workspace:*", + "randomcolor": "^0.6.2", + "tslib": "^2.3.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "~21.0.2", + "@rollup/plugin-node-resolve": "~13.1.3", + "@types/jest": "~28.1.1", + "@types/jsdom": "~16.2.14", + "@types/randomcolor": "~0.5.5", + "@typescript-eslint/eslint-plugin": "~5.15.0", + "@typescript-eslint/parser": "~5.15.0", + "eslint": "~8.11.0", + "jest": "~28.1.3", + "jest-environment-jsdom": "~28.1.3", + "jest-environment-jsdom-global": "~4.0.0", + "jest-standard-reporter": "~2.0.0", + "rollup": "~2.70.1", + "rollup-plugin-cleanup": "~3.2.1", + "rollup-plugin-license": "~2.6.1", + "rollup-plugin-terser": "~7.0.2", + "rollup-plugin-ts": "~2.0.5", + "ts-jest": "~28.0.8", + "typescript": "~4.6.2" + }, + "peerDependencies": { + "@snowplow/browser-tracker": "~4.10.0" + } +} diff --git a/plugins/browser-plugin-debugger/rollup.config.js b/plugins/browser-plugin-debugger/rollup.config.js new file mode 100644 index 000000000..6ae9d968b --- /dev/null +++ b/plugins/browser-plugin-debugger/rollup.config.js @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import ts from 'rollup-plugin-ts'; // Prefered over @rollup/plugin-typescript as it bundles .d.ts files +import { banner } from '../../banner'; +import { terser } from 'rollup-plugin-terser'; +import cleanup from 'rollup-plugin-cleanup'; +import pkg from './package.json'; +import { builtinModules } from 'module'; + +const umdPlugins = [nodeResolve({ browser: true }), commonjs(), ts()]; +const umdName = 'snowplowDebugger'; + +export default [ + // CommonJS (for Node) and ES module (for bundlers) build. + { + input: './src/index.ts', + plugins: [...umdPlugins, banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main, format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + plugins: [...umdPlugins, terser(), cleanup({ comments: 'none' }), banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main.replace('.js', '.min.js'), format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + external: [...builtinModules, ...Object.keys(pkg.dependencies), ...Object.keys(pkg.devDependencies)], + plugins: [ + ts(), // so Rollup can convert TypeScript to JavaScript + banner(), + ], + output: [{ file: pkg.module, format: 'es', sourcemap: true }], + }, +]; diff --git a/plugins/browser-plugin-debugger/src/index.ts b/plugins/browser-plugin-debugger/src/index.ts new file mode 100644 index 000000000..98d2f6138 --- /dev/null +++ b/plugins/browser-plugin-debugger/src/index.ts @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { BrowserPlugin, BrowserTracker } from '@snowplow/browser-tracker-core'; +import { + EventJson, + EventJsonWithKeys, + JsonProcessor, + Logger, + LOG_LEVEL, + Payload, + PayloadBuilder, + payloadJsonProcessor, + version, + getSchemaParts, + SelfDescribingJson, +} from '@snowplow/tracker-core'; +import randomcolor from 'randomcolor'; + +/** + * Adds advertisement tracking functions + */ +export function DebuggerPlugin(logLevel: LOG_LEVEL = LOG_LEVEL.debug): BrowserPlugin { + let LOG: Logger; + let tracker: BrowserTracker; + let eventColour: string; + + const colours = { + event: () => `color: White; background: ${eventColour}; font-weight: bold; padding: 1px 4px; border-radius: 2px;`, + snowplowPurple: 'color: White; background: #6638B8; font-weight: bold; padding: 1px 4px; border-radius: 2px;', + activated: 'color: White; background: #9E62DD; font-weight: bold; padding: 1px 4px; border-radius: 2px;', + payload: 'color: White; background: #3748B8; font-weight: bold; padding: 1px 4px; border-radius: 2px;', + json: 'color: White; background: #388AB8; font-weight: bold; padding: 1px 4px; border-radius: 2px;', + schema: 'color: White; background: #268047; font-weight: bold; padding: 1px 4px; border-radius: 2px;', + schemaVersion: 'color: White; background: #80265F; font-weight: bold; padding: 1px 4px; border-radius: 2px;', + }; + + const debug = (style: string, message: string, extra?: [string, ...unknown[]]) => { + const [extraMessage, ...rest] = extra ?? ['']; + LOG.debug( + `v${version} %c${tracker.namespace}%c %c%s` + extraMessage, + colours.snowplowPurple, + '', + style, + message, + ...rest + ); + }; + + function jsonInterceptor(encodeBase64: boolean): JsonProcessor { + const log = (jsonType: string, data: SelfDescribingJson) => { + const schemaParts = getSchemaParts(data['schema']); + debug(colours.event(), 'Event', [ + '%c%s%c%s%c%s\n%o', + colours.json, + `${jsonType}: ${schemaParts ? schemaParts[1] : 'Unknown Schema'}`, + colours.schemaVersion, + schemaParts ? `Version: ${schemaParts[2]}-${schemaParts[3]}-${schemaParts[4]}` : 'Unknown Schema Version', + colours.schema, + schemaParts ? `Vendor: ${schemaParts[0]}` : 'Unknown Vendor', + data['data'], + ]); + }; + + return ( + payloadBuilder: PayloadBuilder, + jsonForProcessing: EventJson, + contextEntitiesForProcessing: SelfDescribingJson[] + ) => { + if (jsonForProcessing.length) { + for (const json of jsonForProcessing) { + const data = json.json['data'] as SelfDescribingJson; + if (Array.isArray(data)) { + data.forEach((d) => { + log(getJsonType(json), d); + }); + } else { + log(getJsonType(json), data); + } + } + } + if (contextEntitiesForProcessing.length) { + for (const entity of contextEntitiesForProcessing) { + log('Context', entity); + } + } + return payloadJsonProcessor(encodeBase64)(payloadBuilder, jsonForProcessing, contextEntitiesForProcessing); + }; + } + + return { + logger: (logger) => { + LOG = logger; + logger.setLogLevel(logLevel); + }, + activateBrowserPlugin: (t) => { + tracker = t; + debug(colours.activated, 'Tracker Activated'); + }, + beforeTrack: (payloadBuilder: PayloadBuilder) => { + eventColour = randomcolor({ luminosity: 'dark' }); + payloadBuilder.withJsonProcessor(jsonInterceptor(tracker.core.getBase64Encoding())); + debug(colours.event(), 'Event', ['%c%s', colours.snowplowPurple, getEventType(payloadBuilder)]); + payloadBuilder.build(); + }, + afterTrack: (payload: Payload) => { + debug(colours.event(), 'Event', ['%c%s\n%o', colours.payload, 'Payload', payload]); + }, + }; +} + +function getJsonType(json: EventJsonWithKeys) { + switch (json.keyIfEncoded) { + case 'cx': + return 'Context'; + case 'ue_px': + return 'Self Describing'; + default: + return `${json.keyIfEncoded}, ${json.keyIfNotEncoded}`; + } +} + +function getEventType(payloadBuilder: PayloadBuilder) { + const payload = payloadBuilder.getPayload(); + switch (payload['e']) { + case 'pv': + return 'Page View'; + case 'pp': + return 'Page Ping'; + case 'tr': + return 'Ecommerce Transaction'; + case 'ti': + return 'Ecommerce Transaction Item'; + case 'se': + return 'Structured Event'; + case 'ue': + return 'Self Describing'; + default: + return typeof payload['e'] === 'string' ? payload['e'] : 'Invalid'; + } +} diff --git a/plugins/browser-plugin-debugger/tsconfig.json b/plugins/browser-plugin-debugger/tsconfig.json new file mode 100644 index 000000000..4082f16a5 --- /dev/null +++ b/plugins/browser-plugin-debugger/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +} diff --git a/plugins/browser-plugin-element-tracking/CHANGELOG.json b/plugins/browser-plugin-element-tracking/CHANGELOG.json new file mode 100644 index 000000000..3bf0703b6 --- /dev/null +++ b/plugins/browser-plugin-element-tracking/CHANGELOG.json @@ -0,0 +1,137 @@ +{ + "name": "@snowplow/browser-plugin-element-tracking", + "entries": [ + { + "version": "4.10.0", + "tag": "@snowplow/browser-plugin-element-tracking_v4.10.0", + "date": "Mon, 27 Jul 2026 13:52:14 GMT", + "comments": {} + }, + { + "version": "4.9.0", + "tag": "@snowplow/browser-plugin-element-tracking_v4.9.0", + "date": "Tue, 21 Jul 2026 14:53:08 GMT", + "comments": { + "none": [ + { + "comment": "Fix element tracking plugin sending element_index of 0 on expose_element and obscure_element events" + } + ] + } + }, + { + "version": "4.8.4", + "tag": "@snowplow/browser-plugin-element-tracking_v4.8.4", + "date": "Thu, 02 Jul 2026 10:07:52 GMT", + "comments": {} + }, + { + "version": "4.8.3", + "tag": "@snowplow/browser-plugin-element-tracking_v4.8.3", + "date": "Tue, 30 Jun 2026 14:22:03 GMT", + "comments": { + "none": [ + { + "comment": "Update uuid to v11 and remove closure-compiler from the build pipeline" + } + ] + } + }, + { + "version": "4.8.2", + "tag": "@snowplow/browser-plugin-element-tracking_v4.8.2", + "date": "Wed, 17 Jun 2026 12:30:12 GMT", + "comments": {} + }, + { + "version": "4.8.1", + "tag": "@snowplow/browser-plugin-element-tracking_v4.8.1", + "date": "Wed, 13 May 2026 09:26:05 GMT", + "comments": {} + }, + { + "version": "4.8.0", + "tag": "@snowplow/browser-plugin-element-tracking_v4.8.0", + "date": "Tue, 28 Apr 2026 07:56:22 GMT", + "comments": {} + }, + { + "version": "4.7.0", + "tag": "@snowplow/browser-plugin-element-tracking_v4.7.0", + "date": "Wed, 01 Apr 2026 12:59:29 GMT", + "comments": {} + }, + { + "version": "4.6.9", + "tag": "@snowplow/browser-plugin-element-tracking_v4.6.9", + "date": "Mon, 16 Mar 2026 15:43:06 GMT", + "comments": {} + }, + { + "version": "4.6.8", + "tag": "@snowplow/browser-plugin-element-tracking_v4.6.8", + "date": "Tue, 28 Oct 2025 09:46:42 GMT", + "comments": {} + }, + { + "version": "4.6.7", + "tag": "@snowplow/browser-plugin-element-tracking_v4.6.7", + "date": "Tue, 07 Oct 2025 14:53:36 GMT", + "comments": {} + }, + { + "version": "4.6.6", + "tag": "@snowplow/browser-plugin-element-tracking_v4.6.6", + "date": "Tue, 26 Aug 2025 08:42:27 GMT", + "comments": {} + }, + { + "version": "4.6.5", + "tag": "@snowplow/browser-plugin-element-tracking_v4.6.5", + "date": "Wed, 25 Jun 2025 21:16:46 GMT", + "comments": {} + }, + { + "version": "4.6.4", + "tag": "@snowplow/browser-plugin-element-tracking_v4.6.4", + "date": "Wed, 25 Jun 2025 12:08:50 GMT", + "comments": {} + }, + { + "version": "4.6.3", + "tag": "@snowplow/browser-plugin-element-tracking_v4.6.3", + "date": "Thu, 29 May 2025 19:52:07 GMT", + "comments": {} + }, + { + "version": "4.6.2", + "tag": "@snowplow/browser-plugin-element-tracking_v4.6.2", + "date": "Tue, 20 May 2025 07:39:05 GMT", + "comments": { + "none": [ + { + "comment": "Fix element_content schema implementation." + } + ] + } + }, + { + "version": "4.6.1", + "tag": "@snowplow/browser-plugin-element-tracking_v4.6.1", + "date": "Tue, 06 May 2025 13:10:51 GMT", + "comments": {} + }, + { + "version": "4.6.0", + "tag": "@snowplow/browser-plugin-element-tracking_v4.6.0", + "date": "Thu, 01 May 2025 09:58:59 GMT", + "comments": { + "none": [ + { + "comment": "Create element tracking plugin" + } + ] + } + } + ] +} diff --git a/plugins/browser-plugin-element-tracking/CHANGELOG.md b/plugins/browser-plugin-element-tracking/CHANGELOG.md new file mode 100644 index 000000000..545fe47f6 --- /dev/null +++ b/plugins/browser-plugin-element-tracking/CHANGELOG.md @@ -0,0 +1,102 @@ +# Change Log - @snowplow/browser-plugin-element-tracking + +This log was last generated on Mon, 27 Jul 2026 13:52:14 GMT and should not be manually modified. + +## 4.10.0 +Mon, 27 Jul 2026 13:52:14 GMT + +_Version update only_ + +## 4.9.0 +Tue, 21 Jul 2026 14:53:08 GMT + +### Updates + +- Fix element tracking plugin sending element_index of 0 on expose_element and obscure_element events + +## 4.8.4 +Thu, 02 Jul 2026 10:07:52 GMT + +_Version update only_ + +## 4.8.3 +Tue, 30 Jun 2026 14:22:03 GMT + +### Updates + +- Update uuid to v11 and remove closure-compiler from the build pipeline + +## 4.8.2 +Wed, 17 Jun 2026 12:30:12 GMT + +_Version update only_ + +## 4.8.1 +Wed, 13 May 2026 09:26:05 GMT + +_Version update only_ + +## 4.8.0 +Tue, 28 Apr 2026 07:56:22 GMT + +_Version update only_ + +## 4.7.0 +Wed, 01 Apr 2026 12:59:29 GMT + +_Version update only_ + +## 4.6.9 +Mon, 16 Mar 2026 15:43:06 GMT + +_Version update only_ + +## 4.6.8 +Tue, 28 Oct 2025 09:46:42 GMT + +_Version update only_ + +## 4.6.7 +Tue, 07 Oct 2025 14:53:36 GMT + +_Version update only_ + +## 4.6.6 +Tue, 26 Aug 2025 08:42:27 GMT + +_Version update only_ + +## 4.6.5 +Wed, 25 Jun 2025 21:16:46 GMT + +_Version update only_ + +## 4.6.4 +Wed, 25 Jun 2025 12:08:50 GMT + +_Version update only_ + +## 4.6.3 +Thu, 29 May 2025 19:52:07 GMT + +_Version update only_ + +## 4.6.2 +Tue, 20 May 2025 07:39:05 GMT + +### Updates + +- Fix element_content schema implementation. + +## 4.6.1 +Tue, 06 May 2025 13:10:51 GMT + +_Version update only_ + +## 4.6.0 +Thu, 01 May 2025 09:58:59 GMT + +### Updates + +- Create element tracking plugin + diff --git a/plugins/browser-plugin-element-tracking/LICENSE b/plugins/browser-plugin-element-tracking/LICENSE new file mode 100644 index 000000000..a311732d5 --- /dev/null +++ b/plugins/browser-plugin-element-tracking/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2023 Snowplow Analytics Ltd, 2010 Anthon Pang +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/plugins/browser-plugin-element-tracking/README.md b/plugins/browser-plugin-element-tracking/README.md new file mode 100644 index 000000000..c87e8931f --- /dev/null +++ b/plugins/browser-plugin-element-tracking/README.md @@ -0,0 +1,195 @@ +# Snowplow Element Tracking Plugin + +[![npm version][npm-image]][npm-url] +[![License][license-image]](LICENSE) + +Browser Plugin to be used with `@snowplow/browser-tracker`. + +This plugin allows tracking the addition/removal and visibility of page elements. + +## Maintainer quick start + +Part of the Snowplow JavaScript Tracker monorepo. +Build with [Node.js](https://nodejs.org/en/) (18 - 20) and [Rush](https://rushjs.io/). + +### Setup repository + +```bash +npm install -g @microsoft/rush +git clone https://github.com/snowplow/snowplow-javascript-tracker.git +rush update +``` + +## Package Installation + +With npm: + +```bash +npm install @snowplow/browser-plugin-element-tracking +``` + +## Usage + +Initialize your tracker with the SnowplowElementTrackingPlugin and then call `startElementTracking`: + +```js +import { newTracker } from '@snowplow/browser-tracker'; +import { SnowplowElementTrackingPlugin, startElementTracking } from '@snowplow/browser-plugin-element-tracking'; + +newTracker('sp1', '{{collector_url}}', { + appId: 'my-app-id', + plugins: [ SnowplowElementTrackingPlugin() ], +}); + +startElementTracking({ + elements: [ + {selector: '.newsletter-signup'} + ] +}); +``` + +### Configuration + +Configuration occurs primarily via the `elements` setting passed to `startElementTracking`. + +You can pass a single configuration or an array of multiple configurations. + +Each configuration requires a `selector`, with a CSS selector describing the elements the configuration applies to. +All other configuration is optional. + +You can label each configuration with the `name` property (if not specified, the `selector` is used as the `name`). +The `name` is used in the event payloads and matches the `element_name` of any entities specific to the target element(s). + +The settings control triggering events for: + +- `expose_element`: When a selected element enters the viewport, becoming visible +- `obscure_element`: When a selected element exists the viewport, no longer being visible +- `create_element`: When a selected element is created or exists in the document +- `destroy_element`: When a selected element is removed from or no longer found in the document + +Each of these events can be enabled, disabled, or configured more specifically. +By default, only `expose_element` is enabled. + +Rather than trigger events, configurations can also define the selected elements as "components", which can be listed as a `component_parents` entity for other events; or can have their current state attached to other events (such as page pings) via `element_statistics` entities. + +The plugin manages the following custom entities: + +- `element`: This is shared between all the above events. It contains the `element_name` from the matching configuration, and data about the element that generated the event. This includes the element's dimensions, position (relative to the viewport and document), how many elements matched it's selector (and the index of the element in question, if you selector matches multiple elements). It will also contain custom attributes you can extract from the element via the `details` configuration. +- `component_parents`: For the element generating the event, provides a list of components (defined by the `component` setting) that are ancestors of that element. +- `element_content`: You can also attach details about child elements of the element that matches your selector. E.g. you can select a recommendations widget, and then extract details about the individual recommendations within it. +- `element_statistics`: This entity can be attached to other events and provides a snapshot of what this plugin has observed at that point; it includes the current/smallest/largest dimensions so far, how long the element has existed since it was first observed, its current/maximum scroll depth, its total time in view, and how many times it has been visible in the viewport. + +A detailed example configuration follows: + +```javascript +snowplow('startElementTracking', { + elements: [ + // can be a single or array of many configurations; additive, can be called multiple times to add more configurations, but doesn't dedupe + { + selector: '.oncreate', // required: selector for element, relative to document scope by default + name: 'created div', // logical name: can be shared across multiple configs; defaults to `selector` if not specified; this is used in event payloads and as a key to reference entities + create: true, // track an event when the element is added to the DOM (or when plugin loads if already on page) (default: false) + destroy: true, // track an event when the element is removed from the DOM (or when plugin loads if already on page) (default: false) + expose: true, // track an event when the element intersects with the viewport (default: true) + obscure: true, // track an event when the element scrolls out of the viewport (default: false) + details: [ + // details can be extracted from the element and included in the entity + function (element) { + return { example: 'from a function' }; + }, // use a function that returns an object + { attributes: ['class'], selector: true }, // or declarative options; either as a single object or array elements if you want config re-use; this is less flexible but will be useful to Google Tag Manager where functions may not be able to reference DOM elements + { attributes: ['class'] }, // attributes: get the static/default attributes originally defined on the element when created + { properties: ['className'] }, // properties: get the dynamic/current attributes defined on the element + { dataset: ['example'] }, // dataset: extract values from dataset attributes + { child_text: { heading: 'h2' } }, // child_text: for each given name:selector pair, extract the textContent of the first child matching selector, if it has text content use that value with the given name; if there's no matching children it will try shadow children + { selector: true }, // selector: attach the matching CSS selector as an attribute; useful if you're using logical names but want to differentiate + { content: { textType: /text (\S+)/ } }, //content (map of regex patterns to match text against, first capture group used if detected); if no innerText, will try shadow innerText + ], + includeStats: ['page_ping'], // you can include a list of event names here; statistics about elements matching this configuration will be attached as entities to those events; event names don't have to be generated by this plugin so can include built-in events like page_pings or custom events + }, + { selector: 'nav', expose: false, component: true }, // `expose` is true by default so may need disabling; `component` means the name/selector is attached to the component_parents entity list for other events triggered on descendants + { + selector: 'div.toggled', // elements that exist but don't yet match the selector will count as created/destroyed if they later are changed to match it + name: 'mutated div', + create: true, + destroy: true, + expose: false, + obscure: false, + }, + { + selector: '.perpage.toggled', + name: 'perpage mutation', + create: { when: 'pageview' }, // for each type of event you can specify frequency caps for when the event will fire: never, always, once, element, pageview + destroy: { when: 'pageview' }, + /* + the frequency options are "per": + - per never will never track the event, effectively disabling the configuration + - per always will track an event every time it is eligible (e.g. every time on screen when scrolled past) + - per once will only track the event a single time for each configuration for the duration of the plugin instance; this reduces volume since only the first matching element will fire the event + - per element is like once, but for each individually matching element instance + - per pageview is like once, but useful for single-page-applications with long-lasting plugin instances where you may want to track the element on each virtual pageview + */ + expose: false, // `false` is equivalent to `when: never`, and `true` is `when: always` + obscure: false, + }, + { + name: 'recommendations', + selector: '.recommendations', + expose: { + // expose has more options than the other events: + minTimeMillis: 5000, // cumulative time in milliseconds that each matching element should be visible for before considered exposed + minPercentage: 0, // the minimum percentage of the element's area that should be visible before considering exposed; range 0.0 - 1.0 + minSize: 0, // the minimum size the element should be before being considered exposed; this can be used to ignore elements with 0 size + boundaryPixels: 0, // arbitrary margins to apply to the element when calculating minPercentage; can be a number to apply to all sides, 2-element array to specify vertical and horizontal, or 4-element array to specify margins for each size individually + }, + obscure: true, + component: true, + details: { child_text: ['h2'] }, + contents: [ + // content information can be extracted + { + name: 'recommendation-item', // contents can be named too + selector: 'li', // selectors are relative to the parent element + details: { content: { item_name: /.+/ } }, // content item details can be captured too + contents: { name: 'recommendation_image', selector: 'img', details: { attributes: ['alt'] } }, // you can descend contents like a tree + }, + ], + }, + { + name: 'shadow', + selector: 'button.shadow', + shadowSelector: 'shadow-host', // elements within custom components/shadow hosts require their hosts' selectors to be specified + shadowOnly: true, // if the selector could erroneously catch elements outside your shadow hosts, you can restrict it to only match in shadows; by default it will match elements in and out of shadow hosts if they match the selector + }, + ], +}); + +snowplow('getComponentListGenerator', function (componentGenerator, componentGeneratorWithDetail) { + // access a context generator aware of the startElementTracking "components" configuration + // this will attach the component_parents entity to events generated by these plugins that show the component hierarchy + snowplow('enableLinkClickTracking', { context: [componentGenerator] }); + snowplow('enableFormTracking', { context: [componentGenerator] }); + + // componentGeneratorWithDetail will also populate element_detail entities for each component, but may not be directly compatible with the above APIs +}); + +snowplow('endElementTracking', {elements: ['names']}); // stop tracking all configurations with given `name`s +snowplow('endElementTracking', {elementIds: ['id']}); // to be more specific, each configuration can also have an ID to remove explicitly +snowplow('endElementTracking', {filter: (config) => true}); // decide for yourself if the configuration should be removed; must explicitly return `true` to remove; "truthy" values will not count +snowplow('endElementTracking'); // stop tracking all elements and remove listeners +``` + + +## Copyright and license + +Licensed and distributed under the [BSD 3-Clause License](LICENSE) ([An OSI Approved License][osi]). + +Copyright (c) 2024 Snowplow Analytics Ltd. + +All rights reserved. + +[npm-url]: https://www.npmjs.com/package/@snowplow/browser-plugin-element-tracking +[npm-image]: https://img.shields.io/npm/v/@snowplow/browser-plugin-element-tracking +[docs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-tracker/ +[osi]: https://opensource.org/licenses/BSD-3-Clause +[license-image]: https://img.shields.io/npm/l/@snowplow/browser-plugin-element-tracking diff --git a/plugins/browser-plugin-element-tracking/jest.config.js b/plugins/browser-plugin-element-tracking/jest.config.js new file mode 100644 index 000000000..90f99fb5b --- /dev/null +++ b/plugins/browser-plugin-element-tracking/jest.config.js @@ -0,0 +1,6 @@ +module.exports = { + preset: 'ts-jest', + reporters: ['jest-standard-reporter'], + testEnvironment: 'jest-environment-jsdom-global', + setupFilesAfterEnv: ['../../setupTestGlobals.ts'], +}; diff --git a/plugins/browser-plugin-element-tracking/package.json b/plugins/browser-plugin-element-tracking/package.json new file mode 100644 index 000000000..2b3b0c493 --- /dev/null +++ b/plugins/browser-plugin-element-tracking/package.json @@ -0,0 +1,52 @@ +{ + "name": "@snowplow/browser-plugin-element-tracking", + "version": "4.10.0", + "description": "Snowplow element tracking", + "homepage": "https://github.com/snowplow/snowplow-javascript-tracker", + "bugs": "https://github.com/snowplow/snowplow-javascript-tracker/issues", + "repository": { + "type": "git", + "url": "https://github.com/snowplow/snowplow-javascript-tracker.git" + }, + "license": "BSD-3-Clause", + "author": "Snowplow Analytics Ltd (https://snowplow.io/)", + "sideEffects": false, + "main": "./dist/index.umd.js", + "module": "./dist/index.module.js", + "types": "./dist/index.module.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "rollup -c --silent --failAfterWarnings", + "test": "jest" + }, + "dependencies": { + "@snowplow/browser-tracker-core": "workspace:*", + "@snowplow/tracker-core": "workspace:*", + "tslib": "^2.3.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "~21.0.2", + "@rollup/plugin-node-resolve": "~13.1.3", + "@types/jest": "~28.1.1", + "@types/jsdom": "~16.2.14", + "@typescript-eslint/eslint-plugin": "~5.15.0", + "@typescript-eslint/parser": "~5.15.0", + "eslint": "~8.11.0", + "jest": "~28.1.3", + "jest-environment-jsdom": "~28.1.3", + "jest-environment-jsdom-global": "~4.0.0", + "jest-standard-reporter": "~2.0.0", + "rollup": "~2.70.1", + "rollup-plugin-cleanup": "~3.2.1", + "rollup-plugin-license": "~2.6.1", + "rollup-plugin-terser": "~7.0.2", + "rollup-plugin-ts": "~2.0.5", + "ts-jest": "~28.0.8", + "typescript": "~4.6.2" + }, + "peerDependencies": { + "@snowplow/browser-tracker": "~4.10.0" + } +} diff --git a/plugins/browser-plugin-element-tracking/rollup.config.js b/plugins/browser-plugin-element-tracking/rollup.config.js new file mode 100644 index 000000000..07574f559 --- /dev/null +++ b/plugins/browser-plugin-element-tracking/rollup.config.js @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import ts from 'rollup-plugin-ts'; // Preferred over @rollup/plugin-typescript as it bundles .d.ts files +import { banner } from '../../banner'; +import { terser } from 'rollup-plugin-terser'; +import cleanup from 'rollup-plugin-cleanup'; +import pkg from './package.json'; +import { builtinModules } from 'module'; + +const umdPlugins = [nodeResolve({ browser: true }), commonjs(), ts()]; +const umdName = 'snowplowElementTracking'; + +export default [ + // CommonJS (for Node) and ES module (for bundlers) build. + { + input: './src/index.ts', + plugins: [...umdPlugins, banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main, format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + plugins: [...umdPlugins, terser(), cleanup({ comments: 'none' }), banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main.replace('.js', '.min.js'), format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + external: [...builtinModules, ...Object.keys(pkg.dependencies), ...Object.keys(pkg.devDependencies)], + plugins: [ + ts(), // so Rollup can convert TypeScript to JavaScript + banner(), + ], + output: [{ file: pkg.module, format: 'es', sourcemap: true }], + }, +]; diff --git a/plugins/browser-plugin-element-tracking/src/api.ts b/plugins/browser-plugin-element-tracking/src/api.ts new file mode 100644 index 000000000..89e41496d --- /dev/null +++ b/plugins/browser-plugin-element-tracking/src/api.ts @@ -0,0 +1,594 @@ +import { + type BrowserPlugin, + type BrowserTracker, + dispatchToTrackersInCollection, +} from '@snowplow/browser-tracker-core'; +import { type Logger, SelfDescribingJson, buildSelfDescribingEvent } from '@snowplow/tracker-core'; + +import { baseComponentGenerator } from './components'; +import { + ConfigurationState, + checkConfig, + createContextMerger, + type Configuration, + type ContextProvider, + type ElementConfiguration, +} from './configuration'; +import { buildContentTree, evaluateDataSelector, getElementDetails } from './data'; +import { ElementStatus, aggregateStats, getState } from './elementsState'; +import { ComponentsEntity, ElementDetailsEntity, Entity, Events, Event } from './schemata'; +import { Frequency, type OneOrMany } from './types'; +import { getMatchingElements, nodeIsElement, shouldTrackExpose } from './util'; + +/** + * Parameters for startElementTracking. + */ +export type ElementTrackingConfiguration = { + /** + * Optional context generator or static contexts to apply/add to any events generated by this batch of element configurations. + */ + context?: ContextProvider; + /** + * Single or array of element configurations to start tracking events for. + */ + elements: OneOrMany; +}; + +/** + * Parameters for endElementTracking. + */ +export type ElementTrackingDisable = + | { + /** + * A list of configuration names to stop tracking. Configurations can share names so this may match multiple cases. + * Configurations with no explicit name use their selector as their name. + */ + elements: OneOrMany; + } + | { + /** + * A list of configuration IDs to stop tracking. Only a single Configuration is allowed to exist per ID so this can be used to target specific instances. + */ + elementIds: OneOrMany>; + } + | { + /** + * Custom predicate to return if each Configuration should be removed (`true`) or kept (`false`). + * @param configuration The filter function to decide if the Configuration should be removed or not. + * @returns + */ + filter: (configuration: Readonly) => boolean; + }; + +const trackers: Record = {}; +const configurations: Configuration[] = []; + +const WeakestSet = typeof WeakSet === 'undefined' ? Set : WeakSet; + +const trackedThisPage: Record> = { + [Events.ELEMENT_CREATE]: new Set(), + [Events.ELEMENT_DESTROY]: new Set(), + [Events.ELEMENT_EXPOSE]: new Set(), + [Events.ELEMENT_OBSCURE]: new Set(), +}; + +const trackedElements: Record> = { + [Events.ELEMENT_CREATE]: new WeakestSet(), + [Events.ELEMENT_DESTROY]: new WeakestSet(), + [Events.ELEMENT_EXPOSE]: new WeakestSet(), + [Events.ELEMENT_OBSCURE]: new WeakestSet(), +}; + +const trackedConfigs: Record> = { + [Events.ELEMENT_CREATE]: new WeakestSet(), + [Events.ELEMENT_DESTROY]: new WeakestSet(), + [Events.ELEMENT_EXPOSE]: new WeakestSet(), + [Events.ELEMENT_OBSCURE]: new WeakestSet(), +}; + +let LOG: Logger | undefined = undefined; +let mutationObserver: MutationObserver | false = false; +let intersectionObserver: IntersectionObserver | false = false; +let currentPageViewId: string = ''; + +/** + * Plugin for tracking the addition and removal of elements to a page and the visibility of those elements. + * @param param0 Plugin configuration. + * @param param0.ignoreNextPageView Only required when use per-pageview frequency configurations and the ordering vs the pageview event matters. Defaults to `true`, which means the next pageview event will be ignored and not count as resetting the per-pageview state; this is correct if you're calling startElementTracking before calling trackPageView. + * @returns + */ +export function SnowplowElementTrackingPlugin({ ignoreNextPageView = true } = {}): BrowserPlugin { + // book keeping for controlling behavior if activated before/after first pageview + // used when tracking `when: pageview` frequency + if (ignoreNextPageView) { + Object.values(trackedThisPage).forEach((trackedThisPage) => { + trackedThisPage.add('initial'); + }); + } + + return { + activateBrowserPlugin(tracker) { + trackers[tracker.id] = tracker; + currentPageViewId = tracker.getPageViewId(); + setupObservers(); + }, + afterTrack(payload) { + if (payload['e'] === 'pv') { + // update originating pageview id + const trackerName = payload['tna']; + if (typeof trackerName === 'string' && trackerName in trackers) { + currentPageViewId = trackers[trackerName].getPageViewId(); + } + + // re-set state for `when: pageview` frequency caps + Object.values(trackedThisPage).forEach((trackedThisPage) => { + // handle book-keeping from above + if (trackedThisPage.has('initial')) { + trackedThisPage.delete('initial'); + } else { + trackedThisPage.clear(); + } + }); + } + }, + beforeTrack(payload) { + // attach stat/component entities for configured events + const e = payload.getPayload()['e']; + let eventName: string; + + if (e === 'pv') eventName = 'page_view'; + else if (e === 'pp') eventName = 'page_ping'; + else if (e === 'se') eventName = 'event'; + else if (e === 'tr') eventName = 'transaction'; + else if (e === 'ti') eventName = 'transaction_item'; + else if (e === 'ue') { + const sdjData = payload.getJson(); + for (const sdjWithKey of sdjData) { + if (sdjWithKey.keyIfEncoded === 'ue_px') { + const schema = (sdjWithKey.json.data as SelfDescribingJson).schema; + eventName = schema.split('/')[1]; + } + } + } else return; + + configurations.forEach((config) => { + if (!config.includeStats.includes(eventName) && !config.includeStats.includes('*')) return; + const elements = getMatchingElements(config); + elements.forEach((elem, i, a) => { + payload.addContextEntity(aggregateStats(config.name, elem, i + 1, a.length)); + }); + }); + }, + logger(logger) { + LOG = logger; + }, + }; +} + +function setupObservers() { + if (!mutationObserver) { + mutationObserver = typeof MutationObserver === 'function' && new MutationObserver(mutationCallback); + if (mutationObserver) + mutationObserver.observe(document.documentElement, { + attributes: true, + childList: true, + subtree: true, + }); + } + intersectionObserver = + intersectionObserver || + (typeof IntersectionObserver === 'function' && new IntersectionObserver(intersectionCallback)); +} + +/** + * Start Element tracking for elements that match the given configuration(s). + * + * Invalid configurations will be ignored, but valid configurations in the same batch will still apply. + * + * You can call this multiple times with different batches of configurations. E.g. section-specific configs, different custom context, different tracker instance destinations. + * Configurations supplied in multiple calls will not be deduped unless an `id` is provided and it collides with previous `id` values. + * + * @param param0 Element Tracking configuration options containing a batch of element configurations and optionally, custom context. + * @param trackers A list of tracker instance names that should receive events generated by this batch of element configurations. If not provided, events go to all trackers the plugin has activated for. + * @returns + */ +export function startElementTracking( + { elements = [], context }: ElementTrackingConfiguration, + trackers?: Array +): void { + const elementConfigs = Array.isArray(elements) ? elements : [elements]; + + // may have stopped observers via `endElementTracking` + if (elementConfigs.length) setupObservers(); + + elementConfigs.forEach((config) => { + try { + const batchContext = createContextMerger(context, config.context); + const valid = checkConfig(config, batchContext, !!intersectionObserver, !!mutationObserver, LOG, trackers); + + // upsert by id if provided + if (valid.id) { + const existing = configurations.findIndex(({ id }) => id === valid.id); + if (existing > -1) { + configurations[existing] = valid; + } else configurations.push(valid); + } else configurations.push(valid); + } catch (e) { + LOG?.error('Failed to process Element Tracking configuration', e, config); + } + }); + + configurations.forEach((config) => { + const { expose, obscure, state } = config; + if (state === ConfigurationState.INITIAL) { + config.state = ConfigurationState.CONFIGURED; + + const elements = getMatchingElements(config); + + elements.forEach((element, i) => { + const state = getState(element, { originalPageViewId: currentPageViewId }); + + state.lastPosition = i; + state.matches.add(config); + + trackEvent(Events.ELEMENT_CREATE, config, element, { position: i + 1, matches: elements.length }); + + if (intersectionObserver && (expose.when !== Frequency.NEVER || obscure.when !== Frequency.NEVER)) { + intersectionObserver.observe(element); + } + }); + } + }); +} + +/** + * Stop tracking events for the configurations with the given names or IDs, or satisfying a custom predicate. + * If no parameters provided, removes all previous configurations. + * All element configurations have names, if not provided the `name` is the `selector` which is required. + * + * No considerations are made for tracker instance destinations. Use IDs or filters if you need specific routing options. + * @param remove Filter information for which element configurations should be removed. Omit to remove all configurations. + */ +export function endElementTracking(remove?: ElementTrackingDisable): void { + if (!remove) { + configurations.length = 0; + } else { + if ('elementIds' in remove) { + const { elementIds } = remove; + const idsToRemove = Array.isArray(elementIds) ? elementIds : [elementIds]; + + const remaining = configurations.filter(({ id }) => { + const shouldRemove = typeof id === 'string' && idsToRemove.includes(id); + return !shouldRemove; + }); + + configurations.splice(0, configurations.length, ...remaining); + } + + if ('elements' in remove) { + const { elements } = remove; + const elsToRemove = Array.isArray(elements) ? elements : [elements]; + + const remaining = configurations.filter(({ name }) => elsToRemove.includes(name)); + + configurations.splice(0, configurations.length, ...remaining); + } + + if ('filter' in remove && typeof remove.filter === 'function') { + const remaining = configurations.filter((config) => { + try { + return remove.filter(config) !== true; + } catch (e) { + return true; + } + }); + configurations.splice(0, configurations.length, ...remaining); + } + } + + if (!configurations.length) { + if (intersectionObserver) intersectionObserver.disconnect(); + if (mutationObserver) mutationObserver.disconnect(); + mutationObserver = intersectionObserver = false; + } +} + +const componentGenerator = baseComponentGenerator.bind(null, false, configurations) as ( + ...args: any[] +) => ComponentsEntity | null; +const detailedComponentGenerator = baseComponentGenerator.bind(null, true, configurations) as ( + ...args: any[] +) => [ComponentsEntity, ...ElementDetailsEntity[]] | null; + +/** + * Obtain access to functions that can determine details about any configured `component`s and return `component_parents` context for given elements. + * + * It returns two generator functions: + * - one returns a single `component_parents` entity, which lists the names of any defined components that are ancestors of the provided element + * - the second returns multiple entities, including `component_parents` plus any element_details information about each matching component + * + * When called, the generators will examine all parameters in order looking for: + * - an element to look for owning components of + * - a string to use as the element_name in the component_parents entity + * + * The functions are suitable for use in Dynamic Context Generator functions used in other plugins such as Link and Form tracking. + * + * If a `cb` function is provided, it is called with the above generators as parameters that it can use in asynchronous situations (such as the JavaScript tracker). + * + * @param cb Callback function to receive the generator callbacks described above asynchronously. + * @returns Array of callbacks described above. + */ +export function getComponentListGenerator( + cb?: (basic: typeof componentGenerator, detailed: typeof detailedComponentGenerator) => void +): [typeof componentGenerator, typeof detailedComponentGenerator] { + if (cb) cb(componentGenerator, detailedComponentGenerator); + return [componentGenerator, detailedComponentGenerator]; +} + +/** + * Do the thing! + * + * - Build the event payload for `schema` + * - Evaluate whether we have been configured to actually send that event + * - Evaluate frequency caps + * - Build entity payloads + * - Dispatch event to trackers + * + * The actual tracking is scheduled in a new task to yield back to the callers quickly, as they may need to be performant. + * @param schema The type of event to generate/track. + * @param config The configuration that matched and triggered this event to generate. This will include any criteria for the preventing the event to fire, and information for which entities are required. + * @param element The element that is the subject of the event; used to generate entity information. + * @param options Other details about the situation; like the bounding rect of the element, its number of siblings/etc. Some of these may be expensive to recalculate if needed, so you can provide them in advance if already available. + * @returns + */ +function trackEvent( + schema: T, + config: Configuration, + element: Element | HTMLElement, + options?: Partial<{ + boundingRect: DOMRect; + position: number; + matches: number; + }> +): void { + const { boundingRect, position, matches } = options ?? {}; + + // core payload + const payload: Event = { + schema, + data: { + element_name: config.name, + }, + }; + + // check custom conditions + const conditions = { + [Events.ELEMENT_CREATE]: config.create.condition, + [Events.ELEMENT_DESTROY]: config.destroy.condition, + [Events.ELEMENT_EXPOSE]: config.expose.condition, + [Events.ELEMENT_OBSCURE]: config.obscure.condition, + }; + + if (conditions[schema]) { + if (!evaluateDataSelector(element, config.selector, conditions[schema]!).length) return; + } + + // check frequency caps + const frequencies = { + [Events.ELEMENT_CREATE]: config.create.when, + [Events.ELEMENT_DESTROY]: config.destroy.when, + [Events.ELEMENT_EXPOSE]: config.expose.when, + [Events.ELEMENT_OBSCURE]: config.obscure.when, + }; + + switch (frequencies[schema]) { + case Frequency.NEVER: + return; // abort + case Frequency.ALWAYS: + break; // continue + case Frequency.ONCE: + if (trackedConfigs[schema].has(config)) return; // once / once per config + trackedConfigs[schema].add(config); + break; + case Frequency.ELEMENT: + if (trackedElements[schema].has(element)) return; // once per element + trackedElements[schema].add(element); + break; + case Frequency.PAGEVIEW: + if (trackedThisPage[schema].has(element)) return; // once per pageview + trackedThisPage[schema].add(element); + break; + } + + // build entities + const context: (Entity | SelfDescribingJson)[] = []; + + context.push(...(config.context(element, config) as Entity[])); + + if (config.details) { + context.push( + getElementDetails( + config, + element, + boundingRect, + position, + matches, + schema === Events.ELEMENT_DESTROY || schema === Events.ELEMENT_OBSCURE + ) + ); + } + + if (config.contents.length) { + context.push(...buildContentTree(config, element, position)); + } + + const components = detailedComponentGenerator(config.name, element); + if (components) context.push(...components); + + // track the event + setTimeout(dispatchToTrackersInCollection, 0, config.trackers, trackers, (tracker: BrowserTracker) => { + const event = buildSelfDescribingEvent({ event: payload }); + tracker.core.track(event, context); + }); +} + +/** + * Handle some boilerplate/book-keeping to track an element as CREATEd. + * Saves use duplicating this logic many times in `mutationCallback`. + */ +function handleCreate(nowTs: number, config: Configuration, node: Node | Element) { + if (nodeIsElement(node) && node.matches(config.selector)) { + const state = getState(node, { originalPageViewId: currentPageViewId }); + state.state = ElementStatus.CREATED; + state.createdTs = nowTs; + state.matches.add(config); + trackEvent(Events.ELEMENT_CREATE, config, node); + if (config.expose.when !== Frequency.NEVER && intersectionObserver) intersectionObserver.observe(node); + } +} + +/** + * Handler for the mutation observer. + * Checks for two mutation types: + * attributes: for existing nodes in the document that may mutate into matching a config when they didn't previously (or vice-versa) + * childList: for node adds/removals, to find new elements added dynamically to the page that may match configurations + * + * For the former, we need to keep track of if we've matched each element against a config before to determine if it's mutated away or not; not matching now isn't enough enough information to know if it previously matched. + * If we determine a matching element has been DESTROYed, we stop observing it for intersections. + * On the other hand, if a CREATE was determined, start observing intersections if that's requested in the configuration. + */ +function mutationCallback(mutations: MutationRecord[]): void { + const nowTs = performance.now() + performance.timeOrigin; + mutations.forEach((record) => { + configurations.forEach((config) => { + const createFn = handleCreate.bind(null, nowTs, config); + + if (record.type === 'attributes') { + if (nodeIsElement(record.target)) { + const element = record.target; + const prevState = getState(element, { originalPageViewId: currentPageViewId }); + + if (prevState.state !== ElementStatus.INITIAL) { + if (!element.matches(config.selector)) { + if (prevState.matches.has(config)) { + if (prevState.state === ElementStatus.EXPOSED) trackEvent(Events.ELEMENT_OBSCURE, config, element); + trackEvent(Events.ELEMENT_DESTROY, config, element); + prevState.matches.delete(config); + if (intersectionObserver) intersectionObserver.unobserve(element); + prevState.state = ElementStatus.DESTROYED; + } + } else { + if (!prevState.matches.has(config)) { + createFn(element); + } + } + } else { + createFn(element); + } + } + } else if (record.type === 'childList') { + const matches = getMatchingElements(config); + record.addedNodes.forEach((node) => { + matches.filter((m) => node.contains(m)).forEach(createFn); + }); + record.removedNodes.forEach((node) => { + if (nodeIsElement(node)) { + const removals = node.matches(config.selector) ? [node] : []; + removals.push(...getMatchingElements(config, node)); + removals.forEach((node) => { + const state = getState(node, { originalPageViewId: currentPageViewId }); + if (state.state === ElementStatus.EXPOSED) trackEvent(Events.ELEMENT_OBSCURE, config, node); + trackEvent(Events.ELEMENT_DESTROY, config, node); + if (intersectionObserver) intersectionObserver.unobserve(node); + state.state = ElementStatus.DESTROYED; + }); + } + }); + } + }); + }); +} + +/** + * Handler for the intersection observer. + * Called when there are intersection updates, and when an element is first observed (the latter when new configs are added, or the mutation observer tries to evaluate visibility). + * + * Each entry is for a specific element, so we need to find if the element matches a config. + * With a config match we can determine if we need to fire EXPOSE/OBSCURE events for that element. + * For intersections, we first put it in a PENDING state in case we need to account for minimum time conditions. + * If time and other conditions are met, we can track the EXPOSE. + * Otherwise, we schedule an unobserve/reobserve in the next animation frame to update time in view, which will repeat until the time condition is met. This feels expensive, but seems to be OK since the layout should all be pretty freshly calculated at these points so it's actually pretty light. + * If no longer visible, consider tracking OBSCURE (unless it was DESTROYED, which would already have tried OBSCURE). + */ +function intersectionCallback(entries: IntersectionObserverEntry[], observer: IntersectionObserver): void { + entries.forEach((entry) => { + let frameRequest: number | undefined = undefined; + const state = getState(entry.target, { lastObservationTs: entry.time, originalPageViewId: currentPageViewId }); + configurations.forEach((config) => { + if (entry.target.matches(config.selector)) { + const siblings = getMatchingElements(config); + const foundIndex = siblings.findIndex((el) => el.isSameNode(entry.target)); + const position = foundIndex !== -1 ? foundIndex + 1 : Math.max(state.lastPosition + 1, 1); + const matchCount = foundIndex !== -1 ? siblings.length : Math.max(siblings.length + 1, position); + + if (foundIndex !== -1) { + state.lastPosition = foundIndex; + } + + if (entry.isIntersecting) { + if (state.state !== ElementStatus.EXPOSED && state.state !== ElementStatus.PENDING) { + Object.assign(state, { + state: ElementStatus.PENDING, + lastObservationTs: entry.time, + views: state.views + 1, + }); + } + + if (state.state === ElementStatus.PENDING) { + // check configured criteria, if any + if (shouldTrackExpose(config, entry)) { + // check time criteria + if (config.expose.minTimeMillis <= state.elapsedVisibleMs) { + state.state = ElementStatus.EXPOSED; + trackEvent(Events.ELEMENT_EXPOSE, config, entry.target, { + boundingRect: entry.boundingClientRect, + position, + matches: matchCount, + }); + } + } + } + + if (state.state === ElementStatus.PENDING || state.state === ElementStatus.EXPOSED) { + const elapsedVisibleMs = state.elapsedVisibleMs + (entry.time - state.lastObservationTs); + Object.assign(state, { + lastObservationTs: entry.time, + elapsedVisibleMs, + }); + + // check visibility time next frame + if (!frameRequest) { + frameRequest = requestAnimationFrame(() => { + observer.unobserve(entry.target); // observe is no-op for already observed elements + observer.observe(entry.target); // for non-observed elements, it immediately generates an entry of current state + }); + } + } + } else { + if (state.state === ElementStatus.EXPOSED) { + trackEvent(Events.ELEMENT_OBSCURE, config, entry.target, { + boundingRect: entry.boundingClientRect, + position, + matches: matchCount, + }); + } + + Object.assign(state, { + state: state.state === ElementStatus.DESTROYED ? ElementStatus.DESTROYED : ElementStatus.OBSCURED, + lastObservationTs: entry.time, + }); + } + } + }); + }); +} diff --git a/plugins/browser-plugin-element-tracking/src/components.ts b/plugins/browser-plugin-element-tracking/src/components.ts new file mode 100644 index 000000000..9c8e9fdb6 --- /dev/null +++ b/plugins/browser-plugin-element-tracking/src/components.ts @@ -0,0 +1,50 @@ +import type { Configuration } from './configuration'; +import { getElementDetails } from './data'; +import { ComponentsEntity, ElementDetailsEntity, Entities } from './schemata'; +import { nodeIsElement } from './util'; + +/** + * Generic callback for providing `component` entities for given Elements. + * Auto discovers element and name from parameters and returns the list of components that encapsulate that element. + * @param withDetails Whether details for each component should be included. + * @param configurations List of configurations that contain component definitions. + * @param params Arbitrary parameters that should include an element and optionally a logical name for that element. + * @returns `component_parents` entity, or if `withDetails` specified, a list of entities containing `component_parents` and the details for each component as `element` entities. + */ +export const baseComponentGenerator = ( + withDetails: boolean, + configurations: Configuration[], + ...params: any[] +): ComponentsEntity | [ComponentsEntity, ...ElementDetailsEntity[]] | null => { + const elementParams = params.filter((arg) => arg instanceof Node && nodeIsElement(arg)); + const elementName = params.find((arg) => typeof arg === 'string'); + + if (!elementParams.length) return null; + + const components: string[] = []; + const details: ElementDetailsEntity[] = []; + + elementParams.forEach((elem) => { + configurations.forEach((config) => { + if (!config.component) return; + + const ancestor = elem.closest(config.selector); + if (ancestor !== null) { + components.push(config.name); + if (withDetails && config.details) { + details.push(getElementDetails(config, ancestor)); + } + } + }); + }); + + const entity: ComponentsEntity = { + schema: Entities.COMPONENT_PARENTS, + data: { + element_name: elementName, + component_list: components, + }, + }; + + return components.length ? (withDetails ? [entity, ...details] : entity) : null; +}; diff --git a/plugins/browser-plugin-element-tracking/src/configuration.ts b/plugins/browser-plugin-element-tracking/src/configuration.ts new file mode 100644 index 000000000..d15db3f3e --- /dev/null +++ b/plugins/browser-plugin-element-tracking/src/configuration.ts @@ -0,0 +1,310 @@ +import type { Logger, SelfDescribingJson } from '@snowplow/tracker-core'; + +import { isDataSelector } from './data'; +import { type DataSelector, Frequency, type OneOrMany, type RequiredExcept } from './types'; + +export enum ConfigurationState { + INITIAL, + CONFIGURED, +} + +/** + * A dynamic context provider for events generated from the plugin. + * + * Can be a static list of Self Describing JSON entities, or a function that returns the same. + * The function will receive the matching element, and matching element configuration as parameters. + */ +export type ContextProvider = + | SelfDescribingJson[] + | ((element: Element | HTMLElement | undefined, match: Configuration) => SelfDescribingJson[]); + +/** + * Options controlling when this type of event should occur. + */ +type BaseOptions = { + /** + * Frequency cap options for how often this should be tracked over the lifetime of the plugin. + */ + when: `${Frequency}`; + /** + * A custom DataSelector defining if an element should trigger the event or not. If the DataSelector returns no result triplets, the event does not trigger. The `match` operation can be used here to do some logic against the other types of operators. + */ + condition?: DataSelector; +}; + +/** + * Additional options for controlling when an EXPOSE event should occur. + */ +type ExposeOptions = BaseOptions & { + /** + * For larger elements, only trigger if at least this proportion of the element is visible on screen; expects: 0.0 - 1.0; default: 0 + */ + minPercentage?: number; + /** + * Only trigger once the element has been in view for at least this many milliseconds. The time is measured cumulatively. After the threshold is met it will re-fire immediately. + */ + minTimeMillis?: number; + /** + * Don't count this element as visible unless its area (height * width) is at least this many pixels. Useful to prohibit empty container elements being tracked as visible. + */ + minSize?: number; + /** + * Add these dimensions (in pixels) to the element size when calculating minPercentage. Used to increase/decrease the size of the actual element before considering it visible. + */ + boundaryPixels?: [number, number, number, number] | [number, number] | number; +}; + +/** + * Input configuration format for describing a set of elements to be tracked with this plugin. + */ +export type ElementConfiguration = { + /** + * Logical name for elements matched by this configuration. This name will be used to describe any matching elements in event payloads and entities, and to associate the data between them. + * If not provided, the `selector` is used as `name`. + */ + name?: string; + /** + * Required. CSS selector to determine the set of elements that match this configuration. + */ + selector: string; + /** + * If `selector` is intended for matching elements within custom elements or shadow DOM hosts, specify a selector for the shadow hosts here; this will be used to identify shadow-elements that match `selector` that would otherwise not be visible. + */ + shadowSelector?: string; + /** + * If using `shadowSelector` to indicate `selector` matches elements in shadow hosts; use this to specify that only elements within shadow hosts matching `shadowSelector` should match; if `false` (default), elements outside shadow hosts (that are not necessarily children of `shadowSelector` hosts) will match the configuration also. + */ + shadowOnly?: boolean; + /** + * Configure when, if ever, element create events should be triggered when detected for elements matching this configuration. + * Defaults to `false`, which is shorthand for `{ when: 'never' }`. + */ + create?: boolean | BaseOptions; + /** + * Configure when, if ever, element destroy events should be triggered when detected for elements matching this configuration. + * Defaults to `false`, which is shorthand for `{ when: 'never' }`. + */ + destroy?: boolean | BaseOptions; + /** + * Configure when, if ever, element expose events should be triggered when detected for elements matching this configuration. + * Also specify additional criteria on relevant for expose events like minimum size or visibility time. + * Defaults to `true`, which is shorthand for `{ when: 'always' }` and `0` for all other options. + */ + expose?: boolean | ExposeOptions; + /** + * Configure when, if ever, element obscure events should be triggered when detected for elements matching this configuration. + * Defaults to `false`, which is shorthand for `{ when: 'never' }`. + */ + obscure?: boolean | BaseOptions; + /** + * Indicate that elements matching this configuration are "components"; their ancestry of other elements will be identified in the component_parents entity if this is set (using this configuration's `name`). + */ + component?: boolean; + /** + * When events occur to elements matching this configuration, extract data from one or more DataSelectors and include them in `attributes` in the `element` entity that describes that element. + */ + details?: OneOrMany; + /** + * When events occur to elements matching this configuration, evaluate one or more nested configurations using the matching element as a root; the `name`, `selector`, `details`, and `contents` will be processed, with other options ignored. The resulting elements (and optionally their `details` will be included as entities on events for this element.) + */ + contents?: OneOrMany; + /** + * Types of events that statistics for the element should be included on, if any. Should be the `event_name` value for events that should have the entity attached. E.g. `page_view`, `page_ping`, `expose_element`, `my_custom_event`. + */ + includeStats?: OneOrMany; + /** + * Provide custom context entities for events generated from this configuration. + */ + context?: ContextProvider; + /** + * An optional ID for this configuration. + * Calls to track configurations with a specific ID will override previous configurations with the same ID. + * No impact on actual tracking or payloads. + */ + id?: string; +}; + +/** + * Parsed valid version of `ElementConfiguration`. + * Removes some ambiguities allowed in that type that are there for a more pleasant configuration API. + */ +export type Configuration = Omit< + RequiredExcept, + 'create' | 'destroy' | 'expose' | 'obscure' | 'details' | 'includeStats' | 'contents' +> & { + trackers?: string[]; + create: BaseOptions; + destroy: BaseOptions; + expose: RequiredExcept; + obscure: BaseOptions; + state: ConfigurationState; + details: DataSelector[]; + includeStats: string[]; + contents: Configuration[]; + context: Extract; +}; + +const DEFAULT_FREQUENCY_OPTIONS: BaseOptions = { when: 'always' }; + +const emptyProvider: ContextProvider = () => []; + +/** + * Create a new ContextProvider that will merge the given `context` into that generated by the plugin or other configuration itself. + * @param context An existing ContextProvider to merge with future unknown context. + * @returns New ContextProvider function that will produce the results of merging its own context with the provided `context`. + */ +export function createContextMerger(batchContext?: ContextProvider, configContext?: ContextProvider): ContextProvider { + return function contextMerger(element, config) { + const result: SelfDescribingJson[] = []; + + for (const contextSrc of [batchContext, configContext]) { + if (contextSrc) { + if (typeof contextSrc === 'function') { + if (contextSrc !== contextMerger) result.push(...contextSrc(element, config)); + } else { + result.push(...contextSrc); + } + } + } + + return result; + }; +} + +/** + * Parse and validate a given `ElementConfiguration`, returning a more concrete `Configuration` if successful. + * @param config Input configuration to evaluate. + * @param contextProvider The context provider to embed into the configuration; this will handle merging any batch-level context into configuration-level context. + * @param trackers A list of trackers the resulting configuration should send events to, if specified. + * @returns Validated Configuration. + */ +export function checkConfig( + config: ElementConfiguration, + contextProvider: ContextProvider, + intersectionPossible: boolean, + mutationPossible: boolean, + logger?: Logger, + trackers?: string[] +): Configuration { + const { selector, name = selector, shadowSelector, shadowOnly = false, id, component = false } = config; + + // essential configs + if (typeof name !== 'string' || !name) throw new Error(`Invalid element name value: ${name}`); + if (typeof selector !== 'string' || !selector) throw new Error(`Invalid element selector value: ${selector}`); + + // these will throw if selectors invalid + document.querySelector(selector); + if (shadowSelector) document.querySelector(shadowSelector); + + // event type frequencies & options + const { create = false, destroy = false, expose = true, obscure = false } = config; + + // simple event configs + const [validCreate, validDestroy, validObscure] = [create, destroy, obscure].map((input) => { + if (!input) return { when: Frequency.NEVER }; + if (typeof input === 'object') { + const { when = 'always', condition } = input; + + if (condition && !isDataSelector(condition)) throw new Error('Invalid data selector provided for condition'); + + if (when.toUpperCase() in Frequency) { + return { + when: when.toLowerCase() as Frequency, + condition, + }; + } else { + throw new Error(`Unknown tracking frequency: ${when}`); + } + } + return DEFAULT_FREQUENCY_OPTIONS; + }); + + if ((validCreate.when !== Frequency.NEVER || validDestroy.when !== Frequency.NEVER) && !mutationPossible) + logger?.warn('MutationObserver API unavailable but required for events in configuration:', config); + + let validExpose: RequiredExcept | null = null; + + // expose has custom options and is more complex + if (expose && typeof expose === 'object') { + const { + when = 'always', + condition, + boundaryPixels = 0, + minPercentage = 0, + minSize = 0, + minTimeMillis = 0, + } = expose; + + if (condition && !isDataSelector(condition)) throw new Error('Invalid data selector provided for condition'); + if ( + (typeof boundaryPixels !== 'number' && !Array.isArray(boundaryPixels)) || + typeof minPercentage !== 'number' || + typeof minSize !== 'number' || + typeof minTimeMillis !== 'number' + ) + throw new Error('Invalid expose options provided'); + + if (when.toUpperCase() in Frequency) { + validExpose = { + when: when.toLowerCase() as Frequency, + condition, + boundaryPixels, + minPercentage, + minSize, + minTimeMillis, + }; + } else { + throw new Error(`Unknown tracking frequency: ${when}`); + } + } else if (expose) { + validExpose = { + ...DEFAULT_FREQUENCY_OPTIONS, + boundaryPixels: 0, + minPercentage: 0, + minSize: 0, + minTimeMillis: 0, + }; + } else { + validExpose = { + when: Frequency.NEVER, + boundaryPixels: 0, + minPercentage: 0, + minSize: 0, + minTimeMillis: 0, + }; + } + + if ((validExpose.when !== Frequency.NEVER || validObscure.when !== Frequency.NEVER) && !intersectionPossible) + logger?.warn('IntersectionObserver API unavailable but required for events in configuration:', config); + + // normalize to arrays (scalars allowed in input for convenience) + let { details = [], contents = [], includeStats = [] } = config; + + if (!Array.isArray(details)) details = details == null ? [] : [details]; + if (!Array.isArray(contents)) contents = contents == null ? [] : [contents]; + if (!Array.isArray(includeStats)) includeStats = includeStats == null ? [] : [includeStats]; + + if (details.length !== details.filter(isDataSelector).length) + throw new Error('Invalid DataSelector given for details'); + + return { + name, + selector, + id, + shadowSelector, + shadowOnly, + create: validCreate, + destroy: validDestroy, + expose: validExpose, + obscure: validObscure, + component: !!component, + details, + includeStats, + contents: contents.map((inner) => + checkConfig(inner, inner.context ?? emptyProvider, intersectionPossible, mutationPossible, logger, trackers) + ), + context: typeof contextProvider === 'function' ? contextProvider : () => contextProvider, + trackers, + state: ConfigurationState.INITIAL, + }; +} diff --git a/plugins/browser-plugin-element-tracking/src/data.ts b/plugins/browser-plugin-element-tracking/src/data.ts new file mode 100644 index 000000000..05315dccc --- /dev/null +++ b/plugins/browser-plugin-element-tracking/src/data.ts @@ -0,0 +1,258 @@ +import { SelfDescribingJson } from '@snowplow/tracker-core'; +import type { Configuration } from './configuration'; +import { getState } from './elementsState'; +import { ElementContentEntity, ElementDetailsEntity, Entities } from './schemata'; +import { AttributeList, type DataSelector } from './types'; +import { getMatchingElements } from './util'; + +/** + * Type guard to determine if `val` is a valid `DataSelector` function or descriptor + */ +export function isDataSelector(val: unknown): val is DataSelector { + if (val == null) return false; + if (typeof val === 'function') return true; + + type KeysOf = T extends Function ? never : keyof T; + type AllOf = Exclude extends never + ? Exclude extends never + ? T + : Exclude + : Exclude; + + const knownKeys = ['match', 'content', 'selector', 'dataset', 'attributes', 'properties', 'child_text'] as const; + const selectorKeys: AllOf, typeof knownKeys> = knownKeys; // type error if we add a new selector without updating knownKeys + + if (typeof val === 'object') return selectorKeys.some((key) => key in val); + return false; +} + +/** + * Combine the results of an array of DataSelectors + * @param element Element to select data from + * @param path The CSS path used to select `element`, which may be requested by the `selector` + * @param selectors The list of DataSelectors to evaluate + * @returns Flattened list of results found processing the element. + */ +export function extractSelectorDetails(element: Element, path: string, selectors: DataSelector[]): AttributeList { + return selectors.reduce((attributes: AttributeList, selector) => { + const result = evaluateDataSelector(element, path, selector); + + if (result.length) { + return attributes.concat(result); + } else if ('match' in selector) return []; + + return attributes; + }, []); +} + +/** + * Combine the results of an array of DataSelectors + * @param element Element to select data from + * @param path The CSS path used to select `element`, which may be requested by the `selector` DataSelector type + * @param selector The single DataSelector to evaluate + * @returns Selector results; list of key/value/source triplets that were extracted from the element + */ +export function evaluateDataSelector( + element: HTMLElement | Element, + path: string, + selector: DataSelector +): AttributeList { + const result: AttributeList = []; + + type DataSelectorType = (T extends T ? keyof T : never) | 'callback'; + let source: DataSelectorType = 'callback'; + + if (typeof selector === 'function') { + try { + const discovered = selector(element); + for (const attribute in discovered) { + if (typeof attribute === 'string' && discovered.hasOwnProperty(attribute)) { + const value = + typeof discovered[attribute] === 'object' + ? JSON.stringify(discovered[attribute]) + : String(discovered[attribute]); + result.push({ source, attribute, value }); + } + } + } catch (e) { + const value = e instanceof Error ? e.message || e.name : String(e); + result.push({ source: 'error', attribute: 'message', value }); + } + + return result; + } + + source = 'attributes'; + if (source in selector && Array.isArray(selector[source])) { + selector[source].forEach((attribute) => { + const value = element.getAttribute(attribute); + + if (value !== null) { + result.push({ source, attribute, value }); + } + }); + } + + source = 'properties'; + if (source in selector && Array.isArray(selector[source])) { + selector[source].forEach((attribute) => { + const value = (element as any)[attribute]; + + if (typeof value !== 'object' && typeof value !== 'undefined') { + result.push({ source, attribute, value: String(value) }); + } + }); + } + + source = 'dataset'; + if (source in selector && Array.isArray(selector[source])) { + selector[source].forEach((attribute) => { + if ('dataset' in element) { + const value = element.dataset[attribute]; + + if (typeof value !== 'undefined') { + result.push({ source, attribute, value: String(value) }); + } + } + }); + } + + source = 'child_text'; + if (source in selector && typeof selector[source] === 'object' && selector[source]) { + Object.entries(selector[source]).forEach(([attribute, selector]) => { + try { + const child = element.querySelector(selector) || element.shadowRoot?.querySelector(selector); + if (child && child.textContent) result.push({ source, attribute, value: child.textContent }); + } catch (e) {} + }); + } + + source = 'content'; + if (source in selector && typeof selector[source] === 'object' && selector[source]) { + Object.entries(selector[source]).forEach(([attribute, pattern]) => { + if (!(pattern instanceof RegExp)) + try { + pattern = new RegExp(pattern); + } catch (e) { + return; + } + + const innerText = element.textContent || element.shadowRoot?.textContent; + if (innerText) { + try { + const match = pattern.exec(innerText); + if (match) { + result.push({ source, attribute, value: match.length > 1 ? match[1] : match[0] }); + } + } catch (e) { + console.error(e); + } + } + }); + } + + source = 'selector'; + if (source in selector && selector[source]) { + result.push({ source, attribute: source, value: path }); + } + + source = 'match'; + if (source in selector && selector[source]) { + const condition = selector[source]; + + for (const [attribute, value] of Object.entries(condition)) { + if ( + !result.some( + (r) => r.attribute === attribute && (typeof value === 'function' ? value(r.value) : r.value === value) + ) + ) + return []; + } + } + + return result; +} + +/** + * Builds a flat list of `element_content` entities describing the matched element and any child configuration matches. + * @param config A root/branch element configuration with nested `contents` configurations. + * @param element The element that matched `config` that will be (and have its children) described. + * @param parentPosition The position of this element amongst its matching sibling elements. Used to de-flatten the tree at analysis time. + * @returns A list of `element_content` entities describing the elements and its content, and the same of its children. + */ +export function buildContentTree( + config: Configuration, + element: Element, + parentPosition: number = 1 +): (ElementContentEntity | SelfDescribingJson)[] { + const context: (ElementContentEntity | SelfDescribingJson)[] = []; + + if (element && config.contents.length) { + config.contents.forEach((contentConfig) => { + const contents = getMatchingElements(contentConfig, element); + + contents.forEach((contentElement, i) => { + const entity: ElementContentEntity = { + schema: Entities.ELEMENT_CONTENT, + data: { + parent_name: config.name, + parent_index: parentPosition, + element_name: contentConfig.name, + element_index: i + 1, + attributes: extractSelectorDetails(contentElement, contentConfig.selector, contentConfig.details), + }, + }; + + context.push(entity); + context.push(...contentConfig.context(contentElement, contentConfig)); + context.push(...buildContentTree(contentConfig, contentElement, i + 1)); + }); + }); + } + + return context; +} + +/** + * Builds an `element` entity. + * @param config Configuration describing any additional data that should be included in the entity. + * @param element The element this entity will describe. + * @param rect The position/dimension information of the element. + * @param position Which match this element is amongst those that match the Configuration's selector. + * @param matches The total number, including this one, of elements that matched the Configuration selector. + * @param usePreviousForEmpty Whether to use the previously seen size instead of the current one. Useful if the node no longer exists (e.g. destroyed). Will only apply if the new size is 0. + * @returns The Element entity SDJ. + */ +export function getElementDetails( + config: Configuration, + element: Element, + rect: DOMRect = element.getBoundingClientRect(), + position?: number, + matches?: number, + usePreviousForEmpty: boolean = false +): ElementDetailsEntity { + const state = getState(element); + + if (usePreviousForEmpty && state.lastKnownSize && (rect.height === 0 || rect.width === 0)) { + rect = state.lastKnownSize; + } + + state.lastKnownSize = rect; + + return { + schema: Entities.ELEMENT_DETAILS, + data: { + element_name: config.name, + width: rect.width, + height: rect.height, + position_x: rect.x, + position_y: rect.y, + doc_position_x: rect.x + window.scrollX, + doc_position_y: rect.y + window.scrollY, + element_index: position, + element_matches: matches, + originating_page_view: state.originalPageViewId, + attributes: extractSelectorDetails(element, config.selector, config.details), + }, + }; +} diff --git a/plugins/browser-plugin-element-tracking/src/elementsState.ts b/plugins/browser-plugin-element-tracking/src/elementsState.ts new file mode 100644 index 000000000..dd1f0ba07 --- /dev/null +++ b/plugins/browser-plugin-element-tracking/src/elementsState.ts @@ -0,0 +1,163 @@ +import type { Configuration } from './configuration'; +import { Entities, type ElementStatisticsEntity } from './schemata'; + +export enum ElementStatus { + INITIAL, + CREATED, + DESTROYED, + EXPOSED, + PENDING, + OBSCURED, +} + +/** + * Keeps track of per-element stuff we need to keep track of. + */ +type ElementState = { + /** + * Last known state for this element. Used to decide if events should be triggered or not when it's otherwise ambiguous. + */ + state: ElementStatus; + /** + * When the element was first seen/deemed "created"; for use in aggregate stats in future version. + */ + createdTs: number; + /** + * Last time we evaluated this element for a state change. Used for a delta to calculate cumulative visible time. + */ + lastObservationTs: number; + /** + * The above mentioned cumulative visible time. + */ + elapsedVisibleMs: number; + /** + * The pageview ID when we first observed this element. + */ + originalPageViewId: string; + /** + * The last position we saw of this element amongst the other matches we saw for this element. + */ + lastPosition: number; + /** + * The last non-0 size information available for this element. + */ + lastKnownSize?: DOMRect; + /** + * The other matches for this element's selector we last saw, of which the element is/was at `lastPosition`-1 position. + */ + matches: Set; + /** + * Smallest size dimensions seen so far for this element. + */ + minSize?: [number, number]; + /** + * Largest size dimensions seen so far for this element. + */ + maxSize?: [number, number]; + /** + * Largest vertical depth seen so far for this element, and the height the element was at that time. + */ + maxDepth?: [number, number]; + /** + * Number of times this element has entered viewport so far. + */ + views: number; +}; + +/** + * Bank of per-element state that needs to be stored. + */ +const elementsState = + typeof WeakMap !== 'undefined' ? new WeakMap() : new Map(); + +/** + * Obtain element state from `elementState`, creating with sane defaults if element is unknown. + * @param target Element to obtain state for. + * @param initial Initial state to include in the state if created. + * @returns State for the target element. + */ +export function getState(target: Element, initial: Partial = {}): ElementState { + if (elementsState.has(target)) { + return elementsState.get(target)!; + } else { + const nowTs = performance.now(); + const state: ElementState = { + state: ElementStatus.INITIAL, + matches: new Set(), + originalPageViewId: '', + createdTs: nowTs + performance.timeOrigin, + lastPosition: -1, + lastObservationTs: nowTs, + elapsedVisibleMs: 0, + views: 0, + ...initial, + }; + elementsState.set(target, state); + return state; + } +} + +const stateLabels: Record = { + [ElementStatus.CREATED]: 'exists', + [ElementStatus.DESTROYED]: 'destroyed', + [ElementStatus.EXPOSED]: 'on screen', + [ElementStatus.INITIAL]: 'unknown', + [ElementStatus.OBSCURED]: 'off screen', + [ElementStatus.PENDING]: 'awaiting time criteria', +}; + +const compareSize = (a: [number, number], b?: [number, number]) => { + if (b === undefined) return 0; + const asize = a[0] * a[1]; + const bsize = b[0] * b[1]; + return asize - bsize; +}; + +export function aggregateStats( + element_name: string, + target: Element, + index: number, + matches: number +): ElementStatisticsEntity { + const state = getState(target); + const stateLabel = stateLabels[state.state]; + + const rect = target.getBoundingClientRect(); + const curSize: [number, number] = [rect.width, rect.height]; + const minSize = compareSize(curSize, state.minSize) <= 0 ? curSize : state.minSize!; + const maxSize = compareSize(curSize, state.maxSize) < 0 ? state.maxSize! : curSize; + + const vpBottom = window.visualViewport + ? window.visualViewport.height + window.visualViewport.pageTop + : window.innerHeight + window.scrollY; + const curDepth: [number, number] = [Math.min(vpBottom, rect.top + rect.height) - rect.top, rect.height]; + const maxDepth = + state.maxDepth === undefined || state.maxDepth[1] === 0 + ? curDepth + : curDepth[1] === 0 + ? state.maxDepth + : curDepth[0] / curDepth[1] > state.maxDepth[0] / state.maxDepth[1] + ? curDepth + : state.maxDepth; + + Object.assign(state, { minSize, maxSize, maxDepth }); + + return { + schema: Entities.ELEMENT_STATISTICS, + data: { + element_name, + element_index: index, + element_matches: matches, + current_state: stateLabel, + min_size: minSize.join('x'), + current_size: curSize.join('x'), + max_size: maxSize.join('x'), + y_depth_ratio: curDepth[1] === 0 ? null : curDepth[0] / curDepth[1], + max_y_depth_ratio: maxDepth[1] === 0 ? null : maxDepth[0] / maxDepth[1], + max_y_depth: maxDepth.join('/'), + element_age_ms: Math.floor(performance.now() - (state.createdTs - performance.timeOrigin)), + times_in_view: state.views, + total_time_visible_ms: Math.floor(state.elapsedVisibleMs), + }, + }; +} diff --git a/plugins/browser-plugin-element-tracking/src/index.ts b/plugins/browser-plugin-element-tracking/src/index.ts new file mode 100644 index 000000000..b1c13e734 --- /dev/null +++ b/plugins/browser-plugin-element-tracking/src/index.ts @@ -0,0 +1 @@ +export * from './api'; diff --git a/plugins/browser-plugin-element-tracking/src/schemata.ts b/plugins/browser-plugin-element-tracking/src/schemata.ts new file mode 100644 index 000000000..2da3375a5 --- /dev/null +++ b/plugins/browser-plugin-element-tracking/src/schemata.ts @@ -0,0 +1,107 @@ +import { SelfDescribingJson } from '@snowplow/tracker-core'; + +import type { AttributeList } from './types'; + +export enum Events { + ELEMENT_CREATE = 'iglu:com.snowplowanalytics.snowplow/create_element/jsonschema/1-0-0', + ELEMENT_DESTROY = 'iglu:com.snowplowanalytics.snowplow/destroy_element/jsonschema/1-0-0', + ELEMENT_EXPOSE = 'iglu:com.snowplowanalytics.snowplow/expose_element/jsonschema/1-0-0', + ELEMENT_OBSCURE = 'iglu:com.snowplowanalytics.snowplow/obscure_element/jsonschema/1-0-0', +} + +export enum Entities { + ELEMENT_DETAILS = 'iglu:com.snowplowanalytics.snowplow/element/jsonschema/1-0-0', + ELEMENT_CONTENT = 'iglu:com.snowplowanalytics.snowplow/element_content/jsonschema/1-0-0', + ELEMENT_STATISTICS = 'iglu:com.snowplowanalytics.snowplow/element_statistics/jsonschema/1-0-0', + COMPONENT_PARENTS = 'iglu:com.snowplowanalytics.snowplow/component_parents/jsonschema/1-0-0', +} + +export type SDJ> = SelfDescribingJson & { + schema: S; +}; + +export type Event> = SDJ; +export type Entity> = SDJ; + +export type ElementCreateEvent = SDJ< + Events.ELEMENT_CREATE, + { + element_name: string; + } +>; + +export type ElementDestroyEvent = SDJ< + Events.ELEMENT_DESTROY, + { + element_name: string; + } +>; + +export type ElementExposeEvent = SDJ< + Events.ELEMENT_EXPOSE, + { + element_name: string; + } +>; + +export type ElementObscureEvent = SDJ< + Events.ELEMENT_OBSCURE, + { + element_name: string; + } +>; + +export type ElementContentEntity = SDJ< + Entities.ELEMENT_CONTENT, + { + parent_name: string; + parent_index: number; + element_name: string; + element_index: number; + attributes?: AttributeList; + } +>; + +export type ElementDetailsEntity = SDJ< + Entities.ELEMENT_DETAILS, + { + element_name: string; + height: number; + width: number; + position_x: number; + position_y: number; + doc_position_x: number; + doc_position_y: number; + element_index?: number; + element_matches?: number; + originating_page_view: string; + attributes?: AttributeList; + } +>; + +export type ComponentsEntity = SDJ< + Entities.COMPONENT_PARENTS, + { + element_name?: string; + component_list: string[]; + } +>; + +export type ElementStatisticsEntity = SDJ< + Entities.ELEMENT_STATISTICS, + { + element_name: string; + element_index: number; + element_matches: number; + current_state: string; + min_size: string; + current_size: string; + max_size: string; + y_depth_ratio: number | null; + max_y_depth_ratio: number | null; + max_y_depth: string; + element_age_ms: number; + times_in_view: number; + total_time_visible_ms: number; + } +>; diff --git a/plugins/browser-plugin-element-tracking/src/types.ts b/plugins/browser-plugin-element-tracking/src/types.ts new file mode 100644 index 000000000..1f046bfe3 --- /dev/null +++ b/plugins/browser-plugin-element-tracking/src/types.ts @@ -0,0 +1,76 @@ +/** + * Like `Required`, but any keys in `E` are optional instead of required. + */ +export type RequiredExcept = { + [P in Exclude]-?: Exclude; +} & { + [P in E]?: T[P]; +}; + +/** + * A thing, or an array of thing. Just a neater interface for the user writing configuration. + */ +export type OneOrMany = T | T[]; + +/** + * An attribute list details the results of running DataSelectors on an element. + * + * It's a list of key-value pairs along with a label for the source DataSelector to remove ambiguity. + * The list of objects is chosen for BigQuery compat, as it doesn't really support arbitrary "map" types. + */ +export type AttributeList = { + source: string; + attribute: string; + value: string; +}[]; + +/** + * A DataSelector defines information to extract from an element. + * + * It can be a custom function returning arbitrary key/values as an object. Non-string values will be cast to string or cast to JSON strings. If exceptions are thrown, the error information is captured. + * Alternatively there are several declarative options that can be specified as object properties. + * + * The properties allowed are: + * - attributes: Return the values of a list of attributes of the element + * - properties: Return the values of a list of property names of the element's DOM node; this is similar to attributes in some cases but different in others. E.g. `class` as an attribute needs to be `className` as a property; some attributes will reflect their initial value rather than what has been updated via JavaScript + * - dataset: Return the values of a list of data-* attributes; uses the camelCase name rather than the kebab-case name of the attribute + * - selector: Specify `true` to attach the CSS selector used to match the element; can be used to differentiate elements with the same `name` + * - content: Provide an object mapping names to RegExp patterns to run on the element's text content. If it matches it is included. The first group in the pattern will be prioritized if specified. + * - child_text: Provide an object mapping names to CSS selectors; the selectors are evaluated against the element and the first matching element's text content is the value. + * - match: Logical operator for use when used as a condition; always evaluated last. Look at existing matches so far, comparing each key/value to the provided object. Alternatively supply a predicate function that determines if this matches or not. If there are no matches, discard any matches found to this point. + */ +export type DataSelector = + | ((element: Element) => Record) + | { attributes: string[] } + | { properties: string[] } + | { dataset: string[] } + | { selector: boolean } + | { content: Record } + | { child_text: Record } + | { match: Record boolean)> }; + +/** + * When this type of event should actually be tracked after it has been detected. + */ +export enum Frequency { + /** + * Track this event every time it occurs; e.g. EXPOSE every time it scrolls into/out of view. + */ + ALWAYS = 'always', + /** + * Track this event at most once per element that matches the selector for the lifetime of the plugin. + */ + ELEMENT = 'element', + /** + * Only track the event the first time it occurs per configuration. Even if other elements would trigger the event, ignore them after the first time it occurs. + */ + ONCE = 'once', + /** + * Never track this event, effectively disabling a configuration. + */ + NEVER = 'never', + /** + * Track each event only once per element until the next pageview is seen, allowing it to be tracked again. Mostly useful for Single Page Applications. + */ + PAGEVIEW = 'pageview', +} diff --git a/plugins/browser-plugin-element-tracking/src/util.ts b/plugins/browser-plugin-element-tracking/src/util.ts new file mode 100644 index 000000000..030fc3d46 --- /dev/null +++ b/plugins/browser-plugin-element-tracking/src/util.ts @@ -0,0 +1,85 @@ +import { Configuration } from './configuration'; +import { Frequency } from './types'; + +/** + * Parses custom boundaries config. + * @param boundaryPixels Input format boundaries. + * @returns Object describing the input boundary configuration. + */ +export function defineBoundaries(boundaryPixels: number | [number, number] | [number, number, number, number]) { + let boundTop: number, boundRight: number, boundBottom: number, boundLeft: number; + if (typeof boundaryPixels === 'number') { + boundTop = boundRight = boundBottom = boundLeft = boundaryPixels; + } else if (Array.isArray(boundaryPixels)) { + if (boundaryPixels.length === 2) { + boundTop = boundBottom = boundaryPixels[0]; + boundRight = boundLeft = boundaryPixels[1]; + } else if (boundaryPixels.length === 4) { + [boundTop, boundRight, boundBottom, boundLeft] = boundaryPixels; + } else { + boundTop = boundRight = boundBottom = boundLeft = 0; + } + } else { + boundTop = boundRight = boundBottom = boundLeft = 0; + } + + return { boundTop, boundRight, boundBottom, boundLeft }; +} + +/** + * Gets descendent elements of `target` (`document` by default) that match the selector info in `config`. + * This is usually a wrapper around `querySelectorAll`, but accounts for shadow roots that can be specified in `config`. + * @param config The configuration containing the selector and other details that influence how elements will be found. + * @param target The root to start finding descendent elements from; defaults to `document` + * @returns Array of elements within `target` that matched the configuration in `config`. + */ +export function getMatchingElements(config: Configuration, target: ParentNode = document) { + const { selector, shadowOnly, shadowSelector } = config; + const elements: Element[] = shadowOnly ? [] : Array.from(target.querySelectorAll(selector)); + + if (shadowSelector) { + Array.from(target.querySelectorAll(shadowSelector), (host) => { + if (host.shadowRoot) { + // these will have been skipped in the above check but should be included if we're recursing + if (shadowOnly) elements.push(...Array.from(host.shadowRoot.querySelectorAll(selector))); + // look for nested shadow elements + elements.push(...getMatchingElements(config, host.shadowRoot)); + } + }); + } + + return elements; +} + +/** + * Type guard to check that `Node` is an `Element` + * @param node Node to check. + * @returns If `node` is an Element. + */ +export function nodeIsElement(node: Node): node is Element { + return node.nodeType === Node.ELEMENT_NODE; +} + +/** + * Evaluates whether the current intersection is eligible for firing an EXPOSE event against the given configuration. + * Mostly this handles "disabled" config (when: never), minimum size/intersection checks and custom boundaries. + */ +export function shouldTrackExpose(config: Configuration, entry: IntersectionObserverEntry): boolean { + if (config.expose.when === Frequency.NEVER) return false; + if (!entry.isIntersecting) return false; + + const { boundaryPixels, minPercentage, minSize } = config.expose; + + const { boundTop, boundRight, boundBottom, boundLeft } = defineBoundaries(boundaryPixels); + + const { boundingClientRect } = entry; + if (boundingClientRect.height * boundingClientRect.width < minSize) return false; + + const intersectionArea = entry.intersectionRect.height * entry.intersectionRect.width; + const boundingHeight = entry.boundingClientRect.height + boundTop + boundBottom; + const boundingWidth = entry.boundingClientRect.width + boundLeft + boundRight; + const boundingArea = boundingHeight * boundingWidth; + if (minPercentage > intersectionArea / boundingArea) return false; + + return true; +} diff --git a/plugins/browser-plugin-element-tracking/test/api.test.ts b/plugins/browser-plugin-element-tracking/test/api.test.ts new file mode 100644 index 000000000..4fd77b224 --- /dev/null +++ b/plugins/browser-plugin-element-tracking/test/api.test.ts @@ -0,0 +1,624 @@ +import { addTracker, BrowserTracker, SharedState } from '@snowplow/browser-tracker-core'; +import type { Logger } from '@snowplow/tracker-core'; + +import { SnowplowElementTrackingPlugin, endElementTracking, startElementTracking } from '../src'; +import { AttributeList } from '../src/types'; + +/** + * Note: jsdom does not support IntersectionObserver so unit tests can only cover create/destroy events. + * + * https://github.com/jsdom/jsdom/issues/2032 + */ + +/** + * The plugin performs asynchronously when possible for performance. + * To actually see generated events, we need to check for them in a new task. + * This fn handles boilerplate for that. + * @param cb Callback making actual assertions + * @returns Promise resolving after callback succeeds after executing in new task. Rejects if `cb` throws to avoid timeouts. + */ +const inNewTask = (cb: () => void) => + new Promise((resolve, reject) => { + expect.hasAssertions(); + setTimeout(() => { + try { + resolve(cb()); + } catch (e) { + reject(e); + } + }, 50); + }); + +const eventSDJ = ( + field: string, + evt: { evt: Record }, + schema: string +): Record | Record[] | undefined => { + try { + const payloadString = evt.evt[field] as string; + const payload = JSON.parse(payloadString); + + if (/^ue_p[rx]$/.test(field)) { + if (payload.data.schema.split('/').includes(schema)) return payload.data; + } else if (/^c[ox]$/.test(field)) { + return payload.data.filter((e: any) => e.schema.split('/').includes(schema)).map((e: any) => e.data); + } + } catch (e) {} + return; +}; + +const unstructOf = eventSDJ.bind(null, 'ue_pr'); +const entityOf = eventSDJ.bind(null, 'co'); + +const FAKE_CONTEXT_SCHEMA = 'iglu:com.example/custom_entity/jsonschema/1-0-0'; + +describe('Element Tracking Plugin API', () => { + const eventQueue: { evt: Record }[] = []; + const secondEventQueue: { evt: Record }[] = []; + let warnLog: jest.SpyInstance>; + let tracker: BrowserTracker; + + beforeAll(() => { + const state = new SharedState(); + const plugin = SnowplowElementTrackingPlugin({ ignoreNextPageView: false }); + + const activateBrowserPlugin = jest.spyOn(plugin, 'activateBrowserPlugin'); + const logger = jest.spyOn(plugin, 'logger'); + + tracker = addTracker('test', 'test', 'js-test', '', state, { + stateStorageStrategy: 'cookie', + encodeBase64: false, + plugins: [ + plugin, + { + beforeTrack: (pb) => { + eventQueue.push({ evt: pb.build() }); + }, + }, + ], + customFetch: async () => new Response(null, { status: 200 }), + })!; + + expect(activateBrowserPlugin).toHaveBeenCalled(); + expect(logger).toHaveBeenCalledTimes(1); + + addTracker('test2', 'test2', 'js-test', '', state, { + stateStorageStrategy: 'cookie', + encodeBase64: false, + plugins: [ + plugin, + { + beforeTrack: (pb) => { + secondEventQueue.push({ evt: pb.build() }); + }, + }, + ], + customFetch: async () => new Response(null, { status: 200 }), + }); + + warnLog = jest.spyOn(logger.mock.calls[0][0], 'warn'); + }); + + afterEach(() => { + endElementTracking(); + document.body.replaceChildren(); + warnLog.mockReset(); + eventQueue.length = 0; + secondEventQueue.length = 0; + }); + + describe('startElementTracking', () => { + it('warns for unavailable observer', () => { + expect(typeof IntersectionObserver).toBe('undefined'); + + startElementTracking({ elements: { selector: 'div', expose: true } }); + + return inNewTask(() => { + expect(warnLog).toHaveBeenCalled(); + expect(eventQueue).toHaveLength(0); + }); + }); + + it('silent when not requesting unavailable observer', () => { + expect(typeof IntersectionObserver).toBe('undefined'); + expect(typeof MutationObserver).toBe('function'); + + startElementTracking({ elements: { selector: 'div', expose: false, create: true } }); + + return inNewTask(() => { + expect(warnLog).not.toHaveBeenCalled(); + expect(eventQueue).toHaveLength(0); + }); + }); + + it('tracks element creation', () => { + startElementTracking({ elements: { selector: '.newelement', expose: false, create: true } }); + + const div = document.createElement('div'); + div.classList.add('newelement'); + document.body.appendChild(div); + + return inNewTask(() => { + expect(eventQueue).toHaveLength(1); + expect(unstructOf(eventQueue[0], 'create_element')).toBeDefined(); + expect(entityOf(eventQueue[0], 'element')).toHaveLength(1); + }); + }); + + it('tracks element removal', () => { + const div = document.createElement('div'); + div.classList.add('existing'); + document.body.appendChild(div); + + startElementTracking({ elements: [{ selector: '.existing', expose: false, destroy: true }] }); + + document.body.removeChild(div); + + return inNewTask(() => { + expect(eventQueue).toHaveLength(1); + expect(unstructOf(eventQueue[0], 'destroy_element')).toBeDefined(); + expect(entityOf(eventQueue[0], 'element')).toHaveLength(1); + }); + }); + + it('tracks element mutation', () => { + const div = document.createElement('div'); + document.body.appendChild(div); + + startElementTracking({ elements: [{ selector: '.mutated', expose: false, create: true, destroy: true }] }); + + // we split these changes into microtasks or else the double toggle can't actually be observed + return Promise.resolve() + .then(() => { + div.classList.toggle('mutated'); + }) + .then(() => { + div.classList.toggle('mutated'); + }) + .then(() => { + div.classList.toggle('mutated'); + }) + .then(() => + inNewTask(() => { + expect(eventQueue).toHaveLength(3); + expect(unstructOf(eventQueue[0], 'create_element')).toBeDefined(); + expect(unstructOf(eventQueue[1], 'destroy_element')).toBeDefined(); + expect(unstructOf(eventQueue[2], 'create_element')).toBeDefined(); + }) + ); + }); + + it('includes advanced details', () => { + startElementTracking({ + elements: [ + { + selector: 'body', + component: true, + }, + { + selector: '.advanced', + expose: false, + create: { + when: 'always', + }, + details: { properties: ['className'] }, + contents: { selector: 'h1', details: { content: { heading_text: '.+' } } }, + context: () => [{ schema: FAKE_CONTEXT_SCHEMA, data: { from: 'config' } }], + }, + ], + context: [{ schema: FAKE_CONTEXT_SCHEMA, data: { from: 'batch' } }], + }); + + const div = document.createElement('div'); + div.classList.add('advanced'); + const heading = document.createElement('h1'); + heading.replaceChildren('Heading'); + div.replaceChildren(heading); + document.body.appendChild(div); + + return inNewTask(() => { + expect(eventQueue).toHaveLength(1); + expect(unstructOf(eventQueue[0], 'create_element')).toBeDefined(); + + expect(entityOf(eventQueue[0], 'element')).toHaveLength(2); // .advanced and body component + const elementEntities = entityOf(eventQueue[0], 'element'); + const elementEntity = Array.isArray(elementEntities) ? elementEntities[0] : (undefined as never); + const attributeList = elementEntity.attributes as AttributeList; + expect(attributeList).toHaveLength(1); + expect(attributeList).toEqual([ + { + source: 'properties', + attribute: 'className', + value: 'advanced', + }, + ]); + + expect(entityOf(eventQueue[0], 'component_parents')).toEqual([ + { + element_name: '.advanced', + component_list: ['body'], + }, + ]); + expect(entityOf(eventQueue[0], 'element_content')).toEqual([ + { + parent_name: '.advanced', + parent_index: 1, + element_name: 'h1', + element_index: 1, + attributes: [ + { + source: 'content', + attribute: 'heading_text', + value: 'Heading', + }, + ], + }, + ]); + expect(entityOf(eventQueue[0], 'custom_entity')).toEqual([{ from: 'batch' }, { from: 'config' }]); + }); + }); + + it('frequency: once', () => { + const div = document.createElement('div'); + document.body.appendChild(div); + const div2 = document.createElement('div'); + document.body.appendChild(div2); + + startElementTracking({ elements: [{ selector: '.mutated', expose: false, create: { when: 'once' } }] }); + + // we split these changes into microtasks or else the double toggle can't actually be observed + return Promise.resolve() + .then(() => { + div.classList.toggle('mutated'); + }) + .then(() => { + div.classList.toggle('mutated'); + }) + .then(() => { + div.classList.toggle('mutated'); // this create should be skipped + }) + .then(() => { + div2.classList.toggle('mutated'); // second div should skip too + }) + .then(() => + inNewTask(() => { + expect(eventQueue).toHaveLength(1); + expect(unstructOf(eventQueue[0], 'create_element')).toBeDefined(); + }) + ); + }); + + it('frequency: element', () => { + const div = document.createElement('div'); + document.body.appendChild(div); + const div2 = document.createElement('div'); + document.body.appendChild(div2); + + startElementTracking({ + elements: [{ selector: '.mutated', expose: false, create: { when: 'element' }, destroy: true }], + }); + + // we split these changes into microtasks or else the double toggle can't actually be observed + return Promise.resolve() + .then(() => { + div.classList.toggle('mutated'); + }) + .then(() => { + div.classList.toggle('mutated'); + }) + .then(() => { + div.classList.toggle('mutated'); // this create should be skipped + }) + .then(() => { + div.classList.toggle('mutated'); + }) + .then(() => { + div2.classList.toggle('mutated'); // but not for div2 + }) + .then(() => + inNewTask(() => { + expect(eventQueue).toHaveLength(4); + expect(unstructOf(eventQueue[0], 'create_element')).toBeDefined(); + expect(unstructOf(eventQueue[1], 'destroy_element')).toBeDefined(); + expect(unstructOf(eventQueue[2], 'destroy_element')).toBeDefined(); + expect(unstructOf(eventQueue[3], 'create_element')).toBeDefined(); + }) + ); + }); + + it('frequency: pageview', () => { + const div = document.createElement('div'); + document.body.appendChild(div); + + startElementTracking({ + elements: [{ selector: '.mutated', expose: false, create: { when: 'pageview' }, destroy: true }], + }); + + // we split these changes into microtasks or else the double toggle can't actually be observed + return Promise.resolve() + .then(() => { + div.classList.toggle('mutated'); + }) + .then(() => { + div.classList.toggle('mutated'); + }) + .then(() => { + div.classList.toggle('mutated'); // this create should be skipped + }) + .then(() => { + div.classList.toggle('mutated'); + }) + .then(() => + inNewTask(() => { + tracker.trackPageView(); // new task or the order is weird + }) + ) + .then(() => { + div.classList.toggle('mutated'); // new pv, don't skip this one + }) + .then(() => + inNewTask(() => { + expect(eventQueue).toHaveLength(5); + expect(unstructOf(eventQueue[0], 'create_element')).toBeDefined(); + expect(unstructOf(eventQueue[1], 'destroy_element')).toBeDefined(); + expect(unstructOf(eventQueue[2], 'destroy_element')).toBeDefined(); + expect(eventQueue[3].evt.e).toBe('pv'); + expect(unstructOf(eventQueue[4], 'create_element')).toBeDefined(); + }) + ); + }); + + it('evaluates conditions', () => { + startElementTracking({ + elements: { + selector: 'div', + expose: false, + create: { + when: 'always', + condition: { dataset: ['fake'] }, + }, + }, + }); + + const div = document.createElement('div'); + document.body.appendChild(div); + + return inNewTask(() => { + expect(eventQueue).toHaveLength(0); + }); + }); + + it('dedupes by id', () => { + startElementTracking({ + elements: { + id: 'test', + selector: 'span', + expose: false, + create: true, + }, + }); + + startElementTracking({ + elements: { + id: 'test', + selector: 'div', + expose: false, + create: true, + }, + }); + + for (const nodeName of ['div', 'span']) { + const element = document.createElement(nodeName); + document.body.appendChild(element); + } + + return inNewTask(() => { + expect(eventQueue).toHaveLength(1); + }); + }); + + it('adds element stats', () => { + startElementTracking({ + elements: { selector: '.newelement', expose: false, create: false, includeStats: 'page_view' }, + }); + + const div = document.createElement('div'); + div.classList.add('newelement'); + document.body.appendChild(div); + + tracker.trackPageView(); + tracker.trackPageView(); + + return inNewTask(() => { + expect(eventQueue).toHaveLength(2); + expect(entityOf(eventQueue[0], 'element_statistics')).toHaveLength(1); + expect(entityOf(eventQueue[1], 'element_statistics')).toHaveLength(1); + }); + }); + }); + + describe('multiple tracker', () => { + it('works with multiple trackers', () => { + startElementTracking({ elements: { selector: '.newelement', expose: false, create: true } }); + + const div = document.createElement('div'); + div.classList.add('newelement'); + document.body.appendChild(div); + + return inNewTask(() => { + expect(eventQueue).toHaveLength(1); + expect(secondEventQueue).toHaveLength(1); + expect(unstructOf(eventQueue[0], 'create_element')).toBeDefined(); + expect(unstructOf(secondEventQueue[0], 'create_element')).toBeDefined(); + expect(entityOf(eventQueue[0], 'element')).toHaveLength(1); + expect(entityOf(secondEventQueue[0], 'element')).toHaveLength(1); + }); + }); + + it('works with selective trackers', () => { + startElementTracking({ elements: { selector: '.newelement', expose: false, create: true } }, ['test']); + + const div = document.createElement('div'); + div.classList.add('newelement'); + document.body.appendChild(div); + + return inNewTask(() => { + expect(eventQueue).toHaveLength(1); + expect(secondEventQueue).toHaveLength(0); + expect(unstructOf(eventQueue[0], 'create_element')).toBeDefined(); + expect(entityOf(eventQueue[0], 'element')).toHaveLength(1); + }); + }); + }); + + describe('endElementTracking', () => { + it('untracks by id', () => { + startElementTracking({ + elements: { + id: 'test', + selector: 'div', + expose: false, + create: true, + }, + }); + + endElementTracking({ elementIds: ['test'] }); + + const div = document.createElement('div'); + document.body.appendChild(div); + + return inNewTask(() => { + expect(eventQueue).toHaveLength(0); + }); + }); + + it('untracks by name', () => { + startElementTracking({ + elements: [ + { + selector: 'div', + expose: false, + create: true, + }, + { + selector: 'span', + expose: false, + create: true, + }, + ], + }); + + endElementTracking({ elements: ['span'] }); + + for (const nodeName of ['div', 'span']) { + const element = document.createElement(nodeName); + document.body.appendChild(element); + } + + return inNewTask(() => { + expect(eventQueue).toHaveLength(1); + }); + }); + + it('untracks by filter', () => { + startElementTracking({ + elements: [ + { + selector: 'div', + expose: false, + create: true, + }, + { + selector: 'span', + expose: false, + create: true, + }, + ], + }); + + endElementTracking({ filter: (config) => config.create.when === 'always' }); + + for (const nodeName of ['div', 'span']) { + const element = document.createElement(nodeName); + document.body.appendChild(element); + } + + return inNewTask(() => { + expect(eventQueue).toHaveLength(0); + }); + }); + }); + + describe('intersectionCallback position fallback', () => { + let intersectionCallback: IntersectionObserverCallback; + + beforeAll(() => { + // Mock IntersectionObserver to capture the callback + (globalThis as any).IntersectionObserver = class { + constructor(cb: IntersectionObserverCallback) { + intersectionCallback = cb; + } + observe() {} + unobserve() {} + disconnect() {} + }; + }); + + afterAll(() => { + delete (globalThis as any).IntersectionObserver; + }); + + it('uses last-known position when element is no longer in DOM during intersection callback', () => { + // Create two matching elements so position > 1 is testable + const div1 = document.createElement('div'); + div1.classList.add('disappearing'); + document.body.appendChild(div1); + + const div2 = document.createElement('div'); + div2.classList.add('disappearing'); + document.body.appendChild(div2); + + startElementTracking({ + elements: { + selector: '.disappearing', + expose: true, + }, + }); + + // Remove div2 from DOM before firing intersection + document.body.removeChild(div2); + + // Simulate intersection callback for the now-removed div2 + const fakeEntry = { + target: div2, + isIntersecting: true, + intersectionRatio: 1, + intersectionRect: { height: 100, width: 100 } as DOMRect, + boundingClientRect: { x: 0, y: 0, width: 100, height: 100 } as DOMRect, + rootBounds: null, + time: performance.now(), + } as IntersectionObserverEntry; + + intersectionCallback([fakeEntry], { + unobserve() {}, + observe() {}, + disconnect() {}, + } as unknown as IntersectionObserver); + + return inNewTask(() => { + expect(eventQueue.length).toBeGreaterThanOrEqual(1); + + const exposeEvent = eventQueue.find((e) => unstructOf(e, 'expose_element')); + expect(exposeEvent).toBeDefined(); + + const elementEntities = entityOf(exposeEvent!, 'element') as Record[]; + expect(elementEntities).toBeDefined(); + expect(elementEntities.length).toBeGreaterThanOrEqual(1); + + // element_index must be >= 1, never 0 + const elementEntity = elementEntities[0]; + expect(elementEntity.element_index).toBeGreaterThanOrEqual(1); + }); + }); + }); +}); diff --git a/plugins/browser-plugin-element-tracking/test/components.test.ts b/plugins/browser-plugin-element-tracking/test/components.test.ts new file mode 100644 index 000000000..6dabfb996 --- /dev/null +++ b/plugins/browser-plugin-element-tracking/test/components.test.ts @@ -0,0 +1,43 @@ +import { baseComponentGenerator } from '../src/components'; +import { Entities } from '../src/schemata'; +import { Configuration } from '../src/configuration'; + +describe('component detection', () => { + let container: HTMLElement; + const config: Configuration = { + name: 'template', + selector: 'body', + shadowOnly: false, + component: true, + context: () => [], + trackers: [], + create: { when: 'never' }, + destroy: { when: 'never' }, + expose: { when: 'never', minPercentage: 0, boundaryPixels: 0, minSize: 0, minTimeMillis: 0 }, + obscure: { when: 'never' }, + state: 0, + details: [], + contents: [], + includeStats: [], + }; + + beforeAll(() => { + container = document.createElement('div'); + document.body.appendChild(container); + }); + + it('no-ops without target element', () => { + expect(baseComponentGenerator(true, [config])).toBeNull(); + }); + + it('finds components from child target', () => { + expect(baseComponentGenerator(false, [config], container)).toEqual({ + schema: Entities.COMPONENT_PARENTS, + data: { + component_list: [config.name], + }, + }); + + expect(baseComponentGenerator(true, [config], container)).toHaveLength(2); + }); +}); diff --git a/plugins/browser-plugin-element-tracking/test/configuration.test.ts b/plugins/browser-plugin-element-tracking/test/configuration.test.ts new file mode 100644 index 000000000..b1818d1de --- /dev/null +++ b/plugins/browser-plugin-element-tracking/test/configuration.test.ts @@ -0,0 +1,128 @@ +import { + Configuration, + type ContextProvider, + ElementConfiguration, + checkConfig, + createContextMerger, +} from '../src/configuration'; + +describe('configuration parsing', () => { + const emptyMerger = createContextMerger(); + + // Accept valid configs + it.each<{ note: string; input: ElementConfiguration; expected?: Partial }>([ + { + note: 'minimal configuration', + input: { selector: '.oncreate' }, + }, + { + note: 'use selector when no name', + input: { selector: 'unnamed' }, + expected: { selector: 'unnamed', name: 'unnamed' }, + }, + { + note: 'custom name', + input: { selector: '.selector', name: 'named' }, + expected: { selector: '.selector', name: 'named' }, + }, + { + note: 'default event frequencies', + input: { selector: 'unnamed' }, + expected: { + create: { when: 'never' }, + destroy: { when: 'never' }, + expose: { when: 'always', boundaryPixels: 0, minPercentage: 0, minSize: 0, minTimeMillis: 0 }, + obscure: { when: 'never' }, + component: false, + contents: [], + details: [], + }, + }, + { + note: 'custom frequencies', + input: { selector: 'unnamed', expose: false, create: true }, + expected: { + create: { when: 'always' }, + expose: { when: 'never', boundaryPixels: 0, minPercentage: 0, minSize: 0, minTimeMillis: 0 }, + }, + }, + { + note: 'mis-cased frequencies', + input: { selector: 'unnamed', create: { when: 'ALWAYs' as any }, expose: { when: 'Never' as any } }, + expected: { + create: { when: 'always' }, + expose: { when: 'never' } as any, + }, + }, + { + note: 'context provider', + input: { selector: 'unnamed', context: [] }, + expected: { + context: emptyMerger as Extract, + }, + }, + { + note: 'contents recursion', + input: { selector: 'unnamed', contents: { selector: 'inner' } }, + }, + ])('accepts valid config: $note', ({ input, expected }) => { + const result = checkConfig(input, emptyMerger, true, true); + expect(result).toBeDefined(); + if (expected) expect(result).toMatchObject(expected); + }); + + // Reject invalid configs + it.each<{ note: string; input: ElementConfiguration }>([ + { + note: 'invalid name', + input: { selector: 'a', name: '' }, + }, + { + note: 'empty selector', + input: { selector: '' }, + }, + { + note: 'invalid selector', + input: { selector: ':asdf' }, + }, + { + note: 'mistyped selector', + input: { selector: 1 as any }, + }, + { + note: 'good name, bad selector', + input: { selector: '', name: 'named' }, + }, + { + note: 'bad expose condition', + input: { selector: '.good', name: 'named', expose: { condition: {} } as any }, + }, + { + note: 'bad other condition', + input: { selector: '.good', name: 'named', create: { condition: true } as any }, + }, + { + note: 'bad expose frequency', + input: { selector: '.good', name: 'named', expose: { when: 'fail' } }, + }, + { + note: 'bad other frequency', + input: { selector: '.good', name: 'named', create: { when: 'fail' } }, + }, + { + note: 'bad boundaries', + input: { selector: '.good', name: 'named', expose: { when: 'always', boundaryPixels: '1em' } }, + }, + { + note: 'bad details request', + input: { selector: '.good', name: 'named', details: {} as any }, + }, + ])('rejects invalid config: $note', ({ input }) => { + expect.hasAssertions(); + try { + checkConfig(input, emptyMerger, true, true); + } catch (e) { + expect(e).toBeDefined(); + } + }); +}); diff --git a/plugins/browser-plugin-element-tracking/test/data.test.ts b/plugins/browser-plugin-element-tracking/test/data.test.ts new file mode 100644 index 000000000..cb0b2552a --- /dev/null +++ b/plugins/browser-plugin-element-tracking/test/data.test.ts @@ -0,0 +1,139 @@ +import { evaluateDataSelector, extractSelectorDetails, isDataSelector } from '../src/data'; +import type { DataSelector } from '../src/types'; + +describe('DataSelector behavior', () => { + const fake_selector = 'css_path_val'; + let elem: HTMLDivElement; + + beforeAll(() => { + // sample element we'll be selecting from + elem = document.createElement('div'); + + elem.textContent = 'text_content_val\n'; + elem.setAttribute('id', 'id_attr'); + elem.className = 'class_prop'; + elem.dataset.dsAttr = 'ds_val'; + + const child = document.createElement('span'); + child.textContent = 'child_text_val'; + elem.appendChild(child); + }); + + it.each([ + ['attributes', ['id'], 'id_attr'], + ['properties', ['className'], 'class_prop'], + ['dataset', ['dsAttr'], 'ds_val'], + ['child_text', { inner: 'span' }, 'child_text_val'], + ['content', { inner: 'text_content\\S+' }, 'text_content_val'], + ['selector', true, fake_selector], + ])('extracts %p', (source, params, value) => { + const selector = { [source]: params } as DataSelector; + expect(isDataSelector(selector)).toBe(true); + + const result = evaluateDataSelector(elem, fake_selector, selector); + + const expected = Array.isArray(params) ? params : params === true ? [source] : Object.keys(params); + + expect(result).toEqual( + expected.map((attribute) => ({ + source, + attribute, + value, + })) + ); + }); + + it('handles callbacks', () => { + const sel = jest.fn().mockReturnValueOnce({ attribute: 'value', complex: { nested: 'data' } }); + + expect(isDataSelector(sel)).toBe(true); + + const result = evaluateDataSelector(elem, fake_selector, sel); + + expect(sel).toBeCalledWith(elem); + expect(result).toEqual([ + { + source: 'callback', + attribute: 'attribute', + value: 'value', + }, + { + source: 'callback', + attribute: 'complex', + value: '{"nested":"data"}', + }, + ]); + }); + + it('handles callback failures', () => { + const sel = jest.fn, Element[]>(() => { + throw new Error('deliberate failure'); + }); + + expect(isDataSelector(sel)).toBe(true); + + const result = evaluateDataSelector(elem, fake_selector, sel); + + expect(sel).toBeCalledWith(elem); + expect(result).toEqual([ + { + source: 'error', + attribute: 'message', + value: 'deliberate failure', + }, + ]); + }); + + it('flattens correctly', () => { + const result = extractSelectorDetails(elem, fake_selector, [ + { attributes: ['id'] }, + { properties: ['className'] }, + { properties: ['DOES_NOT_EXIST'] }, + ]); + + expect(result).toHaveLength(2); + }); + + it('doesnt mix properties and attributes', () => { + const result = evaluateDataSelector(elem, fake_selector, { + attributes: ['className', 'class'], + properties: ['className', 'class'], + }); + + expect(result).toHaveLength(2); + + expect(result).toContainEqual({ + source: 'properties', + attribute: 'className', + value: 'class_prop', + }); + + expect(result).toContainEqual({ + source: 'attributes', + attribute: 'class', + value: 'class_prop', + }); + }); + + it('produces successful matches', () => { + const result = evaluateDataSelector(elem, fake_selector, { + attributes: ['id'], + match: { id: 'id_attr' }, + }); + + expect(result).toHaveLength(1); + }); + + it('filters unsuccessful matches', () => { + const result = evaluateDataSelector(elem, fake_selector, { + attributes: ['id'], + match: { id: 'NOT_REAL_VALUE' }, + }); + + expect(result).toHaveLength(0); + }); + + it.each([null, {}, { notASelector: [] }])('ignores empty: %j', (invalid) => { + expect(isDataSelector(invalid)).toBe(false); + }); +}); diff --git a/plugins/browser-plugin-element-tracking/test/util.test.ts b/plugins/browser-plugin-element-tracking/test/util.test.ts new file mode 100644 index 000000000..6325ab74e --- /dev/null +++ b/plugins/browser-plugin-element-tracking/test/util.test.ts @@ -0,0 +1,246 @@ +import { defineBoundaries, getMatchingElements, nodeIsElement, shouldTrackExpose } from '../src/util'; +import type { Configuration } from '../src/configuration'; + +const TEMPLATE_CONFIG: Configuration = { + name: 'template', + selector: '', + shadowOnly: false, + component: false, + context: () => [], + trackers: [], + create: { when: 'never' }, + destroy: { when: 'never' }, + expose: { when: 'never', minPercentage: 0, boundaryPixels: 0, minSize: 0, minTimeMillis: 0 }, + obscure: { when: 'never' }, + state: 0, + details: [], + contents: [], + includeStats: [], +}; + +const TEMPLATE_DOMRECT: DOMRectReadOnly = { + bottom: 0, + top: 0, + left: 0, + right: 0, + height: 0, + width: 0, + x: 0, + y: 0, + toJSON() {}, +}; + +const TEMPLATE_INTERSECTION: IntersectionObserverEntry = { + time: 0, + isIntersecting: true, + target: document.body, + rootBounds: null, + boundingClientRect: TEMPLATE_DOMRECT, + intersectionRatio: 0, + intersectionRect: TEMPLATE_DOMRECT, +}; + +describe('utils', () => { + describe('defineBoundaries', () => { + it.each([ + [0, [0, 0, 0, 0]], + [1, [1, 1, 1, 1]], + [[0, 1] as [number, number], [0, 1, 0, 1]], + [[2, 2, 2, 2] as [number, number, number, number], [2, 2, 2, 2]], + [[2, 2, 2] as any as [number, number, number, number], [0, 0, 0, 0]], // silent error + [{} as any as number, [0, 0, 0, 0]], // silent error + ])('interprets: %j', (provided, expected) => { + const [boundTop, boundRight, boundBottom, boundLeft] = expected; + expect(defineBoundaries(provided)).toEqual({ + boundTop, + boundRight, + boundBottom, + boundLeft, + }); + }); + }); + + describe('getMatchingElements', () => { + it('queries for nodes', () => { + const config: Configuration = { ...TEMPLATE_CONFIG, selector: 'body' }; + const results = getMatchingElements(config); + expect(results).toHaveLength(1); + expect(results[0]).toBe(document.body); + expect(nodeIsElement(results[0])).toBe(true); + + const explicitTarget = getMatchingElements(config, document); + expect(results).toEqual(explicitTarget); + }); + + describe('shadow host support', () => { + const elements: Element[] = []; + const config: Configuration = { ...TEMPLATE_CONFIG, selector: 'span' }; + + beforeAll(() => { + const host = document.createElement('div'); + host.id = 'shadowHost'; + const shadow = host.attachShadow({ mode: 'open' }); + document.body.appendChild(host); + + for (let i = 5; i > 0; i--) { + const el = document.createElement('span'); + shadow.appendChild(el); + elements.push(el); + } + }); + + afterAll(() => { + document.body.replaceChildren(); + }); + + it('should not find from shadow roots by default', () => { + expect(getMatchingElements(config)).toHaveLength(0); + }); + + it('should descend shadow hosts matching shadowSelector', () => { + const shadowConfig: Configuration = { + ...config, + shadowSelector: '#shadowHost', + }; + + expect(getMatchingElements(shadowConfig)).toEqual(elements); + }); + + it('should respect shadowOnly setting', () => { + const shadowConfig: Configuration = { + ...config, + shadowSelector: '#shadowHost', + shadowOnly: false, + }; + + let results = getMatchingElements(shadowConfig); + + expect(results).toEqual(elements); + + // with shadowOnly: false, should find a non-shadow span, too + const addition = document.createElement('span'); + document.body.appendChild(addition); + + results = getMatchingElements(shadowConfig); + expect(results).not.toEqual(elements); + expect(results).toHaveLength(elements.length + 1); + expect(results).toEqual(elements.concat([addition])); + + // with shadowOnly: true, should ignore the non-shadow span + results = getMatchingElements({ ...shadowConfig, shadowOnly: true }); + expect(results).toEqual(elements); + }); + + it('should find nested shadow targets', () => { + const shadowConfig: Configuration = { + ...config, + shadowSelector: '#shadowHost', + shadowOnly: true, + }; + + let results = getMatchingElements(shadowConfig); + + expect(results).toEqual(elements); + + const host = document.querySelector('#shadowHost')!.shadowRoot!; + const addition = document.createElement('span'); + host.appendChild(addition); + + results = getMatchingElements(shadowConfig); + expect(results).not.toEqual(elements); + expect(results).toHaveLength(elements.length + 1); + expect(results).toEqual(elements.concat([addition])); + }); + }); + }); + + describe('shouldTrackExpose', () => { + it.each([ + ['frequency: never', { when: 'never' as const }, {}, false], + ['not intersecting', { when: 'always' as const }, { isIntersecting: false }, false], + ['intersecting', { when: 'always' as const }, { isIntersecting: true }, true], + ['zero-size', { when: 'always' as const, minSize: 1 }, { isIntersecting: true }, false], + [ + 'partial view', + { when: 'always' as const, minPercentage: 1 }, + { + intersectionRatio: (100 * 100) / (200 * 200), + intersectionRect: { ...TEMPLATE_DOMRECT, width: 100, height: 100 }, + boundingClientRect: { ...TEMPLATE_DOMRECT, width: 200, height: 200 }, + }, + false, + ], + [ + 'sufficent view', + { when: 'always' as const, minPercentage: (200 * 160) / (200 * 200) }, + { + intersectionRatio: (200 * 160) / (200 * 200), + intersectionRect: { ...TEMPLATE_DOMRECT, width: 200, height: 160 }, + boundingClientRect: { ...TEMPLATE_DOMRECT, width: 200, height: 200 }, + }, + true, + ], + [ + 'insufficent view', + { when: 'always' as const, minPercentage: (200 * 160) / (200 * 200) }, + { + intersectionRatio: (200 * 159) / (200 * 200), + intersectionRect: { ...TEMPLATE_DOMRECT, width: 200, height: 159 }, + boundingClientRect: { ...TEMPLATE_DOMRECT, width: 200, height: 200 }, + }, + false, + ], + [ + 'shrunken element', + { when: 'always' as const, minPercentage: (200 * 160) / (200 * 200), boundaryPixels: -100 }, + { + intersectionRatio: (200 * 159) / (200 * 200), + intersectionRect: { ...TEMPLATE_DOMRECT, width: 200, height: 159 }, + boundingClientRect: { ...TEMPLATE_DOMRECT, width: 200, height: 200 }, + }, + true, + ], + [ + 'enlarged element - possible', + { when: 'always' as const, minPercentage: 0.1, boundaryPixels: 100 }, + { + intersectionRatio: (200 * 200) / (200 * 200), + intersectionRect: { ...TEMPLATE_DOMRECT, width: 200, height: 200 }, + boundingClientRect: { ...TEMPLATE_DOMRECT, width: 200, height: 200 }, + }, + true, + ], + [ + 'enlarged element - impossible', + { when: 'always' as const, minPercentage: 1, boundaryPixels: 100 }, + { + intersectionRatio: (200 * 200) / (200 * 200), + intersectionRect: { ...TEMPLATE_DOMRECT, width: 200, height: 200 }, + boundingClientRect: { ...TEMPLATE_DOMRECT, width: 200, height: 200 }, + }, + false, + ], + ])( + '%s', + ( + _: string, + expose: Partial, + entry: Partial, + shouldPass: boolean + ) => { + expect( + shouldTrackExpose( + { + ...TEMPLATE_CONFIG, + expose: { ...TEMPLATE_CONFIG.expose, ...expose }, + }, + { + ...TEMPLATE_INTERSECTION, + ...entry, + } + ) + ).toBe(shouldPass); + } + ); + }); +}); diff --git a/plugins/browser-plugin-element-tracking/tsconfig.json b/plugins/browser-plugin-element-tracking/tsconfig.json new file mode 100644 index 000000000..4082f16a5 --- /dev/null +++ b/plugins/browser-plugin-element-tracking/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +} diff --git a/plugins/browser-plugin-enhanced-consent/CHANGELOG.json b/plugins/browser-plugin-enhanced-consent/CHANGELOG.json new file mode 100644 index 000000000..2680d876b --- /dev/null +++ b/plugins/browser-plugin-enhanced-consent/CHANGELOG.json @@ -0,0 +1,365 @@ +{ + "name": "@snowplow/browser-plugin-enhanced-consent", + "entries": [ + { + "version": "4.10.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.10.0", + "date": "Mon, 27 Jul 2026 13:52:14 GMT", + "comments": {} + }, + { + "version": "4.9.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.9.0", + "date": "Tue, 21 Jul 2026 14:53:08 GMT", + "comments": {} + }, + { + "version": "4.8.4", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.8.4", + "date": "Thu, 02 Jul 2026 10:07:52 GMT", + "comments": {} + }, + { + "version": "4.8.3", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.8.3", + "date": "Tue, 30 Jun 2026 14:22:03 GMT", + "comments": { + "none": [ + { + "comment": "Update uuid to v11 and remove closure-compiler from the build pipeline" + } + ] + } + }, + { + "version": "4.8.2", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.8.2", + "date": "Wed, 17 Jun 2026 12:30:12 GMT", + "comments": {} + }, + { + "version": "4.8.1", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.8.1", + "date": "Wed, 13 May 2026 09:26:05 GMT", + "comments": {} + }, + { + "version": "4.8.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.8.0", + "date": "Tue, 28 Apr 2026 07:56:22 GMT", + "comments": {} + }, + { + "version": "4.7.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.7.0", + "date": "Wed, 01 Apr 2026 12:59:29 GMT", + "comments": {} + }, + { + "version": "4.6.9", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.6.9", + "date": "Mon, 16 Mar 2026 15:43:06 GMT", + "comments": {} + }, + { + "version": "4.6.8", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.6.8", + "date": "Tue, 28 Oct 2025 09:46:42 GMT", + "comments": {} + }, + { + "version": "4.6.7", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.6.7", + "date": "Tue, 07 Oct 2025 14:53:36 GMT", + "comments": {} + }, + { + "version": "4.6.6", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.6.6", + "date": "Tue, 26 Aug 2025 08:42:27 GMT", + "comments": {} + }, + { + "version": "4.6.5", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.6.5", + "date": "Wed, 25 Jun 2025 21:16:46 GMT", + "comments": {} + }, + { + "version": "4.6.4", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.6.4", + "date": "Wed, 25 Jun 2025 12:08:50 GMT", + "comments": {} + }, + { + "version": "4.6.3", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.6.3", + "date": "Thu, 29 May 2025 19:52:07 GMT", + "comments": {} + }, + { + "version": "4.6.2", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.6.2", + "date": "Tue, 20 May 2025 07:39:05 GMT", + "comments": {} + }, + { + "version": "4.6.1", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.6.1", + "date": "Tue, 06 May 2025 13:10:51 GMT", + "comments": {} + }, + { + "version": "4.6.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.6.0", + "date": "Thu, 01 May 2025 09:58:59 GMT", + "comments": {} + }, + { + "version": "4.5.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.5.0", + "date": "Fri, 04 Apr 2025 09:21:23 GMT", + "comments": {} + }, + { + "version": "4.4.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.4.0", + "date": "Thu, 20 Mar 2025 12:14:34 GMT", + "comments": {} + }, + { + "version": "4.3.1", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.3.1", + "date": "Tue, 21 Jan 2025 11:09:42 GMT", + "comments": {} + }, + { + "version": "4.3.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.3.0", + "date": "Mon, 20 Jan 2025 11:45:13 GMT", + "comments": {} + }, + { + "version": "4.2.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.2.0", + "date": "Mon, 13 Jan 2025 08:30:05 GMT", + "comments": {} + }, + { + "version": "4.1.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.1.0", + "date": "Thu, 28 Nov 2024 10:57:30 GMT", + "comments": {} + }, + { + "version": "4.0.4", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.0.4", + "date": "Thu, 21 Nov 2024 09:06:36 GMT", + "comments": {} + }, + { + "version": "4.0.3", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.0.3", + "date": "Wed, 20 Nov 2024 09:30:31 GMT", + "comments": {} + }, + { + "version": "4.0.2", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.0.2", + "date": "Mon, 11 Nov 2024 15:46:33 GMT", + "comments": {} + }, + { + "version": "4.0.1", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.0.1", + "date": "Fri, 01 Nov 2024 10:35:07 GMT", + "comments": {} + }, + { + "version": "4.0.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v4.0.0", + "date": "Mon, 28 Oct 2024 11:48:53 GMT", + "comments": {} + }, + { + "version": "3.24.6", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.24.6", + "date": "Mon, 28 Oct 2024 10:23:28 GMT", + "comments": {} + }, + { + "version": "3.24.5", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.24.5", + "date": "Fri, 25 Oct 2024 08:53:04 GMT", + "comments": {} + }, + { + "version": "3.24.4", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.24.4", + "date": "Thu, 26 Sep 2024 06:10:22 GMT", + "comments": {} + }, + { + "version": "3.24.3", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.24.3", + "date": "Tue, 03 Sep 2024 08:15:14 GMT", + "comments": { + "none": [ + { + "comment": "Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush" + } + ] + } + }, + { + "version": "3.24.2", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.24.2", + "date": "Wed, 24 Jul 2024 08:59:00 GMT", + "comments": {} + }, + { + "version": "3.24.1", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.24.1", + "date": "Tue, 02 Jul 2024 07:08:17 GMT", + "comments": {} + }, + { + "version": "3.24.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.24.0", + "date": "Tue, 25 Jun 2024 08:31:05 GMT", + "comments": {} + }, + { + "version": "3.23.1", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.23.1", + "date": "Tue, 04 Jun 2024 13:34:45 GMT", + "comments": {} + }, + { + "version": "3.23.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.23.0", + "date": "Thu, 28 Mar 2024 11:28:45 GMT", + "comments": {} + }, + { + "version": "3.22.1", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.22.1", + "date": "Wed, 13 Mar 2024 08:39:48 GMT", + "comments": {} + }, + { + "version": "3.22.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.22.0", + "date": "Fri, 08 Mar 2024 08:13:04 GMT", + "comments": {} + }, + { + "version": "3.21.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.21.0", + "date": "Mon, 29 Jan 2024 08:34:06 GMT", + "comments": {} + }, + { + "version": "3.20.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.20.0", + "date": "Mon, 15 Jan 2024 14:41:16 GMT", + "comments": {} + }, + { + "version": "3.19.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.19.0", + "date": "Thu, 14 Dec 2023 10:45:22 GMT", + "comments": {} + }, + { + "version": "3.18.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.18.0", + "date": "Mon, 04 Dec 2023 13:44:02 GMT", + "comments": {} + }, + { + "version": "3.17.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.17.0", + "date": "Tue, 14 Nov 2023 17:58:26 GMT", + "comments": {} + }, + { + "version": "3.16.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.16.0", + "date": "Mon, 16 Oct 2023 14:58:08 GMT", + "comments": {} + }, + { + "version": "3.15.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.15.0", + "date": "Mon, 28 Aug 2023 14:25:14 GMT", + "comments": {} + }, + { + "version": "3.14.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.14.0", + "date": "Thu, 10 Aug 2023 13:56:44 GMT", + "comments": {} + }, + { + "version": "3.13.1", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.13.1", + "date": "Thu, 29 Jun 2023 14:20:06 GMT", + "comments": {} + }, + { + "version": "3.13.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.13.0", + "date": "Tue, 20 Jun 2023 07:44:23 GMT", + "comments": {} + }, + { + "version": "3.12.1", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.12.1", + "date": "Thu, 15 Jun 2023 10:05:37 GMT", + "comments": {} + }, + { + "version": "3.12.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.12.0", + "date": "Mon, 05 Jun 2023 11:51:22 GMT", + "comments": {} + }, + { + "version": "3.11.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.11.0", + "date": "Wed, 24 May 2023 15:56:17 GMT", + "comments": {} + }, + { + "version": "3.10.1", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.10.1", + "date": "Fri, 12 May 2023 06:59:31 GMT", + "comments": {} + }, + { + "version": "3.10.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.10.0", + "date": "Thu, 11 May 2023 08:29:15 GMT", + "comments": {} + }, + { + "version": "3.9.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.9.0", + "date": "Thu, 30 Mar 2023 13:46:56 GMT", + "comments": { + "none": [ + { + "comment": "Update README" + } + ] + } + }, + { + "version": "3.8.0", + "tag": "@snowplow/browser-plugin-enhanced-consent_v3.8.0", + "date": "Tue, 03 Jan 2023 15:36:33 GMT", + "comments": {} + } + ] +} diff --git a/plugins/browser-plugin-enhanced-consent/CHANGELOG.md b/plugins/browser-plugin-enhanced-consent/CHANGELOG.md new file mode 100644 index 000000000..1afa17057 --- /dev/null +++ b/plugins/browser-plugin-enhanced-consent/CHANGELOG.md @@ -0,0 +1,295 @@ +# Change Log - @snowplow/browser-plugin-enhanced-consent + +This log was last generated on Mon, 27 Jul 2026 13:52:14 GMT and should not be manually modified. + +## 4.10.0 +Mon, 27 Jul 2026 13:52:14 GMT + +_Version update only_ + +## 4.9.0 +Tue, 21 Jul 2026 14:53:08 GMT + +_Version update only_ + +## 4.8.4 +Thu, 02 Jul 2026 10:07:52 GMT + +_Version update only_ + +## 4.8.3 +Tue, 30 Jun 2026 14:22:03 GMT + +### Updates + +- Update uuid to v11 and remove closure-compiler from the build pipeline + +## 4.8.2 +Wed, 17 Jun 2026 12:30:12 GMT + +_Version update only_ + +## 4.8.1 +Wed, 13 May 2026 09:26:05 GMT + +_Version update only_ + +## 4.8.0 +Tue, 28 Apr 2026 07:56:22 GMT + +_Version update only_ + +## 4.7.0 +Wed, 01 Apr 2026 12:59:29 GMT + +_Version update only_ + +## 4.6.9 +Mon, 16 Mar 2026 15:43:06 GMT + +_Version update only_ + +## 4.6.8 +Tue, 28 Oct 2025 09:46:42 GMT + +_Version update only_ + +## 4.6.7 +Tue, 07 Oct 2025 14:53:36 GMT + +_Version update only_ + +## 4.6.6 +Tue, 26 Aug 2025 08:42:27 GMT + +_Version update only_ + +## 4.6.5 +Wed, 25 Jun 2025 21:16:46 GMT + +_Version update only_ + +## 4.6.4 +Wed, 25 Jun 2025 12:08:50 GMT + +_Version update only_ + +## 4.6.3 +Thu, 29 May 2025 19:52:07 GMT + +_Version update only_ + +## 4.6.2 +Tue, 20 May 2025 07:39:05 GMT + +_Version update only_ + +## 4.6.1 +Tue, 06 May 2025 13:10:51 GMT + +_Version update only_ + +## 4.6.0 +Thu, 01 May 2025 09:58:59 GMT + +_Version update only_ + +## 4.5.0 +Fri, 04 Apr 2025 09:21:23 GMT + +_Version update only_ + +## 4.4.0 +Thu, 20 Mar 2025 12:14:34 GMT + +_Version update only_ + +## 4.3.1 +Tue, 21 Jan 2025 11:09:42 GMT + +_Version update only_ + +## 4.3.0 +Mon, 20 Jan 2025 11:45:13 GMT + +_Version update only_ + +## 4.2.0 +Mon, 13 Jan 2025 08:30:05 GMT + +_Version update only_ + +## 4.1.0 +Thu, 28 Nov 2024 10:57:30 GMT + +_Version update only_ + +## 4.0.4 +Thu, 21 Nov 2024 09:06:36 GMT + +_Version update only_ + +## 4.0.3 +Wed, 20 Nov 2024 09:30:31 GMT + +_Version update only_ + +## 4.0.2 +Mon, 11 Nov 2024 15:46:33 GMT + +_Version update only_ + +## 4.0.1 +Fri, 01 Nov 2024 10:35:07 GMT + +_Version update only_ + +## 4.0.0 +Mon, 28 Oct 2024 11:48:53 GMT + +_Version update only_ + +## 3.24.6 +Mon, 28 Oct 2024 10:23:28 GMT + +_Version update only_ + +## 3.24.5 +Fri, 25 Oct 2024 08:53:04 GMT + +_Version update only_ + +## 3.24.4 +Thu, 26 Sep 2024 06:10:22 GMT + +_Version update only_ + +## 3.24.3 +Tue, 03 Sep 2024 08:15:14 GMT + +### Updates + +- Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush + +## 3.24.2 +Wed, 24 Jul 2024 08:59:00 GMT + +_Version update only_ + +## 3.24.1 +Tue, 02 Jul 2024 07:08:17 GMT + +_Version update only_ + +## 3.24.0 +Tue, 25 Jun 2024 08:31:05 GMT + +_Version update only_ + +## 3.23.1 +Tue, 04 Jun 2024 13:34:45 GMT + +_Version update only_ + +## 3.23.0 +Thu, 28 Mar 2024 11:28:45 GMT + +_Version update only_ + +## 3.22.1 +Wed, 13 Mar 2024 08:39:48 GMT + +_Version update only_ + +## 3.22.0 +Fri, 08 Mar 2024 08:13:04 GMT + +_Version update only_ + +## 3.21.0 +Mon, 29 Jan 2024 08:34:06 GMT + +_Version update only_ + +## 3.20.0 +Mon, 15 Jan 2024 14:41:16 GMT + +_Version update only_ + +## 3.19.0 +Thu, 14 Dec 2023 10:45:22 GMT + +_Version update only_ + +## 3.18.0 +Mon, 04 Dec 2023 13:44:02 GMT + +_Version update only_ + +## 3.17.0 +Tue, 14 Nov 2023 17:58:26 GMT + +_Version update only_ + +## 3.16.0 +Mon, 16 Oct 2023 14:58:08 GMT + +_Version update only_ + +## 3.15.0 +Mon, 28 Aug 2023 14:25:14 GMT + +_Version update only_ + +## 3.14.0 +Thu, 10 Aug 2023 13:56:44 GMT + +_Version update only_ + +## 3.13.1 +Thu, 29 Jun 2023 14:20:06 GMT + +_Version update only_ + +## 3.13.0 +Tue, 20 Jun 2023 07:44:23 GMT + +_Version update only_ + +## 3.12.1 +Thu, 15 Jun 2023 10:05:37 GMT + +_Version update only_ + +## 3.12.0 +Mon, 05 Jun 2023 11:51:22 GMT + +_Version update only_ + +## 3.11.0 +Wed, 24 May 2023 15:56:17 GMT + +_Version update only_ + +## 3.10.1 +Fri, 12 May 2023 06:59:31 GMT + +_Version update only_ + +## 3.10.0 +Thu, 11 May 2023 08:29:15 GMT + +_Version update only_ + +## 3.9.0 +Thu, 30 Mar 2023 13:46:56 GMT + +### Updates + +- Update README + +## 3.8.0 +Tue, 03 Jan 2023 15:36:33 GMT + +_Initial release_ + diff --git a/plugins/browser-plugin-enhanced-consent/README.md b/plugins/browser-plugin-enhanced-consent/README.md new file mode 100644 index 000000000..5965453b2 --- /dev/null +++ b/plugins/browser-plugin-enhanced-consent/README.md @@ -0,0 +1,59 @@ +# Snowplow Enhanced Consent Plugin + +[![npm version][npm-image]][npm-url] +[![License][license-image]](LICENSE) + +Browser Plugin to be used with `@snowplow/browser-tracker`. + +This plugin is the recommended way to track marketing consent events on your website. Usage and a complete setup journey is showcased on the [Consent Tracking for Marketing accelerator](https://docs.snowplow.io/accelerators/consent/). + +## Maintainer quick start + +Part of the Snowplow JavaScript Tracker monorepo. +Build with [Node.js](https://nodejs.org/en/) (18 - 20) and [Rush](https://rushjs.io/). + +### Setup repository + +```bash +npm install -g @microsoft/rush +git clone https://github.com/snowplow/snowplow-javascript-tracker.git +rush update +``` + +## Package Installation + +With npm: + +```bash +npm install @snowplow/browser-plugin-enhanced-consent +``` + +## Usage + +Initialize your tracker with the EnhancedConsentPlugin: + +```js +import { newTracker } from '@snowplow/browser-tracker'; +import { EnhancedConsentPlugin } from '@snowplow/browser-plugin-enhanced-consent'; + +newTracker('sp1', '{{collector_url}}', { + appId: 'my-app-id', + plugins: [ EnhancedConsentPlugin() ], +}); +``` + +For a full API reference, you can read the plugin [documentation page](https://docs.snowplow.io/docs/collecting-data/collecting-from-own-applications/javascript-trackers/browser-tracker/browser-tracker-v3-reference/plugins/enhanced-consent/). + +## Copyright and license + +Licensed and distributed under the [BSD 3-Clause License](LICENSE) ([An OSI Approved License][osi]). + +Copyright (c) 2022 Snowplow Analytics Ltd. + +All rights reserved. + +[npm-url]: https://www.npmjs.com/package/@snowplow/browser-plugin-enhanced-consent +[npm-image]: https://img.shields.io/npm/v/@snowplow/browser-plugin-enhanced-consent +[docs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-tracker/ +[osi]: https://opensource.org/licenses/BSD-3-Clause +[license-image]: https://img.shields.io/npm/l/@snowplow/browser-plugin-enhanced-consent diff --git a/plugins/browser-plugin-enhanced-consent/jest.config.js b/plugins/browser-plugin-enhanced-consent/jest.config.js new file mode 100644 index 000000000..87d15da9b --- /dev/null +++ b/plugins/browser-plugin-enhanced-consent/jest.config.js @@ -0,0 +1,6 @@ +module.exports = { + preset: 'ts-jest', + reporters: ['jest-standard-reporter'], + setupFilesAfterEnv: ['../../setupTestGlobals.ts'], + testEnvironment: 'jest-environment-jsdom-global', +}; diff --git a/plugins/browser-plugin-enhanced-consent/package.json b/plugins/browser-plugin-enhanced-consent/package.json new file mode 100644 index 000000000..c3ebfc814 --- /dev/null +++ b/plugins/browser-plugin-enhanced-consent/package.json @@ -0,0 +1,53 @@ +{ + "name": "@snowplow/browser-plugin-enhanced-consent", + "version": "4.10.0", + "description": "Consent tracking for Snowplow", + "bugs": "https://github.com/snowplow/snowplow-javascript-tracker/issues", + "repository": { + "type": "git", + "url": "https://github.com/snowplow/snowplow-javascript-tracker.git" + }, + "license": "BSD-3-Clause", + "author": "Jack Keene", + "sideEffects": false, + "main": "./dist/index.umd.js", + "module": "./dist/index.module.js", + "types": "./dist/index.module.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "rollup -c --silent --failAfterWarnings", + "test": "jest" + }, + "dependencies": { + "@snowplow/browser-tracker-core": "workspace:*", + "@snowplow/tracker-core": "workspace:*", + "tslib": "^2.3.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "~21.0.2", + "@rollup/plugin-node-resolve": "~13.1.3", + "@types/jest": "~28.1.1", + "@types/jsdom": "~16.2.14", + "@types/lodash": "~4.14.180", + "@typescript-eslint/eslint-plugin": "~5.15.0", + "@typescript-eslint/parser": "~5.15.0", + "eslint": "~8.11.0", + "jest": "~28.1.3", + "jest-environment-jsdom": "~28.1.3", + "jest-environment-jsdom-global": "~4.0.0", + "jest-standard-reporter": "~2.0.0", + "lodash": "~4.17.21", + "rollup": "~2.70.1", + "rollup-plugin-cleanup": "~3.2.1", + "rollup-plugin-license": "~2.6.1", + "rollup-plugin-terser": "~7.0.2", + "rollup-plugin-ts": "~2.0.5", + "ts-jest": "~28.0.8", + "typescript": "~4.6.2" + }, + "peerDependencies": { + "@snowplow/browser-tracker": "~4.10.0" + } +} diff --git a/plugins/browser-plugin-enhanced-consent/rollup.config.js b/plugins/browser-plugin-enhanced-consent/rollup.config.js new file mode 100644 index 000000000..fc20df5fe --- /dev/null +++ b/plugins/browser-plugin-enhanced-consent/rollup.config.js @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import ts from 'rollup-plugin-ts'; // Prefered over @rollup/plugin-typescript as it bundles .d.ts files +import { banner } from '../../banner'; +import { terser } from 'rollup-plugin-terser'; +import cleanup from 'rollup-plugin-cleanup'; +import pkg from './package.json'; +import { builtinModules } from 'module'; + +const umdPlugins = [nodeResolve({ browser: true }), commonjs(), ts()]; +const umdName = 'snowplowEnhancedConsentTracking'; + +export default [ + // CommonJS (for Node) and ES module (for bundlers) build. + { + input: './src/index.ts', + plugins: [...umdPlugins, banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main, format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + plugins: [...umdPlugins, terser(), cleanup({ comments: 'none' }), banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main.replace('.js', '.min.js'), format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + external: [...builtinModules, ...Object.keys(pkg.dependencies), ...Object.keys(pkg.devDependencies)], + plugins: [ + ts(), // so Rollup can convert TypeScript to JavaScript + banner(), + ], + output: [{ file: pkg.module, format: 'es', sourcemap: true }], + }, +]; diff --git a/plugins/browser-plugin-enhanced-consent/src/api.ts b/plugins/browser-plugin-enhanced-consent/src/api.ts new file mode 100644 index 000000000..e1a2cf08c --- /dev/null +++ b/plugins/browser-plugin-enhanced-consent/src/api.ts @@ -0,0 +1,138 @@ +import { BrowserPlugin, BrowserTracker, dispatchToTrackersInCollection } from '@snowplow/browser-tracker-core'; +import { buildConsentEvent, buildCmpVisibleEvent } from './core'; +import { CommonConsentEventProperties, Consent, CmpVisible } from './types'; + +const _trackers: Record = {}; + +type ConsentEventProperties = Omit & CommonConsentEventProperties; + +/** + * Adds consent tracking + */ + +export function EnhancedConsentPlugin(): BrowserPlugin { + let trackerId: string; + return { + activateBrowserPlugin: (tracker) => { + trackerId = tracker.id; + _trackers[trackerId] = tracker; + }, + }; +} + +/** + * Track the loadtime of a CMP banner + */ + +export function trackCmpVisible( + cmpVisible: CmpVisible & CommonConsentEventProperties, + trackers: Array = Object.keys(_trackers) +) { + const { context, timestamp, elapsedTime } = cmpVisible; + dispatchToTrackersInCollection(trackers, _trackers, (t) => { + t.core.track( + buildCmpVisibleEvent({ + elapsedTime, + }), + context, + timestamp + ); + }); +} + +// Generic consent action +function trackConsentAction( + consent: Consent & CommonConsentEventProperties, + trackers: Array = Object.keys(_trackers) +) { + const { context, timestamp, ...consentAttributes } = consent; + dispatchToTrackersInCollection(trackers, _trackers, (t) => { + t.core.track(buildConsentEvent(consentAttributes), context, timestamp); + }); +} + +/** + * Track an allow consent event + * + * @param consent - The consent information + * @param trackers - The tracker identifiers which the event will be sent to + */ + +export function trackConsentAllow(consent: ConsentEventProperties, trackers: Array = Object.keys(_trackers)) { + trackConsentAction({ ...consent, eventType: 'allow_all' }, trackers); +} + +/** + * Track an allow selected consent event + * + * @param consent - The consent information + * @param trackers - The tracker identifiers which the event will be sent to + */ + +export function trackConsentSelected( + consent: ConsentEventProperties, + trackers: Array = Object.keys(_trackers) +) { + trackConsentAction({ ...consent, eventType: 'allow_selected' }, trackers); +} + +/** + * Track a consent pending event + * + * @param consent - The consent information + * @param trackers - The tracker identifiers which the event will be sent to + */ + +export function trackConsentPending(consent: ConsentEventProperties, trackers: Array = Object.keys(_trackers)) { + trackConsentAction({ ...consent, eventType: 'pending' }, trackers); +} + +/** + * Track an implicit consent event + * + * @param consent - The consent information + * @param trackers - The tracker identifiers which the event will be sent to + */ + +export function trackConsentImplicit( + consent: ConsentEventProperties, + trackers: Array = Object.keys(_trackers) +) { + trackConsentAction({ ...consent, eventType: 'implicit_consent' }, trackers); +} + +/** + * Track a deny consent event + * + * @param consent - The consent information + * @param trackers - The tracker identifiers which the event will be sent to + */ + +export function trackConsentDeny(consent: ConsentEventProperties, trackers: Array = Object.keys(_trackers)) { + trackConsentAction({ ...consent, eventType: 'deny_all' }, trackers); +} + +/** + * Track a consent expired event + * + * @param consent - The consent information + * @param trackers - The tracker identifiers which the event will be sent to + */ + +export function trackConsentExpired(consent: ConsentEventProperties, trackers: Array = Object.keys(_trackers)) { + trackConsentAction({ ...consent, eventType: 'expired' }, trackers); +} + +/** + * Track a consent withdrawn event + * + * @param consent - The consent information + * @param trackers - The tracker identifiers which the event will be sent to + */ + +export function trackConsentWithdrawn( + consent: ConsentEventProperties, + trackers: Array = Object.keys(_trackers) +) { + trackConsentAction({ ...consent, eventType: 'withdrawn' }, trackers); +} diff --git a/plugins/browser-plugin-enhanced-consent/src/core.ts b/plugins/browser-plugin-enhanced-consent/src/core.ts new file mode 100644 index 000000000..f4ae936ad --- /dev/null +++ b/plugins/browser-plugin-enhanced-consent/src/core.ts @@ -0,0 +1,52 @@ +import { buildSelfDescribingEvent } from '@snowplow/tracker-core'; +import { CONSENT_SCHEMA, CMP_VISIBLE_SCHEMA } from './schemata'; +import { CmpVisible, Consent } from './types'; +/** + * Build a Consent Action Event + * for tracking consent actions + * + * @param event - Contains properties of Consent action events + * @returns PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track} + */ + +export function buildConsentEvent(event: Consent) { + return buildSelfDescribingEvent({ + event: { + schema: CONSENT_SCHEMA, + data: removeEmptyProperties({ ...event }), + }, + }); +} + +/** + * Build a CMP Visible Event + * for tracking loadtime of CMP banner + * + * @param event - Contains properties of CMP Visible events + * @returns PayloadBuilder to be sent to {@link @snowplow/tracker-core#TrackerCore.track} + */ + +export function buildCmpVisibleEvent(event: CmpVisible) { + return buildSelfDescribingEvent({ + event: { + schema: CMP_VISIBLE_SCHEMA, + data: removeEmptyProperties({ ...event }), + }, + }); +} + +/** + * Returns a copy of a JSON with undefined and null properties removed + * + * @param event - Object to clean + * @returns A cleaned copy of eventJson + */ +function removeEmptyProperties(event: Record): Record { + const ret: Record = {}; + for (const k in event) { + if (event[k] !== null && typeof event[k] !== 'undefined') { + ret[k] = event[k]; + } + } + return ret; +} diff --git a/plugins/browser-plugin-enhanced-consent/src/index.ts b/plugins/browser-plugin-enhanced-consent/src/index.ts new file mode 100644 index 000000000..b1c13e734 --- /dev/null +++ b/plugins/browser-plugin-enhanced-consent/src/index.ts @@ -0,0 +1 @@ +export * from './api'; diff --git a/plugins/browser-plugin-enhanced-consent/src/schemata.ts b/plugins/browser-plugin-enhanced-consent/src/schemata.ts new file mode 100644 index 000000000..bc201d173 --- /dev/null +++ b/plugins/browser-plugin-enhanced-consent/src/schemata.ts @@ -0,0 +1,2 @@ +export const CONSENT_SCHEMA = 'iglu:com.snowplowanalytics.snowplow/consent_preferences/jsonschema/1-0-0'; +export const CMP_VISIBLE_SCHEMA = 'iglu:com.snowplowanalytics.snowplow/cmp_visible/jsonschema/1-0-0'; diff --git a/plugins/browser-plugin-enhanced-consent/src/types.ts b/plugins/browser-plugin-enhanced-consent/src/types.ts new file mode 100644 index 000000000..3645a9dbb --- /dev/null +++ b/plugins/browser-plugin-enhanced-consent/src/types.ts @@ -0,0 +1,53 @@ +import { CommonEventProperties, SelfDescribingJson } from '@snowplow/tracker-core'; + +/** + * Type for Consent Action + */ +export interface Consent { + /** + * The action for the consent preferences of a user + */ + eventType: 'deny_all' | 'allow_all' | 'allow_selected' | 'pending' | 'implicit_consent' | 'withdrawn' | 'expired'; + /** + * GDPR lawful basis for data collection & processing + */ + basisForProcessing: + | 'consent' + | 'contract' + | 'legal_obligation' + | 'vital_interests' + | 'public_task' + | 'legitimate_interests'; + /** + * URI of the privacy policy related document + */ + consentUrl: string; + /** + * Version of the privacy policy related document + */ + consentVersion: string; + /** + * The scopes allowed after the user finalized his selection of consent preferences. E.g ['analytics', 'functional', 'advertisement']. + */ + consentScopes: string[]; + /** + * The domains for which this consent allows these preferences to persist to. + */ + domainsApplied: string[]; + /** + * Determine if GDPR applies based on the user's geo-location. + */ + gdprApplies?: boolean; +} + +export interface CmpVisible { + /** + * The time between the page load and dialog box appearing + */ + elapsedTime: number; +} + +export interface CommonConsentEventProperties extends CommonEventProperties { + /** Add context to an event by setting an Array of Self Describing JSON */ + context?: Array; +} diff --git a/plugins/browser-plugin-enhanced-consent/test/events.test.ts b/plugins/browser-plugin-enhanced-consent/test/events.test.ts new file mode 100644 index 000000000..d7431ab5f --- /dev/null +++ b/plugins/browser-plugin-enhanced-consent/test/events.test.ts @@ -0,0 +1,207 @@ +import { addTracker, SharedState, EventStore } from '@snowplow/browser-tracker-core'; +import { + EnhancedConsentPlugin, + trackCmpVisible, + trackConsentAllow, + trackConsentSelected, + trackConsentDeny, + trackConsentExpired, + trackConsentImplicit, + trackConsentPending, + trackConsentWithdrawn, +} from '../src'; +import { CMP_VISIBLE_SCHEMA } from '../src/schemata'; +import { newInMemoryEventStore } from '@snowplow/tracker-core'; + +const extractEventProperties = ([{ ue_pr }]: any) => ({ unstructuredEvent: JSON.parse(ue_pr).data }); + +describe('EnhancedConsentPlugin events', () => { + let idx = 1; + let eventStore: EventStore; + + beforeEach(() => { + eventStore = newInMemoryEventStore({}); + addTracker(`sp${idx++}`, `sp${idx++}`, 'js-3.0.0', '', new SharedState(), { + stateStorageStrategy: 'cookie', + encodeBase64: false, + plugins: [EnhancedConsentPlugin()], + contexts: { webPage: false }, + eventStore, + customFetch: async () => new Response(null, { status: 500 }), + }); + }); + + it('trackCmpVisible adds the "CMP Visible" event to the queue', async () => { + trackCmpVisible({ + elapsedTime: 1500, + }); + + const { unstructuredEvent } = extractEventProperties(await eventStore.getAllPayloads()); + + expect(unstructuredEvent).toMatchObject({ + schema: CMP_VISIBLE_SCHEMA, + data: { elapsedTime: 1500 }, + }); + }); + + it('trackConsentAllow adds the "allow consent" event to the queue', async () => { + trackConsentAllow({ + basisForProcessing: 'consent', + consentUrl: 'http://consent.url', + consentVersion: '1.0.0', + consentScopes: ['necessary', 'analytics', 'functional', 'advertisement'], + domainsApplied: ['www.example.com'], + }); + + const { unstructuredEvent } = extractEventProperties(await eventStore.getAllPayloads()); + + expect(unstructuredEvent).toMatchObject({ + data: { + eventType: 'allow_all', + basisForProcessing: 'consent', + consentUrl: 'http://consent.url', + consentVersion: '1.0.0', + consentScopes: ['necessary', 'analytics', 'functional', 'advertisement'], + domainsApplied: ['www.example.com'], + }, + }); + }); + + it('trackConsentSelected adds the "allow selected consent" event to the queue', async () => { + trackConsentSelected({ + basisForProcessing: 'consent', + consentUrl: 'http://consent.url', + consentVersion: '1.0.0', + consentScopes: ['necessary', 'analytics', 'advertisement'], + domainsApplied: ['www.example.com', 'blog.example.com'], + }); + + const { unstructuredEvent } = extractEventProperties(await eventStore.getAllPayloads()); + + expect(unstructuredEvent).toMatchObject({ + data: { + eventType: 'allow_selected', + basisForProcessing: 'consent', + consentUrl: 'http://consent.url', + consentVersion: '1.0.0', + consentScopes: ['necessary', 'analytics', 'advertisement'], + domainsApplied: ['www.example.com', 'blog.example.com'], + }, + }); + }); + + it('trackConsentPending adds the "pending consent" event to the queue', async () => { + trackConsentPending({ + basisForProcessing: 'consent', + consentUrl: 'http://consent.url', + consentVersion: '1.0.0', + consentScopes: ['necessary'], + domainsApplied: ['www.example.com'], + }); + + const { unstructuredEvent } = extractEventProperties(await eventStore.getAllPayloads()); + + expect(unstructuredEvent).toMatchObject({ + data: { + eventType: 'pending', + basisForProcessing: 'consent', + consentUrl: 'http://consent.url', + consentVersion: '1.0.0', + consentScopes: ['necessary'], + domainsApplied: ['www.example.com'], + }, + }); + }); + + it('trackConsentImplicit adds the "implicit consent" event to the queue', async () => { + trackConsentImplicit({ + basisForProcessing: 'consent', + consentUrl: 'http://consent.url', + consentVersion: '1.0.0', + consentScopes: ['necessary'], + domainsApplied: ['www.example.com'], + }); + + const { unstructuredEvent } = extractEventProperties(await eventStore.getAllPayloads()); + + expect(unstructuredEvent).toMatchObject({ + data: { + eventType: 'implicit_consent', + basisForProcessing: 'consent', + consentUrl: 'http://consent.url', + consentVersion: '1.0.0', + consentScopes: ['necessary'], + domainsApplied: ['www.example.com'], + }, + }); + }); + + it('trackConsentExpired adds the "expired consent" event to the queue', async () => { + trackConsentExpired({ + basisForProcessing: 'consent', + consentUrl: 'http://consent.url', + consentVersion: '1.0.0', + consentScopes: ['necessary'], + domainsApplied: ['www.example.com'], + }); + + const { unstructuredEvent } = extractEventProperties(await eventStore.getAllPayloads()); + + expect(unstructuredEvent).toMatchObject({ + data: { + eventType: 'expired', + basisForProcessing: 'consent', + consentUrl: 'http://consent.url', + consentVersion: '1.0.0', + consentScopes: ['necessary'], + domainsApplied: ['www.example.com'], + }, + }); + }); + + it('trackConsentDeny adds the "consent denied" event to the queue', async () => { + trackConsentDeny({ + basisForProcessing: 'consent', + consentUrl: 'http://consent.url', + consentVersion: '1.0.0', + consentScopes: ['necessary'], + domainsApplied: ['www.example.com'], + }); + + const { unstructuredEvent } = extractEventProperties(await eventStore.getAllPayloads()); + + expect(unstructuredEvent).toMatchObject({ + data: { + eventType: 'deny_all', + basisForProcessing: 'consent', + consentUrl: 'http://consent.url', + consentVersion: '1.0.0', + consentScopes: ['necessary'], + domainsApplied: ['www.example.com'], + }, + }); + }); + + it('trackConsentWithdrawn adds the "consent withdrawn" event to the queue', async () => { + trackConsentWithdrawn({ + basisForProcessing: 'consent', + consentUrl: 'http://consent.url', + consentVersion: '1.0.0', + consentScopes: ['necessary'], + domainsApplied: ['www.example.com'], + }); + + const { unstructuredEvent } = extractEventProperties(await eventStore.getAllPayloads()); + + expect(unstructuredEvent).toMatchObject({ + data: { + eventType: 'withdrawn', + basisForProcessing: 'consent', + consentUrl: 'http://consent.url', + consentVersion: '1.0.0', + consentScopes: ['necessary'], + domainsApplied: ['www.example.com'], + }, + }); + }); +}); diff --git a/plugins/browser-plugin-enhanced-consent/tsconfig.json b/plugins/browser-plugin-enhanced-consent/tsconfig.json new file mode 100644 index 000000000..4082f16a5 --- /dev/null +++ b/plugins/browser-plugin-enhanced-consent/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +} diff --git a/plugins/browser-plugin-enhanced-ecommerce/CHANGELOG.json b/plugins/browser-plugin-enhanced-ecommerce/CHANGELOG.json new file mode 100644 index 000000000..84c61b885 --- /dev/null +++ b/plugins/browser-plugin-enhanced-ecommerce/CHANGELOG.json @@ -0,0 +1,605 @@ +{ + "name": "@snowplow/browser-plugin-enhanced-ecommerce", + "entries": [ + { + "version": "4.10.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.10.0", + "date": "Mon, 27 Jul 2026 13:52:14 GMT", + "comments": {} + }, + { + "version": "4.9.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.9.0", + "date": "Tue, 21 Jul 2026 14:53:08 GMT", + "comments": {} + }, + { + "version": "4.8.4", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.8.4", + "date": "Thu, 02 Jul 2026 10:07:52 GMT", + "comments": {} + }, + { + "version": "4.8.3", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.8.3", + "date": "Tue, 30 Jun 2026 14:22:03 GMT", + "comments": { + "none": [ + { + "comment": "Update uuid to v11 and remove closure-compiler from the build pipeline" + } + ] + } + }, + { + "version": "4.8.2", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.8.2", + "date": "Wed, 17 Jun 2026 12:30:12 GMT", + "comments": {} + }, + { + "version": "4.8.1", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.8.1", + "date": "Wed, 13 May 2026 09:26:05 GMT", + "comments": {} + }, + { + "version": "4.8.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.8.0", + "date": "Tue, 28 Apr 2026 07:56:22 GMT", + "comments": {} + }, + { + "version": "4.7.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.7.0", + "date": "Wed, 01 Apr 2026 12:59:29 GMT", + "comments": {} + }, + { + "version": "4.6.9", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.6.9", + "date": "Mon, 16 Mar 2026 15:43:06 GMT", + "comments": {} + }, + { + "version": "4.6.8", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.6.8", + "date": "Tue, 28 Oct 2025 09:46:42 GMT", + "comments": {} + }, + { + "version": "4.6.7", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.6.7", + "date": "Tue, 07 Oct 2025 14:53:36 GMT", + "comments": {} + }, + { + "version": "4.6.6", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.6.6", + "date": "Tue, 26 Aug 2025 08:42:27 GMT", + "comments": {} + }, + { + "version": "4.6.5", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.6.5", + "date": "Wed, 25 Jun 2025 21:16:46 GMT", + "comments": {} + }, + { + "version": "4.6.4", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.6.4", + "date": "Wed, 25 Jun 2025 12:08:50 GMT", + "comments": {} + }, + { + "version": "4.6.3", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.6.3", + "date": "Thu, 29 May 2025 19:52:07 GMT", + "comments": {} + }, + { + "version": "4.6.2", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.6.2", + "date": "Tue, 20 May 2025 07:39:05 GMT", + "comments": {} + }, + { + "version": "4.6.1", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.6.1", + "date": "Tue, 06 May 2025 13:10:51 GMT", + "comments": {} + }, + { + "version": "4.6.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.6.0", + "date": "Thu, 01 May 2025 09:58:59 GMT", + "comments": {} + }, + { + "version": "4.5.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.5.0", + "date": "Fri, 04 Apr 2025 09:21:23 GMT", + "comments": {} + }, + { + "version": "4.4.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.4.0", + "date": "Thu, 20 Mar 2025 12:14:34 GMT", + "comments": {} + }, + { + "version": "4.3.1", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.3.1", + "date": "Tue, 21 Jan 2025 11:09:42 GMT", + "comments": {} + }, + { + "version": "4.3.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.3.0", + "date": "Mon, 20 Jan 2025 11:45:13 GMT", + "comments": {} + }, + { + "version": "4.2.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.2.0", + "date": "Mon, 13 Jan 2025 08:30:05 GMT", + "comments": {} + }, + { + "version": "4.1.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.1.0", + "date": "Thu, 28 Nov 2024 10:57:30 GMT", + "comments": {} + }, + { + "version": "4.0.4", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.0.4", + "date": "Thu, 21 Nov 2024 09:06:36 GMT", + "comments": {} + }, + { + "version": "4.0.3", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.0.3", + "date": "Wed, 20 Nov 2024 09:30:31 GMT", + "comments": {} + }, + { + "version": "4.0.2", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.0.2", + "date": "Mon, 11 Nov 2024 15:46:33 GMT", + "comments": {} + }, + { + "version": "4.0.1", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.0.1", + "date": "Fri, 01 Nov 2024 10:35:07 GMT", + "comments": {} + }, + { + "version": "4.0.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v4.0.0", + "date": "Mon, 28 Oct 2024 11:48:53 GMT", + "comments": { + "none": [ + { + "comment": "Add deprecation warning" + } + ] + } + }, + { + "version": "3.24.6", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.24.6", + "date": "Mon, 28 Oct 2024 10:23:28 GMT", + "comments": {} + }, + { + "version": "3.24.5", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.24.5", + "date": "Fri, 25 Oct 2024 08:53:04 GMT", + "comments": {} + }, + { + "version": "3.24.4", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.24.4", + "date": "Thu, 26 Sep 2024 06:10:22 GMT", + "comments": {} + }, + { + "version": "3.24.3", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.24.3", + "date": "Tue, 03 Sep 2024 08:15:14 GMT", + "comments": { + "none": [ + { + "comment": "Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush" + } + ] + } + }, + { + "version": "3.24.2", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.24.2", + "date": "Wed, 24 Jul 2024 08:59:00 GMT", + "comments": {} + }, + { + "version": "3.24.1", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.24.1", + "date": "Tue, 02 Jul 2024 07:08:17 GMT", + "comments": {} + }, + { + "version": "3.24.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.24.0", + "date": "Tue, 25 Jun 2024 08:31:05 GMT", + "comments": {} + }, + { + "version": "3.23.1", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.23.1", + "date": "Tue, 04 Jun 2024 13:34:45 GMT", + "comments": {} + }, + { + "version": "3.23.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.23.0", + "date": "Thu, 28 Mar 2024 11:28:45 GMT", + "comments": {} + }, + { + "version": "3.22.1", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.22.1", + "date": "Wed, 13 Mar 2024 08:39:48 GMT", + "comments": {} + }, + { + "version": "3.22.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.22.0", + "date": "Fri, 08 Mar 2024 08:13:04 GMT", + "comments": {} + }, + { + "version": "3.21.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.21.0", + "date": "Mon, 29 Jan 2024 08:34:06 GMT", + "comments": {} + }, + { + "version": "3.20.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.20.0", + "date": "Mon, 15 Jan 2024 14:41:16 GMT", + "comments": {} + }, + { + "version": "3.19.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.19.0", + "date": "Thu, 14 Dec 2023 10:45:22 GMT", + "comments": {} + }, + { + "version": "3.18.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.18.0", + "date": "Mon, 04 Dec 2023 13:44:02 GMT", + "comments": {} + }, + { + "version": "3.17.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.17.0", + "date": "Tue, 14 Nov 2023 17:58:26 GMT", + "comments": {} + }, + { + "version": "3.16.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.16.0", + "date": "Mon, 16 Oct 2023 14:58:08 GMT", + "comments": {} + }, + { + "version": "3.15.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.15.0", + "date": "Mon, 28 Aug 2023 14:25:14 GMT", + "comments": {} + }, + { + "version": "3.14.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.14.0", + "date": "Thu, 10 Aug 2023 13:56:44 GMT", + "comments": {} + }, + { + "version": "3.13.1", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.13.1", + "date": "Thu, 29 Jun 2023 14:20:06 GMT", + "comments": {} + }, + { + "version": "3.13.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.13.0", + "date": "Tue, 20 Jun 2023 07:44:23 GMT", + "comments": {} + }, + { + "version": "3.12.1", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.12.1", + "date": "Thu, 15 Jun 2023 10:05:37 GMT", + "comments": {} + }, + { + "version": "3.12.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.12.0", + "date": "Mon, 05 Jun 2023 11:51:22 GMT", + "comments": {} + }, + { + "version": "3.11.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.11.0", + "date": "Wed, 24 May 2023 15:56:17 GMT", + "comments": {} + }, + { + "version": "3.10.1", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.10.1", + "date": "Fri, 12 May 2023 06:59:31 GMT", + "comments": {} + }, + { + "version": "3.10.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.10.0", + "date": "Thu, 11 May 2023 08:29:15 GMT", + "comments": {} + }, + { + "version": "3.9.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.9.0", + "date": "Thu, 30 Mar 2023 13:46:56 GMT", + "comments": {} + }, + { + "version": "3.8.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.8.0", + "date": "Tue, 03 Jan 2023 15:36:33 GMT", + "comments": {} + }, + { + "version": "3.7.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.7.0", + "date": "Mon, 31 Oct 2022 06:26:28 GMT", + "comments": {} + }, + { + "version": "3.6.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.6.0", + "date": "Thu, 15 Sep 2022 07:55:20 GMT", + "comments": {} + }, + { + "version": "3.5.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.5.0", + "date": "Fri, 10 Jun 2022 18:57:46 GMT", + "comments": {} + }, + { + "version": "3.4.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.4.0", + "date": "Thu, 07 Apr 2022 11:56:26 GMT", + "comments": { + "none": [ + { + "comment": "Bump dependencies (#1067)" + } + ] + } + }, + { + "version": "3.3.1", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.3.1", + "date": "Wed, 23 Feb 2022 19:27:40 GMT", + "comments": {} + }, + { + "version": "3.3.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.3.0", + "date": "Mon, 31 Jan 2022 15:58:10 GMT", + "comments": {} + }, + { + "version": "3.2.3", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.2.3", + "date": "Tue, 18 Jan 2022 16:23:52 GMT", + "comments": { + "none": [ + { + "comment": "Bump Copyright to 2022 (#1040)" + } + ] + } + }, + { + "version": "3.2.2", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.2.2", + "date": "Fri, 14 Jan 2022 10:17:59 GMT", + "comments": {} + }, + { + "version": "3.2.1", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.2.1", + "date": "Wed, 12 Jan 2022 09:50:29 GMT", + "comments": {} + }, + { + "version": "3.2.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.2.0", + "date": "Tue, 11 Jan 2022 12:53:22 GMT", + "comments": {} + }, + { + "version": "3.1.6", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.1.6", + "date": "Tue, 19 Oct 2021 09:17:22 GMT", + "comments": { + "none": [ + { + "comment": "Fix failing build on ARM Macs (#1012)" + } + ] + } + }, + { + "version": "3.1.5", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.1.5", + "date": "Fri, 01 Oct 2021 08:09:21 GMT", + "comments": {} + }, + { + "version": "3.1.4", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.1.4", + "date": "Tue, 21 Sep 2021 14:59:36 GMT", + "comments": {} + }, + { + "version": "3.1.3", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.1.3", + "date": "Mon, 23 Aug 2021 10:13:18 GMT", + "comments": {} + }, + { + "version": "3.1.2", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.1.2", + "date": "Mon, 16 Aug 2021 12:59:59 GMT", + "comments": { + "none": [ + { + "comment": "Update READMEs with correct Node requirements (#994)" + } + ] + } + }, + { + "version": "3.1.1", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.1.1", + "date": "Wed, 04 Aug 2021 10:12:25 GMT", + "comments": { + "none": [ + { + "comment": "Bump tslib to 2.3.0 (#986)" + }, + { + "comment": "Bump typescript to 4.3.5 (#987)" + }, + { + "comment": "Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988)" + } + ] + } + }, + { + "version": "3.1.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.1.0", + "date": "Fri, 14 May 2021 10:45:32 GMT", + "comments": {} + }, + { + "version": "3.0.3", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.0.3", + "date": "Wed, 21 Apr 2021 12:35:06 GMT", + "comments": {} + }, + { + "version": "3.0.2", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.0.2", + "date": "Thu, 15 Apr 2021 21:07:39 GMT", + "comments": {} + }, + { + "version": "3.0.1", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.0.1", + "date": "Wed, 14 Apr 2021 16:30:05 GMT", + "comments": { + "none": [ + { + "comment": "Add peerDependencies to plugins (#950)" + }, + { + "comment": "Mark packages as sideEffect: false (#951)" + }, + { + "comment": "Add unit tests to plugin track* functions (#954)" + } + ] + } + }, + { + "version": "3.0.0", + "tag": "@snowplow/browser-plugin-enhanced-ecommerce_v3.0.0", + "date": "Wed, 31 Mar 2021 14:46:47 GMT", + "comments": { + "none": [ + { + "comment": "Bump rollup to 2.41 (#916)" + }, + { + "comment": "Publish UMD versions of plugins to GitHub release (#923)" + }, + { + "comment": "Ensure browser-tracker API methods catch exceptions (#919)" + }, + { + "comment": "Introduce TSDoc comments and extract interfaces where appropriate (#906)" + }, + { + "comment": "Bump major version to v3 and update READMEs (#904)" + }, + { + "comment": "Improve Core API for module bundlers which support treeshaking (#903)" + }, + { + "comment": "Rename @snowplow/browser-core to @snowplow/browser-tracker-core (#901)" + }, + { + "comment": "Publish lite version of sp.js (#900)" + }, + { + "comment": "Ensure correct 3-Clause BSD License notices are being used (#316)" + }, + { + "comment": "Improve API for module bundlers which support treeshaking (#899)" + }, + { + "comment": "Bump rush to 5.39 (#895)" + }, + { + "comment": "Port to TypeScript (#72)" + }, + { + "comment": "Make sp.js build process modular (#450)" + }, + { + "comment": "Create @snowplow/browser-tracker package for npm distribution (#541)" + }, + { + "comment": "Split auto contexts into plugins (#880)" + }, + { + "comment": "Add rush to manage monorepo (#883)" + }, + { + "comment": "Add ES Module builds (#882)" + }, + { + "comment": "Cleanup deprecated methods (#557)" + }, + { + "comment": "Update publishing process for rush (#907)" + }, + { + "comment": "Change white and black lists to allow and deny lists (#908)" + }, + { + "comment": "Create rush change files for major version 3 release (#909)" + } + ] + } + } + ] +} diff --git a/plugins/browser-plugin-enhanced-ecommerce/CHANGELOG.md b/plugins/browser-plugin-enhanced-ecommerce/CHANGELOG.md new file mode 100644 index 000000000..df0fafd2d --- /dev/null +++ b/plugins/browser-plugin-enhanced-ecommerce/CHANGELOG.md @@ -0,0 +1,438 @@ +# Change Log - @snowplow/browser-plugin-enhanced-ecommerce + +This log was last generated on Mon, 27 Jul 2026 13:52:14 GMT and should not be manually modified. + +## 4.10.0 +Mon, 27 Jul 2026 13:52:14 GMT + +_Version update only_ + +## 4.9.0 +Tue, 21 Jul 2026 14:53:08 GMT + +_Version update only_ + +## 4.8.4 +Thu, 02 Jul 2026 10:07:52 GMT + +_Version update only_ + +## 4.8.3 +Tue, 30 Jun 2026 14:22:03 GMT + +### Updates + +- Update uuid to v11 and remove closure-compiler from the build pipeline + +## 4.8.2 +Wed, 17 Jun 2026 12:30:12 GMT + +_Version update only_ + +## 4.8.1 +Wed, 13 May 2026 09:26:05 GMT + +_Version update only_ + +## 4.8.0 +Tue, 28 Apr 2026 07:56:22 GMT + +_Version update only_ + +## 4.7.0 +Wed, 01 Apr 2026 12:59:29 GMT + +_Version update only_ + +## 4.6.9 +Mon, 16 Mar 2026 15:43:06 GMT + +_Version update only_ + +## 4.6.8 +Tue, 28 Oct 2025 09:46:42 GMT + +_Version update only_ + +## 4.6.7 +Tue, 07 Oct 2025 14:53:36 GMT + +_Version update only_ + +## 4.6.6 +Tue, 26 Aug 2025 08:42:27 GMT + +_Version update only_ + +## 4.6.5 +Wed, 25 Jun 2025 21:16:46 GMT + +_Version update only_ + +## 4.6.4 +Wed, 25 Jun 2025 12:08:50 GMT + +_Version update only_ + +## 4.6.3 +Thu, 29 May 2025 19:52:07 GMT + +_Version update only_ + +## 4.6.2 +Tue, 20 May 2025 07:39:05 GMT + +_Version update only_ + +## 4.6.1 +Tue, 06 May 2025 13:10:51 GMT + +_Version update only_ + +## 4.6.0 +Thu, 01 May 2025 09:58:59 GMT + +_Version update only_ + +## 4.5.0 +Fri, 04 Apr 2025 09:21:23 GMT + +_Version update only_ + +## 4.4.0 +Thu, 20 Mar 2025 12:14:34 GMT + +_Version update only_ + +## 4.3.1 +Tue, 21 Jan 2025 11:09:42 GMT + +_Version update only_ + +## 4.3.0 +Mon, 20 Jan 2025 11:45:13 GMT + +_Version update only_ + +## 4.2.0 +Mon, 13 Jan 2025 08:30:05 GMT + +_Version update only_ + +## 4.1.0 +Thu, 28 Nov 2024 10:57:30 GMT + +_Version update only_ + +## 4.0.4 +Thu, 21 Nov 2024 09:06:36 GMT + +_Version update only_ + +## 4.0.3 +Wed, 20 Nov 2024 09:30:31 GMT + +_Version update only_ + +## 4.0.2 +Mon, 11 Nov 2024 15:46:33 GMT + +_Version update only_ + +## 4.0.1 +Fri, 01 Nov 2024 10:35:07 GMT + +_Version update only_ + +## 4.0.0 +Mon, 28 Oct 2024 11:48:53 GMT + +### Updates + +- Add deprecation warning + +## 3.24.6 +Mon, 28 Oct 2024 10:23:28 GMT + +_Version update only_ + +## 3.24.5 +Fri, 25 Oct 2024 08:53:04 GMT + +_Version update only_ + +## 3.24.4 +Thu, 26 Sep 2024 06:10:22 GMT + +_Version update only_ + +## 3.24.3 +Tue, 03 Sep 2024 08:15:14 GMT + +### Updates + +- Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush + +## 3.24.2 +Wed, 24 Jul 2024 08:59:00 GMT + +_Version update only_ + +## 3.24.1 +Tue, 02 Jul 2024 07:08:17 GMT + +_Version update only_ + +## 3.24.0 +Tue, 25 Jun 2024 08:31:05 GMT + +_Version update only_ + +## 3.23.1 +Tue, 04 Jun 2024 13:34:45 GMT + +_Version update only_ + +## 3.23.0 +Thu, 28 Mar 2024 11:28:45 GMT + +_Version update only_ + +## 3.22.1 +Wed, 13 Mar 2024 08:39:48 GMT + +_Version update only_ + +## 3.22.0 +Fri, 08 Mar 2024 08:13:04 GMT + +_Version update only_ + +## 3.21.0 +Mon, 29 Jan 2024 08:34:06 GMT + +_Version update only_ + +## 3.20.0 +Mon, 15 Jan 2024 14:41:16 GMT + +_Version update only_ + +## 3.19.0 +Thu, 14 Dec 2023 10:45:22 GMT + +_Version update only_ + +## 3.18.0 +Mon, 04 Dec 2023 13:44:02 GMT + +_Version update only_ + +## 3.17.0 +Tue, 14 Nov 2023 17:58:26 GMT + +_Version update only_ + +## 3.16.0 +Mon, 16 Oct 2023 14:58:08 GMT + +_Version update only_ + +## 3.15.0 +Mon, 28 Aug 2023 14:25:14 GMT + +_Version update only_ + +## 3.14.0 +Thu, 10 Aug 2023 13:56:44 GMT + +_Version update only_ + +## 3.13.1 +Thu, 29 Jun 2023 14:20:06 GMT + +_Version update only_ + +## 3.13.0 +Tue, 20 Jun 2023 07:44:23 GMT + +_Version update only_ + +## 3.12.1 +Thu, 15 Jun 2023 10:05:37 GMT + +_Version update only_ + +## 3.12.0 +Mon, 05 Jun 2023 11:51:22 GMT + +_Version update only_ + +## 3.11.0 +Wed, 24 May 2023 15:56:17 GMT + +_Version update only_ + +## 3.10.1 +Fri, 12 May 2023 06:59:31 GMT + +_Version update only_ + +## 3.10.0 +Thu, 11 May 2023 08:29:15 GMT + +_Version update only_ + +## 3.9.0 +Thu, 30 Mar 2023 13:46:56 GMT + +_Version update only_ + +## 3.8.0 +Tue, 03 Jan 2023 15:36:33 GMT + +_Version update only_ + +## 3.7.0 +Mon, 31 Oct 2022 06:26:28 GMT + +_Version update only_ + +## 3.6.0 +Thu, 15 Sep 2022 07:55:20 GMT + +_Version update only_ + +## 3.5.0 +Fri, 10 Jun 2022 18:57:46 GMT + +_Version update only_ + +## 3.4.0 +Thu, 07 Apr 2022 11:56:26 GMT + +### Updates + +- Bump dependencies (#1067) + +## 3.3.1 +Wed, 23 Feb 2022 19:27:40 GMT + +_Version update only_ + +## 3.3.0 +Mon, 31 Jan 2022 15:58:10 GMT + +_Version update only_ + +## 3.2.3 +Tue, 18 Jan 2022 16:23:52 GMT + +### Updates + +- Bump Copyright to 2022 (#1040) + +## 3.2.2 +Fri, 14 Jan 2022 10:17:59 GMT + +_Version update only_ + +## 3.2.1 +Wed, 12 Jan 2022 09:50:29 GMT + +_Version update only_ + +## 3.2.0 +Tue, 11 Jan 2022 12:53:22 GMT + +_Version update only_ + +## 3.1.6 +Tue, 19 Oct 2021 09:17:22 GMT + +### Updates + +- Fix failing build on ARM Macs (#1012) + +## 3.1.5 +Fri, 01 Oct 2021 08:09:21 GMT + +_Version update only_ + +## 3.1.4 +Tue, 21 Sep 2021 14:59:36 GMT + +_Version update only_ + +## 3.1.3 +Mon, 23 Aug 2021 10:13:18 GMT + +_Version update only_ + +## 3.1.2 +Mon, 16 Aug 2021 12:59:59 GMT + +### Updates + +- Update READMEs with correct Node requirements (#994) + +## 3.1.1 +Wed, 04 Aug 2021 10:12:25 GMT + +### Updates + +- Bump tslib to 2.3.0 (#986) +- Bump typescript to 4.3.5 (#987) +- Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988) + +## 3.1.0 +Fri, 14 May 2021 10:45:32 GMT + +_Version update only_ + +## 3.0.3 +Wed, 21 Apr 2021 12:35:06 GMT + +_Version update only_ + +## 3.0.2 +Thu, 15 Apr 2021 21:07:39 GMT + +_Version update only_ + +## 3.0.1 +Wed, 14 Apr 2021 16:30:05 GMT + +### Updates + +- Add peerDependencies to plugins (#950) +- Mark packages as sideEffect: false (#951) +- Add unit tests to plugin track* functions (#954) + +## 3.0.0 +Wed, 31 Mar 2021 14:46:47 GMT + +### Updates + +- Bump rollup to 2.41 (#916) +- Publish UMD versions of plugins to GitHub release (#923) +- Ensure browser-tracker API methods catch exceptions (#919) +- Introduce TSDoc comments and extract interfaces where appropriate (#906) +- Bump major version to v3 and update READMEs (#904) +- Improve Core API for module bundlers which support treeshaking (#903) +- Rename @snowplow/browser-core to @snowplow/browser-tracker-core (#901) +- Publish lite version of sp.js (#900) +- Ensure correct 3-Clause BSD License notices are being used (#316) +- Improve API for module bundlers which support treeshaking (#899) +- Bump rush to 5.39 (#895) +- Port to TypeScript (#72) +- Make sp.js build process modular (#450) +- Create @snowplow/browser-tracker package for npm distribution (#541) +- Split auto contexts into plugins (#880) +- Add rush to manage monorepo (#883) +- Add ES Module builds (#882) +- Cleanup deprecated methods (#557) +- Update publishing process for rush (#907) +- Change white and black lists to allow and deny lists (#908) +- Create rush change files for major version 3 release (#909) + diff --git a/plugins/browser-plugin-enhanced-ecommerce/LICENSE b/plugins/browser-plugin-enhanced-ecommerce/LICENSE new file mode 100644 index 000000000..76f1946ea --- /dev/null +++ b/plugins/browser-plugin-enhanced-ecommerce/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/plugins/browser-plugin-enhanced-ecommerce/README.md b/plugins/browser-plugin-enhanced-ecommerce/README.md new file mode 100644 index 000000000..f51375227 --- /dev/null +++ b/plugins/browser-plugin-enhanced-ecommerce/README.md @@ -0,0 +1,84 @@ +# Snowplow Enhanced Ecommerce Tracking + +[![npm version][npm-image]][npm-url] +[![License][license-image]](LICENSE) + + + +--- + +Browser Plugin to be used with `@snowplow/browser-tracker`. + +Adds enhanced ecommerce events to your Snowplow tracking. + +## Maintainer quick start + +Part of the Snowplow JavaScript Tracker monorepo. +Build with [Node.js](https://nodejs.org/en/) (18 - 20) and [Rush](https://rushjs.io/). + +### Setup repository + +```bash +npm install -g @microsoft/rush +git clone https://github.com/snowplow/snowplow-javascript-tracker.git +rush update +``` + +## Package Installation + +With npm: + +```bash +npm install @snowplow/browser-plugin-enhanced-ecommerce +``` + +## Usage + +Initialize your tracker with the EnhancedEcommercePlugin: + +```js +import { newTracker } from '@snowplow/browser-tracker'; +import { EnhancedEcommercePlugin } from '@snowplow/browser-plugin-enhanced-ecommerce'; + +newTracker('sp1', '{{collector}}', { plugins: [ EnhancedEcommercePlugin() ] }); // Also stores reference at module level +``` + +Then use the available functions from this package to track to all trackers which have been initialized with this plugin: + +```js +import { addEnhancedEcommerceProductContext, addEnhancedEcommercePromoContext, trackEnhancedEcommerceAction } from '@snowplow/browser-plugin-enhanced-ecommerce'; + +addEnhancedEcommerceProductContext({ + id: 'P12345', + name: 'Blue T-Shirt', + list: 'Search Results', + brand: 'The T-Shirt Company', + category: 'Apparel/T-Shirts', + variant: 'Black', + quantity: 1, +}); + +addEnhancedEcommercePromoContext({ + id: 'PROMO_1234', + name: 'Summer Sale', + creative: 'summer_banner2', + position: 'banner_slot1', +}); + +trackEnhancedEcommerceAction({ action: 'purchase' }); + +``` + +## Copyright and license + +Licensed and distributed under the [BSD 3-Clause License](LICENSE) ([An OSI Approved License][osi]). + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang. + +All rights reserved. + +[npm-url]: https://www.npmjs.com/package/@snowplow/browser-plugin-enhanced-ecommerce +[npm-image]: https://img.shields.io/npm/v/@snowplow/browser-plugin-enhanced-ecommerce +[docs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-tracker/ +[osi]: https://opensource.org/licenses/BSD-3-Clause +[license-image]: https://img.shields.io/npm/l/@snowplow/browser-plugin-enhanced-ecommerce diff --git a/plugins/browser-plugin-enhanced-ecommerce/jest.config.js b/plugins/browser-plugin-enhanced-ecommerce/jest.config.js new file mode 100644 index 000000000..87d15da9b --- /dev/null +++ b/plugins/browser-plugin-enhanced-ecommerce/jest.config.js @@ -0,0 +1,6 @@ +module.exports = { + preset: 'ts-jest', + reporters: ['jest-standard-reporter'], + setupFilesAfterEnv: ['../../setupTestGlobals.ts'], + testEnvironment: 'jest-environment-jsdom-global', +}; diff --git a/plugins/browser-plugin-enhanced-ecommerce/package.json b/plugins/browser-plugin-enhanced-ecommerce/package.json new file mode 100644 index 000000000..4717fed7d --- /dev/null +++ b/plugins/browser-plugin-enhanced-ecommerce/package.json @@ -0,0 +1,54 @@ +{ + "name": "@snowplow/browser-plugin-enhanced-ecommerce", + "version": "4.10.0", + "description": "Enhanced Ecommerce tracking for Snowplow", + "homepage": "http://bit.ly/sp-js", + "bugs": "https://github.com/snowplow/snowplow-javascript-tracker/issues", + "repository": { + "type": "git", + "url": "https://github.com/snowplow/snowplow-javascript-tracker.git" + }, + "license": "BSD-3-Clause", + "author": "Paul Boocock", + "sideEffects": false, + "main": "./dist/index.umd.js", + "module": "./dist/index.module.js", + "types": "./dist/index.module.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "rollup -c --silent --failAfterWarnings", + "test": "jest" + }, + "dependencies": { + "@snowplow/browser-tracker-core": "workspace:*", + "@snowplow/tracker-core": "workspace:*", + "tslib": "^2.3.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "~21.0.2", + "@rollup/plugin-node-resolve": "~13.1.3", + "@types/jest": "~28.1.1", + "@types/jsdom": "~16.2.14", + "@types/lodash": "~4.14.180", + "@typescript-eslint/eslint-plugin": "~5.15.0", + "@typescript-eslint/parser": "~5.15.0", + "eslint": "~8.11.0", + "jest": "~28.1.3", + "jest-environment-jsdom": "~28.1.3", + "jest-environment-jsdom-global": "~4.0.0", + "jest-standard-reporter": "~2.0.0", + "lodash": "~4.17.21", + "rollup": "~2.70.1", + "rollup-plugin-cleanup": "~3.2.1", + "rollup-plugin-license": "~2.6.1", + "rollup-plugin-terser": "~7.0.2", + "rollup-plugin-ts": "~2.0.5", + "ts-jest": "~28.0.8", + "typescript": "~4.6.2" + }, + "peerDependencies": { + "@snowplow/browser-tracker": "~4.10.0" + } +} diff --git a/plugins/browser-plugin-enhanced-ecommerce/rollup.config.js b/plugins/browser-plugin-enhanced-ecommerce/rollup.config.js new file mode 100644 index 000000000..fe36add47 --- /dev/null +++ b/plugins/browser-plugin-enhanced-ecommerce/rollup.config.js @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import ts from 'rollup-plugin-ts'; // Prefered over @rollup/plugin-typescript as it bundles .d.ts files +import { banner } from '../../banner'; +import { terser } from 'rollup-plugin-terser'; +import cleanup from 'rollup-plugin-cleanup'; +import pkg from './package.json'; +import { builtinModules } from 'module'; + +const umdPlugins = [nodeResolve({ browser: true }), commonjs(), ts()]; +const umdName = 'snowplowEnhancedEcommerce'; + +export default [ + // CommonJS (for Node) and ES module (for bundlers) build. + { + input: './src/index.ts', + plugins: [...umdPlugins, banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main, format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + plugins: [...umdPlugins, terser(), cleanup({ comments: 'none' }), banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main.replace('.js', '.min.js'), format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + external: [...builtinModules, ...Object.keys(pkg.dependencies), ...Object.keys(pkg.devDependencies)], + plugins: [ + ts(), // so Rollup can convert TypeScript to JavaScript + banner(), + ], + output: [{ file: pkg.module, format: 'es', sourcemap: true }], + }, +]; diff --git a/plugins/browser-plugin-enhanced-ecommerce/src/index.ts b/plugins/browser-plugin-enhanced-ecommerce/src/index.ts new file mode 100644 index 000000000..43cc52cbf --- /dev/null +++ b/plugins/browser-plugin-enhanced-ecommerce/src/index.ts @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { + BrowserPlugin, + BrowserTracker, + parseAndValidateFloat, + parseAndValidateInt, + dispatchToTrackersInCollection, +} from '@snowplow/browser-tracker-core'; +import { buildSelfDescribingEvent, CommonEventProperties, SelfDescribingJson } from '@snowplow/tracker-core'; + +const _trackers: Record = {}; +const _context: Record> = {}; + +/** + * For tracking GA Enhanced Ecommerce events and contexts + * {@link https://developers.google.com/analytics/devguides/collection/analyticsjs/enhanced-ecommerce} + * + * @deprecated Use @snowplow/browser-plugin-snowplow-ecommerce instead + */ +export function EnhancedEcommercePlugin(): BrowserPlugin { + return { + activateBrowserPlugin: (tracker) => { + _trackers[tracker.id] = tracker; + _context[tracker.id] = []; + }, + }; +} + +/** + * An Enhanced Ecommerce Action + * Used when tracking an GA Enhanced Ecommerce Action with all stored Enhanced Ecommerce contexts + */ +export interface EnhancedEcommerceAction { + /** Actions specify how to interpret product and promotion data */ + action?: string; +} + +/** + * Track a GA Enhanced Ecommerce Action with all stored + * Enhanced Ecommerce contexts + * + * @param event + * @param trackers + */ +export function trackEnhancedEcommerceAction( + event: EnhancedEcommerceAction & CommonEventProperties = {}, + trackers: Array = Object.keys(_trackers) +) { + dispatchToTrackersInCollection(trackers, _trackers, (t) => { + const combinedContexts = _context[t.id].concat(event.context || []); + _context[t.id].length = 0; + + t.core.track( + buildSelfDescribingEvent({ + event: { + schema: 'iglu:com.google.analytics.enhanced-ecommerce/action/jsonschema/1-0-0', + data: { + action: event.action, + }, + }, + }), + combinedContexts, + event.timestamp + ); + }); +} + +/** + * The Action Context + * Represents information about an ecommerce related action that has taken place. + */ +export interface EnhanacedCommerceActionContext { + /** The transaction id */ + id?: string; + /** The store of affiliation from which this transaction occured */ + affiliation?: string; + /** Specifies the total revenue or grand total associated with the transaction */ + revenue?: string; + /** The total tax associated with the transaction. */ + tax?: number; + /** The shipping cost associated with the transaction. */ + shipping?: number; + /** The transaction coupon redeemed with the transaction. */ + coupon?: string; + /** The list that the associated products belong to. */ + list?: string; + /** A number representing a step in the checkout process. Optional on `checkout` actions. */ + step?: number; + /** Additional field for checkout and checkout_option actions that can describe option information on the checkout page, like selected payment method. */ + option?: string; + /** The currency of the transactoin */ + currency?: string; +} + +/** + * Adds a GA Enhanced Ecommerce Action Context + * + * @param context - The context to be stored + * @param trackers - The tracker identifiers which the context will be stored against + */ +export function addEnhancedEcommerceActionContext( + context: EnhanacedCommerceActionContext = {}, + trackers: Array = Object.keys(_trackers) +) { + const { id, affiliation, revenue, tax, shipping, coupon, list, step, option, currency } = context; + trackers.forEach((trackerId) => { + if (_context[trackerId]) { + _context[trackerId].push({ + schema: 'iglu:com.google.analytics.enhanced-ecommerce/actionFieldObject/jsonschema/1-0-0', + data: { + id: id, + affiliation: affiliation, + revenue: parseAndValidateFloat(revenue), + tax: parseAndValidateFloat(tax), + shipping: parseAndValidateFloat(shipping), + coupon: coupon, + list: list, + step: parseAndValidateInt(step), + option: option, + currency: currency, + }, + }); + } + }); +} + +/** + * An enhanced ecommerce impression context + */ +export interface EnhancedEcommerceImpressionContext { + /** The product ID or SKU */ + id?: string; + /** The name of the product */ + name?: string; + /** The list or collection to which the product belongs */ + list?: string; + /** The brand associated with the product */ + brand?: string; + /** The category to which the product belongs */ + category?: string; + /** The variant of the product */ + variant?: string; + /** The product's position in a list or collection */ + position?: number; + /** The price of a product */ + price?: string; + /** The currency of a product */ + currency?: string; +} + +/** + * Adds a GA Enhanced Ecommerce Impression Context + * + * @param context - The context to be stored + * @param trackers - The tracker identifiers which the context will be stored against + */ +export function addEnhancedEcommerceImpressionContext( + context: EnhancedEcommerceImpressionContext = {}, + trackers: Array = Object.keys(_trackers) +) { + const { id, name, list, brand, category, variant, position, price, currency } = context; + trackers.forEach((trackerId) => { + if (_context[trackerId]) { + _context[trackerId].push({ + schema: 'iglu:com.google.analytics.enhanced-ecommerce/impressionFieldObject/jsonschema/1-0-0', + data: { + id: id, + name: name, + list: list, + brand: brand, + category: category, + variant: variant, + position: parseAndValidateInt(position), + price: parseAndValidateFloat(price), + currency: currency, + }, + }); + } + }); +} + +/** + * An enhanced ecommerce product context + */ +export interface EnhancedEcommerceProductContext { + /** The product ID or SKU */ + id?: string; + /** The name of the product */ + name?: string; + /** The list or collection to which the product belongs */ + list?: string; + /** The brand associated with the product */ + brand?: string; + /** The category to which the product belongs */ + category?: string; + /** The variant of the product */ + variant?: string; + /** The price of a product */ + price?: number; + /** The quantity of a product */ + quantity?: number; + /** The coupon code associated with a product */ + coupon?: string; + /** The product's position in a list or collection */ + position?: number; + /** The currency of the product */ + currency?: string; +} + +/** + * Adds a GA Enhanced Ecommerce Product Context + * + * @param context - The context to be stored + * @param trackers - The tracker identifiers which the context will be stored against + */ +export function addEnhancedEcommerceProductContext( + context: EnhancedEcommerceProductContext = {}, + trackers: Array = Object.keys(_trackers) +) { + const { id, name, list, brand, category, variant, price, quantity, coupon, position, currency } = context; + trackers.forEach((trackerId) => { + if (_context[trackerId]) { + _context[trackerId].push({ + schema: 'iglu:com.google.analytics.enhanced-ecommerce/productFieldObject/jsonschema/1-0-0', + data: { + id: id, + name: name, + list: list, + brand: brand, + category: category, + variant: variant, + price: parseAndValidateFloat(price), + quantity: parseAndValidateInt(quantity), + coupon: coupon, + position: parseAndValidateInt(position), + currency: currency, + }, + }); + } + }); +} + +/** + * An enhanced ecommerce promo context + */ +export interface EnhancedEcommercePromoContext { + /** The promotion ID */ + id?: string; + /** The name of the promotion */ + name?: string; + /** The creative associated with the promotion */ + creative?: string; + /** The position of the creative */ + position?: string; + /** The currency of the product */ + currency?: string; +} + +/** + * Adds a GA Enhanced Ecommerce Promo Context + * + * @param context - The context to be stored + * @param trackers - The tracker identifiers which the context will be stored against + */ +export function addEnhancedEcommercePromoContext( + context: EnhancedEcommercePromoContext = {}, + trackers: Array = Object.keys(_trackers) +) { + const { id, name, creative, position, currency } = context; + trackers.forEach((trackerId) => { + if (_context[trackerId]) { + _context[trackerId].push({ + schema: 'iglu:com.google.analytics.enhanced-ecommerce/promoFieldObject/jsonschema/1-0-0', + data: { + id, + name, + creative, + position, + currency, + }, + }); + } + }); +} diff --git a/plugins/browser-plugin-enhanced-ecommerce/test/contexts.test.ts b/plugins/browser-plugin-enhanced-ecommerce/test/contexts.test.ts new file mode 100644 index 000000000..c8ce5ed35 --- /dev/null +++ b/plugins/browser-plugin-enhanced-ecommerce/test/contexts.test.ts @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { addTracker, SharedState } from '@snowplow/browser-tracker-core'; +import F from 'lodash/fp'; +import { + EnhancedEcommercePlugin, + addEnhancedEcommerceActionContext, + addEnhancedEcommerceImpressionContext, + addEnhancedEcommerceProductContext, + addEnhancedEcommercePromoContext, + trackEnhancedEcommerceAction, +} from '../src'; +import { newInMemoryEventStore } from '@snowplow/tracker-core'; + +const getUEEvents = F.compose(F.filter(F.compose(F.eq('ue'), F.get('e')))); +const extractSchemas = F.map(F.compose(F.get('data'), (cx: string) => JSON.parse(cx), F.get('co'))); + +it('attaches enhanced ecommerce contexts to enhanced ecommerce events', async () => { + const eventStore = newInMemoryEventStore({}); + addTracker('sp1', 'sp1', 'js-3.0.0', '', new SharedState(), { + stateStorageStrategy: 'cookie', + encodeBase64: false, + plugins: [EnhancedEcommercePlugin()], + eventStore, + customFetch: async () => new Response(null, { status: 500 }), + }); + + addEnhancedEcommerceProductContext({ id: '1234-5678', name: 'T-Shirt' }); + addEnhancedEcommerceImpressionContext({ id: '1234-5678', name: 'T-Shirt' }); + addEnhancedEcommercePromoContext({ id: '1234-5678', name: 'T-Shirt' }); + addEnhancedEcommerceActionContext({ id: '1234-5678', affiliation: 'acme' }); + trackEnhancedEcommerceAction(); + + const findWithStaticValue = F.filter(F.get('data.id')); + const extractContextsWithStaticValue = F.compose(findWithStaticValue, F.flatten, extractSchemas, getUEEvents); + + const countWithStaticValueEq = (value: string) => + F.compose(F.size, F.filter(F.compose(F.eq(value), F.get('data.id'))), extractContextsWithStaticValue); + + // we expect there to be four contexts added to the event + expect(countWithStaticValueEq('1234-5678')(await eventStore.getAllPayloads())).toBe(4); +}); diff --git a/plugins/browser-plugin-enhanced-ecommerce/tsconfig.json b/plugins/browser-plugin-enhanced-ecommerce/tsconfig.json new file mode 100644 index 000000000..4082f16a5 --- /dev/null +++ b/plugins/browser-plugin-enhanced-ecommerce/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +} diff --git a/plugins/browser-plugin-error-tracking/CHANGELOG.json b/plugins/browser-plugin-error-tracking/CHANGELOG.json new file mode 100644 index 000000000..2c7b5871b --- /dev/null +++ b/plugins/browser-plugin-error-tracking/CHANGELOG.json @@ -0,0 +1,620 @@ +{ + "name": "@snowplow/browser-plugin-error-tracking", + "entries": [ + { + "version": "4.10.0", + "tag": "@snowplow/browser-plugin-error-tracking_v4.10.0", + "date": "Mon, 27 Jul 2026 13:52:14 GMT", + "comments": {} + }, + { + "version": "4.9.0", + "tag": "@snowplow/browser-plugin-error-tracking_v4.9.0", + "date": "Tue, 21 Jul 2026 14:53:08 GMT", + "comments": {} + }, + { + "version": "4.8.4", + "tag": "@snowplow/browser-plugin-error-tracking_v4.8.4", + "date": "Thu, 02 Jul 2026 10:07:52 GMT", + "comments": {} + }, + { + "version": "4.8.3", + "tag": "@snowplow/browser-plugin-error-tracking_v4.8.3", + "date": "Tue, 30 Jun 2026 14:22:03 GMT", + "comments": { + "none": [ + { + "comment": "Update uuid to v11 and remove closure-compiler from the build pipeline" + } + ] + } + }, + { + "version": "4.8.2", + "tag": "@snowplow/browser-plugin-error-tracking_v4.8.2", + "date": "Wed, 17 Jun 2026 12:30:12 GMT", + "comments": {} + }, + { + "version": "4.8.1", + "tag": "@snowplow/browser-plugin-error-tracking_v4.8.1", + "date": "Wed, 13 May 2026 09:26:05 GMT", + "comments": {} + }, + { + "version": "4.8.0", + "tag": "@snowplow/browser-plugin-error-tracking_v4.8.0", + "date": "Tue, 28 Apr 2026 07:56:22 GMT", + "comments": {} + }, + { + "version": "4.7.0", + "tag": "@snowplow/browser-plugin-error-tracking_v4.7.0", + "date": "Wed, 01 Apr 2026 12:59:29 GMT", + "comments": {} + }, + { + "version": "4.6.9", + "tag": "@snowplow/browser-plugin-error-tracking_v4.6.9", + "date": "Mon, 16 Mar 2026 15:43:06 GMT", + "comments": { + "none": [ + { + "comment": "Truncate fileName property in application_error events to max 1024 characters to avoid validation errors" + } + ] + } + }, + { + "version": "4.6.8", + "tag": "@snowplow/browser-plugin-error-tracking_v4.6.8", + "date": "Tue, 28 Oct 2025 09:46:42 GMT", + "comments": {} + }, + { + "version": "4.6.7", + "tag": "@snowplow/browser-plugin-error-tracking_v4.6.7", + "date": "Tue, 07 Oct 2025 14:53:36 GMT", + "comments": {} + }, + { + "version": "4.6.6", + "tag": "@snowplow/browser-plugin-error-tracking_v4.6.6", + "date": "Tue, 26 Aug 2025 08:42:27 GMT", + "comments": {} + }, + { + "version": "4.6.5", + "tag": "@snowplow/browser-plugin-error-tracking_v4.6.5", + "date": "Wed, 25 Jun 2025 21:16:46 GMT", + "comments": {} + }, + { + "version": "4.6.4", + "tag": "@snowplow/browser-plugin-error-tracking_v4.6.4", + "date": "Wed, 25 Jun 2025 12:08:50 GMT", + "comments": {} + }, + { + "version": "4.6.3", + "tag": "@snowplow/browser-plugin-error-tracking_v4.6.3", + "date": "Thu, 29 May 2025 19:52:07 GMT", + "comments": {} + }, + { + "version": "4.6.2", + "tag": "@snowplow/browser-plugin-error-tracking_v4.6.2", + "date": "Tue, 20 May 2025 07:39:05 GMT", + "comments": {} + }, + { + "version": "4.6.1", + "tag": "@snowplow/browser-plugin-error-tracking_v4.6.1", + "date": "Tue, 06 May 2025 13:10:51 GMT", + "comments": {} + }, + { + "version": "4.6.0", + "tag": "@snowplow/browser-plugin-error-tracking_v4.6.0", + "date": "Thu, 01 May 2025 09:58:59 GMT", + "comments": {} + }, + { + "version": "4.5.0", + "tag": "@snowplow/browser-plugin-error-tracking_v4.5.0", + "date": "Fri, 04 Apr 2025 09:21:23 GMT", + "comments": {} + }, + { + "version": "4.4.0", + "tag": "@snowplow/browser-plugin-error-tracking_v4.4.0", + "date": "Thu, 20 Mar 2025 12:14:34 GMT", + "comments": {} + }, + { + "version": "4.3.1", + "tag": "@snowplow/browser-plugin-error-tracking_v4.3.1", + "date": "Tue, 21 Jan 2025 11:09:42 GMT", + "comments": {} + }, + { + "version": "4.3.0", + "tag": "@snowplow/browser-plugin-error-tracking_v4.3.0", + "date": "Mon, 20 Jan 2025 11:45:13 GMT", + "comments": {} + }, + { + "version": "4.2.0", + "tag": "@snowplow/browser-plugin-error-tracking_v4.2.0", + "date": "Mon, 13 Jan 2025 08:30:05 GMT", + "comments": {} + }, + { + "version": "4.1.0", + "tag": "@snowplow/browser-plugin-error-tracking_v4.1.0", + "date": "Thu, 28 Nov 2024 10:57:30 GMT", + "comments": {} + }, + { + "version": "4.0.4", + "tag": "@snowplow/browser-plugin-error-tracking_v4.0.4", + "date": "Thu, 21 Nov 2024 09:06:36 GMT", + "comments": {} + }, + { + "version": "4.0.3", + "tag": "@snowplow/browser-plugin-error-tracking_v4.0.3", + "date": "Wed, 20 Nov 2024 09:30:31 GMT", + "comments": {} + }, + { + "version": "4.0.2", + "tag": "@snowplow/browser-plugin-error-tracking_v4.0.2", + "date": "Mon, 11 Nov 2024 15:46:34 GMT", + "comments": {} + }, + { + "version": "4.0.1", + "tag": "@snowplow/browser-plugin-error-tracking_v4.0.1", + "date": "Fri, 01 Nov 2024 10:35:07 GMT", + "comments": {} + }, + { + "version": "4.0.0", + "tag": "@snowplow/browser-plugin-error-tracking_v4.0.0", + "date": "Mon, 28 Oct 2024 11:48:53 GMT", + "comments": { + "none": [ + { + "comment": "Fix message when a resource triggers error instead of script" + } + ] + } + }, + { + "version": "3.24.6", + "tag": "@snowplow/browser-plugin-error-tracking_v3.24.6", + "date": "Mon, 28 Oct 2024 10:23:28 GMT", + "comments": {} + }, + { + "version": "3.24.5", + "tag": "@snowplow/browser-plugin-error-tracking_v3.24.5", + "date": "Fri, 25 Oct 2024 08:53:04 GMT", + "comments": {} + }, + { + "version": "3.24.4", + "tag": "@snowplow/browser-plugin-error-tracking_v3.24.4", + "date": "Thu, 26 Sep 2024 06:10:22 GMT", + "comments": {} + }, + { + "version": "3.24.3", + "tag": "@snowplow/browser-plugin-error-tracking_v3.24.3", + "date": "Tue, 03 Sep 2024 08:15:14 GMT", + "comments": { + "none": [ + { + "comment": "Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush" + } + ] + } + }, + { + "version": "3.24.2", + "tag": "@snowplow/browser-plugin-error-tracking_v3.24.2", + "date": "Wed, 24 Jul 2024 08:59:00 GMT", + "comments": { + "none": [ + { + "comment": "Truncate error stack trace if it's size is greater than 8kb" + } + ] + } + }, + { + "version": "3.24.1", + "tag": "@snowplow/browser-plugin-error-tracking_v3.24.1", + "date": "Tue, 02 Jul 2024 07:08:17 GMT", + "comments": {} + }, + { + "version": "3.24.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.24.0", + "date": "Tue, 25 Jun 2024 08:31:05 GMT", + "comments": {} + }, + { + "version": "3.23.1", + "tag": "@snowplow/browser-plugin-error-tracking_v3.23.1", + "date": "Tue, 04 Jun 2024 13:34:45 GMT", + "comments": {} + }, + { + "version": "3.23.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.23.0", + "date": "Thu, 28 Mar 2024 11:28:45 GMT", + "comments": {} + }, + { + "version": "3.22.1", + "tag": "@snowplow/browser-plugin-error-tracking_v3.22.1", + "date": "Wed, 13 Mar 2024 08:39:48 GMT", + "comments": {} + }, + { + "version": "3.22.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.22.0", + "date": "Fri, 08 Mar 2024 08:13:04 GMT", + "comments": {} + }, + { + "version": "3.21.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.21.0", + "date": "Mon, 29 Jan 2024 08:34:06 GMT", + "comments": {} + }, + { + "version": "3.20.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.20.0", + "date": "Mon, 15 Jan 2024 14:41:16 GMT", + "comments": {} + }, + { + "version": "3.19.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.19.0", + "date": "Thu, 14 Dec 2023 10:45:22 GMT", + "comments": {} + }, + { + "version": "3.18.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.18.0", + "date": "Mon, 04 Dec 2023 13:44:02 GMT", + "comments": {} + }, + { + "version": "3.17.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.17.0", + "date": "Tue, 14 Nov 2023 17:58:26 GMT", + "comments": {} + }, + { + "version": "3.16.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.16.0", + "date": "Mon, 16 Oct 2023 14:58:08 GMT", + "comments": {} + }, + { + "version": "3.15.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.15.0", + "date": "Mon, 28 Aug 2023 14:25:14 GMT", + "comments": {} + }, + { + "version": "3.14.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.14.0", + "date": "Thu, 10 Aug 2023 13:56:44 GMT", + "comments": {} + }, + { + "version": "3.13.1", + "tag": "@snowplow/browser-plugin-error-tracking_v3.13.1", + "date": "Thu, 29 Jun 2023 14:20:06 GMT", + "comments": {} + }, + { + "version": "3.13.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.13.0", + "date": "Tue, 20 Jun 2023 07:44:23 GMT", + "comments": {} + }, + { + "version": "3.12.1", + "tag": "@snowplow/browser-plugin-error-tracking_v3.12.1", + "date": "Thu, 15 Jun 2023 10:05:37 GMT", + "comments": {} + }, + { + "version": "3.12.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.12.0", + "date": "Mon, 05 Jun 2023 11:51:22 GMT", + "comments": {} + }, + { + "version": "3.11.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.11.0", + "date": "Wed, 24 May 2023 15:56:17 GMT", + "comments": {} + }, + { + "version": "3.10.1", + "tag": "@snowplow/browser-plugin-error-tracking_v3.10.1", + "date": "Fri, 12 May 2023 06:59:31 GMT", + "comments": {} + }, + { + "version": "3.10.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.10.0", + "date": "Thu, 11 May 2023 08:29:15 GMT", + "comments": {} + }, + { + "version": "3.9.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.9.0", + "date": "Thu, 30 Mar 2023 13:46:56 GMT", + "comments": {} + }, + { + "version": "3.8.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.8.0", + "date": "Tue, 03 Jan 2023 15:36:33 GMT", + "comments": {} + }, + { + "version": "3.7.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.7.0", + "date": "Mon, 31 Oct 2022 06:26:28 GMT", + "comments": {} + }, + { + "version": "3.6.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.6.0", + "date": "Thu, 15 Sep 2022 07:55:20 GMT", + "comments": {} + }, + { + "version": "3.5.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.5.0", + "date": "Fri, 10 Jun 2022 18:57:46 GMT", + "comments": {} + }, + { + "version": "3.4.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.4.0", + "date": "Thu, 07 Apr 2022 11:56:26 GMT", + "comments": { + "none": [ + { + "comment": "Bump dependencies (#1067)" + } + ] + } + }, + { + "version": "3.3.1", + "tag": "@snowplow/browser-plugin-error-tracking_v3.3.1", + "date": "Wed, 23 Feb 2022 19:27:40 GMT", + "comments": {} + }, + { + "version": "3.3.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.3.0", + "date": "Mon, 31 Jan 2022 15:58:10 GMT", + "comments": {} + }, + { + "version": "3.2.3", + "tag": "@snowplow/browser-plugin-error-tracking_v3.2.3", + "date": "Tue, 18 Jan 2022 16:23:52 GMT", + "comments": { + "none": [ + { + "comment": "Bump Copyright to 2022 (#1040)" + } + ] + } + }, + { + "version": "3.2.2", + "tag": "@snowplow/browser-plugin-error-tracking_v3.2.2", + "date": "Fri, 14 Jan 2022 10:17:59 GMT", + "comments": {} + }, + { + "version": "3.2.1", + "tag": "@snowplow/browser-plugin-error-tracking_v3.2.1", + "date": "Wed, 12 Jan 2022 09:50:29 GMT", + "comments": {} + }, + { + "version": "3.2.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.2.0", + "date": "Tue, 11 Jan 2022 12:53:22 GMT", + "comments": {} + }, + { + "version": "3.1.6", + "tag": "@snowplow/browser-plugin-error-tracking_v3.1.6", + "date": "Tue, 19 Oct 2021 09:17:22 GMT", + "comments": { + "none": [ + { + "comment": "Fix failing build on ARM Macs (#1012)" + } + ] + } + }, + { + "version": "3.1.5", + "tag": "@snowplow/browser-plugin-error-tracking_v3.1.5", + "date": "Fri, 01 Oct 2021 08:09:21 GMT", + "comments": {} + }, + { + "version": "3.1.4", + "tag": "@snowplow/browser-plugin-error-tracking_v3.1.4", + "date": "Tue, 21 Sep 2021 14:59:36 GMT", + "comments": {} + }, + { + "version": "3.1.3", + "tag": "@snowplow/browser-plugin-error-tracking_v3.1.3", + "date": "Mon, 23 Aug 2021 10:13:18 GMT", + "comments": {} + }, + { + "version": "3.1.2", + "tag": "@snowplow/browser-plugin-error-tracking_v3.1.2", + "date": "Mon, 16 Aug 2021 12:59:59 GMT", + "comments": { + "none": [ + { + "comment": "Update READMEs with correct Node requirements (#994)" + } + ] + } + }, + { + "version": "3.1.1", + "tag": "@snowplow/browser-plugin-error-tracking_v3.1.1", + "date": "Wed, 04 Aug 2021 10:12:25 GMT", + "comments": { + "none": [ + { + "comment": "Bump tslib to 2.3.0 (#986)" + }, + { + "comment": "Bump typescript to 4.3.5 (#987)" + }, + { + "comment": "Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988)" + } + ] + } + }, + { + "version": "3.1.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.1.0", + "date": "Fri, 14 May 2021 10:45:32 GMT", + "comments": {} + }, + { + "version": "3.0.3", + "tag": "@snowplow/browser-plugin-error-tracking_v3.0.3", + "date": "Wed, 21 Apr 2021 12:35:06 GMT", + "comments": {} + }, + { + "version": "3.0.2", + "tag": "@snowplow/browser-plugin-error-tracking_v3.0.2", + "date": "Thu, 15 Apr 2021 21:07:39 GMT", + "comments": {} + }, + { + "version": "3.0.1", + "tag": "@snowplow/browser-plugin-error-tracking_v3.0.1", + "date": "Wed, 14 Apr 2021 16:30:05 GMT", + "comments": { + "none": [ + { + "comment": "Add peerDependencies to plugins (#950)" + }, + { + "comment": "Mark packages as sideEffect: false (#951)" + }, + { + "comment": "Add unit tests to plugin track* functions (#954)" + } + ] + } + }, + { + "version": "3.0.0", + "tag": "@snowplow/browser-plugin-error-tracking_v3.0.0", + "date": "Wed, 31 Mar 2021 14:46:47 GMT", + "comments": { + "none": [ + { + "comment": "Bump rollup to 2.41 (#916)" + }, + { + "comment": "Publish UMD versions of plugins to GitHub release (#923)" + }, + { + "comment": "Remove module level references to window and document (close #928)" + }, + { + "comment": "Ensure browser-tracker API methods catch exceptions (#919)" + }, + { + "comment": "Introduce TSDoc comments and extract interfaces where appropriate (#906)" + }, + { + "comment": "Bump major version to v3 and update READMEs (#904)" + }, + { + "comment": "Improve Core API for module bundlers which support treeshaking (#903)" + }, + { + "comment": "Rename @snowplow/browser-core to @snowplow/browser-tracker-core (#901)" + }, + { + "comment": "Publish lite version of sp.js (#900)" + }, + { + "comment": "Ensure correct 3-Clause BSD License notices are being used (#316)" + }, + { + "comment": "Improve API for module bundlers which support treeshaking (#899)" + }, + { + "comment": "Bump rush to 5.39 (#895)" + }, + { + "comment": "Port to TypeScript (#72)" + }, + { + "comment": "Make sp.js build process modular (#450)" + }, + { + "comment": "Create @snowplow/browser-tracker package for npm distribution (#541)" + }, + { + "comment": "Split auto contexts into plugins (#880)" + }, + { + "comment": "Add rush to manage monorepo (#883)" + }, + { + "comment": "Add ES Module builds (#882)" + }, + { + "comment": "Cleanup deprecated methods (#557)" + }, + { + "comment": "Update publishing process for rush (#907)" + }, + { + "comment": "Change white and black lists to allow and deny lists (#908)" + }, + { + "comment": "Create rush change files for major version 3 release (#909)" + } + ] + } + } + ] +} diff --git a/plugins/browser-plugin-error-tracking/CHANGELOG.md b/plugins/browser-plugin-error-tracking/CHANGELOG.md new file mode 100644 index 000000000..257e8f02d --- /dev/null +++ b/plugins/browser-plugin-error-tracking/CHANGELOG.md @@ -0,0 +1,443 @@ +# Change Log - @snowplow/browser-plugin-error-tracking + +This log was last generated on Mon, 27 Jul 2026 13:52:14 GMT and should not be manually modified. + +## 4.10.0 +Mon, 27 Jul 2026 13:52:14 GMT + +_Version update only_ + +## 4.9.0 +Tue, 21 Jul 2026 14:53:08 GMT + +_Version update only_ + +## 4.8.4 +Thu, 02 Jul 2026 10:07:52 GMT + +_Version update only_ + +## 4.8.3 +Tue, 30 Jun 2026 14:22:03 GMT + +### Updates + +- Update uuid to v11 and remove closure-compiler from the build pipeline + +## 4.8.2 +Wed, 17 Jun 2026 12:30:12 GMT + +_Version update only_ + +## 4.8.1 +Wed, 13 May 2026 09:26:05 GMT + +_Version update only_ + +## 4.8.0 +Tue, 28 Apr 2026 07:56:22 GMT + +_Version update only_ + +## 4.7.0 +Wed, 01 Apr 2026 12:59:29 GMT + +_Version update only_ + +## 4.6.9 +Mon, 16 Mar 2026 15:43:06 GMT + +### Updates + +- Truncate fileName property in application_error events to max 1024 characters to avoid validation errors + +## 4.6.8 +Tue, 28 Oct 2025 09:46:42 GMT + +_Version update only_ + +## 4.6.7 +Tue, 07 Oct 2025 14:53:36 GMT + +_Version update only_ + +## 4.6.6 +Tue, 26 Aug 2025 08:42:27 GMT + +_Version update only_ + +## 4.6.5 +Wed, 25 Jun 2025 21:16:46 GMT + +_Version update only_ + +## 4.6.4 +Wed, 25 Jun 2025 12:08:50 GMT + +_Version update only_ + +## 4.6.3 +Thu, 29 May 2025 19:52:07 GMT + +_Version update only_ + +## 4.6.2 +Tue, 20 May 2025 07:39:05 GMT + +_Version update only_ + +## 4.6.1 +Tue, 06 May 2025 13:10:51 GMT + +_Version update only_ + +## 4.6.0 +Thu, 01 May 2025 09:58:59 GMT + +_Version update only_ + +## 4.5.0 +Fri, 04 Apr 2025 09:21:23 GMT + +_Version update only_ + +## 4.4.0 +Thu, 20 Mar 2025 12:14:34 GMT + +_Version update only_ + +## 4.3.1 +Tue, 21 Jan 2025 11:09:42 GMT + +_Version update only_ + +## 4.3.0 +Mon, 20 Jan 2025 11:45:13 GMT + +_Version update only_ + +## 4.2.0 +Mon, 13 Jan 2025 08:30:05 GMT + +_Version update only_ + +## 4.1.0 +Thu, 28 Nov 2024 10:57:30 GMT + +_Version update only_ + +## 4.0.4 +Thu, 21 Nov 2024 09:06:36 GMT + +_Version update only_ + +## 4.0.3 +Wed, 20 Nov 2024 09:30:31 GMT + +_Version update only_ + +## 4.0.2 +Mon, 11 Nov 2024 15:46:34 GMT + +_Version update only_ + +## 4.0.1 +Fri, 01 Nov 2024 10:35:07 GMT + +_Version update only_ + +## 4.0.0 +Mon, 28 Oct 2024 11:48:53 GMT + +### Updates + +- Fix message when a resource triggers error instead of script + +## 3.24.6 +Mon, 28 Oct 2024 10:23:28 GMT + +_Version update only_ + +## 3.24.5 +Fri, 25 Oct 2024 08:53:04 GMT + +_Version update only_ + +## 3.24.4 +Thu, 26 Sep 2024 06:10:22 GMT + +_Version update only_ + +## 3.24.3 +Tue, 03 Sep 2024 08:15:14 GMT + +### Updates + +- Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush + +## 3.24.2 +Wed, 24 Jul 2024 08:59:00 GMT + +### Updates + +- Truncate error stack trace if it's size is greater than 8kb + +## 3.24.1 +Tue, 02 Jul 2024 07:08:17 GMT + +_Version update only_ + +## 3.24.0 +Tue, 25 Jun 2024 08:31:05 GMT + +_Version update only_ + +## 3.23.1 +Tue, 04 Jun 2024 13:34:45 GMT + +_Version update only_ + +## 3.23.0 +Thu, 28 Mar 2024 11:28:45 GMT + +_Version update only_ + +## 3.22.1 +Wed, 13 Mar 2024 08:39:48 GMT + +_Version update only_ + +## 3.22.0 +Fri, 08 Mar 2024 08:13:04 GMT + +_Version update only_ + +## 3.21.0 +Mon, 29 Jan 2024 08:34:06 GMT + +_Version update only_ + +## 3.20.0 +Mon, 15 Jan 2024 14:41:16 GMT + +_Version update only_ + +## 3.19.0 +Thu, 14 Dec 2023 10:45:22 GMT + +_Version update only_ + +## 3.18.0 +Mon, 04 Dec 2023 13:44:02 GMT + +_Version update only_ + +## 3.17.0 +Tue, 14 Nov 2023 17:58:26 GMT + +_Version update only_ + +## 3.16.0 +Mon, 16 Oct 2023 14:58:08 GMT + +_Version update only_ + +## 3.15.0 +Mon, 28 Aug 2023 14:25:14 GMT + +_Version update only_ + +## 3.14.0 +Thu, 10 Aug 2023 13:56:44 GMT + +_Version update only_ + +## 3.13.1 +Thu, 29 Jun 2023 14:20:06 GMT + +_Version update only_ + +## 3.13.0 +Tue, 20 Jun 2023 07:44:23 GMT + +_Version update only_ + +## 3.12.1 +Thu, 15 Jun 2023 10:05:37 GMT + +_Version update only_ + +## 3.12.0 +Mon, 05 Jun 2023 11:51:22 GMT + +_Version update only_ + +## 3.11.0 +Wed, 24 May 2023 15:56:17 GMT + +_Version update only_ + +## 3.10.1 +Fri, 12 May 2023 06:59:31 GMT + +_Version update only_ + +## 3.10.0 +Thu, 11 May 2023 08:29:15 GMT + +_Version update only_ + +## 3.9.0 +Thu, 30 Mar 2023 13:46:56 GMT + +_Version update only_ + +## 3.8.0 +Tue, 03 Jan 2023 15:36:33 GMT + +_Version update only_ + +## 3.7.0 +Mon, 31 Oct 2022 06:26:28 GMT + +_Version update only_ + +## 3.6.0 +Thu, 15 Sep 2022 07:55:20 GMT + +_Version update only_ + +## 3.5.0 +Fri, 10 Jun 2022 18:57:46 GMT + +_Version update only_ + +## 3.4.0 +Thu, 07 Apr 2022 11:56:26 GMT + +### Updates + +- Bump dependencies (#1067) + +## 3.3.1 +Wed, 23 Feb 2022 19:27:40 GMT + +_Version update only_ + +## 3.3.0 +Mon, 31 Jan 2022 15:58:10 GMT + +_Version update only_ + +## 3.2.3 +Tue, 18 Jan 2022 16:23:52 GMT + +### Updates + +- Bump Copyright to 2022 (#1040) + +## 3.2.2 +Fri, 14 Jan 2022 10:17:59 GMT + +_Version update only_ + +## 3.2.1 +Wed, 12 Jan 2022 09:50:29 GMT + +_Version update only_ + +## 3.2.0 +Tue, 11 Jan 2022 12:53:22 GMT + +_Version update only_ + +## 3.1.6 +Tue, 19 Oct 2021 09:17:22 GMT + +### Updates + +- Fix failing build on ARM Macs (#1012) + +## 3.1.5 +Fri, 01 Oct 2021 08:09:21 GMT + +_Version update only_ + +## 3.1.4 +Tue, 21 Sep 2021 14:59:36 GMT + +_Version update only_ + +## 3.1.3 +Mon, 23 Aug 2021 10:13:18 GMT + +_Version update only_ + +## 3.1.2 +Mon, 16 Aug 2021 12:59:59 GMT + +### Updates + +- Update READMEs with correct Node requirements (#994) + +## 3.1.1 +Wed, 04 Aug 2021 10:12:25 GMT + +### Updates + +- Bump tslib to 2.3.0 (#986) +- Bump typescript to 4.3.5 (#987) +- Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988) + +## 3.1.0 +Fri, 14 May 2021 10:45:32 GMT + +_Version update only_ + +## 3.0.3 +Wed, 21 Apr 2021 12:35:06 GMT + +_Version update only_ + +## 3.0.2 +Thu, 15 Apr 2021 21:07:39 GMT + +_Version update only_ + +## 3.0.1 +Wed, 14 Apr 2021 16:30:05 GMT + +### Updates + +- Add peerDependencies to plugins (#950) +- Mark packages as sideEffect: false (#951) +- Add unit tests to plugin track* functions (#954) + +## 3.0.0 +Wed, 31 Mar 2021 14:46:47 GMT + +### Updates + +- Bump rollup to 2.41 (#916) +- Publish UMD versions of plugins to GitHub release (#923) +- Remove module level references to window and document (close #928) +- Ensure browser-tracker API methods catch exceptions (#919) +- Introduce TSDoc comments and extract interfaces where appropriate (#906) +- Bump major version to v3 and update READMEs (#904) +- Improve Core API for module bundlers which support treeshaking (#903) +- Rename @snowplow/browser-core to @snowplow/browser-tracker-core (#901) +- Publish lite version of sp.js (#900) +- Ensure correct 3-Clause BSD License notices are being used (#316) +- Improve API for module bundlers which support treeshaking (#899) +- Bump rush to 5.39 (#895) +- Port to TypeScript (#72) +- Make sp.js build process modular (#450) +- Create @snowplow/browser-tracker package for npm distribution (#541) +- Split auto contexts into plugins (#880) +- Add rush to manage monorepo (#883) +- Add ES Module builds (#882) +- Cleanup deprecated methods (#557) +- Update publishing process for rush (#907) +- Change white and black lists to allow and deny lists (#908) +- Create rush change files for major version 3 release (#909) + diff --git a/plugins/browser-plugin-error-tracking/LICENSE b/plugins/browser-plugin-error-tracking/LICENSE new file mode 100644 index 000000000..76f1946ea --- /dev/null +++ b/plugins/browser-plugin-error-tracking/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/plugins/browser-plugin-error-tracking/README.md b/plugins/browser-plugin-error-tracking/README.md new file mode 100644 index 000000000..de3d0e460 --- /dev/null +++ b/plugins/browser-plugin-error-tracking/README.md @@ -0,0 +1,89 @@ +# Snowplow Error Tracking + +[![npm version][npm-image]][npm-url] +[![License][license-image]](LICENSE) + +Browser Plugin to be used with `@snowplow/browser-tracker`. + +Adds error tracking events to your Snowplow tracking. + +## Maintainer quick start + +Part of the Snowplow JavaScript Tracker monorepo. +Build with [Node.js](https://nodejs.org/en/) (18 - 20) and [Rush](https://rushjs.io/). + +### Setup repository + +```bash +npm install -g @microsoft/rush +git clone https://github.com/snowplow/snowplow-javascript-tracker.git +rush update +``` + +## Package Installation + +With npm: + +```bash +npm install @snowplow/browser-plugin-error-tracking +``` + +## Usage + +Initialize your tracker with the ErrorTrackingPlugin: + +```js +import { newTracker } from '@snowplow/browser-tracker'; +import { ErrorTrackingPlugin } from '@snowplow/browser-plugin-error-tracking'; + +newTracker('sp1', '{{collector}}', { plugins: [ ErrorTrackingPlugin() ] }); // Also stores reference at module level +``` + +Then use the available functions from this package to track to all trackers which have been initialized with this plugin: + +```js +import { enableErrorTracking, trackError } from '@snowplow/browser-plugin-error-tracking'; + +enableErrorTracking(); + +// OR + +enableErrorTracking({ + filter: function (error) { + return true; + }, + contextsAdder: function (error) { + return [ + { + schema: 'iglu:org.schema/WebPage/jsonschema/1-0-0', + data: { + keywords: ['tester'], + }, + }, + ]; + }, +}); + +trackError({ + message: 'Cannot access notExistentProperty()', + filename: 'trackError.js', + lineno: 237, + colno: 5, + error: ex, +}); + +``` + +## Copyright and license + +Licensed and distributed under the [BSD 3-Clause License](LICENSE) ([An OSI Approved License][osi]). + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang. + +All rights reserved. + +[npm-url]: https://www.npmjs.com/package/@snowplow/browser-plugin-error-tracking +[npm-image]: https://img.shields.io/npm/v/@snowplow/browser-plugin-error-tracking +[docs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-tracker/ +[osi]: https://opensource.org/licenses/BSD-3-Clause +[license-image]: https://img.shields.io/npm/l/@snowplow/browser-plugin-error-tracking diff --git a/plugins/browser-plugin-error-tracking/jest.config.js b/plugins/browser-plugin-error-tracking/jest.config.js new file mode 100644 index 000000000..76a179aab --- /dev/null +++ b/plugins/browser-plugin-error-tracking/jest.config.js @@ -0,0 +1,7 @@ +module.exports = { + preset: 'ts-jest', + reporters: ['jest-standard-reporter'], + setupFilesAfterEnv: ['../../setupTestGlobals.ts'], + testEnvironment: 'jest-environment-jsdom-global', + testEnvironmentOptions: { resources: 'usable', runScripts: 'dangerously' }, +}; diff --git a/plugins/browser-plugin-error-tracking/package.json b/plugins/browser-plugin-error-tracking/package.json new file mode 100644 index 000000000..42bf1af57 --- /dev/null +++ b/plugins/browser-plugin-error-tracking/package.json @@ -0,0 +1,54 @@ +{ + "name": "@snowplow/browser-plugin-error-tracking", + "version": "4.10.0", + "description": "Error tracking for Snowplow", + "homepage": "http://bit.ly/sp-js", + "bugs": "https://github.com/snowplow/snowplow-javascript-tracker/issues", + "repository": { + "type": "git", + "url": "https://github.com/snowplow/snowplow-javascript-tracker.git" + }, + "license": "BSD-3-Clause", + "author": "Paul Boocock", + "sideEffects": false, + "main": "./dist/index.umd.js", + "module": "./dist/index.module.js", + "types": "./dist/index.module.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "rollup -c --silent --failAfterWarnings", + "test": "jest" + }, + "dependencies": { + "@snowplow/browser-tracker-core": "workspace:*", + "@snowplow/tracker-core": "workspace:*", + "tslib": "^2.3.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "~21.0.2", + "@rollup/plugin-node-resolve": "~13.1.3", + "@types/jest": "~28.1.1", + "@types/jsdom": "~16.2.14", + "@types/lodash": "~4.14.180", + "@typescript-eslint/eslint-plugin": "~5.15.0", + "@typescript-eslint/parser": "~5.15.0", + "eslint": "~8.11.0", + "jest": "~28.1.3", + "jest-environment-jsdom": "~28.1.3", + "jest-environment-jsdom-global": "~4.0.0", + "jest-standard-reporter": "~2.0.0", + "lodash": "~4.17.21", + "rollup": "~2.70.1", + "rollup-plugin-cleanup": "~3.2.1", + "rollup-plugin-license": "~2.6.1", + "rollup-plugin-terser": "~7.0.2", + "rollup-plugin-ts": "~2.0.5", + "ts-jest": "~28.0.8", + "typescript": "~4.6.2" + }, + "peerDependencies": { + "@snowplow/browser-tracker": "~4.10.0" + } +} diff --git a/plugins/browser-plugin-error-tracking/rollup.config.js b/plugins/browser-plugin-error-tracking/rollup.config.js new file mode 100644 index 000000000..9d4e4080e --- /dev/null +++ b/plugins/browser-plugin-error-tracking/rollup.config.js @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import ts from 'rollup-plugin-ts'; // Prefered over @rollup/plugin-typescript as it bundles .d.ts files +import { banner } from '../../banner'; +import { terser } from 'rollup-plugin-terser'; +import cleanup from 'rollup-plugin-cleanup'; +import pkg from './package.json'; +import { builtinModules } from 'module'; + +const umdPlugins = [nodeResolve({ browser: true }), commonjs(), ts()]; +const umdName = 'snowplowErrorTracking'; + +export default [ + // CommonJS (for Node) and ES module (for bundlers) build. + { + input: './src/index.ts', + plugins: [...umdPlugins, banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main, format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + plugins: [...umdPlugins, terser(), cleanup({ comments: 'none' }), banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main.replace('.js', '.min.js'), format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + external: [...builtinModules, ...Object.keys(pkg.dependencies), ...Object.keys(pkg.devDependencies)], + plugins: [ + ts(), // so Rollup can convert TypeScript to JavaScript + banner(), + ], + output: [{ file: pkg.module, format: 'es', sourcemap: true }], + }, +]; diff --git a/plugins/browser-plugin-error-tracking/src/contexts.ts b/plugins/browser-plugin-error-tracking/src/contexts.ts new file mode 100644 index 000000000..46c82c3fb --- /dev/null +++ b/plugins/browser-plugin-error-tracking/src/contexts.ts @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Schema for a web page context + */ +export interface Gdpr { + /** + * GDPR basis for data collection & processing + */ + basisForProcessing: + | 'consent' + | 'contract' + | 'legal_obligation' + | 'vital_interests' + | 'public_task' + | 'legitimate_interests'; + /** + * ID for document detailing basis for processing + */ + documentId?: string | null; + /** + * Version of document detailing basis for processing + */ + documentVersion?: string | null; + /** + * Description of document detailing basis for processing + */ + documentDescription?: string | null; + [key: string]: unknown; +} diff --git a/plugins/browser-plugin-error-tracking/src/index.ts b/plugins/browser-plugin-error-tracking/src/index.ts new file mode 100644 index 000000000..eb4238587 --- /dev/null +++ b/plugins/browser-plugin-error-tracking/src/index.ts @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { + isFunction, + addEventListener, + BrowserPlugin, + BrowserTracker, + dispatchToTrackersInCollection, +} from '@snowplow/browser-tracker-core'; +import { buildSelfDescribingEvent, CommonEventProperties, SelfDescribingJson } from '@snowplow/tracker-core'; +import { truncateString } from './util'; + +let _trackers: Record = {}; + +export function ErrorTrackingPlugin(): BrowserPlugin { + return { + activateBrowserPlugin: (tracker: BrowserTracker) => { + _trackers[tracker.id] = tracker; + }, + }; +} + +/** + * Event for tracking an error + */ +export interface ErrorEventProperties { + /** The error message */ + message: string; + /** The filename where the error occurred */ + filename?: string; + /** The line number which the error occurred on */ + lineno?: number; + /** The column number which the error occurred on */ + colno?: number; + /** The error object */ + error?: Error; +} + +/** + * Send error as self-describing event + * + * @param event - The event information + * @param trackers - The tracker identifiers which the event will be sent to + */ +export function trackError( + event: ErrorEventProperties & CommonEventProperties, + trackers: Array = Object.keys(_trackers) +) { + const { message, filename, lineno, colno, error, context, timestamp } = event, + stack = error && truncateString(error.stack, 8192), + truncatedMessage = message && truncateString(message, 2048), + truncatedFilename = truncateString(filename, 1024); + + dispatchToTrackersInCollection(trackers, _trackers, (t) => { + t.core.track( + buildSelfDescribingEvent({ + event: { + schema: 'iglu:com.snowplowanalytics.snowplow/application_error/jsonschema/1-0-1', + data: { + programmingLanguage: 'JAVASCRIPT', + message: truncatedMessage ?? 'trackError called without required message', + stackTrace: stack, + lineNumber: lineno, + lineColumn: colno, + fileName: truncatedFilename, + }, + }, + }), + context, + timestamp + ); + }); +} + +/** + * The configuration for automatic error tracking + */ +export interface ErrorTrackingConfiguration { + /** A callback which allows only certain errors to be tracked */ + filter?: (error: ErrorEvent | Event) => boolean; + /** A callback to dynamically add extra context based on the error */ + contextAdder?: (error: ErrorEvent | Event) => Array; + /** Context to be added to every error */ + context?: Array; +} + +/** + * Enable automatic error tracking, added event handler for 'error' event on window + * @param configuration - The error tracking configuration + * @param trackers - The tracker identifiers which the event will be sent to + */ +export function enableErrorTracking( + configuration: ErrorTrackingConfiguration = {}, + trackers: Array = Object.keys(_trackers) +) { + const { filter, contextAdder, context } = configuration, + captureError = (errorEvent: ErrorEvent | Event) => { + if ((filter && isFunction(filter) && filter(errorEvent)) || filter == null) { + sendError({ errorEvent: errorEvent, commonContext: context, contextAdder }, trackers); + } + }; + + addEventListener(window, 'error', captureError, true); +} + +function sendError( + { + errorEvent, + commonContext, + contextAdder, + }: { + errorEvent: ErrorEvent | Event; + commonContext?: Array; + contextAdder?: (error: ErrorEvent | Event) => Array; + }, + trackers: Array +) { + let context = commonContext || []; + if (contextAdder && isFunction(contextAdder)) { + context = context.concat(contextAdder(errorEvent)); + } + + if ('message' in errorEvent) { + trackError( + { + message: errorEvent.message, + filename: errorEvent.filename, + lineno: errorEvent.lineno, + colno: errorEvent.colno, + error: errorEvent.error, + context, + }, + trackers + ); + } else if (errorEvent.target && 'tagName' in errorEvent.target) { + const element: any = errorEvent.target; + trackError( + { + message: `Non-script error on ${element.tagName} element`, + filename: element.src || undefined, + context, + }, + trackers + ); + } else { + trackError( + { + message: "JS Exception. Browser doesn't support ErrorEvent API", + context, + }, + trackers + ); + } +} diff --git a/plugins/browser-plugin-error-tracking/src/util.ts b/plugins/browser-plugin-error-tracking/src/util.ts new file mode 100644 index 000000000..714f5c246 --- /dev/null +++ b/plugins/browser-plugin-error-tracking/src/util.ts @@ -0,0 +1,15 @@ +/** + * Truncate string if it's longer than 8192 chars + * + * @param string - The stack trace to truncate + * @param maxLength - The maximum length of the truncated string. Default = 8192 + * @returns The truncated string + */ +export function truncateString(string?: string, maxLength: number = 8192): string | undefined { + if (string && string.length > maxLength) { + const truncatedString = string.substring(0, maxLength); + return truncatedString; + } + + return string; +} diff --git a/plugins/browser-plugin-error-tracking/test/events.test.ts b/plugins/browser-plugin-error-tracking/test/events.test.ts new file mode 100644 index 000000000..2d2b0d0f4 --- /dev/null +++ b/plugins/browser-plugin-error-tracking/test/events.test.ts @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { addTracker, SharedState } from '@snowplow/browser-tracker-core'; +import F from 'lodash/fp'; +import { ErrorTrackingPlugin, enableErrorTracking, trackError } from '../src'; +import { newInMemoryEventStore } from '@snowplow/tracker-core'; + +const getUEEvents = F.compose(F.filter(F.compose(F.eq('ue'), F.get('e')))); +const extractEventProperties = F.map(F.compose(F.get('data'), (cx: string) => JSON.parse(cx), F.get('ue_pr'))); +const extractUeEvent = (schema: string) => { + return { + from: F.compose( + F.first, + F.filter(F.compose(F.eq(schema), F.get('schema'))), + F.flatten, + extractEventProperties, + getUEEvents + ), + }; +}; + +describe('ErrorTrackingPlugin', () => { + const eventStore1 = newInMemoryEventStore({}); + const eventStore2 = newInMemoryEventStore({}); + const eventStore3 = newInMemoryEventStore({}); + const eventStore4 = newInMemoryEventStore({}); + const eventStore5 = newInMemoryEventStore({}); + const eventStore6 = newInMemoryEventStore({}); + + const state = new SharedState(); + addTracker('sp1', 'sp1', 'js-3.0.0', '', state, { + encodeBase64: false, + plugins: [ErrorTrackingPlugin()], + eventStore: eventStore1, + customFetch: async () => new Response(null, { status: 500 }), + }); + addTracker('sp2', 'sp2', 'js-3.0.0', '', state, { + encodeBase64: false, + plugins: [ErrorTrackingPlugin()], + eventStore: eventStore2, + customFetch: async () => new Response(null, { status: 500 }), + }); + addTracker('sp3', 'sp3', 'js-3.0.0', '', state, { + encodeBase64: false, + plugins: [ErrorTrackingPlugin()], + eventStore: eventStore3, + customFetch: async () => new Response(null, { status: 500 }), + }); + addTracker('sp4', 'sp4', 'js-3.0.0', '', state, { + encodeBase64: false, + plugins: [ErrorTrackingPlugin()], + eventStore: eventStore4, + customFetch: async () => new Response(null, { status: 500 }), + }); + addTracker('sp5', 'sp5', 'js-3.0.0', '', state, { + encodeBase64: false, + plugins: [ErrorTrackingPlugin()], + eventStore: eventStore5, + customFetch: async () => new Response(null, { status: 500 }), + }); + addTracker('sp6', 'sp6', 'js-3.0.0', '', state, { + encodeBase64: false, + plugins: [ErrorTrackingPlugin()], + eventStore: eventStore6, + customFetch: async () => new Response(null, { status: 500 }), + }); + + const error = new Error('this is an error'); + error.stack = 'stacktrace-1'; + + const oversizedError = new Error('this is a longer error'); + oversizedError.stack = 'x'.repeat(10000); + const oversizedMessage = 'y'.repeat(10000); + const oversizedFilename = 'z'.repeat(2000); + + trackError( + { + message: 'message-1', + colno: 1, + lineno: 10, + filename: 'index.js', + error: error, + }, + ['sp1'] + ); + + trackError( + { + message: '', + }, + ['sp2'] + ); + + trackError( + { + message: undefined, + }, + ['sp3'] + ); + + trackError( + { + message: oversizedMessage, + error: oversizedError, + }, + ['sp4'] + ); + + trackError( + { + message: 'message-6', + filename: oversizedFilename, + }, + ['sp6'] + ); + + enableErrorTracking({}, ['sp5']); + + it('trackError adds the expected application error event to the queue', async () => { + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/application_error/jsonschema/1-0-1').from( + await eventStore1.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/application_error/jsonschema/1-0-1', + data: { + programmingLanguage: 'JAVASCRIPT', + message: 'message-1', + stackTrace: 'stacktrace-1', + lineNumber: 10, + lineColumn: 1, + fileName: 'index.js', + }, + }); + }); + + it('trackError accepts empty error messages', async () => { + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/application_error/jsonschema/1-0-1').from( + await eventStore2.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/application_error/jsonschema/1-0-1', + data: { + message: '', + }, + }); + }); + + it('trackError replaces undefined messages with placeholder', async () => { + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/application_error/jsonschema/1-0-1').from( + await eventStore3.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/application_error/jsonschema/1-0-1', + data: { + message: 'trackError called without required message', + }, + }); + }); + + it('trackError truncates long message and stack traces', async () => { + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/application_error/jsonschema/1-0-1').from( + await eventStore4.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/application_error/jsonschema/1-0-1', + data: { + message: 'y'.repeat(2048), + stackTrace: 'x'.repeat(8192), + }, + }); + }); + + it('trackError truncates long fileName to 1024 characters', async () => { + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/application_error/jsonschema/1-0-1').from( + await eventStore6.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/application_error/jsonschema/1-0-1', + data: { + fileName: 'z'.repeat(1024), + }, + }); + }); + + it('trackError should be called by listener for resource errors', async () => { + const resourceUrl = '/fake-should-404.js'; + + await new Promise((resolve) => { + const resource = document.createElement('script'); + resource.onerror = resolve; + resource.src = resourceUrl; + document.head.appendChild(resource); + }); + + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/application_error/jsonschema/1-0-1').from( + await eventStore5.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/application_error/jsonschema/1-0-1', + data: { + message: 'Non-script error on SCRIPT element', + fileName: 'http://localhost' + resourceUrl, + }, + }); + }); +}); diff --git a/plugins/browser-plugin-error-tracking/tsconfig.json b/plugins/browser-plugin-error-tracking/tsconfig.json new file mode 100644 index 000000000..4082f16a5 --- /dev/null +++ b/plugins/browser-plugin-error-tracking/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +} diff --git a/plugins/browser-plugin-event-specifications/CHANGELOG.json b/plugins/browser-plugin-event-specifications/CHANGELOG.json new file mode 100644 index 000000000..15a948ef1 --- /dev/null +++ b/plugins/browser-plugin-event-specifications/CHANGELOG.json @@ -0,0 +1,251 @@ +{ + "name": "@snowplow/browser-plugin-event-specifications", + "entries": [ + { + "version": "4.10.0", + "tag": "@snowplow/browser-plugin-event-specifications_v4.10.0", + "date": "Mon, 27 Jul 2026 13:52:14 GMT", + "comments": {} + }, + { + "version": "4.9.0", + "tag": "@snowplow/browser-plugin-event-specifications_v4.9.0", + "date": "Tue, 21 Jul 2026 14:53:08 GMT", + "comments": {} + }, + { + "version": "4.8.4", + "tag": "@snowplow/browser-plugin-event-specifications_v4.8.4", + "date": "Thu, 02 Jul 2026 10:07:52 GMT", + "comments": {} + }, + { + "version": "4.8.3", + "tag": "@snowplow/browser-plugin-event-specifications_v4.8.3", + "date": "Tue, 30 Jun 2026 14:22:03 GMT", + "comments": { + "none": [ + { + "comment": "Update uuid to v11 and remove closure-compiler from the build pipeline" + } + ] + } + }, + { + "version": "4.8.2", + "tag": "@snowplow/browser-plugin-event-specifications_v4.8.2", + "date": "Wed, 17 Jun 2026 12:30:12 GMT", + "comments": {} + }, + { + "version": "4.8.1", + "tag": "@snowplow/browser-plugin-event-specifications_v4.8.1", + "date": "Wed, 13 May 2026 09:26:05 GMT", + "comments": {} + }, + { + "version": "4.8.0", + "tag": "@snowplow/browser-plugin-event-specifications_v4.8.0", + "date": "Tue, 28 Apr 2026 07:56:22 GMT", + "comments": {} + }, + { + "version": "4.7.0", + "tag": "@snowplow/browser-plugin-event-specifications_v4.7.0", + "date": "Wed, 01 Apr 2026 12:59:29 GMT", + "comments": {} + }, + { + "version": "4.6.9", + "tag": "@snowplow/browser-plugin-event-specifications_v4.6.9", + "date": "Mon, 16 Mar 2026 15:43:06 GMT", + "comments": {} + }, + { + "version": "4.6.8", + "tag": "@snowplow/browser-plugin-event-specifications_v4.6.8", + "date": "Tue, 28 Oct 2025 09:46:42 GMT", + "comments": {} + }, + { + "version": "4.6.7", + "tag": "@snowplow/browser-plugin-event-specifications_v4.6.7", + "date": "Tue, 07 Oct 2025 14:53:36 GMT", + "comments": {} + }, + { + "version": "4.6.6", + "tag": "@snowplow/browser-plugin-event-specifications_v4.6.6", + "date": "Tue, 26 Aug 2025 08:42:27 GMT", + "comments": {} + }, + { + "version": "4.6.5", + "tag": "@snowplow/browser-plugin-event-specifications_v4.6.5", + "date": "Wed, 25 Jun 2025 21:16:46 GMT", + "comments": {} + }, + { + "version": "4.6.4", + "tag": "@snowplow/browser-plugin-event-specifications_v4.6.4", + "date": "Wed, 25 Jun 2025 12:08:50 GMT", + "comments": {} + }, + { + "version": "4.6.3", + "tag": "@snowplow/browser-plugin-event-specifications_v4.6.3", + "date": "Thu, 29 May 2025 19:52:07 GMT", + "comments": {} + }, + { + "version": "4.6.2", + "tag": "@snowplow/browser-plugin-event-specifications_v4.6.2", + "date": "Tue, 20 May 2025 07:39:05 GMT", + "comments": {} + }, + { + "version": "4.6.1", + "tag": "@snowplow/browser-plugin-event-specifications_v4.6.1", + "date": "Tue, 06 May 2025 13:10:51 GMT", + "comments": {} + }, + { + "version": "4.6.0", + "tag": "@snowplow/browser-plugin-event-specifications_v4.6.0", + "date": "Thu, 01 May 2025 09:58:59 GMT", + "comments": {} + }, + { + "version": "4.5.0", + "tag": "@snowplow/browser-plugin-event-specifications_v4.5.0", + "date": "Fri, 04 Apr 2025 09:21:23 GMT", + "comments": {} + }, + { + "version": "4.4.0", + "tag": "@snowplow/browser-plugin-event-specifications_v4.4.0", + "date": "Thu, 20 Mar 2025 12:14:34 GMT", + "comments": {} + }, + { + "version": "4.3.1", + "tag": "@snowplow/browser-plugin-event-specifications_v4.3.1", + "date": "Tue, 21 Jan 2025 11:09:42 GMT", + "comments": {} + }, + { + "version": "4.3.0", + "tag": "@snowplow/browser-plugin-event-specifications_v4.3.0", + "date": "Mon, 20 Jan 2025 11:45:13 GMT", + "comments": {} + }, + { + "version": "4.2.0", + "tag": "@snowplow/browser-plugin-event-specifications_v4.2.0", + "date": "Mon, 13 Jan 2025 08:30:05 GMT", + "comments": {} + }, + { + "version": "4.1.0", + "tag": "@snowplow/browser-plugin-event-specifications_v4.1.0", + "date": "Thu, 28 Nov 2024 10:57:30 GMT", + "comments": {} + }, + { + "version": "4.0.4", + "tag": "@snowplow/browser-plugin-event-specifications_v4.0.4", + "date": "Thu, 21 Nov 2024 09:06:36 GMT", + "comments": {} + }, + { + "version": "4.0.3", + "tag": "@snowplow/browser-plugin-event-specifications_v4.0.3", + "date": "Wed, 20 Nov 2024 09:30:31 GMT", + "comments": {} + }, + { + "version": "4.0.2", + "tag": "@snowplow/browser-plugin-event-specifications_v4.0.2", + "date": "Mon, 11 Nov 2024 15:46:34 GMT", + "comments": {} + }, + { + "version": "4.0.1", + "tag": "@snowplow/browser-plugin-event-specifications_v4.0.1", + "date": "Fri, 01 Nov 2024 10:35:07 GMT", + "comments": {} + }, + { + "version": "4.0.0", + "tag": "@snowplow/browser-plugin-event-specifications_v4.0.0", + "date": "Mon, 28 Oct 2024 11:48:53 GMT", + "comments": {} + }, + { + "version": "3.24.6", + "tag": "@snowplow/browser-plugin-event-specifications_v3.24.6", + "date": "Mon, 28 Oct 2024 10:23:28 GMT", + "comments": {} + }, + { + "version": "3.24.5", + "tag": "@snowplow/browser-plugin-event-specifications_v3.24.5", + "date": "Fri, 25 Oct 2024 08:53:04 GMT", + "comments": {} + }, + { + "version": "3.24.4", + "tag": "@snowplow/browser-plugin-event-specifications_v3.24.4", + "date": "Thu, 26 Sep 2024 06:10:22 GMT", + "comments": {} + }, + { + "version": "3.24.3", + "tag": "@snowplow/browser-plugin-event-specifications_v3.24.3", + "date": "Tue, 03 Sep 2024 08:15:14 GMT", + "comments": { + "none": [ + { + "comment": "Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush" + } + ] + } + }, + { + "version": "3.24.2", + "tag": "@snowplow/browser-plugin-event-specifications_v3.24.2", + "date": "Wed, 24 Jul 2024 08:59:00 GMT", + "comments": {} + }, + { + "version": "3.24.1", + "tag": "@snowplow/browser-plugin-event-specifications_v3.24.1", + "date": "Tue, 02 Jul 2024 07:08:17 GMT", + "comments": {} + }, + { + "version": "3.24.0", + "tag": "@snowplow/browser-plugin-event-specifications_v3.24.0", + "date": "Tue, 25 Jun 2024 08:31:05 GMT", + "comments": {} + }, + { + "version": "3.23.1", + "tag": "@snowplow/browser-plugin-event-specifications_v3.23.1", + "date": "Tue, 04 Jun 2024 13:34:45 GMT", + "comments": {} + }, + { + "version": "3.23.0", + "tag": "@snowplow/browser-plugin-event-specifications_v3.23.0", + "date": "Thu, 28 Mar 2024 11:28:45 GMT", + "comments": { + "none": [ + { + "comment": "Created" + } + ] + } + } + ] +} diff --git a/plugins/browser-plugin-event-specifications/CHANGELOG.md b/plugins/browser-plugin-event-specifications/CHANGELOG.md new file mode 100644 index 000000000..275ced3d8 --- /dev/null +++ b/plugins/browser-plugin-event-specifications/CHANGELOG.md @@ -0,0 +1,200 @@ +# Change Log - @snowplow/browser-plugin-event-specifications + +This log was last generated on Mon, 27 Jul 2026 13:52:14 GMT and should not be manually modified. + +## 4.10.0 +Mon, 27 Jul 2026 13:52:14 GMT + +_Version update only_ + +## 4.9.0 +Tue, 21 Jul 2026 14:53:08 GMT + +_Version update only_ + +## 4.8.4 +Thu, 02 Jul 2026 10:07:52 GMT + +_Version update only_ + +## 4.8.3 +Tue, 30 Jun 2026 14:22:03 GMT + +### Updates + +- Update uuid to v11 and remove closure-compiler from the build pipeline + +## 4.8.2 +Wed, 17 Jun 2026 12:30:12 GMT + +_Version update only_ + +## 4.8.1 +Wed, 13 May 2026 09:26:05 GMT + +_Version update only_ + +## 4.8.0 +Tue, 28 Apr 2026 07:56:22 GMT + +_Version update only_ + +## 4.7.0 +Wed, 01 Apr 2026 12:59:29 GMT + +_Version update only_ + +## 4.6.9 +Mon, 16 Mar 2026 15:43:06 GMT + +_Version update only_ + +## 4.6.8 +Tue, 28 Oct 2025 09:46:42 GMT + +_Version update only_ + +## 4.6.7 +Tue, 07 Oct 2025 14:53:36 GMT + +_Version update only_ + +## 4.6.6 +Tue, 26 Aug 2025 08:42:27 GMT + +_Version update only_ + +## 4.6.5 +Wed, 25 Jun 2025 21:16:46 GMT + +_Version update only_ + +## 4.6.4 +Wed, 25 Jun 2025 12:08:50 GMT + +_Version update only_ + +## 4.6.3 +Thu, 29 May 2025 19:52:07 GMT + +_Version update only_ + +## 4.6.2 +Tue, 20 May 2025 07:39:05 GMT + +_Version update only_ + +## 4.6.1 +Tue, 06 May 2025 13:10:51 GMT + +_Version update only_ + +## 4.6.0 +Thu, 01 May 2025 09:58:59 GMT + +_Version update only_ + +## 4.5.0 +Fri, 04 Apr 2025 09:21:23 GMT + +_Version update only_ + +## 4.4.0 +Thu, 20 Mar 2025 12:14:34 GMT + +_Version update only_ + +## 4.3.1 +Tue, 21 Jan 2025 11:09:42 GMT + +_Version update only_ + +## 4.3.0 +Mon, 20 Jan 2025 11:45:13 GMT + +_Version update only_ + +## 4.2.0 +Mon, 13 Jan 2025 08:30:05 GMT + +_Version update only_ + +## 4.1.0 +Thu, 28 Nov 2024 10:57:30 GMT + +_Version update only_ + +## 4.0.4 +Thu, 21 Nov 2024 09:06:36 GMT + +_Version update only_ + +## 4.0.3 +Wed, 20 Nov 2024 09:30:31 GMT + +_Version update only_ + +## 4.0.2 +Mon, 11 Nov 2024 15:46:34 GMT + +_Version update only_ + +## 4.0.1 +Fri, 01 Nov 2024 10:35:07 GMT + +_Version update only_ + +## 4.0.0 +Mon, 28 Oct 2024 11:48:53 GMT + +_Version update only_ + +## 3.24.6 +Mon, 28 Oct 2024 10:23:28 GMT + +_Version update only_ + +## 3.24.5 +Fri, 25 Oct 2024 08:53:04 GMT + +_Version update only_ + +## 3.24.4 +Thu, 26 Sep 2024 06:10:22 GMT + +_Version update only_ + +## 3.24.3 +Tue, 03 Sep 2024 08:15:14 GMT + +### Updates + +- Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush + +## 3.24.2 +Wed, 24 Jul 2024 08:59:00 GMT + +_Version update only_ + +## 3.24.1 +Tue, 02 Jul 2024 07:08:17 GMT + +_Version update only_ + +## 3.24.0 +Tue, 25 Jun 2024 08:31:05 GMT + +_Version update only_ + +## 3.23.1 +Tue, 04 Jun 2024 13:34:45 GMT + +_Version update only_ + +## 3.23.0 +Thu, 28 Mar 2024 11:28:45 GMT + +### Updates + +- Created + diff --git a/plugins/browser-plugin-event-specifications/LICENSE b/plugins/browser-plugin-event-specifications/LICENSE new file mode 100644 index 000000000..48c0a11e4 --- /dev/null +++ b/plugins/browser-plugin-event-specifications/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2024 Snowplow Analytics Ltd +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/plugins/browser-plugin-event-specifications/README.md b/plugins/browser-plugin-event-specifications/README.md new file mode 100644 index 000000000..8f428c430 --- /dev/null +++ b/plugins/browser-plugin-event-specifications/README.md @@ -0,0 +1,89 @@ +# Snowplow Event Specifications Plugin + +[![npm version][npm-image]][npm-url] +[![License][license-image]](LICENSE) + +Browser Plugin to be used with `@snowplow/browser-tracker`. + +The plugin allows you to integrate with Event Specifications for a selected set of plugins. The plugin will automatically add an Event Specification context to the events matching the configuration added on the plugin. This configuration should be retrieved directly from your Data Product in the [Snowplow BDP Console](https://console.snowplowanalytics.com). + +## Maintainer quick start + +Part of the Snowplow JavaScript Tracker monorepo. +Build with [Node.js](https://nodejs.org/en/) (18 - 20) and [Rush](https://rushjs.io/). + +### Setup repository + +```bash +npm install -g @microsoft/rush +git clone https://github.com/snowplow/snowplow-javascript-tracker.git +rush update +``` + +## Package Installation + +With npm: + +```bash +npm install @snowplow/browser-plugin-event-specifications +``` + +## Usage + +Initialize your tracker with the `EventSpecificationsPlugin`: + +```js +import { newTracker } from '@snowplow/browser-tracker'; +import { EventSpecificationsPlugin } from '@snowplow/browser-plugin-event-specifications'; + +newTracker('sp1', '{{collector}}', { plugins: [ EventSpecificationsPlugin(/* pluginOptions */) ] }); + +/* + * Available plugin options `EventSpecificationsPluginOptions`: + * { + * [k in AvailablePlugins]: Keys for available plugins that have been added as integrations. + * } + */ +``` + +### Getting the expected Event Specification options input + +The expected Event Specification option input can be retrieved directly from your Data Product in the [Snowplow BDP Console](https://console.snowplowanalytics.com) and would be similar to the following example: + +```js +EventSpecificationsPlugin( + SnowplowMediaPlugin: { play_event: 'event_specification_id' } +); +``` + +### Adding a new integration + +Every integration needs to satisfy the following interface: + +```ts +export type Integration = { + /** + * Find a matching event for the integration with a plugin and an event specification id map. + * The returned string should match what we expect as key coming from the configuration object on this specific plugin integration. + */ + detectMatchingEvent: (payloadBuilder: PayloadBuilder) => string | undefined +} +``` + +The `detectMatchingEvent` function should return the key expected for the Event Specification input option of the integration. + +To add a new integration, add the required code under `src/integrations` and export it accordingly on the `integrations` object on the `src/integrations/index.ts` file. + +## Copyright and license + +Licensed and distributed under the [BSD 3-Clause License](LICENSE) ([An OSI Approved License][osi]). + +Copyright (c) 2024 Snowplow Analytics Ltd. + +All rights reserved. + +[npm-url]: https://www.npmjs.com/package/@snowplow/browser-plugin-event-specifications +[npm-image]: https://img.shields.io/npm/v/@snowplow/browser-plugin-event-specifications +[docs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-tracker/ +[osi]: https://opensource.org/licenses/BSD-3-Clause +[license-image]: https://img.shields.io/npm/l/@snowplow/browser-plugin-event-specifications diff --git a/plugins/browser-plugin-event-specifications/jest.config.js b/plugins/browser-plugin-event-specifications/jest.config.js new file mode 100644 index 000000000..87d15da9b --- /dev/null +++ b/plugins/browser-plugin-event-specifications/jest.config.js @@ -0,0 +1,6 @@ +module.exports = { + preset: 'ts-jest', + reporters: ['jest-standard-reporter'], + setupFilesAfterEnv: ['../../setupTestGlobals.ts'], + testEnvironment: 'jest-environment-jsdom-global', +}; diff --git a/plugins/browser-plugin-event-specifications/package.json b/plugins/browser-plugin-event-specifications/package.json new file mode 100644 index 000000000..a07e56bfe --- /dev/null +++ b/plugins/browser-plugin-event-specifications/package.json @@ -0,0 +1,52 @@ +{ + "name": "@snowplow/browser-plugin-event-specifications", + "version": "4.10.0", + "description": "Automatically adds Event Specifications context to event specifications of a Data Product template.", + "homepage": "https://github.com/snowplow/snowplow-javascript-tracker", + "bugs": "https://github.com/snowplow/snowplow-javascript-tracker/issues", + "repository": { + "type": "git", + "url": "https://github.com/snowplow/snowplow-javascript-tracker.git" + }, + "license": "BSD-3-Clause", + "author": "Snowplow Analytics Ltd (https://snowplow.io/)", + "sideEffects": false, + "main": "./dist/index.umd.js", + "module": "./dist/index.module.js", + "types": "./dist/index.module.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "rollup -c --silent --failAfterWarnings", + "test": "jest" + }, + "dependencies": { + "@snowplow/browser-tracker-core": "workspace:*", + "@snowplow/tracker-core": "workspace:*", + "tslib": "^2.3.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "~21.0.2", + "@rollup/plugin-node-resolve": "~13.1.3", + "@types/jest": "~28.1.1", + "@types/jsdom": "~16.2.14", + "@typescript-eslint/eslint-plugin": "~5.15.0", + "@typescript-eslint/parser": "~5.15.0", + "eslint": "~8.11.0", + "jest": "~28.1.3", + "jest-environment-jsdom": "~28.1.3", + "jest-environment-jsdom-global": "~4.0.0", + "jest-standard-reporter": "~2.0.0", + "rollup": "~2.70.1", + "rollup-plugin-cleanup": "~3.2.1", + "rollup-plugin-license": "~2.6.1", + "rollup-plugin-terser": "~7.0.2", + "rollup-plugin-ts": "~2.0.5", + "ts-jest": "~28.0.8", + "typescript": "~4.6.2" + }, + "peerDependencies": { + "@snowplow/browser-tracker": "~4.10.0" + } +} diff --git a/plugins/browser-plugin-event-specifications/rollup.config.js b/plugins/browser-plugin-event-specifications/rollup.config.js new file mode 100644 index 000000000..2fdaec972 --- /dev/null +++ b/plugins/browser-plugin-event-specifications/rollup.config.js @@ -0,0 +1,36 @@ +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import ts from 'rollup-plugin-ts'; // Preferred over @rollup/plugin-typescript as it bundles .d.ts files +import { banner } from '../../banner'; +import { terser } from 'rollup-plugin-terser'; +import cleanup from 'rollup-plugin-cleanup'; +import pkg from './package.json'; +import { builtinModules } from 'module'; + +const umdPlugins = [nodeResolve({ browser: true }), commonjs(), ts()]; +const umdName = 'eventSpecifications'; + +export default [ + // CommonJS (for Node) and ES module (for bundlers) build. + { + input: './src/index.ts', + plugins: [...umdPlugins, banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main, format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + plugins: [...umdPlugins, terser(), cleanup({ comments: 'none' }), banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main.replace('.js', '.min.js'), format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + external: [...builtinModules, ...Object.keys(pkg.dependencies), ...Object.keys(pkg.devDependencies)], + plugins: [ + ts(), // so Rollup can convert TypeScript to JavaScript + banner(), + ], + output: [{ file: pkg.module, format: 'es', sourcemap: true }], + }, +]; diff --git a/plugins/browser-plugin-event-specifications/src/index.ts b/plugins/browser-plugin-event-specifications/src/index.ts new file mode 100644 index 000000000..47f5efb75 --- /dev/null +++ b/plugins/browser-plugin-event-specifications/src/index.ts @@ -0,0 +1,41 @@ +import { BrowserPlugin, BrowserTracker } from '@snowplow/browser-tracker-core'; +import { integrations, AvailablePlugins } from './integrations'; +import { createEventSpecificationContext } from './utils'; + +const _trackers: Record = {}; + +type EventSpecificationsPluginOptions = { + [k in AvailablePlugins]?: Record; +}; + +const defaultPluginOptions = {}; + +export function EventSpecificationsPlugin( + pluginOptions: EventSpecificationsPluginOptions = defaultPluginOptions +): BrowserPlugin { + const options = { ...defaultPluginOptions, ...pluginOptions }; + const enabledIntegrations = Object.keys(integrations).filter( + (integration) => options[integration as AvailablePlugins] + ); + let trackerId: string; + return { + activateBrowserPlugin: (tracker) => { + trackerId = tracker.id; + _trackers[trackerId] = tracker; + }, + beforeTrack(payloadBuilder) { + enabledIntegrations.forEach((integrationKey) => { + const matchedEvent = integrations[integrationKey as AvailablePlugins].detectMatchingEvent(payloadBuilder); + if (!matchedEvent) { + return; + } + const matchingPluginEventMap = options[integrationKey as AvailablePlugins]; + const matchingEventSpecificationId = matchingPluginEventMap && matchingPluginEventMap[matchedEvent]; + if (!matchingEventSpecificationId) { + return; + } + payloadBuilder.addContextEntity(createEventSpecificationContext(matchingEventSpecificationId)); + }); + }, + }; +} diff --git a/plugins/browser-plugin-event-specifications/src/integrations/index.ts b/plugins/browser-plugin-event-specifications/src/integrations/index.ts new file mode 100644 index 000000000..641fdb815 --- /dev/null +++ b/plugins/browser-plugin-event-specifications/src/integrations/index.ts @@ -0,0 +1,16 @@ +import { PayloadBuilder } from '@snowplow/tracker-core'; +import { snowplowMediaPluginIntegration } from './snowplow-media-plugin'; + +export type AvailablePlugins = 'SnowplowMediaPlugin'; + +export type Integration = { + /** + * Find a matching event for the integration with a plugin and an event specification id map. + * The returned string should match what we expect as key coming from the configuration object on this specific plugin integration. + */ + detectMatchingEvent: (payloadBuilder: PayloadBuilder) => string | undefined; +}; + +export const integrations: Record = { + SnowplowMediaPlugin: snowplowMediaPluginIntegration, +} as const; diff --git a/plugins/browser-plugin-event-specifications/src/integrations/snowplow-media-plugin.ts b/plugins/browser-plugin-event-specifications/src/integrations/snowplow-media-plugin.ts new file mode 100644 index 000000000..aa3c7210f --- /dev/null +++ b/plugins/browser-plugin-event-specifications/src/integrations/snowplow-media-plugin.ts @@ -0,0 +1,26 @@ +import { PayloadBuilder } from '@snowplow/tracker-core'; +import { Integration } from './index'; + +export const snowplowMediaPluginIntegration: Integration = { + detectMatchingEvent(payloadBuilder) { + return getMediaEventSchemaName(payloadBuilder); + }, +}; + +function getMediaEventSchemaName(payloadBuilder: PayloadBuilder): string | undefined { + const payloadJson = payloadBuilder.getJson(); + const mediaEventSchema = payloadJson.find( + (e) => + e.keyIfEncoded === 'ue_px' && + (e.json.data as { schema: string }).schema.match(/iglu:com.snowplowanalytics.snowplow.media\/.*\/jsonschema/) + ); + if (typeof mediaEventSchema === 'undefined') { + return; + } + // We know schemas are in this otherwise it would not match the above regex. + const eventSourceName = (mediaEventSchema.json.data as { schema: string }).schema.match( + /iglu:com.snowplowanalytics.snowplow.media\/(.*)\/jsonschema/ + )![1]; + + return eventSourceName; +} diff --git a/plugins/browser-plugin-event-specifications/src/schemata.ts b/plugins/browser-plugin-event-specifications/src/schemata.ts new file mode 100644 index 000000000..158e9cc10 --- /dev/null +++ b/plugins/browser-plugin-event-specifications/src/schemata.ts @@ -0,0 +1 @@ +export const EVENT_SPECIFICATION_SCHEMA = 'iglu:com.snowplowanalytics.snowplow/event_specification/jsonschema/1-0-0'; diff --git a/plugins/browser-plugin-event-specifications/src/utils.ts b/plugins/browser-plugin-event-specifications/src/utils.ts new file mode 100644 index 000000000..0cce4ab86 --- /dev/null +++ b/plugins/browser-plugin-event-specifications/src/utils.ts @@ -0,0 +1,10 @@ +import { EVENT_SPECIFICATION_SCHEMA } from './schemata'; + +export function createEventSpecificationContext(eventSpecificationId: string) { + return { + schema: EVENT_SPECIFICATION_SCHEMA, + data: { + id: eventSpecificationId, + }, + }; +} diff --git a/plugins/browser-plugin-event-specifications/test/event-specs.test.ts b/plugins/browser-plugin-event-specifications/test/event-specs.test.ts new file mode 100644 index 000000000..24bddcf42 --- /dev/null +++ b/plugins/browser-plugin-event-specifications/test/event-specs.test.ts @@ -0,0 +1,67 @@ +import { buildSelfDescribingEvent, trackerCore } from '@snowplow/tracker-core'; +import { EventSpecificationsPlugin } from '../src'; +import { BrowserTracker } from '@snowplow/browser-tracker-core'; + +describe('Event Specifications plugin', () => { + it('Detects matching event and adds context', (done) => { + const playEventSpecificationId = '1234'; + const eventSpecsPlugin = EventSpecificationsPlugin({ + SnowplowMediaPlugin: { play_event: playEventSpecificationId }, + }); + const core = trackerCore({ + base64: false, + corePlugins: [ + eventSpecsPlugin, + { + afterTrack(payload) { + let context = JSON.parse(payload.co as string); + expect(context.data[0].schema).toMatch( + 'iglu:com.snowplowanalytics.snowplow/event_specification/jsonschema/1-0-0' + ); + expect(context.data[0].data).toEqual({ id: playEventSpecificationId }); + done(); + }, + }, + ], + }); + + eventSpecsPlugin.activateBrowserPlugin?.({ core } as BrowserTracker); + core.track( + buildSelfDescribingEvent({ + event: { + schema: 'iglu:com.snowplowanalytics.snowplow.media/play_event/jsonschema/1-0-0', + data: {}, + }, + }) + ); + }); + + it('Does not add context on non-matching event', (done) => { + const eventSpecsPlugin = EventSpecificationsPlugin({ + SnowplowMediaPlugin: { pause_event: '1234' }, + }); + const core = trackerCore({ + base64: false, + corePlugins: [ + eventSpecsPlugin, + { + afterTrack(payload) { + const context = payload.co as string; + expect(context).toBe(undefined); + done(); + }, + }, + ], + }); + + eventSpecsPlugin.activateBrowserPlugin?.({ core } as BrowserTracker); + core.track( + buildSelfDescribingEvent({ + event: { + schema: 'iglu:com.snowplowanalytics.snowplow.media/play_event/jsonschema/1-0-0', + data: {}, + }, + }) + ); + }); +}); diff --git a/plugins/browser-plugin-event-specifications/tsconfig.json b/plugins/browser-plugin-event-specifications/tsconfig.json new file mode 100644 index 000000000..4082f16a5 --- /dev/null +++ b/plugins/browser-plugin-event-specifications/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +} diff --git a/plugins/browser-plugin-focalmeter/CHANGELOG.json b/plugins/browser-plugin-focalmeter/CHANGELOG.json new file mode 100644 index 000000000..6997bd19b --- /dev/null +++ b/plugins/browser-plugin-focalmeter/CHANGELOG.json @@ -0,0 +1,299 @@ +{ + "name": "@snowplow/browser-plugin-focalmeter", + "entries": [ + { + "version": "4.10.0", + "tag": "@snowplow/browser-plugin-focalmeter_v4.10.0", + "date": "Mon, 27 Jul 2026 13:52:14 GMT", + "comments": {} + }, + { + "version": "4.9.0", + "tag": "@snowplow/browser-plugin-focalmeter_v4.9.0", + "date": "Tue, 21 Jul 2026 14:53:08 GMT", + "comments": {} + }, + { + "version": "4.8.4", + "tag": "@snowplow/browser-plugin-focalmeter_v4.8.4", + "date": "Thu, 02 Jul 2026 10:07:52 GMT", + "comments": {} + }, + { + "version": "4.8.3", + "tag": "@snowplow/browser-plugin-focalmeter_v4.8.3", + "date": "Tue, 30 Jun 2026 14:22:03 GMT", + "comments": { + "none": [ + { + "comment": "Update uuid to v11 and remove closure-compiler from the build pipeline" + } + ] + } + }, + { + "version": "4.8.2", + "tag": "@snowplow/browser-plugin-focalmeter_v4.8.2", + "date": "Wed, 17 Jun 2026 12:30:12 GMT", + "comments": {} + }, + { + "version": "4.8.1", + "tag": "@snowplow/browser-plugin-focalmeter_v4.8.1", + "date": "Wed, 13 May 2026 09:26:05 GMT", + "comments": {} + }, + { + "version": "4.8.0", + "tag": "@snowplow/browser-plugin-focalmeter_v4.8.0", + "date": "Tue, 28 Apr 2026 07:56:22 GMT", + "comments": {} + }, + { + "version": "4.7.0", + "tag": "@snowplow/browser-plugin-focalmeter_v4.7.0", + "date": "Wed, 01 Apr 2026 12:59:29 GMT", + "comments": {} + }, + { + "version": "4.6.9", + "tag": "@snowplow/browser-plugin-focalmeter_v4.6.9", + "date": "Mon, 16 Mar 2026 15:43:06 GMT", + "comments": {} + }, + { + "version": "4.6.8", + "tag": "@snowplow/browser-plugin-focalmeter_v4.6.8", + "date": "Tue, 28 Oct 2025 09:46:42 GMT", + "comments": {} + }, + { + "version": "4.6.7", + "tag": "@snowplow/browser-plugin-focalmeter_v4.6.7", + "date": "Tue, 07 Oct 2025 14:53:36 GMT", + "comments": {} + }, + { + "version": "4.6.6", + "tag": "@snowplow/browser-plugin-focalmeter_v4.6.6", + "date": "Tue, 26 Aug 2025 08:42:27 GMT", + "comments": {} + }, + { + "version": "4.6.5", + "tag": "@snowplow/browser-plugin-focalmeter_v4.6.5", + "date": "Wed, 25 Jun 2025 21:16:46 GMT", + "comments": {} + }, + { + "version": "4.6.4", + "tag": "@snowplow/browser-plugin-focalmeter_v4.6.4", + "date": "Wed, 25 Jun 2025 12:08:50 GMT", + "comments": {} + }, + { + "version": "4.6.3", + "tag": "@snowplow/browser-plugin-focalmeter_v4.6.3", + "date": "Thu, 29 May 2025 19:52:07 GMT", + "comments": {} + }, + { + "version": "4.6.2", + "tag": "@snowplow/browser-plugin-focalmeter_v4.6.2", + "date": "Tue, 20 May 2025 07:39:05 GMT", + "comments": {} + }, + { + "version": "4.6.1", + "tag": "@snowplow/browser-plugin-focalmeter_v4.6.1", + "date": "Tue, 06 May 2025 13:10:51 GMT", + "comments": {} + }, + { + "version": "4.6.0", + "tag": "@snowplow/browser-plugin-focalmeter_v4.6.0", + "date": "Thu, 01 May 2025 09:58:59 GMT", + "comments": {} + }, + { + "version": "4.5.0", + "tag": "@snowplow/browser-plugin-focalmeter_v4.5.0", + "date": "Fri, 04 Apr 2025 09:21:23 GMT", + "comments": {} + }, + { + "version": "4.4.0", + "tag": "@snowplow/browser-plugin-focalmeter_v4.4.0", + "date": "Thu, 20 Mar 2025 12:14:34 GMT", + "comments": {} + }, + { + "version": "4.3.1", + "tag": "@snowplow/browser-plugin-focalmeter_v4.3.1", + "date": "Tue, 21 Jan 2025 11:09:42 GMT", + "comments": {} + }, + { + "version": "4.3.0", + "tag": "@snowplow/browser-plugin-focalmeter_v4.3.0", + "date": "Mon, 20 Jan 2025 11:45:13 GMT", + "comments": {} + }, + { + "version": "4.2.0", + "tag": "@snowplow/browser-plugin-focalmeter_v4.2.0", + "date": "Mon, 13 Jan 2025 08:30:05 GMT", + "comments": {} + }, + { + "version": "4.1.0", + "tag": "@snowplow/browser-plugin-focalmeter_v4.1.0", + "date": "Thu, 28 Nov 2024 10:57:30 GMT", + "comments": {} + }, + { + "version": "4.0.4", + "tag": "@snowplow/browser-plugin-focalmeter_v4.0.4", + "date": "Thu, 21 Nov 2024 09:06:36 GMT", + "comments": {} + }, + { + "version": "4.0.3", + "tag": "@snowplow/browser-plugin-focalmeter_v4.0.3", + "date": "Wed, 20 Nov 2024 09:30:31 GMT", + "comments": {} + }, + { + "version": "4.0.2", + "tag": "@snowplow/browser-plugin-focalmeter_v4.0.2", + "date": "Mon, 11 Nov 2024 15:46:34 GMT", + "comments": {} + }, + { + "version": "4.0.1", + "tag": "@snowplow/browser-plugin-focalmeter_v4.0.1", + "date": "Fri, 01 Nov 2024 10:35:07 GMT", + "comments": {} + }, + { + "version": "4.0.0", + "tag": "@snowplow/browser-plugin-focalmeter_v4.0.0", + "date": "Mon, 28 Oct 2024 11:48:53 GMT", + "comments": {} + }, + { + "version": "3.24.6", + "tag": "@snowplow/browser-plugin-focalmeter_v3.24.6", + "date": "Mon, 28 Oct 2024 10:23:28 GMT", + "comments": {} + }, + { + "version": "3.24.5", + "tag": "@snowplow/browser-plugin-focalmeter_v3.24.5", + "date": "Fri, 25 Oct 2024 08:53:04 GMT", + "comments": {} + }, + { + "version": "3.24.4", + "tag": "@snowplow/browser-plugin-focalmeter_v3.24.4", + "date": "Thu, 26 Sep 2024 06:10:22 GMT", + "comments": {} + }, + { + "version": "3.24.3", + "tag": "@snowplow/browser-plugin-focalmeter_v3.24.3", + "date": "Tue, 03 Sep 2024 08:15:14 GMT", + "comments": { + "none": [ + { + "comment": "Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush" + } + ] + } + }, + { + "version": "3.24.2", + "tag": "@snowplow/browser-plugin-focalmeter_v3.24.2", + "date": "Wed, 24 Jul 2024 08:59:00 GMT", + "comments": {} + }, + { + "version": "3.24.1", + "tag": "@snowplow/browser-plugin-focalmeter_v3.24.1", + "date": "Tue, 02 Jul 2024 07:08:17 GMT", + "comments": {} + }, + { + "version": "3.24.0", + "tag": "@snowplow/browser-plugin-focalmeter_v3.24.0", + "date": "Tue, 25 Jun 2024 08:31:05 GMT", + "comments": {} + }, + { + "version": "3.23.1", + "tag": "@snowplow/browser-plugin-focalmeter_v3.23.1", + "date": "Tue, 04 Jun 2024 13:34:45 GMT", + "comments": {} + }, + { + "version": "3.23.0", + "tag": "@snowplow/browser-plugin-focalmeter_v3.23.0", + "date": "Thu, 28 Mar 2024 11:28:45 GMT", + "comments": {} + }, + { + "version": "3.22.1", + "tag": "@snowplow/browser-plugin-focalmeter_v3.22.1", + "date": "Wed, 13 Mar 2024 08:39:48 GMT", + "comments": {} + }, + { + "version": "3.22.0", + "tag": "@snowplow/browser-plugin-focalmeter_v3.22.0", + "date": "Fri, 08 Mar 2024 08:13:04 GMT", + "comments": {} + }, + { + "version": "3.21.0", + "tag": "@snowplow/browser-plugin-focalmeter_v3.21.0", + "date": "Mon, 29 Jan 2024 08:34:06 GMT", + "comments": {} + }, + { + "version": "3.20.0", + "tag": "@snowplow/browser-plugin-focalmeter_v3.20.0", + "date": "Mon, 15 Jan 2024 14:41:16 GMT", + "comments": {} + }, + { + "version": "3.19.0", + "tag": "@snowplow/browser-plugin-focalmeter_v3.19.0", + "date": "Thu, 14 Dec 2023 10:45:22 GMT", + "comments": {} + }, + { + "version": "3.18.0", + "tag": "@snowplow/browser-plugin-focalmeter_v3.18.0", + "date": "Mon, 04 Dec 2023 13:44:02 GMT", + "comments": {} + }, + { + "version": "3.17.0", + "tag": "@snowplow/browser-plugin-focalmeter_v3.17.0", + "date": "Tue, 14 Nov 2023 17:58:26 GMT", + "comments": {} + }, + { + "version": "3.16.0", + "tag": "@snowplow/browser-plugin-focalmeter_v3.16.0", + "date": "Mon, 16 Oct 2023 14:58:08 GMT", + "comments": { + "none": [ + { + "comment": "Add plugin to send requests with user ID to a Kantar FocalMeter endpoint (#1133)" + } + ] + } + } + ] +} diff --git a/plugins/browser-plugin-focalmeter/CHANGELOG.md b/plugins/browser-plugin-focalmeter/CHANGELOG.md new file mode 100644 index 000000000..5a8378490 --- /dev/null +++ b/plugins/browser-plugin-focalmeter/CHANGELOG.md @@ -0,0 +1,240 @@ +# Change Log - @snowplow/browser-plugin-focalmeter + +This log was last generated on Mon, 27 Jul 2026 13:52:14 GMT and should not be manually modified. + +## 4.10.0 +Mon, 27 Jul 2026 13:52:14 GMT + +_Version update only_ + +## 4.9.0 +Tue, 21 Jul 2026 14:53:08 GMT + +_Version update only_ + +## 4.8.4 +Thu, 02 Jul 2026 10:07:52 GMT + +_Version update only_ + +## 4.8.3 +Tue, 30 Jun 2026 14:22:03 GMT + +### Updates + +- Update uuid to v11 and remove closure-compiler from the build pipeline + +## 4.8.2 +Wed, 17 Jun 2026 12:30:12 GMT + +_Version update only_ + +## 4.8.1 +Wed, 13 May 2026 09:26:05 GMT + +_Version update only_ + +## 4.8.0 +Tue, 28 Apr 2026 07:56:22 GMT + +_Version update only_ + +## 4.7.0 +Wed, 01 Apr 2026 12:59:29 GMT + +_Version update only_ + +## 4.6.9 +Mon, 16 Mar 2026 15:43:06 GMT + +_Version update only_ + +## 4.6.8 +Tue, 28 Oct 2025 09:46:42 GMT + +_Version update only_ + +## 4.6.7 +Tue, 07 Oct 2025 14:53:36 GMT + +_Version update only_ + +## 4.6.6 +Tue, 26 Aug 2025 08:42:27 GMT + +_Version update only_ + +## 4.6.5 +Wed, 25 Jun 2025 21:16:46 GMT + +_Version update only_ + +## 4.6.4 +Wed, 25 Jun 2025 12:08:50 GMT + +_Version update only_ + +## 4.6.3 +Thu, 29 May 2025 19:52:07 GMT + +_Version update only_ + +## 4.6.2 +Tue, 20 May 2025 07:39:05 GMT + +_Version update only_ + +## 4.6.1 +Tue, 06 May 2025 13:10:51 GMT + +_Version update only_ + +## 4.6.0 +Thu, 01 May 2025 09:58:59 GMT + +_Version update only_ + +## 4.5.0 +Fri, 04 Apr 2025 09:21:23 GMT + +_Version update only_ + +## 4.4.0 +Thu, 20 Mar 2025 12:14:34 GMT + +_Version update only_ + +## 4.3.1 +Tue, 21 Jan 2025 11:09:42 GMT + +_Version update only_ + +## 4.3.0 +Mon, 20 Jan 2025 11:45:13 GMT + +_Version update only_ + +## 4.2.0 +Mon, 13 Jan 2025 08:30:05 GMT + +_Version update only_ + +## 4.1.0 +Thu, 28 Nov 2024 10:57:30 GMT + +_Version update only_ + +## 4.0.4 +Thu, 21 Nov 2024 09:06:36 GMT + +_Version update only_ + +## 4.0.3 +Wed, 20 Nov 2024 09:30:31 GMT + +_Version update only_ + +## 4.0.2 +Mon, 11 Nov 2024 15:46:34 GMT + +_Version update only_ + +## 4.0.1 +Fri, 01 Nov 2024 10:35:07 GMT + +_Version update only_ + +## 4.0.0 +Mon, 28 Oct 2024 11:48:53 GMT + +_Version update only_ + +## 3.24.6 +Mon, 28 Oct 2024 10:23:28 GMT + +_Version update only_ + +## 3.24.5 +Fri, 25 Oct 2024 08:53:04 GMT + +_Version update only_ + +## 3.24.4 +Thu, 26 Sep 2024 06:10:22 GMT + +_Version update only_ + +## 3.24.3 +Tue, 03 Sep 2024 08:15:14 GMT + +### Updates + +- Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush + +## 3.24.2 +Wed, 24 Jul 2024 08:59:00 GMT + +_Version update only_ + +## 3.24.1 +Tue, 02 Jul 2024 07:08:17 GMT + +_Version update only_ + +## 3.24.0 +Tue, 25 Jun 2024 08:31:05 GMT + +_Version update only_ + +## 3.23.1 +Tue, 04 Jun 2024 13:34:45 GMT + +_Version update only_ + +## 3.23.0 +Thu, 28 Mar 2024 11:28:45 GMT + +_Version update only_ + +## 3.22.1 +Wed, 13 Mar 2024 08:39:48 GMT + +_Version update only_ + +## 3.22.0 +Fri, 08 Mar 2024 08:13:04 GMT + +_Version update only_ + +## 3.21.0 +Mon, 29 Jan 2024 08:34:06 GMT + +_Version update only_ + +## 3.20.0 +Mon, 15 Jan 2024 14:41:16 GMT + +_Version update only_ + +## 3.19.0 +Thu, 14 Dec 2023 10:45:22 GMT + +_Version update only_ + +## 3.18.0 +Mon, 04 Dec 2023 13:44:02 GMT + +_Version update only_ + +## 3.17.0 +Tue, 14 Nov 2023 17:58:26 GMT + +_Version update only_ + +## 3.16.0 +Mon, 16 Oct 2023 14:58:08 GMT + +### Updates + +- Add plugin to send requests with user ID to a Kantar FocalMeter endpoint (#1133) + diff --git a/plugins/browser-plugin-focalmeter/LICENSE b/plugins/browser-plugin-focalmeter/LICENSE new file mode 100644 index 000000000..a311732d5 --- /dev/null +++ b/plugins/browser-plugin-focalmeter/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2023 Snowplow Analytics Ltd, 2010 Anthon Pang +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/plugins/browser-plugin-focalmeter/README.md b/plugins/browser-plugin-focalmeter/README.md new file mode 100644 index 000000000..b3a9a6c01 --- /dev/null +++ b/plugins/browser-plugin-focalmeter/README.md @@ -0,0 +1,56 @@ +# Snowplow FocalMeter Integration + +[![npm version][npm-image]][npm-url] +[![License][license-image]](LICENSE) + +Browser Plugin to be used with `@snowplow/browser-tracker`. + +Adds integration with the Kantar FocalMeter to your Snowplow tracking. +The plugin sends requests with the domain user ID to a Kantar endpoint used with the FocalMeter system. +A request is made when the first event with a new user ID is tracked. + +## Maintainer quick start + +Part of the Snowplow JavaScript Tracker monorepo. +Build with [Node.js](https://nodejs.org/en/) (18 - 20) and [Rush](https://rushjs.io/). + +### Setup repository + +```bash +npm install -g @microsoft/rush +git clone https://github.com/snowplow/snowplow-javascript-tracker.git +rush update +``` + +## Package Installation + +With npm: + +```bash +npm install @snowplow/browser-plugin-focalmeter +``` + +## Usage + +Initialize your tracker with the FocalMeterPlugin: + +```js +import { newTracker } from '@snowplow/browser-tracker'; +import { FocalMeterPlugin } from '@snowplow/browser-plugin-focalmeter'; + +newTracker('sp1', '{{collector}}', { plugins: [ FocalMeterPlugin() ] }); // Also stores reference at module level +``` + +## Copyright and license + +Licensed and distributed under the [BSD 3-Clause License](LICENSE) ([An OSI Approved License][osi]). + +Copyright (c) 2023 Snowplow Analytics Ltd, 2010 Anthon Pang. + +All rights reserved. + +[npm-url]: https://www.npmjs.com/package/@snowplow/browser-plugin-focalmeter +[npm-image]: https://img.shields.io/npm/v/@snowplow/browser-plugin-focalmeter +[docs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-tracker/ +[osi]: https://opensource.org/licenses/BSD-3-Clause +[license-image]: https://img.shields.io/npm/l/@snowplow/browser-plugin-focalmeter diff --git a/plugins/browser-plugin-focalmeter/jest.config.js b/plugins/browser-plugin-focalmeter/jest.config.js new file mode 100644 index 000000000..87d15da9b --- /dev/null +++ b/plugins/browser-plugin-focalmeter/jest.config.js @@ -0,0 +1,6 @@ +module.exports = { + preset: 'ts-jest', + reporters: ['jest-standard-reporter'], + setupFilesAfterEnv: ['../../setupTestGlobals.ts'], + testEnvironment: 'jest-environment-jsdom-global', +}; diff --git a/plugins/browser-plugin-focalmeter/package.json b/plugins/browser-plugin-focalmeter/package.json new file mode 100644 index 000000000..4595b87d3 --- /dev/null +++ b/plugins/browser-plugin-focalmeter/package.json @@ -0,0 +1,52 @@ +{ + "name": "@snowplow/browser-plugin-focalmeter", + "version": "4.10.0", + "description": "Kantar FocalMeter integration for Snowplow", + "homepage": "http://bit.ly/sp-js", + "bugs": "https://github.com/snowplow/snowplow-javascript-tracker/issues", + "repository": { + "type": "git", + "url": "https://github.com/snowplow/snowplow-javascript-tracker.git" + }, + "license": "BSD-3-Clause", + "author": "Matus Tomlein", + "sideEffects": false, + "main": "./dist/index.umd.js", + "module": "./dist/index.module.js", + "types": "./dist/index.module.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "rollup -c --silent --failAfterWarnings", + "test": "jest" + }, + "dependencies": { + "@snowplow/browser-tracker-core": "workspace:*", + "@snowplow/tracker-core": "workspace:*", + "tslib": "^2.3.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "~21.0.2", + "@rollup/plugin-node-resolve": "~13.1.3", + "@types/jest": "~28.1.1", + "@types/jsdom": "~16.2.14", + "@typescript-eslint/eslint-plugin": "~5.15.0", + "@typescript-eslint/parser": "~5.15.0", + "eslint": "~8.11.0", + "jest": "~28.1.3", + "jest-environment-jsdom": "~28.1.3", + "jest-environment-jsdom-global": "~4.0.0", + "jest-standard-reporter": "~2.0.0", + "rollup": "~2.70.1", + "rollup-plugin-cleanup": "~3.2.1", + "rollup-plugin-license": "~2.6.1", + "rollup-plugin-terser": "~7.0.2", + "rollup-plugin-ts": "~2.0.5", + "ts-jest": "~28.0.8", + "typescript": "~4.6.2" + }, + "peerDependencies": { + "@snowplow/browser-tracker": "~4.10.0" + } +} diff --git a/plugins/browser-plugin-focalmeter/rollup.config.js b/plugins/browser-plugin-focalmeter/rollup.config.js new file mode 100644 index 000000000..659f9438b --- /dev/null +++ b/plugins/browser-plugin-focalmeter/rollup.config.js @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import ts from 'rollup-plugin-ts'; // Prefered over @rollup/plugin-typescript as it bundles .d.ts files +import { banner } from '../../banner'; +import { terser } from 'rollup-plugin-terser'; +import cleanup from 'rollup-plugin-cleanup'; +import pkg from './package.json'; +import { builtinModules } from 'module'; + +const umdPlugins = [nodeResolve({ browser: true }), commonjs(), ts()]; +const umdName = 'snowplowFocalMeter'; + +export default [ + // CommonJS (for Node) and ES module (for bundlers) build. + { + input: './src/index.ts', + plugins: [...umdPlugins, banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main, format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + plugins: [...umdPlugins, terser(), cleanup({ comments: 'none' }), banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main.replace('.js', '.min.js'), format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + external: [...builtinModules, ...Object.keys(pkg.dependencies), ...Object.keys(pkg.devDependencies)], + plugins: [ + ts(), // so Rollup can convert TypeScript to JavaScript + banner(), + ], + output: [{ file: pkg.module, format: 'es', sourcemap: true }], + }, +]; diff --git a/plugins/browser-plugin-focalmeter/src/index.ts b/plugins/browser-plugin-focalmeter/src/index.ts new file mode 100644 index 000000000..ef2c290f8 --- /dev/null +++ b/plugins/browser-plugin-focalmeter/src/index.ts @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2023 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { + attemptGetLocalStorage, + BrowserPlugin, + hasLocalStorage, + BrowserTracker, + attemptWriteLocalStorage, +} from '@snowplow/browser-tracker-core'; +import { Logger, Payload } from '@snowplow/tracker-core'; + +/** FocalMeter plugin configuration */ +export interface FocalMeterConfiguration { + /** URL of the Kantar endpoint to send the requests to (including protocol) */ + kantarEndpoint: string; + /** Whether to store information about the last submitted user ID in local storage to prevent sending it again on next load (defaults not to use local storage) */ + useLocalStorage?: boolean; + /** Callback to process user ID before sending it in a request. This may be used to apply hashing to the value. */ + processUserId?: (userId: string) => string; +} + +const _trackers: Record = {}; +const _configurations: Record = {}; + +/** + * The FocalMeter Plugin + * + * The plugin sends requests with the domain user ID to a Kantar endpoint used with the FocalMeter system. + * A request is made when the first event with a new user ID is tracked. + * + * Call `enableFocalMeterIntegration()` to enable the integration with given configuration. + */ +export function FocalMeterPlugin(): BrowserPlugin { + let LOG: Logger; + let lastUserId: string | undefined | null; + let trackerId: string; + + return { + activateBrowserPlugin: (tracker: BrowserTracker) => { + trackerId = tracker.id; + _trackers[tracker.id] = tracker; + }, + + logger: (logger: Logger) => { + LOG = logger; + }, + + afterTrack: (payload: Payload) => { + if (!_configurations[trackerId]) { + LOG.error('FocalMeter integration not enabled'); + return; + } + + const newUserId = payload['duid'] as string; + const { kantarEndpoint, useLocalStorage, processUserId } = _configurations[trackerId]; + + if (!lastUserId && useLocalStorage && hasLocalStorage()) { + const key = getLocalStorageKey(trackerId); + lastUserId = attemptGetLocalStorage(key); + } + + if (newUserId && newUserId != lastUserId) { + lastUserId = newUserId; + const processedUserId = processUserId !== undefined ? processUserId(newUserId) : newUserId; + + sendRequest(kantarEndpoint, processedUserId, LOG, () => { + // only write in local storage if the request succeeded + if (useLocalStorage && hasLocalStorage()) { + const key = getLocalStorageKey(trackerId); + attemptWriteLocalStorage(key, newUserId); + } + }); + } + }, + }; +} + +/** + * Enables the integration with Kantar FocalMeter. + * + * @param configuration - Configuration with the URL endpoint to send requests to + * @param trackers - The tracker identifiers which should have the context enabled + */ +export function enableFocalMeterIntegration( + configuration: FocalMeterConfiguration, + trackers: Array = Object.keys(_trackers) +): void { + for (const id of trackers) { + if (_trackers[id]) { + _configurations[id] = configuration; + } + } +} + +function getLocalStorageKey(trackerId: string): string { + return `sp-fclmtr-${trackerId}`; +} + +function sendRequest(url: string, userId: string, LOG: Logger, successCallback: () => void): void { + const xhr = new XMLHttpRequest(); + xhr.open('GET', getKantarURL(url, userId)); + xhr.timeout = 5000; + + xhr.onreadystatechange = function () { + if (xhr.readyState === 4 && xhr.status >= 200) { + if (xhr.status < 300) { + successCallback(); + LOG.debug(`ID sent to Kantar: ${userId}`); + } else { + LOG.error(`Kantar request failed: ${xhr.status}: ${xhr.statusText}`); + } + } + }; + + xhr.send(); +} + +function getKantarURL(url: string, userId: string): string { + const query: Record = { + vendor: 'snowplow', + cs_fpid: userId, + c12: 'not_set', + }; + return ( + url + + '?' + + Object.keys(query) + .map((key) => key + '=' + query[key]) + .join('&') + ); +} diff --git a/plugins/browser-plugin-focalmeter/test/request.test.ts b/plugins/browser-plugin-focalmeter/test/request.test.ts new file mode 100644 index 000000000..7058c31e5 --- /dev/null +++ b/plugins/browser-plugin-focalmeter/test/request.test.ts @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2023 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { addTracker, SharedState } from '@snowplow/browser-tracker-core'; +import { enableFocalMeterIntegration, FocalMeterPlugin } from '../src'; + +describe('FocalmeterPlugin', () => { + // Mock XHR network requests + let xhrMock: Partial; + let xhrOpenMock: jest.Mock; + let queuedStateChangeCallbacks: any[] = []; + let domain = 'https://kantar.com'; + + beforeEach(() => { + xhrOpenMock = jest.fn(); + xhrMock = { + open: xhrOpenMock, + send: jest.fn(), + setRequestHeader: jest.fn(), + withCredentials: true, + status: 200, + response: '', + readyState: 4, + }; + + Object.defineProperty(xhrMock, 'onreadystatechange', { + set: (val) => { + queuedStateChangeCallbacks.push(val); + }, + }); + + jest.spyOn(window, 'XMLHttpRequest').mockImplementation(() => xhrMock as XMLHttpRequest); + }); + + it('makes a request to Kantar endpoint with user ID', async () => { + const tracker = createTrackerWithPlugin(); + enableFocalMeterIntegration({ kantarEndpoint: domain }); + + tracker?.trackPageView(); + const userId = tracker?.getDomainUserId(); + + await checkMock(() => { + expect(xhrOpenMock).toHaveBeenCalledTimes(1); + expect(xhrOpenMock).toHaveBeenLastCalledWith('GET', `${domain}?vendor=snowplow&cs_fpid=${userId}&c12=not_set`); + }); + }); + + it('makes a request to Kantar endpoint with processed user ID', async () => { + const tracker = createTrackerWithPlugin(); + enableFocalMeterIntegration({ kantarEndpoint: domain, processUserId: (userId) => userId + '-processed' }); + + tracker?.trackPageView(); + const userId = tracker?.getDomainUserId(); + + await checkMock(() => { + expect(xhrOpenMock).toHaveBeenCalledTimes(1); + expect(xhrOpenMock).toHaveBeenLastCalledWith('GET', `${domain}?vendor=snowplow&cs_fpid=${userId}-processed&c12=not_set`); + }); + }); + + it('makes a request to Kantar endpoint when user ID changes', async () => { + const tracker = createTrackerWithPlugin(); + enableFocalMeterIntegration({ kantarEndpoint: domain }); + + // Doesn't make a request if anonymous tracking + tracker?.enableAnonymousTracking(); + tracker?.trackPageView(); + await checkMock(() => { + expect(xhrOpenMock).toHaveBeenCalledTimes(0); + }); + + // Makes a request when disabling anonymous tracking + tracker?.disableAnonymousTracking(); + tracker?.trackPageView(); + const userId = tracker?.getDomainUserId(); + await checkMock(() => { + expect(xhrOpenMock).toHaveBeenCalledTimes(1); + expect(xhrOpenMock).toHaveBeenLastCalledWith('GET', `${domain}?vendor=snowplow&cs_fpid=${userId}&c12=not_set`); + }); + + // Doesn't make another request since user ID didn't change + tracker?.trackPageView(); + await checkMock(() => { + expect(xhrOpenMock).toHaveBeenCalledTimes(0); + }); + }); + + it('can work with multiple trackers', async () => { + const tracker1 = createTrackerWithPlugin(); + const tracker2 = createTrackerWithPlugin(); + + enableFocalMeterIntegration( + { + kantarEndpoint: domain, + }, + [tracker1!.namespace, tracker2!.namespace] + ); + + // Makes requests for both trackers + tracker1?.trackPageView(); + await checkMock(() => expect(xhrOpenMock).toHaveBeenCalledTimes(1)); + tracker2?.trackPageView(); + await checkMock(() => expect(xhrOpenMock).toHaveBeenCalledTimes(1)); + + // Doesn't make any more requests for the trackers + tracker1?.trackPageView(); + await checkMock(() => expect(xhrOpenMock).toHaveBeenCalledTimes(0)); + tracker2?.trackPageView(); + await checkMock(() => expect(xhrOpenMock).toHaveBeenCalledTimes(0)); + }); + + function createTrackerWithPlugin(id: string | undefined = undefined) { + const state = new SharedState(); + id ??= 'sp-' + Math.random(); + + return addTracker(id, id, 'js-3.0.0', '', state, { + stateStorageStrategy: 'cookie', + encodeBase64: false, + plugins: [FocalMeterPlugin()], + customFetch: async () => new Response(null, { status: 200 }), + }); + } + + function checkMock(callback: () => void) { + return new Promise((resolve) => { + setTimeout(() => { + callback(); + queuedStateChangeCallbacks.forEach((callback) => callback()); + queuedStateChangeCallbacks = []; + xhrOpenMock.mockReset(); + resolve(true); + }, 100); + }); + } +}); diff --git a/plugins/browser-plugin-focalmeter/tsconfig.json b/plugins/browser-plugin-focalmeter/tsconfig.json new file mode 100644 index 000000000..4082f16a5 --- /dev/null +++ b/plugins/browser-plugin-focalmeter/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +} diff --git a/plugins/browser-plugin-form-tracking/CHANGELOG.json b/plugins/browser-plugin-form-tracking/CHANGELOG.json new file mode 100644 index 000000000..d7035cb5b --- /dev/null +++ b/plugins/browser-plugin-form-tracking/CHANGELOG.json @@ -0,0 +1,632 @@ +{ + "name": "@snowplow/browser-plugin-form-tracking", + "entries": [ + { + "version": "4.10.0", + "tag": "@snowplow/browser-plugin-form-tracking_v4.10.0", + "date": "Mon, 27 Jul 2026 13:52:14 GMT", + "comments": {} + }, + { + "version": "4.9.0", + "tag": "@snowplow/browser-plugin-form-tracking_v4.9.0", + "date": "Tue, 21 Jul 2026 14:53:08 GMT", + "comments": {} + }, + { + "version": "4.8.4", + "tag": "@snowplow/browser-plugin-form-tracking_v4.8.4", + "date": "Thu, 02 Jul 2026 10:07:52 GMT", + "comments": {} + }, + { + "version": "4.8.3", + "tag": "@snowplow/browser-plugin-form-tracking_v4.8.3", + "date": "Tue, 30 Jun 2026 14:22:03 GMT", + "comments": { + "none": [ + { + "comment": "Update uuid to v11 and remove closure-compiler from the build pipeline" + } + ] + } + }, + { + "version": "4.8.2", + "tag": "@snowplow/browser-plugin-form-tracking_v4.8.2", + "date": "Wed, 17 Jun 2026 12:30:12 GMT", + "comments": {} + }, + { + "version": "4.8.1", + "tag": "@snowplow/browser-plugin-form-tracking_v4.8.1", + "date": "Wed, 13 May 2026 09:26:05 GMT", + "comments": {} + }, + { + "version": "4.8.0", + "tag": "@snowplow/browser-plugin-form-tracking_v4.8.0", + "date": "Tue, 28 Apr 2026 07:56:22 GMT", + "comments": {} + }, + { + "version": "4.7.0", + "tag": "@snowplow/browser-plugin-form-tracking_v4.7.0", + "date": "Wed, 01 Apr 2026 12:59:29 GMT", + "comments": {} + }, + { + "version": "4.6.9", + "tag": "@snowplow/browser-plugin-form-tracking_v4.6.9", + "date": "Mon, 16 Mar 2026 15:43:06 GMT", + "comments": {} + }, + { + "version": "4.6.8", + "tag": "@snowplow/browser-plugin-form-tracking_v4.6.8", + "date": "Tue, 28 Oct 2025 09:46:42 GMT", + "comments": { + "none": [ + { + "comment": "Allow opt-in bubble-phase listeners for change/submit" + } + ] + } + }, + { + "version": "4.6.7", + "tag": "@snowplow/browser-plugin-form-tracking_v4.6.7", + "date": "Tue, 07 Oct 2025 14:53:36 GMT", + "comments": {} + }, + { + "version": "4.6.6", + "tag": "@snowplow/browser-plugin-form-tracking_v4.6.6", + "date": "Tue, 26 Aug 2025 08:42:27 GMT", + "comments": {} + }, + { + "version": "4.6.5", + "tag": "@snowplow/browser-plugin-form-tracking_v4.6.5", + "date": "Wed, 25 Jun 2025 21:16:46 GMT", + "comments": {} + }, + { + "version": "4.6.4", + "tag": "@snowplow/browser-plugin-form-tracking_v4.6.4", + "date": "Wed, 25 Jun 2025 12:08:50 GMT", + "comments": {} + }, + { + "version": "4.6.3", + "tag": "@snowplow/browser-plugin-form-tracking_v4.6.3", + "date": "Thu, 29 May 2025 19:52:07 GMT", + "comments": {} + }, + { + "version": "4.6.2", + "tag": "@snowplow/browser-plugin-form-tracking_v4.6.2", + "date": "Tue, 20 May 2025 07:39:05 GMT", + "comments": {} + }, + { + "version": "4.6.1", + "tag": "@snowplow/browser-plugin-form-tracking_v4.6.1", + "date": "Tue, 06 May 2025 13:10:51 GMT", + "comments": {} + }, + { + "version": "4.6.0", + "tag": "@snowplow/browser-plugin-form-tracking_v4.6.0", + "date": "Thu, 01 May 2025 09:58:59 GMT", + "comments": {} + }, + { + "version": "4.5.0", + "tag": "@snowplow/browser-plugin-form-tracking_v4.5.0", + "date": "Fri, 04 Apr 2025 09:21:23 GMT", + "comments": {} + }, + { + "version": "4.4.0", + "tag": "@snowplow/browser-plugin-form-tracking_v4.4.0", + "date": "Thu, 20 Mar 2025 12:14:34 GMT", + "comments": {} + }, + { + "version": "4.3.1", + "tag": "@snowplow/browser-plugin-form-tracking_v4.3.1", + "date": "Tue, 21 Jan 2025 11:09:42 GMT", + "comments": {} + }, + { + "version": "4.3.0", + "tag": "@snowplow/browser-plugin-form-tracking_v4.3.0", + "date": "Mon, 20 Jan 2025 11:45:13 GMT", + "comments": {} + }, + { + "version": "4.2.0", + "tag": "@snowplow/browser-plugin-form-tracking_v4.2.0", + "date": "Mon, 13 Jan 2025 08:30:05 GMT", + "comments": {} + }, + { + "version": "4.1.0", + "tag": "@snowplow/browser-plugin-form-tracking_v4.1.0", + "date": "Thu, 28 Nov 2024 10:57:30 GMT", + "comments": {} + }, + { + "version": "4.0.4", + "tag": "@snowplow/browser-plugin-form-tracking_v4.0.4", + "date": "Thu, 21 Nov 2024 09:06:36 GMT", + "comments": {} + }, + { + "version": "4.0.3", + "tag": "@snowplow/browser-plugin-form-tracking_v4.0.3", + "date": "Wed, 20 Nov 2024 09:30:31 GMT", + "comments": {} + }, + { + "version": "4.0.2", + "tag": "@snowplow/browser-plugin-form-tracking_v4.0.2", + "date": "Mon, 11 Nov 2024 15:46:34 GMT", + "comments": {} + }, + { + "version": "4.0.1", + "tag": "@snowplow/browser-plugin-form-tracking_v4.0.1", + "date": "Fri, 01 Nov 2024 10:35:07 GMT", + "comments": {} + }, + { + "version": "4.0.0", + "tag": "@snowplow/browser-plugin-form-tracking_v4.0.0", + "date": "Mon, 28 Oct 2024 11:48:53 GMT", + "comments": { + "none": [ + { + "comment": "Add event delegation for link click tracking" + }, + { + "comment": "Detect form events within ShadowRoots" + } + ] + } + }, + { + "version": "3.24.6", + "tag": "@snowplow/browser-plugin-form-tracking_v3.24.6", + "date": "Mon, 28 Oct 2024 10:23:28 GMT", + "comments": {} + }, + { + "version": "3.24.5", + "tag": "@snowplow/browser-plugin-form-tracking_v3.24.5", + "date": "Fri, 25 Oct 2024 08:53:04 GMT", + "comments": {} + }, + { + "version": "3.24.4", + "tag": "@snowplow/browser-plugin-form-tracking_v3.24.4", + "date": "Thu, 26 Sep 2024 06:10:22 GMT", + "comments": {} + }, + { + "version": "3.24.3", + "tag": "@snowplow/browser-plugin-form-tracking_v3.24.3", + "date": "Tue, 03 Sep 2024 08:15:14 GMT", + "comments": { + "none": [ + { + "comment": "Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush" + } + ] + } + }, + { + "version": "3.24.2", + "tag": "@snowplow/browser-plugin-form-tracking_v3.24.2", + "date": "Wed, 24 Jul 2024 08:59:00 GMT", + "comments": {} + }, + { + "version": "3.24.1", + "tag": "@snowplow/browser-plugin-form-tracking_v3.24.1", + "date": "Tue, 02 Jul 2024 07:08:17 GMT", + "comments": {} + }, + { + "version": "3.24.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.24.0", + "date": "Tue, 25 Jun 2024 08:31:05 GMT", + "comments": {} + }, + { + "version": "3.23.1", + "tag": "@snowplow/browser-plugin-form-tracking_v3.23.1", + "date": "Tue, 04 Jun 2024 13:34:45 GMT", + "comments": {} + }, + { + "version": "3.23.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.23.0", + "date": "Thu, 28 Mar 2024 11:28:45 GMT", + "comments": {} + }, + { + "version": "3.22.1", + "tag": "@snowplow/browser-plugin-form-tracking_v3.22.1", + "date": "Wed, 13 Mar 2024 08:39:48 GMT", + "comments": {} + }, + { + "version": "3.22.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.22.0", + "date": "Fri, 08 Mar 2024 08:13:04 GMT", + "comments": {} + }, + { + "version": "3.21.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.21.0", + "date": "Mon, 29 Jan 2024 08:34:06 GMT", + "comments": {} + }, + { + "version": "3.20.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.20.0", + "date": "Mon, 15 Jan 2024 14:41:16 GMT", + "comments": {} + }, + { + "version": "3.19.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.19.0", + "date": "Thu, 14 Dec 2023 10:45:22 GMT", + "comments": {} + }, + { + "version": "3.18.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.18.0", + "date": "Mon, 04 Dec 2023 13:44:02 GMT", + "comments": {} + }, + { + "version": "3.17.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.17.0", + "date": "Tue, 14 Nov 2023 17:58:26 GMT", + "comments": {} + }, + { + "version": "3.16.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.16.0", + "date": "Mon, 16 Oct 2023 14:58:08 GMT", + "comments": { + "none": [ + { + "comment": "Fix transform function for submit_form event" + } + ] + } + }, + { + "version": "3.15.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.15.0", + "date": "Mon, 28 Aug 2023 14:25:14 GMT", + "comments": {} + }, + { + "version": "3.14.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.14.0", + "date": "Thu, 10 Aug 2023 13:56:44 GMT", + "comments": {} + }, + { + "version": "3.13.1", + "tag": "@snowplow/browser-plugin-form-tracking_v3.13.1", + "date": "Thu, 29 Jun 2023 14:20:06 GMT", + "comments": {} + }, + { + "version": "3.13.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.13.0", + "date": "Tue, 20 Jun 2023 07:44:23 GMT", + "comments": {} + }, + { + "version": "3.12.1", + "tag": "@snowplow/browser-plugin-form-tracking_v3.12.1", + "date": "Thu, 15 Jun 2023 10:05:37 GMT", + "comments": {} + }, + { + "version": "3.12.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.12.0", + "date": "Mon, 05 Jun 2023 11:51:22 GMT", + "comments": {} + }, + { + "version": "3.11.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.11.0", + "date": "Wed, 24 May 2023 15:56:17 GMT", + "comments": {} + }, + { + "version": "3.10.1", + "tag": "@snowplow/browser-plugin-form-tracking_v3.10.1", + "date": "Fri, 12 May 2023 06:59:31 GMT", + "comments": {} + }, + { + "version": "3.10.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.10.0", + "date": "Thu, 11 May 2023 08:29:15 GMT", + "comments": {} + }, + { + "version": "3.9.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.9.0", + "date": "Thu, 30 Mar 2023 13:46:56 GMT", + "comments": {} + }, + { + "version": "3.8.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.8.0", + "date": "Tue, 03 Jan 2023 15:36:33 GMT", + "comments": {} + }, + { + "version": "3.7.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.7.0", + "date": "Mon, 31 Oct 2022 06:26:28 GMT", + "comments": {} + }, + { + "version": "3.6.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.6.0", + "date": "Thu, 15 Sep 2022 07:55:20 GMT", + "comments": {} + }, + { + "version": "3.5.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.5.0", + "date": "Fri, 10 Jun 2022 18:57:46 GMT", + "comments": {} + }, + { + "version": "3.4.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.4.0", + "date": "Thu, 07 Apr 2022 11:56:26 GMT", + "comments": { + "none": [ + { + "comment": "Enable form tracking on forms embedded within iframes where possible (#1066)" + }, + { + "comment": "Bump dependencies (#1067)" + }, + { + "comment": "Add ability to enable only form_change, or form_submit, focus_form or any combination (#371)" + } + ] + } + }, + { + "version": "3.3.1", + "tag": "@snowplow/browser-plugin-form-tracking_v3.3.1", + "date": "Wed, 23 Feb 2022 19:27:40 GMT", + "comments": {} + }, + { + "version": "3.3.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.3.0", + "date": "Mon, 31 Jan 2022 15:58:10 GMT", + "comments": {} + }, + { + "version": "3.2.3", + "tag": "@snowplow/browser-plugin-form-tracking_v3.2.3", + "date": "Tue, 18 Jan 2022 16:23:52 GMT", + "comments": { + "none": [ + { + "comment": "Bump Copyright to 2022 (#1040)" + } + ] + } + }, + { + "version": "3.2.2", + "tag": "@snowplow/browser-plugin-form-tracking_v3.2.2", + "date": "Fri, 14 Jan 2022 10:17:59 GMT", + "comments": {} + }, + { + "version": "3.2.1", + "tag": "@snowplow/browser-plugin-form-tracking_v3.2.1", + "date": "Wed, 12 Jan 2022 09:50:29 GMT", + "comments": {} + }, + { + "version": "3.2.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.2.0", + "date": "Tue, 11 Jan 2022 12:53:22 GMT", + "comments": { + "none": [ + { + "comment": "Allow enableFormTracking to capture dynamic form changes (#748)" + } + ] + } + }, + { + "version": "3.1.6", + "tag": "@snowplow/browser-plugin-form-tracking_v3.1.6", + "date": "Tue, 19 Oct 2021 09:17:22 GMT", + "comments": { + "none": [ + { + "comment": "Fix failing build on ARM Macs (#1012)" + } + ] + } + }, + { + "version": "3.1.5", + "tag": "@snowplow/browser-plugin-form-tracking_v3.1.5", + "date": "Fri, 01 Oct 2021 08:09:21 GMT", + "comments": {} + }, + { + "version": "3.1.4", + "tag": "@snowplow/browser-plugin-form-tracking_v3.1.4", + "date": "Tue, 21 Sep 2021 14:59:36 GMT", + "comments": {} + }, + { + "version": "3.1.3", + "tag": "@snowplow/browser-plugin-form-tracking_v3.1.3", + "date": "Mon, 23 Aug 2021 10:13:18 GMT", + "comments": {} + }, + { + "version": "3.1.2", + "tag": "@snowplow/browser-plugin-form-tracking_v3.1.2", + "date": "Mon, 16 Aug 2021 12:59:59 GMT", + "comments": { + "none": [ + { + "comment": "Update READMEs with correct Node requirements (#994)" + } + ] + } + }, + { + "version": "3.1.1", + "tag": "@snowplow/browser-plugin-form-tracking_v3.1.1", + "date": "Wed, 04 Aug 2021 10:12:25 GMT", + "comments": { + "none": [ + { + "comment": "Bump tslib to 2.3.0 (#986)" + }, + { + "comment": "Bump typescript to 4.3.5 (#987)" + }, + { + "comment": "Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988)" + } + ] + } + }, + { + "version": "3.1.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.1.0", + "date": "Fri, 14 May 2021 10:45:32 GMT", + "comments": {} + }, + { + "version": "3.0.3", + "tag": "@snowplow/browser-plugin-form-tracking_v3.0.3", + "date": "Wed, 21 Apr 2021 12:35:06 GMT", + "comments": {} + }, + { + "version": "3.0.2", + "tag": "@snowplow/browser-plugin-form-tracking_v3.0.2", + "date": "Thu, 15 Apr 2021 21:07:39 GMT", + "comments": {} + }, + { + "version": "3.0.1", + "tag": "@snowplow/browser-plugin-form-tracking_v3.0.1", + "date": "Wed, 14 Apr 2021 16:30:05 GMT", + "comments": { + "none": [ + { + "comment": "Add peerDependencies to plugins (#950)" + }, + { + "comment": "Mark packages as sideEffect: false (#951)" + }, + { + "comment": "Add unit tests to plugin track* functions (#954)" + } + ] + } + }, + { + "version": "3.0.0", + "tag": "@snowplow/browser-plugin-form-tracking_v3.0.0", + "date": "Wed, 31 Mar 2021 14:46:47 GMT", + "comments": { + "none": [ + { + "comment": "Bump rollup to 2.41 (#916)" + }, + { + "comment": "Publish UMD versions of plugins to GitHub release (#923)" + }, + { + "comment": "Ensure browser-tracker API methods catch exceptions (#919)" + }, + { + "comment": "Introduce TSDoc comments and extract interfaces where appropriate (#906)" + }, + { + "comment": "Bump major version to v3 and update READMEs (#904)" + }, + { + "comment": "Improve Core API for module bundlers which support treeshaking (#903)" + }, + { + "comment": "Rename @snowplow/browser-core to @snowplow/browser-tracker-core (#901)" + }, + { + "comment": "Publish lite version of sp.js (#900)" + }, + { + "comment": "Ensure correct 3-Clause BSD License notices are being used (#316)" + }, + { + "comment": "Improve API for module bundlers which support treeshaking (#899)" + }, + { + "comment": "Bump rush to 5.39 (#895)" + }, + { + "comment": "Port to TypeScript (#72)" + }, + { + "comment": "Make sp.js build process modular (#450)" + }, + { + "comment": "Create @snowplow/browser-tracker package for npm distribution (#541)" + }, + { + "comment": "Split auto contexts into plugins (#880)" + }, + { + "comment": "Add rush to manage monorepo (#883)" + }, + { + "comment": "Add ES Module builds (#882)" + }, + { + "comment": "Cleanup deprecated methods (#557)" + }, + { + "comment": "Update publishing process for rush (#907)" + }, + { + "comment": "Change white and black lists to allow and deny lists (#908)" + }, + { + "comment": "Create rush change files for major version 3 release (#909)" + } + ] + } + } + ] +} diff --git a/plugins/browser-plugin-form-tracking/CHANGELOG.md b/plugins/browser-plugin-form-tracking/CHANGELOG.md new file mode 100644 index 000000000..3ed1d5a32 --- /dev/null +++ b/plugins/browser-plugin-form-tracking/CHANGELOG.md @@ -0,0 +1,447 @@ +# Change Log - @snowplow/browser-plugin-form-tracking + +This log was last generated on Mon, 27 Jul 2026 13:52:14 GMT and should not be manually modified. + +## 4.10.0 +Mon, 27 Jul 2026 13:52:14 GMT + +_Version update only_ + +## 4.9.0 +Tue, 21 Jul 2026 14:53:08 GMT + +_Version update only_ + +## 4.8.4 +Thu, 02 Jul 2026 10:07:52 GMT + +_Version update only_ + +## 4.8.3 +Tue, 30 Jun 2026 14:22:03 GMT + +### Updates + +- Update uuid to v11 and remove closure-compiler from the build pipeline + +## 4.8.2 +Wed, 17 Jun 2026 12:30:12 GMT + +_Version update only_ + +## 4.8.1 +Wed, 13 May 2026 09:26:05 GMT + +_Version update only_ + +## 4.8.0 +Tue, 28 Apr 2026 07:56:22 GMT + +_Version update only_ + +## 4.7.0 +Wed, 01 Apr 2026 12:59:29 GMT + +_Version update only_ + +## 4.6.9 +Mon, 16 Mar 2026 15:43:06 GMT + +_Version update only_ + +## 4.6.8 +Tue, 28 Oct 2025 09:46:42 GMT + +### Updates + +- Allow opt-in bubble-phase listeners for change/submit + +## 4.6.7 +Tue, 07 Oct 2025 14:53:36 GMT + +_Version update only_ + +## 4.6.6 +Tue, 26 Aug 2025 08:42:27 GMT + +_Version update only_ + +## 4.6.5 +Wed, 25 Jun 2025 21:16:46 GMT + +_Version update only_ + +## 4.6.4 +Wed, 25 Jun 2025 12:08:50 GMT + +_Version update only_ + +## 4.6.3 +Thu, 29 May 2025 19:52:07 GMT + +_Version update only_ + +## 4.6.2 +Tue, 20 May 2025 07:39:05 GMT + +_Version update only_ + +## 4.6.1 +Tue, 06 May 2025 13:10:51 GMT + +_Version update only_ + +## 4.6.0 +Thu, 01 May 2025 09:58:59 GMT + +_Version update only_ + +## 4.5.0 +Fri, 04 Apr 2025 09:21:23 GMT + +_Version update only_ + +## 4.4.0 +Thu, 20 Mar 2025 12:14:34 GMT + +_Version update only_ + +## 4.3.1 +Tue, 21 Jan 2025 11:09:42 GMT + +_Version update only_ + +## 4.3.0 +Mon, 20 Jan 2025 11:45:13 GMT + +_Version update only_ + +## 4.2.0 +Mon, 13 Jan 2025 08:30:05 GMT + +_Version update only_ + +## 4.1.0 +Thu, 28 Nov 2024 10:57:30 GMT + +_Version update only_ + +## 4.0.4 +Thu, 21 Nov 2024 09:06:36 GMT + +_Version update only_ + +## 4.0.3 +Wed, 20 Nov 2024 09:30:31 GMT + +_Version update only_ + +## 4.0.2 +Mon, 11 Nov 2024 15:46:34 GMT + +_Version update only_ + +## 4.0.1 +Fri, 01 Nov 2024 10:35:07 GMT + +_Version update only_ + +## 4.0.0 +Mon, 28 Oct 2024 11:48:53 GMT + +### Updates + +- Add event delegation for link click tracking +- Detect form events within ShadowRoots + +## 3.24.6 +Mon, 28 Oct 2024 10:23:28 GMT + +_Version update only_ + +## 3.24.5 +Fri, 25 Oct 2024 08:53:04 GMT + +_Version update only_ + +## 3.24.4 +Thu, 26 Sep 2024 06:10:22 GMT + +_Version update only_ + +## 3.24.3 +Tue, 03 Sep 2024 08:15:14 GMT + +### Updates + +- Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush + +## 3.24.2 +Wed, 24 Jul 2024 08:59:00 GMT + +_Version update only_ + +## 3.24.1 +Tue, 02 Jul 2024 07:08:17 GMT + +_Version update only_ + +## 3.24.0 +Tue, 25 Jun 2024 08:31:05 GMT + +_Version update only_ + +## 3.23.1 +Tue, 04 Jun 2024 13:34:45 GMT + +_Version update only_ + +## 3.23.0 +Thu, 28 Mar 2024 11:28:45 GMT + +_Version update only_ + +## 3.22.1 +Wed, 13 Mar 2024 08:39:48 GMT + +_Version update only_ + +## 3.22.0 +Fri, 08 Mar 2024 08:13:04 GMT + +_Version update only_ + +## 3.21.0 +Mon, 29 Jan 2024 08:34:06 GMT + +_Version update only_ + +## 3.20.0 +Mon, 15 Jan 2024 14:41:16 GMT + +_Version update only_ + +## 3.19.0 +Thu, 14 Dec 2023 10:45:22 GMT + +_Version update only_ + +## 3.18.0 +Mon, 04 Dec 2023 13:44:02 GMT + +_Version update only_ + +## 3.17.0 +Tue, 14 Nov 2023 17:58:26 GMT + +_Version update only_ + +## 3.16.0 +Mon, 16 Oct 2023 14:58:08 GMT + +### Updates + +- Fix transform function for submit_form event + +## 3.15.0 +Mon, 28 Aug 2023 14:25:14 GMT + +_Version update only_ + +## 3.14.0 +Thu, 10 Aug 2023 13:56:44 GMT + +_Version update only_ + +## 3.13.1 +Thu, 29 Jun 2023 14:20:06 GMT + +_Version update only_ + +## 3.13.0 +Tue, 20 Jun 2023 07:44:23 GMT + +_Version update only_ + +## 3.12.1 +Thu, 15 Jun 2023 10:05:37 GMT + +_Version update only_ + +## 3.12.0 +Mon, 05 Jun 2023 11:51:22 GMT + +_Version update only_ + +## 3.11.0 +Wed, 24 May 2023 15:56:17 GMT + +_Version update only_ + +## 3.10.1 +Fri, 12 May 2023 06:59:31 GMT + +_Version update only_ + +## 3.10.0 +Thu, 11 May 2023 08:29:15 GMT + +_Version update only_ + +## 3.9.0 +Thu, 30 Mar 2023 13:46:56 GMT + +_Version update only_ + +## 3.8.0 +Tue, 03 Jan 2023 15:36:33 GMT + +_Version update only_ + +## 3.7.0 +Mon, 31 Oct 2022 06:26:28 GMT + +_Version update only_ + +## 3.6.0 +Thu, 15 Sep 2022 07:55:20 GMT + +_Version update only_ + +## 3.5.0 +Fri, 10 Jun 2022 18:57:46 GMT + +_Version update only_ + +## 3.4.0 +Thu, 07 Apr 2022 11:56:26 GMT + +### Updates + +- Enable form tracking on forms embedded within iframes where possible (#1066) +- Bump dependencies (#1067) +- Add ability to enable only form_change, or form_submit, focus_form or any combination (#371) + +## 3.3.1 +Wed, 23 Feb 2022 19:27:40 GMT + +_Version update only_ + +## 3.3.0 +Mon, 31 Jan 2022 15:58:10 GMT + +_Version update only_ + +## 3.2.3 +Tue, 18 Jan 2022 16:23:52 GMT + +### Updates + +- Bump Copyright to 2022 (#1040) + +## 3.2.2 +Fri, 14 Jan 2022 10:17:59 GMT + +_Version update only_ + +## 3.2.1 +Wed, 12 Jan 2022 09:50:29 GMT + +_Version update only_ + +## 3.2.0 +Tue, 11 Jan 2022 12:53:22 GMT + +### Updates + +- Allow enableFormTracking to capture dynamic form changes (#748) + +## 3.1.6 +Tue, 19 Oct 2021 09:17:22 GMT + +### Updates + +- Fix failing build on ARM Macs (#1012) + +## 3.1.5 +Fri, 01 Oct 2021 08:09:21 GMT + +_Version update only_ + +## 3.1.4 +Tue, 21 Sep 2021 14:59:36 GMT + +_Version update only_ + +## 3.1.3 +Mon, 23 Aug 2021 10:13:18 GMT + +_Version update only_ + +## 3.1.2 +Mon, 16 Aug 2021 12:59:59 GMT + +### Updates + +- Update READMEs with correct Node requirements (#994) + +## 3.1.1 +Wed, 04 Aug 2021 10:12:25 GMT + +### Updates + +- Bump tslib to 2.3.0 (#986) +- Bump typescript to 4.3.5 (#987) +- Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988) + +## 3.1.0 +Fri, 14 May 2021 10:45:32 GMT + +_Version update only_ + +## 3.0.3 +Wed, 21 Apr 2021 12:35:06 GMT + +_Version update only_ + +## 3.0.2 +Thu, 15 Apr 2021 21:07:39 GMT + +_Version update only_ + +## 3.0.1 +Wed, 14 Apr 2021 16:30:05 GMT + +### Updates + +- Add peerDependencies to plugins (#950) +- Mark packages as sideEffect: false (#951) +- Add unit tests to plugin track* functions (#954) + +## 3.0.0 +Wed, 31 Mar 2021 14:46:47 GMT + +### Updates + +- Bump rollup to 2.41 (#916) +- Publish UMD versions of plugins to GitHub release (#923) +- Ensure browser-tracker API methods catch exceptions (#919) +- Introduce TSDoc comments and extract interfaces where appropriate (#906) +- Bump major version to v3 and update READMEs (#904) +- Improve Core API for module bundlers which support treeshaking (#903) +- Rename @snowplow/browser-core to @snowplow/browser-tracker-core (#901) +- Publish lite version of sp.js (#900) +- Ensure correct 3-Clause BSD License notices are being used (#316) +- Improve API for module bundlers which support treeshaking (#899) +- Bump rush to 5.39 (#895) +- Port to TypeScript (#72) +- Make sp.js build process modular (#450) +- Create @snowplow/browser-tracker package for npm distribution (#541) +- Split auto contexts into plugins (#880) +- Add rush to manage monorepo (#883) +- Add ES Module builds (#882) +- Cleanup deprecated methods (#557) +- Update publishing process for rush (#907) +- Change white and black lists to allow and deny lists (#908) +- Create rush change files for major version 3 release (#909) + diff --git a/plugins/browser-plugin-form-tracking/LICENSE b/plugins/browser-plugin-form-tracking/LICENSE new file mode 100644 index 000000000..76f1946ea --- /dev/null +++ b/plugins/browser-plugin-form-tracking/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/plugins/browser-plugin-form-tracking/README.md b/plugins/browser-plugin-form-tracking/README.md new file mode 100644 index 000000000..d8d045856 --- /dev/null +++ b/plugins/browser-plugin-form-tracking/README.md @@ -0,0 +1,62 @@ +# Snowplow Form Tracking + +[![npm version][npm-image]][npm-url] +[![License][license-image]](LICENSE) + +Browser Plugin to be used with `@snowplow/browser-tracker`. + +Adds form tracking events to your Snowplow tracking. + +## Maintainer quick start + +Part of the Snowplow JavaScript Tracker monorepo. +Build with [Node.js](https://nodejs.org/en/) (18 - 20) and [Rush](https://rushjs.io/). + +### Setup repository + +```bash +npm install -g @microsoft/rush +git clone https://github.com/snowplow/snowplow-javascript-tracker.git +rush update +``` + +## Package Installation + +With npm: + +```bash +npm install @snowplow/browser-plugin-form-tracking +``` + +## Usage + +Initialize your tracker with the FormTrackingPlugin: + +```js +import { newTracker } from '@snowplow/browser-tracker'; +import { FormTrackingPlugin } from '@snowplow/browser-plugin-form-tracking'; + +newTracker('sp1', '{{collector}}', { plugins: [ FormTrackingPlugin() ] }); // Also stores reference at module level +``` + +Then use the available functions from this package to track to all trackers which have been initialized with this plugin: + +```js +import { enableFormTracking } from '@snowplow/browser-plugin-form-tracking'; + +enableFormTracking({options: { ... }}); +``` + +## Copyright and license + +Licensed and distributed under the [BSD 3-Clause License](LICENSE) ([An OSI Approved License][osi]). + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang. + +All rights reserved. + +[npm-url]: https://www.npmjs.com/package/@snowplow/browser-plugin-form-tracking +[npm-image]: https://img.shields.io/npm/v/@snowplow/browser-plugin-form-tracking +[docs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-tracker/ +[osi]: https://opensource.org/licenses/BSD-3-Clause +[license-image]: https://img.shields.io/npm/l/@snowplow/browser-plugin-form-tracking diff --git a/plugins/browser-plugin-form-tracking/jest.config.js b/plugins/browser-plugin-form-tracking/jest.config.js new file mode 100644 index 000000000..87d15da9b --- /dev/null +++ b/plugins/browser-plugin-form-tracking/jest.config.js @@ -0,0 +1,6 @@ +module.exports = { + preset: 'ts-jest', + reporters: ['jest-standard-reporter'], + setupFilesAfterEnv: ['../../setupTestGlobals.ts'], + testEnvironment: 'jest-environment-jsdom-global', +}; diff --git a/plugins/browser-plugin-form-tracking/package.json b/plugins/browser-plugin-form-tracking/package.json new file mode 100644 index 000000000..23afb48b3 --- /dev/null +++ b/plugins/browser-plugin-form-tracking/package.json @@ -0,0 +1,52 @@ +{ + "name": "@snowplow/browser-plugin-form-tracking", + "version": "4.10.0", + "description": "Form tracking for Snowplow", + "homepage": "http://bit.ly/sp-js", + "bugs": "https://github.com/snowplow/snowplow-javascript-tracker/issues", + "repository": { + "type": "git", + "url": "https://github.com/snowplow/snowplow-javascript-tracker.git" + }, + "license": "BSD-3-Clause", + "author": "Paul Boocock", + "sideEffects": false, + "main": "./dist/index.umd.js", + "module": "./dist/index.module.js", + "types": "./dist/index.module.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "rollup -c --silent --failAfterWarnings", + "test": "jest" + }, + "dependencies": { + "@snowplow/browser-tracker-core": "workspace:*", + "@snowplow/tracker-core": "workspace:*", + "tslib": "^2.3.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "~21.0.2", + "@rollup/plugin-node-resolve": "~13.1.3", + "@types/jest": "~28.1.1", + "@types/jsdom": "~16.2.14", + "@typescript-eslint/eslint-plugin": "~5.15.0", + "@typescript-eslint/parser": "~5.15.0", + "eslint": "~8.11.0", + "jest": "~28.1.3", + "jest-environment-jsdom": "~28.1.3", + "jest-environment-jsdom-global": "~4.0.0", + "jest-standard-reporter": "~2.0.0", + "rollup": "~2.70.1", + "rollup-plugin-cleanup": "~3.2.1", + "rollup-plugin-license": "~2.6.1", + "rollup-plugin-terser": "~7.0.2", + "rollup-plugin-ts": "~2.0.5", + "ts-jest": "~28.0.8", + "typescript": "~4.6.2" + }, + "peerDependencies": { + "@snowplow/browser-tracker": "~4.10.0" + } +} diff --git a/plugins/browser-plugin-form-tracking/rollup.config.js b/plugins/browser-plugin-form-tracking/rollup.config.js new file mode 100644 index 000000000..48aa953de --- /dev/null +++ b/plugins/browser-plugin-form-tracking/rollup.config.js @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import ts from 'rollup-plugin-ts'; // Prefered over @rollup/plugin-typescript as it bundles .d.ts files +import { banner } from '../../banner'; +import { terser } from 'rollup-plugin-terser'; +import cleanup from 'rollup-plugin-cleanup'; +import pkg from './package.json'; +import { builtinModules } from 'module'; + +const umdPlugins = [nodeResolve({ browser: true }), commonjs(), ts()]; +const umdName = 'snowplowFormTracking'; + +export default [ + // CommonJS (for Node) and ES module (for bundlers) build. + { + input: './src/index.ts', + plugins: [...umdPlugins, banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main, format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + plugins: [...umdPlugins, terser(), cleanup({ comments: 'none' }), banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main.replace('.js', '.min.js'), format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + external: [...builtinModules, ...Object.keys(pkg.dependencies), ...Object.keys(pkg.devDependencies)], + plugins: [ + ts(), // so Rollup can convert TypeScript to JavaScript + banner(), + ], + output: [{ file: pkg.module, format: 'es', sourcemap: true }], + }, +]; diff --git a/plugins/browser-plugin-form-tracking/src/helpers.ts b/plugins/browser-plugin-form-tracking/src/helpers.ts new file mode 100644 index 000000000..6153fee67 --- /dev/null +++ b/plugins/browser-plugin-form-tracking/src/helpers.ts @@ -0,0 +1,452 @@ +import { + addEventListener, + flushPendingCookies, + getCssClasses, + getFilterByClass, + getFilterByName, + type BrowserTracker, + type FilterCriterion, +} from '@snowplow/browser-tracker-core'; +import { + buildFormFocusOrChange, + buildFormSubmission, + resolveDynamicContext, + type DynamicContext, +} from '@snowplow/tracker-core'; + +/** The form tracking configuration */ +export interface FormTrackingConfiguration { + /** The options which can be configured for the form tracking events */ + options?: FormTrackingOptions; + /** The dyanmic context which will be evaluated for each form event */ + context?: DynamicContext | null; +} + +/** Events to capture in form tracking */ +enum FormTrackingEvent { + /** Form field changed event */ + CHANGE_FORM = 'change_form', + /** Form field focused event */ + FOCUS_FORM = 'focus_form', + /** Form submitted event */ + SUBMIT_FORM = 'submit_form', +} + +const defaultFormTrackingEvents = [ + FormTrackingEvent.CHANGE_FORM, + FormTrackingEvent.FOCUS_FORM, + FormTrackingEvent.SUBMIT_FORM, +]; + +/** Form tracking plugin options to determine which events to fire and the elements to listen for */ +interface FormTrackingOptions { + /** Whether to handle events in the capture phase or the bubbling phase. Capture is usually more reliable, but may trigger early if you need changes from other submit handlers in your transforms, filters, or context generators. Defaults to true. */ + useCapture?: boolean; + /** List of `form` elements that are allowed to generate events, or criteria for deciding that when the event listener handles the event */ + forms?: + | FilterCriterion + | HTMLCollectionOf + | NodeListOf + | HTMLFormElement[]; + /** Criteria for fields within forms that should generate focus or change events; you may also include a transformation function for fields that may include personal data */ + fields?: FilterCriterion & { transform?: transformFn }; + /** Allow list of events to enable tracking for; can be any combination of focus_form, change_form, or submit_form */ + events?: `${FormTrackingEvent}`[]; + /** A list of targets to add event listeners to. If not provided, defaults to the current `document` */ + targets?: EventTarget[]; +} + +type TrackedHTMLElementTagNameMap = Pick; + +type TrackedHTMLElement = TrackedHTMLElementTagNameMap[keyof TrackedHTMLElementTagNameMap]; + +interface ElementData extends Record { + name: string; + value: string | null; + nodeName: string; + type?: string; +} + +type transformFn = ( + elementValue: string | null, + elementInfo: ElementData | TrackedHTMLElement, + elt: TrackedHTMLElement +) => string | null; + +type ElementDataWrapper = { elementData: ElementData; originalElement: TrackedHTMLElement }; + +const defaultTransformFn: transformFn = (x) => x; + +interface FormConfiguration { + formFilter: (_: HTMLFormElement) => boolean; + fieldFilter: (_: TrackedHTMLElement) => boolean; + fieldTransform: transformFn; + forms: HTMLCollectionOf | NodeListOf | HTMLFormElement[] | null; +} + +const _focusListeners: Record = {}; +const _changeListeners: Record = {}; +const _submitListeners: Record = {}; +const _targets: Record = {}; +const _captures: Record = {}; + +/** + * Add submission/focus/change event listeners to page for forms and elements according to `configuration` + * + * @param tracker The tracker instance the listener belongs to that will be used to track events + * @param configuration Plugin configuration controlling the events to track and forms/fields to target or transform + */ +export function addFormListeners(tracker: BrowserTracker, configuration: FormTrackingConfiguration) { + const { options, context } = configuration, + config = getConfigurationForOptions(options); + + const events = options?.events ?? defaultFormTrackingEvents; + + const useCapture = (_captures[tracker.id] = options?.useCapture ?? true); + + const targets = (_targets[tracker.id] = getTargetList(options?.targets, config.forms)); + + if (events.indexOf(FormTrackingEvent.FOCUS_FORM) !== -1) { + _focusListeners[tracker.id] = getFormChangeListener(tracker, config, FormTrackingEvent.FOCUS_FORM, context); + targets.forEach((target) => addEventListener(target, 'focus', _focusListeners[tracker.id], true)); // focus does not bubble + } + if (events.indexOf(FormTrackingEvent.CHANGE_FORM) !== -1) { + _changeListeners[tracker.id] = getFormChangeListener(tracker, config, FormTrackingEvent.CHANGE_FORM, context); + targets.forEach((target) => addEventListener(target, 'change', _changeListeners[tracker.id], useCapture)); + } + if (events.indexOf(FormTrackingEvent.SUBMIT_FORM) !== -1) { + _submitListeners[tracker.id] = getFormSubmissionListener(tracker, config, context); + targets.forEach((target) => addEventListener(target, 'submit', _submitListeners[tracker.id], useCapture)); + } +} + +/** + * Builds a list of targets for the plugin event listeners + * + * The list can include any specifically provided targets, and will be extended to include the root nodes of any explicit HTMLFormElements provided + * With neither provided, defaults to the current page's `document` element + * + * @param configTargets Explicitly configured list of event target listeners, if any + * @param forms Explicitly configured list of form elements to track, if any + * @returns List of EventTargets to add the listener to + */ +function getTargetList(configTargets: EventTarget[] | undefined, forms: FormConfiguration['forms']) { + // we attach to document rather than window because the window focus event occurs more often than we require + const targets = configTargets ?? [document]; + + if (forms) { + Array.prototype.forEach.call(forms, (form: HTMLFormElement) => { + targets.push(form.ownerDocument.documentElement); + }); + } + + return targets; +} + +/** + * Remove all submission/focus/change event listeners from page that have been added via a call to `addFormListeners` + * + * @param tracker The tracker instance the listener belongs to that will be used to track events + */ +export function removeFormListeners(tracker: BrowserTracker) { + const targets = _targets[tracker.id] ?? [document]; + const useCapture = _captures[tracker.id] ?? true; + targets.forEach((target) => { + if (_focusListeners[tracker.id]) target.removeEventListener('focus', _focusListeners[tracker.id], true); // focus does not bubble + if (_changeListeners[tracker.id]) target.removeEventListener('change', _changeListeners[tracker.id], useCapture); + if (_submitListeners[tracker.id]) target.removeEventListener('submit', _submitListeners[tracker.id], useCapture); + }); +} + +/** + * Check if forms array is a collection of HTML form elements or a filter or undefined + */ +function isCollectionOfHTMLFormElements( + forms?: + | FilterCriterion + | HTMLCollectionOf + | NodeListOf + | HTMLFormElement[] +): forms is HTMLCollectionOf | NodeListOf | HTMLFormElement[] { + return forms != null && Array.prototype.slice.call(forms).length > 0; +} + +/** + * Typeguard for `element` to see if it appears to be the HTMLElement with tagName `type` + * + * instanceof checks don't work for cross-document nodes, which this plugin supports + * + * @param elem Object to check element type + * @param type Element type we're checking for + * @returns If `element` is an element with tagName `type` + */ +function isElement>( + elem: unknown, + type: E +): elem is HTMLElementTagNameMap[Lowercase] { + if (typeof elem === 'object' && elem) { + if ('tagName' in elem && typeof (elem as Element)['tagName'] === 'string') { + return (elem as Element).tagName.toUpperCase() === type; + } + } + + return false; +} + +/** + * Determine if given object is a `TrackedHTMLElement` or not + * + * @param element Value to determine + * @returns If `element` is `TrackedHTMLElement` + */ +function isTrackableElement(element: EventTarget | null): element is TrackedHTMLElement { + return isElement(element, 'INPUT') || isElement(element, 'SELECT') || isElement(element, 'TEXTAREA'); +} + +/** + * Configures form tracking: which forms and fields will be tracked, and the context to attach + * + * @param options User-supplied configuration + * @returns Final configuration incorporating defaults + */ +function getConfigurationForOptions(options?: FormTrackingOptions): FormConfiguration { + if (options) { + let formFilter = (_: HTMLElement) => true; + let forms: HTMLCollectionOf | NodeListOf | HTMLFormElement[] | null = null; + if (isCollectionOfHTMLFormElements(options.forms)) { + // options.forms is an explicity allowlist of HTML form elements + forms = options.forms; + } else { + // options.forms is null or a filter + formFilter = getFilterByClass(options.forms); + } + return { + forms, + formFilter, + fieldFilter: getFilterByName(options.fields), + fieldTransform: getTransform(options.fields), + }; + } else { + return { + forms: null, + formFilter: () => true, + fieldFilter: () => true, + fieldTransform: defaultTransformFn, + }; + } +} + +/** + * Check if the found target element is included in the explicit form allowlist, if provided. + * + * @param target A `form` element to check if we're allowed to track. + * @param allowed An optional list of form elements we want to track against. + * @returns True if there is no allowlist or the `target` is in the allowlist, false otherwise. + */ +function explicitlyAllowedForm(target: HTMLFormElement, allowed: FormConfiguration['forms']) { + if (!allowed) return true; + + for (let i = 0; i < allowed.length; i++) { + if (allowed[i].isSameNode(target)) return true; + } + + return false; +} + +/** + * Convert a criterion object to a transform function + * + * @param criterion + * @returns Transformation function if provided in `criterion`, or a default identity function + */ +function getTransform(criterion?: { transform?: transformFn }): transformFn { + if (criterion && typeof criterion.transform === 'function') { + return criterion.transform; + } + + return defaultTransformFn; +} + +/** + * Get an identifier for a form or `TrackedHTMLElement` + * + * @param elt Element to identify + * @returns Identifier for `elt` + */ +function getElementIdentifier(elt: Record) { + const properties = ['name', 'id', 'type', 'nodeName'] as const; + for (const propName of properties) { + if (elt[propName] && typeof elt[propName] === 'string') { + return elt[propName]; + } + } + + return null; +} + +/** + * Discovers the parent form in which an element is contained + * + * @param elt Child control to identify the owning form for + * @returns The form element this control belongs to or null if not found + */ +function getParentForm(elt: TrackedHTMLElement | null) { + if (elt && elt.form) return elt.form; + + let parent: ParentNode | null = elt; + + while (parent) { + if (isElement(parent, 'FORM')) { + return parent; + } + parent = parent.parentNode; + } + + return parent; +} + +/** + * Returns a list of the `TrackedHTMLElement`s inside a form along with their values + * + * @param elt Form element to get the control elements for + * @returns Array of wrapped control elements belonging to the form + */ +function getInnerFormElements(elt: HTMLFormElement) { + const innerElements: Array = []; + + Array.prototype.forEach.call(elt.elements, function (child: Element) { + if (!isTrackableElement(child)) return; + + const inputType = (child.type || 'text').toLowerCase(); + + // submit and image are roughly equivalent + if (inputType === 'submit' || inputType === 'image') { + return; + } + + const elementJson: ElementDataWrapper = { + elementData: { + name: getElementIdentifier(child)!, + value: child.value, + nodeName: child.nodeName, + }, + originalElement: child, + }; + + if (isElement(child, 'INPUT')) { + elementJson.elementData.type = inputType; + + if (inputType === 'password' || ((inputType === 'checkbox' || inputType === 'radio') && !child.checked)) { + elementJson.elementData.value = null; + } + } + + innerElements.push(elementJson); + }); + + return innerElements; +} + +/** + * Create closure function to handle form field change/focus event + * + * @param tracker The tracker instance to generate the event with + * @param config Plugin configuration + * @param event_type Type of event to generate + * @param context List of entities or context generators to evaluate with the event + * @returns A form change/focus handler + */ +function getFormChangeListener( + tracker: BrowserTracker, + config: FormConfiguration, + event_type: Exclude, + context?: DynamicContext | null +) { + return function (e: Event) { + const target = e.composed ? e.composedPath()[0] : e.target; + + // `change` and `submit` are not composed and are thus invisible to us + // bind late to the forms/field directly on field focus in this case + if (target !== e.target && e.composed && isTrackableElement(target)) { + if (target.form) { + if (_changeListeners[tracker.id]) + addEventListener(target.form, 'change', _changeListeners[tracker.id], _captures[tracker.id]); + if (_submitListeners[tracker.id]) + addEventListener(target.form, 'submit', _submitListeners[tracker.id], _captures[tracker.id]); + } else { + if (_changeListeners[tracker.id]) + addEventListener(target, 'change', _changeListeners[tracker.id], _captures[tracker.id]); + } + } + + if (isTrackableElement(target) && config.fieldFilter(target)) { + let value: string | null = null; + let type: string | null = null; + + if (isElement(target, 'INPUT')) { + type = (target.type || 'text').toLowerCase(); + value = + (type === 'checkbox' && !target.checked) || type === 'password' + ? null + : config.fieldTransform(target.value, target, target); + } else { + value = config.fieldTransform(target.value, target, target); + } + + const form = getParentForm(target); + if (!(form && config.formFilter(form) && explicitlyAllowedForm(form, config.forms))) return; + + if (event_type === 'change_form' || (type !== 'checkbox' && type !== 'radio')) { + tracker.core.track( + buildFormFocusOrChange({ + schema: event_type, + formId: getElementIdentifier(form ?? {}) ?? '', + elementId: getElementIdentifier(target) ?? '', + nodeName: target.nodeName, + type, + elementClasses: getCssClasses(target), + value: value ?? null, + }), + resolveDynamicContext(context, target, type, value) + ); + } + } + }; +} + +/** + * Create closure function to handle form submission event + * + * @param tracker The tracker instance to generate the event with + * @param config Plugin configuration + * @param context List of entities or context generators to evaluate with the event + * @returns A form submit handler + */ +function getFormSubmissionListener( + tracker: BrowserTracker, + config: FormConfiguration, + context?: DynamicContext | null +) { + return function ({ target }: Event) { + if (isElement(target, 'FORM') && config.formFilter(target) && explicitlyAllowedForm(target, config.forms)) { + const elementsData: ElementData[] = []; + + getInnerFormElements(target).forEach(function ({ elementData, originalElement }) { + if (config.fieldFilter(originalElement) && originalElement.type.toLowerCase() !== 'password') { + elementData.value = config.fieldTransform(elementData.value, elementData, originalElement); + elementsData.push(elementData); + } + }); + + tracker.core.track( + buildFormSubmission({ + formId: getElementIdentifier(target) ?? '', + formClasses: getCssClasses(target), + elements: elementsData, + }), + resolveDynamicContext(context, target, elementsData) + ); + flushPendingCookies(); + } + }; +} diff --git a/plugins/browser-plugin-form-tracking/src/index.ts b/plugins/browser-plugin-form-tracking/src/index.ts new file mode 100644 index 000000000..8649dc16a --- /dev/null +++ b/plugins/browser-plugin-form-tracking/src/index.ts @@ -0,0 +1,53 @@ +import type { BrowserPlugin, BrowserTracker } from '@snowplow/browser-tracker-core'; +import { addFormListeners, removeFormListeners, type FormTrackingConfiguration } from './helpers'; + +export { type FormTrackingConfiguration } from './helpers'; + +const _trackers: Record = {}; + +/** + * A plugin which enables automatic form focus, change, and submit tracking + */ +export function FormTrackingPlugin(): BrowserPlugin { + return { + activateBrowserPlugin: (tracker: BrowserTracker) => { + _trackers[tracker.id] = tracker; + }, + }; +} + +/** + * Enables automatic form tracking. + * + * An event will be fired when a form field is changed or a form submitted. + * This can be called multiple times: previous listeners will be removed and replaced with any updated configuration. + * + * @param configuration - The form tracking configuration + * @param trackers - The tracker identifiers which the events will be sent to + */ +export function enableFormTracking( + configuration: FormTrackingConfiguration = {}, + trackers: Array = Object.keys(_trackers) +) { + trackers.forEach((t) => { + if (_trackers[t]) { + removeFormListeners(_trackers[t]); + addFormListeners(_trackers[t], configuration); + } + }); +} + +/** + * Disables automatic form tracking. + * + * All page-level listeners for the given trackers will be removed. + * + * @param trackers - The tracker identifiers which the events will be sent to + */ +export function disableFormTracking(trackers: Array = Object.keys(_trackers)) { + trackers.forEach((t) => { + if (_trackers[t]) { + removeFormListeners(_trackers[t]); + } + }); +} diff --git a/plugins/browser-plugin-form-tracking/test/events.test.ts b/plugins/browser-plugin-form-tracking/test/events.test.ts new file mode 100644 index 000000000..fb1f7acf4 --- /dev/null +++ b/plugins/browser-plugin-form-tracking/test/events.test.ts @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { addTracker, SharedState } from '@snowplow/browser-tracker-core'; +import { enableFormTracking, disableFormTracking, FormTrackingPlugin } from '../src'; +import { newInMemoryEventStore } from '@snowplow/tracker-core'; + +const getUEEvents = (arr: any) => arr.filter(({ e }: any) => e === 'ue'); +const extractEventProperties = (arr: any) => arr.map(({ ue_pr }: any) => JSON.parse(ue_pr).data); +const extractUeEvent = (schema: string) => ({ + from: (arr: any, n: number = 0) => + extractEventProperties(getUEEvents(arr)) + .reduce((acc: any[], curr: any[]) => acc.concat([curr]), []) + .filter((evt: any) => evt.schema === schema)[n], +}); + +describe('FormTrackingPlugin', () => { + const eventStore = newInMemoryEventStore({}); + addTracker('sp1', 'sp1', 'js-3.0.0', '', new SharedState(), { + stateStorageStrategy: 'cookie', + encodeBase64: false, + plugins: [FormTrackingPlugin()], + eventStore, + customFetch: async () => new Response(null, { status: 500 }), + }); + + const $addEventListener = jest.spyOn(document, 'addEventListener'); + const $removeEventListener = jest.spyOn(document, 'removeEventListener'); + + document.body.appendChild(Object.assign(document.createElement('form'), { id: 'test-form' })); + + afterEach(async () => { + // clear the event store after each test + await eventStore.removeHead(await eventStore.count()); + jest.clearAllMocks(); + document.forms[0].replaceChildren(); + }); + + describe('enableFormTracking', () => { + it('does nothing for no trackers', () => { + enableFormTracking({}, []); + expect($addEventListener).not.toBeCalled(); + }); + + it('adds form listeners by default', () => { + enableFormTracking(); + + expect($addEventListener).toBeCalledWith('focus', expect.anything(), true); + expect($addEventListener).toBeCalledWith('change', expect.anything(), true); + expect($addEventListener).toBeCalledWith('submit', expect.anything(), true); + }); + + it('tracks focus on fields that already exist', async () => { + const target = document.createElement('input'); + document.forms[0].appendChild(target); + + enableFormTracking(); + + target.focus(); + + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/focus_form/jsonschema/1-0-0').from( + await eventStore.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/focus_form/jsonschema/1-0-0', + data: { + formId: 'test-form', + }, + }); + }); + + it('tracks focus on fields added after enabling', async () => { + enableFormTracking(); + + const target = document.createElement('input'); + document.forms[0].appendChild(target); + + target.focus(); + + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/focus_form/jsonschema/1-0-0').from( + await eventStore.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/focus_form/jsonschema/1-0-0', + data: { + formId: 'test-form', + }, + }); + }); + + it('tracks changes on field values', async () => { + enableFormTracking(); + + const target = document.createElement('input'); + document.forms[0].appendChild(target); + + target.value = 'changed'; + target.dispatchEvent(new Event('change')); + + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/change_form/jsonschema/1-0-0').from( + await eventStore.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/change_form/jsonschema/1-0-0', + data: { + formId: 'test-form', + value: 'changed', + }, + }); + }); + + it('tracks from forms in shadowdom', async () => { + window.customElements.define( + 'shadow-form', + class extends HTMLElement { + connectedCallback() { + const form = Object.assign(document.createElement('form'), { id: 'shadow-form' }); + + form.addEventListener( + 'submit', + function (e) { + e.preventDefault(); + }, + false + ); + + const input = document.createElement('input'); + form.appendChild(input); + + const shadowRoot = this.attachShadow({ mode: 'open' }); + shadowRoot.appendChild(form); + } + } + ); + + const shadow = document.createElement('shadow-form'); + document.body.appendChild(shadow); + + enableFormTracking(); + + const target = shadow.shadowRoot!.querySelector('input')!; + + target.focus(); + + target.value = 'changed'; + target.dispatchEvent(new Event('change')); + + target.form!.submit(); + + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/focus_form/jsonschema/1-0-0').from( + await eventStore.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/focus_form/jsonschema/1-0-0', + data: { + formId: 'shadow-form', + }, + }); + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/change_form/jsonschema/1-0-0').from( + await eventStore.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/change_form/jsonschema/1-0-0', + data: { + formId: 'shadow-form', + value: 'changed', + }, + }); + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/submit_form/jsonschema/1-0-0').from( + await eventStore.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/submit_form/jsonschema/1-0-0', + data: { + formId: 'shadow-form', + }, + }); + }); + + it('associates non-nested forms correctly', async () => { + enableFormTracking(); + + const target = document.createElement('input'); + target.setAttribute('form', 'test-form'); + document.body.appendChild(target); + + target.focus(); + + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/focus_form/jsonschema/1-0-0').from( + await eventStore.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/focus_form/jsonschema/1-0-0', + data: { + formId: 'test-form', + }, + }); + + document.body.removeChild(target); + }); + + it('ignores password values', async () => { + enableFormTracking(); + + const target = document.createElement('input'); + target.type = 'password'; + target.value = 'initial'; + document.forms[0].appendChild(target); + + target.focus(); + target.value = 'zomg_private!1'; + target.dispatchEvent(new Event('change')); + + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/focus_form/jsonschema/1-0-0').from( + await eventStore.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/focus_form/jsonschema/1-0-0', + data: { + formId: 'test-form', + nodeName: 'INPUT', + elementType: 'password', + value: null, + }, + }); + + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/change_form/jsonschema/1-0-0').from( + await eventStore.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/change_form/jsonschema/1-0-0', + data: { + formId: 'test-form', + nodeName: 'INPUT', + type: 'password', + value: null, + }, + }); + }); + + it('does not listen for ignored event types', () => { + enableFormTracking({ options: { events: ['focus_form'] } }); + expect($addEventListener).toBeCalledTimes(1); + expect($addEventListener).toBeCalledWith('focus', expect.anything(), true); + }); + + it('ignores form that are not explicitly specified', async () => { + const extra = document.createElement('form'); + extra.id = 'skipme'; + document.body.appendChild(extra); + + enableFormTracking({ options: { forms: [document.forms[0]] } }); + + let target = document.createElement('input'); + extra.appendChild(target); + target.focus(); + + expect(await eventStore.getAllPayloads()).toHaveLength(0); + + target = document.createElement('input'); + document.forms[0].appendChild(target); + target.focus(); + + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/focus_form/jsonschema/1-0-0').from( + await eventStore.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/focus_form/jsonschema/1-0-0', + data: { + formId: 'test-form', + }, + }); + + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/focus_form/jsonschema/1-0-0').from( + await eventStore.getAllPayloads() + ) + ).not.toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/focus_form/jsonschema/1-0-0', + data: { + formId: 'skipme', + }, + }); + + document.body.removeChild(extra); + }); + }); + + describe('disableFormTracking', () => { + it('removes any listeners added', () => { + enableFormTracking(); + disableFormTracking(); + + const addCalls = $addEventListener.mock.calls; + + expect(addCalls).toHaveLength(3); + + addCalls.forEach((call) => expect($removeEventListener.mock.calls).toContainEqual(call)); + }); + }); +}); diff --git a/plugins/browser-plugin-form-tracking/tsconfig.json b/plugins/browser-plugin-form-tracking/tsconfig.json new file mode 100644 index 000000000..4082f16a5 --- /dev/null +++ b/plugins/browser-plugin-form-tracking/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +} diff --git a/plugins/browser-plugin-ga-cookies/CHANGELOG.json b/plugins/browser-plugin-ga-cookies/CHANGELOG.json new file mode 100644 index 000000000..71375c2c5 --- /dev/null +++ b/plugins/browser-plugin-ga-cookies/CHANGELOG.json @@ -0,0 +1,611 @@ +{ + "name": "@snowplow/browser-plugin-ga-cookies", + "entries": [ + { + "version": "4.10.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.10.0", + "date": "Mon, 27 Jul 2026 13:52:14 GMT", + "comments": {} + }, + { + "version": "4.9.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.9.0", + "date": "Tue, 21 Jul 2026 14:53:08 GMT", + "comments": {} + }, + { + "version": "4.8.4", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.8.4", + "date": "Thu, 02 Jul 2026 10:07:52 GMT", + "comments": {} + }, + { + "version": "4.8.3", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.8.3", + "date": "Tue, 30 Jun 2026 14:22:03 GMT", + "comments": { + "none": [ + { + "comment": "Update uuid to v11 and remove closure-compiler from the build pipeline" + } + ] + } + }, + { + "version": "4.8.2", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.8.2", + "date": "Wed, 17 Jun 2026 12:30:12 GMT", + "comments": {} + }, + { + "version": "4.8.1", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.8.1", + "date": "Wed, 13 May 2026 09:26:05 GMT", + "comments": {} + }, + { + "version": "4.8.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.8.0", + "date": "Tue, 28 Apr 2026 07:56:22 GMT", + "comments": {} + }, + { + "version": "4.7.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.7.0", + "date": "Wed, 01 Apr 2026 12:59:29 GMT", + "comments": {} + }, + { + "version": "4.6.9", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.6.9", + "date": "Mon, 16 Mar 2026 15:43:06 GMT", + "comments": {} + }, + { + "version": "4.6.8", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.6.8", + "date": "Tue, 28 Oct 2025 09:46:42 GMT", + "comments": {} + }, + { + "version": "4.6.7", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.6.7", + "date": "Tue, 07 Oct 2025 14:53:36 GMT", + "comments": {} + }, + { + "version": "4.6.6", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.6.6", + "date": "Tue, 26 Aug 2025 08:42:27 GMT", + "comments": {} + }, + { + "version": "4.6.5", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.6.5", + "date": "Wed, 25 Jun 2025 21:16:46 GMT", + "comments": {} + }, + { + "version": "4.6.4", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.6.4", + "date": "Wed, 25 Jun 2025 12:08:50 GMT", + "comments": {} + }, + { + "version": "4.6.3", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.6.3", + "date": "Thu, 29 May 2025 19:52:07 GMT", + "comments": {} + }, + { + "version": "4.6.2", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.6.2", + "date": "Tue, 20 May 2025 07:39:05 GMT", + "comments": {} + }, + { + "version": "4.6.1", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.6.1", + "date": "Tue, 06 May 2025 13:10:51 GMT", + "comments": {} + }, + { + "version": "4.6.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.6.0", + "date": "Thu, 01 May 2025 09:58:59 GMT", + "comments": {} + }, + { + "version": "4.5.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.5.0", + "date": "Fri, 04 Apr 2025 09:21:23 GMT", + "comments": {} + }, + { + "version": "4.4.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.4.0", + "date": "Thu, 20 Mar 2025 12:14:34 GMT", + "comments": {} + }, + { + "version": "4.3.1", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.3.1", + "date": "Tue, 21 Jan 2025 11:09:42 GMT", + "comments": {} + }, + { + "version": "4.3.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.3.0", + "date": "Mon, 20 Jan 2025 11:45:13 GMT", + "comments": {} + }, + { + "version": "4.2.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.2.0", + "date": "Mon, 13 Jan 2025 08:30:05 GMT", + "comments": {} + }, + { + "version": "4.1.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.1.0", + "date": "Thu, 28 Nov 2024 10:57:30 GMT", + "comments": {} + }, + { + "version": "4.0.4", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.0.4", + "date": "Thu, 21 Nov 2024 09:06:36 GMT", + "comments": {} + }, + { + "version": "4.0.3", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.0.3", + "date": "Wed, 20 Nov 2024 09:30:31 GMT", + "comments": {} + }, + { + "version": "4.0.2", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.0.2", + "date": "Mon, 11 Nov 2024 15:46:34 GMT", + "comments": {} + }, + { + "version": "4.0.1", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.0.1", + "date": "Fri, 01 Nov 2024 10:35:07 GMT", + "comments": {} + }, + { + "version": "4.0.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v4.0.0", + "date": "Mon, 28 Oct 2024 11:48:53 GMT", + "comments": { + "none": [ + { + "comment": "Change default from UA to GA4" + } + ] + } + }, + { + "version": "3.24.6", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.24.6", + "date": "Mon, 28 Oct 2024 10:23:28 GMT", + "comments": {} + }, + { + "version": "3.24.5", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.24.5", + "date": "Fri, 25 Oct 2024 08:53:04 GMT", + "comments": {} + }, + { + "version": "3.24.4", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.24.4", + "date": "Thu, 26 Sep 2024 06:10:22 GMT", + "comments": {} + }, + { + "version": "3.24.3", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.24.3", + "date": "Tue, 03 Sep 2024 08:15:14 GMT", + "comments": { + "none": [ + { + "comment": "Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush" + } + ] + } + }, + { + "version": "3.24.2", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.24.2", + "date": "Wed, 24 Jul 2024 08:59:00 GMT", + "comments": {} + }, + { + "version": "3.24.1", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.24.1", + "date": "Tue, 02 Jul 2024 07:08:17 GMT", + "comments": {} + }, + { + "version": "3.24.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.24.0", + "date": "Tue, 25 Jun 2024 08:31:05 GMT", + "comments": {} + }, + { + "version": "3.23.1", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.23.1", + "date": "Tue, 04 Jun 2024 13:34:45 GMT", + "comments": {} + }, + { + "version": "3.23.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.23.0", + "date": "Thu, 28 Mar 2024 11:28:45 GMT", + "comments": {} + }, + { + "version": "3.22.1", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.22.1", + "date": "Wed, 13 Mar 2024 08:39:48 GMT", + "comments": {} + }, + { + "version": "3.22.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.22.0", + "date": "Fri, 08 Mar 2024 08:13:04 GMT", + "comments": {} + }, + { + "version": "3.21.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.21.0", + "date": "Mon, 29 Jan 2024 08:34:06 GMT", + "comments": {} + }, + { + "version": "3.20.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.20.0", + "date": "Mon, 15 Jan 2024 14:41:16 GMT", + "comments": {} + }, + { + "version": "3.19.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.19.0", + "date": "Thu, 14 Dec 2023 10:45:22 GMT", + "comments": {} + }, + { + "version": "3.18.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.18.0", + "date": "Mon, 04 Dec 2023 13:44:02 GMT", + "comments": {} + }, + { + "version": "3.17.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.17.0", + "date": "Tue, 14 Nov 2023 17:58:26 GMT", + "comments": { + "none": [ + { + "comment": "Update to include options for Google Analytics 4 cookies" + } + ] + } + }, + { + "version": "3.16.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.16.0", + "date": "Mon, 16 Oct 2023 14:58:08 GMT", + "comments": {} + }, + { + "version": "3.15.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.15.0", + "date": "Mon, 28 Aug 2023 14:25:14 GMT", + "comments": {} + }, + { + "version": "3.14.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.14.0", + "date": "Thu, 10 Aug 2023 13:56:44 GMT", + "comments": {} + }, + { + "version": "3.13.1", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.13.1", + "date": "Thu, 29 Jun 2023 14:20:06 GMT", + "comments": {} + }, + { + "version": "3.13.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.13.0", + "date": "Tue, 20 Jun 2023 07:44:23 GMT", + "comments": {} + }, + { + "version": "3.12.1", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.12.1", + "date": "Thu, 15 Jun 2023 10:05:37 GMT", + "comments": {} + }, + { + "version": "3.12.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.12.0", + "date": "Mon, 05 Jun 2023 11:51:22 GMT", + "comments": {} + }, + { + "version": "3.11.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.11.0", + "date": "Wed, 24 May 2023 15:56:17 GMT", + "comments": {} + }, + { + "version": "3.10.1", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.10.1", + "date": "Fri, 12 May 2023 06:59:31 GMT", + "comments": {} + }, + { + "version": "3.10.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.10.0", + "date": "Thu, 11 May 2023 08:29:15 GMT", + "comments": {} + }, + { + "version": "3.9.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.9.0", + "date": "Thu, 30 Mar 2023 13:46:56 GMT", + "comments": {} + }, + { + "version": "3.8.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.8.0", + "date": "Tue, 03 Jan 2023 15:36:33 GMT", + "comments": {} + }, + { + "version": "3.7.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.7.0", + "date": "Mon, 31 Oct 2022 06:26:28 GMT", + "comments": {} + }, + { + "version": "3.6.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.6.0", + "date": "Thu, 15 Sep 2022 07:55:20 GMT", + "comments": {} + }, + { + "version": "3.5.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.5.0", + "date": "Fri, 10 Jun 2022 18:57:46 GMT", + "comments": {} + }, + { + "version": "3.4.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.4.0", + "date": "Thu, 07 Apr 2022 11:56:26 GMT", + "comments": { + "none": [ + { + "comment": "Bump dependencies (#1067)" + } + ] + } + }, + { + "version": "3.3.1", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.3.1", + "date": "Wed, 23 Feb 2022 19:27:40 GMT", + "comments": {} + }, + { + "version": "3.3.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.3.0", + "date": "Mon, 31 Jan 2022 15:58:10 GMT", + "comments": {} + }, + { + "version": "3.2.3", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.2.3", + "date": "Tue, 18 Jan 2022 16:23:52 GMT", + "comments": { + "none": [ + { + "comment": "Bump Copyright to 2022 (#1040)" + } + ] + } + }, + { + "version": "3.2.2", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.2.2", + "date": "Fri, 14 Jan 2022 10:17:59 GMT", + "comments": {} + }, + { + "version": "3.2.1", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.2.1", + "date": "Wed, 12 Jan 2022 09:50:29 GMT", + "comments": {} + }, + { + "version": "3.2.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.2.0", + "date": "Tue, 11 Jan 2022 12:53:22 GMT", + "comments": {} + }, + { + "version": "3.1.6", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.1.6", + "date": "Tue, 19 Oct 2021 09:17:22 GMT", + "comments": { + "none": [ + { + "comment": "Fix failing build on ARM Macs (#1012)" + } + ] + } + }, + { + "version": "3.1.5", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.1.5", + "date": "Fri, 01 Oct 2021 08:09:21 GMT", + "comments": {} + }, + { + "version": "3.1.4", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.1.4", + "date": "Tue, 21 Sep 2021 14:59:36 GMT", + "comments": {} + }, + { + "version": "3.1.3", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.1.3", + "date": "Mon, 23 Aug 2021 10:13:18 GMT", + "comments": {} + }, + { + "version": "3.1.2", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.1.2", + "date": "Mon, 16 Aug 2021 12:59:59 GMT", + "comments": { + "none": [ + { + "comment": "Update READMEs with correct Node requirements (#994)" + } + ] + } + }, + { + "version": "3.1.1", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.1.1", + "date": "Wed, 04 Aug 2021 10:12:25 GMT", + "comments": { + "none": [ + { + "comment": "Bump tslib to 2.3.0 (#986)" + }, + { + "comment": "Bump typescript to 4.3.5 (#987)" + }, + { + "comment": "Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988)" + } + ] + } + }, + { + "version": "3.1.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.1.0", + "date": "Fri, 14 May 2021 10:45:32 GMT", + "comments": {} + }, + { + "version": "3.0.3", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.0.3", + "date": "Wed, 21 Apr 2021 12:35:06 GMT", + "comments": {} + }, + { + "version": "3.0.2", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.0.2", + "date": "Thu, 15 Apr 2021 21:07:39 GMT", + "comments": {} + }, + { + "version": "3.0.1", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.0.1", + "date": "Wed, 14 Apr 2021 16:30:05 GMT", + "comments": { + "none": [ + { + "comment": "Add peerDependencies to plugins (#950)" + }, + { + "comment": "Mark packages as sideEffect: false (#951)" + }, + { + "comment": "Add unit tests to plugin track* functions (#954)" + } + ] + } + }, + { + "version": "3.0.0", + "tag": "@snowplow/browser-plugin-ga-cookies_v3.0.0", + "date": "Wed, 31 Mar 2021 14:46:47 GMT", + "comments": { + "none": [ + { + "comment": "Bump rollup to 2.41 (#916)" + }, + { + "comment": "Publish UMD versions of plugins to GitHub release (#923)" + }, + { + "comment": "Ensure browser-tracker API methods catch exceptions (#919)" + }, + { + "comment": "Introduce TSDoc comments and extract interfaces where appropriate (#906)" + }, + { + "comment": "Bump major version to v3 and update READMEs (#904)" + }, + { + "comment": "Improve Core API for module bundlers which support treeshaking (#903)" + }, + { + "comment": "Rename @snowplow/browser-core to @snowplow/browser-tracker-core (#901)" + }, + { + "comment": "Publish lite version of sp.js (#900)" + }, + { + "comment": "Ensure correct 3-Clause BSD License notices are being used (#316)" + }, + { + "comment": "Improve API for module bundlers which support treeshaking (#899)" + }, + { + "comment": "Bump rush to 5.39 (#895)" + }, + { + "comment": "Port to TypeScript (#72)" + }, + { + "comment": "Make sp.js build process modular (#450)" + }, + { + "comment": "Create @snowplow/browser-tracker package for npm distribution (#541)" + }, + { + "comment": "Split auto contexts into plugins (#880)" + }, + { + "comment": "Add rush to manage monorepo (#883)" + }, + { + "comment": "Add ES Module builds (#882)" + }, + { + "comment": "Cleanup deprecated methods (#557)" + }, + { + "comment": "Update publishing process for rush (#907)" + }, + { + "comment": "Change white and black lists to allow and deny lists (#908)" + }, + { + "comment": "Create rush change files for major version 3 release (#909)" + } + ] + } + } + ] +} diff --git a/plugins/browser-plugin-ga-cookies/CHANGELOG.md b/plugins/browser-plugin-ga-cookies/CHANGELOG.md new file mode 100644 index 000000000..3c3e4bb63 --- /dev/null +++ b/plugins/browser-plugin-ga-cookies/CHANGELOG.md @@ -0,0 +1,440 @@ +# Change Log - @snowplow/browser-plugin-ga-cookies + +This log was last generated on Mon, 27 Jul 2026 13:52:14 GMT and should not be manually modified. + +## 4.10.0 +Mon, 27 Jul 2026 13:52:14 GMT + +_Version update only_ + +## 4.9.0 +Tue, 21 Jul 2026 14:53:08 GMT + +_Version update only_ + +## 4.8.4 +Thu, 02 Jul 2026 10:07:52 GMT + +_Version update only_ + +## 4.8.3 +Tue, 30 Jun 2026 14:22:03 GMT + +### Updates + +- Update uuid to v11 and remove closure-compiler from the build pipeline + +## 4.8.2 +Wed, 17 Jun 2026 12:30:12 GMT + +_Version update only_ + +## 4.8.1 +Wed, 13 May 2026 09:26:05 GMT + +_Version update only_ + +## 4.8.0 +Tue, 28 Apr 2026 07:56:22 GMT + +_Version update only_ + +## 4.7.0 +Wed, 01 Apr 2026 12:59:29 GMT + +_Version update only_ + +## 4.6.9 +Mon, 16 Mar 2026 15:43:06 GMT + +_Version update only_ + +## 4.6.8 +Tue, 28 Oct 2025 09:46:42 GMT + +_Version update only_ + +## 4.6.7 +Tue, 07 Oct 2025 14:53:36 GMT + +_Version update only_ + +## 4.6.6 +Tue, 26 Aug 2025 08:42:27 GMT + +_Version update only_ + +## 4.6.5 +Wed, 25 Jun 2025 21:16:46 GMT + +_Version update only_ + +## 4.6.4 +Wed, 25 Jun 2025 12:08:50 GMT + +_Version update only_ + +## 4.6.3 +Thu, 29 May 2025 19:52:07 GMT + +_Version update only_ + +## 4.6.2 +Tue, 20 May 2025 07:39:05 GMT + +_Version update only_ + +## 4.6.1 +Tue, 06 May 2025 13:10:51 GMT + +_Version update only_ + +## 4.6.0 +Thu, 01 May 2025 09:58:59 GMT + +_Version update only_ + +## 4.5.0 +Fri, 04 Apr 2025 09:21:23 GMT + +_Version update only_ + +## 4.4.0 +Thu, 20 Mar 2025 12:14:34 GMT + +_Version update only_ + +## 4.3.1 +Tue, 21 Jan 2025 11:09:42 GMT + +_Version update only_ + +## 4.3.0 +Mon, 20 Jan 2025 11:45:13 GMT + +_Version update only_ + +## 4.2.0 +Mon, 13 Jan 2025 08:30:05 GMT + +_Version update only_ + +## 4.1.0 +Thu, 28 Nov 2024 10:57:30 GMT + +_Version update only_ + +## 4.0.4 +Thu, 21 Nov 2024 09:06:36 GMT + +_Version update only_ + +## 4.0.3 +Wed, 20 Nov 2024 09:30:31 GMT + +_Version update only_ + +## 4.0.2 +Mon, 11 Nov 2024 15:46:34 GMT + +_Version update only_ + +## 4.0.1 +Fri, 01 Nov 2024 10:35:07 GMT + +_Version update only_ + +## 4.0.0 +Mon, 28 Oct 2024 11:48:53 GMT + +### Updates + +- Change default from UA to GA4 + +## 3.24.6 +Mon, 28 Oct 2024 10:23:28 GMT + +_Version update only_ + +## 3.24.5 +Fri, 25 Oct 2024 08:53:04 GMT + +_Version update only_ + +## 3.24.4 +Thu, 26 Sep 2024 06:10:22 GMT + +_Version update only_ + +## 3.24.3 +Tue, 03 Sep 2024 08:15:14 GMT + +### Updates + +- Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush + +## 3.24.2 +Wed, 24 Jul 2024 08:59:00 GMT + +_Version update only_ + +## 3.24.1 +Tue, 02 Jul 2024 07:08:17 GMT + +_Version update only_ + +## 3.24.0 +Tue, 25 Jun 2024 08:31:05 GMT + +_Version update only_ + +## 3.23.1 +Tue, 04 Jun 2024 13:34:45 GMT + +_Version update only_ + +## 3.23.0 +Thu, 28 Mar 2024 11:28:45 GMT + +_Version update only_ + +## 3.22.1 +Wed, 13 Mar 2024 08:39:48 GMT + +_Version update only_ + +## 3.22.0 +Fri, 08 Mar 2024 08:13:04 GMT + +_Version update only_ + +## 3.21.0 +Mon, 29 Jan 2024 08:34:06 GMT + +_Version update only_ + +## 3.20.0 +Mon, 15 Jan 2024 14:41:16 GMT + +_Version update only_ + +## 3.19.0 +Thu, 14 Dec 2023 10:45:22 GMT + +_Version update only_ + +## 3.18.0 +Mon, 04 Dec 2023 13:44:02 GMT + +_Version update only_ + +## 3.17.0 +Tue, 14 Nov 2023 17:58:26 GMT + +### Updates + +- Update to include options for Google Analytics 4 cookies + +## 3.16.0 +Mon, 16 Oct 2023 14:58:08 GMT + +_Version update only_ + +## 3.15.0 +Mon, 28 Aug 2023 14:25:14 GMT + +_Version update only_ + +## 3.14.0 +Thu, 10 Aug 2023 13:56:44 GMT + +_Version update only_ + +## 3.13.1 +Thu, 29 Jun 2023 14:20:06 GMT + +_Version update only_ + +## 3.13.0 +Tue, 20 Jun 2023 07:44:23 GMT + +_Version update only_ + +## 3.12.1 +Thu, 15 Jun 2023 10:05:37 GMT + +_Version update only_ + +## 3.12.0 +Mon, 05 Jun 2023 11:51:22 GMT + +_Version update only_ + +## 3.11.0 +Wed, 24 May 2023 15:56:17 GMT + +_Version update only_ + +## 3.10.1 +Fri, 12 May 2023 06:59:31 GMT + +_Version update only_ + +## 3.10.0 +Thu, 11 May 2023 08:29:15 GMT + +_Version update only_ + +## 3.9.0 +Thu, 30 Mar 2023 13:46:56 GMT + +_Version update only_ + +## 3.8.0 +Tue, 03 Jan 2023 15:36:33 GMT + +_Version update only_ + +## 3.7.0 +Mon, 31 Oct 2022 06:26:28 GMT + +_Version update only_ + +## 3.6.0 +Thu, 15 Sep 2022 07:55:20 GMT + +_Version update only_ + +## 3.5.0 +Fri, 10 Jun 2022 18:57:46 GMT + +_Version update only_ + +## 3.4.0 +Thu, 07 Apr 2022 11:56:26 GMT + +### Updates + +- Bump dependencies (#1067) + +## 3.3.1 +Wed, 23 Feb 2022 19:27:40 GMT + +_Version update only_ + +## 3.3.0 +Mon, 31 Jan 2022 15:58:10 GMT + +_Version update only_ + +## 3.2.3 +Tue, 18 Jan 2022 16:23:52 GMT + +### Updates + +- Bump Copyright to 2022 (#1040) + +## 3.2.2 +Fri, 14 Jan 2022 10:17:59 GMT + +_Version update only_ + +## 3.2.1 +Wed, 12 Jan 2022 09:50:29 GMT + +_Version update only_ + +## 3.2.0 +Tue, 11 Jan 2022 12:53:22 GMT + +_Version update only_ + +## 3.1.6 +Tue, 19 Oct 2021 09:17:22 GMT + +### Updates + +- Fix failing build on ARM Macs (#1012) + +## 3.1.5 +Fri, 01 Oct 2021 08:09:21 GMT + +_Version update only_ + +## 3.1.4 +Tue, 21 Sep 2021 14:59:36 GMT + +_Version update only_ + +## 3.1.3 +Mon, 23 Aug 2021 10:13:18 GMT + +_Version update only_ + +## 3.1.2 +Mon, 16 Aug 2021 12:59:59 GMT + +### Updates + +- Update READMEs with correct Node requirements (#994) + +## 3.1.1 +Wed, 04 Aug 2021 10:12:25 GMT + +### Updates + +- Bump tslib to 2.3.0 (#986) +- Bump typescript to 4.3.5 (#987) +- Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988) + +## 3.1.0 +Fri, 14 May 2021 10:45:32 GMT + +_Version update only_ + +## 3.0.3 +Wed, 21 Apr 2021 12:35:06 GMT + +_Version update only_ + +## 3.0.2 +Thu, 15 Apr 2021 21:07:39 GMT + +_Version update only_ + +## 3.0.1 +Wed, 14 Apr 2021 16:30:05 GMT + +### Updates + +- Add peerDependencies to plugins (#950) +- Mark packages as sideEffect: false (#951) +- Add unit tests to plugin track* functions (#954) + +## 3.0.0 +Wed, 31 Mar 2021 14:46:47 GMT + +### Updates + +- Bump rollup to 2.41 (#916) +- Publish UMD versions of plugins to GitHub release (#923) +- Ensure browser-tracker API methods catch exceptions (#919) +- Introduce TSDoc comments and extract interfaces where appropriate (#906) +- Bump major version to v3 and update READMEs (#904) +- Improve Core API for module bundlers which support treeshaking (#903) +- Rename @snowplow/browser-core to @snowplow/browser-tracker-core (#901) +- Publish lite version of sp.js (#900) +- Ensure correct 3-Clause BSD License notices are being used (#316) +- Improve API for module bundlers which support treeshaking (#899) +- Bump rush to 5.39 (#895) +- Port to TypeScript (#72) +- Make sp.js build process modular (#450) +- Create @snowplow/browser-tracker package for npm distribution (#541) +- Split auto contexts into plugins (#880) +- Add rush to manage monorepo (#883) +- Add ES Module builds (#882) +- Cleanup deprecated methods (#557) +- Update publishing process for rush (#907) +- Change white and black lists to allow and deny lists (#908) +- Create rush change files for major version 3 release (#909) + diff --git a/plugins/browser-plugin-ga-cookies/LICENSE b/plugins/browser-plugin-ga-cookies/LICENSE new file mode 100644 index 000000000..76f1946ea --- /dev/null +++ b/plugins/browser-plugin-ga-cookies/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/plugins/browser-plugin-ga-cookies/README.md b/plugins/browser-plugin-ga-cookies/README.md new file mode 100644 index 000000000..05bd088f2 --- /dev/null +++ b/plugins/browser-plugin-ga-cookies/README.md @@ -0,0 +1,66 @@ +# Snowplow GA Cookies Tracking + +[![npm version][npm-image]][npm-url] +[![License][license-image]](LICENSE) + +Browser Plugin to be used with `@snowplow/browser-tracker`. + +Adds Google Analytics 4 and optionally Universal Analytics cookies to your Snowplow tracking. + +## Maintainer quick start + +Part of the Snowplow JavaScript Tracker monorepo. +Build with [Node.js](https://nodejs.org/en/) (18+) and [Rush](https://rushjs.io/). + +### Setup repository + +```bash +npm install -g @microsoft/rush +git clone https://github.com/snowplow/snowplow-javascript-tracker.git +rush update +``` + +## Package Installation + +With npm: + +```bash +npm install @snowplow/browser-plugin-ga-cookies +``` + +## Usage + +Initialize your tracker with the GaCookiesPlugin: + +```js +import { newTracker } from '@snowplow/browser-tracker'; +import { GaCookiesPlugin } from '@snowplow/browser-plugin-ga-cookies'; + +newTracker('sp1', '{{collector}}', { plugins: [ GaCookiesPlugin( + /* pluginOptions */ +) ] }); + +/* + * Available plugin options `GACookiesPluginOptions`: + * { + * ua: Send Universal Analytics specific cookie values. Defaults to false. + * ga4: Send Google Analytics 4 specific cookie values. Defaults to true. + * ga4MeasurementId: Measurement id/ids to search the Google Analytics 4 session cookie. Can be a single measurement id as a string or an array of measurement id strings. The cookie has the form of _ga_ where is the data stream container id and is the optional cookie_prefix option of the gtag.js tracker. + * cookiePrefix: Cookie prefix set on the Google Analytics 4 cookies using the cookie_prefix option of the gtag.js tracker. + * } + */ +``` + +## Copyright and license + +Licensed and distributed under the [BSD 3-Clause License](LICENSE) ([An OSI Approved License][osi]). + +Copyright (c) 2023 Snowplow Analytics Ltd. + +All rights reserved. + +[npm-url]: https://www.npmjs.com/package/@snowplow/browser-plugin-ga-cookies +[npm-image]: https://img.shields.io/npm/v/@snowplow/browser-plugin-ga-cookies +[docs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-tracker/ +[osi]: https://opensource.org/licenses/BSD-3-Clause +[license-image]: https://img.shields.io/npm/l/@snowplow/browser-plugin-ga-cookies diff --git a/plugins/browser-plugin-ga-cookies/jest.config.js b/plugins/browser-plugin-ga-cookies/jest.config.js new file mode 100644 index 000000000..87d15da9b --- /dev/null +++ b/plugins/browser-plugin-ga-cookies/jest.config.js @@ -0,0 +1,6 @@ +module.exports = { + preset: 'ts-jest', + reporters: ['jest-standard-reporter'], + setupFilesAfterEnv: ['../../setupTestGlobals.ts'], + testEnvironment: 'jest-environment-jsdom-global', +}; diff --git a/plugins/browser-plugin-ga-cookies/package.json b/plugins/browser-plugin-ga-cookies/package.json new file mode 100644 index 000000000..49aefdb36 --- /dev/null +++ b/plugins/browser-plugin-ga-cookies/package.json @@ -0,0 +1,52 @@ +{ + "name": "@snowplow/browser-plugin-ga-cookies", + "version": "4.10.0", + "description": "Attaches GA cookie data to Snowplow events", + "homepage": "http://bit.ly/sp-js", + "bugs": "https://github.com/snowplow/snowplow-javascript-tracker/issues", + "repository": { + "type": "git", + "url": "https://github.com/snowplow/snowplow-javascript-tracker.git" + }, + "license": "BSD-3-Clause", + "author": "Paul Boocock", + "sideEffects": false, + "main": "./dist/index.umd.js", + "module": "./dist/index.module.js", + "types": "./dist/index.module.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "rollup -c --silent --failAfterWarnings", + "test": "jest" + }, + "dependencies": { + "@snowplow/browser-tracker-core": "workspace:*", + "@snowplow/tracker-core": "workspace:*", + "tslib": "^2.3.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "~21.0.2", + "@rollup/plugin-node-resolve": "~13.1.3", + "@types/jest": "~28.1.1", + "@types/jsdom": "~16.2.14", + "@typescript-eslint/eslint-plugin": "~5.15.0", + "@typescript-eslint/parser": "~5.15.0", + "eslint": "~8.11.0", + "jest": "~28.1.3", + "jest-environment-jsdom": "~28.1.3", + "jest-environment-jsdom-global": "~4.0.0", + "jest-standard-reporter": "~2.0.0", + "rollup": "~2.70.1", + "rollup-plugin-cleanup": "~3.2.1", + "rollup-plugin-license": "~2.6.1", + "rollup-plugin-terser": "~7.0.2", + "rollup-plugin-ts": "~2.0.5", + "ts-jest": "~28.0.8", + "typescript": "~4.6.2" + }, + "peerDependencies": { + "@snowplow/browser-tracker": "~4.10.0" + } +} diff --git a/plugins/browser-plugin-ga-cookies/rollup.config.js b/plugins/browser-plugin-ga-cookies/rollup.config.js new file mode 100644 index 000000000..4748aabab --- /dev/null +++ b/plugins/browser-plugin-ga-cookies/rollup.config.js @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import ts from 'rollup-plugin-ts'; // Prefered over @rollup/plugin-typescript as it bundles .d.ts files +import { banner } from '../../banner'; +import { terser } from 'rollup-plugin-terser'; +import cleanup from 'rollup-plugin-cleanup'; +import pkg from './package.json'; +import { builtinModules } from 'module'; + +const umdPlugins = [nodeResolve({ browser: true }), commonjs(), ts()]; +const umdName = 'snowplowGaCookies'; + +export default [ + // CommonJS (for Node) and ES module (for bundlers) build. + { + input: './src/index.ts', + plugins: [...umdPlugins, banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main, format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + plugins: [...umdPlugins, terser(), cleanup({ comments: 'none' }), banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main.replace('.js', '.min.js'), format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + external: [...builtinModules, ...Object.keys(pkg.dependencies), ...Object.keys(pkg.devDependencies)], + plugins: [ + ts(), // so Rollup can convert TypeScript to JavaScript + banner(), + ], + output: [{ file: pkg.module, format: 'es', sourcemap: true }], + }, +]; diff --git a/plugins/browser-plugin-ga-cookies/src/index.ts b/plugins/browser-plugin-ga-cookies/src/index.ts new file mode 100644 index 000000000..c44597148 --- /dev/null +++ b/plugins/browser-plugin-ga-cookies/src/index.ts @@ -0,0 +1,94 @@ +import { SelfDescribingJson } from '@snowplow/tracker-core'; +import { BrowserPlugin, cookie } from '@snowplow/browser-tracker-core'; +import { GA4Cookies, GA4SessionCookies, UACookies } from './types'; +import { GOOGLE_ANALYTICS_4_COOKIES_SCHEMA, UNIVERSAL_ANALYTICS_COOKIES_SCHEMA } from './schemata'; + +interface GACookiesPluginOptions { + ua?: boolean; + ga4?: boolean; + ga4MeasurementId?: string | string[]; + cookiePrefix?: string | string[]; +} + +const defaultPluginOptions: GACookiesPluginOptions = { + ua: false, + ga4: true, + ga4MeasurementId: '', + cookiePrefix: [], +}; + +/** + * Captures the GA cookies on a page and sends as context on each event + * @param pluginOptions.ua - Send Universal Analytics specific cookie values. + * @param pluginOptions.ga4 - Send Google Analytics 4 specific cookie values. + * @param pluginOptions.ga4MeasurementId - Measurement id/ids to search the Google Analytics 4 session cookie. Can be a single measurement id as a string or an array of measurement id strings. The cookie has the form of _ga_ where is the data stream container id. + * @param pluginOptions.cookiePrefix - Cookie prefix set on the Google Analytics 4 cookies using the cookie_prefix option of the gtag.js tracker. + */ +export function GaCookiesPlugin(pluginOptions: GACookiesPluginOptions = defaultPluginOptions): BrowserPlugin { + return { + contexts: () => { + const contexts: SelfDescribingJson>[] = []; + const { ga4, ga4MeasurementId, ua, cookiePrefix } = { ...defaultPluginOptions, ...pluginOptions }; + const GA_USER_COOKIE = '_ga'; + const GA4_MEASUREMENT_ID_PREFIX = 'G-'; + const GA4_COOKIE_PREFIX = '_ga_'; + + if (ua) { + const uaCookiesContext: SelfDescribingJson = { + schema: UNIVERSAL_ANALYTICS_COOKIES_SCHEMA, + data: {}, + }; + ['__utma', '__utmb', '__utmc', '__utmv', '__utmz', GA_USER_COOKIE].forEach(function (cookieType) { + var value = cookie(cookieType); + if (value) { + uaCookiesContext.data[cookieType] = value; + } + }); + contexts.push(uaCookiesContext); + } + + if (ga4) { + const cookiePrefixes = Array.isArray(cookiePrefix) ? [...cookiePrefix] : [cookiePrefix]; + + /* We also will search for the default (no prefix) in every case. */ + cookiePrefixes.unshift(''); + cookiePrefixes.forEach((prefix) => { + const userCookie = cookie(prefix + GA_USER_COOKIE); + const sessionCookies: GA4SessionCookies[] = []; + if (ga4MeasurementId) { + const measurementIdentifiers = Array.isArray(ga4MeasurementId) ? [...ga4MeasurementId] : [ga4MeasurementId]; + + measurementIdentifiers.forEach(function (cookieIdentifier) { + const sessionCookieValue = cookie( + prefix + cookieIdentifier.replace(GA4_MEASUREMENT_ID_PREFIX, GA4_COOKIE_PREFIX) + ); + if (sessionCookieValue) { + sessionCookies.push({ + measurement_id: cookieIdentifier, + session_cookie: sessionCookieValue, + }); + } + }); + } + + if (!userCookie && !sessionCookies.length) { + return; + } + + const ga4CookiesContext: SelfDescribingJson = { + schema: GOOGLE_ANALYTICS_4_COOKIES_SCHEMA, + data: { + _ga: userCookie, + session_cookies: sessionCookies.length ? sessionCookies : undefined, + cookie_prefix: prefix || undefined, + }, + }; + + contexts.push(ga4CookiesContext); + }); + } + + return contexts; + }, + }; +} diff --git a/plugins/browser-plugin-ga-cookies/src/schemata.ts b/plugins/browser-plugin-ga-cookies/src/schemata.ts new file mode 100644 index 000000000..39e923674 --- /dev/null +++ b/plugins/browser-plugin-ga-cookies/src/schemata.ts @@ -0,0 +1,2 @@ +export const UNIVERSAL_ANALYTICS_COOKIES_SCHEMA = 'iglu:com.google.analytics/cookies/jsonschema/1-0-0'; +export const GOOGLE_ANALYTICS_4_COOKIES_SCHEMA = 'iglu:com.google.ga4/cookies/jsonschema/1-0-0'; diff --git a/plugins/browser-plugin-ga-cookies/src/types.ts b/plugins/browser-plugin-ga-cookies/src/types.ts new file mode 100644 index 000000000..6e41dfe54 --- /dev/null +++ b/plugins/browser-plugin-ga-cookies/src/types.ts @@ -0,0 +1,20 @@ +export interface UACookies { + __utma?: string; + __utmb?: string; + __utmc?: string; + __utmv?: string; + __utmz?: string; + _ga?: string; + [key: string]: string | undefined; +} + +export interface GA4Cookies { + _ga?: string; + session_cookies?: GA4SessionCookies[]; + [key: string]: unknown; +} + +export interface GA4SessionCookies { + measurement_id: string; + session_cookie?: string; +} diff --git a/plugins/browser-plugin-ga-cookies/test/__snapshots__/ga-cookies.test.ts.snap b/plugins/browser-plugin-ga-cookies/test/__snapshots__/ga-cookies.test.ts.snap new file mode 100644 index 000000000..6ec8c8107 --- /dev/null +++ b/plugins/browser-plugin-ga-cookies/test/__snapshots__/ga-cookies.test.ts.snap @@ -0,0 +1,171 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`GA Cookies plugin Correctly returns values for GA4 cookies for multiple measurement ids 1`] = ` +Array [ + Object { + "data": Object { + "_ga": "1234", + "cookie_prefix": undefined, + "session_cookies": Array [ + Object { + "measurement_id": "G-1234", + "session_cookie": "567", + }, + Object { + "measurement_id": "G-5678", + "session_cookie": "789", + }, + ], + }, + "schema": "iglu:com.google.ga4/cookies/jsonschema/1-0-0", + }, +] +`; + +exports[`GA Cookies plugin Correctly returns values for GA4 cookies with cookie prefix 1`] = ` +Array [ + Object { + "data": Object { + "_ga": "1234", + "cookie_prefix": "test", + "session_cookies": Array [ + Object { + "measurement_id": "G-1234", + "session_cookie": "567", + }, + ], + }, + "schema": "iglu:com.google.ga4/cookies/jsonschema/1-0-0", + }, +] +`; + +exports[`GA Cookies plugin Does not add any additional GA4 context when GA4 cookies are not detected 1`] = ` +Array [ + Object { + "data": Object {}, + "schema": "iglu:com.google.analytics/cookies/jsonschema/1-0-0", + }, +] +`; + +exports[`GA Cookies plugin Only returns values for GA4 user cookies without measurement id/s and GA4 enabled 1`] = ` +Array [ + Object { + "data": Object { + "_ga": "1234", + "cookie_prefix": undefined, + "session_cookies": undefined, + }, + "schema": "iglu:com.google.ga4/cookies/jsonschema/1-0-0", + }, +] +`; + +exports[`GA Cookies plugin Returns separate contexts for GA4 enabled setup with different cookie_prefix options 1`] = ` +Array [ + Object { + "data": Object { + "_ga": "1234", + "cookie_prefix": undefined, + "session_cookies": undefined, + }, + "schema": "iglu:com.google.ga4/cookies/jsonschema/1-0-0", + }, + Object { + "data": Object { + "_ga": "890", + "cookie_prefix": "test", + "session_cookies": undefined, + }, + "schema": "iglu:com.google.ga4/cookies/jsonschema/1-0-0", + }, +] +`; + +exports[`GA Cookies plugin Returns separate contexts for GA4 enabled setup with different cookie_prefix options and measurement ids 1`] = ` +Array [ + Object { + "data": Object { + "_ga": "1234", + "cookie_prefix": undefined, + "session_cookies": Array [ + Object { + "measurement_id": "G-1234", + "session_cookie": "567", + }, + ], + }, + "schema": "iglu:com.google.ga4/cookies/jsonschema/1-0-0", + }, + Object { + "data": Object { + "_ga": "890", + "cookie_prefix": "test", + "session_cookies": Array [ + Object { + "measurement_id": "G-567", + "session_cookie": "098", + }, + ], + }, + "schema": "iglu:com.google.ga4/cookies/jsonschema/1-0-0", + }, +] +`; + +exports[`GA Cookies plugin Returns values for GA4 cookies and Universal Analytics cookies 1`] = ` +Array [ + Object { + "data": Object { + "__utma": "567", + "_ga": "1234", + }, + "schema": "iglu:com.google.analytics/cookies/jsonschema/1-0-0", + }, + Object { + "data": Object { + "_ga": "1234", + "cookie_prefix": undefined, + "session_cookies": Array [ + Object { + "measurement_id": "G-1234", + "session_cookie": "567", + }, + ], + }, + "schema": "iglu:com.google.ga4/cookies/jsonschema/1-0-0", + }, +] +`; + +exports[`GA Cookies plugin Returns values for GA4 cookies and not Universal Analytics cookies 1`] = ` +Array [ + Object { + "data": Object { + "_ga": "1234", + "cookie_prefix": undefined, + "session_cookies": Array [ + Object { + "measurement_id": "G-1234", + "session_cookie": "567", + }, + ], + }, + "schema": "iglu:com.google.ga4/cookies/jsonschema/1-0-0", + }, +] +`; + +exports[`GA Cookies plugin Returns values for GA4 cookies by default 1`] = ` +Array [ + Object { + "data": Object { + "_ga": "1234", + "cookie_prefix": undefined, + "session_cookies": undefined, + }, + "schema": "iglu:com.google.ga4/cookies/jsonschema/1-0-0", + }, +] +`; diff --git a/plugins/browser-plugin-ga-cookies/test/ga-cookies.test.ts b/plugins/browser-plugin-ga-cookies/test/ga-cookies.test.ts new file mode 100644 index 000000000..168d30065 --- /dev/null +++ b/plugins/browser-plugin-ga-cookies/test/ga-cookies.test.ts @@ -0,0 +1,175 @@ +import { buildLinkClick, trackerCore } from '@snowplow/tracker-core'; +import { GaCookiesPlugin } from '../src'; + +describe('GA Cookies plugin', () => { + let cookieJar: string; + + beforeAll(() => { + cookieJar = ''; + jest.spyOn(document, 'cookie', 'set').mockImplementation((cookie) => { + cookieJar += cookie; + }); + jest.spyOn(document, 'cookie', 'get').mockImplementation(() => cookieJar); + }); + + afterEach(() => { + cookieJar = ''; + jest.clearAllTimers(); + }); + + afterAll(() => { + jest.clearAllMocks(); + }); + + it('Returns values for GA4 cookies by default', (done) => { + const containerId = '1234'; + document.cookie = `_ga=1234; __utma=567; _ga_${containerId}=567;`; + const core = trackerCore({ + corePlugins: [GaCookiesPlugin()], + callback: (payloadBuilder) => { + const { data } = payloadBuilder.getJson()[1].json; + expect(data).toMatchSnapshot(); + done(); + }, + }); + + core.track(buildLinkClick({ targetUrl: 'https://example.com' })); + }); + + it('Does not add any additional GA4 context when GA4 cookies are not detected', (done) => { + /* In v3, an empty Universal Analytics cookies context was added to the contexts array. */ + const containerId = '1234'; + const measurementId = `G-${containerId}`; + document.cookie = ``; + const core = trackerCore({ + corePlugins: [GaCookiesPlugin({ ua: true, ga4MeasurementId: measurementId })], + callback: (payloadBuilder) => { + const { data } = payloadBuilder.getJson()[1].json; + expect(data).toMatchSnapshot(); + done(); + }, + }); + + core.track(buildLinkClick({ targetUrl: 'https://example.com' })); + }); + + it('Returns values for GA4 cookies and Universal Analytics cookies', (done) => { + const containerId = '1234'; + const measurementId = `G-${containerId}`; + document.cookie = `_ga=1234; __utma=567; _ga_${containerId}=567;`; + const core = trackerCore({ + corePlugins: [GaCookiesPlugin({ ua: true, ga4MeasurementId: measurementId })], + callback: (payloadBuilder) => { + const { data } = payloadBuilder.getJson()[1].json; + expect(data).toMatchSnapshot(); + done(); + }, + }); + + core.track(buildLinkClick({ targetUrl: 'https://example.com' })); + }); + + it('Returns values for GA4 cookies and not Universal Analytics cookies', (done) => { + const containerId = '1234'; + const measurementId = `G-${containerId}`; + document.cookie = `_ga=1234; __utma=567; _ga_${containerId}=567;`; + const core = trackerCore({ + corePlugins: [GaCookiesPlugin({ ua: false, ga4: true, ga4MeasurementId: measurementId })], + callback: (payloadBuilder) => { + const { data } = payloadBuilder.getJson()[1].json; + expect(data).toMatchSnapshot(); + done(); + }, + }); + + core.track(buildLinkClick({ targetUrl: 'https://example.com' })); + }); + + it('Correctly returns values for GA4 cookies for multiple measurement ids', (done) => { + const containerIdFoo = '1234'; + const containerIdBar = '5678'; + const measurementIds = [`G-${containerIdFoo}`, `G-${containerIdBar}`]; + document.cookie = `_ga=1234; __utma=567; _ga_${containerIdFoo}=567; _ga_${containerIdBar}=789;`; + const core = trackerCore({ + corePlugins: [GaCookiesPlugin({ ua: false, ga4: true, ga4MeasurementId: measurementIds })], + callback: (payloadBuilder) => { + const { data } = payloadBuilder.getJson()[1].json; + expect(data).toMatchSnapshot(); + done(); + }, + }); + + core.track(buildLinkClick({ targetUrl: 'https://example.com' })); + }); + + it('Correctly returns values for GA4 cookies with cookie prefix', (done) => { + const containerId = '1234'; + const measurementId = `G-${containerId}`; + const cookiePrefix = 'test'; + document.cookie = `${cookiePrefix}_ga=1234; __utma=567; ${cookiePrefix}_ga_${containerId}=567;`; + const core = trackerCore({ + corePlugins: [GaCookiesPlugin({ ua: false, ga4: true, ga4MeasurementId: measurementId, cookiePrefix })], + callback: (payloadBuilder) => { + const { data } = payloadBuilder.getJson()[1].json; + expect(data).toMatchSnapshot(); + done(); + }, + }); + + core.track(buildLinkClick({ targetUrl: 'https://example.com' })); + }); + + it('Only returns values for GA4 user cookies without measurement id/s and GA4 enabled', (done) => { + const containerId = '1234'; + document.cookie = `_ga=1234; __utma=567; _ga_${containerId}=567;`; + const core = trackerCore({ + corePlugins: [GaCookiesPlugin({ ua: false, ga4: true })], + callback: (payloadBuilder) => { + const { data } = payloadBuilder.getJson()[1].json; + expect(data).toMatchSnapshot(); + done(); + }, + }); + + core.track(buildLinkClick({ targetUrl: 'https://example.com' })); + }); + + it('Returns separate contexts for GA4 enabled setup with different cookie_prefix options', (done) => { + const containerId = '1234'; + const cookiePrefix = 'test'; + /* gtag.js with the { cookie_prefix } option will create {cookie_prefix}_ga and {cookie_prefix}_ga_{containerId} cookies. */ + document.cookie = `_ga=1234; __utma=567; _ga_${containerId}=567; ${cookiePrefix}_ga=890;`; + const core = trackerCore({ + corePlugins: [GaCookiesPlugin({ ua: false, ga4: true, cookiePrefix })], + callback: (payloadBuilder) => { + const { data } = payloadBuilder.getJson()[1].json; + expect(data).toMatchSnapshot(); + done(); + }, + }); + + core.track(buildLinkClick({ targetUrl: 'https://example.com' })); + }); + + it('Returns separate contexts for GA4 enabled setup with different cookie_prefix options and measurement ids', (done) => { + const containerId = '1234'; + const measurementId = `G-${containerId}`; + const prefixContainerId = '567'; + const prefixMeasurementId = `G-${prefixContainerId}`; + const cookiePrefix = 'test'; + /* gtag.js with the { cookie_prefix } option will create {cookie_prefix}_ga and {cookie_prefix}_ga_{containerId} cookies. */ + document.cookie = `_ga=1234; __utma=567; _ga_${containerId}=567; ${cookiePrefix}_ga=890; ${cookiePrefix}_ga_${prefixContainerId}=098`; + const core = trackerCore({ + corePlugins: [ + GaCookiesPlugin({ ua: false, ga4: true, cookiePrefix, ga4MeasurementId: [measurementId, prefixMeasurementId] }), + ], + callback: (payloadBuilder) => { + const { data } = payloadBuilder.getJson()[1].json; + expect(data).toMatchSnapshot(); + done(); + }, + }); + + core.track(buildLinkClick({ targetUrl: 'https://example.com' })); + }); +}); diff --git a/plugins/browser-plugin-ga-cookies/tsconfig.json b/plugins/browser-plugin-ga-cookies/tsconfig.json new file mode 100644 index 000000000..4082f16a5 --- /dev/null +++ b/plugins/browser-plugin-ga-cookies/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +} diff --git a/plugins/browser-plugin-geolocation/CHANGELOG.json b/plugins/browser-plugin-geolocation/CHANGELOG.json new file mode 100644 index 000000000..7ef792ae1 --- /dev/null +++ b/plugins/browser-plugin-geolocation/CHANGELOG.json @@ -0,0 +1,605 @@ +{ + "name": "@snowplow/browser-plugin-geolocation", + "entries": [ + { + "version": "4.10.0", + "tag": "@snowplow/browser-plugin-geolocation_v4.10.0", + "date": "Mon, 27 Jul 2026 13:52:14 GMT", + "comments": {} + }, + { + "version": "4.9.0", + "tag": "@snowplow/browser-plugin-geolocation_v4.9.0", + "date": "Tue, 21 Jul 2026 14:53:08 GMT", + "comments": {} + }, + { + "version": "4.8.4", + "tag": "@snowplow/browser-plugin-geolocation_v4.8.4", + "date": "Thu, 02 Jul 2026 10:07:52 GMT", + "comments": {} + }, + { + "version": "4.8.3", + "tag": "@snowplow/browser-plugin-geolocation_v4.8.3", + "date": "Tue, 30 Jun 2026 14:22:03 GMT", + "comments": { + "none": [ + { + "comment": "Update uuid to v11 and remove closure-compiler from the build pipeline" + } + ] + } + }, + { + "version": "4.8.2", + "tag": "@snowplow/browser-plugin-geolocation_v4.8.2", + "date": "Wed, 17 Jun 2026 12:30:12 GMT", + "comments": {} + }, + { + "version": "4.8.1", + "tag": "@snowplow/browser-plugin-geolocation_v4.8.1", + "date": "Wed, 13 May 2026 09:26:05 GMT", + "comments": {} + }, + { + "version": "4.8.0", + "tag": "@snowplow/browser-plugin-geolocation_v4.8.0", + "date": "Tue, 28 Apr 2026 07:56:22 GMT", + "comments": {} + }, + { + "version": "4.7.0", + "tag": "@snowplow/browser-plugin-geolocation_v4.7.0", + "date": "Wed, 01 Apr 2026 12:59:29 GMT", + "comments": {} + }, + { + "version": "4.6.9", + "tag": "@snowplow/browser-plugin-geolocation_v4.6.9", + "date": "Mon, 16 Mar 2026 15:43:06 GMT", + "comments": {} + }, + { + "version": "4.6.8", + "tag": "@snowplow/browser-plugin-geolocation_v4.6.8", + "date": "Tue, 28 Oct 2025 09:46:42 GMT", + "comments": {} + }, + { + "version": "4.6.7", + "tag": "@snowplow/browser-plugin-geolocation_v4.6.7", + "date": "Tue, 07 Oct 2025 14:53:36 GMT", + "comments": {} + }, + { + "version": "4.6.6", + "tag": "@snowplow/browser-plugin-geolocation_v4.6.6", + "date": "Tue, 26 Aug 2025 08:42:27 GMT", + "comments": {} + }, + { + "version": "4.6.5", + "tag": "@snowplow/browser-plugin-geolocation_v4.6.5", + "date": "Wed, 25 Jun 2025 21:16:46 GMT", + "comments": {} + }, + { + "version": "4.6.4", + "tag": "@snowplow/browser-plugin-geolocation_v4.6.4", + "date": "Wed, 25 Jun 2025 12:08:50 GMT", + "comments": {} + }, + { + "version": "4.6.3", + "tag": "@snowplow/browser-plugin-geolocation_v4.6.3", + "date": "Thu, 29 May 2025 19:52:07 GMT", + "comments": {} + }, + { + "version": "4.6.2", + "tag": "@snowplow/browser-plugin-geolocation_v4.6.2", + "date": "Tue, 20 May 2025 07:39:05 GMT", + "comments": {} + }, + { + "version": "4.6.1", + "tag": "@snowplow/browser-plugin-geolocation_v4.6.1", + "date": "Tue, 06 May 2025 13:10:51 GMT", + "comments": {} + }, + { + "version": "4.6.0", + "tag": "@snowplow/browser-plugin-geolocation_v4.6.0", + "date": "Thu, 01 May 2025 09:58:59 GMT", + "comments": {} + }, + { + "version": "4.5.0", + "tag": "@snowplow/browser-plugin-geolocation_v4.5.0", + "date": "Fri, 04 Apr 2025 09:21:23 GMT", + "comments": {} + }, + { + "version": "4.4.0", + "tag": "@snowplow/browser-plugin-geolocation_v4.4.0", + "date": "Thu, 20 Mar 2025 12:14:34 GMT", + "comments": {} + }, + { + "version": "4.3.1", + "tag": "@snowplow/browser-plugin-geolocation_v4.3.1", + "date": "Tue, 21 Jan 2025 11:09:42 GMT", + "comments": {} + }, + { + "version": "4.3.0", + "tag": "@snowplow/browser-plugin-geolocation_v4.3.0", + "date": "Mon, 20 Jan 2025 11:45:13 GMT", + "comments": {} + }, + { + "version": "4.2.0", + "tag": "@snowplow/browser-plugin-geolocation_v4.2.0", + "date": "Mon, 13 Jan 2025 08:30:05 GMT", + "comments": {} + }, + { + "version": "4.1.0", + "tag": "@snowplow/browser-plugin-geolocation_v4.1.0", + "date": "Thu, 28 Nov 2024 10:57:30 GMT", + "comments": {} + }, + { + "version": "4.0.4", + "tag": "@snowplow/browser-plugin-geolocation_v4.0.4", + "date": "Thu, 21 Nov 2024 09:06:36 GMT", + "comments": {} + }, + { + "version": "4.0.3", + "tag": "@snowplow/browser-plugin-geolocation_v4.0.3", + "date": "Wed, 20 Nov 2024 09:30:31 GMT", + "comments": {} + }, + { + "version": "4.0.2", + "tag": "@snowplow/browser-plugin-geolocation_v4.0.2", + "date": "Mon, 11 Nov 2024 15:46:34 GMT", + "comments": {} + }, + { + "version": "4.0.1", + "tag": "@snowplow/browser-plugin-geolocation_v4.0.1", + "date": "Fri, 01 Nov 2024 10:35:07 GMT", + "comments": {} + }, + { + "version": "4.0.0", + "tag": "@snowplow/browser-plugin-geolocation_v4.0.0", + "date": "Mon, 28 Oct 2024 11:48:53 GMT", + "comments": {} + }, + { + "version": "3.24.6", + "tag": "@snowplow/browser-plugin-geolocation_v3.24.6", + "date": "Mon, 28 Oct 2024 10:23:28 GMT", + "comments": {} + }, + { + "version": "3.24.5", + "tag": "@snowplow/browser-plugin-geolocation_v3.24.5", + "date": "Fri, 25 Oct 2024 08:53:04 GMT", + "comments": {} + }, + { + "version": "3.24.4", + "tag": "@snowplow/browser-plugin-geolocation_v3.24.4", + "date": "Thu, 26 Sep 2024 06:10:22 GMT", + "comments": {} + }, + { + "version": "3.24.3", + "tag": "@snowplow/browser-plugin-geolocation_v3.24.3", + "date": "Tue, 03 Sep 2024 08:15:14 GMT", + "comments": { + "none": [ + { + "comment": "Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush" + } + ] + } + }, + { + "version": "3.24.2", + "tag": "@snowplow/browser-plugin-geolocation_v3.24.2", + "date": "Wed, 24 Jul 2024 08:59:00 GMT", + "comments": {} + }, + { + "version": "3.24.1", + "tag": "@snowplow/browser-plugin-geolocation_v3.24.1", + "date": "Tue, 02 Jul 2024 07:08:17 GMT", + "comments": {} + }, + { + "version": "3.24.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.24.0", + "date": "Tue, 25 Jun 2024 08:31:05 GMT", + "comments": {} + }, + { + "version": "3.23.1", + "tag": "@snowplow/browser-plugin-geolocation_v3.23.1", + "date": "Tue, 04 Jun 2024 13:34:45 GMT", + "comments": {} + }, + { + "version": "3.23.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.23.0", + "date": "Thu, 28 Mar 2024 11:28:45 GMT", + "comments": {} + }, + { + "version": "3.22.1", + "tag": "@snowplow/browser-plugin-geolocation_v3.22.1", + "date": "Wed, 13 Mar 2024 08:39:48 GMT", + "comments": {} + }, + { + "version": "3.22.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.22.0", + "date": "Fri, 08 Mar 2024 08:13:04 GMT", + "comments": {} + }, + { + "version": "3.21.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.21.0", + "date": "Mon, 29 Jan 2024 08:34:06 GMT", + "comments": {} + }, + { + "version": "3.20.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.20.0", + "date": "Mon, 15 Jan 2024 14:41:16 GMT", + "comments": {} + }, + { + "version": "3.19.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.19.0", + "date": "Thu, 14 Dec 2023 10:45:22 GMT", + "comments": {} + }, + { + "version": "3.18.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.18.0", + "date": "Mon, 04 Dec 2023 13:44:02 GMT", + "comments": {} + }, + { + "version": "3.17.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.17.0", + "date": "Tue, 14 Nov 2023 17:58:26 GMT", + "comments": {} + }, + { + "version": "3.16.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.16.0", + "date": "Mon, 16 Oct 2023 14:58:08 GMT", + "comments": {} + }, + { + "version": "3.15.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.15.0", + "date": "Mon, 28 Aug 2023 14:25:14 GMT", + "comments": {} + }, + { + "version": "3.14.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.14.0", + "date": "Thu, 10 Aug 2023 13:56:44 GMT", + "comments": {} + }, + { + "version": "3.13.1", + "tag": "@snowplow/browser-plugin-geolocation_v3.13.1", + "date": "Thu, 29 Jun 2023 14:20:06 GMT", + "comments": {} + }, + { + "version": "3.13.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.13.0", + "date": "Tue, 20 Jun 2023 07:44:23 GMT", + "comments": {} + }, + { + "version": "3.12.1", + "tag": "@snowplow/browser-plugin-geolocation_v3.12.1", + "date": "Thu, 15 Jun 2023 10:05:37 GMT", + "comments": {} + }, + { + "version": "3.12.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.12.0", + "date": "Mon, 05 Jun 2023 11:51:22 GMT", + "comments": {} + }, + { + "version": "3.11.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.11.0", + "date": "Wed, 24 May 2023 15:56:17 GMT", + "comments": {} + }, + { + "version": "3.10.1", + "tag": "@snowplow/browser-plugin-geolocation_v3.10.1", + "date": "Fri, 12 May 2023 06:59:31 GMT", + "comments": {} + }, + { + "version": "3.10.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.10.0", + "date": "Thu, 11 May 2023 08:29:15 GMT", + "comments": {} + }, + { + "version": "3.9.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.9.0", + "date": "Thu, 30 Mar 2023 13:46:56 GMT", + "comments": {} + }, + { + "version": "3.8.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.8.0", + "date": "Tue, 03 Jan 2023 15:36:33 GMT", + "comments": {} + }, + { + "version": "3.7.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.7.0", + "date": "Mon, 31 Oct 2022 06:26:28 GMT", + "comments": {} + }, + { + "version": "3.6.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.6.0", + "date": "Thu, 15 Sep 2022 07:55:20 GMT", + "comments": {} + }, + { + "version": "3.5.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.5.0", + "date": "Fri, 10 Jun 2022 18:57:46 GMT", + "comments": {} + }, + { + "version": "3.4.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.4.0", + "date": "Thu, 07 Apr 2022 11:56:26 GMT", + "comments": { + "none": [ + { + "comment": "Bump dependencies (#1067)" + } + ] + } + }, + { + "version": "3.3.1", + "tag": "@snowplow/browser-plugin-geolocation_v3.3.1", + "date": "Wed, 23 Feb 2022 19:27:40 GMT", + "comments": {} + }, + { + "version": "3.3.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.3.0", + "date": "Mon, 31 Jan 2022 15:58:10 GMT", + "comments": {} + }, + { + "version": "3.2.3", + "tag": "@snowplow/browser-plugin-geolocation_v3.2.3", + "date": "Tue, 18 Jan 2022 16:23:52 GMT", + "comments": { + "none": [ + { + "comment": "Bump Copyright to 2022 (#1040)" + } + ] + } + }, + { + "version": "3.2.2", + "tag": "@snowplow/browser-plugin-geolocation_v3.2.2", + "date": "Fri, 14 Jan 2022 10:17:59 GMT", + "comments": {} + }, + { + "version": "3.2.1", + "tag": "@snowplow/browser-plugin-geolocation_v3.2.1", + "date": "Wed, 12 Jan 2022 09:50:29 GMT", + "comments": {} + }, + { + "version": "3.2.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.2.0", + "date": "Tue, 11 Jan 2022 12:53:22 GMT", + "comments": {} + }, + { + "version": "3.1.6", + "tag": "@snowplow/browser-plugin-geolocation_v3.1.6", + "date": "Tue, 19 Oct 2021 09:17:22 GMT", + "comments": { + "none": [ + { + "comment": "Fix failing build on ARM Macs (#1012)" + }, + { + "comment": "Fix issues importing some plugins in Next SSR (#1015)" + } + ] + } + }, + { + "version": "3.1.5", + "tag": "@snowplow/browser-plugin-geolocation_v3.1.5", + "date": "Fri, 01 Oct 2021 08:09:21 GMT", + "comments": {} + }, + { + "version": "3.1.4", + "tag": "@snowplow/browser-plugin-geolocation_v3.1.4", + "date": "Tue, 21 Sep 2021 14:59:36 GMT", + "comments": {} + }, + { + "version": "3.1.3", + "tag": "@snowplow/browser-plugin-geolocation_v3.1.3", + "date": "Mon, 23 Aug 2021 10:13:18 GMT", + "comments": {} + }, + { + "version": "3.1.2", + "tag": "@snowplow/browser-plugin-geolocation_v3.1.2", + "date": "Mon, 16 Aug 2021 12:59:59 GMT", + "comments": { + "none": [ + { + "comment": "Update READMEs with correct Node requirements (#994)" + } + ] + } + }, + { + "version": "3.1.1", + "tag": "@snowplow/browser-plugin-geolocation_v3.1.1", + "date": "Wed, 04 Aug 2021 10:12:25 GMT", + "comments": { + "none": [ + { + "comment": "Automate api-extractor on release (#972)" + }, + { + "comment": "Bump tslib to 2.3.0 (#986)" + }, + { + "comment": "Bump typescript to 4.3.5 (#987)" + }, + { + "comment": "Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988)" + } + ] + } + }, + { + "version": "3.1.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.1.0", + "date": "Fri, 14 May 2021 10:45:32 GMT", + "comments": {} + }, + { + "version": "3.0.3", + "tag": "@snowplow/browser-plugin-geolocation_v3.0.3", + "date": "Wed, 21 Apr 2021 12:35:06 GMT", + "comments": {} + }, + { + "version": "3.0.2", + "tag": "@snowplow/browser-plugin-geolocation_v3.0.2", + "date": "Thu, 15 Apr 2021 21:07:39 GMT", + "comments": {} + }, + { + "version": "3.0.1", + "tag": "@snowplow/browser-plugin-geolocation_v3.0.1", + "date": "Wed, 14 Apr 2021 16:30:05 GMT", + "comments": { + "none": [ + { + "comment": "Add peerDependencies to plugins (#950)" + }, + { + "comment": "Mark packages as sideEffect: false (#951)" + }, + { + "comment": "Add unit tests to plugin track* functions (#954)" + } + ] + } + }, + { + "version": "3.0.0", + "tag": "@snowplow/browser-plugin-geolocation_v3.0.0", + "date": "Wed, 31 Mar 2021 14:46:47 GMT", + "comments": { + "none": [ + { + "comment": "Bump rollup to 2.41 (#916)" + }, + { + "comment": "Publish UMD versions of plugins to GitHub release (#923)" + }, + { + "comment": "Ensure browser-tracker API methods catch exceptions (#919)" + }, + { + "comment": "Introduce TSDoc comments and extract interfaces where appropriate (#906)" + }, + { + "comment": "Bump major version to v3 and update READMEs (#904)" + }, + { + "comment": "Improve Core API for module bundlers which support treeshaking (#903)" + }, + { + "comment": "Rename @snowplow/browser-core to @snowplow/browser-tracker-core (#901)" + }, + { + "comment": "Publish lite version of sp.js (#900)" + }, + { + "comment": "Ensure correct 3-Clause BSD License notices are being used (#316)" + }, + { + "comment": "Improve API for module bundlers which support treeshaking (#899)" + }, + { + "comment": "Bump rush to 5.39 (#895)" + }, + { + "comment": "Port to TypeScript (#72)" + }, + { + "comment": "Make sp.js build process modular (#450)" + }, + { + "comment": "Create @snowplow/browser-tracker package for npm distribution (#541)" + }, + { + "comment": "Split auto contexts into plugins (#880)" + }, + { + "comment": "Add rush to manage monorepo (#883)" + }, + { + "comment": "Add ES Module builds (#882)" + }, + { + "comment": "Cleanup deprecated methods (#557)" + }, + { + "comment": "Update publishing process for rush (#907)" + }, + { + "comment": "Change white and black lists to allow and deny lists (#908)" + }, + { + "comment": "Create rush change files for major version 3 release (#909)" + } + ] + } + } + ] +} diff --git a/plugins/browser-plugin-geolocation/CHANGELOG.md b/plugins/browser-plugin-geolocation/CHANGELOG.md new file mode 100644 index 000000000..1f2a78159 --- /dev/null +++ b/plugins/browser-plugin-geolocation/CHANGELOG.md @@ -0,0 +1,438 @@ +# Change Log - @snowplow/browser-plugin-geolocation + +This log was last generated on Mon, 27 Jul 2026 13:52:14 GMT and should not be manually modified. + +## 4.10.0 +Mon, 27 Jul 2026 13:52:14 GMT + +_Version update only_ + +## 4.9.0 +Tue, 21 Jul 2026 14:53:08 GMT + +_Version update only_ + +## 4.8.4 +Thu, 02 Jul 2026 10:07:52 GMT + +_Version update only_ + +## 4.8.3 +Tue, 30 Jun 2026 14:22:03 GMT + +### Updates + +- Update uuid to v11 and remove closure-compiler from the build pipeline + +## 4.8.2 +Wed, 17 Jun 2026 12:30:12 GMT + +_Version update only_ + +## 4.8.1 +Wed, 13 May 2026 09:26:05 GMT + +_Version update only_ + +## 4.8.0 +Tue, 28 Apr 2026 07:56:22 GMT + +_Version update only_ + +## 4.7.0 +Wed, 01 Apr 2026 12:59:29 GMT + +_Version update only_ + +## 4.6.9 +Mon, 16 Mar 2026 15:43:06 GMT + +_Version update only_ + +## 4.6.8 +Tue, 28 Oct 2025 09:46:42 GMT + +_Version update only_ + +## 4.6.7 +Tue, 07 Oct 2025 14:53:36 GMT + +_Version update only_ + +## 4.6.6 +Tue, 26 Aug 2025 08:42:27 GMT + +_Version update only_ + +## 4.6.5 +Wed, 25 Jun 2025 21:16:46 GMT + +_Version update only_ + +## 4.6.4 +Wed, 25 Jun 2025 12:08:50 GMT + +_Version update only_ + +## 4.6.3 +Thu, 29 May 2025 19:52:07 GMT + +_Version update only_ + +## 4.6.2 +Tue, 20 May 2025 07:39:05 GMT + +_Version update only_ + +## 4.6.1 +Tue, 06 May 2025 13:10:51 GMT + +_Version update only_ + +## 4.6.0 +Thu, 01 May 2025 09:58:59 GMT + +_Version update only_ + +## 4.5.0 +Fri, 04 Apr 2025 09:21:23 GMT + +_Version update only_ + +## 4.4.0 +Thu, 20 Mar 2025 12:14:34 GMT + +_Version update only_ + +## 4.3.1 +Tue, 21 Jan 2025 11:09:42 GMT + +_Version update only_ + +## 4.3.0 +Mon, 20 Jan 2025 11:45:13 GMT + +_Version update only_ + +## 4.2.0 +Mon, 13 Jan 2025 08:30:05 GMT + +_Version update only_ + +## 4.1.0 +Thu, 28 Nov 2024 10:57:30 GMT + +_Version update only_ + +## 4.0.4 +Thu, 21 Nov 2024 09:06:36 GMT + +_Version update only_ + +## 4.0.3 +Wed, 20 Nov 2024 09:30:31 GMT + +_Version update only_ + +## 4.0.2 +Mon, 11 Nov 2024 15:46:34 GMT + +_Version update only_ + +## 4.0.1 +Fri, 01 Nov 2024 10:35:07 GMT + +_Version update only_ + +## 4.0.0 +Mon, 28 Oct 2024 11:48:53 GMT + +_Version update only_ + +## 3.24.6 +Mon, 28 Oct 2024 10:23:28 GMT + +_Version update only_ + +## 3.24.5 +Fri, 25 Oct 2024 08:53:04 GMT + +_Version update only_ + +## 3.24.4 +Thu, 26 Sep 2024 06:10:22 GMT + +_Version update only_ + +## 3.24.3 +Tue, 03 Sep 2024 08:15:14 GMT + +### Updates + +- Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush + +## 3.24.2 +Wed, 24 Jul 2024 08:59:00 GMT + +_Version update only_ + +## 3.24.1 +Tue, 02 Jul 2024 07:08:17 GMT + +_Version update only_ + +## 3.24.0 +Tue, 25 Jun 2024 08:31:05 GMT + +_Version update only_ + +## 3.23.1 +Tue, 04 Jun 2024 13:34:45 GMT + +_Version update only_ + +## 3.23.0 +Thu, 28 Mar 2024 11:28:45 GMT + +_Version update only_ + +## 3.22.1 +Wed, 13 Mar 2024 08:39:48 GMT + +_Version update only_ + +## 3.22.0 +Fri, 08 Mar 2024 08:13:04 GMT + +_Version update only_ + +## 3.21.0 +Mon, 29 Jan 2024 08:34:06 GMT + +_Version update only_ + +## 3.20.0 +Mon, 15 Jan 2024 14:41:16 GMT + +_Version update only_ + +## 3.19.0 +Thu, 14 Dec 2023 10:45:22 GMT + +_Version update only_ + +## 3.18.0 +Mon, 04 Dec 2023 13:44:02 GMT + +_Version update only_ + +## 3.17.0 +Tue, 14 Nov 2023 17:58:26 GMT + +_Version update only_ + +## 3.16.0 +Mon, 16 Oct 2023 14:58:08 GMT + +_Version update only_ + +## 3.15.0 +Mon, 28 Aug 2023 14:25:14 GMT + +_Version update only_ + +## 3.14.0 +Thu, 10 Aug 2023 13:56:44 GMT + +_Version update only_ + +## 3.13.1 +Thu, 29 Jun 2023 14:20:06 GMT + +_Version update only_ + +## 3.13.0 +Tue, 20 Jun 2023 07:44:23 GMT + +_Version update only_ + +## 3.12.1 +Thu, 15 Jun 2023 10:05:37 GMT + +_Version update only_ + +## 3.12.0 +Mon, 05 Jun 2023 11:51:22 GMT + +_Version update only_ + +## 3.11.0 +Wed, 24 May 2023 15:56:17 GMT + +_Version update only_ + +## 3.10.1 +Fri, 12 May 2023 06:59:31 GMT + +_Version update only_ + +## 3.10.0 +Thu, 11 May 2023 08:29:15 GMT + +_Version update only_ + +## 3.9.0 +Thu, 30 Mar 2023 13:46:56 GMT + +_Version update only_ + +## 3.8.0 +Tue, 03 Jan 2023 15:36:33 GMT + +_Version update only_ + +## 3.7.0 +Mon, 31 Oct 2022 06:26:28 GMT + +_Version update only_ + +## 3.6.0 +Thu, 15 Sep 2022 07:55:20 GMT + +_Version update only_ + +## 3.5.0 +Fri, 10 Jun 2022 18:57:46 GMT + +_Version update only_ + +## 3.4.0 +Thu, 07 Apr 2022 11:56:26 GMT + +### Updates + +- Bump dependencies (#1067) + +## 3.3.1 +Wed, 23 Feb 2022 19:27:40 GMT + +_Version update only_ + +## 3.3.0 +Mon, 31 Jan 2022 15:58:10 GMT + +_Version update only_ + +## 3.2.3 +Tue, 18 Jan 2022 16:23:52 GMT + +### Updates + +- Bump Copyright to 2022 (#1040) + +## 3.2.2 +Fri, 14 Jan 2022 10:17:59 GMT + +_Version update only_ + +## 3.2.1 +Wed, 12 Jan 2022 09:50:29 GMT + +_Version update only_ + +## 3.2.0 +Tue, 11 Jan 2022 12:53:22 GMT + +_Version update only_ + +## 3.1.6 +Tue, 19 Oct 2021 09:17:22 GMT + +### Updates + +- Fix failing build on ARM Macs (#1012) +- Fix issues importing some plugins in Next SSR (#1015) + +## 3.1.5 +Fri, 01 Oct 2021 08:09:21 GMT + +_Version update only_ + +## 3.1.4 +Tue, 21 Sep 2021 14:59:36 GMT + +_Version update only_ + +## 3.1.3 +Mon, 23 Aug 2021 10:13:18 GMT + +_Version update only_ + +## 3.1.2 +Mon, 16 Aug 2021 12:59:59 GMT + +### Updates + +- Update READMEs with correct Node requirements (#994) + +## 3.1.1 +Wed, 04 Aug 2021 10:12:25 GMT + +### Updates + +- Automate api-extractor on release (#972) +- Bump tslib to 2.3.0 (#986) +- Bump typescript to 4.3.5 (#987) +- Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988) + +## 3.1.0 +Fri, 14 May 2021 10:45:32 GMT + +_Version update only_ + +## 3.0.3 +Wed, 21 Apr 2021 12:35:06 GMT + +_Version update only_ + +## 3.0.2 +Thu, 15 Apr 2021 21:07:39 GMT + +_Version update only_ + +## 3.0.1 +Wed, 14 Apr 2021 16:30:05 GMT + +### Updates + +- Add peerDependencies to plugins (#950) +- Mark packages as sideEffect: false (#951) +- Add unit tests to plugin track* functions (#954) + +## 3.0.0 +Wed, 31 Mar 2021 14:46:47 GMT + +### Updates + +- Bump rollup to 2.41 (#916) +- Publish UMD versions of plugins to GitHub release (#923) +- Ensure browser-tracker API methods catch exceptions (#919) +- Introduce TSDoc comments and extract interfaces where appropriate (#906) +- Bump major version to v3 and update READMEs (#904) +- Improve Core API for module bundlers which support treeshaking (#903) +- Rename @snowplow/browser-core to @snowplow/browser-tracker-core (#901) +- Publish lite version of sp.js (#900) +- Ensure correct 3-Clause BSD License notices are being used (#316) +- Improve API for module bundlers which support treeshaking (#899) +- Bump rush to 5.39 (#895) +- Port to TypeScript (#72) +- Make sp.js build process modular (#450) +- Create @snowplow/browser-tracker package for npm distribution (#541) +- Split auto contexts into plugins (#880) +- Add rush to manage monorepo (#883) +- Add ES Module builds (#882) +- Cleanup deprecated methods (#557) +- Update publishing process for rush (#907) +- Change white and black lists to allow and deny lists (#908) +- Create rush change files for major version 3 release (#909) + diff --git a/plugins/browser-plugin-geolocation/LICENSE b/plugins/browser-plugin-geolocation/LICENSE new file mode 100644 index 000000000..76f1946ea --- /dev/null +++ b/plugins/browser-plugin-geolocation/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/plugins/browser-plugin-geolocation/README.md b/plugins/browser-plugin-geolocation/README.md new file mode 100644 index 000000000..1e76b587d --- /dev/null +++ b/plugins/browser-plugin-geolocation/README.md @@ -0,0 +1,57 @@ +# Snowplow Geolocation Tracking + +[![npm version][npm-image]][npm-url] +[![License][license-image]](LICENSE) + +Browser Plugin to be used with `@snowplow/browser-tracker`. + +Adds Geolocation to your Snowplow tracking. + +## Maintainer quick start + +Part of the Snowplow JavaScript Tracker monorepo. +Build with [Node.js](https://nodejs.org/en/) (18 - 20) and [Rush](https://rushjs.io/). + +### Setup repository + +```bash +npm install -g @microsoft/rush +git clone https://github.com/snowplow/snowplow-javascript-tracker.git +rush update +``` + +## Package Installation + +With npm: + +```bash +npm install @snowplow/browser-plugin-geolocation +``` + +## Usage + +Initialize your tracker with the GeolocationPlugin: + +```js +import { newTracker } from '@snowplow/browser-tracker'; +import { GeolocationPlugin, enableGeolocationContext } from '@snowplow/browser-plugin-geolocation'; + +// Enables at tracker load - set to `false` to load later with `enableGeolocationContext` +newTracker('sp1', '{{collector}}', { plugins: [ GeolocationPlugin(true) ] }); + +enableGeolocationContext(); // If initializing with `false`, call this to switch it on +``` + +## Copyright and license + +Licensed and distributed under the [BSD 3-Clause License](LICENSE) ([An OSI Approved License][osi]). + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang. + +All rights reserved. + +[npm-url]: https://www.npmjs.com/package/@snowplow/browser-plugin-geolocation +[npm-image]: https://img.shields.io/npm/v/@snowplow/browser-plugin-geolocation +[docs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-tracker/ +[osi]: https://opensource.org/licenses/BSD-3-Clause +[license-image]: https://img.shields.io/npm/l/@snowplow/browser-plugin-geolocation diff --git a/plugins/browser-plugin-geolocation/package.json b/plugins/browser-plugin-geolocation/package.json new file mode 100644 index 000000000..901ab6d62 --- /dev/null +++ b/plugins/browser-plugin-geolocation/package.json @@ -0,0 +1,52 @@ +{ + "name": "@snowplow/browser-plugin-geolocation", + "version": "4.10.0", + "description": "Attaches Geolocation data to Snowplow events", + "homepage": "http://bit.ly/sp-js", + "bugs": "https://github.com/snowplow/snowplow-javascript-tracker/issues", + "repository": { + "type": "git", + "url": "https://github.com/snowplow/snowplow-javascript-tracker.git" + }, + "license": "BSD-3-Clause", + "author": "Paul Boocock", + "sideEffects": false, + "main": "./dist/index.umd.js", + "module": "./dist/index.module.js", + "types": "./dist/index.module.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "rollup -c --silent --failAfterWarnings", + "test": "" + }, + "dependencies": { + "@snowplow/browser-tracker-core": "workspace:*", + "@snowplow/tracker-core": "workspace:*", + "tslib": "^2.3.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "~21.0.2", + "@rollup/plugin-node-resolve": "~13.1.3", + "@types/jest": "~28.1.1", + "@types/jsdom": "~16.2.14", + "@typescript-eslint/eslint-plugin": "~5.15.0", + "@typescript-eslint/parser": "~5.15.0", + "eslint": "~8.11.0", + "jest": "~28.1.3", + "jest-environment-jsdom": "~28.1.3", + "jest-environment-jsdom-global": "~4.0.0", + "jest-standard-reporter": "~2.0.0", + "rollup": "~2.70.1", + "rollup-plugin-cleanup": "~3.2.1", + "rollup-plugin-license": "~2.6.1", + "rollup-plugin-terser": "~7.0.2", + "rollup-plugin-ts": "~2.0.5", + "ts-jest": "~28.0.8", + "typescript": "~4.6.2" + }, + "peerDependencies": { + "@snowplow/browser-tracker": "~4.10.0" + } +} diff --git a/plugins/browser-plugin-geolocation/rollup.config.js b/plugins/browser-plugin-geolocation/rollup.config.js new file mode 100644 index 000000000..ae1d93d44 --- /dev/null +++ b/plugins/browser-plugin-geolocation/rollup.config.js @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import ts from 'rollup-plugin-ts'; // Prefered over @rollup/plugin-typescript as it bundles .d.ts files +import { banner } from '../../banner'; +import { terser } from 'rollup-plugin-terser'; +import cleanup from 'rollup-plugin-cleanup'; +import pkg from './package.json'; +import { builtinModules } from 'module'; + +const umdPlugins = [nodeResolve({ browser: true }), commonjs(), ts()]; +const umdName = 'snowplowGeolocation'; + +export default [ + // CommonJS (for Node) and ES module (for bundlers) build. + { + input: './src/index.ts', + plugins: [...umdPlugins, banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main, format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + plugins: [...umdPlugins, terser(), cleanup({ comments: 'none' }), banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main.replace('.js', '.min.js'), format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + external: [...builtinModules, ...Object.keys(pkg.dependencies), ...Object.keys(pkg.devDependencies)], + plugins: [ + ts(), // so Rollup can convert TypeScript to JavaScript + banner(), + ], + output: [{ file: pkg.module, format: 'es', sourcemap: true }], + }, +]; diff --git a/plugins/browser-plugin-geolocation/src/contexts.ts b/plugins/browser-plugin-geolocation/src/contexts.ts new file mode 100644 index 000000000..cef754020 --- /dev/null +++ b/plugins/browser-plugin-geolocation/src/contexts.ts @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Schema for client geolocation contexts + */ +export interface Geolocation { + latitude: number; + longitude: number; + latitudeLongitudeAccuracy?: number | null; + altitude?: number | null; + altitudeAccuracy?: number | null; + bearing?: number | null; + speed?: number | null; + timestamp?: number | null; + [key: string]: unknown; +} diff --git a/plugins/browser-plugin-geolocation/src/index.ts b/plugins/browser-plugin-geolocation/src/index.ts new file mode 100644 index 000000000..894bead4f --- /dev/null +++ b/plugins/browser-plugin-geolocation/src/index.ts @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { SelfDescribingJson } from '@snowplow/tracker-core'; +import { BrowserPlugin } from '@snowplow/browser-tracker-core'; +import { Geolocation } from './contexts'; + +const _trackers: Record | undefined]> = {}; + +let geolocation: SelfDescribingJson, + geolocationContextAdded = false; + +/** + * Captures the geolocation information from the users browser + * The geolocation will be cached and will be only be requested once + * @param enableAtLoad - Should the geolocation context be populated immediately + * + * @remarks + * Enabling this will produce a popup for the user asking for permission to read their location information + */ +export function GeolocationPlugin(enableAtLoad: boolean = false): BrowserPlugin { + let trackerId: string; + + return { + activateBrowserPlugin: (tracker) => { + trackerId = tracker.id; + _trackers[tracker.id] = [false, undefined]; + + if (enableAtLoad) { + enableGeolocationContext([trackerId]); + } + }, + contexts: () => { + let context = _trackers[trackerId]?.[1]; + if (context) { + return [context]; + } + + return []; + }, + }; +} + +/** + * Attempts to create a context using the geolocation API + * + * @param trackers - The tracker identifiers which the context will be sent to + */ +export function enableGeolocationContext(trackers: Array = Object.keys(_trackers)) { + const navigatorAlias = navigator; + + trackers.forEach((t) => { + //Mark as enabled + _trackers[t] = [true, geolocation]; // Geolocation might still be undefined but it could also be set already + }); + + if (!geolocationContextAdded && navigatorAlias.geolocation && navigatorAlias.geolocation.getCurrentPosition) { + geolocationContextAdded = true; + navigatorAlias.geolocation.getCurrentPosition(function (position) { + var coords = position.coords; + geolocation = { + schema: 'iglu:com.snowplowanalytics.snowplow/geolocation_context/jsonschema/1-1-0', + data: { + latitude: coords.latitude, + longitude: coords.longitude, + latitudeLongitudeAccuracy: coords.accuracy, + altitude: coords.altitude, + altitudeAccuracy: coords.altitudeAccuracy, + bearing: coords.heading, + speed: coords.speed, + timestamp: Math.round(position.timestamp), + }, + }; + + // Ensure all trackers with geolocation enabled have the context set + for (const key in _trackers) { + if (Object.prototype.hasOwnProperty.call(_trackers, key) && _trackers[key][0]) { + _trackers[key] = [true, geolocation]; + } + } + }); + } +} diff --git a/plugins/browser-plugin-geolocation/tsconfig.json b/plugins/browser-plugin-geolocation/tsconfig.json new file mode 100644 index 000000000..4082f16a5 --- /dev/null +++ b/plugins/browser-plugin-geolocation/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +} diff --git a/plugins/browser-plugin-link-click-tracking/CHANGELOG.json b/plugins/browser-plugin-link-click-tracking/CHANGELOG.json new file mode 100644 index 000000000..d46303677 --- /dev/null +++ b/plugins/browser-plugin-link-click-tracking/CHANGELOG.json @@ -0,0 +1,626 @@ +{ + "name": "@snowplow/browser-plugin-link-click-tracking", + "entries": [ + { + "version": "4.10.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.10.0", + "date": "Mon, 27 Jul 2026 13:52:14 GMT", + "comments": {} + }, + { + "version": "4.9.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.9.0", + "date": "Tue, 21 Jul 2026 14:53:08 GMT", + "comments": {} + }, + { + "version": "4.8.4", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.8.4", + "date": "Thu, 02 Jul 2026 10:07:52 GMT", + "comments": {} + }, + { + "version": "4.8.3", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.8.3", + "date": "Tue, 30 Jun 2026 14:22:03 GMT", + "comments": { + "none": [ + { + "comment": "Update uuid to v11 and remove closure-compiler from the build pipeline" + } + ] + } + }, + { + "version": "4.8.2", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.8.2", + "date": "Wed, 17 Jun 2026 12:30:12 GMT", + "comments": {} + }, + { + "version": "4.8.1", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.8.1", + "date": "Wed, 13 May 2026 09:26:05 GMT", + "comments": {} + }, + { + "version": "4.8.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.8.0", + "date": "Tue, 28 Apr 2026 07:56:22 GMT", + "comments": {} + }, + { + "version": "4.7.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.7.0", + "date": "Wed, 01 Apr 2026 12:59:29 GMT", + "comments": {} + }, + { + "version": "4.6.9", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.6.9", + "date": "Mon, 16 Mar 2026 15:43:06 GMT", + "comments": {} + }, + { + "version": "4.6.8", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.6.8", + "date": "Tue, 28 Oct 2025 09:46:42 GMT", + "comments": {} + }, + { + "version": "4.6.7", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.6.7", + "date": "Tue, 07 Oct 2025 14:53:36 GMT", + "comments": {} + }, + { + "version": "4.6.6", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.6.6", + "date": "Tue, 26 Aug 2025 08:42:27 GMT", + "comments": {} + }, + { + "version": "4.6.5", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.6.5", + "date": "Wed, 25 Jun 2025 21:16:46 GMT", + "comments": {} + }, + { + "version": "4.6.4", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.6.4", + "date": "Wed, 25 Jun 2025 12:08:50 GMT", + "comments": {} + }, + { + "version": "4.6.3", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.6.3", + "date": "Thu, 29 May 2025 19:52:07 GMT", + "comments": {} + }, + { + "version": "4.6.2", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.6.2", + "date": "Tue, 20 May 2025 07:39:05 GMT", + "comments": {} + }, + { + "version": "4.6.1", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.6.1", + "date": "Tue, 06 May 2025 13:10:51 GMT", + "comments": {} + }, + { + "version": "4.6.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.6.0", + "date": "Thu, 01 May 2025 09:58:59 GMT", + "comments": {} + }, + { + "version": "4.5.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.5.0", + "date": "Fri, 04 Apr 2025 09:21:23 GMT", + "comments": {} + }, + { + "version": "4.4.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.4.0", + "date": "Thu, 20 Mar 2025 12:14:34 GMT", + "comments": {} + }, + { + "version": "4.3.1", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.3.1", + "date": "Tue, 21 Jan 2025 11:09:42 GMT", + "comments": {} + }, + { + "version": "4.3.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.3.0", + "date": "Mon, 20 Jan 2025 11:45:13 GMT", + "comments": {} + }, + { + "version": "4.2.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.2.0", + "date": "Mon, 13 Jan 2025 08:30:05 GMT", + "comments": {} + }, + { + "version": "4.1.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.1.0", + "date": "Thu, 28 Nov 2024 10:57:30 GMT", + "comments": {} + }, + { + "version": "4.0.4", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.0.4", + "date": "Thu, 21 Nov 2024 09:06:36 GMT", + "comments": { + "none": [ + { + "comment": "Fix multiple link click events tracked for a single tracker in case multiple trackers are initialized on the page (#1384)" + } + ] + } + }, + { + "version": "4.0.3", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.0.3", + "date": "Wed, 20 Nov 2024 09:30:31 GMT", + "comments": {} + }, + { + "version": "4.0.2", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.0.2", + "date": "Mon, 11 Nov 2024 15:46:34 GMT", + "comments": {} + }, + { + "version": "4.0.1", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.0.1", + "date": "Fri, 01 Nov 2024 10:35:07 GMT", + "comments": {} + }, + { + "version": "4.0.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v4.0.0", + "date": "Mon, 28 Oct 2024 11:48:53 GMT", + "comments": { + "none": [ + { + "comment": "Update plugin to use global rather than per-element event listeners" + }, + { + "comment": "Detect link clicks within ShadowRoots" + } + ] + } + }, + { + "version": "3.24.6", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.24.6", + "date": "Mon, 28 Oct 2024 10:23:28 GMT", + "comments": {} + }, + { + "version": "3.24.5", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.24.5", + "date": "Fri, 25 Oct 2024 08:53:04 GMT", + "comments": {} + }, + { + "version": "3.24.4", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.24.4", + "date": "Thu, 26 Sep 2024 06:10:22 GMT", + "comments": {} + }, + { + "version": "3.24.3", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.24.3", + "date": "Tue, 03 Sep 2024 08:15:14 GMT", + "comments": { + "none": [ + { + "comment": "Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush" + } + ] + } + }, + { + "version": "3.24.2", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.24.2", + "date": "Wed, 24 Jul 2024 08:59:00 GMT", + "comments": {} + }, + { + "version": "3.24.1", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.24.1", + "date": "Tue, 02 Jul 2024 07:08:17 GMT", + "comments": {} + }, + { + "version": "3.24.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.24.0", + "date": "Tue, 25 Jun 2024 08:31:05 GMT", + "comments": {} + }, + { + "version": "3.23.1", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.23.1", + "date": "Tue, 04 Jun 2024 13:34:45 GMT", + "comments": {} + }, + { + "version": "3.23.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.23.0", + "date": "Thu, 28 Mar 2024 11:28:45 GMT", + "comments": {} + }, + { + "version": "3.22.1", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.22.1", + "date": "Wed, 13 Mar 2024 08:39:48 GMT", + "comments": {} + }, + { + "version": "3.22.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.22.0", + "date": "Fri, 08 Mar 2024 08:13:04 GMT", + "comments": {} + }, + { + "version": "3.21.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.21.0", + "date": "Mon, 29 Jan 2024 08:34:06 GMT", + "comments": {} + }, + { + "version": "3.20.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.20.0", + "date": "Mon, 15 Jan 2024 14:41:16 GMT", + "comments": {} + }, + { + "version": "3.19.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.19.0", + "date": "Thu, 14 Dec 2023 10:45:22 GMT", + "comments": {} + }, + { + "version": "3.18.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.18.0", + "date": "Mon, 04 Dec 2023 13:44:02 GMT", + "comments": { + "none": [ + { + "comment": "Track mailto links in link click tracking (#1270)" + } + ] + } + }, + { + "version": "3.17.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.17.0", + "date": "Tue, 14 Nov 2023 17:58:26 GMT", + "comments": {} + }, + { + "version": "3.16.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.16.0", + "date": "Mon, 16 Oct 2023 14:58:08 GMT", + "comments": {} + }, + { + "version": "3.15.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.15.0", + "date": "Mon, 28 Aug 2023 14:25:14 GMT", + "comments": {} + }, + { + "version": "3.14.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.14.0", + "date": "Thu, 10 Aug 2023 13:56:44 GMT", + "comments": {} + }, + { + "version": "3.13.1", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.13.1", + "date": "Thu, 29 Jun 2023 14:20:06 GMT", + "comments": {} + }, + { + "version": "3.13.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.13.0", + "date": "Tue, 20 Jun 2023 07:44:23 GMT", + "comments": {} + }, + { + "version": "3.12.1", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.12.1", + "date": "Thu, 15 Jun 2023 10:05:37 GMT", + "comments": {} + }, + { + "version": "3.12.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.12.0", + "date": "Mon, 05 Jun 2023 11:51:22 GMT", + "comments": {} + }, + { + "version": "3.11.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.11.0", + "date": "Wed, 24 May 2023 15:56:17 GMT", + "comments": {} + }, + { + "version": "3.10.1", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.10.1", + "date": "Fri, 12 May 2023 06:59:31 GMT", + "comments": {} + }, + { + "version": "3.10.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.10.0", + "date": "Thu, 11 May 2023 08:29:15 GMT", + "comments": {} + }, + { + "version": "3.9.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.9.0", + "date": "Thu, 30 Mar 2023 13:46:56 GMT", + "comments": {} + }, + { + "version": "3.8.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.8.0", + "date": "Tue, 03 Jan 2023 15:36:33 GMT", + "comments": {} + }, + { + "version": "3.7.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.7.0", + "date": "Mon, 31 Oct 2022 06:26:28 GMT", + "comments": {} + }, + { + "version": "3.6.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.6.0", + "date": "Thu, 15 Sep 2022 07:55:20 GMT", + "comments": {} + }, + { + "version": "3.5.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.5.0", + "date": "Fri, 10 Jun 2022 18:57:46 GMT", + "comments": {} + }, + { + "version": "3.4.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.4.0", + "date": "Thu, 07 Apr 2022 11:56:26 GMT", + "comments": { + "none": [ + { + "comment": "Bump dependencies (#1067)" + } + ] + } + }, + { + "version": "3.3.1", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.3.1", + "date": "Wed, 23 Feb 2022 19:27:40 GMT", + "comments": {} + }, + { + "version": "3.3.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.3.0", + "date": "Mon, 31 Jan 2022 15:58:10 GMT", + "comments": {} + }, + { + "version": "3.2.3", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.2.3", + "date": "Tue, 18 Jan 2022 16:23:52 GMT", + "comments": { + "none": [ + { + "comment": "Bump Copyright to 2022 (#1040)" + } + ] + } + }, + { + "version": "3.2.2", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.2.2", + "date": "Fri, 14 Jan 2022 10:17:59 GMT", + "comments": {} + }, + { + "version": "3.2.1", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.2.1", + "date": "Wed, 12 Jan 2022 09:50:29 GMT", + "comments": {} + }, + { + "version": "3.2.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.2.0", + "date": "Tue, 11 Jan 2022 12:53:22 GMT", + "comments": {} + }, + { + "version": "3.1.6", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.1.6", + "date": "Tue, 19 Oct 2021 09:17:22 GMT", + "comments": { + "none": [ + { + "comment": "Fix failing build on ARM Macs (#1012)" + } + ] + } + }, + { + "version": "3.1.5", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.1.5", + "date": "Fri, 01 Oct 2021 08:09:21 GMT", + "comments": {} + }, + { + "version": "3.1.4", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.1.4", + "date": "Tue, 21 Sep 2021 14:59:36 GMT", + "comments": {} + }, + { + "version": "3.1.3", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.1.3", + "date": "Mon, 23 Aug 2021 10:13:18 GMT", + "comments": {} + }, + { + "version": "3.1.2", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.1.2", + "date": "Mon, 16 Aug 2021 12:59:59 GMT", + "comments": { + "none": [ + { + "comment": "Update READMEs with correct Node requirements (#994)" + } + ] + } + }, + { + "version": "3.1.1", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.1.1", + "date": "Wed, 04 Aug 2021 10:12:25 GMT", + "comments": { + "none": [ + { + "comment": "Automate api-extractor on release (#972)" + }, + { + "comment": "Bump tslib to 2.3.0 (#986)" + }, + { + "comment": "Bump typescript to 4.3.5 (#987)" + }, + { + "comment": "Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988)" + } + ] + } + }, + { + "version": "3.1.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.1.0", + "date": "Fri, 14 May 2021 10:45:32 GMT", + "comments": {} + }, + { + "version": "3.0.3", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.0.3", + "date": "Wed, 21 Apr 2021 12:35:06 GMT", + "comments": {} + }, + { + "version": "3.0.2", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.0.2", + "date": "Thu, 15 Apr 2021 21:07:39 GMT", + "comments": {} + }, + { + "version": "3.0.1", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.0.1", + "date": "Wed, 14 Apr 2021 16:30:05 GMT", + "comments": { + "none": [ + { + "comment": "Fix typo in link-click-tracking plugin (#946)" + }, + { + "comment": "Add peerDependencies to plugins (#950)" + }, + { + "comment": "Mark packages as sideEffect: false (#951)" + }, + { + "comment": "Add unit tests to plugin track* functions (#954)" + } + ] + } + }, + { + "version": "3.0.0", + "tag": "@snowplow/browser-plugin-link-click-tracking_v3.0.0", + "date": "Wed, 31 Mar 2021 14:46:47 GMT", + "comments": { + "none": [ + { + "comment": "Bump rollup to 2.41 (#916)" + }, + { + "comment": "Publish UMD versions of plugins to GitHub release (#923)" + }, + { + "comment": "Ensure browser-tracker API methods catch exceptions (#919)" + }, + { + "comment": "Introduce TSDoc comments and extract interfaces where appropriate (#906)" + }, + { + "comment": "Bump major version to v3 and update READMEs (#904)" + }, + { + "comment": "Improve Core API for module bundlers which support treeshaking (#903)" + }, + { + "comment": "Rename @snowplow/browser-core to @snowplow/browser-tracker-core (#901)" + }, + { + "comment": "Publish lite version of sp.js (#900)" + }, + { + "comment": "Ensure correct 3-Clause BSD License notices are being used (#316)" + }, + { + "comment": "Improve API for module bundlers which support treeshaking (#899)" + }, + { + "comment": "Bump rush to 5.39 (#895)" + }, + { + "comment": "Port to TypeScript (#72)" + }, + { + "comment": "Make sp.js build process modular (#450)" + }, + { + "comment": "Create @snowplow/browser-tracker package for npm distribution (#541)" + }, + { + "comment": "Split auto contexts into plugins (#880)" + }, + { + "comment": "Add rush to manage monorepo (#883)" + }, + { + "comment": "Add ES Module builds (#882)" + }, + { + "comment": "Cleanup deprecated methods (#557)" + }, + { + "comment": "Update publishing process for rush (#907)" + }, + { + "comment": "Change white and black lists to allow and deny lists (#908)" + }, + { + "comment": "Create rush change files for major version 3 release (#909)" + } + ] + } + } + ] +} diff --git a/plugins/browser-plugin-link-click-tracking/CHANGELOG.md b/plugins/browser-plugin-link-click-tracking/CHANGELOG.md new file mode 100644 index 000000000..1de7ae1d8 --- /dev/null +++ b/plugins/browser-plugin-link-click-tracking/CHANGELOG.md @@ -0,0 +1,445 @@ +# Change Log - @snowplow/browser-plugin-link-click-tracking + +This log was last generated on Mon, 27 Jul 2026 13:52:14 GMT and should not be manually modified. + +## 4.10.0 +Mon, 27 Jul 2026 13:52:14 GMT + +_Version update only_ + +## 4.9.0 +Tue, 21 Jul 2026 14:53:08 GMT + +_Version update only_ + +## 4.8.4 +Thu, 02 Jul 2026 10:07:52 GMT + +_Version update only_ + +## 4.8.3 +Tue, 30 Jun 2026 14:22:03 GMT + +### Updates + +- Update uuid to v11 and remove closure-compiler from the build pipeline + +## 4.8.2 +Wed, 17 Jun 2026 12:30:12 GMT + +_Version update only_ + +## 4.8.1 +Wed, 13 May 2026 09:26:05 GMT + +_Version update only_ + +## 4.8.0 +Tue, 28 Apr 2026 07:56:22 GMT + +_Version update only_ + +## 4.7.0 +Wed, 01 Apr 2026 12:59:29 GMT + +_Version update only_ + +## 4.6.9 +Mon, 16 Mar 2026 15:43:06 GMT + +_Version update only_ + +## 4.6.8 +Tue, 28 Oct 2025 09:46:42 GMT + +_Version update only_ + +## 4.6.7 +Tue, 07 Oct 2025 14:53:36 GMT + +_Version update only_ + +## 4.6.6 +Tue, 26 Aug 2025 08:42:27 GMT + +_Version update only_ + +## 4.6.5 +Wed, 25 Jun 2025 21:16:46 GMT + +_Version update only_ + +## 4.6.4 +Wed, 25 Jun 2025 12:08:50 GMT + +_Version update only_ + +## 4.6.3 +Thu, 29 May 2025 19:52:07 GMT + +_Version update only_ + +## 4.6.2 +Tue, 20 May 2025 07:39:05 GMT + +_Version update only_ + +## 4.6.1 +Tue, 06 May 2025 13:10:51 GMT + +_Version update only_ + +## 4.6.0 +Thu, 01 May 2025 09:58:59 GMT + +_Version update only_ + +## 4.5.0 +Fri, 04 Apr 2025 09:21:23 GMT + +_Version update only_ + +## 4.4.0 +Thu, 20 Mar 2025 12:14:34 GMT + +_Version update only_ + +## 4.3.1 +Tue, 21 Jan 2025 11:09:42 GMT + +_Version update only_ + +## 4.3.0 +Mon, 20 Jan 2025 11:45:13 GMT + +_Version update only_ + +## 4.2.0 +Mon, 13 Jan 2025 08:30:05 GMT + +_Version update only_ + +## 4.1.0 +Thu, 28 Nov 2024 10:57:30 GMT + +_Version update only_ + +## 4.0.4 +Thu, 21 Nov 2024 09:06:36 GMT + +### Updates + +- Fix multiple link click events tracked for a single tracker in case multiple trackers are initialized on the page (#1384) + +## 4.0.3 +Wed, 20 Nov 2024 09:30:31 GMT + +_Version update only_ + +## 4.0.2 +Mon, 11 Nov 2024 15:46:34 GMT + +_Version update only_ + +## 4.0.1 +Fri, 01 Nov 2024 10:35:07 GMT + +_Version update only_ + +## 4.0.0 +Mon, 28 Oct 2024 11:48:53 GMT + +### Updates + +- Update plugin to use global rather than per-element event listeners +- Detect link clicks within ShadowRoots + +## 3.24.6 +Mon, 28 Oct 2024 10:23:28 GMT + +_Version update only_ + +## 3.24.5 +Fri, 25 Oct 2024 08:53:04 GMT + +_Version update only_ + +## 3.24.4 +Thu, 26 Sep 2024 06:10:22 GMT + +_Version update only_ + +## 3.24.3 +Tue, 03 Sep 2024 08:15:14 GMT + +### Updates + +- Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush + +## 3.24.2 +Wed, 24 Jul 2024 08:59:00 GMT + +_Version update only_ + +## 3.24.1 +Tue, 02 Jul 2024 07:08:17 GMT + +_Version update only_ + +## 3.24.0 +Tue, 25 Jun 2024 08:31:05 GMT + +_Version update only_ + +## 3.23.1 +Tue, 04 Jun 2024 13:34:45 GMT + +_Version update only_ + +## 3.23.0 +Thu, 28 Mar 2024 11:28:45 GMT + +_Version update only_ + +## 3.22.1 +Wed, 13 Mar 2024 08:39:48 GMT + +_Version update only_ + +## 3.22.0 +Fri, 08 Mar 2024 08:13:04 GMT + +_Version update only_ + +## 3.21.0 +Mon, 29 Jan 2024 08:34:06 GMT + +_Version update only_ + +## 3.20.0 +Mon, 15 Jan 2024 14:41:16 GMT + +_Version update only_ + +## 3.19.0 +Thu, 14 Dec 2023 10:45:22 GMT + +_Version update only_ + +## 3.18.0 +Mon, 04 Dec 2023 13:44:02 GMT + +### Updates + +- Track mailto links in link click tracking (#1270) + +## 3.17.0 +Tue, 14 Nov 2023 17:58:26 GMT + +_Version update only_ + +## 3.16.0 +Mon, 16 Oct 2023 14:58:08 GMT + +_Version update only_ + +## 3.15.0 +Mon, 28 Aug 2023 14:25:14 GMT + +_Version update only_ + +## 3.14.0 +Thu, 10 Aug 2023 13:56:44 GMT + +_Version update only_ + +## 3.13.1 +Thu, 29 Jun 2023 14:20:06 GMT + +_Version update only_ + +## 3.13.0 +Tue, 20 Jun 2023 07:44:23 GMT + +_Version update only_ + +## 3.12.1 +Thu, 15 Jun 2023 10:05:37 GMT + +_Version update only_ + +## 3.12.0 +Mon, 05 Jun 2023 11:51:22 GMT + +_Version update only_ + +## 3.11.0 +Wed, 24 May 2023 15:56:17 GMT + +_Version update only_ + +## 3.10.1 +Fri, 12 May 2023 06:59:31 GMT + +_Version update only_ + +## 3.10.0 +Thu, 11 May 2023 08:29:15 GMT + +_Version update only_ + +## 3.9.0 +Thu, 30 Mar 2023 13:46:56 GMT + +_Version update only_ + +## 3.8.0 +Tue, 03 Jan 2023 15:36:33 GMT + +_Version update only_ + +## 3.7.0 +Mon, 31 Oct 2022 06:26:28 GMT + +_Version update only_ + +## 3.6.0 +Thu, 15 Sep 2022 07:55:20 GMT + +_Version update only_ + +## 3.5.0 +Fri, 10 Jun 2022 18:57:46 GMT + +_Version update only_ + +## 3.4.0 +Thu, 07 Apr 2022 11:56:26 GMT + +### Updates + +- Bump dependencies (#1067) + +## 3.3.1 +Wed, 23 Feb 2022 19:27:40 GMT + +_Version update only_ + +## 3.3.0 +Mon, 31 Jan 2022 15:58:10 GMT + +_Version update only_ + +## 3.2.3 +Tue, 18 Jan 2022 16:23:52 GMT + +### Updates + +- Bump Copyright to 2022 (#1040) + +## 3.2.2 +Fri, 14 Jan 2022 10:17:59 GMT + +_Version update only_ + +## 3.2.1 +Wed, 12 Jan 2022 09:50:29 GMT + +_Version update only_ + +## 3.2.0 +Tue, 11 Jan 2022 12:53:22 GMT + +_Version update only_ + +## 3.1.6 +Tue, 19 Oct 2021 09:17:22 GMT + +### Updates + +- Fix failing build on ARM Macs (#1012) + +## 3.1.5 +Fri, 01 Oct 2021 08:09:21 GMT + +_Version update only_ + +## 3.1.4 +Tue, 21 Sep 2021 14:59:36 GMT + +_Version update only_ + +## 3.1.3 +Mon, 23 Aug 2021 10:13:18 GMT + +_Version update only_ + +## 3.1.2 +Mon, 16 Aug 2021 12:59:59 GMT + +### Updates + +- Update READMEs with correct Node requirements (#994) + +## 3.1.1 +Wed, 04 Aug 2021 10:12:25 GMT + +### Updates + +- Automate api-extractor on release (#972) +- Bump tslib to 2.3.0 (#986) +- Bump typescript to 4.3.5 (#987) +- Switch from @wessberg/rollup-plugin-ts to rollup-plugin-ts (#988) + +## 3.1.0 +Fri, 14 May 2021 10:45:32 GMT + +_Version update only_ + +## 3.0.3 +Wed, 21 Apr 2021 12:35:06 GMT + +_Version update only_ + +## 3.0.2 +Thu, 15 Apr 2021 21:07:39 GMT + +_Version update only_ + +## 3.0.1 +Wed, 14 Apr 2021 16:30:05 GMT + +### Updates + +- Fix typo in link-click-tracking plugin (#946) +- Add peerDependencies to plugins (#950) +- Mark packages as sideEffect: false (#951) +- Add unit tests to plugin track* functions (#954) + +## 3.0.0 +Wed, 31 Mar 2021 14:46:47 GMT + +### Updates + +- Bump rollup to 2.41 (#916) +- Publish UMD versions of plugins to GitHub release (#923) +- Ensure browser-tracker API methods catch exceptions (#919) +- Introduce TSDoc comments and extract interfaces where appropriate (#906) +- Bump major version to v3 and update READMEs (#904) +- Improve Core API for module bundlers which support treeshaking (#903) +- Rename @snowplow/browser-core to @snowplow/browser-tracker-core (#901) +- Publish lite version of sp.js (#900) +- Ensure correct 3-Clause BSD License notices are being used (#316) +- Improve API for module bundlers which support treeshaking (#899) +- Bump rush to 5.39 (#895) +- Port to TypeScript (#72) +- Make sp.js build process modular (#450) +- Create @snowplow/browser-tracker package for npm distribution (#541) +- Split auto contexts into plugins (#880) +- Add rush to manage monorepo (#883) +- Add ES Module builds (#882) +- Cleanup deprecated methods (#557) +- Update publishing process for rush (#907) +- Change white and black lists to allow and deny lists (#908) +- Create rush change files for major version 3 release (#909) + diff --git a/plugins/browser-plugin-link-click-tracking/LICENSE b/plugins/browser-plugin-link-click-tracking/LICENSE new file mode 100644 index 000000000..76f1946ea --- /dev/null +++ b/plugins/browser-plugin-link-click-tracking/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/plugins/browser-plugin-link-click-tracking/README.md b/plugins/browser-plugin-link-click-tracking/README.md new file mode 100644 index 000000000..39da9bff9 --- /dev/null +++ b/plugins/browser-plugin-link-click-tracking/README.md @@ -0,0 +1,71 @@ +# Snowplow Link Click Tracking + +[![npm version][npm-image]][npm-url] +[![License][license-image]](LICENSE) + +Browser Plugin to be used with `@snowplow/browser-tracker`. + +Adds link click tracking events to your Snowplow tracking. + +## Maintainer quick start + +Part of the Snowplow JavaScript Tracker monorepo. +Build with [Node.js](https://nodejs.org/en/) ( 18 - 20) and [Rush](https://rushjs.io/). + +### Setup repository + +```bash +npm install -g @microsoft/rush +git clone https://github.com/snowplow/snowplow-javascript-tracker.git +rush update +``` + +## Package Installation + +With npm: + +```bash +npm install @snowplow/browser-plugin-link-click-tracking +``` + +## Usage + +Initialize your tracker with the LinkClickTrackingPlugin: + +```js +import { newTracker } from '@snowplow/browser-tracker'; +import { LinkClickTrackingPlugin } from '@snowplow/browser-plugin-link-click-tracking'; + +newTracker('sp1', '{{collector}}', { plugins: [ LinkClickTrackingPlugin() ] }); // Also stores reference at module level +``` + +Then use the available functions from this package to track to all trackers which have been initialized with this plugin: + +```js +import { enableLinkClickTracking } from '@snowplow/browser-plugin-link-click-tracking'; + +enableLinkClickTracking({ options: { ... }, psuedoClicks: true }); +``` + +You can also explicitly track a click without installing listeners: + +```js +import { trackLinkClick } from '@snowplow/browser-plugin-link-click-tracking'; + +trackLinkClick({ element: document.querySelector("a, area") }); +trackLinkClick({ targetUrl: "http://example.com/" }); +``` + +## Copyright and license + +Licensed and distributed under the [BSD 3-Clause License](LICENSE) ([An OSI Approved License][osi]). + +Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang. + +All rights reserved. + +[npm-url]: https://www.npmjs.com/package/@snowplow/browser-plugin-form-tracking +[npm-image]: https://img.shields.io/npm/v/@snowplow/browser-plugin-form-tracking +[docs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-tracker/ +[osi]: https://opensource.org/licenses/BSD-3-Clause +[license-image]: https://img.shields.io/npm/l/@snowplow/browser-plugin-form-tracking diff --git a/plugins/browser-plugin-link-click-tracking/jest.config.js b/plugins/browser-plugin-link-click-tracking/jest.config.js new file mode 100644 index 000000000..87d15da9b --- /dev/null +++ b/plugins/browser-plugin-link-click-tracking/jest.config.js @@ -0,0 +1,6 @@ +module.exports = { + preset: 'ts-jest', + reporters: ['jest-standard-reporter'], + setupFilesAfterEnv: ['../../setupTestGlobals.ts'], + testEnvironment: 'jest-environment-jsdom-global', +}; diff --git a/plugins/browser-plugin-link-click-tracking/package.json b/plugins/browser-plugin-link-click-tracking/package.json new file mode 100644 index 000000000..00be780d0 --- /dev/null +++ b/plugins/browser-plugin-link-click-tracking/package.json @@ -0,0 +1,54 @@ +{ + "name": "@snowplow/browser-plugin-link-click-tracking", + "version": "4.10.0", + "description": "Link Click tracking for Snowplow", + "homepage": "http://bit.ly/sp-js", + "bugs": "https://github.com/snowplow/snowplow-javascript-tracker/issues", + "repository": { + "type": "git", + "url": "https://github.com/snowplow/snowplow-javascript-tracker.git" + }, + "license": "BSD-3-Clause", + "author": "Paul Boocock", + "sideEffects": false, + "main": "./dist/index.umd.js", + "module": "./dist/index.module.js", + "types": "./dist/index.module.d.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "rollup -c --silent --failAfterWarnings", + "test": "jest" + }, + "dependencies": { + "@snowplow/browser-tracker-core": "workspace:*", + "@snowplow/tracker-core": "workspace:*", + "tslib": "^2.3.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "~21.0.2", + "@rollup/plugin-node-resolve": "~13.1.3", + "@types/jest": "~28.1.1", + "@types/jsdom": "~16.2.14", + "@types/lodash": "~4.14.180", + "@typescript-eslint/eslint-plugin": "~5.15.0", + "@typescript-eslint/parser": "~5.15.0", + "eslint": "~8.11.0", + "jest": "~28.1.3", + "jest-environment-jsdom": "~28.1.3", + "jest-environment-jsdom-global": "~4.0.0", + "jest-standard-reporter": "~2.0.0", + "lodash": "~4.17.21", + "rollup": "~2.70.1", + "rollup-plugin-cleanup": "~3.2.1", + "rollup-plugin-license": "~2.6.1", + "rollup-plugin-terser": "~7.0.2", + "rollup-plugin-ts": "~2.0.5", + "ts-jest": "~28.0.8", + "typescript": "~4.6.2" + }, + "peerDependencies": { + "@snowplow/browser-tracker": "~4.10.0" + } +} diff --git a/plugins/browser-plugin-link-click-tracking/rollup.config.js b/plugins/browser-plugin-link-click-tracking/rollup.config.js new file mode 100644 index 000000000..132b51fdb --- /dev/null +++ b/plugins/browser-plugin-link-click-tracking/rollup.config.js @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import ts from 'rollup-plugin-ts'; // Prefered over @rollup/plugin-typescript as it bundles .d.ts files +import { banner } from '../../banner'; +import { terser } from 'rollup-plugin-terser'; +import cleanup from 'rollup-plugin-cleanup'; +import pkg from './package.json'; +import { builtinModules } from 'module'; + +const umdPlugins = [nodeResolve({ browser: true }), commonjs(), ts()]; +const umdName = 'snowplowLinkClickTracking'; + +export default [ + // CommonJS (for Node) and ES module (for bundlers) build. + { + input: './src/index.ts', + plugins: [...umdPlugins, banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main, format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + plugins: [...umdPlugins, terser(), cleanup({ comments: 'none' }), banner()], + treeshake: { moduleSideEffects: ['sha1'] }, + output: [{ file: pkg.main.replace('.js', '.min.js'), format: 'umd', sourcemap: true, name: umdName }], + }, + { + input: './src/index.ts', + external: [...builtinModules, ...Object.keys(pkg.dependencies), ...Object.keys(pkg.devDependencies)], + plugins: [ + ts(), // so Rollup can convert TypeScript to JavaScript + banner(), + ], + output: [{ file: pkg.module, format: 'es', sourcemap: true }], + }, +]; diff --git a/plugins/browser-plugin-link-click-tracking/src/index.ts b/plugins/browser-plugin-link-click-tracking/src/index.ts new file mode 100644 index 000000000..b7c060993 --- /dev/null +++ b/plugins/browser-plugin-link-click-tracking/src/index.ts @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { + addEventListener, + dispatchToTrackersInCollection, + getCssClasses, + getFilterByClass, + getHostName, + flushPendingCookies, + type BrowserPlugin, + type BrowserTracker, + type FilterCriterion, +} from '@snowplow/browser-tracker-core'; + +import { + buildLinkClick, + resolveDynamicContext, + type CommonEventProperties, + type DynamicContext, + type LinkClickEvent, + type Logger, + type PayloadBuilder, +} from '@snowplow/tracker-core'; + +interface LinkClickConfiguration { + linkTrackingFilter?: (element: HTMLElement) => boolean; + // Whether pseudo clicks are tracked + linkTrackingPseudoClicks?: boolean | null; + // Whether to track the innerHTML of clicked links + linkTrackingContent?: boolean | null; + // The context attached to link click events + linkTrackingContext?: DynamicContext | null; + lastButton?: number; + lastTarget?: EventTarget; +} + +type TrackableElement = HTMLAnchorElement | HTMLAreaElement; + +const TRACKABLE_ELEMENTS = ['a', 'area']; // should be kept in sync with TrackableElement type +const TRACKABLE_ELEMENTS_SELECTOR = TRACKABLE_ELEMENTS.join(', '); +const ELEMENT_PROTOCOL_FILTER = /^(javascript|vbscript|jscript|mocha|livescript|ecmascript):/i; + +const _trackers: Record = {}; +const _listeners: Record = {}; +const _configuration: Record = {}; +let _logger: Logger | undefined = undefined; + +/** + * Link click tracking. + * + * Will automatically track link clicks once enabled with `enableLinkClickTracking` + * or you can manually track link clicks with `trackLinkClick`. + * + * @returns Plugin instance + */ +export function LinkClickTrackingPlugin(): BrowserPlugin { + return { + activateBrowserPlugin: (tracker: BrowserTracker) => { + _trackers[tracker.id] = tracker; + }, + logger: (logger: Logger) => { + _logger = logger; + }, + }; +} + +/** The configuration for automatic link click tracking */ +export interface LinkClickTrackingConfiguration { + /** The filter options for the link click tracking */ + options?: FilterCriterion | null; + /** + * Captures middle click events in browsers that don't generate standard click + * events for middle click actions + */ + pseudoClicks?: boolean; + /** Whether the content of the links should be tracked */ + trackContent?: boolean; + /** The dynamic context which will be evaluated for each link click event */ + context?: DynamicContext | null; +} + +/** + * Enable link click tracking. + * + * @remarks + * The default behaviour is to use actual click events. However, some browsers + * (e.g., Firefox, Opera, and Konqueror) don't generate click events for the middle mouse button. + * + * To capture more "clicks", the pseudo click-handler uses mousedown + mouseup events. + * This is not industry standard and is vulnerable to false positives (e.g., drag events). + * + * @param configuration The link tracking configuration to use for the new click handlers + * @param trackers List of tracker IDs that should track the click events + */ +export function enableLinkClickTracking( + configuration: LinkClickTrackingConfiguration = {}, + trackers: Array = Object.keys(_trackers) +) { + // remove listeners in case pseudoclick support has been toggled, which may duplicate handlers + disableLinkClickTracking(trackers); + trackers.forEach((id) => { + if (_trackers[id]) { + configureLinkClickTracking(configuration, id); + addClickListeners(id); + } + }); +} + +/** + * Disable link click tracking. + * + * Removes all document-level click event handlers installed by the plugin for + * provided tracker instances. + * + * @param trackers The tracker identifiers that will have their listeners removed + */ +export function disableLinkClickTracking(trackers: Array = Object.keys(_trackers)) { + trackers.forEach((id) => { + if (_trackers[id] && _listeners[id]) { + // remove all possible cases where the handler may have been attached + window.removeEventListener('click', _listeners[id], true); + window.removeEventListener('mouseup', _listeners[id], true); + window.removeEventListener('mousedown', _listeners[id], true); + } + }); +} + +/** + * Add click event listeners to links which have been added to the page since the + * last time `enableLinkClickTracking` or `refreshLinkClickTracking` was called. + * + * @deprecated v4.0 moved to event delegation and this is no longer required + * @param trackers The tracker identifiers which the have their link click state refreshed + */ +export function refreshLinkClickTracking(_trackers: Array = []) { + _logger?.warn('refreshLinkClickTracking is deprecated in v4 and has no effect'); +} + +/** + * Manually log a click. + * + * @param event The event or element information + * @param trackers The tracker identifiers which the event will be sent to + */ +export function trackLinkClick( + event: (LinkClickEvent | { element: TrackableElement; trackContent?: boolean }) & CommonEventProperties, + trackers: Array = Object.keys(_trackers) +) { + dispatchToTrackersInCollection(trackers, _trackers, (t) => { + let payload: PayloadBuilder | undefined; + if ('element' in event) { + const includeContent = event.trackContent ?? _configuration[t.id]?.linkTrackingContent ?? false; + payload = processClick(event.element, includeContent); + } else { + payload = buildLinkClick(event); + } + if (payload) t.core.track(payload, event.context, event.timestamp); + }); + + flushPendingCookies(); +} + +/** + * Process a clicked element into a link_click event payload. + * + * In case the href of the element is empty, "about:invalid" is used as the target URL. + * + * @param sourceElement The trackable element to be used to build the payload + * @param includeContent Whether to include the element's contents in the payload + * @returns A link_click SDE payload for the given element, or nothing if the element shouldn't be tracked + */ +function processClick(sourceElement: TrackableElement, includeContent: boolean = false) { + let elementId, elementClasses, elementTarget, elementContent; + + const anchorElement = sourceElement; + // browsers, such as Safari, don't downcase hostname and href + const originalSourceHostName = anchorElement.hostname || getHostName(anchorElement.href); + const targetUrl = anchorElement.href.replace(originalSourceHostName, (s) => s.toLowerCase()); + + // Ignore script pseudo-protocol links + if (!ELEMENT_PROTOCOL_FILTER.test(targetUrl)) { + elementId = anchorElement.id; + elementClasses = getCssClasses(anchorElement); + elementTarget = anchorElement.target; + elementContent = includeContent ? anchorElement.innerHTML : undefined; + + if (!targetUrl) { + _logger?.warn('Link click target URL empty', anchorElement); + } + + // decodeUrl %xx + return buildLinkClick({ + targetUrl: targetUrl || 'about:invalid', + elementId, + elementClasses, + elementTarget, + elementContent, + }); + } + + return; +} + +/** + * Find the nearest trackable element to the given element; this is Element.closest() + * with a polyfill if required. + * + * @param target + * @returns An element that may be used to track a link click event, or null if `target` has no eligible parent + */ +function findNearestEligibleElement(target: EventTarget | null): TrackableElement | null { + if (target instanceof Element) { + if (typeof target['closest'] === 'function') return target.closest(TRACKABLE_ELEMENTS_SELECTOR); + let sourceElement: Element | null = target; + + while (sourceElement) { + const tagName = sourceElement.tagName.toLowerCase(); + if (TRACKABLE_ELEMENTS.indexOf(tagName) !== -1) return sourceElement as TrackableElement; + sourceElement = sourceElement.parentElement; + } + } + + return null; +} + +/** + * Handle a (pseudo)click event; decide if the click is for a valid, unfiltered, + * element and track the click. + * + * @param tracker Tracker ID to generate the event for + * @param evt The DOM click event itself + */ +function clickHandler(tracker: string, evt: MouseEvent | undefined): void { + const context = _configuration[tracker].linkTrackingContext; + const filter = _configuration[tracker].linkTrackingFilter; + + const event = evt || (window.event as MouseEvent); + + const button = event.which || event.button; + + const clicked = event.composed ? event.composedPath()[0] : event.target || event.srcElement; + const target = findNearestEligibleElement(clicked); + + if (!target || target.href == null) return; + if (filter && !filter(target)) return; + + // Using evt.type (added in IE4), we avoid defining separate handlers for mouseup and mousedown. + if (event.type === 'click') { + trackLinkClick( + { + element: target, + context: resolveDynamicContext(context, target), + }, + [tracker] + ); + } else if (event.type === 'mousedown') { + if (button === 1 || button === 2) { + _configuration[tracker].lastButton = button; + _configuration[tracker].lastTarget = target; + } else { + delete _configuration[tracker].lastButton; + } + } else if (event.type === 'mouseup') { + if (button === _configuration[tracker].lastButton && target === _configuration[tracker].lastTarget) { + trackLinkClick( + { + element: target, + context: resolveDynamicContext(context, target), + }, + [tracker] + ); + } + delete _configuration[tracker].lastButton; + delete _configuration[tracker].lastTarget; + } +} + +/** + * Update the link-tracking configuration for the given tracker ID. + * + * @param param0 The new link-tracking configuration + * @param tracker The tracker ID to update configuration for + */ +function configureLinkClickTracking( + { options, pseudoClicks, trackContent, context }: LinkClickTrackingConfiguration = {}, + tracker: string +) { + _configuration[tracker] = { + linkTrackingContent: trackContent, + linkTrackingContext: context, + linkTrackingPseudoClicks: pseudoClicks, + linkTrackingFilter: getFilterByClass(options), + }; +} + +/** + * Add (psuedo)click handlers to the window for the given tracker ID. + * + * @param trackerId Tracker ID to install a listener for + */ +function addClickListeners(trackerId: string) { + // by re-using exact function references the browser will prevent dupes and allow removal + _listeners[trackerId] = _listeners[trackerId] || clickHandler.bind(null, trackerId); + + if (_configuration[trackerId].linkTrackingPseudoClicks) { + // for simplicity and performance, we ignore drag events + addEventListener(window, 'mouseup', _listeners[trackerId], true); + addEventListener(window, 'mousedown', _listeners[trackerId], true); + } else { + addEventListener(window, 'click', _listeners[trackerId], true); + } +} diff --git a/plugins/browser-plugin-link-click-tracking/test/events.test.ts b/plugins/browser-plugin-link-click-tracking/test/events.test.ts new file mode 100644 index 000000000..0436c5183 --- /dev/null +++ b/plugins/browser-plugin-link-click-tracking/test/events.test.ts @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2022 Snowplow Analytics Ltd, 2010 Anthon Pang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import { addTracker, SharedState } from '@snowplow/browser-tracker-core'; +import F from 'lodash/fp'; +import { LinkClickTrackingPlugin, disableLinkClickTracking, enableLinkClickTracking, trackLinkClick } from '../src'; +import { newInMemoryEventStore } from '@snowplow/tracker-core'; + +const getUEEvents = F.compose(F.filter(F.compose(F.eq('ue'), F.get('e')))); +const extractEventProperties = F.map(F.compose(F.get('data'), (cx: string) => JSON.parse(cx), F.get('ue_pr'))); +const extractUeEvent = (schema: string) => { + return { + from: (a: any, n: number = 0) => + F.nth( + n, + F.compose(F.filter(F.compose(F.eq(schema), F.get('schema'))), F.flatten, extractEventProperties, getUEEvents)(a) + ), + }; +}; + +describe('LinkClickTrackingPlugin', () => { + const eventStore = newInMemoryEventStore({}); + addTracker('sp1', 'sp1', 'js-3.0.0', '', new SharedState(), { + stateStorageStrategy: 'cookie', + encodeBase64: false, + plugins: [LinkClickTrackingPlugin()], + eventStore, + customFetch: async () => new Response(null, { status: 500 }), + }); + + const $addEventListener = jest.spyOn(window, 'addEventListener'); + const $removeEventListener = jest.spyOn(window, 'removeEventListener'); + + afterEach(async () => { + // clear the outQueue(s) after each test + await eventStore.removeHead(await eventStore.count()); + jest.clearAllMocks(); + }); + + describe('trackLinkClick', () => { + it('adds the specified link click event to the queue', async () => { + trackLinkClick({ + targetUrl: 'https://www.example.com', + elementClasses: ['class-1', 'class-2'], + elementContent: 'content-1', + elementId: 'id-1234', + elementTarget: '_blank', + }); + + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1').from( + await eventStore.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1', + data: { + targetUrl: 'https://www.example.com', + elementClasses: ['class-1', 'class-2'], + elementContent: 'content-1', + elementId: 'id-1234', + elementTarget: '_blank', + }, + }); + }); + + it('generates a link click event from a given element and adds it to the queue', async () => { + const a = Object.assign(document.createElement('a'), { + href: 'https://www.example.com/abc', + className: 'class-1 class-2', + textContent: 'content-1', + id: 'id-1234', + target: '_blank', + }); + + trackLinkClick({ element: a }); + + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1').from( + await eventStore.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1', + data: { + targetUrl: 'https://www.example.com/abc', + elementClasses: ['class-1', 'class-2'], + //elementContent: missing because disabled in default configuration + elementId: 'id-1234', + elementTarget: '_blank', + }, + }); + }); + + it('does nothing for no trackers', async () => { + trackLinkClick( + { + targetUrl: 'https://www.example.com', + elementClasses: ['class-1', 'class-2'], + elementContent: 'content-1', + elementId: 'id-1234', + elementTarget: '_blank', + }, + [] + ); + + expect(await eventStore.getAllPayloads()).toHaveLength(0); + }); + + it('does nothing for fake trackers', async () => { + trackLinkClick( + { + targetUrl: 'https://www.example.com', + elementClasses: ['class-1', 'class-2'], + elementContent: 'content-1', + elementId: 'id-1234', + elementTarget: '_blank', + }, + ['doesNotExist'] + ); + + expect(await eventStore.getAllPayloads()).toHaveLength(0); + }); + }); + + describe('enableLinkClickTracking', () => { + it('does nothing for no trackers', () => { + enableLinkClickTracking({}, []); + expect($addEventListener).not.toBeCalled(); + }); + + it('adds click listeners by default', () => { + enableLinkClickTracking(); + + expect($addEventListener).lastCalledWith('click', expect.anything(), true); + }); + + it('adds pseudo-click listeners when requested', () => { + enableLinkClickTracking({ pseudoClicks: true }); + expect($addEventListener).lastCalledWith('mousedown', expect.anything(), true); + }); + + it('tracks clicks on links that already exist', async () => { + const target = document.createElement('a'); + target.href = 'https://www.example.com/exists'; + document.body.appendChild(target); + + enableLinkClickTracking(); + + target.click(); + + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1').from( + await eventStore.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1', + data: { + targetUrl: 'https://www.example.com/exists', + }, + }); + }); + + it('tracks clicks on links added after enabling', async () => { + enableLinkClickTracking(); + + const target = document.createElement('a'); + target.href = 'https://www.example.com/dynamic'; + document.body.appendChild(target); + + target.click(); + + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1').from( + await eventStore.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1', + data: { + targetUrl: 'https://www.example.com/dynamic', + }, + }); + }); + + it('tracks clicks on links without href', async () => { + enableLinkClickTracking(); + + const target = document.createElement('a'); + document.body.appendChild(target); + + target.click(); + + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1').from( + await eventStore.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1', + data: { + targetUrl: 'about:invalid', + }, + }); + }); + + it('tracks clicks on child elements of links and contents', async () => { + enableLinkClickTracking({ trackContent: true }); + + const parent = document.createElement('a'); + parent.href = 'https://www.example.com/parent'; + + const target = document.createElement('span'); + target.textContent = 'child'; + parent.appendChild(target); + + document.body.appendChild(parent); + + target.click(); + + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1').from( + await eventStore.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1', + data: { + targetUrl: 'https://www.example.com/parent', + elementContent: 'child', + }, + }); + }); + + it('tracks clicks on links in custom components', async () => { + enableLinkClickTracking(); + + window.customElements.define( + 'shadow-link', + class extends HTMLElement { + connectedCallback() { + const a = document.createElement('a'); + a.textContent = 'Shadow'; + a.href = 'https://www.example.com/shadow'; + + const shadowRoot = this.attachShadow({ mode: 'open' }); + shadowRoot.appendChild(a); + } + } + ); + + const shadow = document.createElement('shadow-link'); + document.body.appendChild(shadow); + + shadow.shadowRoot!.querySelector('a')!.click(); + + expect( + extractUeEvent('iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1').from( + await eventStore.getAllPayloads() + ) + ).toMatchObject({ + schema: 'iglu:com.snowplowanalytics.snowplow/link_click/jsonschema/1-0-1', + data: { + targetUrl: 'https://www.example.com/shadow', + }, + }); + }); + + it('doesnt double track clicks', async () => { + enableLinkClickTracking({ pseudoClicks: true }); + enableLinkClickTracking({ pseudoClicks: false }); + + const target = document.createElement('a'); + target.href = 'https://www.example.com/multiple'; + document.body.appendChild(target); + + expect(await eventStore.getAllPayloads()).toHaveLength(0); + + target.click(); + + expect(await eventStore.getAllPayloads()).toHaveLength(1); + }); + + it('ignores links that match denylist criteria', async () => { + enableLinkClickTracking({ options: { denylist: ['exclude'] } }); + + const target = document.createElement('a'); + target.href = 'https://www.example.com/exclude'; + target.className = 'exclude'; + document.body.appendChild(target); + + expect(await eventStore.getAllPayloads()).toHaveLength(0); + + target.click(); + + expect(await eventStore.getAllPayloads()).toHaveLength(0); + + target.className = 'include'; + target.click(); + + expect(await eventStore.getAllPayloads()).toHaveLength(1); + }); + + it('ignores links that dont match allowlist criteria', async () => { + enableLinkClickTracking({ options: { allowlist: ['include'] } }); + + const target = document.createElement('a'); + target.href = 'https://www.example.com/include'; + target.className = 'exclude'; + document.body.appendChild(target); + + expect(await eventStore.getAllPayloads()).toHaveLength(0); + + target.click(); + + expect(await eventStore.getAllPayloads()).toHaveLength(0); + + target.className = 'include'; + target.click(); + + expect(await eventStore.getAllPayloads()).toHaveLength(1); + }); + + it('tracks a single link click with each tracker', async () => { + addTracker('sp2', 'sp2', 'js-3.0.0', '', new SharedState(), { + stateStorageStrategy: 'cookie', + encodeBase64: false, + plugins: [LinkClickTrackingPlugin()], + eventStore, + customFetch: async () => new Response(null, { status: 500 }), + }); + + enableLinkClickTracking(); + + const target = document.createElement('a'); + target.href = 'https://www.example.com/exists'; + document.body.appendChild(target); + + target.click(); + + expect(await eventStore.getAllPayloads()).toHaveLength(2); + }); + }); + + describe('disableLinkClickTracking', () => { + it('removes any listeners added', () => { + enableLinkClickTracking(); + disableLinkClickTracking(); + + const addCalls = $addEventListener.mock.calls; + + expect(addCalls).toHaveLength(2); + expect($removeEventListener.mock.calls).toContainEqual(addCalls[0]); + }); + }); +}); diff --git a/plugins/browser-plugin-link-click-tracking/tsconfig.json b/plugins/browser-plugin-link-click-tracking/tsconfig.json new file mode 100644 index 000000000..4082f16a5 --- /dev/null +++ b/plugins/browser-plugin-link-click-tracking/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +} diff --git a/plugins/browser-plugin-media-tracking/.gitignore b/plugins/browser-plugin-media-tracking/.gitignore new file mode 100644 index 000000000..f06235c46 --- /dev/null +++ b/plugins/browser-plugin-media-tracking/.gitignore @@ -0,0 +1,2 @@ +node_modules +dist diff --git a/plugins/browser-plugin-media-tracking/CHANGELOG.json b/plugins/browser-plugin-media-tracking/CHANGELOG.json new file mode 100644 index 000000000..d712cff36 --- /dev/null +++ b/plugins/browser-plugin-media-tracking/CHANGELOG.json @@ -0,0 +1,509 @@ +{ + "name": "@snowplow/browser-plugin-media-tracking", + "entries": [ + { + "version": "4.10.0", + "tag": "@snowplow/browser-plugin-media-tracking_v4.10.0", + "date": "Mon, 27 Jul 2026 13:52:14 GMT", + "comments": {} + }, + { + "version": "4.9.0", + "tag": "@snowplow/browser-plugin-media-tracking_v4.9.0", + "date": "Tue, 21 Jul 2026 14:53:08 GMT", + "comments": {} + }, + { + "version": "4.8.4", + "tag": "@snowplow/browser-plugin-media-tracking_v4.8.4", + "date": "Thu, 02 Jul 2026 10:07:52 GMT", + "comments": {} + }, + { + "version": "4.8.3", + "tag": "@snowplow/browser-plugin-media-tracking_v4.8.3", + "date": "Tue, 30 Jun 2026 14:22:03 GMT", + "comments": { + "none": [ + { + "comment": "Update uuid to v11 and remove closure-compiler from the build pipeline" + } + ] + } + }, + { + "version": "4.8.2", + "tag": "@snowplow/browser-plugin-media-tracking_v4.8.2", + "date": "Wed, 17 Jun 2026 12:30:12 GMT", + "comments": {} + }, + { + "version": "4.8.1", + "tag": "@snowplow/browser-plugin-media-tracking_v4.8.1", + "date": "Wed, 13 May 2026 09:26:05 GMT", + "comments": {} + }, + { + "version": "4.8.0", + "tag": "@snowplow/browser-plugin-media-tracking_v4.8.0", + "date": "Tue, 28 Apr 2026 07:56:22 GMT", + "comments": {} + }, + { + "version": "4.7.0", + "tag": "@snowplow/browser-plugin-media-tracking_v4.7.0", + "date": "Wed, 01 Apr 2026 12:59:29 GMT", + "comments": {} + }, + { + "version": "4.6.9", + "tag": "@snowplow/browser-plugin-media-tracking_v4.6.9", + "date": "Mon, 16 Mar 2026 15:43:06 GMT", + "comments": {} + }, + { + "version": "4.6.8", + "tag": "@snowplow/browser-plugin-media-tracking_v4.6.8", + "date": "Tue, 28 Oct 2025 09:46:42 GMT", + "comments": {} + }, + { + "version": "4.6.7", + "tag": "@snowplow/browser-plugin-media-tracking_v4.6.7", + "date": "Tue, 07 Oct 2025 14:53:36 GMT", + "comments": {} + }, + { + "version": "4.6.6", + "tag": "@snowplow/browser-plugin-media-tracking_v4.6.6", + "date": "Tue, 26 Aug 2025 08:42:27 GMT", + "comments": { + "none": [ + { + "comment": "Allow using a CSS selector to find media elements" + } + ] + } + }, + { + "version": "4.6.5", + "tag": "@snowplow/browser-plugin-media-tracking_v4.6.5", + "date": "Wed, 25 Jun 2025 21:16:46 GMT", + "comments": {} + }, + { + "version": "4.6.4", + "tag": "@snowplow/browser-plugin-media-tracking_v4.6.4", + "date": "Wed, 25 Jun 2025 12:08:50 GMT", + "comments": {} + }, + { + "version": "4.6.3", + "tag": "@snowplow/browser-plugin-media-tracking_v4.6.3", + "date": "Thu, 29 May 2025 19:52:07 GMT", + "comments": {} + }, + { + "version": "4.6.2", + "tag": "@snowplow/browser-plugin-media-tracking_v4.6.2", + "date": "Tue, 20 May 2025 07:39:05 GMT", + "comments": {} + }, + { + "version": "4.6.1", + "tag": "@snowplow/browser-plugin-media-tracking_v4.6.1", + "date": "Tue, 06 May 2025 13:10:51 GMT", + "comments": { + "none": [ + { + "comment": "Add a default 0 value for start and end in the media_element entity time ranges" + } + ] + } + }, + { + "version": "4.6.0", + "tag": "@snowplow/browser-plugin-media-tracking_v4.6.0", + "date": "Thu, 01 May 2025 09:58:59 GMT", + "comments": {} + }, + { + "version": "4.5.0", + "tag": "@snowplow/browser-plugin-media-tracking_v4.5.0", + "date": "Fri, 04 Apr 2025 09:21:23 GMT", + "comments": {} + }, + { + "version": "4.4.0", + "tag": "@snowplow/browser-plugin-media-tracking_v4.4.0", + "date": "Thu, 20 Mar 2025 12:14:34 GMT", + "comments": {} + }, + { + "version": "4.3.1", + "tag": "@snowplow/browser-plugin-media-tracking_v4.3.1", + "date": "Tue, 21 Jan 2025 11:09:42 GMT", + "comments": {} + }, + { + "version": "4.3.0", + "tag": "@snowplow/browser-plugin-media-tracking_v4.3.0", + "date": "Mon, 20 Jan 2025 11:45:13 GMT", + "comments": {} + }, + { + "version": "4.2.0", + "tag": "@snowplow/browser-plugin-media-tracking_v4.2.0", + "date": "Mon, 13 Jan 2025 08:30:05 GMT", + "comments": {} + }, + { + "version": "4.1.0", + "tag": "@snowplow/browser-plugin-media-tracking_v4.1.0", + "date": "Thu, 28 Nov 2024 10:57:30 GMT", + "comments": {} + }, + { + "version": "4.0.4", + "tag": "@snowplow/browser-plugin-media-tracking_v4.0.4", + "date": "Thu, 21 Nov 2024 09:06:36 GMT", + "comments": {} + }, + { + "version": "4.0.3", + "tag": "@snowplow/browser-plugin-media-tracking_v4.0.3", + "date": "Wed, 20 Nov 2024 09:30:31 GMT", + "comments": {} + }, + { + "version": "4.0.2", + "tag": "@snowplow/browser-plugin-media-tracking_v4.0.2", + "date": "Mon, 11 Nov 2024 15:46:34 GMT", + "comments": { + "none": [ + { + "comment": "Fix ignored label property in the startHtml5MediaTracking call" + } + ] + } + }, + { + "version": "4.0.1", + "tag": "@snowplow/browser-plugin-media-tracking_v4.0.1", + "date": "Fri, 01 Nov 2024 10:35:07 GMT", + "comments": { + "none": [ + { + "comment": "Fix initialization of the HTML5 media tracking plugin so that it initializes the parent media plugin (#1369)" + } + ] + } + }, + { + "version": "4.0.0", + "tag": "@snowplow/browser-plugin-media-tracking_v4.0.0", + "date": "Mon, 28 Oct 2024 11:48:53 GMT", + "comments": { + "none": [ + { + "comment": "Migrate HTML Media Tracking to Snowplow Media Plugin" + } + ] + } + }, + { + "version": "3.24.6", + "tag": "@snowplow/browser-plugin-media-tracking_v3.24.6", + "date": "Mon, 28 Oct 2024 10:23:28 GMT", + "comments": {} + }, + { + "version": "3.24.5", + "tag": "@snowplow/browser-plugin-media-tracking_v3.24.5", + "date": "Fri, 25 Oct 2024 08:53:04 GMT", + "comments": {} + }, + { + "version": "3.24.4", + "tag": "@snowplow/browser-plugin-media-tracking_v3.24.4", + "date": "Thu, 26 Sep 2024 06:10:22 GMT", + "comments": {} + }, + { + "version": "3.24.3", + "tag": "@snowplow/browser-plugin-media-tracking_v3.24.3", + "date": "Tue, 03 Sep 2024 08:15:14 GMT", + "comments": { + "none": [ + { + "comment": "Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush" + } + ] + } + }, + { + "version": "3.24.2", + "tag": "@snowplow/browser-plugin-media-tracking_v3.24.2", + "date": "Wed, 24 Jul 2024 08:59:00 GMT", + "comments": {} + }, + { + "version": "3.24.1", + "tag": "@snowplow/browser-plugin-media-tracking_v3.24.1", + "date": "Tue, 02 Jul 2024 07:08:17 GMT", + "comments": {} + }, + { + "version": "3.24.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.24.0", + "date": "Tue, 25 Jun 2024 08:31:05 GMT", + "comments": { + "none": [ + { + "comment": "Handle Infinity/NaN durations in Media Tracking" + } + ] + } + }, + { + "version": "3.23.1", + "tag": "@snowplow/browser-plugin-media-tracking_v3.23.1", + "date": "Tue, 04 Jun 2024 13:34:45 GMT", + "comments": { + "none": [ + { + "comment": "Adjust extraction of media_element.fileExtension from source URIs." + } + ] + } + }, + { + "version": "3.23.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.23.0", + "date": "Thu, 28 Mar 2024 11:28:45 GMT", + "comments": {} + }, + { + "version": "3.22.1", + "tag": "@snowplow/browser-plugin-media-tracking_v3.22.1", + "date": "Wed, 13 Mar 2024 08:39:48 GMT", + "comments": {} + }, + { + "version": "3.22.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.22.0", + "date": "Fri, 08 Mar 2024 08:13:04 GMT", + "comments": {} + }, + { + "version": "3.21.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.21.0", + "date": "Mon, 29 Jan 2024 08:34:06 GMT", + "comments": {} + }, + { + "version": "3.20.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.20.0", + "date": "Mon, 15 Jan 2024 14:41:16 GMT", + "comments": {} + }, + { + "version": "3.19.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.19.0", + "date": "Thu, 14 Dec 2023 10:45:22 GMT", + "comments": {} + }, + { + "version": "3.18.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.18.0", + "date": "Mon, 04 Dec 2023 13:44:02 GMT", + "comments": {} + }, + { + "version": "3.17.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.17.0", + "date": "Tue, 14 Nov 2023 17:58:26 GMT", + "comments": {} + }, + { + "version": "3.16.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.16.0", + "date": "Mon, 16 Oct 2023 14:58:08 GMT", + "comments": {} + }, + { + "version": "3.15.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.15.0", + "date": "Mon, 28 Aug 2023 14:25:14 GMT", + "comments": {} + }, + { + "version": "3.14.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.14.0", + "date": "Thu, 10 Aug 2023 13:56:44 GMT", + "comments": {} + }, + { + "version": "3.13.1", + "tag": "@snowplow/browser-plugin-media-tracking_v3.13.1", + "date": "Thu, 29 Jun 2023 14:20:06 GMT", + "comments": {} + }, + { + "version": "3.13.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.13.0", + "date": "Tue, 20 Jun 2023 07:44:23 GMT", + "comments": {} + }, + { + "version": "3.12.1", + "tag": "@snowplow/browser-plugin-media-tracking_v3.12.1", + "date": "Thu, 15 Jun 2023 10:05:37 GMT", + "comments": {} + }, + { + "version": "3.12.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.12.0", + "date": "Mon, 05 Jun 2023 11:51:22 GMT", + "comments": {} + }, + { + "version": "3.11.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.11.0", + "date": "Wed, 24 May 2023 15:56:17 GMT", + "comments": {} + }, + { + "version": "3.10.1", + "tag": "@snowplow/browser-plugin-media-tracking_v3.10.1", + "date": "Fri, 12 May 2023 06:59:31 GMT", + "comments": {} + }, + { + "version": "3.10.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.10.0", + "date": "Thu, 11 May 2023 08:29:15 GMT", + "comments": {} + }, + { + "version": "3.9.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.9.0", + "date": "Thu, 30 Mar 2023 13:46:56 GMT", + "comments": {} + }, + { + "version": "3.8.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.8.0", + "date": "Tue, 03 Jan 2023 15:36:33 GMT", + "comments": {} + }, + { + "version": "3.7.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.7.0", + "date": "Mon, 31 Oct 2022 06:26:28 GMT", + "comments": { + "none": [ + { + "comment": "Support JWPlayer in browser-plugin-media-tracking (closes #1116)" + }, + { + "comment": "Use currentSrc as src when source element in used in media-tracking (closes #1118)" + } + ] + } + }, + { + "version": "3.6.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.6.0", + "date": "Thu, 15 Sep 2022 07:55:20 GMT", + "comments": {} + }, + { + "version": "3.5.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.5.0", + "date": "Fri, 10 Jun 2022 18:57:46 GMT", + "comments": {} + }, + { + "version": "3.4.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.4.0", + "date": "Thu, 07 Apr 2022 11:56:26 GMT", + "comments": { + "none": [ + { + "comment": "Bump dependencies (#1067)" + } + ] + } + }, + { + "version": "3.3.1", + "tag": "@snowplow/browser-plugin-media-tracking_v3.3.1", + "date": "Wed, 23 Feb 2022 19:27:40 GMT", + "comments": {} + }, + { + "version": "3.3.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.3.0", + "date": "Mon, 31 Jan 2022 15:58:10 GMT", + "comments": { + "none": [ + { + "comment": "Add ready to Media Plugin DefaultEvents (#1053)" + } + ] + } + }, + { + "version": "3.2.3", + "tag": "@snowplow/browser-plugin-media-tracking_v3.2.3", + "date": "Tue, 18 Jan 2022 16:23:52 GMT", + "comments": { + "none": [ + { + "comment": "Fix video progress event becoming out of sync on pause/play (#1038)" + }, + { + "comment": "Bump Copyright to 2022 (#1040)" + } + ] + } + }, + { + "version": "3.2.2", + "tag": "@snowplow/browser-plugin-media-tracking_v3.2.2", + "date": "Fri, 14 Jan 2022 10:17:59 GMT", + "comments": { + "none": [ + { + "comment": "Remove logging from event tracker in media plugin (#1035)" + } + ] + } + }, + { + "version": "3.2.1", + "tag": "@snowplow/browser-plugin-media-tracking_v3.2.1", + "date": "Wed, 12 Jan 2022 09:50:29 GMT", + "comments": { + "none": [ + { + "comment": " Fix License Badges in READMEs (#1028) " + } + ] + } + }, + { + "version": "3.2.0", + "tag": "@snowplow/browser-plugin-media-tracking_v3.2.0", + "date": "Tue, 11 Jan 2022 12:53:22 GMT", + "comments": { + "none": [ + { + "comment": "Add HTML5 Media Tracking plugin (#805)" + } + ] + } + } + ] +} diff --git a/plugins/browser-plugin-media-tracking/CHANGELOG.md b/plugins/browser-plugin-media-tracking/CHANGELOG.md new file mode 100644 index 000000000..4e1c3549e --- /dev/null +++ b/plugins/browser-plugin-media-tracking/CHANGELOG.md @@ -0,0 +1,373 @@ +# Change Log - @snowplow/browser-plugin-media-tracking + +This log was last generated on Mon, 27 Jul 2026 13:52:14 GMT and should not be manually modified. + +## 4.10.0 +Mon, 27 Jul 2026 13:52:14 GMT + +_Version update only_ + +## 4.9.0 +Tue, 21 Jul 2026 14:53:08 GMT + +_Version update only_ + +## 4.8.4 +Thu, 02 Jul 2026 10:07:52 GMT + +_Version update only_ + +## 4.8.3 +Tue, 30 Jun 2026 14:22:03 GMT + +### Updates + +- Update uuid to v11 and remove closure-compiler from the build pipeline + +## 4.8.2 +Wed, 17 Jun 2026 12:30:12 GMT + +_Version update only_ + +## 4.8.1 +Wed, 13 May 2026 09:26:05 GMT + +_Version update only_ + +## 4.8.0 +Tue, 28 Apr 2026 07:56:22 GMT + +_Version update only_ + +## 4.7.0 +Wed, 01 Apr 2026 12:59:29 GMT + +_Version update only_ + +## 4.6.9 +Mon, 16 Mar 2026 15:43:06 GMT + +_Version update only_ + +## 4.6.8 +Tue, 28 Oct 2025 09:46:42 GMT + +_Version update only_ + +## 4.6.7 +Tue, 07 Oct 2025 14:53:36 GMT + +_Version update only_ + +## 4.6.6 +Tue, 26 Aug 2025 08:42:27 GMT + +### Updates + +- Allow using a CSS selector to find media elements + +## 4.6.5 +Wed, 25 Jun 2025 21:16:46 GMT + +_Version update only_ + +## 4.6.4 +Wed, 25 Jun 2025 12:08:50 GMT + +_Version update only_ + +## 4.6.3 +Thu, 29 May 2025 19:52:07 GMT + +_Version update only_ + +## 4.6.2 +Tue, 20 May 2025 07:39:05 GMT + +_Version update only_ + +## 4.6.1 +Tue, 06 May 2025 13:10:51 GMT + +### Updates + +- Add a default 0 value for start and end in the media_element entity time ranges + +## 4.6.0 +Thu, 01 May 2025 09:58:59 GMT + +_Version update only_ + +## 4.5.0 +Fri, 04 Apr 2025 09:21:23 GMT + +_Version update only_ + +## 4.4.0 +Thu, 20 Mar 2025 12:14:34 GMT + +_Version update only_ + +## 4.3.1 +Tue, 21 Jan 2025 11:09:42 GMT + +_Version update only_ + +## 4.3.0 +Mon, 20 Jan 2025 11:45:13 GMT + +_Version update only_ + +## 4.2.0 +Mon, 13 Jan 2025 08:30:05 GMT + +_Version update only_ + +## 4.1.0 +Thu, 28 Nov 2024 10:57:30 GMT + +_Version update only_ + +## 4.0.4 +Thu, 21 Nov 2024 09:06:36 GMT + +_Version update only_ + +## 4.0.3 +Wed, 20 Nov 2024 09:30:31 GMT + +_Version update only_ + +## 4.0.2 +Mon, 11 Nov 2024 15:46:34 GMT + +### Updates + +- Fix ignored label property in the startHtml5MediaTracking call + +## 4.0.1 +Fri, 01 Nov 2024 10:35:07 GMT + +### Updates + +- Fix initialization of the HTML5 media tracking plugin so that it initializes the parent media plugin (#1369) + +## 4.0.0 +Mon, 28 Oct 2024 11:48:53 GMT + +### Updates + +- Migrate HTML Media Tracking to Snowplow Media Plugin + +## 3.24.6 +Mon, 28 Oct 2024 10:23:28 GMT + +_Version update only_ + +## 3.24.5 +Fri, 25 Oct 2024 08:53:04 GMT + +_Version update only_ + +## 3.24.4 +Thu, 26 Sep 2024 06:10:22 GMT + +_Version update only_ + +## 3.24.3 +Tue, 03 Sep 2024 08:15:14 GMT + +### Updates + +- Upgrade supported Node.JS versions in build to 18 - 20 and upgrade rush + +## 3.24.2 +Wed, 24 Jul 2024 08:59:00 GMT + +_Version update only_ + +## 3.24.1 +Tue, 02 Jul 2024 07:08:17 GMT + +_Version update only_ + +## 3.24.0 +Tue, 25 Jun 2024 08:31:05 GMT + +### Updates + +- Handle Infinity/NaN durations in Media Tracking + +## 3.23.1 +Tue, 04 Jun 2024 13:34:45 GMT + +### Updates + +- Adjust extraction of media_element.fileExtension from source URIs. + +## 3.23.0 +Thu, 28 Mar 2024 11:28:45 GMT + +_Version update only_ + +## 3.22.1 +Wed, 13 Mar 2024 08:39:48 GMT + +_Version update only_ + +## 3.22.0 +Fri, 08 Mar 2024 08:13:04 GMT + +_Version update only_ + +## 3.21.0 +Mon, 29 Jan 2024 08:34:06 GMT + +_Version update only_ + +## 3.20.0 +Mon, 15 Jan 2024 14:41:16 GMT + +_Version update only_ + +## 3.19.0 +Thu, 14 Dec 2023 10:45:22 GMT + +_Version update only_ + +## 3.18.0 +Mon, 04 Dec 2023 13:44:02 GMT + +_Version update only_ + +## 3.17.0 +Tue, 14 Nov 2023 17:58:26 GMT + +_Version update only_ + +## 3.16.0 +Mon, 16 Oct 2023 14:58:08 GMT + +_Version update only_ + +## 3.15.0 +Mon, 28 Aug 2023 14:25:14 GMT + +_Version update only_ + +## 3.14.0 +Thu, 10 Aug 2023 13:56:44 GMT + +_Version update only_ + +## 3.13.1 +Thu, 29 Jun 2023 14:20:06 GMT + +_Version update only_ + +## 3.13.0 +Tue, 20 Jun 2023 07:44:23 GMT + +_Version update only_ + +## 3.12.1 +Thu, 15 Jun 2023 10:05:37 GMT + +_Version update only_ + +## 3.12.0 +Mon, 05 Jun 2023 11:51:22 GMT + +_Version update only_ + +## 3.11.0 +Wed, 24 May 2023 15:56:17 GMT + +_Version update only_ + +## 3.10.1 +Fri, 12 May 2023 06:59:31 GMT + +_Version update only_ + +## 3.10.0 +Thu, 11 May 2023 08:29:15 GMT + +_Version update only_ + +## 3.9.0 +Thu, 30 Mar 2023 13:46:56 GMT + +_Version update only_ + +## 3.8.0 +Tue, 03 Jan 2023 15:36:33 GMT + +_Version update only_ + +## 3.7.0 +Mon, 31 Oct 2022 06:26:28 GMT + +### Updates + +- Support JWPlayer in browser-plugin-media-tracking (closes #1116) +- Use currentSrc as src when source element in used in media-tracking (closes #1118) + +## 3.6.0 +Thu, 15 Sep 2022 07:55:20 GMT + +_Version update only_ + +## 3.5.0 +Fri, 10 Jun 2022 18:57:46 GMT + +_Version update only_ + +## 3.4.0 +Thu, 07 Apr 2022 11:56:26 GMT + +### Updates + +- Bump dependencies (#1067) + +## 3.3.1 +Wed, 23 Feb 2022 19:27:40 GMT + +_Version update only_ + +## 3.3.0 +Mon, 31 Jan 2022 15:58:10 GMT + +### Updates + +- Add ready to Media Plugin DefaultEvents (#1053) + +## 3.2.3 +Tue, 18 Jan 2022 16:23:52 GMT + +### Updates + +- Fix video progress event becoming out of sync on pause/play (#1038) +- Bump Copyright to 2022 (#1040) + +## 3.2.2 +Fri, 14 Jan 2022 10:17:59 GMT + +### Updates + +- Remove logging from event tracker in media plugin (#1035) + +## 3.2.1 +Wed, 12 Jan 2022 09:50:29 GMT + +### Updates + +- Fix License Badges in READMEs (#1028) + +## 3.2.0 +Tue, 11 Jan 2022 12:53:22 GMT + +### Updates + +- Add HTML5 Media Tracking plugin (#805) + diff --git a/plugins/browser-plugin-media-tracking/LICENSE b/plugins/browser-plugin-media-tracking/LICENSE new file mode 100644 index 000000000..f697ebc56 --- /dev/null +++ b/plugins/browser-plugin-media-tracking/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022 Snowplow Analytics Ltd +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/plugins/browser-plugin-media-tracking/README.md b/plugins/browser-plugin-media-tracking/README.md new file mode 100644 index 000000000..7b32eba4f --- /dev/null +++ b/plugins/browser-plugin-media-tracking/README.md @@ -0,0 +1,94 @@ +# Snowplow Media Tracking + +[![npm version][npm-image]][npm-url] +[![License][license-image]](LICENSE) + +Browser Plugin to be used with `@snowplow/browser-tracker`. + +Adds HTML5 Video and Audio tracking events to your Snowplow tracking. + +## Maintainer quick start + +Part of the Snowplow JavaScript Tracker monorepo. +Build with [Node.js](https://nodejs.org/en/) (18 - 20) and [Rush](https://rushjs.io/). + +### Setup repository + +```bash +npm install -g @microsoft/rush +git clone https://github.com/snowplow/snowplow-javascript-tracker.git +rush update +``` + +### Package Installation + +With npm: + +```bash +npm install @snowplow/browser-plugin-media-tracking +``` + +## Usage + +Initialize your tracker with the MediaTrackingPlugin: + +```js +import { newTracker } from '@snowplow/browser-tracker'; +import { MediaTrackingPlugin, startHtml5MediaTracking, endHtml5MediaTracking } from '@snowplow/browser-plugin-media-tracking'; + +newTracker('sp2', '{{collector}}', { plugins: [ MediaTrackingPlugin() ] }); // Also stores reference at module level +``` + +Then, use the `startHtml5MediaTracking` function described below to produce events from your HTML5 Video/Audio element(s). + +```js +startHtml5MediaTracking({ video, id }) +``` + +| Parameter | Type | Description | Required | +| ----------| ------------------------ | -------------------------------------------------------------------------------------- | -------- | +| `id` | `string` | A UUID identifier to use as the media session ID | Yes | +| `video` | `string` / `HTMLElement` | The HTML id attribute, CSS selector, or actual media element to track media events for | Yes | + +See the [full documentation](https://docs.snowplow.io/docs/sources/trackers/web-trackers/tracking-events/media/html5/#starthtml5mediatracking) for optional parameters. + +## Example Usage + +```html + ... +

⚠️ This package is deprecated, please use @snowplow/browser-plugin-snowplow-ecommerce instead. ⚠️