@peax/consent-core 0.6.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/LICENSE +201 -0
- package/README.md +207 -0
- package/dist/ConsentEnforcementError-Bn_ayWJI.js +16 -0
- package/dist/assertStorageIdentifier-BQuj-9bp.js +7 -0
- package/dist/createConsentIframe-Bw-cl--m.js +93 -0
- package/dist/createConsentRequestScope-D7U8uK6m.js +58 -0
- package/dist/createConsentScript-C_4ecSTX.js +102 -0
- package/dist/createDomGuard-CuIEC0HP.js +101 -0
- package/dist/enforcement/axios.d.ts +222 -0
- package/dist/enforcement/axios.js +92 -0
- package/dist/enforcement/fetch.d.ts +222 -0
- package/dist/enforcement/fetch.js +40 -0
- package/dist/enforcement/iframe.d.ts +245 -0
- package/dist/enforcement/iframe.js +2 -0
- package/dist/enforcement/integration.d.ts +230 -0
- package/dist/enforcement/integration.js +181 -0
- package/dist/enforcement/markup.d.ts +214 -0
- package/dist/enforcement/markup.js +300 -0
- package/dist/enforcement/posthog.d.ts +68 -0
- package/dist/enforcement/posthog.js +96 -0
- package/dist/enforcement/request-rules.d.ts +248 -0
- package/dist/enforcement/request-rules.js +434 -0
- package/dist/enforcement/script.d.ts +240 -0
- package/dist/enforcement/script.js +2 -0
- package/dist/index.d.ts +258 -0
- package/dist/index.js +445 -0
- package/dist/storage/localforage.d.ts +23 -0
- package/dist/storage/localforage.js +26 -0
- package/dist/storage/sync.d.ts +278 -0
- package/dist/storage/sync.js +370 -0
- package/dist/storage.d.ts +77 -0
- package/dist/storage.js +207 -0
- package/dist/validate-D16G7mdG.js +15 -0
- package/package.json +128 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { t as ConsentEnforcementError } from "./ConsentEnforcementError-Bn_ayWJI.js";
|
|
2
|
+
import { a as setReferrerPolicy, n as insertGuarded, o as setStringAttribute, r as requireParent, s as sourceUrl, t as createDomGuard } from "./createDomGuard-CuIEC0HP.js";
|
|
3
|
+
//#region src/enforcement/script/ConsentScriptError.ts
|
|
4
|
+
var ConsentScriptError = class extends ConsentEnforcementError {
|
|
5
|
+
name = "ConsentScriptError";
|
|
6
|
+
constructor(useId, reason) {
|
|
7
|
+
super(`Consent script stopped (${reason}).`, useId, reason);
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/enforcement/script/createScriptElement.ts
|
|
12
|
+
function createScriptElement(options) {
|
|
13
|
+
const { src, parent = globalThis.document?.head, type = "classic", async = true, nonce, integrity, crossOrigin, referrerPolicy } = options;
|
|
14
|
+
if (!parent) throw new TypeError("Expected a script parent or a browser document head.");
|
|
15
|
+
requireParent(parent);
|
|
16
|
+
const url = sourceUrl(src, parent);
|
|
17
|
+
if (type !== "classic" && type !== "module") throw new TypeError("Expected a classic or module script.");
|
|
18
|
+
if (typeof async !== "boolean") throw new TypeError("Expected a boolean async option.");
|
|
19
|
+
if (crossOrigin !== void 0 && crossOrigin !== "anonymous" && crossOrigin !== "use-credentials") throw new TypeError("Expected a valid crossOrigin option.");
|
|
20
|
+
const element = parent.ownerDocument.createElement("script");
|
|
21
|
+
element.type = type === "module" ? "module" : "text/javascript";
|
|
22
|
+
element.async = async;
|
|
23
|
+
setStringAttribute(element, "nonce", nonce);
|
|
24
|
+
setStringAttribute(element, "integrity", integrity);
|
|
25
|
+
setStringAttribute(element, "crossorigin", crossOrigin);
|
|
26
|
+
setReferrerPolicy(element, referrerPolicy);
|
|
27
|
+
return {
|
|
28
|
+
element,
|
|
29
|
+
parent,
|
|
30
|
+
url
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/enforcement/script/createConsentScript.ts
|
|
35
|
+
/** External-script insertion guard, not a sandbox or an SDK shutdown mechanism. */
|
|
36
|
+
function createConsentScript({ consent, useId }) {
|
|
37
|
+
const owner = createDomGuard(consent, useId, (reason) => new ConsentScriptError(useId, reason));
|
|
38
|
+
return Object.freeze({
|
|
39
|
+
load(options) {
|
|
40
|
+
const check = owner.begin();
|
|
41
|
+
const { element, parent, url } = createScriptElement(options);
|
|
42
|
+
check();
|
|
43
|
+
let removed = false;
|
|
44
|
+
let settled = false;
|
|
45
|
+
let resolveReady;
|
|
46
|
+
let rejectReady;
|
|
47
|
+
const ready = new Promise((resolve, reject) => {
|
|
48
|
+
resolveReady = resolve;
|
|
49
|
+
rejectReady = reject;
|
|
50
|
+
});
|
|
51
|
+
function detachListeners() {
|
|
52
|
+
element.removeEventListener("load", loaded);
|
|
53
|
+
element.removeEventListener("error", failed);
|
|
54
|
+
}
|
|
55
|
+
function stop(error) {
|
|
56
|
+
if (removed) return;
|
|
57
|
+
removed = true;
|
|
58
|
+
forget();
|
|
59
|
+
detachListeners();
|
|
60
|
+
element.remove();
|
|
61
|
+
if (!settled) {
|
|
62
|
+
settled = true;
|
|
63
|
+
rejectReady(error);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function loaded() {
|
|
67
|
+
try {
|
|
68
|
+
check();
|
|
69
|
+
} catch (error) {
|
|
70
|
+
stop(error);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (settled) return;
|
|
74
|
+
settled = true;
|
|
75
|
+
detachListeners();
|
|
76
|
+
resolveReady();
|
|
77
|
+
}
|
|
78
|
+
function failed() {
|
|
79
|
+
stop(new ConsentScriptError(useId, "load-error"));
|
|
80
|
+
}
|
|
81
|
+
const forget = owner.track(stop);
|
|
82
|
+
element.addEventListener("load", loaded);
|
|
83
|
+
element.addEventListener("error", failed);
|
|
84
|
+
try {
|
|
85
|
+
check();
|
|
86
|
+
insertGuarded(element, parent, url, check);
|
|
87
|
+
} catch (error) {
|
|
88
|
+
stop(error);
|
|
89
|
+
ready.catch(() => {});
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
return Object.freeze({
|
|
93
|
+
element,
|
|
94
|
+
ready,
|
|
95
|
+
remove: () => stop(new ConsentScriptError(useId, "removed"))
|
|
96
|
+
});
|
|
97
|
+
},
|
|
98
|
+
dispose: owner.dispose
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
//#endregion
|
|
102
|
+
export { ConsentScriptError as n, createConsentScript as t };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { n as requireUseId, t as requireConsent } from "./validate-D16G7mdG.js";
|
|
2
|
+
//#region src/enforcement/dom/elementOptions.ts
|
|
3
|
+
function requireText(value, name) {
|
|
4
|
+
if (typeof value !== "string" || !value.trim()) throw new TypeError(`Expected a non blank ${name}.`);
|
|
5
|
+
}
|
|
6
|
+
function requireParent(parent) {
|
|
7
|
+
if (parent?.nodeType !== 1 || parent.namespaceURI !== "http://www.w3.org/1999/xhtml" || !parent.isConnected || !parent.ownerDocument?.defaultView || typeof parent.appendChild !== "function") throw new TypeError("Expected a connected HTML parent in a browser document.");
|
|
8
|
+
}
|
|
9
|
+
function sourceUrl(src, parent) {
|
|
10
|
+
requireText(src, "source URL");
|
|
11
|
+
const url = new URL(src, parent.ownerDocument.baseURI);
|
|
12
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") throw new TypeError("Expected an HTTP(S) source URL.");
|
|
13
|
+
return url.href;
|
|
14
|
+
}
|
|
15
|
+
function setStringAttribute(element, name, value) {
|
|
16
|
+
if (value === void 0) return;
|
|
17
|
+
if (typeof value !== "string") throw new TypeError(`Expected a string ${name}.`);
|
|
18
|
+
element.setAttribute(name, value);
|
|
19
|
+
}
|
|
20
|
+
function setReferrerPolicy(element, value) {
|
|
21
|
+
if (value !== void 0 && ![
|
|
22
|
+
"",
|
|
23
|
+
"no-referrer",
|
|
24
|
+
"no-referrer-when-downgrade",
|
|
25
|
+
"origin",
|
|
26
|
+
"origin-when-cross-origin",
|
|
27
|
+
"same-origin",
|
|
28
|
+
"strict-origin",
|
|
29
|
+
"strict-origin-when-cross-origin",
|
|
30
|
+
"unsafe-url"
|
|
31
|
+
].includes(value)) throw new TypeError("Expected a valid referrer policy.");
|
|
32
|
+
setStringAttribute(element, "referrerpolicy", value);
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/enforcement/dom/createDomGuard.ts
|
|
36
|
+
/** Private ownership plumbing shared only by the two DOM loaders. */
|
|
37
|
+
function createDomGuard(consent, useId, makeError) {
|
|
38
|
+
requireUseId(useId);
|
|
39
|
+
requireConsent(consent);
|
|
40
|
+
let disposed = false;
|
|
41
|
+
let scope = {};
|
|
42
|
+
const owned = /* @__PURE__ */ new Set();
|
|
43
|
+
function invalidate(error) {
|
|
44
|
+
scope.error = error;
|
|
45
|
+
scope = {};
|
|
46
|
+
const previous = [...owned];
|
|
47
|
+
owned.clear();
|
|
48
|
+
for (const remove of previous) remove(error);
|
|
49
|
+
}
|
|
50
|
+
function assertAllowed() {
|
|
51
|
+
if (disposed) throw makeError("disposed");
|
|
52
|
+
const result = consent.evaluate(useId);
|
|
53
|
+
if (!result.allowed) {
|
|
54
|
+
const error = makeError(result.reason);
|
|
55
|
+
invalidate(error);
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const unsubscribe = consent.subscribe(() => {
|
|
60
|
+
if (disposed) return;
|
|
61
|
+
const result = consent.evaluate(useId);
|
|
62
|
+
if (!result.allowed) invalidate(makeError(result.reason));
|
|
63
|
+
});
|
|
64
|
+
return {
|
|
65
|
+
begin() {
|
|
66
|
+
assertAllowed();
|
|
67
|
+
const active = scope;
|
|
68
|
+
return () => {
|
|
69
|
+
assertAllowed();
|
|
70
|
+
if (active.error) throw active.error;
|
|
71
|
+
};
|
|
72
|
+
},
|
|
73
|
+
track(remove) {
|
|
74
|
+
owned.add(remove);
|
|
75
|
+
return () => {
|
|
76
|
+
owned.delete(remove);
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
dispose() {
|
|
80
|
+
if (disposed) return;
|
|
81
|
+
disposed = true;
|
|
82
|
+
unsubscribe();
|
|
83
|
+
invalidate(makeError("disposed"));
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Starts navigation and inserts the element, re-checking consent at both boundaries that can run
|
|
89
|
+
* app-supplied code (a Trusted Types `createScriptURL` callback during `src`, mutation observers
|
|
90
|
+
* during `appendChild`) and re-validating the parent in between. Callers apply attributes while the
|
|
91
|
+
* element is still disconnected.
|
|
92
|
+
*/
|
|
93
|
+
function insertGuarded(element, parent, url, check) {
|
|
94
|
+
element.src = url;
|
|
95
|
+
requireParent(parent);
|
|
96
|
+
check();
|
|
97
|
+
parent.appendChild(element);
|
|
98
|
+
check();
|
|
99
|
+
}
|
|
100
|
+
//#endregion
|
|
101
|
+
export { setReferrerPolicy as a, requireText as i, insertGuarded as n, setStringAttribute as o, requireParent as r, sourceUrl as s, createDomGuard as t };
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { AxiosInstance } from 'axios';
|
|
2
|
+
import * as z from 'zod/mini';
|
|
3
|
+
|
|
4
|
+
/** Disjoint category/use decisions for one scope actually presented to the user. */
|
|
5
|
+
declare type BatchCommand = z.infer<typeof consentDecisionsCommandSchema>;
|
|
6
|
+
|
|
7
|
+
/** Records choices only for category members in userConsentedPolicy, not future members. */
|
|
8
|
+
declare type CategoryConsentCommand = z.infer<typeof categoryConsentCommandSchema>;
|
|
9
|
+
|
|
10
|
+
declare const categoryConsentCommandSchema: z.ZodMiniReadonly<z.ZodMiniObject<{
|
|
11
|
+
userConsentedPolicy: z.ZodMiniReadonly<z.ZodMiniObject<{
|
|
12
|
+
purposes: z.ZodMiniReadonly<z.ZodMiniArray<z.ZodMiniReadonly<z.ZodMiniObject<{
|
|
13
|
+
id: z.ZodMiniString<string>;
|
|
14
|
+
title: z.ZodMiniString<string>;
|
|
15
|
+
description: z.ZodMiniString<string>;
|
|
16
|
+
}, z.core.$strict>>>>;
|
|
17
|
+
uses: z.ZodMiniReadonly<z.ZodMiniArray<z.ZodMiniReadonly<z.ZodMiniObject<{
|
|
18
|
+
id: z.ZodMiniString<string>;
|
|
19
|
+
serviceId: z.ZodMiniString<string>;
|
|
20
|
+
categoryId: z.ZodMiniString<string>;
|
|
21
|
+
purposeId: z.ZodMiniString<string>;
|
|
22
|
+
consentVersion: z.ZodMiniInt;
|
|
23
|
+
}, z.core.$strict>>>>;
|
|
24
|
+
}, z.core.$strict>>;
|
|
25
|
+
categoryId: z.ZodMiniString<string>;
|
|
26
|
+
decision: z.ZodMiniEnum<{
|
|
27
|
+
granted: "granted";
|
|
28
|
+
denied: "denied";
|
|
29
|
+
}>;
|
|
30
|
+
}, z.core.$strict>>;
|
|
31
|
+
|
|
32
|
+
/** Explicit request methods, not a replacement AxiosInstance or a global interceptor. */
|
|
33
|
+
export declare type ConsentAxios = Readonly<Pick<AxiosInstance, 'request' | 'get' | 'delete' | 'head' | 'options' | 'post' | 'put' | 'patch'> & {
|
|
34
|
+
/** Unsubscribes, cancels outstanding requests/bodies, and permanently closes this guard. */
|
|
35
|
+
dispose: () => void;
|
|
36
|
+
}>;
|
|
37
|
+
|
|
38
|
+
/** Pre-dispatch rejection. In-flight Axios cancellation normally uses ERR_CANCELED instead. */
|
|
39
|
+
export declare class ConsentAxiosError extends ConsentEnforcementError<ConsentAxiosErrorReason> {
|
|
40
|
+
readonly name = "ConsentAxiosError";
|
|
41
|
+
constructor(useId: string, reason: ConsentAxiosErrorReason);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export declare type ConsentAxiosErrorReason = ConsentDeniedReason | 'disposed';
|
|
45
|
+
|
|
46
|
+
export declare type ConsentAxiosOptions = Readonly<{
|
|
47
|
+
consent: Pick<ConsentRuntime, 'evaluate' | 'subscribe'>;
|
|
48
|
+
useId: string;
|
|
49
|
+
/** Existing client; its defaults and interceptors are not mutated. */
|
|
50
|
+
client: AxiosInstance;
|
|
51
|
+
}>;
|
|
52
|
+
|
|
53
|
+
/** userConsentedPolicy is the scope shown for this decision, including a denial. */
|
|
54
|
+
declare type ConsentDecisionCommand = z.infer<typeof consentDecisionCommandSchema>;
|
|
55
|
+
|
|
56
|
+
declare const consentDecisionCommandSchema: z.ZodMiniReadonly<z.ZodMiniObject<{
|
|
57
|
+
userConsentedPolicy: z.ZodMiniReadonly<z.ZodMiniObject<{
|
|
58
|
+
purposes: z.ZodMiniReadonly<z.ZodMiniArray<z.ZodMiniReadonly<z.ZodMiniObject<{
|
|
59
|
+
id: z.ZodMiniString<string>;
|
|
60
|
+
title: z.ZodMiniString<string>;
|
|
61
|
+
description: z.ZodMiniString<string>;
|
|
62
|
+
}, z.core.$strict>>>>;
|
|
63
|
+
uses: z.ZodMiniReadonly<z.ZodMiniArray<z.ZodMiniReadonly<z.ZodMiniObject<{
|
|
64
|
+
id: z.ZodMiniString<string>;
|
|
65
|
+
serviceId: z.ZodMiniString<string>;
|
|
66
|
+
categoryId: z.ZodMiniString<string>;
|
|
67
|
+
purposeId: z.ZodMiniString<string>;
|
|
68
|
+
consentVersion: z.ZodMiniInt;
|
|
69
|
+
}, z.core.$strict>>>>;
|
|
70
|
+
}, z.core.$strict>>;
|
|
71
|
+
useId: z.ZodMiniString<string>;
|
|
72
|
+
decision: z.ZodMiniEnum<{
|
|
73
|
+
granted: "granted";
|
|
74
|
+
denied: "denied";
|
|
75
|
+
}>;
|
|
76
|
+
}, z.core.$strict>>;
|
|
77
|
+
|
|
78
|
+
declare type ConsentDecisionsCommand = Readonly<Omit<BatchCommand, 'decisions'> & {
|
|
79
|
+
decisions: readonly ExclusiveTarget<BatchCommand['decisions'][number]>[];
|
|
80
|
+
}>;
|
|
81
|
+
|
|
82
|
+
declare const consentDecisionsCommandSchema: z.ZodMiniReadonly<z.ZodMiniObject<{
|
|
83
|
+
userConsentedPolicy: z.ZodMiniReadonly<z.ZodMiniObject<{
|
|
84
|
+
purposes: z.ZodMiniReadonly<z.ZodMiniArray<z.ZodMiniReadonly<z.ZodMiniObject<{
|
|
85
|
+
id: z.ZodMiniString<string>;
|
|
86
|
+
title: z.ZodMiniString<string>;
|
|
87
|
+
description: z.ZodMiniString<string>;
|
|
88
|
+
}, z.core.$strict>>>>;
|
|
89
|
+
uses: z.ZodMiniReadonly<z.ZodMiniArray<z.ZodMiniReadonly<z.ZodMiniObject<{
|
|
90
|
+
id: z.ZodMiniString<string>;
|
|
91
|
+
serviceId: z.ZodMiniString<string>;
|
|
92
|
+
categoryId: z.ZodMiniString<string>;
|
|
93
|
+
purposeId: z.ZodMiniString<string>;
|
|
94
|
+
consentVersion: z.ZodMiniInt;
|
|
95
|
+
}, z.core.$strict>>>>;
|
|
96
|
+
}, z.core.$strict>>;
|
|
97
|
+
decisions: z.ZodMiniReadonly<z.ZodMiniArray<z.ZodMiniUnion<readonly [z.ZodMiniReadonly<z.ZodMiniObject<{
|
|
98
|
+
useId: z.ZodMiniString<string>;
|
|
99
|
+
decision: z.ZodMiniEnum<{
|
|
100
|
+
granted: "granted";
|
|
101
|
+
denied: "denied";
|
|
102
|
+
}>;
|
|
103
|
+
}, z.core.$strict>>, z.ZodMiniReadonly<z.ZodMiniObject<{
|
|
104
|
+
categoryId: z.ZodMiniString<string>;
|
|
105
|
+
decision: z.ZodMiniEnum<{
|
|
106
|
+
granted: "granted";
|
|
107
|
+
denied: "denied";
|
|
108
|
+
}>;
|
|
109
|
+
}, z.core.$strict>>]>>>;
|
|
110
|
+
}, z.core.$strict>>;
|
|
111
|
+
|
|
112
|
+
declare type ConsentDeniedReason = 'unknown-use' | 'undecided' | 'denied' | 'consent-version-mismatch';
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Shared shape for enforcement guard errors. Only the concrete classes are public: each subpath
|
|
116
|
+
* exports exactly one of them, so consumers keep their own `instanceof` and literal `name` type.
|
|
117
|
+
*/
|
|
118
|
+
declare abstract class ConsentEnforcementError<Reason extends string> extends Error {
|
|
119
|
+
readonly useId: string;
|
|
120
|
+
readonly reason: Reason;
|
|
121
|
+
constructor(message: string, useId: string, reason: Reason);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
declare type ConsentEvaluation = Readonly<{
|
|
125
|
+
allowed: true;
|
|
126
|
+
}> | Readonly<{
|
|
127
|
+
allowed: false;
|
|
128
|
+
reason: ConsentDeniedReason;
|
|
129
|
+
}>;
|
|
130
|
+
|
|
131
|
+
declare type ConsentPolicy = z.infer<typeof consentPolicySchema>;
|
|
132
|
+
|
|
133
|
+
declare const consentPolicySchema: z.ZodMiniReadonly<z.ZodMiniObject<{
|
|
134
|
+
purposes: z.ZodMiniReadonly<z.ZodMiniArray<z.ZodMiniReadonly<z.ZodMiniObject<{
|
|
135
|
+
id: z.ZodMiniString<string>;
|
|
136
|
+
title: z.ZodMiniString<string>;
|
|
137
|
+
description: z.ZodMiniString<string>;
|
|
138
|
+
}, z.core.$strict>>>>;
|
|
139
|
+
uses: z.ZodMiniReadonly<z.ZodMiniArray<z.ZodMiniReadonly<z.ZodMiniObject<{
|
|
140
|
+
id: z.ZodMiniString<string>;
|
|
141
|
+
serviceId: z.ZodMiniString<string>;
|
|
142
|
+
categoryId: z.ZodMiniString<string>;
|
|
143
|
+
purposeId: z.ZodMiniString<string>;
|
|
144
|
+
consentVersion: z.ZodMiniInt;
|
|
145
|
+
}, z.core.$strict>>>>;
|
|
146
|
+
}, z.core.$strict>>;
|
|
147
|
+
|
|
148
|
+
/** A current use with no decision or a grant for a different consent version. */
|
|
149
|
+
declare type ConsentRequirement = Readonly<{
|
|
150
|
+
useId: string;
|
|
151
|
+
categoryId: string;
|
|
152
|
+
/** The version required by the current policy for this use. */
|
|
153
|
+
consentVersion: number;
|
|
154
|
+
reason: 'undecided' | 'consent-version-mismatch';
|
|
155
|
+
}>;
|
|
156
|
+
|
|
157
|
+
/** In-memory runtime; methods can be passed as callbacks without binding. */
|
|
158
|
+
declare type ConsentRuntime = Readonly<{
|
|
159
|
+
getSnapshot: () => ConsentSnapshot;
|
|
160
|
+
evaluate: (useId: string) => ConsentEvaluation;
|
|
161
|
+
/** Includes undecided uses and version-mismatched grants, not explicit denials. */
|
|
162
|
+
getMismatchedConsent: () => readonly ConsentRequirement[];
|
|
163
|
+
/**
|
|
164
|
+
* Replace all choices from trusted persistence, preserving unknown uses and recorded versions.
|
|
165
|
+
* Validation checks structure, not evidence of user consent; use decision methods for new choices.
|
|
166
|
+
* Does not replace policy, renew versions or perform I/O. Effective changes notify existing guards.
|
|
167
|
+
*/
|
|
168
|
+
restoreState: (state: unknown) => ValidationResult<ConsentSnapshot>;
|
|
169
|
+
setConsentDecision: (command: ConsentDecisionCommand) => ValidationResult<ConsentSnapshot>;
|
|
170
|
+
setCategoryConsent: (command: CategoryConsentCommand) => ValidationResult<ConsentSnapshot>;
|
|
171
|
+
/** Validates all targets before one commit; observer errors can throw after that commit. */
|
|
172
|
+
setConsentDecisions: (command: ConsentDecisionsCommand) => ValidationResult<ConsentSnapshot>;
|
|
173
|
+
updatePolicy: (currentAppPolicy: unknown) => ValidationResult<ConsentSnapshot>;
|
|
174
|
+
subscribe: (listener: () => void) => () => void;
|
|
175
|
+
}>;
|
|
176
|
+
|
|
177
|
+
/** One active app policy and recorded choices; not a history of policies shown to users. */
|
|
178
|
+
declare type ConsentSnapshot = Readonly<{
|
|
179
|
+
currentAppPolicy: ConsentPolicy;
|
|
180
|
+
state: ConsentState;
|
|
181
|
+
}>;
|
|
182
|
+
|
|
183
|
+
declare type ConsentState = z.infer<typeof consentStateSchema>;
|
|
184
|
+
|
|
185
|
+
declare const consentStateSchema: z.ZodMiniReadonly<z.ZodMiniObject<{
|
|
186
|
+
choices: z.ZodMiniReadonly<z.ZodMiniArray<z.ZodMiniReadonly<z.ZodMiniObject<{
|
|
187
|
+
useId: z.ZodMiniString<string>;
|
|
188
|
+
consentVersion: z.ZodMiniInt;
|
|
189
|
+
decision: z.ZodMiniEnum<{
|
|
190
|
+
granted: "granted";
|
|
191
|
+
denied: "denied";
|
|
192
|
+
}>;
|
|
193
|
+
}, z.core.$strict>>>>;
|
|
194
|
+
}, z.core.$strict>>;
|
|
195
|
+
|
|
196
|
+
/** Guards explicit calls through an existing Axios client; never installs global interceptors. */
|
|
197
|
+
export declare function createConsentAxios({ consent, useId, client }: ConsentAxiosOptions): ConsentAxios;
|
|
198
|
+
|
|
199
|
+
declare type ExclusiveTarget<T> = T extends {
|
|
200
|
+
useId: string;
|
|
201
|
+
} ? T & {
|
|
202
|
+
readonly categoryId?: never;
|
|
203
|
+
} : T & {
|
|
204
|
+
readonly useId?: never;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
/** A validation issue without a copy of the rejected input. */
|
|
208
|
+
declare type ValidationIssue = Readonly<{
|
|
209
|
+
code: string;
|
|
210
|
+
path: readonly (string | number)[];
|
|
211
|
+
message: string;
|
|
212
|
+
}>;
|
|
213
|
+
|
|
214
|
+
declare type ValidationResult<T> = Readonly<{
|
|
215
|
+
success: true;
|
|
216
|
+
data: T;
|
|
217
|
+
}> | Readonly<{
|
|
218
|
+
success: false;
|
|
219
|
+
issues: readonly ValidationIssue[];
|
|
220
|
+
}>;
|
|
221
|
+
|
|
222
|
+
export { }
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { t as ConsentEnforcementError } from "../ConsentEnforcementError-Bn_ayWJI.js";
|
|
2
|
+
import { n as retainSignal, t as createConsentRequestScope } from "../createConsentRequestScope-D7U8uK6m.js";
|
|
3
|
+
import { n as requireUseId, t as requireConsent } from "../validate-D16G7mdG.js";
|
|
4
|
+
//#region src/enforcement/axios/ConsentAxiosError.ts
|
|
5
|
+
/** Pre-dispatch rejection. In-flight Axios cancellation normally uses ERR_CANCELED instead. */
|
|
6
|
+
var ConsentAxiosError = class extends ConsentEnforcementError {
|
|
7
|
+
name = "ConsentAxiosError";
|
|
8
|
+
constructor(useId, reason) {
|
|
9
|
+
super(`Consent Axios request blocked (${reason}).`, useId, reason);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/enforcement/axios/combineAxiosSignal.ts
|
|
14
|
+
/** Axios types also permit partial signal shims; this guard requires native-compatible signals. */
|
|
15
|
+
function combineAxiosSignal(scope, caller) {
|
|
16
|
+
return caller ? AbortSignal.any([scope, caller]) : scope;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/enforcement/axios/createConsentAxios.ts
|
|
20
|
+
/** Guards explicit calls through an existing Axios client; never installs global interceptors. */
|
|
21
|
+
function createConsentAxios({ consent, useId, client }) {
|
|
22
|
+
requireUseId(useId);
|
|
23
|
+
requireConsent(consent);
|
|
24
|
+
if (!client || typeof client.request !== "function" || !client.defaults) throw new TypeError("Expected an Axios client.");
|
|
25
|
+
const scope = createConsentRequestScope(consent, useId, (reason) => new ConsentAxiosError(useId, reason));
|
|
26
|
+
async function dispatch(getConfig) {
|
|
27
|
+
const grantSignal = scope.begin();
|
|
28
|
+
const input = { ...getConfig() };
|
|
29
|
+
const originalAdapter = input.adapter === void 0 ? client.defaults.adapter : input.adapter;
|
|
30
|
+
const signal = combineAxiosSignal(grantSignal, input.signal === void 0 ? client.defaults.signal : input.signal);
|
|
31
|
+
const adapter = async (finalConfig) => {
|
|
32
|
+
const axios = await import("axios");
|
|
33
|
+
const dispatchSignal = combineAxiosSignal(signal, finalConfig.signal);
|
|
34
|
+
finalConfig.signal = dispatchSignal;
|
|
35
|
+
scope.assertAllowed();
|
|
36
|
+
if (finalConfig.signal.aborted) throw new axios.CanceledError(void 0, finalConfig);
|
|
37
|
+
finalConfig.cancelToken?.throwIfRequested();
|
|
38
|
+
const getAdapter = axios.getAdapter;
|
|
39
|
+
const transport = getAdapter(originalAdapter || axios.default.defaults.adapter, finalConfig);
|
|
40
|
+
scope.assertAllowed();
|
|
41
|
+
if (finalConfig.signal.aborted) throw new axios.CanceledError(void 0, finalConfig);
|
|
42
|
+
const response = await transport(finalConfig);
|
|
43
|
+
retainSignal(dispatchSignal, response, typeof response.data === "object" ? response.data : void 0);
|
|
44
|
+
return response;
|
|
45
|
+
};
|
|
46
|
+
scope.assertAllowed();
|
|
47
|
+
return client.request({
|
|
48
|
+
...input,
|
|
49
|
+
signal,
|
|
50
|
+
adapter
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/** `method` and `url` always win over the same keys in the caller's config. */
|
|
54
|
+
function makeRequest(method, url, config) {
|
|
55
|
+
return {
|
|
56
|
+
...config,
|
|
57
|
+
method,
|
|
58
|
+
url
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Axios resolves `data` through `valueFromConfig2`, so a method that takes a positional `data`
|
|
63
|
+
* must replace `config.data` even when that argument is undefined; otherwise a caller's
|
|
64
|
+
* `config.data` would leak through a request whose body the caller never meant to send. Methods
|
|
65
|
+
* without a positional argument pass `config.data` through untouched.
|
|
66
|
+
*/
|
|
67
|
+
function makeRequestWithData(method, url, config, data) {
|
|
68
|
+
const input = makeRequest(method, url, config);
|
|
69
|
+
delete input.data;
|
|
70
|
+
if (data !== void 0) input.data = data;
|
|
71
|
+
return input;
|
|
72
|
+
}
|
|
73
|
+
function withoutBody(method) {
|
|
74
|
+
return (url, config) => dispatch(() => makeRequest(method, url, config));
|
|
75
|
+
}
|
|
76
|
+
function withBody(method) {
|
|
77
|
+
return (url, data, config) => dispatch(() => makeRequestWithData(method, url, config, data));
|
|
78
|
+
}
|
|
79
|
+
return Object.freeze({
|
|
80
|
+
request: (config) => dispatch(() => config),
|
|
81
|
+
get: withoutBody("get"),
|
|
82
|
+
delete: withoutBody("delete"),
|
|
83
|
+
head: withoutBody("head"),
|
|
84
|
+
options: withoutBody("options"),
|
|
85
|
+
post: withBody("post"),
|
|
86
|
+
put: withBody("put"),
|
|
87
|
+
patch: withBody("patch"),
|
|
88
|
+
dispose: scope.dispose
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
export { ConsentAxiosError, createConsentAxios };
|