Compare commits

..

8 Commits

Author SHA1 Message Date
Elijah Duffy
eeccb09b0b 0.0.2 2025-12-16 18:24:28 -08:00
Elijah Duffy
ff99579ff1 clean up build warnings 2025-12-16 18:24:24 -08:00
Elijah Duffy
802a825854 add logging with loglevel 2025-12-16 18:21:39 -08:00
Elijah Duffy
af1c423ccb fix type exports 2025-12-16 18:21:25 -08:00
Elijah Duffy
110f0d2434 finish separating meta init from PixelControl.for 2025-12-16 18:07:59 -08:00
Elijah Duffy
51dfcfde59 tracking: rename setAllowed to setConsent 2025-12-16 17:56:06 -08:00
Elijah Duffy
ae08a564a8 separate meta init from PixelControl.for 2025-12-16 17:55:18 -08:00
Elijah Duffy
04ce2d3c57 fix component exports 2025-12-16 17:54:54 -08:00
7 changed files with 68 additions and 37 deletions

View File

@@ -4,7 +4,8 @@
"type": "git", "type": "git",
"url": "https://gitea.auvem.com/svelte-toolkit/spectator.git" "url": "https://gitea.auvem.com/svelte-toolkit/spectator.git"
}, },
"version": "0.0.1", "version": "0.0.2",
"license": "MIT",
"scripts": { "scripts": {
"dev": "vite dev", "dev": "vite dev",
"build": "vite build && npm run prepack", "build": "vite build && npm run prepack",
@@ -34,12 +35,12 @@
} }
}, },
"peerDependencies": { "peerDependencies": {
"@sveltejs/kit": "^2.0.0",
"svelte": "^5.0.0" "svelte": "^5.0.0"
}, },
"devDependencies": { "devDependencies": {
"@eslint/compat": "^1.4.0", "@eslint/compat": "^1.4.0",
"@eslint/js": "^9.39.1", "@eslint/js": "^9.39.1",
"@sveltejs/adapter-auto": "^7.0.0",
"@sveltejs/kit": "^2.49.1", "@sveltejs/kit": "^2.49.1",
"@sveltejs/package": "^2.5.7", "@sveltejs/package": "^2.5.7",
"@sveltejs/vite-plugin-svelte": "^6.2.1", "@sveltejs/vite-plugin-svelte": "^6.2.1",
@@ -61,7 +62,8 @@
"svelte" "svelte"
], ],
"dependencies": { "dependencies": {
"@types/umami": "^2.10.1" "@types/umami": "^2.10.1",
"loglevel": "^1.9.2"
}, },
"publishConfig": { "publishConfig": {
"registry": "https://gitea.auvem.com/api/packages/svelte-toolkit/npm/" "registry": "https://gitea.auvem.com/api/packages/svelte-toolkit/npm/"

21
pnpm-lock.yaml generated
View File

@@ -11,6 +11,9 @@ importers:
'@types/umami': '@types/umami':
specifier: ^2.10.1 specifier: ^2.10.1
version: 2.10.1 version: 2.10.1
loglevel:
specifier: ^1.9.2
version: 1.9.2
devDependencies: devDependencies:
'@eslint/compat': '@eslint/compat':
specifier: ^1.4.0 specifier: ^1.4.0
@@ -18,9 +21,6 @@ importers:
'@eslint/js': '@eslint/js':
specifier: ^9.39.1 specifier: ^9.39.1
version: 9.39.2 version: 9.39.2
'@sveltejs/adapter-auto':
specifier: ^7.0.0
version: 7.0.0(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@24.10.4)))(svelte@5.46.0)(vite@7.3.0(@types/node@24.10.4)))
'@sveltejs/kit': '@sveltejs/kit':
specifier: ^2.49.1 specifier: ^2.49.1
version: 2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@24.10.4)))(svelte@5.46.0)(vite@7.3.0(@types/node@24.10.4)) version: 2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@24.10.4)))(svelte@5.46.0)(vite@7.3.0(@types/node@24.10.4))
@@ -432,11 +432,6 @@ packages:
peerDependencies: peerDependencies:
acorn: ^8.9.0 acorn: ^8.9.0
'@sveltejs/adapter-auto@7.0.0':
resolution: {integrity: sha512-ImDWaErTOCkRS4Gt+5gZuymKFBobnhChXUZ9lhUZLahUgvA4OOvRzi3sahzYgbxGj5nkA6OV0GAW378+dl/gyw==}
peerDependencies:
'@sveltejs/kit': ^2.0.0
'@sveltejs/kit@2.49.2': '@sveltejs/kit@2.49.2':
resolution: {integrity: sha512-Vp3zX/qlwerQmHMP6x0Ry1oY7eKKRcOWGc2P59srOp4zcqyn+etJyQpELgOi4+ZSUgteX8Y387NuwruLgGXLUQ==} resolution: {integrity: sha512-Vp3zX/qlwerQmHMP6x0Ry1oY7eKKRcOWGc2P59srOp4zcqyn+etJyQpELgOi4+ZSUgteX8Y387NuwruLgGXLUQ==}
engines: {node: '>=18.13'} engines: {node: '>=18.13'}
@@ -846,6 +841,10 @@ packages:
lodash.merge@4.6.2: lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
loglevel@1.9.2:
resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==}
engines: {node: '>= 0.6.0'}
magic-string@0.30.21: magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
@@ -1393,10 +1392,6 @@ snapshots:
dependencies: dependencies:
acorn: 8.15.0 acorn: 8.15.0
'@sveltejs/adapter-auto@7.0.0(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@24.10.4)))(svelte@5.46.0)(vite@7.3.0(@types/node@24.10.4)))':
dependencies:
'@sveltejs/kit': 2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@24.10.4)))(svelte@5.46.0)(vite@7.3.0(@types/node@24.10.4))
'@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@24.10.4)))(svelte@5.46.0)(vite@7.3.0(@types/node@24.10.4))': '@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@24.10.4)))(svelte@5.46.0)(vite@7.3.0(@types/node@24.10.4))':
dependencies: dependencies:
'@standard-schema/spec': 1.1.0 '@standard-schema/spec': 1.1.0
@@ -1852,6 +1847,8 @@ snapshots:
lodash.merge@4.6.2: {} lodash.merge@4.6.2: {}
loglevel@1.9.2: {}
magic-string@0.30.21: magic-string@0.30.21:
dependencies: dependencies:
'@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/sourcemap-codec': 1.5.5

