@nexly/web 0.17.0 → 1.0.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/README.md CHANGED
@@ -90,7 +90,32 @@ await fetch('/api/link-visitor', {
90
90
  })
91
91
  ```
92
92
 
93
- `getVisitorId()` reads the persistent anonymous id Nexly stores in `localStorage`; `getSessionId()` reads the 30-minute tab session id from `sessionStorage`. Both are plain strings, safe to call from anywhere.
93
+ `getVisitorId()` reads the persistent pseudonymous ID Nexly stores in `localStorage`; `getSessionId()` reads the 30-minute session ID that is also stored in `localStorage` so it can be shared across tabs. Both are plain strings, safe to call from anywhere. Make sure your use of device storage and analytics has the notices, lawful basis, and consent required in the visitor's jurisdiction.
94
+
95
+ ## Privacy mode (no device storage)
96
+
97
+ Initialize with `privacyMode: true` and Nexly never reads or writes `localStorage` (or any other device storage) for its identifiers:
98
+
99
+ ```ts
100
+ const client = Nexly.init({
101
+ appId: 'your-app-id',
102
+ key: 'your-ingest-key',
103
+ privacyMode: true,
104
+ })
105
+ ```
106
+
107
+ In privacy mode events carry no client-side visitor or session ID. Instead the Nexly collector derives a short-lived visit fingerprint server-side from the request IP and User-Agent. The fingerprint rotates every 24 hours and neither the IP nor the User-Agent is stored, so no persistent identifier links the same device across days. Visitors, visits, bounce rate, and pageviews keep working; cross-day returning-visitor metrics do not (the same trade-off Plausible and Fathom accept).
108
+
109
+ If your application already has its own notion of a user or session, you can supply identifiers explicitly — they take precedence over both `localStorage` and the server-side fingerprint:
110
+
111
+ ```ts
112
+ import { setVisitorId, setSessionId } from '@nexly/web'
113
+
114
+ setVisitorId(user.analyticsId) // stable cross-visit identity you control
115
+ setSessionId(session.id) // explicit visit grouping
116
+ ```
117
+
118
+ In privacy mode `getVisitorId()` / `getSessionId()` return the manual override when set, and an empty string otherwise. Whether privacy mode removes the need for a consent banner depends on the laws that apply to your visitors — the SDK guarantees only that it performs no device-storage access.
94
119
 
95
120
  See the full recipe (backend storage + emitting linked events) in the [`@nexly/node` README](https://www.npmjs.com/package/@nexly/node).
96
121
 
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Does not include geo (country/region/city) — that requires server-side IP lookup.
5
5
  */
6
- import { getSessionId, getVisitorId } from './session.js';
6
+ import { getSessionId, getVisitorId } from './identity.js';
7
7
  function safe(fn) {
8
8
  try {
9
9
  return fn();
@@ -1 +1 @@
1
- {"version":3,"file":"engagement.d.ts","sourceRoot":"","sources":["../../src/events/engagement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AA4BrD,KAAK,MAAM,GAAG,MAAM,IAAI,CAAA;AAExB;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAgHzE"}
1
+ {"version":3,"file":"engagement.d.ts","sourceRoot":"","sources":["../../src/events/engagement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AA6BrD,KAAK,MAAM,GAAG,MAAM,IAAI,CAAA;AAExB;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAgHzE"}
@@ -9,6 +9,7 @@ function sendEngagement(creds, eventName, eventType, data, sessionContext) {
9
9
  collectUrl: creds.collectUrl,
10
10
  credentials: { appId: creds.appId, apiToken: creds.apiToken },
11
11
  client: creds.client,
12
+ privacyMode: creds.privacyMode,
12
13
  eventName,
13
14
  eventType,
14
15
  context: collectEventMeta(),
@@ -1 +1 @@
1
- {"version":3,"file":"outbound-links.d.ts","sourceRoot":"","sources":["../../src/events/outbound-links.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAkKrD,KAAK,MAAM,GAAG,MAAM,IAAI,CAAA;AAExB;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CA0C3E"}
1
+ {"version":3,"file":"outbound-links.d.ts","sourceRoot":"","sources":["../../src/events/outbound-links.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAmKrD,KAAK,MAAM,GAAG,MAAM,IAAI,CAAA;AAExB;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CA0C3E"}
@@ -49,6 +49,7 @@ function sendOutbound(creds, eventName, data) {
49
49
  collectUrl: creds.collectUrl,
50
50
  credentials: { appId: creds.appId, apiToken: creds.apiToken },
51
51
  client: creds.client,
52
+ privacyMode: creds.privacyMode,
52
53
  eventName,
53
54
  eventType: 'navigation',
54
55
  context: collectEventMeta(),
@@ -1 +1 @@
1
- {"version":3,"file":"pageview.d.ts","sourceRoot":"","sources":["../../src/events/pageview.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAIrD,uDAAuD;AACvD,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,EAAE,IAAI,GAAE,MAA6B,GAAG,OAAO,CAW1G"}
1
+ {"version":3,"file":"pageview.d.ts","sourceRoot":"","sources":["../../src/events/pageview.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAIrD,uDAAuD;AACvD,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,EAAE,IAAI,GAAE,MAA6B,GAAG,OAAO,CAY1G"}
@@ -12,6 +12,7 @@ export function sendPageViewBeacon(creds, path = getDefaultPathname()) {
12
12
  collectUrl: creds.collectUrl,
13
13
  credentials: { appId: creds.appId, apiToken: creds.apiToken },
14
14
  client: creds.client,
15
+ privacyMode: creds.privacyMode,
15
16
  eventName: 'pageview',
16
17
  eventType: 'pageview',
17
18
  context: { ...collectEventMeta(), path },
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Browser identity resolution.
3
+ *
4
+ * Central switchboard between the storage-backed identifiers (`./session.js`)
5
+ * and privacy mode. Everything that attaches `visitor_id` / `session_id` to
6
+ * an event (browser-meta, engagement, outbound links) reads through this
7
+ * module, so the privacy-mode guarantee — no device-storage reads or writes —
8
+ * holds for every code path, not just `Nexly.pageview()`.
9
+ */
10
+ /** Called from `Nexly.init` when the browser client starts. */
11
+ export declare function configureBrowserIdentity(options: {
12
+ privacyMode?: boolean;
13
+ }): void;
14
+ /**
15
+ * Override the visitor id attached to subsequent events. Works in both modes;
16
+ * in privacy mode it is the only way to get a stable cross-visit visitor id.
17
+ * Pass an empty string to clear the override.
18
+ */
19
+ export declare function setVisitorId(id: string): void;
20
+ /**
21
+ * Override the session id attached to subsequent events. Works in both modes;
22
+ * in privacy mode it is the only way to control visit grouping client-side.
23
+ * Pass an empty string to clear the override.
24
+ */
25
+ export declare function setSessionId(id: string): void;
26
+ /** True when the SDK was initialized with `privacyMode: true`. */
27
+ export declare function isPrivacyMode(): boolean;
28
+ /**
29
+ * Resolved visitor id attached to each event.
30
+ *
31
+ * Default mode: manual override, else the persistent `localStorage` id.
32
+ * Privacy mode: manual override, else `''` — the SDK never touches device
33
+ * storage, and the collector derives a daily-rotating fingerprint instead.
34
+ */
35
+ export declare function getVisitorId(): string;
36
+ /**
37
+ * Resolved session id attached to each event.
38
+ *
39
+ * Default mode: manual override, else the 30-minute `localStorage` session.
40
+ * Privacy mode: manual override, else `''` (server-side visit grouping).
41
+ */
42
+ export declare function getSessionId(): string;
43
+ //# sourceMappingURL=identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH,+DAA+D;AAC/D,wBAAgB,wBAAwB,CAAC,OAAO,EAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAEjF;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE7C;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE7C;AAED,kEAAkE;AAClE,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAIrC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAIrC"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Browser identity resolution.
3
+ *
4
+ * Central switchboard between the storage-backed identifiers (`./session.js`)
5
+ * and privacy mode. Everything that attaches `visitor_id` / `session_id` to
6
+ * an event (browser-meta, engagement, outbound links) reads through this
7
+ * module, so the privacy-mode guarantee — no device-storage reads or writes —
8
+ * holds for every code path, not just `Nexly.pageview()`.
9
+ */
10
+ import { getStoredSessionId, getStoredVisitorId } from './session.js';
11
+ let privacyMode = false;
12
+ let manualVisitorId = '';
13
+ let manualSessionId = '';
14
+ /** Called from `Nexly.init` when the browser client starts. */
15
+ export function configureBrowserIdentity(options) {
16
+ privacyMode = options.privacyMode === true;
17
+ }
18
+ /**
19
+ * Override the visitor id attached to subsequent events. Works in both modes;
20
+ * in privacy mode it is the only way to get a stable cross-visit visitor id.
21
+ * Pass an empty string to clear the override.
22
+ */
23
+ export function setVisitorId(id) {
24
+ manualVisitorId = typeof id === 'string' ? id.trim() : '';
25
+ }
26
+ /**
27
+ * Override the session id attached to subsequent events. Works in both modes;
28
+ * in privacy mode it is the only way to control visit grouping client-side.
29
+ * Pass an empty string to clear the override.
30
+ */
31
+ export function setSessionId(id) {
32
+ manualSessionId = typeof id === 'string' ? id.trim() : '';
33
+ }
34
+ /** True when the SDK was initialized with `privacyMode: true`. */
35
+ export function isPrivacyMode() {
36
+ return privacyMode;
37
+ }
38
+ /**
39
+ * Resolved visitor id attached to each event.
40
+ *
41
+ * Default mode: manual override, else the persistent `localStorage` id.
42
+ * Privacy mode: manual override, else `''` — the SDK never touches device
43
+ * storage, and the collector derives a daily-rotating fingerprint instead.
44
+ */
45
+ export function getVisitorId() {
46
+ if (manualVisitorId)
47
+ return manualVisitorId;
48
+ if (privacyMode)
49
+ return '';
50
+ return getStoredVisitorId();
51
+ }
52
+ /**
53
+ * Resolved session id attached to each event.
54
+ *
55
+ * Default mode: manual override, else the 30-minute `localStorage` session.
56
+ * Privacy mode: manual override, else `''` (server-side visit grouping).
57
+ */
58
+ export function getSessionId() {
59
+ if (manualSessionId)
60
+ return manualSessionId;
61
+ if (privacyMode)
62
+ return '';
63
+ return getStoredSessionId();
64
+ }
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  export { Nexly } from './nexly.js';
5
5
  export type { NexlyEventInput, NexlyEventType, NexlyInit } from '@nexly/core';
6
6
  export { collectBrowserMeta, collectSessionMeta, collectEventMeta } from './browser-meta.js';
7
- export { getSessionId, getVisitorId } from './session.js';
7
+ export { getSessionId, getVisitorId, isPrivacyMode, setSessionId, setVisitorId, } from './identity.js';
8
8
  export { sendBeaconCollect, type SendBeaconCollectInput } from './beacon.js';
9
9
  export { getDefaultPathname, sendPageViewBeacon, startEngagementTracking, startOutboundLinkTracking, } from './events/index.js';
10
10
  export type { CData, CollectCredentials, IngestCredentials, StandardAttributionKey, StandardContextOverride, TrackEventInput, } from '@nexly/core';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC7E,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAC5F,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AACzD,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAC5E,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EACV,KAAK,EACL,kBAAkB,EAClB,iBAAiB,EACjB,sBAAsB,EACtB,uBAAuB,EACvB,eAAe,GAChB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC7E,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAC5F,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,YAAY,GACb,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAC5E,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EACV,KAAK,EACL,kBAAkB,EAClB,iBAAiB,EACjB,sBAAsB,EACtB,uBAAuB,EACvB,eAAe,GAChB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA"}
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export { Nexly } from './nexly.js';
5
5
  export { collectBrowserMeta, collectSessionMeta, collectEventMeta } from './browser-meta.js';
6
- export { getSessionId, getVisitorId } from './session.js';
6
+ export { getSessionId, getVisitorId, isPrivacyMode, setSessionId, setVisitorId, } from './identity.js';
7
7
  export { sendBeaconCollect } from './beacon.js';
8
8
  export { getDefaultPathname, sendPageViewBeacon, startEngagementTracking, startOutboundLinkTracking, } from './events/index.js';
9
9
  export { buildCollectPayload, isStandardAttributionKey, STANDARD_ATTRIBUTION_KEYS } from '@nexly/core';
@@ -1 +1 @@
1
- {"version":3,"file":"nexly.d.ts","sourceRoot":"","sources":["../src/nexly.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAe,KAAK,SAAS,EAAE,MAAM,aAAa,CAAA;AAOpE;;;GAGG;AACH,qBAAa,KAAM,SAAQ,SAAS;IAClC,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,iBAAiB,CAA4B;IAErD,0FAA0F;IAC1F,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,GAAG,KAAK;IAMtC,uEAAuE;IACvE,MAAM,CAAC,WAAW,IAAI,KAAK,GAAG,IAAI;gBAItB,IAAI,EAAE,SAAS;cAIR,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO;cAKpD,mBAAmB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;cAI9C,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAI1D,cAAc,IAAI,MAAM;IAIjC;;;;OAIG;IACH,eAAe,IAAI,MAAM,IAAI;IAgB7B;;;;OAIG;IACH,kBAAkB,IAAI,MAAM,IAAI;CAejC"}
1
+ {"version":3,"file":"nexly.d.ts","sourceRoot":"","sources":["../src/nexly.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAe,KAAK,SAAS,EAAE,MAAM,aAAa,CAAA;AAQpE;;;GAGG;AACH,qBAAa,KAAM,SAAQ,SAAS;IAClC,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,iBAAiB,CAA4B;IAErD,0FAA0F;IAC1F,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,GAAG,KAAK;IAOtC,uEAAuE;IACvE,MAAM,CAAC,WAAW,IAAI,KAAK,GAAG,IAAI;gBAItB,IAAI,EAAE,SAAS;cAIR,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO;cAKpD,mBAAmB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;cAI9C,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAI1D,cAAc,IAAI,MAAM;IAIjC;;;;OAIG;IACH,eAAe,IAAI,MAAM,IAAI;IAiB7B;;;;OAIG;IACH,kBAAkB,IAAI,MAAM,IAAI;CAgBjC"}
package/dist/nexly.js CHANGED
@@ -4,6 +4,7 @@ import { collectEventMeta, collectSessionMeta } from './browser-meta.js';
4
4
  import { startEngagementTracking } from './events/engagement.js';
5
5
  import { startOutboundLinkTracking } from './events/outbound-links.js';
6
6
  import { getDefaultPathname } from './events/pageview.js';
7
+ import { configureBrowserIdentity } from './identity.js';
7
8
  /**
8
9
  * Browser-specific Nexly client. Implements transport via `navigator.sendBeacon`
9
10
  * and metadata via DOM/Navigator APIs.
@@ -13,6 +14,7 @@ export class Nexly extends NexlyBase {
13
14
  outboundLinksStop = null;
14
15
  /** Creates (or replaces) the browser singleton. Default `client` is `NexlyClient.Web`. */
15
16
  static init(options) {
17
+ configureBrowserIdentity({ privacyMode: options.privacyMode });
16
18
  const instance = new Nexly({ ...options, client: options.client ?? NexlyClient.Web });
17
19
  Nexly.setInstance(instance);
18
20
  return instance;
@@ -52,6 +54,7 @@ export class Nexly extends NexlyBase {
52
54
  appId: this.appId,
53
55
  apiToken: this.key,
54
56
  client: this.client,
57
+ privacyMode: this.privacyMode,
55
58
  });
56
59
  this.engagementStop = stop;
57
60
  return () => {
@@ -74,6 +77,7 @@ export class Nexly extends NexlyBase {
74
77
  appId: this.appId,
75
78
  apiToken: this.key,
76
79
  client: this.client,
80
+ privacyMode: this.privacyMode,
77
81
  });
78
82
  this.outboundLinksStop = stop;
79
83
  return () => {
package/dist/session.d.ts CHANGED
@@ -1,13 +1,19 @@
1
1
  /**
2
- * Persistent anonymous visitor ID (localStorage). One per browser + origin.
2
+ * Persistent pseudonymous visitor ID (localStorage). One per browser + origin.
3
+ *
4
+ * Storage-backed implementation — application code should read identity via
5
+ * `./identity.js`, which layers privacy mode and manual overrides on top.
3
6
  */
4
- export declare function getVisitorId(): string;
7
+ export declare function getStoredVisitorId(): string;
5
8
  /**
6
9
  * Session ID with 30-minute inactivity timeout.
7
10
  *
8
11
  * Stored in `localStorage` (not `sessionStorage`) so the same session is shared
9
12
  * across tabs and survives tab/window close. The 30-minute inactivity window is
10
13
  * enforced via `SESSION_TS_KEY`, matching Plausible's visit definition.
14
+ *
15
+ * Storage-backed implementation — application code should read identity via
16
+ * `./identity.js`, which layers privacy mode and manual overrides on top.
11
17
  */
12
- export declare function getSessionId(): string;
18
+ export declare function getStoredSessionId(): string;
13
19
  //# sourceMappingURL=session.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAoBA;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAUrC;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAkBrC"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAoBA;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAU3C;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAkB3C"}
package/dist/session.js CHANGED
@@ -15,9 +15,12 @@ function nowMs() {
15
15
  return Date.now();
16
16
  }
17
17
  /**
18
- * Persistent anonymous visitor ID (localStorage). One per browser + origin.
18
+ * Persistent pseudonymous visitor ID (localStorage). One per browser + origin.
19
+ *
20
+ * Storage-backed implementation — application code should read identity via
21
+ * `./identity.js`, which layers privacy mode and manual overrides on top.
19
22
  */
20
- export function getVisitorId() {
23
+ export function getStoredVisitorId() {
21
24
  if (typeof localStorage === 'undefined') {
22
25
  return generateId();
23
26
  }
@@ -34,8 +37,11 @@ export function getVisitorId() {
34
37
  * Stored in `localStorage` (not `sessionStorage`) so the same session is shared
35
38
  * across tabs and survives tab/window close. The 30-minute inactivity window is
36
39
  * enforced via `SESSION_TS_KEY`, matching Plausible's visit definition.
40
+ *
41
+ * Storage-backed implementation — application code should read identity via
42
+ * `./identity.js`, which layers privacy mode and manual overrides on top.
37
43
  */
38
- export function getSessionId() {
44
+ export function getStoredSessionId() {
39
45
  if (typeof localStorage === 'undefined') {
40
46
  return generateId();
41
47
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nexly/web",
3
- "version": "0.17.0",
3
+ "version": "1.0.0",
4
4
  "description": "Nexly browser ingest SDK: sendBeacon transport, DOM metadata, engagement listeners on top of @nexly/core",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -38,7 +38,7 @@
38
38
  "node": ">=20"
39
39
  },
40
40
  "dependencies": {
41
- "@nexly/core": "0.17.0"
41
+ "@nexly/core": "1.0.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "typescript": "~6.0.2"