@peax/consent-core 0.6.0 → 0.9.3

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.
@@ -109,7 +109,7 @@ function createConsentMarkupGuard({ consent, root, onIssue }) {
109
109
  const asyncValue = read(template, "async");
110
110
  if (asyncValue !== void 0 && asyncValue !== "true" && asyncValue !== "false") throw new TypeError("Invalid data-peax-async value.");
111
111
  const { nonce, integrity, crossOrigin, referrerPolicy } = {
112
- nonce: read(template, "nonce"),
112
+ nonce: template.nonce || void 0,
113
113
  integrity: read(template, "integrity"),
114
114
  crossOrigin: read(template, "crossOrigin"),
115
115
  referrerPolicy: read(template, "referrerPolicy")
@@ -253,7 +253,7 @@ function createXhrInterceptor(target, rules, permissions, report) {
253
253
  if (args.length < 2) return Reflect.apply(nativeOpen, this, args);
254
254
  const method = domString(args[0]);
255
255
  const urlInput = domString(args[1]);
256
- const rest = args.slice(2, 5).map((value, index) => index === 0 ? Boolean(value) : value == null ? null : domString(value));
256
+ const rest = args.slice(2, 5).map((value, index) => index === 0 ? value === void 0 || Boolean(value) : value == null ? null : domString(value));
257
257
  let url;
258
258
  try {
259
259
  url = new target.URL(urlInput, target.document.baseURI);
package/dist/index.js CHANGED
@@ -145,19 +145,12 @@ function createConsentSubscription() {
145
145
  }
146
146
  //#endregion
147
147
  //#region src/consent/evaluateConsent.ts
148
- /**
149
- * Evaluates one use without mutating inputs or performing enforcement.
150
- * Inputs must be validated, with unique policy use IDs and at most one choice
151
- * per use. Denials remain blocked regardless of their consent version.
152
- * A version mismatch blocks only this use, not other unchanged uses.
153
- */
154
- function evaluateConsent({ currentAppPolicy, state, useId }) {
155
- const use = currentAppPolicy.uses.find((use) => use.id === useId);
148
+ /** Decides one use from its declaration and recorded choice, which callers look up their own way. */
149
+ function decideConsent(use, choice) {
156
150
  if (!use) return {
157
151
  allowed: false,
158
152
  reason: "unknown-use"
159
153
  };
160
- const choice = state.choices.find((choice) => choice.useId === useId);
161
154
  if (!choice) return {
162
155
  allowed: false,
163
156
  reason: "undecided"
@@ -180,12 +173,9 @@ function evaluateConsent({ currentAppPolicy, state, useId }) {
180
173
  * input contract. An empty result is not blanket permission: denials are omitted.
181
174
  */
182
175
  function getMismatchedConsent({ currentAppPolicy, state }) {
176
+ const choices = new Map(state.choices.map((choice) => [choice.useId, choice]));
183
177
  return currentAppPolicy.uses.flatMap((use) => {
184
- const evaluation = evaluateConsent({
185
- currentAppPolicy,
186
- state,
187
- useId: use.id
188
- });
178
+ const evaluation = decideConsent(use, choices.get(use.id));
189
179
  if (evaluation.allowed) return [];
190
180
  if (evaluation.reason !== "undecided" && evaluation.reason !== "consent-version-mismatch") return [];
191
181
  return [{
@@ -357,26 +347,46 @@ function createSnapshot(currentAppPolicy, state) {
357
347
  state
358
348
  });
359
349
  }
350
+ function indexSnapshot({ currentAppPolicy, state }) {
351
+ const uses = new Map(currentAppPolicy.uses.map((use) => [use.id, use]));
352
+ const choices = new Map(state.choices.map((choice) => [choice.useId, choice]));
353
+ return (useId) => decideConsent(uses.get(useId), choices.get(useId));
354
+ }
360
355
  function snapshotRequirements(snapshot) {
361
356
  return Object.freeze(getMismatchedConsent(snapshot).map((requirement) => Object.freeze(requirement)));
362
357
  }
358
+ var maxReentrantCommits = 100;
363
359
  /** Creates an isolated runtime from decoded data; invalid input creates no instance. */
364
360
  function createConsent(input) {
365
361
  const result = validateWithSchema(createConsentOptionsSchema, input);
366
362
  if (!result.success) return result;
367
363
  let snapshot = createSnapshot(result.data.currentAppPolicy, result.data.initialState);
368
364
  let requirements = snapshotRequirements(snapshot);
365
+ let evaluate = indexSnapshot(snapshot);
369
366
  const subscriptions = createConsentSubscription();
367
+ let delivering = false;
368
+ let reentrantCommits = 0;
370
369
  function commit(currentAppPolicy, state) {
371
370
  if (snapshot.currentAppPolicy === currentAppPolicy && snapshot.state === state) return {
372
371
  success: true,
373
372
  data: snapshot
374
373
  };
374
+ if (delivering && ++reentrantCommits > maxReentrantCommits) throw new RangeError("Consent subscribers kept committing changes on every notification.");
375
375
  const next = createSnapshot(currentAppPolicy, state);
376
376
  const nextRequirements = snapshotRequirements(next);
377
377
  snapshot = next;
378
378
  requirements = nextRequirements;
379
- subscriptions.notify();
379
+ evaluate = indexSnapshot(next);
380
+ if (delivering) subscriptions.notify();
381
+ else {
382
+ delivering = true;
383
+ reentrantCommits = 0;
384
+ try {
385
+ subscriptions.notify();
386
+ } finally {
387
+ delivering = false;
388
+ }
389
+ }
380
390
  return {
381
391
  success: true,
382
392
  data: next
@@ -386,10 +396,7 @@ function createConsent(input) {
386
396
  success: true,
387
397
  data: Object.freeze({
388
398
  getSnapshot: () => snapshot,
389
- evaluate: (useId) => evaluateConsent({
390
- ...snapshot,
391
- useId
392
- }),
399
+ evaluate: (useId) => evaluate(useId),
393
400
  getMismatchedConsent: () => requirements,
394
401
  restoreState(input) {
395
402
  const parsed = validateWithSchema(consentStateSchema, input);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peax/consent-core",
3
- "version": "0.6.0",
3
+ "version": "0.9.3",
4
4
  "description": "Framework-independent consent state and runtime primitives.",
5
5
  "keywords": [
6
6
  "consent-management",