View File

@@ -39,42 +39,63 @@
loadMetaPixel(); // Load the Meta Pixel script loadMetaPixel(); // Load the Meta Pixel script
} }
this._baseLoaded = true; this._baseLoaded = true;
log.debug('Meta Pixel base script loaded.');
} }
/** Tells the Meta pixel that the user has given consent for tracking. */ /** Tells the Meta pixel that the user has given consent for tracking. */
static grantConsent() { static grantConsent() {
this.loadGuard(); this.loadGuard();
window.fbq?.('consent', 'grant'); window.fbq?.('consent', 'grant');
log.debug('Meta Pixel consent granted.');
} }
/** Tells the Meta pixel that the user has revoked consent for tracking. */ /** Tells the Meta pixel that the user has revoked consent for tracking. */
static revokeConsent() { static revokeConsent() {
this.loadGuard(); this.loadGuard();
window.fbq?.('consent', 'revoke'); window.fbq?.('consent', 'revoke');
log.debug('Meta Pixel consent revoked.');
} }
/** /**
* Returns a PixelControl instance for the given Meta Pixel ID. If * Returns a PixelControl instance for the given Meta Pixel ID. If
* the base Meta Pixel script has not been loaded yet, it will be * the base Meta Pixel script has not been loaded yet, it will be
* loaded automatically. Optionally sets a test event code for the Pixel. * loaded automatically. Optionally sets a test event code for the Pixel.
* Does NOT initialize the Pixel; call `fireInit()` on the returned instance
* before tracking events.
* @param trackingManager Tracking manager to handle user consent for tracking
* @param pixelID Meta Pixel ID * @param pixelID Meta Pixel ID
* @param testEventCode Optional test event code * @param options Optional settings
* @returns PixelControl instance * @returns PixelControl instance
*/ */
static for( static for(
trackingManager: MaybeGetter<TrackingManager | undefined>, trackingManager: MaybeGetter<TrackingManager | undefined>,
pixelID: string, pixelID: string,
options?: { options?: {
/**
* if provided, events fired will always have this code attached
* to prevent them from polluting real analytics data.
*/
testEventCode?: string; testEventCode?: string;
advancedMatching?: AdvancedMatching;
initOptions?: InitOptions;
} }
): PixelControl { ): PixelControl {
PixelControl.load(); PixelControl.load();
window.fbq('init', pixelID);
return new PixelControl(trackingManager, pixelID, options?.testEventCode); return new PixelControl(trackingManager, pixelID, options?.testEventCode);
} }
/**
* Initializes this pixel with the Meta Pixel API including any advanced
* matching data and options.
* @param advancedMatching Advanced matching data
* @param initOptions Initialization options
* @returns this PixelControl instance
*/
fireInit(advancedMatching?: AdvancedMatching, initOptions?: InitOptions): PixelControl {
PixelControl.loadGuard();
window.fbq('init', this._pixelID, advancedMatching, initOptions);
log.debug(`Meta Pixel [${this._pixelID}] initialized.`);
return this;
}
/** /**
* Checks if the Meta Pixel has consent to track user data * Checks if the Meta Pixel has consent to track user data
* and if the Pixel has been loaded. * and if the Pixel has been loaded.
@@ -94,6 +115,9 @@
pageView() { pageView() {
if (!this.consentGuard()) return; if (!this.consentGuard()) return;
window.fbq('track', 'PageView', undefined, { test_event_code: this._testEventCode }); window.fbq('track', 'PageView', undefined, { test_event_code: this._testEventCode });
log.debug(
`Meta Pixel [${this._pixelID}] PageView event sent (test code: ${this._testEventCode}).`
);
} }
/** /**
@@ -106,6 +130,9 @@
eventID, eventID,
test_event_code: this._testEventCode test_event_code: this._testEventCode
}); });
log.debug(
`Meta Pixel [${this._pixelID}] ${event} event sent (test code: ${this._testEventCode}).`
);
} }
/** /**
@@ -118,6 +145,9 @@
eventID, eventID,
test_event_code: this._testEventCode test_event_code: this._testEventCode
}); });
log.debug(
`Meta Pixel [${this._pixelID}] ${event} custom event sent (test code: ${this._testEventCode}).`
);
} }
} }
</script> </script>
@@ -137,6 +167,7 @@
import { loadMetaPixel } from './util/meta-pixel-loader.ts'; import { loadMetaPixel } from './util/meta-pixel-loader.ts';
import { onNavigate } from '$app/navigation'; import { onNavigate } from '$app/navigation';
import { resolveGetter, type MaybeGetter } from './util/getter.ts'; import { resolveGetter, type MaybeGetter } from './util/getter.ts';
import log from 'loglevel';
interface Props { interface Props {
/** Meta Pixel ID */ /** Meta Pixel ID */
@@ -171,7 +202,7 @@
throw new Error('MetaPixel component requires a TrackingManager to manage consent.'); throw new Error('MetaPixel component requires a TrackingManager to manage consent.');
} }
PixelControl.load(); PixelControl.load();
pixel = PixelControl.for(trackingManager, pixelID, { testEventCode }); pixel = PixelControl.for(trackingManager, pixelID, { testEventCode }).fireInit();
trackingManager.runWithConsent(() => { trackingManager.runWithConsent(() => {
if (autoPageView && pixel) { if (autoPageView && pixel) {

View File

@@ -2,6 +2,7 @@
import { dev } from '$app/environment'; import { dev } from '$app/environment';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import type { TrackingManager } from './tracking.svelte.ts'; import type { TrackingManager } from './tracking.svelte.ts';
import log from 'loglevel';
interface Props { interface Props {
/** /**
@@ -27,11 +28,11 @@
const devConsoleTag = $derived(`[dev][consent: ${consentGranted ? 'granted' : 'revoked'}]`); const devConsoleTag = $derived(`[dev][consent: ${consentGranted ? 'granted' : 'revoked'}]`);
const devOverride = { const devOverride = {
track: (...args: unknown[]): Promise<string> | undefined => { track: (...args: unknown[]): Promise<string> | undefined => {
console.log(`${devConsoleTag}: Track called with:`, ...args); log.debug(`${devConsoleTag}: Track called with:`, ...args);
return undefined; return undefined;
}, },
identify: (...args: unknown[]): Promise<void> => { identify: (...args: unknown[]): Promise<void> => {
console.log(`${devConsoleTag}: Identify called with:`, ...args); log.debug(`${devConsoleTag}: Identify called with:`, ...args);
return Promise.resolve(); return Promise.resolve();
} }
}; };
@@ -61,7 +62,7 @@
} }
}); });
if (dev) console.log('[dev]: Umami tracking disabled'); if (dev) log.debug('[dev]: Umami tracking disabled');
onMount(() => { onMount(() => {
if (dev) { if (dev) {

View File

@@ -1,6 +1,14 @@
// Reexport your entry components here // Reexport your entry components here
export * as fbq from './types/fbq.js'; import { dev } from '$app/environment';
export * from './MetaPixel.svelte'; import log from 'loglevel';
export type * as fbq from './types/fbq.d.ts';
export { default as MetaPixel, PixelControl } from './MetaPixel.svelte';
export * from './tracking.svelte.ts'; export * from './tracking.svelte.ts';
export * from './Umami.svelte'; export { default as Umami } from './Umami.svelte';
// set log level to debug if we're in dev mode
if (dev) {
log.setLevel('debug');
}

View File

@@ -77,10 +77,10 @@ export class TrackingManager {
} }
/** /**
* Sets whether tracking is allowed. If set to true, all queued callbacks * Sets whether tracking is consented. If set to true, all queued callbacks
* will be executed. * will be executed.
*/ */
setAllowed(value: boolean) { setConsent(value: boolean) {
if (this._consent === value) return; if (this._consent === value) return;
this._consent = value; this._consent = value;

View File

@@ -1,18 +1,10 @@
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */ /** @type {import('@sveltejs/kit').Config} */
const config = { const config = {
// Consult https://svelte.dev/docs/kit/integrations // Consult https://svelte.dev/docs/kit/integrations
// for more information about preprocessors // for more information about preprocessors
preprocess: vitePreprocess(), preprocess: vitePreprocess()
kit: {
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
adapter: adapter()
}
}; };
export default config; export default config;