@crelora/mark 0.0.16

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.
@@ -0,0 +1,236 @@
1
+ const d = "https://ingest.onelence.com", u = /* @__PURE__ */ new Set(["event_name", "user_id", "consent_state", "source", "is_conversion"]), h = /* @__PURE__ */ new Set([
2
+ "user_id",
3
+ "visitor_id",
4
+ "click_id",
5
+ "campaign_id",
6
+ "query",
7
+ "consent_state",
8
+ "source"
9
+ ]);
10
+ class l {
11
+ constructor(t, e) {
12
+ this.deps = e, this.validateConfig(t), this.config = {
13
+ endpoint: t.endpoint ?? d,
14
+ ...t,
15
+ include_page_context: t.include_page_context ?? !0
16
+ }, this.consentRequirement = t.require_consent ?? !1, this.siteId = t.site_id, this.siteHost = t.site_host;
17
+ }
18
+ config;
19
+ consentRequirement;
20
+ siteId;
21
+ siteHost;
22
+ track(t, e = {}) {
23
+ return this.trackInternal(t, e, !1);
24
+ }
25
+ trackInternal(t, e = {}, s = !1) {
26
+ if (!t)
27
+ return this.config.debug && console.warn("[Mark] track called without event name"), !1;
28
+ if (!this.hasConsent())
29
+ return this.config.debug && console.warn("[Mark] Tracking blocked due to consent requirement."), !1;
30
+ const i = this.sanitizeTrackData(e), r = { ...i };
31
+ "query" in r && delete r.query, "site_id" in r && delete r.site_id, "site_host" in r && delete r.site_host;
32
+ const n = {
33
+ event_name: t,
34
+ ...this.getIdentityFields(i),
35
+ ...r
36
+ };
37
+ s && (n.is_conversion = !0);
38
+ const a = i.site_id ?? this.siteId, o = i.site_host ?? this.siteHost;
39
+ return a && (n.site_id = a), o && (n.site_host = o), this.config.include_page_context && typeof window < "u" && (this.applyPageContext(n), !o && n.site && (n.site_host = n.site)), this.deps.transport.send("/event", n), !0;
40
+ }
41
+ identify(t, e = {}) {
42
+ if (!t) {
43
+ this.config.debug && console.warn("[Mark] identify called without userId");
44
+ return;
45
+ }
46
+ if (!this.hasConsent()) {
47
+ this.config.debug && console.warn("[Mark] Identify blocked due to consent requirement.");
48
+ return;
49
+ }
50
+ const s = {
51
+ user_id: t,
52
+ ...this.sanitizeIdentifyTraits(e),
53
+ ...this.getIdentityFields()
54
+ };
55
+ this.siteId && (s.site_id = this.siteId), this.siteHost && (s.site_host = this.siteHost), this.deps.transport.send("/identify", s);
56
+ }
57
+ conversion(t, e = {}) {
58
+ return this.trackInternal(t, e, !0);
59
+ }
60
+ /**
61
+ * Returns the current visitor ID from storage, if any.
62
+ * Used by browser/Node wrappers to expose a stable pseudonymous ID for server-side attribution.
63
+ */
64
+ getVisitorId() {
65
+ return this.deps.storage.getVisitorId();
66
+ }
67
+ setConsent(t) {
68
+ this.deps.storage.setConsentStatus(t);
69
+ const e = {
70
+ visitor_id: this.deps.storage.getVisitorId(),
71
+ consent_state: t,
72
+ source: "sdk"
73
+ };
74
+ this.siteId && (e.site_id = this.siteId), this.siteHost && (e.site_host = this.siteHost), this.deps.transport.send("/consent", e);
75
+ }
76
+ getIdentityFields(t) {
77
+ const e = t?.visitor_id ?? this.deps.storage.getVisitorId(), s = t?.click_id ?? this.deps.storage.getLastClickId(), i = t?.campaign_id ?? this.deps.storage.getCampaignId(), r = this.deps.storage.getQueryParams() ?? {}, n = t?.query ?? {}, a = { ...r, ...n }, o = {};
78
+ return e && (o.visitor_id = e), s && (o.click_id = s), i && (o.campaign_id = i), Object.keys(a).length > 0 && (o.query = a), o;
79
+ }
80
+ hasConsent() {
81
+ if (!this.consentRequirement)
82
+ return !0;
83
+ const e = this.deps.storage.getConsentStatus();
84
+ return this.consentRequirement === "auto", e === "granted";
85
+ }
86
+ sanitizeTrackData(t) {
87
+ const e = {};
88
+ for (const [s, i] of Object.entries(t))
89
+ u.has(s) || (e[s] = i);
90
+ return e;
91
+ }
92
+ sanitizeIdentifyTraits(t) {
93
+ const e = {};
94
+ for (const [s, i] of Object.entries(t))
95
+ h.has(s) || (e[s] = i);
96
+ return e;
97
+ }
98
+ validateConfig(t) {
99
+ if (!t.key || !t.key.trim())
100
+ throw new Error("[Mark] `key` must be a non-empty string.");
101
+ if (t.endpoint)
102
+ try {
103
+ new URL(t.endpoint);
104
+ } catch {
105
+ throw new Error("[Mark] `endpoint` must be a valid absolute URL.");
106
+ }
107
+ if (typeof t.site_id == "string" && !t.site_id.trim())
108
+ throw new Error("[Mark] `site_id` cannot be an empty string.");
109
+ if (typeof t.site_host == "string" && !t.site_host.trim())
110
+ throw new Error("[Mark] `site_host` cannot be an empty string.");
111
+ }
112
+ applyPageContext(t) {
113
+ t.page || t.title || t.referrer || t.site || (t.site = window.location.host, t.page = window.location.pathname, t.title = document.title, document.referrer && (t.referrer = document.referrer));
114
+ }
115
+ }
116
+ class f {
117
+ config;
118
+ endpoint;
119
+ constructor(t) {
120
+ this.validateConfig(t), this.config = t, this.endpoint = t.endpoint ?? d;
121
+ }
122
+ async send(t, e) {
123
+ const s = this.joinUrl(this.endpoint, t), i = this.config.key, r = {
124
+ "Content-Type": "application/json",
125
+ [i.startsWith("sk_") ? "x-secret-key" : "x-publishable-key"]: i
126
+ };
127
+ if (this.config.debug && console.log("[Mark] Sending", s, e), typeof fetch != "function") {
128
+ this.config.debug && console.error("[Mark] Global fetch is not available in this runtime.");
129
+ return;
130
+ }
131
+ try {
132
+ const n = await fetch(s, {
133
+ method: "POST",
134
+ headers: r,
135
+ body: JSON.stringify(e),
136
+ keepalive: !0
137
+ });
138
+ if (!n.ok && this.config.debug) {
139
+ const a = await this.readErrorSnippet(n);
140
+ console.error("[Mark] Request rejected", {
141
+ url: s,
142
+ status: n.status,
143
+ statusText: n.statusText,
144
+ body: a
145
+ });
146
+ }
147
+ } catch (n) {
148
+ this.config.debug && console.error("[Mark] Failed to send", s, n);
149
+ }
150
+ }
151
+ joinUrl(t, e) {
152
+ const s = t.replace(/\/+$/, ""), i = e.replace(/^\/+/, "");
153
+ return `${s}/${i}`;
154
+ }
155
+ async readErrorSnippet(t) {
156
+ try {
157
+ return (await t.text()).slice(0, 300);
158
+ } catch {
159
+ return "";
160
+ }
161
+ }
162
+ validateConfig(t) {
163
+ if (!t.key || !t.key.trim())
164
+ throw new Error("[Mark] `key` must be a non-empty string.");
165
+ if (t.endpoint)
166
+ try {
167
+ new URL(t.endpoint);
168
+ } catch {
169
+ throw new Error("[Mark] `endpoint` must be a valid absolute URL.");
170
+ }
171
+ }
172
+ }
173
+ class _ {
174
+ constructor(t = {}) {
175
+ this.defaults = t;
176
+ }
177
+ getVisitorId() {
178
+ return this.defaults.visitor_id;
179
+ }
180
+ getLastClickId() {
181
+ return this.defaults.last_click_id;
182
+ }
183
+ getCampaignId() {
184
+ return this.defaults.campaign_id;
185
+ }
186
+ getQueryParams() {
187
+ return this.defaults.query_params;
188
+ }
189
+ getConsentStatus() {
190
+ return this.defaults.consent_status;
191
+ }
192
+ update() {
193
+ }
194
+ setConsentStatus() {
195
+ }
196
+ }
197
+ class g {
198
+ constructor(t) {
199
+ this.client = t;
200
+ }
201
+ track(t, e = {}) {
202
+ this.client.track(t, e);
203
+ }
204
+ conversion(t, e = {}) {
205
+ this.client.conversion(t, e);
206
+ }
207
+ identify(t, e = {}) {
208
+ this.client.identify(t, e);
209
+ }
210
+ setConsent(t) {
211
+ this.client.setConsent(t);
212
+ }
213
+ /**
214
+ * Returns the visitor ID from the configured storage, if any.
215
+ * With default StatelessStorage, this is the value passed via `storageDefaults.visitor_id` when creating the client.
216
+ * Use it to associate server-side events with the same visitor dimension as browser events.
217
+ */
218
+ getVisitorId() {
219
+ return this.client.getVisitorId();
220
+ }
221
+ }
222
+ const p = (c, t = {}) => {
223
+ const e = t.storage ?? new _({
224
+ visitor_id: t.storageDefaults?.visitor_id,
225
+ last_click_id: t.storageDefaults?.last_click_id,
226
+ campaign_id: t.storageDefaults?.campaign_id,
227
+ query_params: t.storageDefaults?.query_params,
228
+ consent_status: t.storageDefaults?.consent_status
229
+ }), s = t.transport ?? new f(c), i = new l(c, { storage: e, transport: s });
230
+ return new g(i);
231
+ };
232
+ export {
233
+ g as NodeMark,
234
+ _ as StatelessStorage,
235
+ p as createNodeMark
236
+ };
@@ -0,0 +1,32 @@
1
+ import type { ConsentStatus, CrossDomainConfig, StorageData } from '../types';
2
+ import type { StorageAdapter } from '../core/adapters';
3
+ interface BrowserStorageOptions extends CrossDomainConfig {
4
+ storageKey?: string;
5
+ }
6
+ export declare class BrowserStorage implements StorageAdapter {
7
+ private data;
8
+ private readonly storageKey;
9
+ private readonly options;
10
+ private bridgeFrame?;
11
+ private bridgeReady;
12
+ private bridgeOrigin?;
13
+ constructor(options?: BrowserStorageOptions);
14
+ getVisitorId(): string | undefined;
15
+ getLastClickId(): string | undefined;
16
+ getCampaignId(): string | undefined;
17
+ getQueryParams(): Record<string, string> | undefined;
18
+ getConsentStatus(): ConsentStatus | undefined;
19
+ update(updates: Partial<StorageData>): void;
20
+ setConsentStatus(status: ConsentStatus): void;
21
+ private load;
22
+ private save;
23
+ private getCookie;
24
+ private setCookie;
25
+ private generateUUID;
26
+ private isCookieEnabled;
27
+ private setupBridge;
28
+ private handleBridgeMessage;
29
+ private postBridgeMessage;
30
+ private isDomainAllowed;
31
+ }
32
+ export {};
@@ -0,0 +1,28 @@
1
+ import type { MarkConfig, TrackEventData, IdentifyTraits, ConsentStatus } from '../types';
2
+ import { MarkCore } from '../core/MarkCore';
3
+ export declare class Mark {
4
+ private static client;
5
+ private static storage;
6
+ private static config;
7
+ private static pageviewTrackerInstalled;
8
+ private static lastPageviewHref;
9
+ private static emitAutoPageview;
10
+ private static pendingAttribution;
11
+ static init(config: MarkConfig): MarkCore;
12
+ static track(eventName: string, data?: TrackEventData): void;
13
+ static identify(userId: string, traits?: IdentifyTraits): void;
14
+ static conversion(eventName: string, data?: TrackEventData): void;
15
+ static setConsent(status: ConsentStatus): void;
16
+ /**
17
+ * Returns the current visitor ID when available.
18
+ * When consent is required (`require_consent: true` or `'auto'`), returns `undefined` until consent is granted.
19
+ * Use this to pass the visitor ID to your backend (e.g. in a header or request body) for server-side attribution
20
+ * when you do not have an authenticated user ID.
21
+ */
22
+ static getVisitorId(): string | undefined;
23
+ private static installPageviewTracking;
24
+ private static refreshAttribution;
25
+ private static flushPendingAttribution;
26
+ private static shouldPersistAttribution;
27
+ private static mergeAttributionUpdates;
28
+ }
@@ -0,0 +1,3 @@
1
+ import { Mark } from './Mark';
2
+ export { Mark };
3
+ export default Mark;
@@ -0,0 +1,6 @@
1
+ import type { StorageAdapter } from '../core/adapters';
2
+ import type { MarkConfig, StorageData } from '../types';
3
+ type AttributionCaptureConfig = Pick<MarkConfig, 'capture_query_params' | 'capture_all_query_params' | 'query_param_denylist' | 'max_captured_query_params' | 'max_query_param_value_length'>;
4
+ export declare function captureAttributionFromUrl(storage: StorageAdapter, config?: AttributionCaptureConfig): void;
5
+ export declare function extractAttributionFromSearch(search: string, config?: AttributionCaptureConfig): Partial<StorageData>;
6
+ export {};
@@ -0,0 +1,11 @@
1
+ import type { MarkConfig } from '../types';
2
+ import type { TransportAdapter } from './adapters';
3
+ export declare class HttpTransport implements TransportAdapter {
4
+ private readonly config;
5
+ private readonly endpoint;
6
+ constructor(config: MarkConfig);
7
+ send(path: string, data: unknown): Promise<void>;
8
+ private joinUrl;
9
+ private readErrorSnippet;
10
+ private validateConfig;
11
+ }
@@ -0,0 +1,26 @@
1
+ import type { MarkConfig, TrackEventData, IdentifyTraits, ConsentStatus } from '../types';
2
+ import type { MarkDependencies } from './adapters';
3
+ export declare class MarkCore {
4
+ private readonly deps;
5
+ private config;
6
+ private consentRequirement;
7
+ private siteId?;
8
+ private siteHost?;
9
+ constructor(config: MarkConfig, deps: MarkDependencies);
10
+ track(eventName: string, data?: TrackEventData): boolean;
11
+ private trackInternal;
12
+ identify(userId: string, traits?: IdentifyTraits): void;
13
+ conversion(eventName: string, data?: TrackEventData): boolean;
14
+ /**
15
+ * Returns the current visitor ID from storage, if any.
16
+ * Used by browser/Node wrappers to expose a stable pseudonymous ID for server-side attribution.
17
+ */
18
+ getVisitorId(): string | undefined;
19
+ setConsent(status: ConsentStatus): void;
20
+ private getIdentityFields;
21
+ private hasConsent;
22
+ private sanitizeTrackData;
23
+ private sanitizeIdentifyTraits;
24
+ private validateConfig;
25
+ private applyPageContext;
26
+ }
@@ -0,0 +1,18 @@
1
+ import type { StorageData } from '../types';
2
+ import type { ConsentStatus } from '../types';
3
+ export interface StorageAdapter {
4
+ getVisitorId(): string | undefined;
5
+ getLastClickId(): string | undefined;
6
+ getCampaignId(): string | undefined;
7
+ getQueryParams(): Record<string, string> | undefined;
8
+ getConsentStatus(): ConsentStatus | undefined;
9
+ setConsentStatus(status: ConsentStatus): void;
10
+ update(updates: Partial<StorageData>): void;
11
+ }
12
+ export interface TransportAdapter {
13
+ send(path: string, data: unknown): Promise<void>;
14
+ }
15
+ export interface MarkDependencies {
16
+ storage: StorageAdapter;
17
+ transport: TransportAdapter;
18
+ }
@@ -0,0 +1 @@
1
+ export declare const DEFAULT_ENDPOINT = "https://ingest.onelence.com";
@@ -0,0 +1,3 @@
1
+ export { Mark } from './browser/Mark';
2
+ export { createNodeMark, NodeMark, StatelessStorage } from './node';
3
+ export type * from './types';
@@ -0,0 +1,17 @@
1
+ import type { ConsentStatus, StorageData } from '../types';
2
+ import type { StorageAdapter } from '../core/adapters';
3
+ /**
4
+ * Stateless storage adapter used by default in server runtimes.
5
+ * It simply exposes optional defaults and ignores updates.
6
+ */
7
+ export declare class StatelessStorage implements StorageAdapter {
8
+ private defaults;
9
+ constructor(defaults?: StorageData);
10
+ getVisitorId(): string | undefined;
11
+ getLastClickId(): string | undefined;
12
+ getCampaignId(): string | undefined;
13
+ getQueryParams(): Record<string, string> | undefined;
14
+ getConsentStatus(): ConsentStatus | undefined;
15
+ update(): void;
16
+ setConsentStatus(): void;
17
+ }
@@ -0,0 +1,25 @@
1
+ import type { MarkConfig, TrackEventData, IdentifyTraits, StorageData, ConsentStatus } from '../types';
2
+ import { MarkCore } from '../core/MarkCore';
3
+ import type { StorageAdapter, TransportAdapter } from '../core/adapters';
4
+ import { StatelessStorage } from './StatelessStorage';
5
+ export interface NodeMarkOptions {
6
+ storage?: StorageAdapter;
7
+ transport?: TransportAdapter;
8
+ storageDefaults?: StorageData;
9
+ }
10
+ export declare class NodeMark {
11
+ private readonly client;
12
+ constructor(client: MarkCore);
13
+ track(eventName: string, data?: TrackEventData): void;
14
+ conversion(eventName: string, data?: TrackEventData): void;
15
+ identify(userId: string, traits?: IdentifyTraits): void;
16
+ setConsent(status: ConsentStatus): void;
17
+ /**
18
+ * Returns the visitor ID from the configured storage, if any.
19
+ * With default StatelessStorage, this is the value passed via `storageDefaults.visitor_id` when creating the client.
20
+ * Use it to associate server-side events with the same visitor dimension as browser events.
21
+ */
22
+ getVisitorId(): string | undefined;
23
+ }
24
+ export declare const createNodeMark: (config: MarkConfig, options?: NodeMarkOptions) => NodeMark;
25
+ export { StatelessStorage };
@@ -0,0 +1,157 @@
1
+ export interface AutocaptureConfig {
2
+ /**
3
+ * When true, automatically emit `page_view` on init and on SPA route changes.
4
+ * Defaults to false.
5
+ */
6
+ pageview?: boolean;
7
+ }
8
+ export interface MarkConfig {
9
+ /**
10
+ * Publishable or secret key identifying the customer account.
11
+ */
12
+ key: string;
13
+ /**
14
+ * Optional endpoint override.
15
+ * Defaults to 'https://ingest.onelence.com'.
16
+ */
17
+ endpoint?: string;
18
+ /**
19
+ * Enables verbose logging for debugging purposes.
20
+ */
21
+ debug?: boolean;
22
+ /**
23
+ * Optional cross-domain configuration.
24
+ */
25
+ cross_domain?: CrossDomainConfig;
26
+ /**
27
+ * Whether consent is required before tracking.
28
+ * - false (default): always track.
29
+ * - true: require explicit granted consent.
30
+ * - 'auto': honor stored consent; if none, treat as denied until provided.
31
+ */
32
+ require_consent?: boolean | 'auto';
33
+ /**
34
+ * Controls which events are automatically captured.
35
+ * Use { pageview: true } to emit page_view on init and SPA route changes.
36
+ */
37
+ autocapture?: AutocaptureConfig;
38
+ /**
39
+ * When autocapture.pageview is enabled, also track SPA route changes (pushState/replaceState/popstate).
40
+ * Defaults to true when autocapture.pageview is true.
41
+ */
42
+ track_route_changes?: boolean;
43
+ /**
44
+ * When true (default), browser SDK enriches events with page context (path, title, referrer, host).
45
+ * Full URL is only included when explicitly provided in the event payload.
46
+ */
47
+ include_page_context?: boolean;
48
+ /**
49
+ * Optional site identifier (UUID) for associating events with a registered site.
50
+ * When provided, this will be included in all event payloads as `site_id`.
51
+ */
52
+ site_id?: string;
53
+ /**
54
+ * Optional site host for audit/debug purposes.
55
+ * When provided, this will be included in all event payloads as `site_host`.
56
+ * If not provided, the SDK will use the host from page context (browser) or leave it undefined (Node).
57
+ */
58
+ site_host?: string;
59
+ /**
60
+ * Additional query parameter keys to capture for attribution.
61
+ * Keys are matched case-insensitively and stored in lowercase.
62
+ */
63
+ capture_query_params?: string[];
64
+ /**
65
+ * Capture every query string parameter (after denylist/limits are applied).
66
+ * Defaults to false.
67
+ */
68
+ capture_all_query_params?: boolean;
69
+ /**
70
+ * Lowercase query parameter keys that should never be captured.
71
+ * Defaults to sensitive keys such as email/phone/token/auth/password/code.
72
+ */
73
+ query_param_denylist?: string[];
74
+ /**
75
+ * Maximum number of query params persisted in attribution storage.
76
+ * Defaults to 30.
77
+ */
78
+ max_captured_query_params?: number;
79
+ /**
80
+ * Maximum length for each captured query param value.
81
+ * Defaults to 256.
82
+ */
83
+ max_query_param_value_length?: number;
84
+ }
85
+ export type JsonPrimitive = string | number | boolean | null;
86
+ export type JsonValue = JsonPrimitive | JsonValue[] | {
87
+ [key: string]: JsonValue;
88
+ };
89
+ export interface TrackEventData {
90
+ /**
91
+ * Optional explicit identifiers supplied by server runtimes.
92
+ */
93
+ visitor_id?: string;
94
+ click_id?: string;
95
+ campaign_id?: string;
96
+ query?: Record<string, string>;
97
+ /**
98
+ * Optional site identifier (UUID) for this specific event.
99
+ * Overrides the site_id from Mark.init() if provided.
100
+ */
101
+ site_id?: string;
102
+ /**
103
+ * Optional site host for this specific event.
104
+ * Overrides the site_host from Mark.init() if provided.
105
+ */
106
+ site_host?: string;
107
+ [key: string]: JsonValue | undefined;
108
+ }
109
+ export interface IdentifyTraits {
110
+ /**
111
+ * User's email address. Will be hashed server-side for privacy.
112
+ */
113
+ email?: string;
114
+ /**
115
+ * User's display name or full name.
116
+ */
117
+ display_name?: string;
118
+ /**
119
+ * User's preferred language (e.g., 'en', 'en-US', 'fr').
120
+ */
121
+ language?: string;
122
+ /**
123
+ * User's phone number. Will be hashed server-side for privacy.
124
+ */
125
+ phone?: string;
126
+ /**
127
+ * Additional custom traits. All traits are stored in the user profile and can be used for segmentation and personalization.
128
+ */
129
+ [key: string]: JsonValue | undefined;
130
+ }
131
+ export interface StorageData {
132
+ visitor_id?: string;
133
+ last_click_id?: string;
134
+ campaign_id?: string;
135
+ consent_status?: ConsentStatus;
136
+ query_params?: Record<string, string>;
137
+ }
138
+ export type DomainMode = 'single' | 'subdomain' | 'cross_domain';
139
+ export interface CrossDomainConfig {
140
+ mode?: DomainMode;
141
+ /**
142
+ * Explicit cookie domain (e.g., ".example.com") for cross-subdomain tracking.
143
+ */
144
+ cookie_domain?: string;
145
+ /**
146
+ * Bridge configuration for cross-domain syncing using a first-party iframe service.
147
+ */
148
+ bridge?: {
149
+ url: string;
150
+ timeout_ms?: number;
151
+ };
152
+ /**
153
+ * Optional allowlist of domains that are permitted to interact via the bridge.
154
+ */
155
+ allowed_domains?: string[];
156
+ }
157
+ export type ConsentStatus = 'granted' | 'denied';
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@crelora/mark",
3
+ "private": false,
4
+ "version": "0.0.16",
5
+ "license": "SEE LICENSE IN LICENSE",
6
+ "type": "module",
7
+ "main": "./dist/browser.umd.js",
8
+ "module": "./dist/browser.es.js",
9
+ "types": "./dist/types/browser/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/types/browser/index.d.ts",
13
+ "import": "./dist/browser.es.js",
14
+ "require": "./dist/browser.umd.js"
15
+ },
16
+ "./browser": {
17
+ "types": "./dist/types/browser/index.d.ts",
18
+ "import": "./dist/browser.es.js",
19
+ "require": "./dist/browser.umd.js"
20
+ },
21
+ "./node": {
22
+ "types": "./dist/types/node/index.d.ts",
23
+ "import": "./dist/node.es.js",
24
+ "require": "./dist/node.cjs"
25
+ }
26
+ },
27
+ "files": [
28
+ "dist"
29
+ ],
30
+ "scripts": {
31
+ "dev": "vite",
32
+ "build": "rimraf dist && tsc -p tsconfig.build.json && vite build --config vite.browser.config.ts && vite build --config vite.node.config.ts",
33
+ "preview": "vite preview",
34
+ "test": "vitest run"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^24.10.1",
38
+ "rimraf": "^6.1.2",
39
+ "typescript": "~5.9.3",
40
+ "vite": "^7.2.4",
41
+ "vitest": "^4.0.18"
42
+ }
43
+ }