@dumbledor/sdk 0.1.0 → 0.2.0

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/dist/index.cjs CHANGED
@@ -59,6 +59,7 @@ function isTrackingDisabled(honorDoNotTrack) {
59
59
  }
60
60
 
61
61
  // src/client.ts
62
+ var CACHE_HEADER = "x-dumbledor-cache";
62
63
  function defaultPageviewInput() {
63
64
  if (typeof window === "undefined" || typeof document === "undefined") {
64
65
  return {};
@@ -75,15 +76,23 @@ function defaultPageviewInput() {
75
76
  function createTransport(config) {
76
77
  const endpoint = `${config.ingestUrl}/v1/collect`;
77
78
  const fetchImpl = resolveFetch(config.fetch);
78
- return async function send(payload) {
79
+ let cache;
80
+ return async function send(payload, options) {
79
81
  if (config.disabled || isTrackingDisabled(config.honorDoNotTrack)) {
80
82
  return;
81
83
  }
84
+ if (options?.clearCache) {
85
+ cache = void 0;
86
+ }
82
87
  const body = withWebsiteId(payload, config.websiteId);
88
+ const headers = { "Content-Type": "application/json" };
89
+ if (cache) {
90
+ headers[CACHE_HEADER] = cache;
91
+ }
83
92
  try {
84
93
  const response = await fetchImpl(endpoint, {
85
94
  method: "POST",
86
- headers: { "Content-Type": "application/json" },
95
+ headers,
87
96
  body: JSON.stringify(body),
88
97
  keepalive: true,
89
98
  credentials: "omit",
@@ -95,7 +104,11 @@ function createTransport(config) {
95
104
  error: `Ingest request failed with status ${response.status}`
96
105
  };
97
106
  }
98
- return await response.json();
107
+ const data = await response.json();
108
+ if (data.cache) {
109
+ cache = data.cache;
110
+ }
111
+ return data;
99
112
  } catch {
100
113
  return {
101
114
  ok: false,
@@ -136,11 +149,14 @@ function createClient(config) {
136
149
  });
137
150
  },
138
151
  identify(userId, traits) {
139
- void send({
140
- type: "identify",
141
- userId,
142
- traits: traits ?? {}
143
- });
152
+ void send(
153
+ {
154
+ type: "identify",
155
+ userId,
156
+ traits: traits ?? {}
157
+ },
158
+ { clearCache: true }
159
+ );
144
160
  }
145
161
  };
146
162
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/config.ts","../src/dnt.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["export const DEFAULT_INGEST_URL = \"https://ingest.dumbledor.com\";\n\nexport const UUID_PATTERN =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n","import { DEFAULT_INGEST_URL, UUID_PATTERN } from \"./constants\";\nimport type {\n CollectPayload,\n CollectPayloadInput,\n DumbledorClientConfig,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nexport class DumbledorConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DumbledorConfigError\";\n }\n}\n\nexport function normalizeIngestUrl(value?: string): string {\n const raw = value?.trim() || DEFAULT_INGEST_URL;\n return raw.replace(/\\/$/, \"\");\n}\n\nexport function assertClientConfig(config: DumbledorClientConfig): ResolvedDumbledorConfig {\n const websiteId = config.websiteId?.trim();\n\n if (!websiteId) {\n throw new DumbledorConfigError(\"websiteId is required.\");\n }\n\n if (!UUID_PATTERN.test(websiteId)) {\n throw new DumbledorConfigError(\"websiteId must be a valid UUID.\");\n }\n\n return {\n websiteId,\n ingestUrl: normalizeIngestUrl(config.ingestUrl),\n honorDoNotTrack: config.honorDoNotTrack ?? false,\n disabled: config.disabled ?? false,\n fetch: config.fetch,\n };\n}\n\nexport function withWebsiteId(\n payload: CollectPayloadInput,\n websiteId: string,\n): CollectPayload {\n return {\n ...payload,\n websiteId,\n };\n}\n\nexport function resolveFetch(fetchImpl?: typeof fetch): typeof fetch {\n const resolved = fetchImpl ?? globalThis.fetch;\n if (!resolved) {\n throw new DumbledorConfigError(\"fetch is not available in this runtime.\");\n }\n\n return resolved;\n}\n","type NavigatorWithMsDnt = Navigator & {\n msDoNotTrack?: string | number | null;\n};\n\ntype WindowWithDnt = Window & {\n doNotTrack?: string | number | null;\n};\n\nexport function hasDoNotTrack(): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n\n const win = window as WindowWithDnt;\n const dnt =\n win.doNotTrack ??\n win.navigator.doNotTrack ??\n (win.navigator as NavigatorWithMsDnt).msDoNotTrack;\n\n return dnt === 1 || dnt === \"1\" || dnt === \"yes\";\n}\n\nexport function isTrackingDisabled(honorDoNotTrack: boolean): boolean {\n return honorDoNotTrack && hasDoNotTrack();\n}\n","import { assertClientConfig, resolveFetch, withWebsiteId } from \"./config\";\nimport { isTrackingDisabled } from \"./dnt\";\nimport type {\n CollectPayloadInput,\n CollectResponse,\n DumbledorClient,\n DumbledorClientConfig,\n PageviewInput,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nfunction defaultPageviewInput(): PageviewInput {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n return {};\n }\n\n return {\n url: window.location.href,\n referrer: document.referrer || undefined,\n title: document.title,\n hostname: window.location.hostname,\n language: navigator.language,\n screen: typeof screen !== \"undefined\" ? `${screen.width}x${screen.height}` : undefined,\n };\n}\n\nexport function createTransport(config: ResolvedDumbledorConfig) {\n const endpoint = `${config.ingestUrl}/v1/collect`;\n const fetchImpl = resolveFetch(config.fetch);\n\n return async function send(payload: CollectPayloadInput): Promise<CollectResponse | void> {\n if (config.disabled || isTrackingDisabled(config.honorDoNotTrack)) {\n return;\n }\n\n const body = withWebsiteId(payload, config.websiteId);\n\n try {\n const response = await fetchImpl(endpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n keepalive: true,\n credentials: \"omit\",\n mode: \"cors\",\n });\n\n if (!response.ok) {\n return {\n ok: false,\n error: `Ingest request failed with status ${response.status}`,\n };\n }\n\n return (await response.json()) as CollectResponse;\n } catch {\n return {\n ok: false,\n error: \"Ingest request failed\",\n };\n }\n };\n}\n\nexport function createClient(config: DumbledorClientConfig): DumbledorClient {\n const resolved = assertClientConfig(config);\n const send = createTransport(resolved);\n\n return {\n config: resolved,\n page(input = {}) {\n const defaults = defaultPageviewInput();\n const url = input.url ?? defaults.url;\n if (!url) {\n return;\n }\n\n void send({\n type: \"pageview\",\n url,\n referrer: input.referrer ?? defaults.referrer,\n title: input.title ?? defaults.title,\n hostname: input.hostname ?? defaults.hostname,\n language: input.language ?? defaults.language,\n screen: input.screen ?? defaults.screen,\n });\n },\n track(name, properties) {\n const defaults = defaultPageviewInput();\n void send({\n type: \"track\",\n name,\n properties: properties ?? {},\n url: defaults.url,\n hostname: defaults.hostname,\n });\n },\n identify(userId, traits) {\n void send({\n type: \"identify\",\n userId,\n traits: traits ?? {},\n });\n },\n };\n}\n\nlet defaultClient: DumbledorClient | null = null;\n\nexport function init(config: DumbledorClientConfig): DumbledorClient {\n defaultClient = createClient(config);\n return defaultClient;\n}\n\nexport function getClient(): DumbledorClient {\n if (!defaultClient) {\n throw new Error(\n \"Dumbledor is not initialized. Call init(), wrap with DumbledorProvider, or createClient() first.\",\n );\n }\n\n return defaultClient;\n}\n\nexport function page(input?: PageviewInput): void {\n getClient().page(input);\n}\n\nexport function track(name: string, properties?: Record<string, unknown>): void {\n getClient().track(name, properties);\n}\n\nexport function identify(userId: string, traits?: Record<string, unknown>): void {\n getClient().identify(userId, traits);\n}\n"]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/config.ts","../src/dnt.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["export const DEFAULT_INGEST_URL = \"https://ingest.dumbledor.com\";\n\nexport const UUID_PATTERN =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n","import { DEFAULT_INGEST_URL, UUID_PATTERN } from \"./constants\";\nimport type {\n CollectPayload,\n CollectPayloadInput,\n DumbledorClientConfig,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nexport class DumbledorConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DumbledorConfigError\";\n }\n}\n\nexport function normalizeIngestUrl(value?: string): string {\n const raw = value?.trim() || DEFAULT_INGEST_URL;\n return raw.replace(/\\/$/, \"\");\n}\n\nexport function assertClientConfig(config: DumbledorClientConfig): ResolvedDumbledorConfig {\n const websiteId = config.websiteId?.trim();\n\n if (!websiteId) {\n throw new DumbledorConfigError(\"websiteId is required.\");\n }\n\n if (!UUID_PATTERN.test(websiteId)) {\n throw new DumbledorConfigError(\"websiteId must be a valid UUID.\");\n }\n\n return {\n websiteId,\n ingestUrl: normalizeIngestUrl(config.ingestUrl),\n honorDoNotTrack: config.honorDoNotTrack ?? false,\n disabled: config.disabled ?? false,\n fetch: config.fetch,\n };\n}\n\nexport function withWebsiteId(\n payload: CollectPayloadInput,\n websiteId: string,\n): CollectPayload {\n return {\n ...payload,\n websiteId,\n };\n}\n\nexport function resolveFetch(fetchImpl?: typeof fetch): typeof fetch {\n const resolved = fetchImpl ?? globalThis.fetch;\n if (!resolved) {\n throw new DumbledorConfigError(\"fetch is not available in this runtime.\");\n }\n\n return resolved;\n}\n","type NavigatorWithMsDnt = Navigator & {\n msDoNotTrack?: string | number | null;\n};\n\ntype WindowWithDnt = Window & {\n doNotTrack?: string | number | null;\n};\n\nexport function hasDoNotTrack(): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n\n const win = window as WindowWithDnt;\n const dnt =\n win.doNotTrack ??\n win.navigator.doNotTrack ??\n (win.navigator as NavigatorWithMsDnt).msDoNotTrack;\n\n return dnt === 1 || dnt === \"1\" || dnt === \"yes\";\n}\n\nexport function isTrackingDisabled(honorDoNotTrack: boolean): boolean {\n return honorDoNotTrack && hasDoNotTrack();\n}\n","import { assertClientConfig, resolveFetch, withWebsiteId } from \"./config\";\nimport { isTrackingDisabled } from \"./dnt\";\nimport type {\n CollectPayloadInput,\n CollectResponse,\n DumbledorClient,\n DumbledorClientConfig,\n PageviewInput,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nconst CACHE_HEADER = \"x-dumbledor-cache\";\n\nfunction defaultPageviewInput(): PageviewInput {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n return {};\n }\n\n return {\n url: window.location.href,\n referrer: document.referrer || undefined,\n title: document.title,\n hostname: window.location.hostname,\n language: navigator.language,\n screen: typeof screen !== \"undefined\" ? `${screen.width}x${screen.height}` : undefined,\n };\n}\n\ntype SendOptions = {\n clearCache?: boolean;\n};\n\nexport function createTransport(config: ResolvedDumbledorConfig) {\n const endpoint = `${config.ingestUrl}/v1/collect`;\n const fetchImpl = resolveFetch(config.fetch);\n let cache: string | undefined;\n\n return async function send(\n payload: CollectPayloadInput,\n options?: SendOptions,\n ): Promise<CollectResponse | void> {\n if (config.disabled || isTrackingDisabled(config.honorDoNotTrack)) {\n return;\n }\n\n if (options?.clearCache) {\n cache = undefined;\n }\n\n const body = withWebsiteId(payload, config.websiteId);\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (cache) {\n headers[CACHE_HEADER] = cache;\n }\n\n try {\n const response = await fetchImpl(endpoint, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n keepalive: true,\n credentials: \"omit\",\n mode: \"cors\",\n });\n\n if (!response.ok) {\n return {\n ok: false,\n error: `Ingest request failed with status ${response.status}`,\n };\n }\n\n const data = (await response.json()) as CollectResponse;\n if (data.cache) {\n cache = data.cache;\n }\n\n return data;\n } catch {\n return {\n ok: false,\n error: \"Ingest request failed\",\n };\n }\n };\n}\n\nexport function createClient(config: DumbledorClientConfig): DumbledorClient {\n const resolved = assertClientConfig(config);\n const send = createTransport(resolved);\n\n return {\n config: resolved,\n page(input = {}) {\n const defaults = defaultPageviewInput();\n const url = input.url ?? defaults.url;\n if (!url) {\n return;\n }\n\n void send({\n type: \"pageview\",\n url,\n referrer: input.referrer ?? defaults.referrer,\n title: input.title ?? defaults.title,\n hostname: input.hostname ?? defaults.hostname,\n language: input.language ?? defaults.language,\n screen: input.screen ?? defaults.screen,\n });\n },\n track(name, properties) {\n const defaults = defaultPageviewInput();\n void send({\n type: \"track\",\n name,\n properties: properties ?? {},\n url: defaults.url,\n hostname: defaults.hostname,\n });\n },\n identify(userId, traits) {\n void send(\n {\n type: \"identify\",\n userId,\n traits: traits ?? {},\n },\n { clearCache: true },\n );\n },\n };\n}\n\nlet defaultClient: DumbledorClient | null = null;\n\nexport function init(config: DumbledorClientConfig): DumbledorClient {\n defaultClient = createClient(config);\n return defaultClient;\n}\n\nexport function getClient(): DumbledorClient {\n if (!defaultClient) {\n throw new Error(\n \"Dumbledor is not initialized. Call init(), wrap with DumbledorProvider, or createClient() first.\",\n );\n }\n\n return defaultClient;\n}\n\nexport function page(input?: PageviewInput): void {\n getClient().page(input);\n}\n\nexport function track(name: string, properties?: Record<string, unknown>): void {\n getClient().track(name, properties);\n}\n\nexport function identify(userId: string, traits?: Record<string, unknown>): void {\n getClient().identify(userId, traits);\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -1,7 +1,10 @@
1
- import { D as DumbledorClientConfig, a as DumbledorClient, R as ResolvedDumbledorConfig, C as CollectPayloadInput, b as CollectResponse, P as PageviewInput, c as CollectPayload } from './types-DWa2kNUy.cjs';
2
- export { d as CollectEventType, e as DumbledorServerConfig, I as IdentifyPayload, f as PageviewPayload, S as ServerContext, T as TrackPayload } from './types-DWa2kNUy.cjs';
1
+ import { D as DumbledorClientConfig, a as DumbledorClient, R as ResolvedDumbledorConfig, C as CollectPayloadInput, b as CollectResponse, P as PageviewInput, c as CollectPayload } from './types-jDs6E55a.cjs';
2
+ export { d as CollectEventType, e as DumbledorServerConfig, I as IdentifyPayload, f as PageviewPayload, S as ServerContext, T as TrackPayload } from './types-jDs6E55a.cjs';
3
3
 
4
- declare function createTransport(config: ResolvedDumbledorConfig): (payload: CollectPayloadInput) => Promise<CollectResponse | void>;
4
+ type SendOptions = {
5
+ clearCache?: boolean;
6
+ };
7
+ declare function createTransport(config: ResolvedDumbledorConfig): (payload: CollectPayloadInput, options?: SendOptions) => Promise<CollectResponse | void>;
5
8
  declare function createClient(config: DumbledorClientConfig): DumbledorClient;
6
9
  declare function init(config: DumbledorClientConfig): DumbledorClient;
7
10
  declare function getClient(): DumbledorClient;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,10 @@
1
- import { D as DumbledorClientConfig, a as DumbledorClient, R as ResolvedDumbledorConfig, C as CollectPayloadInput, b as CollectResponse, P as PageviewInput, c as CollectPayload } from './types-DWa2kNUy.js';
2
- export { d as CollectEventType, e as DumbledorServerConfig, I as IdentifyPayload, f as PageviewPayload, S as ServerContext, T as TrackPayload } from './types-DWa2kNUy.js';
1
+ import { D as DumbledorClientConfig, a as DumbledorClient, R as ResolvedDumbledorConfig, C as CollectPayloadInput, b as CollectResponse, P as PageviewInput, c as CollectPayload } from './types-jDs6E55a.js';
2
+ export { d as CollectEventType, e as DumbledorServerConfig, I as IdentifyPayload, f as PageviewPayload, S as ServerContext, T as TrackPayload } from './types-jDs6E55a.js';
3
3
 
4
- declare function createTransport(config: ResolvedDumbledorConfig): (payload: CollectPayloadInput) => Promise<CollectResponse | void>;
4
+ type SendOptions = {
5
+ clearCache?: boolean;
6
+ };
7
+ declare function createTransport(config: ResolvedDumbledorConfig): (payload: CollectPayloadInput, options?: SendOptions) => Promise<CollectResponse | void>;
5
8
  declare function createClient(config: DumbledorClientConfig): DumbledorClient;
6
9
  declare function init(config: DumbledorClientConfig): DumbledorClient;
7
10
  declare function getClient(): DumbledorClient;
package/dist/index.js CHANGED
@@ -57,6 +57,7 @@ function isTrackingDisabled(honorDoNotTrack) {
57
57
  }
58
58
 
59
59
  // src/client.ts
60
+ var CACHE_HEADER = "x-dumbledor-cache";
60
61
  function defaultPageviewInput() {
61
62
  if (typeof window === "undefined" || typeof document === "undefined") {
62
63
  return {};
@@ -73,15 +74,23 @@ function defaultPageviewInput() {
73
74
  function createTransport(config) {
74
75
  const endpoint = `${config.ingestUrl}/v1/collect`;
75
76
  const fetchImpl = resolveFetch(config.fetch);
76
- return async function send(payload) {
77
+ let cache;
78
+ return async function send(payload, options) {
77
79
  if (config.disabled || isTrackingDisabled(config.honorDoNotTrack)) {
78
80
  return;
79
81
  }
82
+ if (options?.clearCache) {
83
+ cache = void 0;
84
+ }
80
85
  const body = withWebsiteId(payload, config.websiteId);
86
+ const headers = { "Content-Type": "application/json" };
87
+ if (cache) {
88
+ headers[CACHE_HEADER] = cache;
89
+ }
81
90
  try {
82
91
  const response = await fetchImpl(endpoint, {
83
92
  method: "POST",
84
- headers: { "Content-Type": "application/json" },
93
+ headers,
85
94
  body: JSON.stringify(body),
86
95
  keepalive: true,
87
96
  credentials: "omit",
@@ -93,7 +102,11 @@ function createTransport(config) {
93
102
  error: `Ingest request failed with status ${response.status}`
94
103
  };
95
104
  }
96
- return await response.json();
105
+ const data = await response.json();
106
+ if (data.cache) {
107
+ cache = data.cache;
108
+ }
109
+ return data;
97
110
  } catch {
98
111
  return {
99
112
  ok: false,
@@ -134,11 +147,14 @@ function createClient(config) {
134
147
  });
135
148
  },
136
149
  identify(userId, traits) {
137
- void send({
138
- type: "identify",
139
- userId,
140
- traits: traits ?? {}
141
- });
150
+ void send(
151
+ {
152
+ type: "identify",
153
+ userId,
154
+ traits: traits ?? {}
155
+ },
156
+ { clearCache: true }
157
+ );
142
158
  }
143
159
  };
144
160
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/config.ts","../src/dnt.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export const DEFAULT_INGEST_URL = \"https://ingest.dumbledor.com\";\n\nexport const UUID_PATTERN =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n","import { DEFAULT_INGEST_URL, UUID_PATTERN } from \"./constants\";\nimport type {\n CollectPayload,\n CollectPayloadInput,\n DumbledorClientConfig,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nexport class DumbledorConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DumbledorConfigError\";\n }\n}\n\nexport function normalizeIngestUrl(value?: string): string {\n const raw = value?.trim() || DEFAULT_INGEST_URL;\n return raw.replace(/\\/$/, \"\");\n}\n\nexport function assertClientConfig(config: DumbledorClientConfig): ResolvedDumbledorConfig {\n const websiteId = config.websiteId?.trim();\n\n if (!websiteId) {\n throw new DumbledorConfigError(\"websiteId is required.\");\n }\n\n if (!UUID_PATTERN.test(websiteId)) {\n throw new DumbledorConfigError(\"websiteId must be a valid UUID.\");\n }\n\n return {\n websiteId,\n ingestUrl: normalizeIngestUrl(config.ingestUrl),\n honorDoNotTrack: config.honorDoNotTrack ?? false,\n disabled: config.disabled ?? false,\n fetch: config.fetch,\n };\n}\n\nexport function withWebsiteId(\n payload: CollectPayloadInput,\n websiteId: string,\n): CollectPayload {\n return {\n ...payload,\n websiteId,\n };\n}\n\nexport function resolveFetch(fetchImpl?: typeof fetch): typeof fetch {\n const resolved = fetchImpl ?? globalThis.fetch;\n if (!resolved) {\n throw new DumbledorConfigError(\"fetch is not available in this runtime.\");\n }\n\n return resolved;\n}\n","type NavigatorWithMsDnt = Navigator & {\n msDoNotTrack?: string | number | null;\n};\n\ntype WindowWithDnt = Window & {\n doNotTrack?: string | number | null;\n};\n\nexport function hasDoNotTrack(): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n\n const win = window as WindowWithDnt;\n const dnt =\n win.doNotTrack ??\n win.navigator.doNotTrack ??\n (win.navigator as NavigatorWithMsDnt).msDoNotTrack;\n\n return dnt === 1 || dnt === \"1\" || dnt === \"yes\";\n}\n\nexport function isTrackingDisabled(honorDoNotTrack: boolean): boolean {\n return honorDoNotTrack && hasDoNotTrack();\n}\n","import { assertClientConfig, resolveFetch, withWebsiteId } from \"./config\";\nimport { isTrackingDisabled } from \"./dnt\";\nimport type {\n CollectPayloadInput,\n CollectResponse,\n DumbledorClient,\n DumbledorClientConfig,\n PageviewInput,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nfunction defaultPageviewInput(): PageviewInput {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n return {};\n }\n\n return {\n url: window.location.href,\n referrer: document.referrer || undefined,\n title: document.title,\n hostname: window.location.hostname,\n language: navigator.language,\n screen: typeof screen !== \"undefined\" ? `${screen.width}x${screen.height}` : undefined,\n };\n}\n\nexport function createTransport(config: ResolvedDumbledorConfig) {\n const endpoint = `${config.ingestUrl}/v1/collect`;\n const fetchImpl = resolveFetch(config.fetch);\n\n return async function send(payload: CollectPayloadInput): Promise<CollectResponse | void> {\n if (config.disabled || isTrackingDisabled(config.honorDoNotTrack)) {\n return;\n }\n\n const body = withWebsiteId(payload, config.websiteId);\n\n try {\n const response = await fetchImpl(endpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n keepalive: true,\n credentials: \"omit\",\n mode: \"cors\",\n });\n\n if (!response.ok) {\n return {\n ok: false,\n error: `Ingest request failed with status ${response.status}`,\n };\n }\n\n return (await response.json()) as CollectResponse;\n } catch {\n return {\n ok: false,\n error: \"Ingest request failed\",\n };\n }\n };\n}\n\nexport function createClient(config: DumbledorClientConfig): DumbledorClient {\n const resolved = assertClientConfig(config);\n const send = createTransport(resolved);\n\n return {\n config: resolved,\n page(input = {}) {\n const defaults = defaultPageviewInput();\n const url = input.url ?? defaults.url;\n if (!url) {\n return;\n }\n\n void send({\n type: \"pageview\",\n url,\n referrer: input.referrer ?? defaults.referrer,\n title: input.title ?? defaults.title,\n hostname: input.hostname ?? defaults.hostname,\n language: input.language ?? defaults.language,\n screen: input.screen ?? defaults.screen,\n });\n },\n track(name, properties) {\n const defaults = defaultPageviewInput();\n void send({\n type: \"track\",\n name,\n properties: properties ?? {},\n url: defaults.url,\n hostname: defaults.hostname,\n });\n },\n identify(userId, traits) {\n void send({\n type: \"identify\",\n userId,\n traits: traits ?? {},\n });\n },\n };\n}\n\nlet defaultClient: DumbledorClient | null = null;\n\nexport function init(config: DumbledorClientConfig): DumbledorClient {\n defaultClient = createClient(config);\n return defaultClient;\n}\n\nexport function getClient(): DumbledorClient {\n if (!defaultClient) {\n throw new Error(\n \"Dumbledor is not initialized. Call init(), wrap with DumbledorProvider, or createClient() first.\",\n );\n }\n\n return defaultClient;\n}\n\nexport function page(input?: PageviewInput): void {\n getClient().page(input);\n}\n\nexport function track(name: string, properties?: Record<string, unknown>): void {\n getClient().track(name, properties);\n}\n\nexport function identify(userId: string, traits?: Record<string, unknown>): void {\n getClient().identify(userId, traits);\n}\n"]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/config.ts","../src/dnt.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export const DEFAULT_INGEST_URL = \"https://ingest.dumbledor.com\";\n\nexport const UUID_PATTERN =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n","import { DEFAULT_INGEST_URL, UUID_PATTERN } from \"./constants\";\nimport type {\n CollectPayload,\n CollectPayloadInput,\n DumbledorClientConfig,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nexport class DumbledorConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DumbledorConfigError\";\n }\n}\n\nexport function normalizeIngestUrl(value?: string): string {\n const raw = value?.trim() || DEFAULT_INGEST_URL;\n return raw.replace(/\\/$/, \"\");\n}\n\nexport function assertClientConfig(config: DumbledorClientConfig): ResolvedDumbledorConfig {\n const websiteId = config.websiteId?.trim();\n\n if (!websiteId) {\n throw new DumbledorConfigError(\"websiteId is required.\");\n }\n\n if (!UUID_PATTERN.test(websiteId)) {\n throw new DumbledorConfigError(\"websiteId must be a valid UUID.\");\n }\n\n return {\n websiteId,\n ingestUrl: normalizeIngestUrl(config.ingestUrl),\n honorDoNotTrack: config.honorDoNotTrack ?? false,\n disabled: config.disabled ?? false,\n fetch: config.fetch,\n };\n}\n\nexport function withWebsiteId(\n payload: CollectPayloadInput,\n websiteId: string,\n): CollectPayload {\n return {\n ...payload,\n websiteId,\n };\n}\n\nexport function resolveFetch(fetchImpl?: typeof fetch): typeof fetch {\n const resolved = fetchImpl ?? globalThis.fetch;\n if (!resolved) {\n throw new DumbledorConfigError(\"fetch is not available in this runtime.\");\n }\n\n return resolved;\n}\n","type NavigatorWithMsDnt = Navigator & {\n msDoNotTrack?: string | number | null;\n};\n\ntype WindowWithDnt = Window & {\n doNotTrack?: string | number | null;\n};\n\nexport function hasDoNotTrack(): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n\n const win = window as WindowWithDnt;\n const dnt =\n win.doNotTrack ??\n win.navigator.doNotTrack ??\n (win.navigator as NavigatorWithMsDnt).msDoNotTrack;\n\n return dnt === 1 || dnt === \"1\" || dnt === \"yes\";\n}\n\nexport function isTrackingDisabled(honorDoNotTrack: boolean): boolean {\n return honorDoNotTrack && hasDoNotTrack();\n}\n","import { assertClientConfig, resolveFetch, withWebsiteId } from \"./config\";\nimport { isTrackingDisabled } from \"./dnt\";\nimport type {\n CollectPayloadInput,\n CollectResponse,\n DumbledorClient,\n DumbledorClientConfig,\n PageviewInput,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nconst CACHE_HEADER = \"x-dumbledor-cache\";\n\nfunction defaultPageviewInput(): PageviewInput {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n return {};\n }\n\n return {\n url: window.location.href,\n referrer: document.referrer || undefined,\n title: document.title,\n hostname: window.location.hostname,\n language: navigator.language,\n screen: typeof screen !== \"undefined\" ? `${screen.width}x${screen.height}` : undefined,\n };\n}\n\ntype SendOptions = {\n clearCache?: boolean;\n};\n\nexport function createTransport(config: ResolvedDumbledorConfig) {\n const endpoint = `${config.ingestUrl}/v1/collect`;\n const fetchImpl = resolveFetch(config.fetch);\n let cache: string | undefined;\n\n return async function send(\n payload: CollectPayloadInput,\n options?: SendOptions,\n ): Promise<CollectResponse | void> {\n if (config.disabled || isTrackingDisabled(config.honorDoNotTrack)) {\n return;\n }\n\n if (options?.clearCache) {\n cache = undefined;\n }\n\n const body = withWebsiteId(payload, config.websiteId);\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (cache) {\n headers[CACHE_HEADER] = cache;\n }\n\n try {\n const response = await fetchImpl(endpoint, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n keepalive: true,\n credentials: \"omit\",\n mode: \"cors\",\n });\n\n if (!response.ok) {\n return {\n ok: false,\n error: `Ingest request failed with status ${response.status}`,\n };\n }\n\n const data = (await response.json()) as CollectResponse;\n if (data.cache) {\n cache = data.cache;\n }\n\n return data;\n } catch {\n return {\n ok: false,\n error: \"Ingest request failed\",\n };\n }\n };\n}\n\nexport function createClient(config: DumbledorClientConfig): DumbledorClient {\n const resolved = assertClientConfig(config);\n const send = createTransport(resolved);\n\n return {\n config: resolved,\n page(input = {}) {\n const defaults = defaultPageviewInput();\n const url = input.url ?? defaults.url;\n if (!url) {\n return;\n }\n\n void send({\n type: \"pageview\",\n url,\n referrer: input.referrer ?? defaults.referrer,\n title: input.title ?? defaults.title,\n hostname: input.hostname ?? defaults.hostname,\n language: input.language ?? defaults.language,\n screen: input.screen ?? defaults.screen,\n });\n },\n track(name, properties) {\n const defaults = defaultPageviewInput();\n void send({\n type: \"track\",\n name,\n properties: properties ?? {},\n url: defaults.url,\n hostname: defaults.hostname,\n });\n },\n identify(userId, traits) {\n void send(\n {\n type: \"identify\",\n userId,\n traits: traits ?? {},\n },\n { clearCache: true },\n );\n },\n };\n}\n\nlet defaultClient: DumbledorClient | null = null;\n\nexport function init(config: DumbledorClientConfig): DumbledorClient {\n defaultClient = createClient(config);\n return defaultClient;\n}\n\nexport function getClient(): DumbledorClient {\n if (!defaultClient) {\n throw new Error(\n \"Dumbledor is not initialized. Call init(), wrap with DumbledorProvider, or createClient() first.\",\n );\n }\n\n return defaultClient;\n}\n\nexport function page(input?: PageviewInput): void {\n getClient().page(input);\n}\n\nexport function track(name: string, properties?: Record<string, unknown>): void {\n getClient().track(name, properties);\n}\n\nexport function identify(userId: string, traits?: Record<string, unknown>): void {\n getClient().identify(userId, traits);\n}\n"]}
@@ -64,6 +64,7 @@ function isTrackingDisabled(honorDoNotTrack) {
64
64
  }
65
65
 
66
66
  // src/client.ts
67
+ var CACHE_HEADER = "x-dumbledor-cache";
67
68
  function defaultPageviewInput() {
68
69
  if (typeof window === "undefined" || typeof document === "undefined") {
69
70
  return {};
@@ -80,15 +81,23 @@ function defaultPageviewInput() {
80
81
  function createTransport(config) {
81
82
  const endpoint = `${config.ingestUrl}/v1/collect`;
82
83
  const fetchImpl = resolveFetch(config.fetch);
83
- return async function send(payload) {
84
+ let cache;
85
+ return async function send(payload, options) {
84
86
  if (config.disabled || isTrackingDisabled(config.honorDoNotTrack)) {
85
87
  return;
86
88
  }
89
+ if (options?.clearCache) {
90
+ cache = void 0;
91
+ }
87
92
  const body = withWebsiteId(payload, config.websiteId);
93
+ const headers = { "Content-Type": "application/json" };
94
+ if (cache) {
95
+ headers[CACHE_HEADER] = cache;
96
+ }
88
97
  try {
89
98
  const response = await fetchImpl(endpoint, {
90
99
  method: "POST",
91
- headers: { "Content-Type": "application/json" },
100
+ headers,
92
101
  body: JSON.stringify(body),
93
102
  keepalive: true,
94
103
  credentials: "omit",
@@ -100,7 +109,11 @@ function createTransport(config) {
100
109
  error: `Ingest request failed with status ${response.status}`
101
110
  };
102
111
  }
103
- return await response.json();
112
+ const data = await response.json();
113
+ if (data.cache) {
114
+ cache = data.cache;
115
+ }
116
+ return data;
104
117
  } catch {
105
118
  return {
106
119
  ok: false,
@@ -141,11 +154,14 @@ function createClient(config) {
141
154
  });
142
155
  },
143
156
  identify(userId, traits) {
144
- void send({
145
- type: "identify",
146
- userId,
147
- traits: traits ?? {}
148
- });
157
+ void send(
158
+ {
159
+ type: "identify",
160
+ userId,
161
+ traits: traits ?? {}
162
+ },
163
+ { clearCache: true }
164
+ );
149
165
  }
150
166
  };
151
167
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/constants.ts","../../src/config.ts","../../src/dnt.ts","../../src/client.ts","../../src/react/context.tsx","../../src/react/page-view.tsx","../../src/react/provider.tsx","../../src/react/hooks.ts","../../src/next/index.tsx"],"names":["createContext","useContext","useRef","useEffect","useMemo","useCallback","usePathname","useSearchParams","jsx"],"mappings":"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","file":"index.cjs","sourcesContent":["export const DEFAULT_INGEST_URL = \"https://ingest.dumbledor.com\";\n\nexport const UUID_PATTERN =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n","import { DEFAULT_INGEST_URL, UUID_PATTERN } from \"./constants\";\nimport type {\n CollectPayload,\n CollectPayloadInput,\n DumbledorClientConfig,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nexport class DumbledorConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DumbledorConfigError\";\n }\n}\n\nexport function normalizeIngestUrl(value?: string): string {\n const raw = value?.trim() || DEFAULT_INGEST_URL;\n return raw.replace(/\\/$/, \"\");\n}\n\nexport function assertClientConfig(config: DumbledorClientConfig): ResolvedDumbledorConfig {\n const websiteId = config.websiteId?.trim();\n\n if (!websiteId) {\n throw new DumbledorConfigError(\"websiteId is required.\");\n }\n\n if (!UUID_PATTERN.test(websiteId)) {\n throw new DumbledorConfigError(\"websiteId must be a valid UUID.\");\n }\n\n return {\n websiteId,\n ingestUrl: normalizeIngestUrl(config.ingestUrl),\n honorDoNotTrack: config.honorDoNotTrack ?? false,\n disabled: config.disabled ?? false,\n fetch: config.fetch,\n };\n}\n\nexport function withWebsiteId(\n payload: CollectPayloadInput,\n websiteId: string,\n): CollectPayload {\n return {\n ...payload,\n websiteId,\n };\n}\n\nexport function resolveFetch(fetchImpl?: typeof fetch): typeof fetch {\n const resolved = fetchImpl ?? globalThis.fetch;\n if (!resolved) {\n throw new DumbledorConfigError(\"fetch is not available in this runtime.\");\n }\n\n return resolved;\n}\n","type NavigatorWithMsDnt = Navigator & {\n msDoNotTrack?: string | number | null;\n};\n\ntype WindowWithDnt = Window & {\n doNotTrack?: string | number | null;\n};\n\nexport function hasDoNotTrack(): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n\n const win = window as WindowWithDnt;\n const dnt =\n win.doNotTrack ??\n win.navigator.doNotTrack ??\n (win.navigator as NavigatorWithMsDnt).msDoNotTrack;\n\n return dnt === 1 || dnt === \"1\" || dnt === \"yes\";\n}\n\nexport function isTrackingDisabled(honorDoNotTrack: boolean): boolean {\n return honorDoNotTrack && hasDoNotTrack();\n}\n","import { assertClientConfig, resolveFetch, withWebsiteId } from \"./config\";\nimport { isTrackingDisabled } from \"./dnt\";\nimport type {\n CollectPayloadInput,\n CollectResponse,\n DumbledorClient,\n DumbledorClientConfig,\n PageviewInput,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nfunction defaultPageviewInput(): PageviewInput {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n return {};\n }\n\n return {\n url: window.location.href,\n referrer: document.referrer || undefined,\n title: document.title,\n hostname: window.location.hostname,\n language: navigator.language,\n screen: typeof screen !== \"undefined\" ? `${screen.width}x${screen.height}` : undefined,\n };\n}\n\nexport function createTransport(config: ResolvedDumbledorConfig) {\n const endpoint = `${config.ingestUrl}/v1/collect`;\n const fetchImpl = resolveFetch(config.fetch);\n\n return async function send(payload: CollectPayloadInput): Promise<CollectResponse | void> {\n if (config.disabled || isTrackingDisabled(config.honorDoNotTrack)) {\n return;\n }\n\n const body = withWebsiteId(payload, config.websiteId);\n\n try {\n const response = await fetchImpl(endpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n keepalive: true,\n credentials: \"omit\",\n mode: \"cors\",\n });\n\n if (!response.ok) {\n return {\n ok: false,\n error: `Ingest request failed with status ${response.status}`,\n };\n }\n\n return (await response.json()) as CollectResponse;\n } catch {\n return {\n ok: false,\n error: \"Ingest request failed\",\n };\n }\n };\n}\n\nexport function createClient(config: DumbledorClientConfig): DumbledorClient {\n const resolved = assertClientConfig(config);\n const send = createTransport(resolved);\n\n return {\n config: resolved,\n page(input = {}) {\n const defaults = defaultPageviewInput();\n const url = input.url ?? defaults.url;\n if (!url) {\n return;\n }\n\n void send({\n type: \"pageview\",\n url,\n referrer: input.referrer ?? defaults.referrer,\n title: input.title ?? defaults.title,\n hostname: input.hostname ?? defaults.hostname,\n language: input.language ?? defaults.language,\n screen: input.screen ?? defaults.screen,\n });\n },\n track(name, properties) {\n const defaults = defaultPageviewInput();\n void send({\n type: \"track\",\n name,\n properties: properties ?? {},\n url: defaults.url,\n hostname: defaults.hostname,\n });\n },\n identify(userId, traits) {\n void send({\n type: \"identify\",\n userId,\n traits: traits ?? {},\n });\n },\n };\n}\n\nlet defaultClient: DumbledorClient | null = null;\n\nexport function init(config: DumbledorClientConfig): DumbledorClient {\n defaultClient = createClient(config);\n return defaultClient;\n}\n\nexport function getClient(): DumbledorClient {\n if (!defaultClient) {\n throw new Error(\n \"Dumbledor is not initialized. Call init(), wrap with DumbledorProvider, or createClient() first.\",\n );\n }\n\n return defaultClient;\n}\n\nexport function page(input?: PageviewInput): void {\n getClient().page(input);\n}\n\nexport function track(name: string, properties?: Record<string, unknown>): void {\n getClient().track(name, properties);\n}\n\nexport function identify(userId: string, traits?: Record<string, unknown>): void {\n getClient().identify(userId, traits);\n}\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport { getClient } from \"../client\";\nimport type { DumbledorClient } from \"../types\";\n\nexport const DumbledorContext = createContext<DumbledorClient | null>(null);\n\nexport function useDumbledor(): DumbledorClient {\n const client = useContext(DumbledorContext);\n if (client) {\n return client;\n }\n\n return getClient();\n}\n","\"use client\";\n\nimport { useEffect, useRef } from \"react\";\nimport { useDumbledor } from \"./context\";\n\nexport type PageViewProps = {\n /** Route pathname. When omitted, falls back to `window.location.pathname`. */\n pathname?: string;\n /** Track the first render. Default: `true`. */\n trackInitialView?: boolean;\n};\n\nexport function PageView({ pathname, trackInitialView = true }: PageViewProps) {\n const client = useDumbledor();\n const lastPathRef = useRef<string | null>(null);\n\n useEffect(() => {\n const nextPath =\n pathname ??\n (typeof window !== \"undefined\"\n ? `${window.location.pathname}${window.location.search}`\n : null);\n\n if (!nextPath || lastPathRef.current === nextPath) {\n return;\n }\n\n const isFirstView = lastPathRef.current === null;\n lastPathRef.current = nextPath;\n\n if (isFirstView && !trackInitialView) {\n return;\n }\n\n client.page();\n }, [client, pathname, trackInitialView]);\n\n return null;\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { init } from \"../client\";\nimport type { DumbledorClientConfig } from \"../types\";\nimport { DumbledorContext } from \"./context\";\n\nexport type DumbledorProviderProps = DumbledorClientConfig & {\n children: React.ReactNode;\n};\n\nexport function DumbledorProvider({\n children,\n websiteId,\n ingestUrl,\n honorDoNotTrack,\n disabled,\n fetch,\n}: DumbledorProviderProps) {\n const client = useMemo(\n () =>\n init({\n websiteId,\n ingestUrl,\n honorDoNotTrack,\n disabled,\n fetch,\n }),\n [websiteId, ingestUrl, honorDoNotTrack, disabled, fetch],\n );\n\n return <DumbledorContext.Provider value={client}>{children}</DumbledorContext.Provider>;\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { useDumbledor } from \"./context\";\n\nexport function useTrack() {\n const client = useDumbledor();\n return useCallback(\n (name: string, properties?: Record<string, unknown>) => {\n client.track(name, properties);\n },\n [client],\n );\n}\n\nexport function useIdentify() {\n const client = useDumbledor();\n return useCallback(\n (userId: string, traits?: Record<string, unknown>) => {\n client.identify(userId, traits);\n },\n [client],\n );\n}\n\nexport function usePage() {\n const client = useDumbledor();\n return useCallback(\n (input?: Parameters<typeof client.page>[0]) => {\n client.page(input);\n },\n [client],\n );\n}\n","\"use client\";\n\nimport { usePathname, useSearchParams } from \"next/navigation\";\nimport { useMemo } from \"react\";\nimport { PageView } from \"../react/page-view\";\nimport { DumbledorProvider, type DumbledorProviderProps } from \"../react/provider\";\n\nexport type AppRouterPageViewProps = {\n trackInitialView?: boolean;\n};\n\nexport function AppRouterPageView({ trackInitialView = true }: AppRouterPageViewProps) {\n const pathname = usePathname();\n const searchParams = useSearchParams();\n const routeKey = useMemo(() => {\n const query = searchParams.toString();\n return query ? `${pathname}?${query}` : pathname;\n }, [pathname, searchParams]);\n\n return <PageView pathname={routeKey} trackInitialView={trackInitialView} />;\n}\n\nexport { DumbledorProvider, type DumbledorProviderProps };\nexport { PageView, useDumbledor, useIdentify, usePage, useTrack } from \"../react\";\n"]}
1
+ {"version":3,"sources":["../../src/constants.ts","../../src/config.ts","../../src/dnt.ts","../../src/client.ts","../../src/react/context.tsx","../../src/react/page-view.tsx","../../src/react/provider.tsx","../../src/react/hooks.ts","../../src/next/index.tsx"],"names":["createContext","useContext","useRef","useEffect","useMemo","useCallback","usePathname","useSearchParams","jsx"],"mappings":"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","file":"index.cjs","sourcesContent":["export const DEFAULT_INGEST_URL = \"https://ingest.dumbledor.com\";\n\nexport const UUID_PATTERN =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n","import { DEFAULT_INGEST_URL, UUID_PATTERN } from \"./constants\";\nimport type {\n CollectPayload,\n CollectPayloadInput,\n DumbledorClientConfig,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nexport class DumbledorConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DumbledorConfigError\";\n }\n}\n\nexport function normalizeIngestUrl(value?: string): string {\n const raw = value?.trim() || DEFAULT_INGEST_URL;\n return raw.replace(/\\/$/, \"\");\n}\n\nexport function assertClientConfig(config: DumbledorClientConfig): ResolvedDumbledorConfig {\n const websiteId = config.websiteId?.trim();\n\n if (!websiteId) {\n throw new DumbledorConfigError(\"websiteId is required.\");\n }\n\n if (!UUID_PATTERN.test(websiteId)) {\n throw new DumbledorConfigError(\"websiteId must be a valid UUID.\");\n }\n\n return {\n websiteId,\n ingestUrl: normalizeIngestUrl(config.ingestUrl),\n honorDoNotTrack: config.honorDoNotTrack ?? false,\n disabled: config.disabled ?? false,\n fetch: config.fetch,\n };\n}\n\nexport function withWebsiteId(\n payload: CollectPayloadInput,\n websiteId: string,\n): CollectPayload {\n return {\n ...payload,\n websiteId,\n };\n}\n\nexport function resolveFetch(fetchImpl?: typeof fetch): typeof fetch {\n const resolved = fetchImpl ?? globalThis.fetch;\n if (!resolved) {\n throw new DumbledorConfigError(\"fetch is not available in this runtime.\");\n }\n\n return resolved;\n}\n","type NavigatorWithMsDnt = Navigator & {\n msDoNotTrack?: string | number | null;\n};\n\ntype WindowWithDnt = Window & {\n doNotTrack?: string | number | null;\n};\n\nexport function hasDoNotTrack(): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n\n const win = window as WindowWithDnt;\n const dnt =\n win.doNotTrack ??\n win.navigator.doNotTrack ??\n (win.navigator as NavigatorWithMsDnt).msDoNotTrack;\n\n return dnt === 1 || dnt === \"1\" || dnt === \"yes\";\n}\n\nexport function isTrackingDisabled(honorDoNotTrack: boolean): boolean {\n return honorDoNotTrack && hasDoNotTrack();\n}\n","import { assertClientConfig, resolveFetch, withWebsiteId } from \"./config\";\nimport { isTrackingDisabled } from \"./dnt\";\nimport type {\n CollectPayloadInput,\n CollectResponse,\n DumbledorClient,\n DumbledorClientConfig,\n PageviewInput,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nconst CACHE_HEADER = \"x-dumbledor-cache\";\n\nfunction defaultPageviewInput(): PageviewInput {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n return {};\n }\n\n return {\n url: window.location.href,\n referrer: document.referrer || undefined,\n title: document.title,\n hostname: window.location.hostname,\n language: navigator.language,\n screen: typeof screen !== \"undefined\" ? `${screen.width}x${screen.height}` : undefined,\n };\n}\n\ntype SendOptions = {\n clearCache?: boolean;\n};\n\nexport function createTransport(config: ResolvedDumbledorConfig) {\n const endpoint = `${config.ingestUrl}/v1/collect`;\n const fetchImpl = resolveFetch(config.fetch);\n let cache: string | undefined;\n\n return async function send(\n payload: CollectPayloadInput,\n options?: SendOptions,\n ): Promise<CollectResponse | void> {\n if (config.disabled || isTrackingDisabled(config.honorDoNotTrack)) {\n return;\n }\n\n if (options?.clearCache) {\n cache = undefined;\n }\n\n const body = withWebsiteId(payload, config.websiteId);\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (cache) {\n headers[CACHE_HEADER] = cache;\n }\n\n try {\n const response = await fetchImpl(endpoint, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n keepalive: true,\n credentials: \"omit\",\n mode: \"cors\",\n });\n\n if (!response.ok) {\n return {\n ok: false,\n error: `Ingest request failed with status ${response.status}`,\n };\n }\n\n const data = (await response.json()) as CollectResponse;\n if (data.cache) {\n cache = data.cache;\n }\n\n return data;\n } catch {\n return {\n ok: false,\n error: \"Ingest request failed\",\n };\n }\n };\n}\n\nexport function createClient(config: DumbledorClientConfig): DumbledorClient {\n const resolved = assertClientConfig(config);\n const send = createTransport(resolved);\n\n return {\n config: resolved,\n page(input = {}) {\n const defaults = defaultPageviewInput();\n const url = input.url ?? defaults.url;\n if (!url) {\n return;\n }\n\n void send({\n type: \"pageview\",\n url,\n referrer: input.referrer ?? defaults.referrer,\n title: input.title ?? defaults.title,\n hostname: input.hostname ?? defaults.hostname,\n language: input.language ?? defaults.language,\n screen: input.screen ?? defaults.screen,\n });\n },\n track(name, properties) {\n const defaults = defaultPageviewInput();\n void send({\n type: \"track\",\n name,\n properties: properties ?? {},\n url: defaults.url,\n hostname: defaults.hostname,\n });\n },\n identify(userId, traits) {\n void send(\n {\n type: \"identify\",\n userId,\n traits: traits ?? {},\n },\n { clearCache: true },\n );\n },\n };\n}\n\nlet defaultClient: DumbledorClient | null = null;\n\nexport function init(config: DumbledorClientConfig): DumbledorClient {\n defaultClient = createClient(config);\n return defaultClient;\n}\n\nexport function getClient(): DumbledorClient {\n if (!defaultClient) {\n throw new Error(\n \"Dumbledor is not initialized. Call init(), wrap with DumbledorProvider, or createClient() first.\",\n );\n }\n\n return defaultClient;\n}\n\nexport function page(input?: PageviewInput): void {\n getClient().page(input);\n}\n\nexport function track(name: string, properties?: Record<string, unknown>): void {\n getClient().track(name, properties);\n}\n\nexport function identify(userId: string, traits?: Record<string, unknown>): void {\n getClient().identify(userId, traits);\n}\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport { getClient } from \"../client\";\nimport type { DumbledorClient } from \"../types\";\n\nexport const DumbledorContext = createContext<DumbledorClient | null>(null);\n\nexport function useDumbledor(): DumbledorClient {\n const client = useContext(DumbledorContext);\n if (client) {\n return client;\n }\n\n return getClient();\n}\n","\"use client\";\n\nimport { useEffect, useRef } from \"react\";\nimport { useDumbledor } from \"./context\";\n\nexport type PageViewProps = {\n /** Route pathname. When omitted, falls back to `window.location.pathname`. */\n pathname?: string;\n /** Track the first render. Default: `true`. */\n trackInitialView?: boolean;\n};\n\nexport function PageView({ pathname, trackInitialView = true }: PageViewProps) {\n const client = useDumbledor();\n const lastPathRef = useRef<string | null>(null);\n\n useEffect(() => {\n const nextPath =\n pathname ??\n (typeof window !== \"undefined\"\n ? `${window.location.pathname}${window.location.search}`\n : null);\n\n if (!nextPath || lastPathRef.current === nextPath) {\n return;\n }\n\n const isFirstView = lastPathRef.current === null;\n lastPathRef.current = nextPath;\n\n if (isFirstView && !trackInitialView) {\n return;\n }\n\n client.page();\n }, [client, pathname, trackInitialView]);\n\n return null;\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { init } from \"../client\";\nimport type { DumbledorClientConfig } from \"../types\";\nimport { DumbledorContext } from \"./context\";\n\nexport type DumbledorProviderProps = DumbledorClientConfig & {\n children: React.ReactNode;\n};\n\nexport function DumbledorProvider({\n children,\n websiteId,\n ingestUrl,\n honorDoNotTrack,\n disabled,\n fetch,\n}: DumbledorProviderProps) {\n const client = useMemo(\n () =>\n init({\n websiteId,\n ingestUrl,\n honorDoNotTrack,\n disabled,\n fetch,\n }),\n [websiteId, ingestUrl, honorDoNotTrack, disabled, fetch],\n );\n\n return <DumbledorContext.Provider value={client}>{children}</DumbledorContext.Provider>;\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { useDumbledor } from \"./context\";\n\nexport function useTrack() {\n const client = useDumbledor();\n return useCallback(\n (name: string, properties?: Record<string, unknown>) => {\n client.track(name, properties);\n },\n [client],\n );\n}\n\nexport function useIdentify() {\n const client = useDumbledor();\n return useCallback(\n (userId: string, traits?: Record<string, unknown>) => {\n client.identify(userId, traits);\n },\n [client],\n );\n}\n\nexport function usePage() {\n const client = useDumbledor();\n return useCallback(\n (input?: Parameters<typeof client.page>[0]) => {\n client.page(input);\n },\n [client],\n );\n}\n","\"use client\";\n\nimport { usePathname, useSearchParams } from \"next/navigation\";\nimport { useMemo } from \"react\";\nimport { PageView } from \"../react/page-view\";\nimport { DumbledorProvider, type DumbledorProviderProps } from \"../react/provider\";\n\nexport type AppRouterPageViewProps = {\n trackInitialView?: boolean;\n};\n\nexport function AppRouterPageView({ trackInitialView = true }: AppRouterPageViewProps) {\n const pathname = usePathname();\n const searchParams = useSearchParams();\n const routeKey = useMemo(() => {\n const query = searchParams.toString();\n return query ? `${pathname}?${query}` : pathname;\n }, [pathname, searchParams]);\n\n return <PageView pathname={routeKey} trackInitialView={trackInitialView} />;\n}\n\nexport { DumbledorProvider, type DumbledorProviderProps };\nexport { PageView, useDumbledor, useIdentify, usePage, useTrack } from \"../react\";\n"]}
@@ -62,6 +62,7 @@ function isTrackingDisabled(honorDoNotTrack) {
62
62
  }
63
63
 
64
64
  // src/client.ts
65
+ var CACHE_HEADER = "x-dumbledor-cache";
65
66
  function defaultPageviewInput() {
66
67
  if (typeof window === "undefined" || typeof document === "undefined") {
67
68
  return {};
@@ -78,15 +79,23 @@ function defaultPageviewInput() {
78
79
  function createTransport(config) {
79
80
  const endpoint = `${config.ingestUrl}/v1/collect`;
80
81
  const fetchImpl = resolveFetch(config.fetch);
81
- return async function send(payload) {
82
+ let cache;
83
+ return async function send(payload, options) {
82
84
  if (config.disabled || isTrackingDisabled(config.honorDoNotTrack)) {
83
85
  return;
84
86
  }
87
+ if (options?.clearCache) {
88
+ cache = void 0;
89
+ }
85
90
  const body = withWebsiteId(payload, config.websiteId);
91
+ const headers = { "Content-Type": "application/json" };
92
+ if (cache) {
93
+ headers[CACHE_HEADER] = cache;
94
+ }
86
95
  try {
87
96
  const response = await fetchImpl(endpoint, {
88
97
  method: "POST",
89
- headers: { "Content-Type": "application/json" },
98
+ headers,
90
99
  body: JSON.stringify(body),
91
100
  keepalive: true,
92
101
  credentials: "omit",
@@ -98,7 +107,11 @@ function createTransport(config) {
98
107
  error: `Ingest request failed with status ${response.status}`
99
108
  };
100
109
  }
101
- return await response.json();
110
+ const data = await response.json();
111
+ if (data.cache) {
112
+ cache = data.cache;
113
+ }
114
+ return data;
102
115
  } catch {
103
116
  return {
104
117
  ok: false,
@@ -139,11 +152,14 @@ function createClient(config) {
139
152
  });
140
153
  },
141
154
  identify(userId, traits) {
142
- void send({
143
- type: "identify",
144
- userId,
145
- traits: traits ?? {}
146
- });
155
+ void send(
156
+ {
157
+ type: "identify",
158
+ userId,
159
+ traits: traits ?? {}
160
+ },
161
+ { clearCache: true }
162
+ );
147
163
  }
148
164
  };
149
165
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/constants.ts","../../src/config.ts","../../src/dnt.ts","../../src/client.ts","../../src/react/context.tsx","../../src/react/page-view.tsx","../../src/react/provider.tsx","../../src/react/hooks.ts","../../src/next/index.tsx"],"names":["useMemo","jsx"],"mappings":"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","file":"index.js","sourcesContent":["export const DEFAULT_INGEST_URL = \"https://ingest.dumbledor.com\";\n\nexport const UUID_PATTERN =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n","import { DEFAULT_INGEST_URL, UUID_PATTERN } from \"./constants\";\nimport type {\n CollectPayload,\n CollectPayloadInput,\n DumbledorClientConfig,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nexport class DumbledorConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DumbledorConfigError\";\n }\n}\n\nexport function normalizeIngestUrl(value?: string): string {\n const raw = value?.trim() || DEFAULT_INGEST_URL;\n return raw.replace(/\\/$/, \"\");\n}\n\nexport function assertClientConfig(config: DumbledorClientConfig): ResolvedDumbledorConfig {\n const websiteId = config.websiteId?.trim();\n\n if (!websiteId) {\n throw new DumbledorConfigError(\"websiteId is required.\");\n }\n\n if (!UUID_PATTERN.test(websiteId)) {\n throw new DumbledorConfigError(\"websiteId must be a valid UUID.\");\n }\n\n return {\n websiteId,\n ingestUrl: normalizeIngestUrl(config.ingestUrl),\n honorDoNotTrack: config.honorDoNotTrack ?? false,\n disabled: config.disabled ?? false,\n fetch: config.fetch,\n };\n}\n\nexport function withWebsiteId(\n payload: CollectPayloadInput,\n websiteId: string,\n): CollectPayload {\n return {\n ...payload,\n websiteId,\n };\n}\n\nexport function resolveFetch(fetchImpl?: typeof fetch): typeof fetch {\n const resolved = fetchImpl ?? globalThis.fetch;\n if (!resolved) {\n throw new DumbledorConfigError(\"fetch is not available in this runtime.\");\n }\n\n return resolved;\n}\n","type NavigatorWithMsDnt = Navigator & {\n msDoNotTrack?: string | number | null;\n};\n\ntype WindowWithDnt = Window & {\n doNotTrack?: string | number | null;\n};\n\nexport function hasDoNotTrack(): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n\n const win = window as WindowWithDnt;\n const dnt =\n win.doNotTrack ??\n win.navigator.doNotTrack ??\n (win.navigator as NavigatorWithMsDnt).msDoNotTrack;\n\n return dnt === 1 || dnt === \"1\" || dnt === \"yes\";\n}\n\nexport function isTrackingDisabled(honorDoNotTrack: boolean): boolean {\n return honorDoNotTrack && hasDoNotTrack();\n}\n","import { assertClientConfig, resolveFetch, withWebsiteId } from \"./config\";\nimport { isTrackingDisabled } from \"./dnt\";\nimport type {\n CollectPayloadInput,\n CollectResponse,\n DumbledorClient,\n DumbledorClientConfig,\n PageviewInput,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nfunction defaultPageviewInput(): PageviewInput {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n return {};\n }\n\n return {\n url: window.location.href,\n referrer: document.referrer || undefined,\n title: document.title,\n hostname: window.location.hostname,\n language: navigator.language,\n screen: typeof screen !== \"undefined\" ? `${screen.width}x${screen.height}` : undefined,\n };\n}\n\nexport function createTransport(config: ResolvedDumbledorConfig) {\n const endpoint = `${config.ingestUrl}/v1/collect`;\n const fetchImpl = resolveFetch(config.fetch);\n\n return async function send(payload: CollectPayloadInput): Promise<CollectResponse | void> {\n if (config.disabled || isTrackingDisabled(config.honorDoNotTrack)) {\n return;\n }\n\n const body = withWebsiteId(payload, config.websiteId);\n\n try {\n const response = await fetchImpl(endpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n keepalive: true,\n credentials: \"omit\",\n mode: \"cors\",\n });\n\n if (!response.ok) {\n return {\n ok: false,\n error: `Ingest request failed with status ${response.status}`,\n };\n }\n\n return (await response.json()) as CollectResponse;\n } catch {\n return {\n ok: false,\n error: \"Ingest request failed\",\n };\n }\n };\n}\n\nexport function createClient(config: DumbledorClientConfig): DumbledorClient {\n const resolved = assertClientConfig(config);\n const send = createTransport(resolved);\n\n return {\n config: resolved,\n page(input = {}) {\n const defaults = defaultPageviewInput();\n const url = input.url ?? defaults.url;\n if (!url) {\n return;\n }\n\n void send({\n type: \"pageview\",\n url,\n referrer: input.referrer ?? defaults.referrer,\n title: input.title ?? defaults.title,\n hostname: input.hostname ?? defaults.hostname,\n language: input.language ?? defaults.language,\n screen: input.screen ?? defaults.screen,\n });\n },\n track(name, properties) {\n const defaults = defaultPageviewInput();\n void send({\n type: \"track\",\n name,\n properties: properties ?? {},\n url: defaults.url,\n hostname: defaults.hostname,\n });\n },\n identify(userId, traits) {\n void send({\n type: \"identify\",\n userId,\n traits: traits ?? {},\n });\n },\n };\n}\n\nlet defaultClient: DumbledorClient | null = null;\n\nexport function init(config: DumbledorClientConfig): DumbledorClient {\n defaultClient = createClient(config);\n return defaultClient;\n}\n\nexport function getClient(): DumbledorClient {\n if (!defaultClient) {\n throw new Error(\n \"Dumbledor is not initialized. Call init(), wrap with DumbledorProvider, or createClient() first.\",\n );\n }\n\n return defaultClient;\n}\n\nexport function page(input?: PageviewInput): void {\n getClient().page(input);\n}\n\nexport function track(name: string, properties?: Record<string, unknown>): void {\n getClient().track(name, properties);\n}\n\nexport function identify(userId: string, traits?: Record<string, unknown>): void {\n getClient().identify(userId, traits);\n}\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport { getClient } from \"../client\";\nimport type { DumbledorClient } from \"../types\";\n\nexport const DumbledorContext = createContext<DumbledorClient | null>(null);\n\nexport function useDumbledor(): DumbledorClient {\n const client = useContext(DumbledorContext);\n if (client) {\n return client;\n }\n\n return getClient();\n}\n","\"use client\";\n\nimport { useEffect, useRef } from \"react\";\nimport { useDumbledor } from \"./context\";\n\nexport type PageViewProps = {\n /** Route pathname. When omitted, falls back to `window.location.pathname`. */\n pathname?: string;\n /** Track the first render. Default: `true`. */\n trackInitialView?: boolean;\n};\n\nexport function PageView({ pathname, trackInitialView = true }: PageViewProps) {\n const client = useDumbledor();\n const lastPathRef = useRef<string | null>(null);\n\n useEffect(() => {\n const nextPath =\n pathname ??\n (typeof window !== \"undefined\"\n ? `${window.location.pathname}${window.location.search}`\n : null);\n\n if (!nextPath || lastPathRef.current === nextPath) {\n return;\n }\n\n const isFirstView = lastPathRef.current === null;\n lastPathRef.current = nextPath;\n\n if (isFirstView && !trackInitialView) {\n return;\n }\n\n client.page();\n }, [client, pathname, trackInitialView]);\n\n return null;\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { init } from \"../client\";\nimport type { DumbledorClientConfig } from \"../types\";\nimport { DumbledorContext } from \"./context\";\n\nexport type DumbledorProviderProps = DumbledorClientConfig & {\n children: React.ReactNode;\n};\n\nexport function DumbledorProvider({\n children,\n websiteId,\n ingestUrl,\n honorDoNotTrack,\n disabled,\n fetch,\n}: DumbledorProviderProps) {\n const client = useMemo(\n () =>\n init({\n websiteId,\n ingestUrl,\n honorDoNotTrack,\n disabled,\n fetch,\n }),\n [websiteId, ingestUrl, honorDoNotTrack, disabled, fetch],\n );\n\n return <DumbledorContext.Provider value={client}>{children}</DumbledorContext.Provider>;\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { useDumbledor } from \"./context\";\n\nexport function useTrack() {\n const client = useDumbledor();\n return useCallback(\n (name: string, properties?: Record<string, unknown>) => {\n client.track(name, properties);\n },\n [client],\n );\n}\n\nexport function useIdentify() {\n const client = useDumbledor();\n return useCallback(\n (userId: string, traits?: Record<string, unknown>) => {\n client.identify(userId, traits);\n },\n [client],\n );\n}\n\nexport function usePage() {\n const client = useDumbledor();\n return useCallback(\n (input?: Parameters<typeof client.page>[0]) => {\n client.page(input);\n },\n [client],\n );\n}\n","\"use client\";\n\nimport { usePathname, useSearchParams } from \"next/navigation\";\nimport { useMemo } from \"react\";\nimport { PageView } from \"../react/page-view\";\nimport { DumbledorProvider, type DumbledorProviderProps } from \"../react/provider\";\n\nexport type AppRouterPageViewProps = {\n trackInitialView?: boolean;\n};\n\nexport function AppRouterPageView({ trackInitialView = true }: AppRouterPageViewProps) {\n const pathname = usePathname();\n const searchParams = useSearchParams();\n const routeKey = useMemo(() => {\n const query = searchParams.toString();\n return query ? `${pathname}?${query}` : pathname;\n }, [pathname, searchParams]);\n\n return <PageView pathname={routeKey} trackInitialView={trackInitialView} />;\n}\n\nexport { DumbledorProvider, type DumbledorProviderProps };\nexport { PageView, useDumbledor, useIdentify, usePage, useTrack } from \"../react\";\n"]}
1
+ {"version":3,"sources":["../../src/constants.ts","../../src/config.ts","../../src/dnt.ts","../../src/client.ts","../../src/react/context.tsx","../../src/react/page-view.tsx","../../src/react/provider.tsx","../../src/react/hooks.ts","../../src/next/index.tsx"],"names":["useMemo","jsx"],"mappings":"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","file":"index.js","sourcesContent":["export const DEFAULT_INGEST_URL = \"https://ingest.dumbledor.com\";\n\nexport const UUID_PATTERN =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n","import { DEFAULT_INGEST_URL, UUID_PATTERN } from \"./constants\";\nimport type {\n CollectPayload,\n CollectPayloadInput,\n DumbledorClientConfig,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nexport class DumbledorConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DumbledorConfigError\";\n }\n}\n\nexport function normalizeIngestUrl(value?: string): string {\n const raw = value?.trim() || DEFAULT_INGEST_URL;\n return raw.replace(/\\/$/, \"\");\n}\n\nexport function assertClientConfig(config: DumbledorClientConfig): ResolvedDumbledorConfig {\n const websiteId = config.websiteId?.trim();\n\n if (!websiteId) {\n throw new DumbledorConfigError(\"websiteId is required.\");\n }\n\n if (!UUID_PATTERN.test(websiteId)) {\n throw new DumbledorConfigError(\"websiteId must be a valid UUID.\");\n }\n\n return {\n websiteId,\n ingestUrl: normalizeIngestUrl(config.ingestUrl),\n honorDoNotTrack: config.honorDoNotTrack ?? false,\n disabled: config.disabled ?? false,\n fetch: config.fetch,\n };\n}\n\nexport function withWebsiteId(\n payload: CollectPayloadInput,\n websiteId: string,\n): CollectPayload {\n return {\n ...payload,\n websiteId,\n };\n}\n\nexport function resolveFetch(fetchImpl?: typeof fetch): typeof fetch {\n const resolved = fetchImpl ?? globalThis.fetch;\n if (!resolved) {\n throw new DumbledorConfigError(\"fetch is not available in this runtime.\");\n }\n\n return resolved;\n}\n","type NavigatorWithMsDnt = Navigator & {\n msDoNotTrack?: string | number | null;\n};\n\ntype WindowWithDnt = Window & {\n doNotTrack?: string | number | null;\n};\n\nexport function hasDoNotTrack(): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n\n const win = window as WindowWithDnt;\n const dnt =\n win.doNotTrack ??\n win.navigator.doNotTrack ??\n (win.navigator as NavigatorWithMsDnt).msDoNotTrack;\n\n return dnt === 1 || dnt === \"1\" || dnt === \"yes\";\n}\n\nexport function isTrackingDisabled(honorDoNotTrack: boolean): boolean {\n return honorDoNotTrack && hasDoNotTrack();\n}\n","import { assertClientConfig, resolveFetch, withWebsiteId } from \"./config\";\nimport { isTrackingDisabled } from \"./dnt\";\nimport type {\n CollectPayloadInput,\n CollectResponse,\n DumbledorClient,\n DumbledorClientConfig,\n PageviewInput,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nconst CACHE_HEADER = \"x-dumbledor-cache\";\n\nfunction defaultPageviewInput(): PageviewInput {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n return {};\n }\n\n return {\n url: window.location.href,\n referrer: document.referrer || undefined,\n title: document.title,\n hostname: window.location.hostname,\n language: navigator.language,\n screen: typeof screen !== \"undefined\" ? `${screen.width}x${screen.height}` : undefined,\n };\n}\n\ntype SendOptions = {\n clearCache?: boolean;\n};\n\nexport function createTransport(config: ResolvedDumbledorConfig) {\n const endpoint = `${config.ingestUrl}/v1/collect`;\n const fetchImpl = resolveFetch(config.fetch);\n let cache: string | undefined;\n\n return async function send(\n payload: CollectPayloadInput,\n options?: SendOptions,\n ): Promise<CollectResponse | void> {\n if (config.disabled || isTrackingDisabled(config.honorDoNotTrack)) {\n return;\n }\n\n if (options?.clearCache) {\n cache = undefined;\n }\n\n const body = withWebsiteId(payload, config.websiteId);\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (cache) {\n headers[CACHE_HEADER] = cache;\n }\n\n try {\n const response = await fetchImpl(endpoint, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n keepalive: true,\n credentials: \"omit\",\n mode: \"cors\",\n });\n\n if (!response.ok) {\n return {\n ok: false,\n error: `Ingest request failed with status ${response.status}`,\n };\n }\n\n const data = (await response.json()) as CollectResponse;\n if (data.cache) {\n cache = data.cache;\n }\n\n return data;\n } catch {\n return {\n ok: false,\n error: \"Ingest request failed\",\n };\n }\n };\n}\n\nexport function createClient(config: DumbledorClientConfig): DumbledorClient {\n const resolved = assertClientConfig(config);\n const send = createTransport(resolved);\n\n return {\n config: resolved,\n page(input = {}) {\n const defaults = defaultPageviewInput();\n const url = input.url ?? defaults.url;\n if (!url) {\n return;\n }\n\n void send({\n type: \"pageview\",\n url,\n referrer: input.referrer ?? defaults.referrer,\n title: input.title ?? defaults.title,\n hostname: input.hostname ?? defaults.hostname,\n language: input.language ?? defaults.language,\n screen: input.screen ?? defaults.screen,\n });\n },\n track(name, properties) {\n const defaults = defaultPageviewInput();\n void send({\n type: \"track\",\n name,\n properties: properties ?? {},\n url: defaults.url,\n hostname: defaults.hostname,\n });\n },\n identify(userId, traits) {\n void send(\n {\n type: \"identify\",\n userId,\n traits: traits ?? {},\n },\n { clearCache: true },\n );\n },\n };\n}\n\nlet defaultClient: DumbledorClient | null = null;\n\nexport function init(config: DumbledorClientConfig): DumbledorClient {\n defaultClient = createClient(config);\n return defaultClient;\n}\n\nexport function getClient(): DumbledorClient {\n if (!defaultClient) {\n throw new Error(\n \"Dumbledor is not initialized. Call init(), wrap with DumbledorProvider, or createClient() first.\",\n );\n }\n\n return defaultClient;\n}\n\nexport function page(input?: PageviewInput): void {\n getClient().page(input);\n}\n\nexport function track(name: string, properties?: Record<string, unknown>): void {\n getClient().track(name, properties);\n}\n\nexport function identify(userId: string, traits?: Record<string, unknown>): void {\n getClient().identify(userId, traits);\n}\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport { getClient } from \"../client\";\nimport type { DumbledorClient } from \"../types\";\n\nexport const DumbledorContext = createContext<DumbledorClient | null>(null);\n\nexport function useDumbledor(): DumbledorClient {\n const client = useContext(DumbledorContext);\n if (client) {\n return client;\n }\n\n return getClient();\n}\n","\"use client\";\n\nimport { useEffect, useRef } from \"react\";\nimport { useDumbledor } from \"./context\";\n\nexport type PageViewProps = {\n /** Route pathname. When omitted, falls back to `window.location.pathname`. */\n pathname?: string;\n /** Track the first render. Default: `true`. */\n trackInitialView?: boolean;\n};\n\nexport function PageView({ pathname, trackInitialView = true }: PageViewProps) {\n const client = useDumbledor();\n const lastPathRef = useRef<string | null>(null);\n\n useEffect(() => {\n const nextPath =\n pathname ??\n (typeof window !== \"undefined\"\n ? `${window.location.pathname}${window.location.search}`\n : null);\n\n if (!nextPath || lastPathRef.current === nextPath) {\n return;\n }\n\n const isFirstView = lastPathRef.current === null;\n lastPathRef.current = nextPath;\n\n if (isFirstView && !trackInitialView) {\n return;\n }\n\n client.page();\n }, [client, pathname, trackInitialView]);\n\n return null;\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { init } from \"../client\";\nimport type { DumbledorClientConfig } from \"../types\";\nimport { DumbledorContext } from \"./context\";\n\nexport type DumbledorProviderProps = DumbledorClientConfig & {\n children: React.ReactNode;\n};\n\nexport function DumbledorProvider({\n children,\n websiteId,\n ingestUrl,\n honorDoNotTrack,\n disabled,\n fetch,\n}: DumbledorProviderProps) {\n const client = useMemo(\n () =>\n init({\n websiteId,\n ingestUrl,\n honorDoNotTrack,\n disabled,\n fetch,\n }),\n [websiteId, ingestUrl, honorDoNotTrack, disabled, fetch],\n );\n\n return <DumbledorContext.Provider value={client}>{children}</DumbledorContext.Provider>;\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { useDumbledor } from \"./context\";\n\nexport function useTrack() {\n const client = useDumbledor();\n return useCallback(\n (name: string, properties?: Record<string, unknown>) => {\n client.track(name, properties);\n },\n [client],\n );\n}\n\nexport function useIdentify() {\n const client = useDumbledor();\n return useCallback(\n (userId: string, traits?: Record<string, unknown>) => {\n client.identify(userId, traits);\n },\n [client],\n );\n}\n\nexport function usePage() {\n const client = useDumbledor();\n return useCallback(\n (input?: Parameters<typeof client.page>[0]) => {\n client.page(input);\n },\n [client],\n );\n}\n","\"use client\";\n\nimport { usePathname, useSearchParams } from \"next/navigation\";\nimport { useMemo } from \"react\";\nimport { PageView } from \"../react/page-view\";\nimport { DumbledorProvider, type DumbledorProviderProps } from \"../react/provider\";\n\nexport type AppRouterPageViewProps = {\n trackInitialView?: boolean;\n};\n\nexport function AppRouterPageView({ trackInitialView = true }: AppRouterPageViewProps) {\n const pathname = usePathname();\n const searchParams = useSearchParams();\n const routeKey = useMemo(() => {\n const query = searchParams.toString();\n return query ? `${pathname}?${query}` : pathname;\n }, [pathname, searchParams]);\n\n return <PageView pathname={routeKey} trackInitialView={trackInitialView} />;\n}\n\nexport { DumbledorProvider, type DumbledorProviderProps };\nexport { PageView, useDumbledor, useIdentify, usePage, useTrack } from \"../react\";\n"]}
@@ -63,6 +63,7 @@ function isTrackingDisabled(honorDoNotTrack) {
63
63
  }
64
64
 
65
65
  // src/client.ts
66
+ var CACHE_HEADER = "x-dumbledor-cache";
66
67
  function defaultPageviewInput() {
67
68
  if (typeof window === "undefined" || typeof document === "undefined") {
68
69
  return {};
@@ -79,15 +80,23 @@ function defaultPageviewInput() {
79
80
  function createTransport(config) {
80
81
  const endpoint = `${config.ingestUrl}/v1/collect`;
81
82
  const fetchImpl = resolveFetch(config.fetch);
82
- return async function send(payload) {
83
+ let cache;
84
+ return async function send(payload, options) {
83
85
  if (config.disabled || isTrackingDisabled(config.honorDoNotTrack)) {
84
86
  return;
85
87
  }
88
+ if (options?.clearCache) {
89
+ cache = void 0;
90
+ }
86
91
  const body = withWebsiteId(payload, config.websiteId);
92
+ const headers = { "Content-Type": "application/json" };
93
+ if (cache) {
94
+ headers[CACHE_HEADER] = cache;
95
+ }
87
96
  try {
88
97
  const response = await fetchImpl(endpoint, {
89
98
  method: "POST",
90
- headers: { "Content-Type": "application/json" },
99
+ headers,
91
100
  body: JSON.stringify(body),
92
101
  keepalive: true,
93
102
  credentials: "omit",
@@ -99,7 +108,11 @@ function createTransport(config) {
99
108
  error: `Ingest request failed with status ${response.status}`
100
109
  };
101
110
  }
102
- return await response.json();
111
+ const data = await response.json();
112
+ if (data.cache) {
113
+ cache = data.cache;
114
+ }
115
+ return data;
103
116
  } catch {
104
117
  return {
105
118
  ok: false,
@@ -140,11 +153,14 @@ function createClient(config) {
140
153
  });
141
154
  },
142
155
  identify(userId, traits) {
143
- void send({
144
- type: "identify",
145
- userId,
146
- traits: traits ?? {}
147
- });
156
+ void send(
157
+ {
158
+ type: "identify",
159
+ userId,
160
+ traits: traits ?? {}
161
+ },
162
+ { clearCache: true }
163
+ );
148
164
  }
149
165
  };
150
166
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/constants.ts","../../src/config.ts","../../src/dnt.ts","../../src/client.ts","../../src/react/context.tsx","../../src/react/page-view.tsx","../../src/react/hooks.ts","../../src/react/provider.tsx"],"names":["createContext","useContext","useRef","useEffect","useCallback","useMemo"],"mappings":"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","file":"index.cjs","sourcesContent":["export const DEFAULT_INGEST_URL = \"https://ingest.dumbledor.com\";\n\nexport const UUID_PATTERN =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n","import { DEFAULT_INGEST_URL, UUID_PATTERN } from \"./constants\";\nimport type {\n CollectPayload,\n CollectPayloadInput,\n DumbledorClientConfig,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nexport class DumbledorConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DumbledorConfigError\";\n }\n}\n\nexport function normalizeIngestUrl(value?: string): string {\n const raw = value?.trim() || DEFAULT_INGEST_URL;\n return raw.replace(/\\/$/, \"\");\n}\n\nexport function assertClientConfig(config: DumbledorClientConfig): ResolvedDumbledorConfig {\n const websiteId = config.websiteId?.trim();\n\n if (!websiteId) {\n throw new DumbledorConfigError(\"websiteId is required.\");\n }\n\n if (!UUID_PATTERN.test(websiteId)) {\n throw new DumbledorConfigError(\"websiteId must be a valid UUID.\");\n }\n\n return {\n websiteId,\n ingestUrl: normalizeIngestUrl(config.ingestUrl),\n honorDoNotTrack: config.honorDoNotTrack ?? false,\n disabled: config.disabled ?? false,\n fetch: config.fetch,\n };\n}\n\nexport function withWebsiteId(\n payload: CollectPayloadInput,\n websiteId: string,\n): CollectPayload {\n return {\n ...payload,\n websiteId,\n };\n}\n\nexport function resolveFetch(fetchImpl?: typeof fetch): typeof fetch {\n const resolved = fetchImpl ?? globalThis.fetch;\n if (!resolved) {\n throw new DumbledorConfigError(\"fetch is not available in this runtime.\");\n }\n\n return resolved;\n}\n","type NavigatorWithMsDnt = Navigator & {\n msDoNotTrack?: string | number | null;\n};\n\ntype WindowWithDnt = Window & {\n doNotTrack?: string | number | null;\n};\n\nexport function hasDoNotTrack(): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n\n const win = window as WindowWithDnt;\n const dnt =\n win.doNotTrack ??\n win.navigator.doNotTrack ??\n (win.navigator as NavigatorWithMsDnt).msDoNotTrack;\n\n return dnt === 1 || dnt === \"1\" || dnt === \"yes\";\n}\n\nexport function isTrackingDisabled(honorDoNotTrack: boolean): boolean {\n return honorDoNotTrack && hasDoNotTrack();\n}\n","import { assertClientConfig, resolveFetch, withWebsiteId } from \"./config\";\nimport { isTrackingDisabled } from \"./dnt\";\nimport type {\n CollectPayloadInput,\n CollectResponse,\n DumbledorClient,\n DumbledorClientConfig,\n PageviewInput,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nfunction defaultPageviewInput(): PageviewInput {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n return {};\n }\n\n return {\n url: window.location.href,\n referrer: document.referrer || undefined,\n title: document.title,\n hostname: window.location.hostname,\n language: navigator.language,\n screen: typeof screen !== \"undefined\" ? `${screen.width}x${screen.height}` : undefined,\n };\n}\n\nexport function createTransport(config: ResolvedDumbledorConfig) {\n const endpoint = `${config.ingestUrl}/v1/collect`;\n const fetchImpl = resolveFetch(config.fetch);\n\n return async function send(payload: CollectPayloadInput): Promise<CollectResponse | void> {\n if (config.disabled || isTrackingDisabled(config.honorDoNotTrack)) {\n return;\n }\n\n const body = withWebsiteId(payload, config.websiteId);\n\n try {\n const response = await fetchImpl(endpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n keepalive: true,\n credentials: \"omit\",\n mode: \"cors\",\n });\n\n if (!response.ok) {\n return {\n ok: false,\n error: `Ingest request failed with status ${response.status}`,\n };\n }\n\n return (await response.json()) as CollectResponse;\n } catch {\n return {\n ok: false,\n error: \"Ingest request failed\",\n };\n }\n };\n}\n\nexport function createClient(config: DumbledorClientConfig): DumbledorClient {\n const resolved = assertClientConfig(config);\n const send = createTransport(resolved);\n\n return {\n config: resolved,\n page(input = {}) {\n const defaults = defaultPageviewInput();\n const url = input.url ?? defaults.url;\n if (!url) {\n return;\n }\n\n void send({\n type: \"pageview\",\n url,\n referrer: input.referrer ?? defaults.referrer,\n title: input.title ?? defaults.title,\n hostname: input.hostname ?? defaults.hostname,\n language: input.language ?? defaults.language,\n screen: input.screen ?? defaults.screen,\n });\n },\n track(name, properties) {\n const defaults = defaultPageviewInput();\n void send({\n type: \"track\",\n name,\n properties: properties ?? {},\n url: defaults.url,\n hostname: defaults.hostname,\n });\n },\n identify(userId, traits) {\n void send({\n type: \"identify\",\n userId,\n traits: traits ?? {},\n });\n },\n };\n}\n\nlet defaultClient: DumbledorClient | null = null;\n\nexport function init(config: DumbledorClientConfig): DumbledorClient {\n defaultClient = createClient(config);\n return defaultClient;\n}\n\nexport function getClient(): DumbledorClient {\n if (!defaultClient) {\n throw new Error(\n \"Dumbledor is not initialized. Call init(), wrap with DumbledorProvider, or createClient() first.\",\n );\n }\n\n return defaultClient;\n}\n\nexport function page(input?: PageviewInput): void {\n getClient().page(input);\n}\n\nexport function track(name: string, properties?: Record<string, unknown>): void {\n getClient().track(name, properties);\n}\n\nexport function identify(userId: string, traits?: Record<string, unknown>): void {\n getClient().identify(userId, traits);\n}\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport { getClient } from \"../client\";\nimport type { DumbledorClient } from \"../types\";\n\nexport const DumbledorContext = createContext<DumbledorClient | null>(null);\n\nexport function useDumbledor(): DumbledorClient {\n const client = useContext(DumbledorContext);\n if (client) {\n return client;\n }\n\n return getClient();\n}\n","\"use client\";\n\nimport { useEffect, useRef } from \"react\";\nimport { useDumbledor } from \"./context\";\n\nexport type PageViewProps = {\n /** Route pathname. When omitted, falls back to `window.location.pathname`. */\n pathname?: string;\n /** Track the first render. Default: `true`. */\n trackInitialView?: boolean;\n};\n\nexport function PageView({ pathname, trackInitialView = true }: PageViewProps) {\n const client = useDumbledor();\n const lastPathRef = useRef<string | null>(null);\n\n useEffect(() => {\n const nextPath =\n pathname ??\n (typeof window !== \"undefined\"\n ? `${window.location.pathname}${window.location.search}`\n : null);\n\n if (!nextPath || lastPathRef.current === nextPath) {\n return;\n }\n\n const isFirstView = lastPathRef.current === null;\n lastPathRef.current = nextPath;\n\n if (isFirstView && !trackInitialView) {\n return;\n }\n\n client.page();\n }, [client, pathname, trackInitialView]);\n\n return null;\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { useDumbledor } from \"./context\";\n\nexport function useTrack() {\n const client = useDumbledor();\n return useCallback(\n (name: string, properties?: Record<string, unknown>) => {\n client.track(name, properties);\n },\n [client],\n );\n}\n\nexport function useIdentify() {\n const client = useDumbledor();\n return useCallback(\n (userId: string, traits?: Record<string, unknown>) => {\n client.identify(userId, traits);\n },\n [client],\n );\n}\n\nexport function usePage() {\n const client = useDumbledor();\n return useCallback(\n (input?: Parameters<typeof client.page>[0]) => {\n client.page(input);\n },\n [client],\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { init } from \"../client\";\nimport type { DumbledorClientConfig } from \"../types\";\nimport { DumbledorContext } from \"./context\";\n\nexport type DumbledorProviderProps = DumbledorClientConfig & {\n children: React.ReactNode;\n};\n\nexport function DumbledorProvider({\n children,\n websiteId,\n ingestUrl,\n honorDoNotTrack,\n disabled,\n fetch,\n}: DumbledorProviderProps) {\n const client = useMemo(\n () =>\n init({\n websiteId,\n ingestUrl,\n honorDoNotTrack,\n disabled,\n fetch,\n }),\n [websiteId, ingestUrl, honorDoNotTrack, disabled, fetch],\n );\n\n return <DumbledorContext.Provider value={client}>{children}</DumbledorContext.Provider>;\n}\n"]}
1
+ {"version":3,"sources":["../../src/constants.ts","../../src/config.ts","../../src/dnt.ts","../../src/client.ts","../../src/react/context.tsx","../../src/react/page-view.tsx","../../src/react/hooks.ts","../../src/react/provider.tsx"],"names":["createContext","useContext","useRef","useEffect","useCallback","useMemo"],"mappings":"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","file":"index.cjs","sourcesContent":["export const DEFAULT_INGEST_URL = \"https://ingest.dumbledor.com\";\n\nexport const UUID_PATTERN =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n","import { DEFAULT_INGEST_URL, UUID_PATTERN } from \"./constants\";\nimport type {\n CollectPayload,\n CollectPayloadInput,\n DumbledorClientConfig,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nexport class DumbledorConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DumbledorConfigError\";\n }\n}\n\nexport function normalizeIngestUrl(value?: string): string {\n const raw = value?.trim() || DEFAULT_INGEST_URL;\n return raw.replace(/\\/$/, \"\");\n}\n\nexport function assertClientConfig(config: DumbledorClientConfig): ResolvedDumbledorConfig {\n const websiteId = config.websiteId?.trim();\n\n if (!websiteId) {\n throw new DumbledorConfigError(\"websiteId is required.\");\n }\n\n if (!UUID_PATTERN.test(websiteId)) {\n throw new DumbledorConfigError(\"websiteId must be a valid UUID.\");\n }\n\n return {\n websiteId,\n ingestUrl: normalizeIngestUrl(config.ingestUrl),\n honorDoNotTrack: config.honorDoNotTrack ?? false,\n disabled: config.disabled ?? false,\n fetch: config.fetch,\n };\n}\n\nexport function withWebsiteId(\n payload: CollectPayloadInput,\n websiteId: string,\n): CollectPayload {\n return {\n ...payload,\n websiteId,\n };\n}\n\nexport function resolveFetch(fetchImpl?: typeof fetch): typeof fetch {\n const resolved = fetchImpl ?? globalThis.fetch;\n if (!resolved) {\n throw new DumbledorConfigError(\"fetch is not available in this runtime.\");\n }\n\n return resolved;\n}\n","type NavigatorWithMsDnt = Navigator & {\n msDoNotTrack?: string | number | null;\n};\n\ntype WindowWithDnt = Window & {\n doNotTrack?: string | number | null;\n};\n\nexport function hasDoNotTrack(): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n\n const win = window as WindowWithDnt;\n const dnt =\n win.doNotTrack ??\n win.navigator.doNotTrack ??\n (win.navigator as NavigatorWithMsDnt).msDoNotTrack;\n\n return dnt === 1 || dnt === \"1\" || dnt === \"yes\";\n}\n\nexport function isTrackingDisabled(honorDoNotTrack: boolean): boolean {\n return honorDoNotTrack && hasDoNotTrack();\n}\n","import { assertClientConfig, resolveFetch, withWebsiteId } from \"./config\";\nimport { isTrackingDisabled } from \"./dnt\";\nimport type {\n CollectPayloadInput,\n CollectResponse,\n DumbledorClient,\n DumbledorClientConfig,\n PageviewInput,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nconst CACHE_HEADER = \"x-dumbledor-cache\";\n\nfunction defaultPageviewInput(): PageviewInput {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n return {};\n }\n\n return {\n url: window.location.href,\n referrer: document.referrer || undefined,\n title: document.title,\n hostname: window.location.hostname,\n language: navigator.language,\n screen: typeof screen !== \"undefined\" ? `${screen.width}x${screen.height}` : undefined,\n };\n}\n\ntype SendOptions = {\n clearCache?: boolean;\n};\n\nexport function createTransport(config: ResolvedDumbledorConfig) {\n const endpoint = `${config.ingestUrl}/v1/collect`;\n const fetchImpl = resolveFetch(config.fetch);\n let cache: string | undefined;\n\n return async function send(\n payload: CollectPayloadInput,\n options?: SendOptions,\n ): Promise<CollectResponse | void> {\n if (config.disabled || isTrackingDisabled(config.honorDoNotTrack)) {\n return;\n }\n\n if (options?.clearCache) {\n cache = undefined;\n }\n\n const body = withWebsiteId(payload, config.websiteId);\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (cache) {\n headers[CACHE_HEADER] = cache;\n }\n\n try {\n const response = await fetchImpl(endpoint, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n keepalive: true,\n credentials: \"omit\",\n mode: \"cors\",\n });\n\n if (!response.ok) {\n return {\n ok: false,\n error: `Ingest request failed with status ${response.status}`,\n };\n }\n\n const data = (await response.json()) as CollectResponse;\n if (data.cache) {\n cache = data.cache;\n }\n\n return data;\n } catch {\n return {\n ok: false,\n error: \"Ingest request failed\",\n };\n }\n };\n}\n\nexport function createClient(config: DumbledorClientConfig): DumbledorClient {\n const resolved = assertClientConfig(config);\n const send = createTransport(resolved);\n\n return {\n config: resolved,\n page(input = {}) {\n const defaults = defaultPageviewInput();\n const url = input.url ?? defaults.url;\n if (!url) {\n return;\n }\n\n void send({\n type: \"pageview\",\n url,\n referrer: input.referrer ?? defaults.referrer,\n title: input.title ?? defaults.title,\n hostname: input.hostname ?? defaults.hostname,\n language: input.language ?? defaults.language,\n screen: input.screen ?? defaults.screen,\n });\n },\n track(name, properties) {\n const defaults = defaultPageviewInput();\n void send({\n type: \"track\",\n name,\n properties: properties ?? {},\n url: defaults.url,\n hostname: defaults.hostname,\n });\n },\n identify(userId, traits) {\n void send(\n {\n type: \"identify\",\n userId,\n traits: traits ?? {},\n },\n { clearCache: true },\n );\n },\n };\n}\n\nlet defaultClient: DumbledorClient | null = null;\n\nexport function init(config: DumbledorClientConfig): DumbledorClient {\n defaultClient = createClient(config);\n return defaultClient;\n}\n\nexport function getClient(): DumbledorClient {\n if (!defaultClient) {\n throw new Error(\n \"Dumbledor is not initialized. Call init(), wrap with DumbledorProvider, or createClient() first.\",\n );\n }\n\n return defaultClient;\n}\n\nexport function page(input?: PageviewInput): void {\n getClient().page(input);\n}\n\nexport function track(name: string, properties?: Record<string, unknown>): void {\n getClient().track(name, properties);\n}\n\nexport function identify(userId: string, traits?: Record<string, unknown>): void {\n getClient().identify(userId, traits);\n}\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport { getClient } from \"../client\";\nimport type { DumbledorClient } from \"../types\";\n\nexport const DumbledorContext = createContext<DumbledorClient | null>(null);\n\nexport function useDumbledor(): DumbledorClient {\n const client = useContext(DumbledorContext);\n if (client) {\n return client;\n }\n\n return getClient();\n}\n","\"use client\";\n\nimport { useEffect, useRef } from \"react\";\nimport { useDumbledor } from \"./context\";\n\nexport type PageViewProps = {\n /** Route pathname. When omitted, falls back to `window.location.pathname`. */\n pathname?: string;\n /** Track the first render. Default: `true`. */\n trackInitialView?: boolean;\n};\n\nexport function PageView({ pathname, trackInitialView = true }: PageViewProps) {\n const client = useDumbledor();\n const lastPathRef = useRef<string | null>(null);\n\n useEffect(() => {\n const nextPath =\n pathname ??\n (typeof window !== \"undefined\"\n ? `${window.location.pathname}${window.location.search}`\n : null);\n\n if (!nextPath || lastPathRef.current === nextPath) {\n return;\n }\n\n const isFirstView = lastPathRef.current === null;\n lastPathRef.current = nextPath;\n\n if (isFirstView && !trackInitialView) {\n return;\n }\n\n client.page();\n }, [client, pathname, trackInitialView]);\n\n return null;\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { useDumbledor } from \"./context\";\n\nexport function useTrack() {\n const client = useDumbledor();\n return useCallback(\n (name: string, properties?: Record<string, unknown>) => {\n client.track(name, properties);\n },\n [client],\n );\n}\n\nexport function useIdentify() {\n const client = useDumbledor();\n return useCallback(\n (userId: string, traits?: Record<string, unknown>) => {\n client.identify(userId, traits);\n },\n [client],\n );\n}\n\nexport function usePage() {\n const client = useDumbledor();\n return useCallback(\n (input?: Parameters<typeof client.page>[0]) => {\n client.page(input);\n },\n [client],\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { init } from \"../client\";\nimport type { DumbledorClientConfig } from \"../types\";\nimport { DumbledorContext } from \"./context\";\n\nexport type DumbledorProviderProps = DumbledorClientConfig & {\n children: React.ReactNode;\n};\n\nexport function DumbledorProvider({\n children,\n websiteId,\n ingestUrl,\n honorDoNotTrack,\n disabled,\n fetch,\n}: DumbledorProviderProps) {\n const client = useMemo(\n () =>\n init({\n websiteId,\n ingestUrl,\n honorDoNotTrack,\n disabled,\n fetch,\n }),\n [websiteId, ingestUrl, honorDoNotTrack, disabled, fetch],\n );\n\n return <DumbledorContext.Provider value={client}>{children}</DumbledorContext.Provider>;\n}\n"]}
@@ -61,6 +61,7 @@ function isTrackingDisabled(honorDoNotTrack) {
61
61
  }
62
62
 
63
63
  // src/client.ts
64
+ var CACHE_HEADER = "x-dumbledor-cache";
64
65
  function defaultPageviewInput() {
65
66
  if (typeof window === "undefined" || typeof document === "undefined") {
66
67
  return {};
@@ -77,15 +78,23 @@ function defaultPageviewInput() {
77
78
  function createTransport(config) {
78
79
  const endpoint = `${config.ingestUrl}/v1/collect`;
79
80
  const fetchImpl = resolveFetch(config.fetch);
80
- return async function send(payload) {
81
+ let cache;
82
+ return async function send(payload, options) {
81
83
  if (config.disabled || isTrackingDisabled(config.honorDoNotTrack)) {
82
84
  return;
83
85
  }
86
+ if (options?.clearCache) {
87
+ cache = void 0;
88
+ }
84
89
  const body = withWebsiteId(payload, config.websiteId);
90
+ const headers = { "Content-Type": "application/json" };
91
+ if (cache) {
92
+ headers[CACHE_HEADER] = cache;
93
+ }
85
94
  try {
86
95
  const response = await fetchImpl(endpoint, {
87
96
  method: "POST",
88
- headers: { "Content-Type": "application/json" },
97
+ headers,
89
98
  body: JSON.stringify(body),
90
99
  keepalive: true,
91
100
  credentials: "omit",
@@ -97,7 +106,11 @@ function createTransport(config) {
97
106
  error: `Ingest request failed with status ${response.status}`
98
107
  };
99
108
  }
100
- return await response.json();
109
+ const data = await response.json();
110
+ if (data.cache) {
111
+ cache = data.cache;
112
+ }
113
+ return data;
101
114
  } catch {
102
115
  return {
103
116
  ok: false,
@@ -138,11 +151,14 @@ function createClient(config) {
138
151
  });
139
152
  },
140
153
  identify(userId, traits) {
141
- void send({
142
- type: "identify",
143
- userId,
144
- traits: traits ?? {}
145
- });
154
+ void send(
155
+ {
156
+ type: "identify",
157
+ userId,
158
+ traits: traits ?? {}
159
+ },
160
+ { clearCache: true }
161
+ );
146
162
  }
147
163
  };
148
164
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/constants.ts","../../src/config.ts","../../src/dnt.ts","../../src/client.ts","../../src/react/context.tsx","../../src/react/page-view.tsx","../../src/react/hooks.ts","../../src/react/provider.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export const DEFAULT_INGEST_URL = \"https://ingest.dumbledor.com\";\n\nexport const UUID_PATTERN =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n","import { DEFAULT_INGEST_URL, UUID_PATTERN } from \"./constants\";\nimport type {\n CollectPayload,\n CollectPayloadInput,\n DumbledorClientConfig,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nexport class DumbledorConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DumbledorConfigError\";\n }\n}\n\nexport function normalizeIngestUrl(value?: string): string {\n const raw = value?.trim() || DEFAULT_INGEST_URL;\n return raw.replace(/\\/$/, \"\");\n}\n\nexport function assertClientConfig(config: DumbledorClientConfig): ResolvedDumbledorConfig {\n const websiteId = config.websiteId?.trim();\n\n if (!websiteId) {\n throw new DumbledorConfigError(\"websiteId is required.\");\n }\n\n if (!UUID_PATTERN.test(websiteId)) {\n throw new DumbledorConfigError(\"websiteId must be a valid UUID.\");\n }\n\n return {\n websiteId,\n ingestUrl: normalizeIngestUrl(config.ingestUrl),\n honorDoNotTrack: config.honorDoNotTrack ?? false,\n disabled: config.disabled ?? false,\n fetch: config.fetch,\n };\n}\n\nexport function withWebsiteId(\n payload: CollectPayloadInput,\n websiteId: string,\n): CollectPayload {\n return {\n ...payload,\n websiteId,\n };\n}\n\nexport function resolveFetch(fetchImpl?: typeof fetch): typeof fetch {\n const resolved = fetchImpl ?? globalThis.fetch;\n if (!resolved) {\n throw new DumbledorConfigError(\"fetch is not available in this runtime.\");\n }\n\n return resolved;\n}\n","type NavigatorWithMsDnt = Navigator & {\n msDoNotTrack?: string | number | null;\n};\n\ntype WindowWithDnt = Window & {\n doNotTrack?: string | number | null;\n};\n\nexport function hasDoNotTrack(): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n\n const win = window as WindowWithDnt;\n const dnt =\n win.doNotTrack ??\n win.navigator.doNotTrack ??\n (win.navigator as NavigatorWithMsDnt).msDoNotTrack;\n\n return dnt === 1 || dnt === \"1\" || dnt === \"yes\";\n}\n\nexport function isTrackingDisabled(honorDoNotTrack: boolean): boolean {\n return honorDoNotTrack && hasDoNotTrack();\n}\n","import { assertClientConfig, resolveFetch, withWebsiteId } from \"./config\";\nimport { isTrackingDisabled } from \"./dnt\";\nimport type {\n CollectPayloadInput,\n CollectResponse,\n DumbledorClient,\n DumbledorClientConfig,\n PageviewInput,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nfunction defaultPageviewInput(): PageviewInput {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n return {};\n }\n\n return {\n url: window.location.href,\n referrer: document.referrer || undefined,\n title: document.title,\n hostname: window.location.hostname,\n language: navigator.language,\n screen: typeof screen !== \"undefined\" ? `${screen.width}x${screen.height}` : undefined,\n };\n}\n\nexport function createTransport(config: ResolvedDumbledorConfig) {\n const endpoint = `${config.ingestUrl}/v1/collect`;\n const fetchImpl = resolveFetch(config.fetch);\n\n return async function send(payload: CollectPayloadInput): Promise<CollectResponse | void> {\n if (config.disabled || isTrackingDisabled(config.honorDoNotTrack)) {\n return;\n }\n\n const body = withWebsiteId(payload, config.websiteId);\n\n try {\n const response = await fetchImpl(endpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n keepalive: true,\n credentials: \"omit\",\n mode: \"cors\",\n });\n\n if (!response.ok) {\n return {\n ok: false,\n error: `Ingest request failed with status ${response.status}`,\n };\n }\n\n return (await response.json()) as CollectResponse;\n } catch {\n return {\n ok: false,\n error: \"Ingest request failed\",\n };\n }\n };\n}\n\nexport function createClient(config: DumbledorClientConfig): DumbledorClient {\n const resolved = assertClientConfig(config);\n const send = createTransport(resolved);\n\n return {\n config: resolved,\n page(input = {}) {\n const defaults = defaultPageviewInput();\n const url = input.url ?? defaults.url;\n if (!url) {\n return;\n }\n\n void send({\n type: \"pageview\",\n url,\n referrer: input.referrer ?? defaults.referrer,\n title: input.title ?? defaults.title,\n hostname: input.hostname ?? defaults.hostname,\n language: input.language ?? defaults.language,\n screen: input.screen ?? defaults.screen,\n });\n },\n track(name, properties) {\n const defaults = defaultPageviewInput();\n void send({\n type: \"track\",\n name,\n properties: properties ?? {},\n url: defaults.url,\n hostname: defaults.hostname,\n });\n },\n identify(userId, traits) {\n void send({\n type: \"identify\",\n userId,\n traits: traits ?? {},\n });\n },\n };\n}\n\nlet defaultClient: DumbledorClient | null = null;\n\nexport function init(config: DumbledorClientConfig): DumbledorClient {\n defaultClient = createClient(config);\n return defaultClient;\n}\n\nexport function getClient(): DumbledorClient {\n if (!defaultClient) {\n throw new Error(\n \"Dumbledor is not initialized. Call init(), wrap with DumbledorProvider, or createClient() first.\",\n );\n }\n\n return defaultClient;\n}\n\nexport function page(input?: PageviewInput): void {\n getClient().page(input);\n}\n\nexport function track(name: string, properties?: Record<string, unknown>): void {\n getClient().track(name, properties);\n}\n\nexport function identify(userId: string, traits?: Record<string, unknown>): void {\n getClient().identify(userId, traits);\n}\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport { getClient } from \"../client\";\nimport type { DumbledorClient } from \"../types\";\n\nexport const DumbledorContext = createContext<DumbledorClient | null>(null);\n\nexport function useDumbledor(): DumbledorClient {\n const client = useContext(DumbledorContext);\n if (client) {\n return client;\n }\n\n return getClient();\n}\n","\"use client\";\n\nimport { useEffect, useRef } from \"react\";\nimport { useDumbledor } from \"./context\";\n\nexport type PageViewProps = {\n /** Route pathname. When omitted, falls back to `window.location.pathname`. */\n pathname?: string;\n /** Track the first render. Default: `true`. */\n trackInitialView?: boolean;\n};\n\nexport function PageView({ pathname, trackInitialView = true }: PageViewProps) {\n const client = useDumbledor();\n const lastPathRef = useRef<string | null>(null);\n\n useEffect(() => {\n const nextPath =\n pathname ??\n (typeof window !== \"undefined\"\n ? `${window.location.pathname}${window.location.search}`\n : null);\n\n if (!nextPath || lastPathRef.current === nextPath) {\n return;\n }\n\n const isFirstView = lastPathRef.current === null;\n lastPathRef.current = nextPath;\n\n if (isFirstView && !trackInitialView) {\n return;\n }\n\n client.page();\n }, [client, pathname, trackInitialView]);\n\n return null;\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { useDumbledor } from \"./context\";\n\nexport function useTrack() {\n const client = useDumbledor();\n return useCallback(\n (name: string, properties?: Record<string, unknown>) => {\n client.track(name, properties);\n },\n [client],\n );\n}\n\nexport function useIdentify() {\n const client = useDumbledor();\n return useCallback(\n (userId: string, traits?: Record<string, unknown>) => {\n client.identify(userId, traits);\n },\n [client],\n );\n}\n\nexport function usePage() {\n const client = useDumbledor();\n return useCallback(\n (input?: Parameters<typeof client.page>[0]) => {\n client.page(input);\n },\n [client],\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { init } from \"../client\";\nimport type { DumbledorClientConfig } from \"../types\";\nimport { DumbledorContext } from \"./context\";\n\nexport type DumbledorProviderProps = DumbledorClientConfig & {\n children: React.ReactNode;\n};\n\nexport function DumbledorProvider({\n children,\n websiteId,\n ingestUrl,\n honorDoNotTrack,\n disabled,\n fetch,\n}: DumbledorProviderProps) {\n const client = useMemo(\n () =>\n init({\n websiteId,\n ingestUrl,\n honorDoNotTrack,\n disabled,\n fetch,\n }),\n [websiteId, ingestUrl, honorDoNotTrack, disabled, fetch],\n );\n\n return <DumbledorContext.Provider value={client}>{children}</DumbledorContext.Provider>;\n}\n"]}
1
+ {"version":3,"sources":["../../src/constants.ts","../../src/config.ts","../../src/dnt.ts","../../src/client.ts","../../src/react/context.tsx","../../src/react/page-view.tsx","../../src/react/hooks.ts","../../src/react/provider.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export const DEFAULT_INGEST_URL = \"https://ingest.dumbledor.com\";\n\nexport const UUID_PATTERN =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n","import { DEFAULT_INGEST_URL, UUID_PATTERN } from \"./constants\";\nimport type {\n CollectPayload,\n CollectPayloadInput,\n DumbledorClientConfig,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nexport class DumbledorConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DumbledorConfigError\";\n }\n}\n\nexport function normalizeIngestUrl(value?: string): string {\n const raw = value?.trim() || DEFAULT_INGEST_URL;\n return raw.replace(/\\/$/, \"\");\n}\n\nexport function assertClientConfig(config: DumbledorClientConfig): ResolvedDumbledorConfig {\n const websiteId = config.websiteId?.trim();\n\n if (!websiteId) {\n throw new DumbledorConfigError(\"websiteId is required.\");\n }\n\n if (!UUID_PATTERN.test(websiteId)) {\n throw new DumbledorConfigError(\"websiteId must be a valid UUID.\");\n }\n\n return {\n websiteId,\n ingestUrl: normalizeIngestUrl(config.ingestUrl),\n honorDoNotTrack: config.honorDoNotTrack ?? false,\n disabled: config.disabled ?? false,\n fetch: config.fetch,\n };\n}\n\nexport function withWebsiteId(\n payload: CollectPayloadInput,\n websiteId: string,\n): CollectPayload {\n return {\n ...payload,\n websiteId,\n };\n}\n\nexport function resolveFetch(fetchImpl?: typeof fetch): typeof fetch {\n const resolved = fetchImpl ?? globalThis.fetch;\n if (!resolved) {\n throw new DumbledorConfigError(\"fetch is not available in this runtime.\");\n }\n\n return resolved;\n}\n","type NavigatorWithMsDnt = Navigator & {\n msDoNotTrack?: string | number | null;\n};\n\ntype WindowWithDnt = Window & {\n doNotTrack?: string | number | null;\n};\n\nexport function hasDoNotTrack(): boolean {\n if (typeof window === \"undefined\") {\n return false;\n }\n\n const win = window as WindowWithDnt;\n const dnt =\n win.doNotTrack ??\n win.navigator.doNotTrack ??\n (win.navigator as NavigatorWithMsDnt).msDoNotTrack;\n\n return dnt === 1 || dnt === \"1\" || dnt === \"yes\";\n}\n\nexport function isTrackingDisabled(honorDoNotTrack: boolean): boolean {\n return honorDoNotTrack && hasDoNotTrack();\n}\n","import { assertClientConfig, resolveFetch, withWebsiteId } from \"./config\";\nimport { isTrackingDisabled } from \"./dnt\";\nimport type {\n CollectPayloadInput,\n CollectResponse,\n DumbledorClient,\n DumbledorClientConfig,\n PageviewInput,\n ResolvedDumbledorConfig,\n} from \"./types\";\n\nconst CACHE_HEADER = \"x-dumbledor-cache\";\n\nfunction defaultPageviewInput(): PageviewInput {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n return {};\n }\n\n return {\n url: window.location.href,\n referrer: document.referrer || undefined,\n title: document.title,\n hostname: window.location.hostname,\n language: navigator.language,\n screen: typeof screen !== \"undefined\" ? `${screen.width}x${screen.height}` : undefined,\n };\n}\n\ntype SendOptions = {\n clearCache?: boolean;\n};\n\nexport function createTransport(config: ResolvedDumbledorConfig) {\n const endpoint = `${config.ingestUrl}/v1/collect`;\n const fetchImpl = resolveFetch(config.fetch);\n let cache: string | undefined;\n\n return async function send(\n payload: CollectPayloadInput,\n options?: SendOptions,\n ): Promise<CollectResponse | void> {\n if (config.disabled || isTrackingDisabled(config.honorDoNotTrack)) {\n return;\n }\n\n if (options?.clearCache) {\n cache = undefined;\n }\n\n const body = withWebsiteId(payload, config.websiteId);\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (cache) {\n headers[CACHE_HEADER] = cache;\n }\n\n try {\n const response = await fetchImpl(endpoint, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n keepalive: true,\n credentials: \"omit\",\n mode: \"cors\",\n });\n\n if (!response.ok) {\n return {\n ok: false,\n error: `Ingest request failed with status ${response.status}`,\n };\n }\n\n const data = (await response.json()) as CollectResponse;\n if (data.cache) {\n cache = data.cache;\n }\n\n return data;\n } catch {\n return {\n ok: false,\n error: \"Ingest request failed\",\n };\n }\n };\n}\n\nexport function createClient(config: DumbledorClientConfig): DumbledorClient {\n const resolved = assertClientConfig(config);\n const send = createTransport(resolved);\n\n return {\n config: resolved,\n page(input = {}) {\n const defaults = defaultPageviewInput();\n const url = input.url ?? defaults.url;\n if (!url) {\n return;\n }\n\n void send({\n type: \"pageview\",\n url,\n referrer: input.referrer ?? defaults.referrer,\n title: input.title ?? defaults.title,\n hostname: input.hostname ?? defaults.hostname,\n language: input.language ?? defaults.language,\n screen: input.screen ?? defaults.screen,\n });\n },\n track(name, properties) {\n const defaults = defaultPageviewInput();\n void send({\n type: \"track\",\n name,\n properties: properties ?? {},\n url: defaults.url,\n hostname: defaults.hostname,\n });\n },\n identify(userId, traits) {\n void send(\n {\n type: \"identify\",\n userId,\n traits: traits ?? {},\n },\n { clearCache: true },\n );\n },\n };\n}\n\nlet defaultClient: DumbledorClient | null = null;\n\nexport function init(config: DumbledorClientConfig): DumbledorClient {\n defaultClient = createClient(config);\n return defaultClient;\n}\n\nexport function getClient(): DumbledorClient {\n if (!defaultClient) {\n throw new Error(\n \"Dumbledor is not initialized. Call init(), wrap with DumbledorProvider, or createClient() first.\",\n );\n }\n\n return defaultClient;\n}\n\nexport function page(input?: PageviewInput): void {\n getClient().page(input);\n}\n\nexport function track(name: string, properties?: Record<string, unknown>): void {\n getClient().track(name, properties);\n}\n\nexport function identify(userId: string, traits?: Record<string, unknown>): void {\n getClient().identify(userId, traits);\n}\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport { getClient } from \"../client\";\nimport type { DumbledorClient } from \"../types\";\n\nexport const DumbledorContext = createContext<DumbledorClient | null>(null);\n\nexport function useDumbledor(): DumbledorClient {\n const client = useContext(DumbledorContext);\n if (client) {\n return client;\n }\n\n return getClient();\n}\n","\"use client\";\n\nimport { useEffect, useRef } from \"react\";\nimport { useDumbledor } from \"./context\";\n\nexport type PageViewProps = {\n /** Route pathname. When omitted, falls back to `window.location.pathname`. */\n pathname?: string;\n /** Track the first render. Default: `true`. */\n trackInitialView?: boolean;\n};\n\nexport function PageView({ pathname, trackInitialView = true }: PageViewProps) {\n const client = useDumbledor();\n const lastPathRef = useRef<string | null>(null);\n\n useEffect(() => {\n const nextPath =\n pathname ??\n (typeof window !== \"undefined\"\n ? `${window.location.pathname}${window.location.search}`\n : null);\n\n if (!nextPath || lastPathRef.current === nextPath) {\n return;\n }\n\n const isFirstView = lastPathRef.current === null;\n lastPathRef.current = nextPath;\n\n if (isFirstView && !trackInitialView) {\n return;\n }\n\n client.page();\n }, [client, pathname, trackInitialView]);\n\n return null;\n}\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport { useDumbledor } from \"./context\";\n\nexport function useTrack() {\n const client = useDumbledor();\n return useCallback(\n (name: string, properties?: Record<string, unknown>) => {\n client.track(name, properties);\n },\n [client],\n );\n}\n\nexport function useIdentify() {\n const client = useDumbledor();\n return useCallback(\n (userId: string, traits?: Record<string, unknown>) => {\n client.identify(userId, traits);\n },\n [client],\n );\n}\n\nexport function usePage() {\n const client = useDumbledor();\n return useCallback(\n (input?: Parameters<typeof client.page>[0]) => {\n client.page(input);\n },\n [client],\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { init } from \"../client\";\nimport type { DumbledorClientConfig } from \"../types\";\nimport { DumbledorContext } from \"./context\";\n\nexport type DumbledorProviderProps = DumbledorClientConfig & {\n children: React.ReactNode;\n};\n\nexport function DumbledorProvider({\n children,\n websiteId,\n ingestUrl,\n honorDoNotTrack,\n disabled,\n fetch,\n}: DumbledorProviderProps) {\n const client = useMemo(\n () =>\n init({\n websiteId,\n ingestUrl,\n honorDoNotTrack,\n disabled,\n fetch,\n }),\n [websiteId, ingestUrl, honorDoNotTrack, disabled, fetch],\n );\n\n return <DumbledorContext.Provider value={client}>{children}</DumbledorContext.Provider>;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { b as CollectResponse, S as ServerContext, e as DumbledorServerConfig } from '../types-DWa2kNUy.cjs';
1
+ import { b as CollectResponse, S as ServerContext, e as DumbledorServerConfig } from '../types-jDs6E55a.cjs';
2
2
 
3
3
  type DumbledorServer = {
4
4
  page: (input: {
@@ -1,4 +1,4 @@
1
- import { b as CollectResponse, S as ServerContext, e as DumbledorServerConfig } from '../types-DWa2kNUy.js';
1
+ import { b as CollectResponse, S as ServerContext, e as DumbledorServerConfig } from '../types-jDs6E55a.js';
2
2
 
3
3
  type DumbledorServer = {
4
4
  page: (input: {
@@ -61,6 +61,7 @@ type ServerContext = {
61
61
  };
62
62
  type CollectResponse = {
63
63
  ok: boolean;
64
+ cache?: string;
64
65
  skipped?: string;
65
66
  error?: string;
66
67
  };
@@ -61,6 +61,7 @@ type ServerContext = {
61
61
  };
62
62
  type CollectResponse = {
63
63
  ok: boolean;
64
+ cache?: string;
64
65
  skipped?: string;
65
66
  error?: string;
66
67
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dumbledor/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Official Dumbledor analytics SDK for browser, React, Next.js, and server runtimes.",
5
5
  "license": "MIT",
6
6
  "type": "module",