diff --git a/packages/audience/pixel/.eslintrc.cjs b/packages/audience/pixel/.eslintrc.cjs new file mode 100644 index 0000000000..183fc73f4c --- /dev/null +++ b/packages/audience/pixel/.eslintrc.cjs @@ -0,0 +1,10 @@ +module.exports = { + extends: ['../../../.eslintrc'], + parserOptions: { + project: './tsconfig.eslint.json', + tsconfigRootDir: __dirname, + }, + rules: { + 'no-underscore-dangle': ['error', { allow: ['__imtbl', '_loaded'] }], + }, +}; diff --git a/packages/audience/pixel/jest.config.ts b/packages/audience/pixel/jest.config.ts new file mode 100644 index 0000000000..59981c1e5a --- /dev/null +++ b/packages/audience/pixel/jest.config.ts @@ -0,0 +1,13 @@ +import type { Config } from 'jest'; + +const config: Config = { + roots: ['/src'], + moduleDirectories: ['node_modules', 'src'], + testEnvironment: 'jsdom', + transform: { + '^.+\\.(t|j)sx?$': '@swc/jest', + }, + transformIgnorePatterns: [], +}; + +export default config; diff --git a/packages/audience/pixel/package.json b/packages/audience/pixel/package.json new file mode 100644 index 0000000000..9a27876d2a --- /dev/null +++ b/packages/audience/pixel/package.json @@ -0,0 +1,43 @@ +{ + "name": "@imtbl/pixel", + "description": "Immutable Tracking Pixel — drop-in JavaScript snippet for device fingerprint, page view, and attribution data", + "version": "0.0.0", + "author": "Immutable", + "private": true, + "bugs": "https://github.com/immutable/ts-immutable-sdk/issues", + "dependencies": {}, + "devDependencies": { + "@swc/core": "^1.4.2", + "@swc/jest": "^0.2.37", + "@types/jest": "^29.5.12", + "eslint": "^8.56.0", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.4.3", + "tsup": "^8.3.0", + "typescript": "^5.6.2" + }, + "exports": { + "development": { + "types": "./src/index.ts", + "default": "./dist/imtbl.js" + }, + "default": { + "types": "./dist/types/index.d.ts", + "default": "./dist/imtbl.js" + } + }, + "files": ["dist"], + "main": "dist/imtbl.js", + "homepage": "https://github.com/immutable/ts-immutable-sdk#readme", + "repository": "immutable/ts-immutable-sdk.git", + "scripts": { + "build": "pnpm transpile && pnpm typegen", + "transpile": "tsup", + "typegen": "tsc --customConditions default --emitDeclarationOnly --outDir dist/types", + "lint": "eslint ./src --ext .ts --max-warnings=0", + "test": "jest --passWithNoTests", + "typecheck": "tsc --customConditions default --noEmit" + }, + "type": "module", + "types": "./dist/types/index.d.ts" +} diff --git a/packages/audience/pixel/src/attribution.test.ts b/packages/audience/pixel/src/attribution.test.ts new file mode 100644 index 0000000000..b742260a35 --- /dev/null +++ b/packages/audience/pixel/src/attribution.test.ts @@ -0,0 +1,132 @@ +import { collectAttribution, clearAttribution } from './attribution'; + +const STORAGE_KEY = '__imtbl_attribution'; + +beforeEach(() => { + sessionStorage.clear(); + jest.restoreAllMocks(); +}); + +function setLocation(url: string) { + Object.defineProperty(window, 'location', { + value: new URL(url), + writable: true, + configurable: true, + }); +} + +describe('collectAttribution', () => { + it('parses UTM parameters from the URL', () => { + setLocation( + 'https://example.com/?utm_source=google&utm_medium=cpc&utm_campaign=spring&utm_content=banner&utm_term=nft', + ); + + const result = collectAttribution(); + expect(result.utm_source).toBe('google'); + expect(result.utm_medium).toBe('cpc'); + expect(result.utm_campaign).toBe('spring'); + expect(result.utm_content).toBe('banner'); + expect(result.utm_term).toBe('nft'); + }); + + it('parses ad network click IDs', () => { + setLocation( + 'https://example.com/?gclid=abc&dclid=dc1&fbclid=fb2&ttclid=tt3&msclkid=ms4&li_fat_id=li5', + ); + + const result = collectAttribution(); + expect(result.gclid).toBe('abc'); + expect(result.dclid).toBe('dc1'); + expect(result.fbclid).toBe('fb2'); + expect(result.ttclid).toBe('tt3'); + expect(result.msclkid).toBe('ms4'); + expect(result.li_fat_id).toBe('li5'); + }); + + it('captures referrer and landing page', () => { + setLocation('https://game.example.com/landing'); + Object.defineProperty(document, 'referrer', { + value: 'https://google.com/search?q=nft', + configurable: true, + }); + + const result = collectAttribution(); + expect(result.referrer).toBe('https://google.com/search?q=nft'); + expect(result.landing_page).toBe('https://game.example.com/landing'); + }); + + it('caches in sessionStorage and returns cached on second call', () => { + setLocation('https://example.com/?utm_source=google'); + + const first = collectAttribution(); + expect(first.utm_source).toBe('google'); + + // Change URL — should still return cached value + setLocation('https://example.com/?utm_source=facebook'); + const second = collectAttribution(); + expect(second.utm_source).toBe('google'); + }); + + it('parses referral_code from the URL', () => { + setLocation('https://example.com/?referral_code=PARTNER42'); + + const result = collectAttribution(); + expect(result.referral_code).toBe('PARTNER42'); + }); + + it('sets touchpoint_type to click when UTMs are present', () => { + setLocation('https://example.com/?utm_source=google'); + + const result = collectAttribution(); + expect(result.touchpoint_type).toBe('click'); + }); + + it('sets touchpoint_type to click when a click ID is present', () => { + setLocation('https://example.com/?gclid=abc123'); + + const result = collectAttribution(); + expect(result.touchpoint_type).toBe('click'); + }); + + it('does not set touchpoint_type when no UTMs or click IDs are present', () => { + setLocation('https://example.com/'); + Object.defineProperty(document, 'referrer', { value: 'https://other.com', configurable: true }); + + const result = collectAttribution(); + expect(result.touchpoint_type).toBeUndefined(); + }); + + it('returns empty attribution when no params are present', () => { + setLocation('https://example.com/'); + Object.defineProperty(document, 'referrer', { value: '', configurable: true }); + + const result = collectAttribution(); + expect(result.utm_source).toBeUndefined(); + expect(result.gclid).toBeUndefined(); + expect(result.referrer).toBeUndefined(); + }); + + it('handles sessionStorage being unavailable', () => { + setLocation('https://example.com/?utm_source=twitter'); + jest.spyOn(Storage.prototype, 'getItem').mockImplementation(() => { + throw new Error('storage disabled'); + }); + jest.spyOn(Storage.prototype, 'setItem').mockImplementation(() => { + throw new Error('storage disabled'); + }); + + const result = collectAttribution(); + expect(result.utm_source).toBe('twitter'); + }); +}); + +describe('clearAttribution', () => { + it('removes cached attribution from sessionStorage', () => { + setLocation('https://example.com/?utm_source=google'); + collectAttribution(); + expect(sessionStorage.getItem(STORAGE_KEY)).not.toBeNull(); + + clearAttribution(); + expect(sessionStorage.getItem(STORAGE_KEY)).toBeNull(); + }); +}); diff --git a/packages/audience/pixel/src/attribution.ts b/packages/audience/pixel/src/attribution.ts new file mode 100644 index 0000000000..0046ba054d --- /dev/null +++ b/packages/audience/pixel/src/attribution.ts @@ -0,0 +1,114 @@ +const UTM_PARAMS = [ + 'utm_source', + 'utm_medium', + 'utm_campaign', + 'utm_content', + 'utm_term', +] as const; + +const CLICK_ID_PARAMS = [ + 'gclid', + 'dclid', + 'fbclid', + 'ttclid', + 'msclkid', + 'li_fat_id', +] as const; + +const STORAGE_KEY = '__imtbl_attribution'; + +export interface Attribution { + utm_source?: string; + utm_medium?: string; + utm_campaign?: string; + utm_content?: string; + utm_term?: string; + gclid?: string; + dclid?: string; + fbclid?: string; + ttclid?: string; + msclkid?: string; + li_fat_id?: string; + referral_code?: string; + referrer?: string; + landing_page?: string; + touchpoint_type?: string; +} + +type AttributionKey = keyof Attribution; + +function parseParams(url: string): Attribution { + let params: URLSearchParams; + try { + params = new URL(url).searchParams; + } catch { + return {}; + } + + const result: Attribution = {}; + for (const key of [...UTM_PARAMS, ...CLICK_ID_PARAMS]) { + const value = params.get(key); + if (value) { + result[key as AttributionKey] = value; + } + } + + const referralCode = params.get('referral_code'); + if (referralCode) { + result.referral_code = referralCode; + } + + return result; +} + +function loadFromStorage(): Attribution | null { + try { + const raw = sessionStorage.getItem(STORAGE_KEY); + return raw ? (JSON.parse(raw) as Attribution) : null; + } catch { + return null; + } +} + +function saveToStorage(attribution: Attribution): void { + try { + sessionStorage.setItem(STORAGE_KEY, JSON.stringify(attribution)); + } catch { + // sessionStorage may be unavailable (private browsing, storage full) + } +} + +export function collectAttribution(): Attribution { + const cached = loadFromStorage(); + if (cached) return cached; + + const urlParams = typeof window !== 'undefined' && window.location + ? parseParams(window.location.href) + : {}; + + const referrer = typeof document !== 'undefined' ? document.referrer || undefined : undefined; + const landingPage = typeof window !== 'undefined' && window.location + ? window.location.href + : undefined; + + const hasClickId = CLICK_ID_PARAMS.some((key) => key in urlParams); + const hasUtm = UTM_PARAMS.some((key) => key in urlParams); + + const attribution: Attribution = { + ...urlParams, + referrer, + landing_page: landingPage, + touchpoint_type: hasClickId || hasUtm ? 'click' : undefined, + }; + + saveToStorage(attribution); + return attribution; +} + +export function clearAttribution(): void { + try { + sessionStorage.removeItem(STORAGE_KEY); + } catch { + // noop + } +} diff --git a/packages/audience/pixel/src/index.ts b/packages/audience/pixel/src/index.ts new file mode 100644 index 0000000000..d6d235bc7f --- /dev/null +++ b/packages/audience/pixel/src/index.ts @@ -0,0 +1,8 @@ +export { collectAttribution, clearAttribution } from './attribution'; +export type { Attribution } from './attribution'; + +export { createLoader } from './loader'; +export type { Command, ImtblGlobal } from './loader'; + +export { generateSnippet } from './snippet'; +export type { SnippetOptions } from './snippet'; diff --git a/packages/audience/pixel/src/loader.test.ts b/packages/audience/pixel/src/loader.test.ts new file mode 100644 index 0000000000..1197b4239c --- /dev/null +++ b/packages/audience/pixel/src/loader.test.ts @@ -0,0 +1,79 @@ +import { createLoader, Command } from './loader'; + +beforeEach(() => { + delete (window as Record).__imtbl; +}); + +describe('createLoader', () => { + it('installs on window.__imtbl', () => { + const handler = jest.fn(); + const loader = createLoader(handler); + + expect((window as Record).__imtbl).toBe(loader); + expect(loader._loaded).toBe(true); + }); + + it('forwards push() calls to the handler', () => { + const handler = jest.fn(); + const loader = createLoader(handler); + + loader.push(['init', { key: 'pk_123' }]); + loader.push(['identify', 'user-1']); + + expect(handler).toHaveBeenCalledTimes(2); + expect(handler).toHaveBeenCalledWith(['init', { key: 'pk_123' }]); + expect(handler).toHaveBeenCalledWith(['identify', 'user-1']); + }); + + it('replays queued commands from the stub array', () => { + // Simulate the snippet having pushed commands before the script loaded + const stub: Command[] = [ + ['init', { key: 'pk_abc' }], + ['consent', 'anonymous'], + ]; + (window as Record).__imtbl = stub; + + const handler = jest.fn(); + createLoader(handler); + + expect(handler).toHaveBeenCalledTimes(2); + expect(handler).toHaveBeenNthCalledWith(1, ['init', { key: 'pk_abc' }]); + expect(handler).toHaveBeenNthCalledWith(2, ['consent', 'anonymous']); + }); + + it('replays queued commands then handles new pushes', () => { + (window as Record).__imtbl = [['init', { key: 'pk_1' }]]; + + const handler = jest.fn(); + const loader = createLoader(handler); + + // Queued command replayed + expect(handler).toHaveBeenCalledTimes(1); + + // New command via push + loader.push(['identify', 'user-2']); + expect(handler).toHaveBeenCalledTimes(2); + expect(handler).toHaveBeenLastCalledWith(['identify', 'user-2']); + }); + + it('handles empty window.__imtbl gracefully', () => { + (window as Record).__imtbl = []; + const handler = jest.fn(); + createLoader(handler); + expect(handler).not.toHaveBeenCalled(); + }); + + it('handles undefined window.__imtbl gracefully', () => { + const handler = jest.fn(); + createLoader(handler); + expect(handler).not.toHaveBeenCalled(); + }); + + it('supports multiple commands in a single push call', () => { + const handler = jest.fn(); + const loader = createLoader(handler); + + loader.push(['init', { key: 'pk_1' }], ['consent', 'full']); + expect(handler).toHaveBeenCalledTimes(2); + }); +}); diff --git a/packages/audience/pixel/src/loader.ts b/packages/audience/pixel/src/loader.ts new file mode 100644 index 0000000000..d85febb267 --- /dev/null +++ b/packages/audience/pixel/src/loader.ts @@ -0,0 +1,37 @@ +export type Command = [string, ...unknown[]]; + +export interface ImtblGlobal { + push: (...commands: Command[]) => void; + _loaded: boolean; +} + +type CommandHandler = (command: Command) => void; + +export function createLoader(handler: CommandHandler): ImtblGlobal { + const win = typeof window !== 'undefined' ? window : undefined; + const existing = win ? (win as unknown as Record).__imtbl : undefined; + + // Replay any commands that were queued before the script loaded + const queued: Command[] = Array.isArray(existing) ? (existing as Command[]) : []; + + const loader: ImtblGlobal = { + push: (...commands: Command[]) => { + for (const cmd of commands) { + handler(cmd); + } + }, + _loaded: true, + }; + + // Install on window + if (win) { + (win as unknown as Record).__imtbl = loader; + } + + // Replay queued commands in order + for (const cmd of queued) { + handler(cmd); + } + + return loader; +} diff --git a/packages/audience/pixel/src/snippet.test.ts b/packages/audience/pixel/src/snippet.test.ts new file mode 100644 index 0000000000..efef6c254d --- /dev/null +++ b/packages/audience/pixel/src/snippet.test.ts @@ -0,0 +1,48 @@ +import { generateSnippet } from './snippet'; + +describe('generateSnippet', () => { + it('generates a script tag with the default CDN URL', () => { + const html = generateSnippet({ key: 'pk_test_123' }); + + expect(html).toContain(''); + expect(html).toContain('https://cdn.immutable.com/pixel/v1/imtbl.js'); + expect(html).toContain('"key":"pk_test_123"'); + }); + + it('uses a custom CDN URL when provided', () => { + const html = generateSnippet({ + key: 'pk_test_123', + cdnUrl: 'https://cdn.dev.immutable.com/pixel/v1/imtbl.js', + }); + + expect(html).toContain('https://cdn.dev.immutable.com/pixel/v1/imtbl.js'); + expect(html).not.toContain('https://cdn.immutable.com/pixel/v1/imtbl.js'); + }); + + it('includes consent level when provided', () => { + const html = generateSnippet({ key: 'pk_test_123', consent: 'anonymous' }); + + expect(html).toContain('"consent":"anonymous"'); + }); + + it('omits consent from init args when not provided', () => { + const html = generateSnippet({ key: 'pk_test_123' }); + + expect(html).not.toContain('consent'); + }); + + it('creates the __imtbl stub array and pushes init command', () => { + const html = generateSnippet({ key: 'pk_test_123' }); + + expect(html).toContain('w[i]=w[i]||[]'); + expect(html).toContain('w[i].push(["init"'); + }); + + it('loads the script asynchronously', () => { + const html = generateSnippet({ key: 'pk_test_123' }); + + expect(html).toContain('s.async=1'); + expect(html).toContain('document.head.appendChild(s)'); + }); +}); diff --git a/packages/audience/pixel/src/snippet.ts b/packages/audience/pixel/src/snippet.ts new file mode 100644 index 0000000000..ef5c7d59bb --- /dev/null +++ b/packages/audience/pixel/src/snippet.ts @@ -0,0 +1,29 @@ +const DEFAULT_CDN_URL = 'https://cdn.immutable.com/pixel/v1/imtbl.js'; + +export interface SnippetOptions { + key: string; + cdnUrl?: string; + consent?: 'none' | 'anonymous' | 'full'; +} + +export function generateSnippet(options: SnippetOptions): string { + const { key, cdnUrl = DEFAULT_CDN_URL, consent } = options; + + const initArgs: Record = { key }; + if (consent) { + initArgs.consent = consent; + } + + const argsJson = JSON.stringify(initArgs); + + return [ + '', + ].join(''); +} diff --git a/packages/audience/pixel/tsconfig.eslint.json b/packages/audience/pixel/tsconfig.eslint.json new file mode 100644 index 0000000000..7a70f2c77d --- /dev/null +++ b/packages/audience/pixel/tsconfig.eslint.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "include": ["src"], + "exclude": [] +} diff --git a/packages/audience/pixel/tsconfig.json b/packages/audience/pixel/tsconfig.json new file mode 100644 index 0000000000..4840acb09d --- /dev/null +++ b/packages/audience/pixel/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./dist", + "rootDirs": ["src"], + "customConditions": ["development"] + }, + "include": ["src"], + "exclude": ["dist", "node_modules", "src/**/*.test.ts"] +} diff --git a/packages/audience/pixel/tsup.config.ts b/packages/audience/pixel/tsup.config.ts new file mode 100644 index 0000000000..9c12136721 --- /dev/null +++ b/packages/audience/pixel/tsup.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from 'tsup'; + +export default defineConfig({ + entry: ['src/index.ts'], + outDir: 'dist', + format: ['iife'], + globalName: '__imtblPixelInternal', + platform: 'browser', + target: 'es2020', + minify: true, + treeshake: true, + splitting: false, + sourcemap: false, + clean: true, + outExtension: () => ({ js: '.js' }), + esbuildOptions(options) { + options.outbase = 'src'; + options.entryNames = 'imtbl'; + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 355af06fa5..eb5d3d6e77 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -138,7 +138,7 @@ importers: version: 0.25.21(@emotion/react@11.11.3(@types/react@18.3.12)(react@18.3.1))(@rive-app/react-canvas-lite@4.9.0(react@18.3.1))(embla-carousel-react@8.1.5(react@18.3.1))(framer-motion@11.18.2(@emotion/is-prop-valid@0.8.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@imtbl/sdk': specifier: latest - version: 2.12.6(bufferutil@4.0.8)(typescript@5.6.2)(utf-8-validate@5.0.10) + version: 2.12.6(typescript@5.6.2) next: specifier: 14.2.25 version: 14.2.25(@babel/core@7.26.10)(@playwright/test@1.45.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -951,6 +951,33 @@ importers: specifier: ^5.6.2 version: 5.6.2 + packages/audience/pixel: + devDependencies: + '@swc/core': + specifier: ^1.4.2 + version: 1.15.3(@swc/helpers@0.5.15) + '@swc/jest': + specifier: ^0.2.37 + version: 0.2.37(@swc/core@1.15.3(@swc/helpers@0.5.15)) + '@types/jest': + specifier: ^29.5.12 + version: 29.5.14 + eslint: + specifier: ^8.56.0 + version: 8.57.0 + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@22.19.7)(babel-plugin-macros@3.1.0)(node-notifier@8.0.2) + jest-environment-jsdom: + specifier: ^29.4.3 + version: 29.6.1(bufferutil@4.0.8)(utf-8-validate@5.0.10) + tsup: + specifier: ^8.3.0 + version: 8.3.0(@swc/core@1.15.3(@swc/helpers@0.5.15))(jiti@1.21.0)(postcss@8.4.49)(typescript@5.6.2)(yaml@2.5.0) + typescript: + specifier: ^5.6.2 + version: 5.6.2 + packages/auth: dependencies: '@imtbl/generated-clients': @@ -19172,7 +19199,7 @@ snapshots: '@confio/ics23@0.6.8': dependencies: - '@noble/hashes': 1.5.0 + '@noble/hashes': 1.8.0 protobufjs: 6.11.4 '@cosmjs/amino@0.31.3': @@ -19211,7 +19238,7 @@ snapshots: '@cosmjs/encoding': 0.31.3 '@cosmjs/math': 0.31.3 '@cosmjs/utils': 0.31.3 - '@noble/hashes': 1.5.0 + '@noble/hashes': 1.8.0 bn.js: 5.2.1 elliptic: 6.6.1 libsodium-wrappers-sumo: 0.7.15 @@ -19221,7 +19248,7 @@ snapshots: '@cosmjs/encoding': 0.32.4 '@cosmjs/math': 0.32.4 '@cosmjs/utils': 0.32.4 - '@noble/hashes': 1.5.0 + '@noble/hashes': 1.8.0 bn.js: 5.2.1 elliptic: 6.6.1 libsodium-wrappers-sumo: 0.7.15 @@ -19490,11 +19517,11 @@ snapshots: '@emnapi/core@1.2.0': dependencies: '@emnapi/wasi-threads': 1.0.1 - tslib: 2.7.0 + tslib: 2.8.1 '@emnapi/runtime@1.2.0': dependencies: - tslib: 2.7.0 + tslib: 2.8.1 '@emnapi/runtime@1.8.1': dependencies: @@ -19503,7 +19530,7 @@ snapshots: '@emnapi/wasi-threads@1.0.1': dependencies: - tslib: 2.7.0 + tslib: 2.8.1 '@emotion/babel-plugin@11.11.0': dependencies: @@ -20231,7 +20258,7 @@ snapshots: transitivePeerDependencies: - debug - '@imtbl/bridge-sdk@2.12.6(bufferutil@4.0.8)(utf-8-validate@5.0.10)': + '@imtbl/bridge-sdk@2.12.6': dependencies: '@imtbl/config': 2.12.6 '@jest/globals': 29.7.0 @@ -20243,16 +20270,16 @@ snapshots: - supports-color - utf-8-validate - '@imtbl/checkout-sdk@2.12.6(bufferutil@4.0.8)(typescript@5.6.2)(utf-8-validate@5.0.10)': + '@imtbl/checkout-sdk@2.12.6(typescript@5.6.2)': dependencies: '@imtbl/blockchain-data': 2.12.6 - '@imtbl/bridge-sdk': 2.12.6(bufferutil@4.0.8)(utf-8-validate@5.0.10) + '@imtbl/bridge-sdk': 2.12.6 '@imtbl/config': 2.12.6 - '@imtbl/dex-sdk': 2.12.6(bufferutil@4.0.8)(utf-8-validate@5.0.10) + '@imtbl/dex-sdk': 2.12.6 '@imtbl/generated-clients': 2.12.6 '@imtbl/metrics': 2.12.6 - '@imtbl/orderbook': 2.12.6(bufferutil@4.0.8)(utf-8-validate@5.0.10) - '@imtbl/passport': 2.12.6(bufferutil@4.0.8)(typescript@5.6.2)(utf-8-validate@5.0.10) + '@imtbl/orderbook': 2.12.6 + '@imtbl/passport': 2.12.6(typescript@5.6.2) '@metamask/detect-provider': 2.0.0 axios: 1.7.7 ethers: 6.13.5(bufferutil@4.0.8)(utf-8-validate@5.0.10) @@ -20314,7 +20341,7 @@ snapshots: - typescript - utf-8-validate - '@imtbl/dex-sdk@2.12.6(bufferutil@4.0.8)(utf-8-validate@5.0.10)': + '@imtbl/dex-sdk@2.12.6': dependencies: '@imtbl/config': 2.12.6 '@uniswap/sdk-core': 3.2.3 @@ -20356,7 +20383,7 @@ snapshots: - debug - pg-native - '@imtbl/orderbook@2.12.6(bufferutil@4.0.8)(utf-8-validate@5.0.10)': + '@imtbl/orderbook@2.12.6': dependencies: '@imtbl/config': 2.12.6 '@imtbl/metrics': 2.12.6 @@ -20370,16 +20397,16 @@ snapshots: - debug - utf-8-validate - '@imtbl/passport@2.12.6(bufferutil@4.0.8)(typescript@5.6.2)(utf-8-validate@5.0.10)': + '@imtbl/passport@2.12.6(typescript@5.6.2)': dependencies: '@imtbl/auth': 2.12.6 '@imtbl/config': 2.12.6 '@imtbl/generated-clients': 2.12.6 '@imtbl/metrics': 2.12.6 - '@imtbl/toolkit': 2.12.6(bufferutil@4.0.8)(utf-8-validate@5.0.10) - '@imtbl/wallet': 2.12.6(bufferutil@4.0.8)(typescript@5.6.2)(utf-8-validate@5.0.10) - '@imtbl/x-client': 2.12.6(bufferutil@4.0.8)(utf-8-validate@5.0.10) - '@imtbl/x-provider': 2.12.6(bufferutil@4.0.8)(utf-8-validate@5.0.10) + '@imtbl/toolkit': 2.12.6 + '@imtbl/wallet': 2.12.6(typescript@5.6.2) + '@imtbl/x-client': 2.12.6 + '@imtbl/x-provider': 2.12.6 ethers: 6.13.5(bufferutil@4.0.8)(utf-8-validate@5.0.10) localforage: 1.10.0 oidc-client-ts: 3.4.1 @@ -20398,19 +20425,19 @@ snapshots: - encoding - supports-color - '@imtbl/sdk@2.12.6(bufferutil@4.0.8)(typescript@5.6.2)(utf-8-validate@5.0.10)': + '@imtbl/sdk@2.12.6(typescript@5.6.2)': dependencies: '@imtbl/auth': 2.12.6 '@imtbl/blockchain-data': 2.12.6 - '@imtbl/checkout-sdk': 2.12.6(bufferutil@4.0.8)(typescript@5.6.2)(utf-8-validate@5.0.10) + '@imtbl/checkout-sdk': 2.12.6(typescript@5.6.2) '@imtbl/config': 2.12.6 '@imtbl/minting-backend': 2.12.6 - '@imtbl/orderbook': 2.12.6(bufferutil@4.0.8)(utf-8-validate@5.0.10) - '@imtbl/passport': 2.12.6(bufferutil@4.0.8)(typescript@5.6.2)(utf-8-validate@5.0.10) - '@imtbl/wallet': 2.12.6(bufferutil@4.0.8)(typescript@5.6.2)(utf-8-validate@5.0.10) + '@imtbl/orderbook': 2.12.6 + '@imtbl/passport': 2.12.6(typescript@5.6.2) + '@imtbl/wallet': 2.12.6(typescript@5.6.2) '@imtbl/webhook': 2.12.6 - '@imtbl/x-client': 2.12.6(bufferutil@4.0.8)(utf-8-validate@5.0.10) - '@imtbl/x-provider': 2.12.6(bufferutil@4.0.8)(utf-8-validate@5.0.10) + '@imtbl/x-client': 2.12.6 + '@imtbl/x-provider': 2.12.6 transitivePeerDependencies: - bufferutil - debug @@ -20421,9 +20448,9 @@ snapshots: - utf-8-validate - zod - '@imtbl/toolkit@2.12.6(bufferutil@4.0.8)(utf-8-validate@5.0.10)': + '@imtbl/toolkit@2.12.6': dependencies: - '@imtbl/x-client': 2.12.6(bufferutil@4.0.8)(utf-8-validate@5.0.10) + '@imtbl/x-client': 2.12.6 '@metamask/detect-provider': 2.0.0 axios: 1.7.7 bn.js: 5.2.1 @@ -20435,7 +20462,7 @@ snapshots: - debug - utf-8-validate - '@imtbl/wallet@2.12.6(bufferutil@4.0.8)(typescript@5.6.2)(utf-8-validate@5.0.10)': + '@imtbl/wallet@2.12.6(typescript@5.6.2)': dependencies: '@imtbl/auth': 2.12.6 '@imtbl/generated-clients': 2.12.6 @@ -20456,7 +20483,7 @@ snapshots: transitivePeerDependencies: - debug - '@imtbl/x-client@2.12.6(bufferutil@4.0.8)(utf-8-validate@5.0.10)': + '@imtbl/x-client@2.12.6': dependencies: '@ethereumjs/wallet': 2.0.4 '@imtbl/config': 2.12.6 @@ -20472,12 +20499,12 @@ snapshots: - debug - utf-8-validate - '@imtbl/x-provider@2.12.6(bufferutil@4.0.8)(utf-8-validate@5.0.10)': + '@imtbl/x-provider@2.12.6': dependencies: '@imtbl/config': 2.12.6 '@imtbl/generated-clients': 2.12.6 - '@imtbl/toolkit': 2.12.6(bufferutil@4.0.8)(utf-8-validate@5.0.10) - '@imtbl/x-client': 2.12.6(bufferutil@4.0.8)(utf-8-validate@5.0.10) + '@imtbl/toolkit': 2.12.6 + '@imtbl/x-client': 2.12.6 '@metamask/detect-provider': 2.0.0 axios: 1.7.7 enc-utils: 3.0.0 @@ -21292,7 +21319,7 @@ snapshots: '@ethereumjs/tx': 4.2.0 '@metamask/superstruct': 3.1.0 '@noble/hashes': 1.8.0 - '@scure/base': 1.1.7 + '@scure/base': 1.2.6 '@types/debug': 4.1.8 debug: 4.3.7(supports-color@8.1.1) pony-cause: 2.1.11 @@ -21306,7 +21333,7 @@ snapshots: '@ethereumjs/tx': 4.2.0 '@metamask/superstruct': 3.1.0 '@noble/hashes': 1.8.0 - '@scure/base': 1.1.7 + '@scure/base': 1.2.6 '@types/debug': 4.1.8 debug: 4.3.7(supports-color@8.1.1) pony-cause: 2.1.11 @@ -21337,7 +21364,7 @@ snapshots: '@motionone/easing': 10.17.0 '@motionone/types': 10.17.0 '@motionone/utils': 10.17.0 - tslib: 2.7.0 + tslib: 2.8.1 '@motionone/dom@10.17.0': dependencies: @@ -21346,23 +21373,23 @@ snapshots: '@motionone/types': 10.17.0 '@motionone/utils': 10.17.0 hey-listen: 1.0.8 - tslib: 2.7.0 + tslib: 2.8.1 '@motionone/easing@10.17.0': dependencies: '@motionone/utils': 10.17.0 - tslib: 2.7.0 + tslib: 2.8.1 '@motionone/generators@10.17.0': dependencies: '@motionone/types': 10.17.0 '@motionone/utils': 10.17.0 - tslib: 2.7.0 + tslib: 2.8.1 '@motionone/svelte@10.16.4': dependencies: '@motionone/dom': 10.17.0 - tslib: 2.7.0 + tslib: 2.8.1 '@motionone/types@10.17.0': {} @@ -21370,12 +21397,12 @@ snapshots: dependencies: '@motionone/types': 10.17.0 hey-listen: 1.0.8 - tslib: 2.7.0 + tslib: 2.8.1 '@motionone/vue@10.16.4': dependencies: '@motionone/dom': 10.17.0 - tslib: 2.7.0 + tslib: 2.8.1 '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.2': optional: true @@ -22620,7 +22647,7 @@ snapshots: is-glob: 4.0.3 open: 9.1.0 picocolors: 1.1.1 - tslib: 2.7.0 + tslib: 2.8.1 '@playwright/test@1.45.3': dependencies: @@ -24357,7 +24384,7 @@ snapshots: '@swc/helpers@0.5.13': dependencies: - tslib: 2.7.0 + tslib: 2.8.1 '@swc/helpers@0.5.15': dependencies: @@ -24473,7 +24500,7 @@ snapshots: '@tybys/wasm-util@0.9.0': dependencies: - tslib: 2.7.0 + tslib: 2.8.1 '@typechain/ethers-v6@0.5.1(ethers@6.13.5(bufferutil@4.0.8)(utf-8-validate@5.0.10))(typechain@8.3.0(typescript@5.6.2))(typescript@5.6.2)': dependencies: @@ -26670,7 +26697,7 @@ snapshots: camel-case@4.1.2: dependencies: pascal-case: 3.1.2 - tslib: 2.7.0 + tslib: 2.8.1 camelcase-css@2.0.1: {} @@ -27786,7 +27813,7 @@ snapshots: dot-case@3.0.4: dependencies: no-case: 3.0.4 - tslib: 2.7.0 + tslib: 2.8.1 dotenv-expand@11.0.6: dependencies: @@ -33131,7 +33158,7 @@ snapshots: no-case@3.0.4: dependencies: lower-case: 2.0.2 - tslib: 2.7.0 + tslib: 2.8.1 nocache@3.0.4: {} @@ -33670,7 +33697,7 @@ snapshots: param-case@3.0.4: dependencies: dot-case: 3.0.4 - tslib: 2.7.0 + tslib: 2.8.1 parcel@2.16.3(@swc/helpers@0.5.15): dependencies: @@ -33730,7 +33757,7 @@ snapshots: pascal-case@3.1.2: dependencies: no-case: 3.0.4 - tslib: 2.7.0 + tslib: 2.8.1 pascalcase@0.1.1: {} @@ -35863,7 +35890,7 @@ snapshots: snake-case@3.0.4: dependencies: dot-case: 3.0.4 - tslib: 2.7.0 + tslib: 2.8.1 snapdragon-node@2.1.1: dependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index a225720a64..e0c84db642 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -22,6 +22,7 @@ packages: - "packages/checkout/widgets-lib" - "packages/blockchain-data/sdk" - "packages/audience/core" + - "packages/audience/pixel" - "packages/game-bridge" - "packages/webhook/sdk" - "packages/minting-backend/sdk"