@walkeros/web-destination-matomo 4.8.1 → 4.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/dist/dev.d.mts +19 -15
- package/dist/dev.d.ts +19 -15
- package/dist/dev.js +1 -1
- package/dist/dev.js.map +1 -1
- package/dist/dev.mjs +1 -1
- package/dist/dev.mjs.map +1 -1
- package/dist/examples/index.d.mts +18 -14
- package/dist/examples/index.d.ts +18 -14
- package/dist/examples/index.js +28 -23
- package/dist/examples/index.mjs +29 -24
- package/dist/index.browser.js +1 -1
- package/dist/index.d.mts +0 -11
- package/dist/index.d.ts +0 -11
- package/dist/index.es5.js +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/walkerOS.json +140 -32
- package/package.json +4 -4
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/dimensions.ts","../src/skip.ts","../src/types/index.ts"],"sourcesContent":["import type { Mapping, Destination, Env } from './types';\nimport { getMappingValue, isArray } from '@walkeros/core';\nimport { getEnv } from '@walkeros/web-core';\nimport { resolveDimensionMap, sequence } from './dimensions';\nimport { logSkip } from './skip';\n\n// Types\nexport * as DestinationMatomo from './types';\n\nexport const destinationMatomo: Destination = {\n type: 'matomo',\n\n config: {},\n\n init({ config, env, logger }) {\n const { window } = getEnv<Env>(env);\n const { settings = {}, loadScript } = config;\n const { siteId, url } = settings;\n\n // Set up the Matomo command queue\n window._paq = window._paq || [];\n const queue = window._paq;\n const paq = (command: unknown[]) => {\n queue.push(command);\n };\n\n if (loadScript) {\n // Required only to load and address the tracker\n if (!siteId) return logger.throw('Config settings siteId missing');\n if (!url) return logger.throw('Config settings url missing');\n\n const baseUrl = normalizeUrl(url);\n\n // Load the Matomo tracking script\n addScript(baseUrl, env);\n\n // Configure tracker URL and site ID\n paq(['setTrackerUrl', baseUrl + 'matomo.php']);\n paq(['setSiteId', siteId]);\n }\n\n // Cookie-free tracking\n if (settings.disableCookies) paq(['disableCookies']);\n\n // Enable link tracking by default\n if (settings.enableLinkTracking !== false) paq(['enableLinkTracking']);\n\n // Heart beat timer for accurate time-on-page\n if (settings.enableHeartBeatTimer)\n paq(['enableHeartBeatTimer', settings.enableHeartBeatTimer]);\n },\n\n async push(event, { config, rule = {}, data, env, collector, logger, id }) {\n const { window } = getEnv<Env>(env);\n const queue = window._paq;\n if (!queue) {\n logger.warn('Matomo _paq queue missing, init() not run');\n return;\n }\n const paq = (command: unknown[]) => {\n queue.push(command);\n };\n\n const settings = config.settings || {};\n const eventMapping: Mapping = rule.settings || {};\n const { goalId } = eventMapping;\n const parameters = isArray(data) ? data : [data];\n\n // Matomo drops a conversion whose goal id is not a positive integer\n const goal = isGoalId(goalId) ? goalId : undefined;\n if (goalId !== undefined && goal === undefined)\n logSkip(\n logger,\n `${id}|${event.name}|invalid goalId`,\n `Goal of event \"${event.name}\" skipped: goalId ${JSON.stringify(goalId)} is not a positive integer`,\n { event: event.name, reason: 'invalid goalId' },\n );\n\n // A tracking flag picks the method, an explicit rule name (already\n // applied to event.name) passes through, and a page view defaults to\n // trackPageView. Anything else sends only its goal, or is unmapped.\n let command: unknown[] | undefined;\n if (eventMapping.siteSearch) {\n command = ['trackSiteSearch', ...parameters];\n } else if (eventMapping.contentImpression) {\n command = ['trackContentImpression', ...parameters];\n } else if (eventMapping.contentInteraction) {\n command = ['trackContentInteraction', ...parameters];\n } else if (rule.name) {\n command = [event.name, ...parameters];\n } else if (event.name === 'page view') {\n // The page title only when the rule maps no data of its own\n command =\n rule.data === undefined\n ? [\n 'trackPageView',\n await getMappingValue(event, 'data.title', { collector }),\n ]\n : ['trackPageView', ...parameters];\n } else if (goal === undefined) {\n logSkip(\n logger,\n `${id}|${event.name}|unmapped`,\n `Event \"${event.name}\" skipped: no rule name, tracking flag or goal, and not a page view`,\n { event: event.name, reason: 'unmapped' },\n );\n return;\n }\n\n // Resolve everything first, so this event's commands are pushed in one\n // synchronous block below and never interleave with another event's.\n const goalValue =\n goal !== undefined && eventMapping.goalValue !== undefined\n ? await getMappingValue(event, eventMapping.goalValue, { collector })\n : undefined;\n\n const { before, after } = sequence(\n await resolveDimensionMap(settings.customDimensions, event, collector),\n await resolveDimensionMap(\n eventMapping.customDimensions,\n event,\n collector,\n ),\n );\n\n before.forEach(paq);\n if (command) paq(command);\n\n // Goal tracking alongside event\n if (goal !== undefined) paq(['trackGoal', goal, goalValue]);\n\n after.forEach(paq);\n },\n};\n\n// A Matomo goal id, the same rule as the mapping schema.\nconst GOAL_ID = /^[1-9]\\d*$/;\n\n/** A positive integer, as a number or a decimal string. */\nfunction isGoalId(value: unknown): value is string | number {\n if (typeof value === 'number') return Number.isInteger(value) && value > 0;\n return typeof value === 'string' && GOAL_ID.test(value);\n}\n\n/** Base URL with exactly one trailing slash. */\nfunction normalizeUrl(url: string): string {\n return `${url.replace(/\\/+$/, '')}/`;\n}\n\nfunction addScript(url: string, env?: Env) {\n const { document } = getEnv<Env>(env);\n const script = document.createElement('script');\n script.type = 'text/javascript';\n script.src = url + 'matomo.js';\n script.async = true;\n script.defer = true;\n document.head.appendChild(script);\n}\n\nexport default destinationMatomo;\n","import type { Collector, WalkerOS } from '@walkeros/core';\nimport type { CustomDimensions } from './types';\nimport { getMappingValue } from '@walkeros/core';\n\n/** Bare dimension id to its resolved value, undefined when nothing resolved. */\nexport type DimensionValues = Record<string, string | undefined>;\n\n// A bare dimension id, the same rule as the settings schema.\nconst DIMENSION_ID = /^\\d+$/;\n\n/** Resolves every Mapping Value of a dimension map against the event. */\nexport async function resolveDimensionMap(\n map: CustomDimensions | undefined,\n event: WalkerOS.Event,\n collector: Collector.Instance,\n): Promise<DimensionValues> {\n const values: DimensionValues = {};\n if (!map) return values;\n\n for (const [id, value] of Object.entries(map)) {\n const resolved = await getMappingValue(event, value, { collector });\n values[id] =\n resolved === undefined || resolved === null\n ? undefined\n : String(resolved);\n }\n\n return values;\n}\n\n/** Commands that apply a map: setCustomDimension for defined values, deleteCustomDimension for undefined. */\nexport function applyCommands(values: DimensionValues): unknown[][] {\n return sortedEntries(values).map(([id, value]) =>\n value === undefined\n ? ['deleteCustomDimension', Number(id)]\n : ['setCustomDimension', Number(id), value],\n );\n}\n\n/**\n * The before and after command lists around an event's hits. Before them the\n * merged map applies; after them the rule-only keys are deleted and the\n * destination map applies again, so a rule value never leaks into later\n * hits. Without rule values the tracker already holds the destination map,\n * so nothing follows.\n */\nexport function sequence(\n destination: DimensionValues,\n rule: DimensionValues,\n): { before: unknown[][]; after: unknown[][] } {\n const before = applyCommands({ ...destination, ...rule });\n if (Object.keys(rule).length === 0) return { before, after: [] };\n\n // Rule-only keys to delete; one that resolved to undefined was already\n // deleted before the hit.\n const ruleOnly: DimensionValues = {};\n for (const [id, value] of Object.entries(rule)) {\n const shared = Object.prototype.hasOwnProperty.call(destination, id);\n if (!shared && value !== undefined) ruleOnly[id] = undefined;\n }\n\n return {\n before,\n after: [...applyCommands(ruleOnly), ...applyCommands(destination)],\n };\n}\n\n/** Entries with a bare integer id, ascending by id; any other key is ignored. */\nfunction sortedEntries(\n values: DimensionValues,\n): Array<[string, string | undefined]> {\n return Object.entries(values)\n .filter(([id]) => DIMENSION_ID.test(id))\n .sort(([a], [b]) => Number(a) - Number(b));\n}\n","import type { Logger } from '@walkeros/core';\n\n/** Most distinct skip keys that get a warning; beyond it every skip logs at debug. */\nexport const SKIP_KEY_CAP = 1000;\n\n// Module-level and bounded, so unbounded event names cannot grow memory.\nconst warned = new Set<string>();\n\n/** Warns once per key, then logs the same skip at debug. */\nexport function logSkip(\n logger: Logger.Instance,\n key: string,\n message: string,\n meta: Record<string, unknown>,\n): void {\n if (!warned.has(key) && warned.size < SKIP_KEY_CAP) {\n warned.add(key);\n logger.warn(message, meta);\n return;\n }\n\n logger.debug(message, meta);\n}\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type { DestinationWeb } from '@walkeros/web-core';\n\ndeclare global {\n interface Window {\n _paq?: Array<unknown>;\n }\n}\n\n/** Bare dimension id (like \"1\") to a Mapping Value resolved per event. */\nexport type CustomDimensions = Record<string, WalkerOSMapping.Value>;\n\nexport interface Settings {\n /** Matomo Site ID; required when `loadScript` is true. */\n siteId?: string;\n /** Base URL of the Matomo instance, like https://analytics.example.com/; required when `loadScript` is true. */\n url?: string;\n /** Disable all tracking cookies for cookie-free analytics. */\n disableCookies?: boolean;\n /** Enable automatic outlink and download tracking. Default: true. */\n enableLinkTracking?: boolean;\n /** Enable heart beat timer with interval in seconds for accurate time-on-page. */\n enableHeartBeatTimer?: number;\n /** Custom dimensions applied to every hit, keyed by bare dimension id. */\n customDimensions?: CustomDimensions;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {\n /** Matomo goal ID, a positive integer like 1; adds a trackGoal conversion. */\n goalId?: string | number;\n /** Goal revenue, resolved from the event (like \"data.revenue\"). */\n goalValue?: WalkerOSMapping.Value;\n /** Track as internal site search via trackSiteSearch. */\n siteSearch?: boolean;\n /** Track as content impression via trackContentImpression. */\n contentImpression?: boolean;\n /** Track as content interaction via trackContentInteraction. */\n contentInteraction?: boolean;\n /** Custom dimensions for this rule; win per key over the destination ones. */\n customDimensions?: CustomDimensions;\n}\n\nexport interface Env extends DestinationWeb.Env {\n window: {\n // Optional: the queue may be absent until `init` installs it.\n _paq?: Array<unknown>;\n location?: { href?: string };\n };\n document: {\n createElement: (tagName: string) => {\n type: string;\n src: string;\n async?: boolean;\n defer?: boolean;\n };\n head: {\n appendChild: (node: unknown) => void;\n };\n };\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport type Destination = DestinationWeb.Destination<Types>;\nexport type Config = DestinationWeb.Config<Types>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n"],"mappings":"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","names":["import_core","command"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/dimensions.ts","../src/types/index.ts"],"sourcesContent":["import type { Mapping, Destination, Env } from './types';\nimport {\n getGrantedConsent,\n getMappingValue,\n isArray,\n isObject,\n reportCause,\n stepId,\n StepError,\n stepCall,\n} from '@walkeros/core';\nimport { getEnv, loadVendor } from '@walkeros/web-core';\nimport { resolveDimensionMap, sequence } from './dimensions';\n\n// Types\nexport * as DestinationMatomo from './types';\n\n/**\n * Pushes commands onto the queue in one synchronous block, so another\n * event's commands never interleave, then waits for what each push returns.\n */\nfunction pushAll(\n queue: unknown[],\n commands: unknown[][],\n code: string,\n message: string,\n): Promise<number[]> {\n return stepCall(\n () => Promise.all(commands.map((command) => queue.push(command))),\n code,\n message,\n );\n}\n\n/**\n * matomo.js, injected by `loadVendor` with `loadScript`. `_paq` replays its\n * own queue, so commands are pushed synchronously and only a failed script\n * is reported.\n */\nfunction vendor(url: string | undefined, env?: Env, timeout?: number) {\n return loadVendor(\n url ? `${normalizeUrl(url)}matomo.js` : undefined,\n () => getEnv<Env>(env).window._paq,\n { timeout, document: getEnv<Env>(env).document },\n );\n}\n\nexport const destinationMatomo: Destination = {\n type: 'matomo',\n\n config: {},\n\n async init({ config, env }) {\n const { window } = getEnv<Env>(env);\n const { settings = {}, loadScript } = config;\n const { siteId, url } = settings;\n const commands: unknown[][] = [];\n\n if (loadScript) {\n // Required only to load and address the tracker\n if (!siteId || !url)\n throw new StepError(\n `Matomo with loadScript needs settings ${[\n ...(siteId ? [] : ['siteId']),\n ...(url ? [] : ['url']),\n ].join(' and ')}`,\n { code: 'config' },\n );\n\n const baseUrl = normalizeUrl(url);\n commands.push(['setTrackerUrl', baseUrl + 'matomo.php']);\n commands.push(['setSiteId', siteId]);\n }\n\n // Cookie-free tracking\n if (settings.disableCookies) commands.push(['disableCookies']);\n\n // Enable link tracking by default\n if (settings.enableLinkTracking !== false)\n commands.push(['enableLinkTracking']);\n\n // Heart beat timer for accurate time-on-page\n if (settings.enableHeartBeatTimer)\n commands.push(['enableHeartBeatTimer', settings.enableHeartBeatTimer]);\n\n // The Matomo command queue\n window._paq = window._paq || [];\n if (loadScript) vendor(url, env, config.timeout);\n await pushAll(\n window._paq,\n commands,\n 'vendor-not-ready',\n 'Matomo did not take its setup commands',\n );\n },\n\n async push(event, { config, rule = {}, data, env, collector, logger, id }) {\n const settings = config.settings || {};\n if (config.loadScript) vendor(settings.url, env, config.timeout).check();\n const queue = getEnv<Env>(env).window._paq;\n if (!queue)\n throw new StepError('Matomo _paq queue missing: init did not run', {\n code: 'vendor-not-ready',\n });\n\n const eventMapping: Mapping = rule.settings || {};\n const { goalId } = eventMapping;\n const parameters = isArray(data) ? data : [data];\n\n // Matomo drops a conversion whose goal id is not a positive integer: the\n // hit goes without it, and the cause log reports it once per cause.\n const goal = goalId === undefined || isGoalId(goalId) ? goalId : undefined;\n if (goalId !== undefined && goal === undefined)\n reportCause(\n collector,\n logger,\n { step: stepId('destination', id), code: 'config' },\n 'Matomo goal skipped: goalId is not a positive integer',\n { event: event.name, mappingKey: 'goalId' },\n );\n\n // A tracking flag picks the method, an explicit rule name (already\n // applied to event.name) passes through, and a page view defaults to\n // trackPageView. A silent rule sends none of them, only its goal.\n let command: unknown[] | undefined;\n if (rule.silent) {\n command = undefined;\n } else if (eventMapping.siteSearch) {\n command = ['trackSiteSearch', ...parameters];\n } else if (eventMapping.contentImpression) {\n command = ['trackContentImpression', ...parameters];\n } else if (eventMapping.contentInteraction) {\n command = ['trackContentInteraction', ...parameters];\n } else if (rule.name) {\n command = [event.name, ...parameters];\n } else if (event.name === 'page view') {\n // The page title only when the rule maps no data of its own\n command =\n rule.data === undefined\n ? [\n 'trackPageView',\n await getMappingValue(event, 'data.title', { collector }),\n ]\n : ['trackPageView', ...parameters];\n } else if (goal === undefined) {\n throw new StepError(\n `Matomo has no command for \"${event.name}\": map it with a rule name, a tracking flag or a goal, or ignore it`,\n { code: 'missing-input' },\n );\n }\n\n // Resolve everything first, so this event's commands are pushed in one\n // synchronous block below and never interleave with another event's.\n const goalValue =\n goal !== undefined && eventMapping.goalValue !== undefined\n ? await getMappingValue(event, eventMapping.goalValue, { collector })\n : undefined;\n\n const { before, after } = sequence(\n await resolveDimensionMap(settings.customDimensions, event, collector),\n await resolveDimensionMap(\n eventMapping.customDimensions,\n event,\n collector,\n ),\n );\n\n // A silent rule without a goal sends nothing, dimensions included.\n if (command || goal !== undefined)\n await pushAll(\n queue,\n [\n ...before,\n ...(command ? [command] : []),\n // Goal tracking alongside event\n ...(goal !== undefined ? [['trackGoal', goal, goalValue]] : []),\n ...after,\n ],\n 'transport',\n 'Matomo did not take the event commands',\n );\n },\n\n // The destination's required consent decides, as it gates the pushes: a\n // revocation stops every tracking request (link tracking included) for the\n // page, a grant resumes them. With disableCookies the grant keeps cookies\n // off.\n async on(type, { config, data, env, collector }) {\n const required = config.consent;\n if (type !== 'consent' || !required || !isObject(data)) return;\n if (!Object.keys(required).some((key) => key in data)) return;\n const queue = getEnv(env).window._paq;\n if (!queue) return;\n\n const granted = getGrantedConsent(required, collector.consent) !== false;\n const disableCookies =\n isObject(config.settings) && config.settings.disableCookies === true;\n const command = !granted\n ? ['forgetConsentGiven']\n : disableCookies\n ? ['setConsentGiven', false]\n : ['setConsentGiven'];\n\n await pushAll(\n queue,\n [command],\n 'consent-not-applied',\n 'Matomo did not take the consent update',\n );\n },\n};\n\n// A Matomo goal id, the same rule as the mapping schema.\nconst GOAL_ID = /^[1-9]\\d*$/;\n\n/** A positive integer, as a number or a decimal string. */\nfunction isGoalId(value: unknown): value is string | number {\n if (typeof value === 'number') return Number.isInteger(value) && value > 0;\n return typeof value === 'string' && GOAL_ID.test(value);\n}\n\n/** Base URL with exactly one trailing slash. */\nfunction normalizeUrl(url: string): string {\n return `${url.replace(/\\/+$/, '')}/`;\n}\n\nexport default destinationMatomo;\n","import type { Collector, WalkerOS } from '@walkeros/core';\nimport type { CustomDimensions } from './types';\nimport { getMappingValue } from '@walkeros/core';\n\n/** Bare dimension id to its resolved value, undefined when nothing resolved. */\nexport type DimensionValues = Record<string, string | undefined>;\n\n// A bare dimension id, the same rule as the settings schema.\nconst DIMENSION_ID = /^\\d+$/;\n\n/** Resolves every Mapping Value of a dimension map against the event. */\nexport async function resolveDimensionMap(\n map: CustomDimensions | undefined,\n event: WalkerOS.Event,\n collector: Collector.Instance,\n): Promise<DimensionValues> {\n const values: DimensionValues = {};\n if (!map) return values;\n\n for (const [id, value] of Object.entries(map)) {\n const resolved = await getMappingValue(event, value, { collector });\n values[id] =\n resolved === undefined || resolved === null\n ? undefined\n : String(resolved);\n }\n\n return values;\n}\n\n/** Commands that apply a map: setCustomDimension for defined values, deleteCustomDimension for undefined. */\nexport function applyCommands(values: DimensionValues): unknown[][] {\n return sortedEntries(values).map(([id, value]) =>\n value === undefined\n ? ['deleteCustomDimension', Number(id)]\n : ['setCustomDimension', Number(id), value],\n );\n}\n\n/**\n * The before and after command lists around an event's hits. Before them the\n * merged map applies; after them the rule-only keys are deleted and the\n * destination map applies again, so a rule value never leaks into later\n * hits. Without rule values the tracker already holds the destination map,\n * so nothing follows.\n */\nexport function sequence(\n destination: DimensionValues,\n rule: DimensionValues,\n): { before: unknown[][]; after: unknown[][] } {\n const before = applyCommands({ ...destination, ...rule });\n if (Object.keys(rule).length === 0) return { before, after: [] };\n\n // Rule-only keys to delete; one that resolved to undefined was already\n // deleted before the hit.\n const ruleOnly: DimensionValues = {};\n for (const [id, value] of Object.entries(rule)) {\n const shared = Object.prototype.hasOwnProperty.call(destination, id);\n if (!shared && value !== undefined) ruleOnly[id] = undefined;\n }\n\n return {\n before,\n after: [...applyCommands(ruleOnly), ...applyCommands(destination)],\n };\n}\n\n/** Entries with a bare integer id, ascending by id; any other key is ignored. */\nfunction sortedEntries(\n values: DimensionValues,\n): Array<[string, string | undefined]> {\n return Object.entries(values)\n .filter(([id]) => DIMENSION_ID.test(id))\n .sort(([a], [b]) => Number(a) - Number(b));\n}\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type { DestinationWeb } from '@walkeros/web-core';\n\ndeclare global {\n interface Window {\n _paq?: Array<unknown>;\n }\n}\n\n/** Bare dimension id (like \"1\") to a Mapping Value resolved per event. */\nexport type CustomDimensions = Record<string, WalkerOSMapping.Value>;\n\nexport interface Settings {\n /** Matomo Site ID; required when `loadScript` is true. */\n siteId?: string;\n /** Base URL of the Matomo instance, like https://analytics.example.com/; required when `loadScript` is true. */\n url?: string;\n /** Disable all tracking cookies for cookie-free analytics. */\n disableCookies?: boolean;\n /** Enable automatic outlink and download tracking. Default: true. */\n enableLinkTracking?: boolean;\n /** Enable heart beat timer with interval in seconds for accurate time-on-page. */\n enableHeartBeatTimer?: number;\n /** Custom dimensions applied to every hit, keyed by bare dimension id. */\n customDimensions?: CustomDimensions;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {\n /** Matomo goal ID, a positive integer like 1; adds a trackGoal conversion. */\n goalId?: string | number;\n /** Goal revenue, resolved from the event (like \"data.revenue\"). */\n goalValue?: WalkerOSMapping.Value;\n /** Track as internal site search via trackSiteSearch. */\n siteSearch?: boolean;\n /** Track as content impression via trackContentImpression. */\n contentImpression?: boolean;\n /** Track as content interaction via trackContentInteraction. */\n contentInteraction?: boolean;\n /** Custom dimensions for this rule; win per key over the destination ones. */\n customDimensions?: CustomDimensions;\n}\n\nexport interface Env extends DestinationWeb.Env {\n window: {\n // Optional: the queue may be absent until `init` installs it.\n _paq?: Array<unknown>;\n location?: { href?: string };\n };\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport type Destination = DestinationWeb.Destination<Types>;\nexport type Config = DestinationWeb.Config<Types>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n"],"mappings":"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","names":["import_core"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{getGrantedConsent as e,getMappingValue as t,isArray as o,isObject as n,reportCause as i,stepId as a,StepError as r,stepCall as s}from"@walkeros/core";import{getEnv as c,loadVendor as d}from"@walkeros/web-core";import{getMappingValue as l}from"@walkeros/core";var m=/^\d+$/;async function u(e,t,o){const n={};if(!e)return n;for(const[i,a]of Object.entries(e)){const e=await l(t,a,{collector:o});n[i]=null==e?void 0:String(e)}return n}function p(e){return function(e){return Object.entries(e).filter(([e])=>m.test(e)).sort(([e],[t])=>Number(e)-Number(t))}(e).map(([e,t])=>void 0===t?["deleteCustomDimension",Number(e)]:["setCustomDimension",Number(e),t])}var f={};function g(e,t,o,n){return s(()=>Promise.all(t.map(t=>e.push(t))),o,n)}function v(e,t,o){return d(e?`${b(e)}matomo.js`:void 0,()=>c(t).window._paq,{timeout:o,document:c(t).document})}var w={type:"matomo",config:{},async init({config:e,env:t}){const{window:o}=c(t),{settings:n={},loadScript:i}=e,{siteId:a,url:s}=n,d=[];if(i){if(!a||!s)throw new r(`Matomo with loadScript needs settings ${[...a?[]:["siteId"],...s?[]:["url"]].join(" and ")}`,{code:"config"});const e=b(s);d.push(["setTrackerUrl",e+"matomo.php"]),d.push(["setSiteId",a])}n.disableCookies&&d.push(["disableCookies"]),!1!==n.enableLinkTracking&&d.push(["enableLinkTracking"]),n.enableHeartBeatTimer&&d.push(["enableHeartBeatTimer",n.enableHeartBeatTimer]),o._paq=o._paq||[],i&&v(s,t,e.timeout),await g(o._paq,d,"vendor-not-ready","Matomo did not take its setup commands")},async push(e,{config:n,rule:s={},data:d,env:l,collector:m,logger:f,id:w}){const b=n.settings||{};n.loadScript&&v(b.url,l,n.timeout).check();const h=c(l).window._paq;if(!h)throw new r("Matomo _paq queue missing: init did not run",{code:"vendor-not-ready"});const y=s.settings||{},{goalId:I}=y,C=o(d)?d:[d],M=void 0===I||("number"==typeof(j=I)?Number.isInteger(j)&&j>0:"string"==typeof j&&k.test(j))?I:void 0;var j;let q;if(void 0!==I&&void 0===M&&i(m,f,{step:a("destination",w),code:"config"},"Matomo goal skipped: goalId is not a positive integer",{event:e.name,mappingKey:"goalId"}),s.silent)q=void 0;else if(y.siteSearch)q=["trackSiteSearch",...C];else if(y.contentImpression)q=["trackContentImpression",...C];else if(y.contentInteraction)q=["trackContentInteraction",...C];else if(s.name)q=[e.name,...C];else if("page view"===e.name)q=void 0===s.data?["trackPageView",await t(e,"data.title",{collector:m})]:["trackPageView",...C];else if(void 0===M)throw new r(`Matomo has no command for "${e.name}": map it with a rule name, a tracking flag or a goal, or ignore it`,{code:"missing-input"});const S=void 0!==M&&void 0!==y.goalValue?await t(e,y.goalValue,{collector:m}):void 0,{before:O,after:$}=function(e,t){const o=p({...e,...t});if(0===Object.keys(t).length)return{before:o,after:[]};const n={};for(const[o,i]of Object.entries(t))Object.prototype.hasOwnProperty.call(e,o)||void 0===i||(n[o]=void 0);return{before:o,after:[...p(n),...p(e)]}}(await u(b.customDimensions,e,m),await u(y.customDimensions,e,m));(q||void 0!==M)&&await g(h,[...O,...q?[q]:[],...void 0!==M?[["trackGoal",M,S]]:[],...$],"transport","Matomo did not take the event commands")},async on(t,{config:o,data:i,env:a,collector:r}){const s=o.consent;if("consent"!==t||!s||!n(i))return;if(!Object.keys(s).some(e=>e in i))return;const d=c(a).window._paq;if(!d)return;const l=!1!==e(s,r.consent),m=n(o.settings)&&!0===o.settings.disableCookies,u=l?m?["setConsentGiven",!1]:["setConsentGiven"]:["forgetConsentGiven"];await g(d,[u],"consent-not-applied","Matomo did not take the consent update")}},k=/^[1-9]\d*$/;function b(e){return`${e.replace(/\/+$/,"")}/`}var h=w;export{f as DestinationMatomo,h as default,w as destinationMatomo};//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/dimensions.ts","../src/skip.ts","../src/types/index.ts"],"sourcesContent":["import type { Mapping, Destination, Env } from './types';\nimport { getMappingValue, isArray } from '@walkeros/core';\nimport { getEnv } from '@walkeros/web-core';\nimport { resolveDimensionMap, sequence } from './dimensions';\nimport { logSkip } from './skip';\n\n// Types\nexport * as DestinationMatomo from './types';\n\nexport const destinationMatomo: Destination = {\n type: 'matomo',\n\n config: {},\n\n init({ config, env, logger }) {\n const { window } = getEnv<Env>(env);\n const { settings = {}, loadScript } = config;\n const { siteId, url } = settings;\n\n // Set up the Matomo command queue\n window._paq = window._paq || [];\n const queue = window._paq;\n const paq = (command: unknown[]) => {\n queue.push(command);\n };\n\n if (loadScript) {\n // Required only to load and address the tracker\n if (!siteId) return logger.throw('Config settings siteId missing');\n if (!url) return logger.throw('Config settings url missing');\n\n const baseUrl = normalizeUrl(url);\n\n // Load the Matomo tracking script\n addScript(baseUrl, env);\n\n // Configure tracker URL and site ID\n paq(['setTrackerUrl', baseUrl + 'matomo.php']);\n paq(['setSiteId', siteId]);\n }\n\n // Cookie-free tracking\n if (settings.disableCookies) paq(['disableCookies']);\n\n // Enable link tracking by default\n if (settings.enableLinkTracking !== false) paq(['enableLinkTracking']);\n\n // Heart beat timer for accurate time-on-page\n if (settings.enableHeartBeatTimer)\n paq(['enableHeartBeatTimer', settings.enableHeartBeatTimer]);\n },\n\n async push(event, { config, rule = {}, data, env, collector, logger, id }) {\n const { window } = getEnv<Env>(env);\n const queue = window._paq;\n if (!queue) {\n logger.warn('Matomo _paq queue missing, init() not run');\n return;\n }\n const paq = (command: unknown[]) => {\n queue.push(command);\n };\n\n const settings = config.settings || {};\n const eventMapping: Mapping = rule.settings || {};\n const { goalId } = eventMapping;\n const parameters = isArray(data) ? data : [data];\n\n // Matomo drops a conversion whose goal id is not a positive integer\n const goal = isGoalId(goalId) ? goalId : undefined;\n if (goalId !== undefined && goal === undefined)\n logSkip(\n logger,\n `${id}|${event.name}|invalid goalId`,\n `Goal of event \"${event.name}\" skipped: goalId ${JSON.stringify(goalId)} is not a positive integer`,\n { event: event.name, reason: 'invalid goalId' },\n );\n\n // A tracking flag picks the method, an explicit rule name (already\n // applied to event.name) passes through, and a page view defaults to\n // trackPageView. Anything else sends only its goal, or is unmapped.\n let command: unknown[] | undefined;\n if (eventMapping.siteSearch) {\n command = ['trackSiteSearch', ...parameters];\n } else if (eventMapping.contentImpression) {\n command = ['trackContentImpression', ...parameters];\n } else if (eventMapping.contentInteraction) {\n command = ['trackContentInteraction', ...parameters];\n } else if (rule.name) {\n command = [event.name, ...parameters];\n } else if (event.name === 'page view') {\n // The page title only when the rule maps no data of its own\n command =\n rule.data === undefined\n ? [\n 'trackPageView',\n await getMappingValue(event, 'data.title', { collector }),\n ]\n : ['trackPageView', ...parameters];\n } else if (goal === undefined) {\n logSkip(\n logger,\n `${id}|${event.name}|unmapped`,\n `Event \"${event.name}\" skipped: no rule name, tracking flag or goal, and not a page view`,\n { event: event.name, reason: 'unmapped' },\n );\n return;\n }\n\n // Resolve everything first, so this event's commands are pushed in one\n // synchronous block below and never interleave with another event's.\n const goalValue =\n goal !== undefined && eventMapping.goalValue !== undefined\n ? await getMappingValue(event, eventMapping.goalValue, { collector })\n : undefined;\n\n const { before, after } = sequence(\n await resolveDimensionMap(settings.customDimensions, event, collector),\n await resolveDimensionMap(\n eventMapping.customDimensions,\n event,\n collector,\n ),\n );\n\n before.forEach(paq);\n if (command) paq(command);\n\n // Goal tracking alongside event\n if (goal !== undefined) paq(['trackGoal', goal, goalValue]);\n\n after.forEach(paq);\n },\n};\n\n// A Matomo goal id, the same rule as the mapping schema.\nconst GOAL_ID = /^[1-9]\\d*$/;\n\n/** A positive integer, as a number or a decimal string. */\nfunction isGoalId(value: unknown): value is string | number {\n if (typeof value === 'number') return Number.isInteger(value) && value > 0;\n return typeof value === 'string' && GOAL_ID.test(value);\n}\n\n/** Base URL with exactly one trailing slash. */\nfunction normalizeUrl(url: string): string {\n return `${url.replace(/\\/+$/, '')}/`;\n}\n\nfunction addScript(url: string, env?: Env) {\n const { document } = getEnv<Env>(env);\n const script = document.createElement('script');\n script.type = 'text/javascript';\n script.src = url + 'matomo.js';\n script.async = true;\n script.defer = true;\n document.head.appendChild(script);\n}\n\nexport default destinationMatomo;\n","import type { Collector, WalkerOS } from '@walkeros/core';\nimport type { CustomDimensions } from './types';\nimport { getMappingValue } from '@walkeros/core';\n\n/** Bare dimension id to its resolved value, undefined when nothing resolved. */\nexport type DimensionValues = Record<string, string | undefined>;\n\n// A bare dimension id, the same rule as the settings schema.\nconst DIMENSION_ID = /^\\d+$/;\n\n/** Resolves every Mapping Value of a dimension map against the event. */\nexport async function resolveDimensionMap(\n map: CustomDimensions | undefined,\n event: WalkerOS.Event,\n collector: Collector.Instance,\n): Promise<DimensionValues> {\n const values: DimensionValues = {};\n if (!map) return values;\n\n for (const [id, value] of Object.entries(map)) {\n const resolved = await getMappingValue(event, value, { collector });\n values[id] =\n resolved === undefined || resolved === null\n ? undefined\n : String(resolved);\n }\n\n return values;\n}\n\n/** Commands that apply a map: setCustomDimension for defined values, deleteCustomDimension for undefined. */\nexport function applyCommands(values: DimensionValues): unknown[][] {\n return sortedEntries(values).map(([id, value]) =>\n value === undefined\n ? ['deleteCustomDimension', Number(id)]\n : ['setCustomDimension', Number(id), value],\n );\n}\n\n/**\n * The before and after command lists around an event's hits. Before them the\n * merged map applies; after them the rule-only keys are deleted and the\n * destination map applies again, so a rule value never leaks into later\n * hits. Without rule values the tracker already holds the destination map,\n * so nothing follows.\n */\nexport function sequence(\n destination: DimensionValues,\n rule: DimensionValues,\n): { before: unknown[][]; after: unknown[][] } {\n const before = applyCommands({ ...destination, ...rule });\n if (Object.keys(rule).length === 0) return { before, after: [] };\n\n // Rule-only keys to delete; one that resolved to undefined was already\n // deleted before the hit.\n const ruleOnly: DimensionValues = {};\n for (const [id, value] of Object.entries(rule)) {\n const shared = Object.prototype.hasOwnProperty.call(destination, id);\n if (!shared && value !== undefined) ruleOnly[id] = undefined;\n }\n\n return {\n before,\n after: [...applyCommands(ruleOnly), ...applyCommands(destination)],\n };\n}\n\n/** Entries with a bare integer id, ascending by id; any other key is ignored. */\nfunction sortedEntries(\n values: DimensionValues,\n): Array<[string, string | undefined]> {\n return Object.entries(values)\n .filter(([id]) => DIMENSION_ID.test(id))\n .sort(([a], [b]) => Number(a) - Number(b));\n}\n","import type { Logger } from '@walkeros/core';\n\n/** Most distinct skip keys that get a warning; beyond it every skip logs at debug. */\nexport const SKIP_KEY_CAP = 1000;\n\n// Module-level and bounded, so unbounded event names cannot grow memory.\nconst warned = new Set<string>();\n\n/** Warns once per key, then logs the same skip at debug. */\nexport function logSkip(\n logger: Logger.Instance,\n key: string,\n message: string,\n meta: Record<string, unknown>,\n): void {\n if (!warned.has(key) && warned.size < SKIP_KEY_CAP) {\n warned.add(key);\n logger.warn(message, meta);\n return;\n }\n\n logger.debug(message, meta);\n}\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type { DestinationWeb } from '@walkeros/web-core';\n\ndeclare global {\n interface Window {\n _paq?: Array<unknown>;\n }\n}\n\n/** Bare dimension id (like \"1\") to a Mapping Value resolved per event. */\nexport type CustomDimensions = Record<string, WalkerOSMapping.Value>;\n\nexport interface Settings {\n /** Matomo Site ID; required when `loadScript` is true. */\n siteId?: string;\n /** Base URL of the Matomo instance, like https://analytics.example.com/; required when `loadScript` is true. */\n url?: string;\n /** Disable all tracking cookies for cookie-free analytics. */\n disableCookies?: boolean;\n /** Enable automatic outlink and download tracking. Default: true. */\n enableLinkTracking?: boolean;\n /** Enable heart beat timer with interval in seconds for accurate time-on-page. */\n enableHeartBeatTimer?: number;\n /** Custom dimensions applied to every hit, keyed by bare dimension id. */\n customDimensions?: CustomDimensions;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {\n /** Matomo goal ID, a positive integer like 1; adds a trackGoal conversion. */\n goalId?: string | number;\n /** Goal revenue, resolved from the event (like \"data.revenue\"). */\n goalValue?: WalkerOSMapping.Value;\n /** Track as internal site search via trackSiteSearch. */\n siteSearch?: boolean;\n /** Track as content impression via trackContentImpression. */\n contentImpression?: boolean;\n /** Track as content interaction via trackContentInteraction. */\n contentInteraction?: boolean;\n /** Custom dimensions for this rule; win per key over the destination ones. */\n customDimensions?: CustomDimensions;\n}\n\nexport interface Env extends DestinationWeb.Env {\n window: {\n // Optional: the queue may be absent until `init` installs it.\n _paq?: Array<unknown>;\n location?: { href?: string };\n };\n document: {\n createElement: (tagName: string) => {\n type: string;\n src: string;\n async?: boolean;\n defer?: boolean;\n };\n head: {\n appendChild: (node: unknown) => void;\n };\n };\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport type Destination = DestinationWeb.Destination<Types>;\nexport type Config = DestinationWeb.Config<Types>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n"],"mappings":"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","names":["getMappingValue","command","getMappingValue"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/dimensions.ts","../src/types/index.ts"],"sourcesContent":["import type { Mapping, Destination, Env } from './types';\nimport {\n getGrantedConsent,\n getMappingValue,\n isArray,\n isObject,\n reportCause,\n stepId,\n StepError,\n stepCall,\n} from '@walkeros/core';\nimport { getEnv, loadVendor } from '@walkeros/web-core';\nimport { resolveDimensionMap, sequence } from './dimensions';\n\n// Types\nexport * as DestinationMatomo from './types';\n\n/**\n * Pushes commands onto the queue in one synchronous block, so another\n * event's commands never interleave, then waits for what each push returns.\n */\nfunction pushAll(\n queue: unknown[],\n commands: unknown[][],\n code: string,\n message: string,\n): Promise<number[]> {\n return stepCall(\n () => Promise.all(commands.map((command) => queue.push(command))),\n code,\n message,\n );\n}\n\n/**\n * matomo.js, injected by `loadVendor` with `loadScript`. `_paq` replays its\n * own queue, so commands are pushed synchronously and only a failed script\n * is reported.\n */\nfunction vendor(url: string | undefined, env?: Env, timeout?: number) {\n return loadVendor(\n url ? `${normalizeUrl(url)}matomo.js` : undefined,\n () => getEnv<Env>(env).window._paq,\n { timeout, document: getEnv<Env>(env).document },\n );\n}\n\nexport const destinationMatomo: Destination = {\n type: 'matomo',\n\n config: {},\n\n async init({ config, env }) {\n const { window } = getEnv<Env>(env);\n const { settings = {}, loadScript } = config;\n const { siteId, url } = settings;\n const commands: unknown[][] = [];\n\n if (loadScript) {\n // Required only to load and address the tracker\n if (!siteId || !url)\n throw new StepError(\n `Matomo with loadScript needs settings ${[\n ...(siteId ? [] : ['siteId']),\n ...(url ? [] : ['url']),\n ].join(' and ')}`,\n { code: 'config' },\n );\n\n const baseUrl = normalizeUrl(url);\n commands.push(['setTrackerUrl', baseUrl + 'matomo.php']);\n commands.push(['setSiteId', siteId]);\n }\n\n // Cookie-free tracking\n if (settings.disableCookies) commands.push(['disableCookies']);\n\n // Enable link tracking by default\n if (settings.enableLinkTracking !== false)\n commands.push(['enableLinkTracking']);\n\n // Heart beat timer for accurate time-on-page\n if (settings.enableHeartBeatTimer)\n commands.push(['enableHeartBeatTimer', settings.enableHeartBeatTimer]);\n\n // The Matomo command queue\n window._paq = window._paq || [];\n if (loadScript) vendor(url, env, config.timeout);\n await pushAll(\n window._paq,\n commands,\n 'vendor-not-ready',\n 'Matomo did not take its setup commands',\n );\n },\n\n async push(event, { config, rule = {}, data, env, collector, logger, id }) {\n const settings = config.settings || {};\n if (config.loadScript) vendor(settings.url, env, config.timeout).check();\n const queue = getEnv<Env>(env).window._paq;\n if (!queue)\n throw new StepError('Matomo _paq queue missing: init did not run', {\n code: 'vendor-not-ready',\n });\n\n const eventMapping: Mapping = rule.settings || {};\n const { goalId } = eventMapping;\n const parameters = isArray(data) ? data : [data];\n\n // Matomo drops a conversion whose goal id is not a positive integer: the\n // hit goes without it, and the cause log reports it once per cause.\n const goal = goalId === undefined || isGoalId(goalId) ? goalId : undefined;\n if (goalId !== undefined && goal === undefined)\n reportCause(\n collector,\n logger,\n { step: stepId('destination', id), code: 'config' },\n 'Matomo goal skipped: goalId is not a positive integer',\n { event: event.name, mappingKey: 'goalId' },\n );\n\n // A tracking flag picks the method, an explicit rule name (already\n // applied to event.name) passes through, and a page view defaults to\n // trackPageView. A silent rule sends none of them, only its goal.\n let command: unknown[] | undefined;\n if (rule.silent) {\n command = undefined;\n } else if (eventMapping.siteSearch) {\n command = ['trackSiteSearch', ...parameters];\n } else if (eventMapping.contentImpression) {\n command = ['trackContentImpression', ...parameters];\n } else if (eventMapping.contentInteraction) {\n command = ['trackContentInteraction', ...parameters];\n } else if (rule.name) {\n command = [event.name, ...parameters];\n } else if (event.name === 'page view') {\n // The page title only when the rule maps no data of its own\n command =\n rule.data === undefined\n ? [\n 'trackPageView',\n await getMappingValue(event, 'data.title', { collector }),\n ]\n : ['trackPageView', ...parameters];\n } else if (goal === undefined) {\n throw new StepError(\n `Matomo has no command for \"${event.name}\": map it with a rule name, a tracking flag or a goal, or ignore it`,\n { code: 'missing-input' },\n );\n }\n\n // Resolve everything first, so this event's commands are pushed in one\n // synchronous block below and never interleave with another event's.\n const goalValue =\n goal !== undefined && eventMapping.goalValue !== undefined\n ? await getMappingValue(event, eventMapping.goalValue, { collector })\n : undefined;\n\n const { before, after } = sequence(\n await resolveDimensionMap(settings.customDimensions, event, collector),\n await resolveDimensionMap(\n eventMapping.customDimensions,\n event,\n collector,\n ),\n );\n\n // A silent rule without a goal sends nothing, dimensions included.\n if (command || goal !== undefined)\n await pushAll(\n queue,\n [\n ...before,\n ...(command ? [command] : []),\n // Goal tracking alongside event\n ...(goal !== undefined ? [['trackGoal', goal, goalValue]] : []),\n ...after,\n ],\n 'transport',\n 'Matomo did not take the event commands',\n );\n },\n\n // The destination's required consent decides, as it gates the pushes: a\n // revocation stops every tracking request (link tracking included) for the\n // page, a grant resumes them. With disableCookies the grant keeps cookies\n // off.\n async on(type, { config, data, env, collector }) {\n const required = config.consent;\n if (type !== 'consent' || !required || !isObject(data)) return;\n if (!Object.keys(required).some((key) => key in data)) return;\n const queue = getEnv(env).window._paq;\n if (!queue) return;\n\n const granted = getGrantedConsent(required, collector.consent) !== false;\n const disableCookies =\n isObject(config.settings) && config.settings.disableCookies === true;\n const command = !granted\n ? ['forgetConsentGiven']\n : disableCookies\n ? ['setConsentGiven', false]\n : ['setConsentGiven'];\n\n await pushAll(\n queue,\n [command],\n 'consent-not-applied',\n 'Matomo did not take the consent update',\n );\n },\n};\n\n// A Matomo goal id, the same rule as the mapping schema.\nconst GOAL_ID = /^[1-9]\\d*$/;\n\n/** A positive integer, as a number or a decimal string. */\nfunction isGoalId(value: unknown): value is string | number {\n if (typeof value === 'number') return Number.isInteger(value) && value > 0;\n return typeof value === 'string' && GOAL_ID.test(value);\n}\n\n/** Base URL with exactly one trailing slash. */\nfunction normalizeUrl(url: string): string {\n return `${url.replace(/\\/+$/, '')}/`;\n}\n\nexport default destinationMatomo;\n","import type { Collector, WalkerOS } from '@walkeros/core';\nimport type { CustomDimensions } from './types';\nimport { getMappingValue } from '@walkeros/core';\n\n/** Bare dimension id to its resolved value, undefined when nothing resolved. */\nexport type DimensionValues = Record<string, string | undefined>;\n\n// A bare dimension id, the same rule as the settings schema.\nconst DIMENSION_ID = /^\\d+$/;\n\n/** Resolves every Mapping Value of a dimension map against the event. */\nexport async function resolveDimensionMap(\n map: CustomDimensions | undefined,\n event: WalkerOS.Event,\n collector: Collector.Instance,\n): Promise<DimensionValues> {\n const values: DimensionValues = {};\n if (!map) return values;\n\n for (const [id, value] of Object.entries(map)) {\n const resolved = await getMappingValue(event, value, { collector });\n values[id] =\n resolved === undefined || resolved === null\n ? undefined\n : String(resolved);\n }\n\n return values;\n}\n\n/** Commands that apply a map: setCustomDimension for defined values, deleteCustomDimension for undefined. */\nexport function applyCommands(values: DimensionValues): unknown[][] {\n return sortedEntries(values).map(([id, value]) =>\n value === undefined\n ? ['deleteCustomDimension', Number(id)]\n : ['setCustomDimension', Number(id), value],\n );\n}\n\n/**\n * The before and after command lists around an event's hits. Before them the\n * merged map applies; after them the rule-only keys are deleted and the\n * destination map applies again, so a rule value never leaks into later\n * hits. Without rule values the tracker already holds the destination map,\n * so nothing follows.\n */\nexport function sequence(\n destination: DimensionValues,\n rule: DimensionValues,\n): { before: unknown[][]; after: unknown[][] } {\n const before = applyCommands({ ...destination, ...rule });\n if (Object.keys(rule).length === 0) return { before, after: [] };\n\n // Rule-only keys to delete; one that resolved to undefined was already\n // deleted before the hit.\n const ruleOnly: DimensionValues = {};\n for (const [id, value] of Object.entries(rule)) {\n const shared = Object.prototype.hasOwnProperty.call(destination, id);\n if (!shared && value !== undefined) ruleOnly[id] = undefined;\n }\n\n return {\n before,\n after: [...applyCommands(ruleOnly), ...applyCommands(destination)],\n };\n}\n\n/** Entries with a bare integer id, ascending by id; any other key is ignored. */\nfunction sortedEntries(\n values: DimensionValues,\n): Array<[string, string | undefined]> {\n return Object.entries(values)\n .filter(([id]) => DIMENSION_ID.test(id))\n .sort(([a], [b]) => Number(a) - Number(b));\n}\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type { DestinationWeb } from '@walkeros/web-core';\n\ndeclare global {\n interface Window {\n _paq?: Array<unknown>;\n }\n}\n\n/** Bare dimension id (like \"1\") to a Mapping Value resolved per event. */\nexport type CustomDimensions = Record<string, WalkerOSMapping.Value>;\n\nexport interface Settings {\n /** Matomo Site ID; required when `loadScript` is true. */\n siteId?: string;\n /** Base URL of the Matomo instance, like https://analytics.example.com/; required when `loadScript` is true. */\n url?: string;\n /** Disable all tracking cookies for cookie-free analytics. */\n disableCookies?: boolean;\n /** Enable automatic outlink and download tracking. Default: true. */\n enableLinkTracking?: boolean;\n /** Enable heart beat timer with interval in seconds for accurate time-on-page. */\n enableHeartBeatTimer?: number;\n /** Custom dimensions applied to every hit, keyed by bare dimension id. */\n customDimensions?: CustomDimensions;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {\n /** Matomo goal ID, a positive integer like 1; adds a trackGoal conversion. */\n goalId?: string | number;\n /** Goal revenue, resolved from the event (like \"data.revenue\"). */\n goalValue?: WalkerOSMapping.Value;\n /** Track as internal site search via trackSiteSearch. */\n siteSearch?: boolean;\n /** Track as content impression via trackContentImpression. */\n contentImpression?: boolean;\n /** Track as content interaction via trackContentInteraction. */\n contentInteraction?: boolean;\n /** Custom dimensions for this rule; win per key over the destination ones. */\n customDimensions?: CustomDimensions;\n}\n\nexport interface Env extends DestinationWeb.Env {\n window: {\n // Optional: the queue may be absent until `init` installs it.\n _paq?: Array<unknown>;\n location?: { href?: string };\n };\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport type Destination = DestinationWeb.Destination<Types>;\nexport type Config = DestinationWeb.Config<Types>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n"],"mappings":"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","names":["getMappingValue","getMappingValue"]}
|
package/dist/walkerOS.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$meta": {
|
|
3
3
|
"package": "@walkeros/web-destination-matomo",
|
|
4
|
-
"version": "4.8.
|
|
4
|
+
"version": "4.8.2",
|
|
5
5
|
"type": "destination",
|
|
6
6
|
"platform": [
|
|
7
7
|
"web"
|
|
@@ -428,16 +428,6 @@
|
|
|
428
428
|
"location": {
|
|
429
429
|
"href": "https://www.example.com/page"
|
|
430
430
|
}
|
|
431
|
-
},
|
|
432
|
-
"document": {
|
|
433
|
-
"createElement": {
|
|
434
|
-
"$code": "()=>({type:\"\",src:\"\",async:!1,defer:!1})"
|
|
435
|
-
},
|
|
436
|
-
"head": {
|
|
437
|
-
"appendChild": {
|
|
438
|
-
"$code": "()=>{}"
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
431
|
}
|
|
442
432
|
},
|
|
443
433
|
"push": {
|
|
@@ -446,16 +436,6 @@
|
|
|
446
436
|
"location": {
|
|
447
437
|
"href": "https://www.example.com/page"
|
|
448
438
|
}
|
|
449
|
-
},
|
|
450
|
-
"document": {
|
|
451
|
-
"createElement": {
|
|
452
|
-
"$code": "()=>({type:\"\",src:\"\",async:!1,defer:!1})"
|
|
453
|
-
},
|
|
454
|
-
"head": {
|
|
455
|
-
"appendChild": {
|
|
456
|
-
"$code": "()=>{}"
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
439
|
}
|
|
460
440
|
},
|
|
461
441
|
"simulation": [
|
|
@@ -463,6 +443,22 @@
|
|
|
463
443
|
]
|
|
464
444
|
},
|
|
465
445
|
"step": {
|
|
446
|
+
"consentRevoke": {
|
|
447
|
+
"public": false,
|
|
448
|
+
"description": "For a destination with config.consent { marketing: true }, revoking marketing pushes forgetConsentGiven, which stops every tracking request of the page, link tracking included.",
|
|
449
|
+
"command": "consent",
|
|
450
|
+
"in": {
|
|
451
|
+
"marketing": false
|
|
452
|
+
},
|
|
453
|
+
"out": [
|
|
454
|
+
[
|
|
455
|
+
"window._paq.push",
|
|
456
|
+
[
|
|
457
|
+
"forgetConsentGiven"
|
|
458
|
+
]
|
|
459
|
+
]
|
|
460
|
+
]
|
|
461
|
+
},
|
|
466
462
|
"customDimensions": {
|
|
467
463
|
"title": "Custom dimensions",
|
|
468
464
|
"description": "Destination and rule custom dimensions are set right before the page view; afterwards the rule-only dimension is deleted and the destination value is set again.",
|
|
@@ -505,7 +501,7 @@
|
|
|
505
501
|
"consent": {
|
|
506
502
|
"functional": true
|
|
507
503
|
},
|
|
508
|
-
"id": "
|
|
504
|
+
"id": "f0cc5f6fec3d8eeb",
|
|
509
505
|
"trigger": "load",
|
|
510
506
|
"entity": "page",
|
|
511
507
|
"action": "view",
|
|
@@ -608,7 +604,7 @@
|
|
|
608
604
|
"consent": {
|
|
609
605
|
"functional": true
|
|
610
606
|
},
|
|
611
|
-
"id": "
|
|
607
|
+
"id": "1264bd65afd24f10",
|
|
612
608
|
"trigger": "visible",
|
|
613
609
|
"entity": "promotion",
|
|
614
610
|
"action": "visible",
|
|
@@ -702,7 +698,7 @@
|
|
|
702
698
|
"consent": {
|
|
703
699
|
"functional": true
|
|
704
700
|
},
|
|
705
|
-
"id": "
|
|
701
|
+
"id": "17fc82ac689238a0",
|
|
706
702
|
"trigger": "load",
|
|
707
703
|
"entity": "cart",
|
|
708
704
|
"action": "view",
|
|
@@ -774,7 +770,7 @@
|
|
|
774
770
|
"currency": "EUR",
|
|
775
771
|
"shipping": 5.22,
|
|
776
772
|
"taxes": 73.76,
|
|
777
|
-
"
|
|
773
|
+
"value": 555
|
|
778
774
|
},
|
|
779
775
|
"context": {
|
|
780
776
|
"shopping": [
|
|
@@ -844,7 +840,7 @@
|
|
|
844
840
|
"consent": {
|
|
845
841
|
"functional": true
|
|
846
842
|
},
|
|
847
|
-
"id": "
|
|
843
|
+
"id": "235d0d7bd7a213f2",
|
|
848
844
|
"trigger": "load",
|
|
849
845
|
"entity": "order",
|
|
850
846
|
"action": "complete",
|
|
@@ -885,7 +881,7 @@
|
|
|
885
881
|
{
|
|
886
882
|
"map": {
|
|
887
883
|
"orderId": "data.id",
|
|
888
|
-
"grandTotal": "data.
|
|
884
|
+
"grandTotal": "data.value",
|
|
889
885
|
"tax": "data.taxes",
|
|
890
886
|
"shipping": "data.shipping"
|
|
891
887
|
}
|
|
@@ -962,7 +958,7 @@
|
|
|
962
958
|
"consent": {
|
|
963
959
|
"functional": true
|
|
964
960
|
},
|
|
965
|
-
"id": "
|
|
961
|
+
"id": "1264bd65afd24f10",
|
|
966
962
|
"trigger": "visible",
|
|
967
963
|
"entity": "promotion",
|
|
968
964
|
"action": "visible",
|
|
@@ -1079,7 +1075,7 @@
|
|
|
1079
1075
|
"consent": {
|
|
1080
1076
|
"functional": true
|
|
1081
1077
|
},
|
|
1082
|
-
"id": "
|
|
1078
|
+
"id": "f0cc5f6fec3d8eeb",
|
|
1083
1079
|
"trigger": "load",
|
|
1084
1080
|
"entity": "page",
|
|
1085
1081
|
"action": "view",
|
|
@@ -1146,7 +1142,7 @@
|
|
|
1146
1142
|
"consent": {
|
|
1147
1143
|
"functional": true
|
|
1148
1144
|
},
|
|
1149
|
-
"id": "
|
|
1145
|
+
"id": "f0cc5f6fec3d8eeb",
|
|
1150
1146
|
"trigger": "load",
|
|
1151
1147
|
"entity": "page",
|
|
1152
1148
|
"action": "view",
|
|
@@ -1216,7 +1212,7 @@
|
|
|
1216
1212
|
"consent": {
|
|
1217
1213
|
"functional": true
|
|
1218
1214
|
},
|
|
1219
|
-
"id": "
|
|
1215
|
+
"id": "db22fb16c70f663d",
|
|
1220
1216
|
"trigger": "load",
|
|
1221
1217
|
"entity": "product",
|
|
1222
1218
|
"action": "view",
|
|
@@ -1267,6 +1263,65 @@
|
|
|
1267
1263
|
]
|
|
1268
1264
|
]
|
|
1269
1265
|
},
|
|
1266
|
+
"silentRule": {
|
|
1267
|
+
"public": false,
|
|
1268
|
+
"description": "A rule with silent: true and no goal sends no command, its dimensions included.",
|
|
1269
|
+
"in": {
|
|
1270
|
+
"name": "page view",
|
|
1271
|
+
"data": {
|
|
1272
|
+
"domain": "www.example.com",
|
|
1273
|
+
"title": "walkerOS documentation",
|
|
1274
|
+
"referrer": "https://www.walkeros.io/",
|
|
1275
|
+
"search": "?foo=bar",
|
|
1276
|
+
"hash": "#hash",
|
|
1277
|
+
"id": "/docs/"
|
|
1278
|
+
},
|
|
1279
|
+
"context": {
|
|
1280
|
+
"dev": [
|
|
1281
|
+
"test",
|
|
1282
|
+
1
|
|
1283
|
+
]
|
|
1284
|
+
},
|
|
1285
|
+
"globals": {
|
|
1286
|
+
"pagegroup": "docs"
|
|
1287
|
+
},
|
|
1288
|
+
"custom": {
|
|
1289
|
+
"completely": "random"
|
|
1290
|
+
},
|
|
1291
|
+
"user": {
|
|
1292
|
+
"id": "us3r",
|
|
1293
|
+
"device": "c00k13",
|
|
1294
|
+
"session": "s3ss10n"
|
|
1295
|
+
},
|
|
1296
|
+
"nested": [
|
|
1297
|
+
{
|
|
1298
|
+
"entity": "child",
|
|
1299
|
+
"data": {
|
|
1300
|
+
"is": "subordinated"
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
],
|
|
1304
|
+
"consent": {
|
|
1305
|
+
"functional": true
|
|
1306
|
+
},
|
|
1307
|
+
"id": "f0cc5f6fec3d8eeb",
|
|
1308
|
+
"trigger": "load",
|
|
1309
|
+
"entity": "page",
|
|
1310
|
+
"action": "view",
|
|
1311
|
+
"timestamp": 1700000300,
|
|
1312
|
+
"timing": 3.14,
|
|
1313
|
+
"source": {
|
|
1314
|
+
"count": 1,
|
|
1315
|
+
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
|
|
1316
|
+
"type": "collector",
|
|
1317
|
+
"schema": "4"
|
|
1318
|
+
}
|
|
1319
|
+
},
|
|
1320
|
+
"mapping": {
|
|
1321
|
+
"silent": true
|
|
1322
|
+
},
|
|
1323
|
+
"out": []
|
|
1324
|
+
},
|
|
1270
1325
|
"siteSearch": {
|
|
1271
1326
|
"title": "Site search",
|
|
1272
1327
|
"description": "A search submit fires Matomo trackSiteSearch with the keyword, category, and number of results.",
|
|
@@ -1305,7 +1360,7 @@
|
|
|
1305
1360
|
"consent": {
|
|
1306
1361
|
"functional": true
|
|
1307
1362
|
},
|
|
1308
|
-
"id": "
|
|
1363
|
+
"id": "190f5157b4d95304",
|
|
1309
1364
|
"trigger": "test",
|
|
1310
1365
|
"entity": "search",
|
|
1311
1366
|
"action": "submit",
|
|
@@ -1342,6 +1397,59 @@
|
|
|
1342
1397
|
]
|
|
1343
1398
|
]
|
|
1344
1399
|
]
|
|
1400
|
+
},
|
|
1401
|
+
"unmappedEvent": {
|
|
1402
|
+
"public": false,
|
|
1403
|
+
"description": "An event without a rule name, a tracking flag or a goal, and not a page view, has no Matomo command: the push fails with missing-input.",
|
|
1404
|
+
"in": {
|
|
1405
|
+
"name": "product view",
|
|
1406
|
+
"data": {
|
|
1407
|
+
"id": "ers",
|
|
1408
|
+
"name": "Everyday Ruck Snack",
|
|
1409
|
+
"color": "black",
|
|
1410
|
+
"size": "l",
|
|
1411
|
+
"price": 420
|
|
1412
|
+
},
|
|
1413
|
+
"context": {
|
|
1414
|
+
"shopping": [
|
|
1415
|
+
"detail",
|
|
1416
|
+
0
|
|
1417
|
+
]
|
|
1418
|
+
},
|
|
1419
|
+
"globals": {
|
|
1420
|
+
"pagegroup": "shop"
|
|
1421
|
+
},
|
|
1422
|
+
"custom": {
|
|
1423
|
+
"completely": "random"
|
|
1424
|
+
},
|
|
1425
|
+
"user": {
|
|
1426
|
+
"id": "us3r",
|
|
1427
|
+
"device": "c00k13",
|
|
1428
|
+
"session": "s3ss10n"
|
|
1429
|
+
},
|
|
1430
|
+
"nested": [],
|
|
1431
|
+
"consent": {
|
|
1432
|
+
"functional": true
|
|
1433
|
+
},
|
|
1434
|
+
"id": "db22fb16c70f663d",
|
|
1435
|
+
"trigger": "load",
|
|
1436
|
+
"entity": "product",
|
|
1437
|
+
"action": "view",
|
|
1438
|
+
"timestamp": 1700000301,
|
|
1439
|
+
"timing": 3.14,
|
|
1440
|
+
"source": {
|
|
1441
|
+
"count": 1,
|
|
1442
|
+
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
|
|
1443
|
+
"type": "collector",
|
|
1444
|
+
"schema": "4"
|
|
1445
|
+
}
|
|
1446
|
+
},
|
|
1447
|
+
"out": [],
|
|
1448
|
+
"outcome": {
|
|
1449
|
+
"status": "failed",
|
|
1450
|
+
"code": "missing-input",
|
|
1451
|
+
"retryable": false
|
|
1452
|
+
}
|
|
1345
1453
|
}
|
|
1346
1454
|
}
|
|
1347
1455
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walkeros/web-destination-matomo",
|
|
3
3
|
"description": "Matomo web destination for walkerOS",
|
|
4
|
-
"version": "4.8.
|
|
4
|
+
"version": "4.8.2",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.mjs",
|
|
@@ -38,11 +38,11 @@
|
|
|
38
38
|
"update": "npx npm-check-updates -u && npm update"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@walkeros/core": "4.8.
|
|
42
|
-
"@walkeros/web-core": "4.8.
|
|
41
|
+
"@walkeros/core": "4.8.2",
|
|
42
|
+
"@walkeros/web-core": "4.8.2"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@walkeros/collector": "4.8.
|
|
45
|
+
"@walkeros/collector": "4.8.2"
|
|
46
46
|
},
|
|
47
47
|
"repository": {
|
|
48
48
|
"url": "git+https://github.com/elbwalker/walkerOS.git",
|