@consentify/core 2.0.0 → 2.1.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.js +11 -1
- package/dist/index.test.js +65 -1
- package/package.json +8 -3
package/dist/index.js
CHANGED
|
@@ -240,6 +240,11 @@ export function createConsentify(init) {
|
|
|
240
240
|
if (isBrowser()) {
|
|
241
241
|
syncState();
|
|
242
242
|
}
|
|
243
|
+
let bc = null;
|
|
244
|
+
if (isBrowser() && typeof BroadcastChannel !== 'undefined') {
|
|
245
|
+
bc = new BroadcastChannel(`consentify:${cookieName}`);
|
|
246
|
+
bc.onmessage = () => { syncState(); notifyListeners(); };
|
|
247
|
+
}
|
|
243
248
|
function clientGet(category) {
|
|
244
249
|
if (typeof category === 'undefined')
|
|
245
250
|
return cachedState;
|
|
@@ -263,13 +268,18 @@ export function createConsentify(init) {
|
|
|
263
268
|
if (changed) {
|
|
264
269
|
syncState();
|
|
265
270
|
notifyListeners();
|
|
271
|
+
bc?.postMessage(null);
|
|
266
272
|
}
|
|
267
273
|
},
|
|
268
274
|
clear: () => {
|
|
275
|
+
const hadConsent = cachedState.decision === 'decided';
|
|
269
276
|
for (const k of new Set([...storageOrder, 'cookie']))
|
|
270
277
|
clearStore(k);
|
|
271
278
|
syncState();
|
|
272
|
-
|
|
279
|
+
if (hadConsent) {
|
|
280
|
+
notifyListeners();
|
|
281
|
+
bc?.postMessage(null);
|
|
282
|
+
}
|
|
273
283
|
},
|
|
274
284
|
subscribe: (callback) => {
|
|
275
285
|
listeners.add(callback);
|
package/dist/index.test.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
2
|
import { createConsentify, enableConsentMode } from './index';
|
|
3
3
|
function stableStringify(o) {
|
|
4
4
|
if (o === null || typeof o !== 'object')
|
|
@@ -30,6 +30,27 @@ function clearAllCookies() {
|
|
|
30
30
|
document.cookie = `${name}=; Max-Age=0; Path=/`;
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
|
+
class MockBroadcastChannel {
|
|
34
|
+
name;
|
|
35
|
+
static channels = new Map();
|
|
36
|
+
onmessage = null;
|
|
37
|
+
constructor(name) {
|
|
38
|
+
this.name = name;
|
|
39
|
+
if (!MockBroadcastChannel.channels.has(name)) {
|
|
40
|
+
MockBroadcastChannel.channels.set(name, new Set());
|
|
41
|
+
}
|
|
42
|
+
MockBroadcastChannel.channels.get(name).add(this);
|
|
43
|
+
}
|
|
44
|
+
postMessage(data) {
|
|
45
|
+
for (const ch of MockBroadcastChannel.channels.get(this.name) ?? []) {
|
|
46
|
+
if (ch !== this)
|
|
47
|
+
ch.onmessage?.(new MessageEvent('message', { data }));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
close() {
|
|
51
|
+
MockBroadcastChannel.channels.get(this.name)?.delete(this);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
33
54
|
describe('stableStringify', () => {
|
|
34
55
|
it('produces deterministic output regardless of key order', () => {
|
|
35
56
|
expect(stableStringify({ b: 2, a: 1 })).toBe(stableStringify({ a: 1, b: 2 }));
|
|
@@ -786,3 +807,46 @@ describe('server API — merge & cookie config', () => {
|
|
|
786
807
|
expect(result1).toBe(result2);
|
|
787
808
|
});
|
|
788
809
|
});
|
|
810
|
+
describe('multi-tab sync (BroadcastChannel)', () => {
|
|
811
|
+
beforeEach(() => {
|
|
812
|
+
clearAllCookies();
|
|
813
|
+
MockBroadcastChannel.channels.clear();
|
|
814
|
+
vi.stubGlobal('BroadcastChannel', MockBroadcastChannel);
|
|
815
|
+
});
|
|
816
|
+
afterEach(() => {
|
|
817
|
+
vi.unstubAllGlobals();
|
|
818
|
+
MockBroadcastChannel.channels.clear();
|
|
819
|
+
});
|
|
820
|
+
it('set() in one instance notifies listeners in another', () => {
|
|
821
|
+
const c1 = createConsentify({ policy: { categories: ['analytics'] } });
|
|
822
|
+
const c2 = createConsentify({ policy: { categories: ['analytics'] } });
|
|
823
|
+
const listener = vi.fn();
|
|
824
|
+
c2.client.subscribe(listener);
|
|
825
|
+
c1.client.set({ analytics: true });
|
|
826
|
+
expect(listener).toHaveBeenCalled();
|
|
827
|
+
});
|
|
828
|
+
it('receiving instance has updated state after set()', () => {
|
|
829
|
+
const c1 = createConsentify({ policy: { categories: ['analytics'] } });
|
|
830
|
+
const c2 = createConsentify({ policy: { categories: ['analytics'] } });
|
|
831
|
+
c1.client.set({ analytics: true });
|
|
832
|
+
expect(c2.client.get('analytics')).toBe(true);
|
|
833
|
+
});
|
|
834
|
+
it('clear() in one instance notifies listeners in another', () => {
|
|
835
|
+
const c1 = createConsentify({ policy: { categories: ['analytics'] } });
|
|
836
|
+
const c2 = createConsentify({ policy: { categories: ['analytics'] } });
|
|
837
|
+
c1.client.set({ analytics: true });
|
|
838
|
+
const listener = vi.fn();
|
|
839
|
+
c2.client.subscribe(listener);
|
|
840
|
+
c1.client.clear();
|
|
841
|
+
expect(listener).toHaveBeenCalled();
|
|
842
|
+
expect(c2.client.get()).toEqual({ decision: 'unset' });
|
|
843
|
+
});
|
|
844
|
+
it('initiating instance does not double-fire its own listeners', () => {
|
|
845
|
+
const c1 = createConsentify({ policy: { categories: ['analytics'] } });
|
|
846
|
+
createConsentify({ policy: { categories: ['analytics'] } });
|
|
847
|
+
const listener = vi.fn();
|
|
848
|
+
c1.client.subscribe(listener);
|
|
849
|
+
c1.client.set({ analytics: true });
|
|
850
|
+
expect(listener).toHaveBeenCalledTimes(1);
|
|
851
|
+
});
|
|
852
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@consentify/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Minimal headless cookie consent SDK (TypeScript, SSR-ready, lazy-init).",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Roman Denysov",
|
|
@@ -27,11 +27,16 @@
|
|
|
27
27
|
"keywords": [
|
|
28
28
|
"cookie",
|
|
29
29
|
"consent",
|
|
30
|
+
"cookie-consent",
|
|
31
|
+
"cookie-banner",
|
|
32
|
+
"consent-management",
|
|
30
33
|
"gdpr",
|
|
31
34
|
"ccpa",
|
|
35
|
+
"eprivacy",
|
|
32
36
|
"privacy",
|
|
33
|
-
"
|
|
34
|
-
"ssr"
|
|
37
|
+
"headless",
|
|
38
|
+
"ssr",
|
|
39
|
+
"typescript"
|
|
35
40
|
],
|
|
36
41
|
"sideEffects": false,
|
|
37
42
|
"repository": {
|