elysium-attribution 0.0.0-stage → 1.0.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/README.md CHANGED
@@ -1,3 +1,365 @@
1
- # Temporary Holding Version
1
+ # ElysiumSDK
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Production-grade JavaScript/TypeScript SDK for global multi-touch marketing attribution, visitor session tracking, and payment gateway integration across any web application or e-commerce storefront.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+ 1. [Architecture Overview](#architecture-overview)
9
+ 2. [Existing Touch Tracking Analysis & Fixes](#existing-touch-tracking-analysis--fixes)
10
+ 3. [Installation](#installation)
11
+ 4. [Configuration (`elysium.config.js`)](#configuration)
12
+ 5. [Quick Start](#quick-start)
13
+ 6. [Payment Gateway Integrations](#payment-gateway-integrations)
14
+ - [Stripe](#stripe)
15
+ - [Razorpay](#razorpay)
16
+ - [PayPal](#paypal)
17
+ - [Custom Gateways](#custom-gateways)
18
+ 7. [Payment Button Detection](#payment-button-detection)
19
+ 8. [Backend Integration & Limitations](#backend-integration--limitations)
20
+ 9. [API Reference](#api-reference)
21
+
22
+ ---
23
+
24
+ ## 1. Architecture Overview
25
+
26
+ ElysiumSDK is structured with strict separation of concerns, framework independence, and zero external runtime dependencies:
27
+
28
+ ```
29
+ elysiumSDK/
30
+ ├── src/
31
+ │ ├── index.js # Unified SDK interface (window.Elysium & ES module exports)
32
+ │ ├── config/
33
+ │ │ ├── index.js # Configuration manager & dynamic updates
34
+ │ │ └── schema.js # Defaults & client-side secret-key detection / audit
35
+ │ ├── tracking/
36
+ │ │ ├── visitor.js # Visitor UUID generator with localStorage + Cookie 2-way sync
37
+ │ │ ├── params.js # Multi-platform click IDs (gclid, fbclid, wbraid, ttclid, etc.)
38
+ │ │ ├── referrer.js # Internal referrer filtering & organic search/social detection
39
+ │ │ ├── session.js # 30-min session windowing, touch deduplication, FIFO bounding
40
+ │ │ ├── transport.js # Resilient HTTP fetch (keepalive, timeouts, dual headers)
41
+ │ │ └── touchTracker.js # Core orchestrator: recordTouch, identifyVisitor, createCheckoutSession
42
+ │ ├── gateways/
43
+ │ │ ├── PaymentGateway.js # Abstract base class with lifecycle hooks and event emitter
44
+ │ │ ├── GatewayRegistry.js # Registry for resolving & registering gateways
45
+ │ │ ├── StripeGateway.js # Stripe Elements, 3DS redirect return checks, PaymentIntent tracking
46
+ │ │ ├── RazorpayGateway.js # Razorpay options wrapping, handler interception, failure events
47
+ │ │ ├── PayPalGateway.js # PayPal JS SDK Buttons interception (createOrder, onApprove, onError)
48
+ │ │ └── GenericGateway.js # Fallback & custom provider support
49
+ │ ├── dom/
50
+ │ │ └── buttonDetector.js # Delegated click listener & MutationObserver for .elysium-payment-button
51
+ │ └── utils/
52
+ │ ├── storage.js # Resilient storage (in-memory fallback, ITP-aware cookie handling)
53
+ │ ├── logger.js # Safe prefixed logging with debug toggle
54
+ │ └── cli.js # CLI tool to initialize elysium.config.js
55
+ ├── test/ # Comprehensive unit tests (node:test)
56
+ ├── index.d.ts # Complete TypeScript definitions
57
+ └── package.json
58
+ ```
59
+
60
+ ---
61
+
62
+ ## 2. Existing Touch Tracking Analysis & Fixes
63
+
64
+ During the audit of `touch-tracking.ts` and `attributionInit.js`, the following critical flaws, security concerns, and edge cases were identified and resolved:
65
+
66
+ | Area | Issue in Original Code | Fixed in ElysiumSDK |
67
+ | :--- | :--- | :--- |
68
+ | **Bundler / Environment Lock-in** | Relied on `import.meta.env.VITE_ATTRIBUTION_*`, which crashed or failed in non-Vite environments, script tags, Webpack, Next.js, and vanilla HTML. | Framework-agnostic configuration via `elysium.config.js`, runtime options to `init()`, and safe global fallback. |
69
+ | **Storage Quota & Memory Leak** | `saveSuccessfulTouch` appended entries indefinitely to `localStorage['aid_touches']` without limits, eventually throwing `QuotaExceededError` on frequent visitors. | Capped history to a maximum of 50 records with automatic FIFO pruning. Added in-memory fallback for Private Browsing mode. |
70
+ | **Organic & Referral Traffic Loss** | `shouldSendTouch` checked only marketing parameters (`utm_` and `gclid/fbclid`). Visitors arriving via organic Google search, DuckDuckGo, Reddit, or Instagram were completely dropped from attribution. | Added `referrer.js` that detects organic search engines and social platforms, populating source/medium when UTMs are absent. |
71
+ | **Internal Navigation Misattribution** | `document.referrer` recorded internal site page-to-page navigation as external referrals, polluting attribution data. | Added domain-level internal referrer filtering that strips same-domain referrers. |
72
+ | **Modern Ad Click IDs Missing** | Only captured `gclid`, `fbclid`, `ttclid`, `msclkid`. Missed iOS privacy click IDs (`wbraid`, `gbraid`), Google Display (`dclid`), Twitter/X (`twclid`), LinkedIn (`li_fat_id`), and Reddit (`rdt_cid`). | Added comprehensive ad platform click ID capture and cookie sync (`_fbc`, `_fbp`, `_ttp`, `_ga`). |
73
+ | **Safari ITP / Cross-Domain Identity Loss** | Relied primarily on localStorage; cookies were only set as a fallback if localStorage failed, breaking cross-subdomain tracking (`shop.store.com` -> `checkout.store.com`). | Dual-writes to both `localStorage` and `SameSite=Lax` cookies with configurable `cookieDomain` to preserve visitor identity across subdomains and Safari ITP resets. |
74
+ | **Payment Button Assumption Flaw** | None existed in original code; clicks cannot be assumed as payment success. | Implemented separate `PaymentGateway` architecture treating clicks as payment *attempts*, and only recording *success* after provider verification or redirect resolution. |
75
+
76
+ ---
77
+
78
+ ## 3. Installation
79
+
80
+ Install via npm:
81
+
82
+ ```bash
83
+ npm install elysium-sdk
84
+ ```
85
+
86
+ Or via CDN script tag:
87
+
88
+ ```html
89
+ <script src="https://cdn.jsdelivr.net/npm/elysium-sdk/dist/elysium.min.js"></script>
90
+ ```
91
+
92
+ Initialize your configuration file:
93
+
94
+ ```bash
95
+ npx elysium
96
+ ```
97
+
98
+ ---
99
+
100
+ ## 4. Configuration (`elysium.config.js`)
101
+
102
+ Create or update `elysium.config.js` in your project root:
103
+
104
+ ```javascript
105
+ /**
106
+ * ElysiumSDK Configuration File
107
+ *
108
+ * IMPORTANT SECURITY NOTICE:
109
+ * This file is bundled for the browser. NEVER include backend secret keys
110
+ * (e.g. Stripe secret key "sk_live_...", Razorpay key secret).
111
+ */
112
+ export default {
113
+ // Public attribution API Key provided by Elysium
114
+ apiKey: "pk_test_b-ej3xXtpwZUdV6BJdu0NTlILFnMsfszkeiJPfQ9CL0",
115
+
116
+ // Attribution API Backend endpoint
117
+ apiBaseUrl: "https://asbTemp-production.up.railway.app",
118
+
119
+ // Enable verbose debugging logs in browser console
120
+ debug: true,
121
+
122
+ // Session inactivity timeout in milliseconds (default: 30 minutes)
123
+ sessionWindowMs: 30 * 60 * 1000,
124
+
125
+ // CSS selector or class for detecting checkout/payment buttons
126
+ buttonSelector: ".elysium-payment-button",
127
+
128
+ // Automatically record touch on page load
129
+ autoTrack: true,
130
+
131
+ // Optional: restrict touch tracking to specific path regex (e.g. product pages only)
132
+ // productPathRegex: /^\/product\/[^/]+\/?$/,
133
+
134
+ // Domain for cross-subdomain cookie tracking (e.g., ".yourstore.com")
135
+ cookieDomain: undefined,
136
+
137
+ // Additional custom query parameters to capture and attribute
138
+ customParams: ["affiliate_id", "promo_code"],
139
+
140
+ // Supported payment gateways configuration (PUBLIC keys only)
141
+ gateways: {
142
+ stripe: {
143
+ enabled: true,
144
+ publishableKey: "pk_test_...",
145
+ },
146
+ razorpay: {
147
+ enabled: true,
148
+ keyId: "rzp_test_...",
149
+ },
150
+ paypal: {
151
+ enabled: true,
152
+ clientId: "YOUR_PAYPAL_CLIENT_ID",
153
+ },
154
+ },
155
+ };
156
+ ```
157
+
158
+ ---
159
+
160
+ ## 5. Quick Start
161
+
162
+ ### In React / Next.js / Vue / Vanilla JS:
163
+
164
+ ```javascript
165
+ import Elysium from 'elysium-sdk';
166
+ import elysiumConfig from './elysium.config.js';
167
+
168
+ // Initialize on application startup
169
+ Elysium.init(elysiumConfig);
170
+
171
+ // Get current visitor ID
172
+ const visitorId = Elysium.getVisitorId();
173
+
174
+ // When customer logs in or submits their email in checkout:
175
+ await Elysium.identifyVisitor('customer@example.com', {
176
+ name: 'Jane Doe',
177
+ loyaltyTier: 'VIP'
178
+ });
179
+ ```
180
+
181
+ ---
182
+
183
+ ## 6. Payment Gateway Integrations
184
+
185
+ ### Stripe
186
+
187
+ The Stripe gateway supports:
188
+ 1. **Stripe Elements (`stripe.confirmPayment`)**: Automatic promise interception
189
+ 2. **Redirect Returns**: Automatically detects `?payment_intent=pi_...&redirect_status=succeeded` when customers return from 3D Secure or Stripe Checkout.
190
+
191
+ ```javascript
192
+ import Elysium from 'elysium-sdk';
193
+
194
+ const stripeGateway = Elysium.getGateway('stripe');
195
+
196
+ // Instrument Stripe instance
197
+ const stripe = stripeGateway.wrapStripe(window.Stripe('pk_test_...'));
198
+
199
+ // Call confirmPayment normally - Elysium automatically records attempt and verified success!
200
+ const { error } = await stripe.confirmPayment({
201
+ elements,
202
+ confirmParams: {
203
+ return_url: 'https://mystore.com/order-confirmation',
204
+ },
205
+ });
206
+ ```
207
+
208
+ ### Razorpay
209
+
210
+ Wrap your Razorpay checkout options. Elysium automatically hooks into the `handler` callback and listens for `payment.failed` events:
211
+
212
+ ```javascript
213
+ import Elysium from 'elysium-sdk';
214
+
215
+ const rzpGateway = Elysium.getGateway('razorpay');
216
+
217
+ const options = rzpGateway.wrapOptions({
218
+ key: 'rzp_test_...',
219
+ amount: 50000,
220
+ currency: 'INR',
221
+ name: 'Acme Store',
222
+ order_id: 'order_123',
223
+ handler: function (response) {
224
+ // response.razorpay_payment_id
225
+ // response.razorpay_order_id
226
+ // response.razorpay_signature
227
+ console.log('Payment completed!');
228
+ },
229
+ });
230
+
231
+ const rzp = new window.Razorpay(options);
232
+ rzpGateway.wrapInstance(rzp); // Attaches failure telemetry
233
+ rzp.open();
234
+ ```
235
+
236
+ ### PayPal
237
+
238
+ Wrap your PayPal JavaScript SDK Button options:
239
+
240
+ ```javascript
241
+ import Elysium from 'elysium-sdk';
242
+
243
+ const paypalGateway = Elysium.getGateway('paypal');
244
+
245
+ window.paypal.Buttons(paypalGateway.wrapButtons({
246
+ createOrder: (data, actions) => {
247
+ return actions.order.create({
248
+ purchase_units: [{ amount: { value: '149.00' } }]
249
+ });
250
+ },
251
+ onApprove: async (data, actions) => {
252
+ const details = await actions.order.capture();
253
+ console.log('PayPal transaction completed:', details);
254
+ }
255
+ })).render('#paypal-button-container');
256
+ ```
257
+
258
+ ### Custom Gateways
259
+
260
+ You can implement custom payment gateways by extending `PaymentGateway`:
261
+
262
+ ```javascript
263
+ import { PaymentGateway, registerGateway } from 'elysium-sdk';
264
+
265
+ class CryptoPaymentGateway extends PaymentGateway {
266
+ constructor() {
267
+ super('crypto');
268
+ }
269
+
270
+ canHandle(buttonOrContext) {
271
+ return buttonOrContext.dataset?.gateway === 'crypto';
272
+ }
273
+
274
+ async handleButtonClick(button, context) {
275
+ await this.recordPaymentAttempt({ cryptoCurrency: 'ETH', ...context });
276
+ }
277
+ }
278
+
279
+ registerGateway('crypto', new CryptoPaymentGateway());
280
+ ```
281
+
282
+ ---
283
+
284
+ ## 7. Payment Button Detection
285
+
286
+ Elysium automatically detects interactions with payment and checkout buttons using a lightweight, delegated event listener and `MutationObserver` (supporting React hydration, Vue, and dynamically rendered buttons).
287
+
288
+ Simply add the configured CSS class (default `elysium-payment-button`) and optional `data-gateway` attributes:
289
+
290
+ ```html
291
+ <!-- Stripe Checkout Button -->
292
+ <button
293
+ class="elysium-payment-button"
294
+ data-gateway="stripe"
295
+ data-amount="149.00"
296
+ data-currency="USD"
297
+ >
298
+ Pay with Card (Stripe)
299
+ </button>
300
+
301
+ <!-- Razorpay Button -->
302
+ <button
303
+ class="elysium-payment-button"
304
+ data-gateway="razorpay"
305
+ data-amount="149.00"
306
+ data-currency="USD"
307
+ >
308
+ Pay with UPI / Cards (Razorpay)
309
+ </button>
310
+
311
+ <!-- PayPal Button -->
312
+ <button
313
+ class="elysium-payment-button"
314
+ data-gateway="paypal"
315
+ >
316
+ PayPal Express Checkout
317
+ </button>
318
+ ```
319
+
320
+ ### Lifecycle Events Dispatched
321
+
322
+ | Event Name | Description | Detail Object |
323
+ | :--- | :--- | :--- |
324
+ | `elysium:touch_recorded` | Fired when a page touch is transmitted and accepted | `{ payload, response }` |
325
+ | `elysium:button_detected` | Fired when a payment button is observed in DOM | `{ button }` |
326
+ | `elysium:payment_attempt` | Fired when user clicks payment button (intent only) | `{ gateway, button, context }` |
327
+ | `elysium:payment_success` | Fired when payment is confirmed by gateway | `{ gateway, transactionId, amount, ... }` |
328
+ | `elysium:payment_failure` | Fired on checkout cancellation or card decline | `{ gateway, errorCode, errorMessage }` |
329
+
330
+ ---
331
+
332
+ ## 8. Backend Integration & Limitations
333
+
334
+ ### Critical Security Rule: Secret Keys on Backend
335
+ Client-side code operates in an untrusted environment. Only publishable API keys may be used in `elysium.config.js`. Secret keys (e.g., Stripe `sk_live_...`, Razorpay `key_secret`) must **NEVER** be placed in frontend code.
336
+
337
+ ### Backend Verification via Webhooks
338
+ While the client-side SDK captures visitor IDs, checkout sessions, and browser-confirmed transactions, **authoritative payment attribution must be validated via server-side webhooks**:
339
+
340
+ 1. **Checkout Session Creation**:
341
+ The frontend calls `Elysium.createCheckoutSession()` before starting payment to get an attribution token.
342
+ 2. **Metadata Attachment**:
343
+ Attach the `checkoutSessionId` and `visitorId` to the gateway's metadata:
344
+ - Stripe: `payment_intent_data.metadata: { elysium_session_id: session.checkoutSessionId, elysium_visitor_id: session.visitorId }`
345
+ - Razorpay: `notes: { elysium_session_id: session.checkoutSessionId }`
346
+ - PayPal: `custom_id: session.checkoutSessionId`
347
+ 3. **Backend Webhook Handler**:
348
+ When receiving `payment_intent.succeeded` (Stripe) or `order.paid` (Razorpay), your backend verifies the cryptographic webhook signature, extracts the `elysium_session_id`, and informs the Elysium Attribution API to lock in the conversion.
349
+
350
+ ---
351
+
352
+ ## 9. API Reference
353
+
354
+ - `Elysium.init(config)`: Initializes tracking, button observers, and gateways.
355
+ - `Elysium.configure(updates)`: Updates configuration dynamically at runtime.
356
+ - `Elysium.getVisitorId()`: Returns active visitor ID.
357
+ - `Elysium.setVisitorId(id)`: Overrides active visitor ID.
358
+ - `Elysium.recordTouch(options)`: Explicitly sends a touchpoint.
359
+ - `Elysium.recordProductTouch()`: Preserved backward-compatible product touch tracking.
360
+ - `Elysium.identifyVisitor(email, traits)`: Links visitor ID to a customer profile.
361
+ - `Elysium.createCheckoutSession()`: Obtains checkout attribution token.
362
+ - `Elysium.recordPaymentSuccess(details)`: Records verified payment.
363
+ - `Elysium.recordPaymentFailure(details)`: Records payment failure or cancellation.
364
+ - `Elysium.registerGateway(name, instance)`: Registers custom payment gateway.
365
+ - `Elysium.getGateway(name)`: Retrieves gateway by name.
package/index.d.ts ADDED
@@ -0,0 +1,213 @@
1
+ /**
2
+ * ElysiumSDK TypeScript Definitions
3
+ */
4
+
5
+ export interface ElysiumGatewayConfig {
6
+ enabled?: boolean;
7
+ publishableKey?: string;
8
+ keyId?: string;
9
+ clientId?: string;
10
+ [key: string]: unknown;
11
+ }
12
+
13
+ export interface ElysiumConfig {
14
+ /** Elysium Public API Key */
15
+ apiKey: string;
16
+ /** Elysium Backend API URL (default: https://asbTemp-production.up.railway.app) */
17
+ apiBaseUrl?: string;
18
+ /** Enable verbose console debug logs */
19
+ debug?: boolean;
20
+ /** Session timeout window in milliseconds (default: 30 minutes) */
21
+ sessionWindowMs?: number;
22
+ /** CSS selector for payment buttons (default: .elysium-payment-button) */
23
+ buttonSelector?: string;
24
+ /** Automatically track touch on initialization (default: true) */
25
+ autoTrack?: boolean;
26
+ /** Optional RegExp to filter paths for touch tracking (e.g. product pages only) */
27
+ productPathRegex?: RegExp | string | null;
28
+ /** Cookie domain for cross-subdomain tracking (e.g. .example.com) */
29
+ cookieDomain?: string;
30
+ /** Additional custom query parameters to track */
31
+ customParams?: string[];
32
+ /** Supported payment gateway options */
33
+ gateways?: {
34
+ stripe?: ElysiumGatewayConfig;
35
+ razorpay?: ElysiumGatewayConfig;
36
+ paypal?: ElysiumGatewayConfig;
37
+ [key: string]: ElysiumGatewayConfig | undefined;
38
+ };
39
+ }
40
+
41
+ export interface TouchPayload {
42
+ visitorId: string;
43
+ touchedAt: string;
44
+ source: string | null;
45
+ medium: string | null;
46
+ campaign: string | null;
47
+ term: string | null;
48
+ content: string | null;
49
+ referrer: string | null;
50
+ landingPage: string;
51
+ pageTitle: string;
52
+ channel?: string;
53
+ gclid?: string | null;
54
+ dclid?: string | null;
55
+ wbraid?: string | null;
56
+ gbraid?: string | null;
57
+ srsltid?: string | null;
58
+ fbclid?: string | null;
59
+ ttclid?: string | null;
60
+ msclkid?: string | null;
61
+ twclid?: string | null;
62
+ li_fat_id?: string | null;
63
+ rdt_cid?: string | null;
64
+ fbc?: string | null;
65
+ fbp?: string | null;
66
+ ttp?: string | null;
67
+ ga?: string | null;
68
+ custom?: Record<string, unknown>;
69
+ }
70
+
71
+ export interface TouchResponse {
72
+ id: string;
73
+ visitorId: string;
74
+ channel: string;
75
+ touchedAt: string;
76
+ [key: string]: unknown;
77
+ }
78
+
79
+ export interface StoredTouch {
80
+ payload: TouchPayload;
81
+ response: TouchResponse;
82
+ recordedAt: number;
83
+ }
84
+
85
+ export interface CheckoutSession {
86
+ checkoutSessionId: string;
87
+ token: string;
88
+ visitorId: string;
89
+ visitorRecordId: string;
90
+ touchIds: string[];
91
+ touchCount: number;
92
+ expiresAt: string;
93
+ }
94
+
95
+ export interface PaymentAttemptDetails {
96
+ gateway?: string;
97
+ buttonId?: string | null;
98
+ buttonClass?: string | null;
99
+ buttonText?: string | null;
100
+ amount?: number | null;
101
+ currency?: string | null;
102
+ productId?: string | null;
103
+ [key: string]: unknown;
104
+ }
105
+
106
+ export interface PaymentSuccessDetails {
107
+ gateway?: string;
108
+ transactionId?: string | null;
109
+ orderId?: string | null;
110
+ amount?: number | null;
111
+ currency?: string | null;
112
+ signature?: string | null;
113
+ [key: string]: unknown;
114
+ }
115
+
116
+ export interface PaymentFailureDetails {
117
+ gateway?: string;
118
+ code?: string | null;
119
+ message?: string | null;
120
+ [key: string]: unknown;
121
+ }
122
+
123
+ export abstract class PaymentGateway {
124
+ name: string;
125
+ config: ElysiumGatewayConfig;
126
+ constructor(name: string, config?: ElysiumGatewayConfig);
127
+ init(config?: ElysiumGatewayConfig): void;
128
+ canHandle(buttonOrContext: HTMLElement | Record<string, unknown>): boolean;
129
+ handleButtonClick(button: HTMLElement | null, context?: Record<string, unknown>): Promise<unknown>;
130
+ recordPaymentAttempt(details?: PaymentAttemptDetails): Promise<unknown>;
131
+ recordPaymentSuccess(paymentData?: PaymentSuccessDetails): Promise<unknown>;
132
+ recordPaymentFailure(errorData?: PaymentFailureDetails): Promise<unknown>;
133
+ on(event: 'attempt' | 'success' | 'failure', callback: (data: unknown) => void): () => void;
134
+ }
135
+
136
+ export class StripeGateway extends PaymentGateway {
137
+ constructor(config?: ElysiumGatewayConfig);
138
+ checkRedirectReturn(): void;
139
+ wrapStripe<T>(stripeInstance: T): T;
140
+ }
141
+
142
+ export class RazorpayGateway extends PaymentGateway {
143
+ constructor(config?: ElysiumGatewayConfig);
144
+ wrapOptions<T extends Record<string, unknown>>(options: T): T;
145
+ wrapInstance<T>(rzpInstance: T): T;
146
+ }
147
+
148
+ export class PayPalGateway extends PaymentGateway {
149
+ constructor(config?: ElysiumGatewayConfig);
150
+ wrapButtons<T extends Record<string, unknown>>(options: T): T;
151
+ }
152
+
153
+ export class GenericGateway extends PaymentGateway {
154
+ constructor(name?: string, config?: ElysiumGatewayConfig);
155
+ }
156
+
157
+ export class GatewayRegistry {
158
+ register(name: string, gatewayInstance: PaymentGateway): PaymentGateway;
159
+ get(name: string): PaymentGateway | null;
160
+ getAll(): PaymentGateway[];
161
+ resolveForButton(buttonElement: HTMLElement | null): PaymentGateway;
162
+ configureAll(gatewaysConfig?: Record<string, ElysiumGatewayConfig>): void;
163
+ }
164
+
165
+ export function init(config?: Partial<ElysiumConfig>): typeof Elysium;
166
+ export function configure(updates?: Partial<ElysiumConfig>): ElysiumConfig;
167
+ export function getConfig(): ElysiumConfig;
168
+ export function getVisitorId(): string;
169
+ export function setVisitorId(newId: string): void;
170
+ export function recordTouch(options?: { force?: boolean; customData?: Record<string, unknown> }): Promise<{ ok: boolean; data?: TouchResponse; error?: string; skipped?: boolean }>;
171
+ export function recordProductTouch(): Promise<unknown>;
172
+ export function identifyVisitor(email: string, traits?: Record<string, unknown>): Promise<boolean>;
173
+ export function createCheckoutSession(): Promise<CheckoutSession>;
174
+ export function buildPayload(customData?: Record<string, unknown>): TouchPayload;
175
+ export function readTouchHistory(): StoredTouch[];
176
+ export function getTouchSignature(payload: TouchPayload): string;
177
+ export function initPaymentButtonDetection(customSelector?: string | null): () => void;
178
+ export function registerGateway(name: string, gatewayInstance: PaymentGateway): PaymentGateway;
179
+ export function getGateway(name: string): PaymentGateway | null;
180
+ export function recordPaymentAttempt(details?: PaymentAttemptDetails): Promise<unknown>;
181
+ export function recordPaymentSuccess(details?: PaymentSuccessDetails): Promise<unknown>;
182
+ export function recordPaymentFailure(details?: PaymentFailureDetails): Promise<unknown>;
183
+
184
+ export const Elysium: {
185
+ init: typeof init;
186
+ configure: typeof configure;
187
+ getConfig: typeof getConfig;
188
+ getVisitorId: typeof getVisitorId;
189
+ setVisitorId: typeof setVisitorId;
190
+ recordTouch: typeof recordTouch;
191
+ recordProductTouch: typeof recordProductTouch;
192
+ identifyVisitor: typeof identifyVisitor;
193
+ createCheckoutSession: typeof createCheckoutSession;
194
+ buildPayload: typeof buildPayload;
195
+ readTouchHistory: typeof readTouchHistory;
196
+ getTouchSignature: typeof getTouchSignature;
197
+ initPaymentButtonDetection: typeof initPaymentButtonDetection;
198
+ registerGateway: typeof registerGateway;
199
+ getGateway: typeof getGateway;
200
+ recordPaymentAttempt: typeof recordPaymentAttempt;
201
+ recordPaymentSuccess: typeof recordPaymentSuccess;
202
+ recordPaymentFailure: typeof recordPaymentFailure;
203
+ gateways: {
204
+ PaymentGateway: typeof PaymentGateway;
205
+ StripeGateway: typeof StripeGateway;
206
+ RazorpayGateway: typeof RazorpayGateway;
207
+ PayPalGateway: typeof PayPalGateway;
208
+ GenericGateway: typeof GenericGateway;
209
+ registry: GatewayRegistry;
210
+ };
211
+ };
212
+
213
+ export default Elysium;
package/package.json CHANGED
@@ -1,6 +1,43 @@
1
1
  {
2
2
  "name": "elysium-attribution",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.2",
4
+ "description": "Multi-touch marketing attribution and payment gateway integration SDK for web storefronts and e-commerce platforms",
5
+ "type": "module",
6
+ "main": "./src/index.js",
7
+ "module": "./src/index.js",
8
+ "types": "./index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./index.d.ts",
12
+ "import": "./src/index.js"
13
+ },
14
+ "./gateways": {
15
+ "import": "./src/gateways/index.js"
16
+ },
17
+ "./tracking": {
18
+ "import": "./src/tracking/touchTracker.js"
19
+ },
20
+ "./config": {
21
+ "import": "./src/config/index.js"
22
+ }
23
+ },
24
+ "bin": {
25
+ "elysium": "./src/utils/cli.js"
26
+ },
27
+ "scripts": {
28
+ "test": "node --test test/**/*.test.js"
29
+ },
30
+ "keywords": [
31
+ "attribution",
32
+ "touch-tracking",
33
+ "marketing",
34
+ "utm",
35
+ "stripe",
36
+ "razorpay",
37
+ "paypal",
38
+ "payment-gateway",
39
+ "e-commerce"
40
+ ],
41
+ "author": "Elysium",
42
+ "license": "ISC"
43
+ }
@@ -0,0 +1,45 @@
1
+ import { DEFAULT_CONFIG, validateAndSanitizeConfig } from './schema.js';
2
+ import { logger } from '../utils/logger.js';
3
+
4
+ class ConfigManager {
5
+ constructor() {
6
+ this.config = { ...DEFAULT_CONFIG };
7
+ logger.getDebug = () => this.config.debug;
8
+ }
9
+
10
+ init(userConfig = {}) {
11
+ // If window.ELYSIUM_CONFIG exists in browser runtime, merge it first
12
+ let globalWindowConfig = {};
13
+ if (typeof window !== 'undefined' && window.ELYSIUM_CONFIG) {
14
+ globalWindowConfig = window.ELYSIUM_CONFIG;
15
+ }
16
+
17
+ this.config = validateAndSanitizeConfig({
18
+ ...globalWindowConfig,
19
+ ...userConfig,
20
+ });
21
+
22
+ logger.debug('Configuration initialized:', {
23
+ ...this.config,
24
+ apiKey: this.config.apiKey ? `${this.config.apiKey.slice(0, 7)}...` : '(empty)',
25
+ });
26
+
27
+ return this.config;
28
+ }
29
+
30
+ get() {
31
+ return this.config;
32
+ }
33
+
34
+ set(updates = {}) {
35
+ this.config = validateAndSanitizeConfig({
36
+ ...this.config,
37
+ ...updates,
38
+ });
39
+ return this.config;
40
+ }
41
+ }
42
+
43
+ export const configManager = new ConfigManager();
44
+ export const getConfig = () => configManager.get();
45
+ export const setConfig = (cfg) => configManager.set(cfg);