@networkpro/web 1.10.1 → 1.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +66 -0
- package/CHANGELOG.template.md +63 -0
- package/LICENSE.md +19 -8
- package/cspell.json +3 -0
- package/jsconfig.json +1 -15
- package/jsconfig.template.jsonc +32 -0
- package/netlify.toml +0 -1
- package/package.json +9 -9
- package/src/app.html +1 -1
- package/src/hooks.server.js +13 -0
- package/src/lib/components/Badges.svelte +6 -2
- package/src/lib/components/LegalNav.svelte +6 -1
- package/src/lib/components/MetaTags.svelte +8 -2
- package/src/lib/components/layout/Footer.svelte +3 -4
- package/src/lib/index.js +7 -33
- package/src/lib/pages/LicenseContent.svelte +22 -3
- package/src/lib/pages/PrivacyContent.svelte +81 -74
- package/src/lib/pages/PrivacyDashboard.svelte +78 -70
- package/src/lib/stores/posthog.js +115 -0
- package/src/lib/stores/trackingPreferences.js +222 -0
- package/src/lib/styles/css/default.css +12 -0
- package/src/lib/styles/global.min.css +1 -1
- package/src/lib/types/appConstants.js +60 -0
- package/src/lib/types/fossTypes.js +17 -0
- package/src/routes/+layout.js +0 -2
- package/src/routes/+layout.svelte +34 -40
- package/static/docs/tracking.md +63 -0
- package/static/img/fb-banner.png +0 -0
- package/static/offline.min.css +2 -3
- package/svelte.config.js +4 -1
- package/vite.config.js +2 -4
- package/CODE_OF_CONDUCT.md +0 -173
- package/src/lib/components/PostHog.svelte +0 -36
- package/src/lib/utils/privacy.js +0 -38
- package/src/lib/utils/trackingCookies.js +0 -40
- package/src/lib/utils/trackingStatus.js +0 -46
|
@@ -9,41 +9,33 @@ This file is part of Network Pro.
|
|
|
9
9
|
<script>
|
|
10
10
|
import { base } from "$app/paths";
|
|
11
11
|
import { onMount } from "svelte";
|
|
12
|
-
import { getTrackingPreferences } from "$lib/utils/trackingStatus.js";
|
|
13
|
-
/** @type {(type: 'enable' | 'disable') => void} */
|
|
14
12
|
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
trackingPreferences,
|
|
14
|
+
setOptIn,
|
|
15
|
+
setOptOut,
|
|
16
|
+
clearPrefs,
|
|
17
|
+
} from "$lib/stores/trackingPreferences.js";
|
|
18
18
|
import { CONSTANTS } from "$lib";
|
|
19
19
|
|
|
20
|
-
// Log the base path to verify its value
|
|
21
|
-
//console.log("Base path:", base);
|
|
22
|
-
|
|
23
|
-
console.log(CONSTANTS.COMPANY_INFO.APP_NAME);
|
|
24
|
-
|
|
25
20
|
const { COMPANY_INFO, CONTACT, PAGE, NAV } = CONSTANTS;
|
|
26
21
|
|
|
27
|
-
/**
|
|
28
|
-
* URL to the Privacy Rights Request Form redirect route, using the base path
|
|
29
|
-
* URL to the Contact Form redirect route, using the base path
|
|
30
|
-
* URL to the Privacy Dashboard using the base path
|
|
31
|
-
* @type {string}
|
|
32
|
-
*/
|
|
22
|
+
/** @type {string} */
|
|
33
23
|
const prightsLink = `${base}/privacy-rights`;
|
|
24
|
+
|
|
25
|
+
/** @type {string} */
|
|
34
26
|
const contactLink = `${base}/contact`;
|
|
27
|
+
|
|
28
|
+
/** @type {string} */
|
|
35
29
|
const pdashLink = `${base}/privacy-dashboard`;
|
|
36
30
|
|
|
37
|
-
/**
|
|
38
|
-
* URL to the privacy policy in Markdown format
|
|
39
|
-
* External URL to the GPC website
|
|
40
|
-
* @type {string}
|
|
41
|
-
*/
|
|
31
|
+
/** @type {string} */
|
|
42
32
|
const privacyLink = "https://docs.netwk.pro/privacy";
|
|
33
|
+
|
|
34
|
+
/** @type {string} */
|
|
43
35
|
const gpcLink = "https://globalprivacycontrol.org/";
|
|
44
36
|
|
|
45
37
|
/**
|
|
46
|
-
* Table of Contents
|
|
38
|
+
* Table of Contents sections and their headings.
|
|
47
39
|
* @type {{ id: string, text: string }[]}
|
|
48
40
|
*/
|
|
49
41
|
const tocLinks = [
|
|
@@ -67,47 +59,49 @@ This file is part of Network Pro.
|
|
|
67
59
|
/** @type {string} */
|
|
68
60
|
const classSmall = "small-text";
|
|
69
61
|
|
|
70
|
-
|
|
71
|
-
let
|
|
72
|
-
let trackingStatus = "";
|
|
62
|
+
/** @type {boolean} */
|
|
63
|
+
let optedOut;
|
|
73
64
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
65
|
+
/** @type {boolean} */
|
|
66
|
+
let optedIn;
|
|
67
|
+
|
|
68
|
+
/** @type {string} */
|
|
69
|
+
let trackingStatus;
|
|
70
|
+
|
|
71
|
+
// Reactive assignments from the store
|
|
72
|
+
$: ({ optedOut, optedIn, status: trackingStatus } = $trackingPreferences);
|
|
81
73
|
|
|
82
74
|
/**
|
|
83
|
-
* Toggle tracking opt-out.
|
|
75
|
+
* Toggle tracking opt-out setting.
|
|
84
76
|
* @param {boolean} value
|
|
85
77
|
*/
|
|
86
78
|
function toggleTracking(value) {
|
|
87
|
-
|
|
88
|
-
if (optedOut) {
|
|
79
|
+
if (value) {
|
|
89
80
|
console.log("[Tracking] User opted out");
|
|
90
|
-
|
|
81
|
+
setOptOut();
|
|
91
82
|
} else {
|
|
92
83
|
console.log("[Tracking] User cleared opt-out");
|
|
93
|
-
|
|
84
|
+
clearPrefs();
|
|
94
85
|
}
|
|
95
86
|
}
|
|
96
87
|
|
|
97
88
|
/**
|
|
98
|
-
* Toggle tracking opt-in.
|
|
89
|
+
* Toggle tracking opt-in setting.
|
|
99
90
|
* @param {boolean} value
|
|
100
91
|
*/
|
|
101
92
|
function toggleOptIn(value) {
|
|
102
|
-
|
|
103
|
-
if (optedIn) {
|
|
93
|
+
if (value) {
|
|
104
94
|
console.log("[Tracking] User opted in");
|
|
105
|
-
|
|
95
|
+
setOptIn();
|
|
106
96
|
} else {
|
|
107
97
|
console.log("[Tracking] User cleared opt-in");
|
|
108
|
-
|
|
98
|
+
clearPrefs();
|
|
109
99
|
}
|
|
110
100
|
}
|
|
101
|
+
|
|
102
|
+
onMount(() => {
|
|
103
|
+
console.log("[Tracking] Store initialized:", $trackingPreferences.status);
|
|
104
|
+
});
|
|
111
105
|
</script>
|
|
112
106
|
|
|
113
107
|
<!-- BEGIN TITLE -->
|
|
@@ -241,38 +235,51 @@ This file is part of Network Pro.
|
|
|
241
235
|
<div class="spacer"></div>
|
|
242
236
|
|
|
243
237
|
<h3>Tracking Preferences</h3>
|
|
244
|
-
<p id="tracking-status" aria-live="polite">
|
|
245
|
-
<strong>Tracking Status:</strong>
|
|
246
|
-
{trackingStatus}
|
|
247
|
-
</p>
|
|
248
238
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
239
|
+
{#if trackingStatus && trackingStatus !== "⏳ Checking tracking preferences..."}
|
|
240
|
+
<p id="tracking-status" aria-live="polite">
|
|
241
|
+
<strong>Tracking Status:</strong>
|
|
242
|
+
{trackingStatus}
|
|
243
|
+
</p>
|
|
244
|
+
{:else}
|
|
245
|
+
<p id="tracking-status" aria-live="polite">
|
|
246
|
+
<strong>Tracking Status:</strong> <em>Loading…</em>
|
|
247
|
+
</p>
|
|
248
|
+
{/if}
|
|
249
|
+
|
|
250
|
+
<fieldset>
|
|
251
|
+
<legend class="sr-only">Tracking Preference Controls</legend>
|
|
252
|
+
|
|
253
|
+
<!-- Opt-out checkbox -->
|
|
254
|
+
<label>
|
|
255
|
+
<input
|
|
256
|
+
type="checkbox"
|
|
257
|
+
checked={optedOut}
|
|
258
|
+
disabled={optedIn}
|
|
259
|
+
aria-describedby="tracking-status"
|
|
260
|
+
on:change={(e) =>
|
|
261
|
+
toggleTracking(
|
|
262
|
+
/** @type {HTMLInputElement} */ (e.target).checked,
|
|
263
|
+
)} />
|
|
264
|
+
<strong> Disable analytics tracking (opt-out)</strong>
|
|
265
|
+
</label>
|
|
266
|
+
|
|
267
|
+
<br />
|
|
268
|
+
|
|
269
|
+
<!-- Opt-in checkbox -->
|
|
270
|
+
<label>
|
|
271
|
+
<input
|
|
272
|
+
type="checkbox"
|
|
273
|
+
checked={optedIn}
|
|
274
|
+
disabled={optedOut}
|
|
275
|
+
aria-describedby="tracking-status"
|
|
276
|
+
on:change={(e) =>
|
|
277
|
+
toggleOptIn(
|
|
278
|
+
/** @type {HTMLInputElement} */ (e.target).checked,
|
|
279
|
+
)} />
|
|
280
|
+
<strong> Enable analytics tracking (opt-in)</strong>
|
|
281
|
+
</label>
|
|
282
|
+
</fieldset>
|
|
276
283
|
|
|
277
284
|
<div class="spacer"></div>
|
|
278
285
|
|
|
@@ -405,7 +412,7 @@ This file is part of Network Pro.
|
|
|
405
412
|
For questions, please utilize our <a
|
|
406
413
|
rel={PAGE.REL}
|
|
407
414
|
href={contactLink}
|
|
408
|
-
target={PAGE.
|
|
415
|
+
target={PAGE.BLANK}>Contact Form</a> or contact us directly:
|
|
409
416
|
</p>
|
|
410
417
|
<p>
|
|
411
418
|
<strong>{COMPANY_INFO.NAME}</strong><br />
|
|
@@ -9,78 +9,76 @@ This file is part of Network Pro.
|
|
|
9
9
|
<script>
|
|
10
10
|
import { base } from "$app/paths";
|
|
11
11
|
import { onMount } from "svelte";
|
|
12
|
-
import { getTrackingPreferences } from "$lib/utils/trackingStatus.js";
|
|
13
|
-
/** @type {(type: 'enable' | 'disable') => void} */
|
|
14
|
-
import {
|
|
15
|
-
setTrackingPreference,
|
|
16
|
-
clearTrackingPreferences,
|
|
17
|
-
} from "$lib/utils/trackingCookies.js";
|
|
18
|
-
import { CONSTANTS } from "$lib";
|
|
19
12
|
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
import {
|
|
14
|
+
trackingPreferences,
|
|
15
|
+
setOptIn,
|
|
16
|
+
setOptOut,
|
|
17
|
+
clearPrefs,
|
|
18
|
+
} from "$lib/stores/trackingPreferences.js";
|
|
22
19
|
|
|
23
|
-
|
|
20
|
+
import { CONSTANTS } from "$lib";
|
|
24
21
|
|
|
25
22
|
const { CONTACT, PAGE, NAV } = CONSTANTS;
|
|
26
23
|
|
|
27
|
-
/**
|
|
28
|
-
* @type {string}
|
|
29
|
-
* Style class for the div element.
|
|
30
|
-
*/
|
|
31
|
-
const spaceStyle = "spacer";
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* URL to the full Privacy Policy using the base path
|
|
35
|
-
* @type {string}
|
|
36
|
-
*/
|
|
24
|
+
/** @type {string} */
|
|
37
25
|
const privacyPolicy = `${base}/privacy`;
|
|
26
|
+
|
|
27
|
+
/** @type {string} */
|
|
38
28
|
const prightsLink = `${base}/privacy-rights`;
|
|
39
29
|
|
|
40
30
|
/** @type {string} */
|
|
41
31
|
const classSmall = "small-text";
|
|
42
32
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
let trackingStatus = "";
|
|
33
|
+
/** @type {string} */
|
|
34
|
+
const spaceStyle = "spacer";
|
|
46
35
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
36
|
+
/** @type {boolean} */
|
|
37
|
+
let optedOut;
|
|
38
|
+
|
|
39
|
+
/** @type {boolean} */
|
|
40
|
+
let optedIn;
|
|
41
|
+
|
|
42
|
+
/** @type {string} */
|
|
43
|
+
let trackingStatus;
|
|
44
|
+
|
|
45
|
+
// Reactive assignments from the store
|
|
46
|
+
$: ({ optedOut, optedIn, status: trackingStatus } = $trackingPreferences);
|
|
54
47
|
|
|
55
48
|
/**
|
|
56
|
-
* Toggle tracking opt-out.
|
|
49
|
+
* Toggle tracking opt-out setting.
|
|
57
50
|
* @param {boolean} value
|
|
58
51
|
*/
|
|
59
52
|
function toggleTracking(value) {
|
|
60
|
-
|
|
61
|
-
if (optedOut) {
|
|
53
|
+
if (value) {
|
|
62
54
|
console.log("[Tracking] User opted out");
|
|
63
|
-
|
|
55
|
+
setOptOut();
|
|
64
56
|
} else {
|
|
65
57
|
console.log("[Tracking] User cleared opt-out");
|
|
66
|
-
|
|
58
|
+
clearPrefs();
|
|
67
59
|
}
|
|
68
60
|
}
|
|
69
61
|
|
|
70
62
|
/**
|
|
71
|
-
* Toggle tracking opt-in.
|
|
63
|
+
* Toggle tracking opt-in setting.
|
|
72
64
|
* @param {boolean} value
|
|
73
65
|
*/
|
|
74
66
|
function toggleOptIn(value) {
|
|
75
|
-
|
|
76
|
-
if (optedIn) {
|
|
67
|
+
if (value) {
|
|
77
68
|
console.log("[Tracking] User opted in");
|
|
78
|
-
|
|
69
|
+
setOptIn();
|
|
79
70
|
} else {
|
|
80
71
|
console.log("[Tracking] User cleared opt-in");
|
|
81
|
-
|
|
72
|
+
clearPrefs();
|
|
82
73
|
}
|
|
83
74
|
}
|
|
75
|
+
|
|
76
|
+
onMount(() => {
|
|
77
|
+
console.log(
|
|
78
|
+
"[PrivacyDashboard] Tracking status:",
|
|
79
|
+
$trackingPreferences.status,
|
|
80
|
+
);
|
|
81
|
+
});
|
|
84
82
|
</script>
|
|
85
83
|
|
|
86
84
|
<section id="top">
|
|
@@ -143,36 +141,46 @@ This file is part of Network Pro.
|
|
|
143
141
|
|
|
144
142
|
|
|
145
143
|
|
|
146
|
-
|
|
147
|
-
<
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
144
|
+
{#if trackingStatus && trackingStatus !== "⏳ Checking tracking preferences..."}
|
|
145
|
+
<p id="tracking-status" aria-live="polite">
|
|
146
|
+
<strong>Tracking Status:</strong>
|
|
147
|
+
{trackingStatus}
|
|
148
|
+
</p>
|
|
149
|
+
{:else}
|
|
150
|
+
<p id="tracking-status" aria-live="polite">
|
|
151
|
+
<strong>Tracking Status:</strong> <em>Loading…</em>
|
|
152
|
+
</p>
|
|
153
|
+
{/if}
|
|
154
|
+
|
|
155
|
+
<fieldset>
|
|
156
|
+
<legend class="sr-only">Tracking Preference Controls</legend>
|
|
157
|
+
|
|
158
|
+
<!-- Opt-out checkbox -->
|
|
159
|
+
<label>
|
|
160
|
+
<input
|
|
161
|
+
type="checkbox"
|
|
162
|
+
checked={optedOut}
|
|
163
|
+
disabled={optedIn}
|
|
164
|
+
aria-describedby="tracking-status"
|
|
165
|
+
on:change={(e) =>
|
|
166
|
+
toggleTracking(/** @type {HTMLInputElement} */ (e.target).checked)} />
|
|
167
|
+
<strong> Disable analytics tracking (opt-out)</strong>
|
|
168
|
+
</label>
|
|
169
|
+
|
|
170
|
+
<br />
|
|
171
|
+
|
|
172
|
+
<!-- Opt-in checkbox -->
|
|
173
|
+
<label>
|
|
174
|
+
<input
|
|
175
|
+
type="checkbox"
|
|
176
|
+
checked={optedIn}
|
|
177
|
+
disabled={optedOut}
|
|
178
|
+
aria-describedby="tracking-status"
|
|
179
|
+
on:change={(e) =>
|
|
180
|
+
toggleOptIn(/** @type {HTMLInputElement} */ (e.target).checked)} />
|
|
181
|
+
<strong> Enable analytics tracking (opt-in)</strong>
|
|
182
|
+
</label>
|
|
183
|
+
</fieldset>
|
|
176
184
|
|
|
177
185
|
<div class={spaceStyle}></div>
|
|
178
186
|
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
src/lib/stores/posthog.js
|
|
3
|
+
|
|
4
|
+
Copyright © 2025 Network Pro Strategies (Network Pro™)
|
|
5
|
+
SPDX-License-Identifier: CC-BY-4.0 OR GPL-3.0-or-later
|
|
6
|
+
========================================================================== */
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @file posthog.js
|
|
10
|
+
* @description Privacy-aware PostHog tracking store with reactive state and safe API surface.
|
|
11
|
+
* @module src/lib/stores
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
remindUserToReconsent,
|
|
16
|
+
trackingPreferences,
|
|
17
|
+
} from "$lib/stores/trackingPreferences.js";
|
|
18
|
+
import { get, writable } from "svelte/store";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Tracks whether tracking is allowed based on cookies, DNT/GPC, and user preference.
|
|
22
|
+
* @type {import("svelte/store").Writable<boolean>}
|
|
23
|
+
*/
|
|
24
|
+
export const trackingEnabled = writable(false);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Determines if the user should be reminded to re-consent (after 6 months).
|
|
28
|
+
* @type {import("svelte/store").Writable<boolean>}
|
|
29
|
+
*/
|
|
30
|
+
export const showReminder = writable(false);
|
|
31
|
+
|
|
32
|
+
/** @type {boolean} Internal one-time init guard */
|
|
33
|
+
let initialized = false;
|
|
34
|
+
|
|
35
|
+
/** @type {import("posthog-js").PostHog | null} Loaded PostHog instance */
|
|
36
|
+
let ph = null;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Initializes the PostHog analytics client if tracking is permitted.
|
|
40
|
+
* Uses dynamic import to avoid SSR failures.
|
|
41
|
+
* @returns {Promise<void>}
|
|
42
|
+
*/
|
|
43
|
+
export async function initPostHog() {
|
|
44
|
+
if (initialized || typeof window === "undefined") return;
|
|
45
|
+
initialized = true;
|
|
46
|
+
|
|
47
|
+
const { enabled } = get(trackingPreferences);
|
|
48
|
+
trackingEnabled.set(enabled);
|
|
49
|
+
showReminder.set(get(remindUserToReconsent)); // ✅ use derived store instead
|
|
50
|
+
|
|
51
|
+
if (!enabled) {
|
|
52
|
+
console.log("[PostHog] Tracking is disabled — skipping init.");
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const posthogModule = await import("posthog-js");
|
|
57
|
+
ph = posthogModule.default;
|
|
58
|
+
|
|
59
|
+
// cspell:disable-next-line
|
|
60
|
+
ph.init("phc_Qshfo6AXzh4pS7aPigfqyeo4qj1qlyh7gDuHDeVMSR0", {
|
|
61
|
+
api_host: "https://us.i.posthog.com",
|
|
62
|
+
autocapture: true,
|
|
63
|
+
capture_pageview: false,
|
|
64
|
+
person_profiles: "identified_only",
|
|
65
|
+
loaded: (phInstance) => {
|
|
66
|
+
if (!enabled) {
|
|
67
|
+
console.log(
|
|
68
|
+
"[PostHog] ⛔ User opted out — calling opt_out_capturing()",
|
|
69
|
+
);
|
|
70
|
+
phInstance.opt_out_capturing();
|
|
71
|
+
} else {
|
|
72
|
+
console.log("[PostHog] ✅ Tracking enabled");
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
ph.capture("$pageview");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Conditionally captures an event if tracking is enabled.
|
|
82
|
+
* @param {string} event - The event name to track
|
|
83
|
+
* @param {Record<string, any>} [properties={}] - Optional event properties
|
|
84
|
+
*/
|
|
85
|
+
export function capture(event, properties = {}) {
|
|
86
|
+
if (ph !== null && get(trackingEnabled)) {
|
|
87
|
+
ph.capture(event, properties);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Conditionally identifies a user if tracking is enabled.
|
|
93
|
+
* @param {string} id - Unique user identifier
|
|
94
|
+
* @param {Record<string, any>} [properties={}] - Optional user traits
|
|
95
|
+
*/
|
|
96
|
+
export function identify(id, properties = {}) {
|
|
97
|
+
if (ph !== null && get(trackingEnabled)) {
|
|
98
|
+
ph.identify(id, properties);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* For test cleanup only — resets internal state.
|
|
104
|
+
* No-op in production.
|
|
105
|
+
* @returns {void}
|
|
106
|
+
*/
|
|
107
|
+
export function _resetPostHog() {
|
|
108
|
+
if (import.meta.env.MODE === "production") {
|
|
109
|
+
console.warn("[PostHog] _resetPostHog() called in production — no-op");
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
initialized = false;
|
|
114
|
+
ph = null;
|
|
115
|
+
}
|