standdown 0.1.0 → 0.2.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 +221 -18
- package/dist/{chunk-25A7QG5Z.mjs → chunk-26BG7FFX.mjs} +3 -3
- package/dist/{chunk-25A7QG5Z.mjs.map → chunk-26BG7FFX.mjs.map} +1 -1
- package/dist/{chunk-SEZFAOUU.mjs → chunk-JKQTHHIP.mjs} +49 -4
- package/dist/chunk-JKQTHHIP.mjs.map +1 -0
- package/dist/{chunk-SVN6UWA4.mjs → chunk-VE7YBR5A.mjs} +142 -24
- package/dist/chunk-VE7YBR5A.mjs.map +1 -0
- package/dist/content.cjs +188 -28
- package/dist/content.cjs.map +1 -1
- package/dist/content.d.cts +11 -4
- package/dist/content.d.ts +11 -4
- package/dist/content.mjs +18 -8
- package/dist/content.mjs.map +1 -1
- package/dist/index.cjs +140 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +3 -7
- package/dist/index.mjs.map +1 -1
- package/dist/policies.cjs +18 -11
- package/dist/policies.cjs.map +1 -1
- package/dist/policies.d.cts +98 -86
- package/dist/policies.d.ts +98 -86
- package/dist/policies.mjs +18 -12
- package/dist/policies.mjs.map +1 -1
- package/dist/{session-C5gH-LaQ.d.ts → session-DA9hkYlD.d.ts} +10 -1
- package/dist/{session-n0px3Agb.d.cts → session-iosT1mEL.d.cts} +10 -1
- package/dist/{stores-CELX9aHN.d.ts → stores-Behkya7C.d.ts} +1 -1
- package/dist/{stores-CKCdKDdX.d.cts → stores-DfovpSqe.d.cts} +1 -1
- package/dist/{types-A9OJ7SWj.d.cts → types-DgKvVCmQ.d.cts} +53 -7
- package/dist/{types-A9OJ7SWj.d.ts → types-DgKvVCmQ.d.ts} +53 -7
- package/dist/webext.cjs +191 -28
- package/dist/webext.cjs.map +1 -1
- package/dist/webext.d.cts +11 -4
- package/dist/webext.d.ts +11 -4
- package/dist/webext.mjs +22 -9
- package/dist/webext.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-SEZFAOUU.mjs.map +0 -1
- package/dist/chunk-SVN6UWA4.mjs.map +0 -1
|
@@ -43,6 +43,9 @@ function validatePolicy(value) {
|
|
|
43
43
|
optionalArray(detection.initiatorRules, "policy.detection.initiatorRules").forEach(
|
|
44
44
|
validateInitiatorRule
|
|
45
45
|
);
|
|
46
|
+
optionalArray(detection.disableHosts, "policy.detection.disableHosts").forEach(
|
|
47
|
+
validateDomainRule
|
|
48
|
+
);
|
|
46
49
|
const standdown = object(policy.standdown, "policy.standdown");
|
|
47
50
|
literal(standdown.scope, "advertiser", "policy.standdown.scope");
|
|
48
51
|
if (standdown.sessionRule !== "session-or-min" && standdown.sessionRule !== "inactivity-window") {
|
|
@@ -68,12 +71,6 @@ function validatePolicy(value) {
|
|
|
68
71
|
if (activation.mode !== "user-click" && activation.mode !== "never") {
|
|
69
72
|
throw new TypeError("policy.activation.mode is invalid");
|
|
70
73
|
}
|
|
71
|
-
if (activation.maxPromptsPerJourney !== void 0) {
|
|
72
|
-
nonNegativeFiniteNumber(
|
|
73
|
-
activation.maxPromptsPerJourney,
|
|
74
|
-
"policy.activation.maxPromptsPerJourney"
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
74
|
for (const referrerClass of optionalArray(
|
|
78
75
|
activation.allowedReferrerClasses,
|
|
79
76
|
"policy.activation.allowedReferrerClasses"
|
|
@@ -233,8 +230,24 @@ function detect(signals, policies) {
|
|
|
233
230
|
}
|
|
234
231
|
const advertiserHost = currentUrl.hostname.toLowerCase();
|
|
235
232
|
const matched = [];
|
|
233
|
+
const selfExemptScopes = [];
|
|
236
234
|
let selfMatch = false;
|
|
237
235
|
for (const policy of policies) {
|
|
236
|
+
const disabledHostRule = (policy.detection.disableHosts ?? []).find(
|
|
237
|
+
(rule) => domainRuleMatchesUrl(rule, advertiserHost)
|
|
238
|
+
);
|
|
239
|
+
if (disabledHostRule) {
|
|
240
|
+
matched.push(
|
|
241
|
+
matchedRule(
|
|
242
|
+
policy,
|
|
243
|
+
"disabled-host",
|
|
244
|
+
`${disabledHostRule.kind}:${disabledHostRule.pattern}`,
|
|
245
|
+
advertiserHost,
|
|
246
|
+
disabledHostRule.comment ?? "host disabled for this network"
|
|
247
|
+
)
|
|
248
|
+
);
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
238
251
|
const scopedSelfMatch = hasScopedSelfExemption(
|
|
239
252
|
currentUrl,
|
|
240
253
|
signals.selfPatterns,
|
|
@@ -248,6 +261,10 @@ function detect(signals, policies) {
|
|
|
248
261
|
selfMatch = true;
|
|
249
262
|
}
|
|
250
263
|
if (scopedSelfMatch) {
|
|
264
|
+
selfExemptScopes.push({
|
|
265
|
+
policyId: policy.id,
|
|
266
|
+
networkId: policy.network.id
|
|
267
|
+
});
|
|
251
268
|
continue;
|
|
252
269
|
}
|
|
253
270
|
matched.push(
|
|
@@ -260,7 +277,14 @@ function detect(signals, policies) {
|
|
|
260
277
|
advertiserHost: matched[0].advertiserHost,
|
|
261
278
|
reason: matched[0].reason
|
|
262
279
|
} : void 0;
|
|
263
|
-
|
|
280
|
+
const base = { matched, selfMatch };
|
|
281
|
+
if (strongest) {
|
|
282
|
+
base.strongest = strongest;
|
|
283
|
+
}
|
|
284
|
+
if (selfExemptScopes.length > 0) {
|
|
285
|
+
base.selfExemptScopes = selfExemptScopes;
|
|
286
|
+
}
|
|
287
|
+
return base;
|
|
264
288
|
}
|
|
265
289
|
function classifyReferrer(signals, advertiserHost) {
|
|
266
290
|
const candidate = signals.initiator ?? signals.referrer;
|
|
@@ -377,16 +401,19 @@ function matchedRule(policy, kind, rule, advertiserHost, reason) {
|
|
|
377
401
|
};
|
|
378
402
|
}
|
|
379
403
|
function kindPriority(kind) {
|
|
380
|
-
if (kind === "
|
|
404
|
+
if (kind === "disabled-host") {
|
|
381
405
|
return 0;
|
|
382
406
|
}
|
|
383
|
-
if (kind === "
|
|
407
|
+
if (kind === "redirect-domain") {
|
|
384
408
|
return 1;
|
|
385
409
|
}
|
|
386
|
-
if (kind === "
|
|
410
|
+
if (kind === "landing-param") {
|
|
387
411
|
return 2;
|
|
388
412
|
}
|
|
389
|
-
|
|
413
|
+
if (kind === "cookie") {
|
|
414
|
+
return 3;
|
|
415
|
+
}
|
|
416
|
+
return 4;
|
|
390
417
|
}
|
|
391
418
|
function paramRuleMatches(rule, params) {
|
|
392
419
|
return rule.anyOf.some(
|
|
@@ -470,11 +497,13 @@ var StanddownSession = class {
|
|
|
470
497
|
#store;
|
|
471
498
|
#auditLog;
|
|
472
499
|
#maxAuditEntries;
|
|
500
|
+
#selfExemptionScope;
|
|
473
501
|
#readOnlyAuditLog = [];
|
|
474
502
|
constructor(store, opts) {
|
|
475
503
|
this.#store = store;
|
|
476
504
|
this.#auditLog = opts?.auditLog ?? true;
|
|
477
505
|
this.#maxAuditEntries = Math.max(0, opts?.maxAuditEntries ?? 1e3);
|
|
506
|
+
this.#selfExemptionScope = opts?.selfExemptionScope ?? "policy";
|
|
478
507
|
}
|
|
479
508
|
async ingest(signals, policies) {
|
|
480
509
|
const advertiserHost = hostFromUrl2(signals.url);
|
|
@@ -500,38 +529,49 @@ var StanddownSession = class {
|
|
|
500
529
|
}
|
|
501
530
|
return this.#withState(signals.now, (state) => {
|
|
502
531
|
pruneExpiredSessions(state, signals.now);
|
|
503
|
-
|
|
504
|
-
|
|
532
|
+
let effective = detection;
|
|
533
|
+
if (this.#selfExemptionScope === "session" && advertiserHost) {
|
|
534
|
+
recordSessionExemptions(state, advertiserHost, detection, signals.now);
|
|
535
|
+
effective = applySessionExemptions(
|
|
536
|
+
advertiserHost,
|
|
537
|
+
detection,
|
|
538
|
+
state.exemptions?.[advertiserHost]
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
if (effective.strongest) {
|
|
542
|
+
const matchedPolicies = policiesForDetection(policies, effective);
|
|
505
543
|
if (matchedPolicies.length === 0) {
|
|
506
544
|
return {
|
|
507
545
|
decision: failClosedDecision("matched-policy-missing"),
|
|
508
|
-
detection
|
|
546
|
+
detection: effective
|
|
509
547
|
};
|
|
510
548
|
}
|
|
511
549
|
const record = upsertSessionRecord(
|
|
512
550
|
state,
|
|
513
|
-
|
|
514
|
-
|
|
551
|
+
effective.strongest.advertiserHost,
|
|
552
|
+
effective.strongest.policyId,
|
|
515
553
|
matchedPolicies,
|
|
516
554
|
signals.now
|
|
517
555
|
);
|
|
518
556
|
return {
|
|
519
557
|
decision: decisionFromRecord(record, signals.now, {
|
|
520
|
-
reason:
|
|
558
|
+
reason: effective.strongest.reason,
|
|
521
559
|
referrerClass: classifyReferrer(signals, record.advertiserHost)
|
|
522
560
|
}),
|
|
523
|
-
detection
|
|
561
|
+
detection: effective
|
|
524
562
|
};
|
|
525
563
|
}
|
|
526
564
|
const activeDecision = advertiserHost ? activeDecisionForHost(state, advertiserHost, signals.now) : void 0;
|
|
565
|
+
const sessionExempted = detection.strongest !== void 0 && effective.strongest === void 0;
|
|
527
566
|
return {
|
|
528
567
|
decision: activeDecision ?? {
|
|
529
568
|
standDown: false,
|
|
530
|
-
reason: detection.selfMatch ? "self-exempted-no-active-standdown" : "no-active-standdown",
|
|
569
|
+
reason: sessionExempted ? "self-exempted-session" : detection.selfMatch ? "self-exempted-no-active-standdown" : "no-active-standdown",
|
|
531
570
|
behaviors: [],
|
|
532
|
-
referrerClass: advertiserHost ? classifyReferrer(signals, advertiserHost) : "other"
|
|
571
|
+
referrerClass: advertiserHost ? classifyReferrer(signals, advertiserHost) : "other",
|
|
572
|
+
...signals.signalCoverage === "partial" ? { degraded: true } : {}
|
|
533
573
|
},
|
|
534
|
-
detection
|
|
574
|
+
detection: effective
|
|
535
575
|
};
|
|
536
576
|
}, "ingest");
|
|
537
577
|
}
|
|
@@ -700,6 +740,66 @@ function upsertSessionRecord(state, advertiserHost, primaryPolicyId, policies, n
|
|
|
700
740
|
state.sessions[key] = baseRecord;
|
|
701
741
|
return baseRecord;
|
|
702
742
|
}
|
|
743
|
+
function recordSessionExemptions(state, advertiserHost, detection, now) {
|
|
744
|
+
const scopes = detection.selfExemptScopes;
|
|
745
|
+
if (!scopes || scopes.length === 0) {
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
if (activeDecisionForHost(state, advertiserHost, now) !== void 0) {
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
const key = normalizeHost(advertiserHost);
|
|
752
|
+
if (state.exemptions === void 0) {
|
|
753
|
+
state.exemptions = {};
|
|
754
|
+
}
|
|
755
|
+
const exemptions = state.exemptions;
|
|
756
|
+
const existing = exemptions[key];
|
|
757
|
+
const policyIds = new Set(existing?.policyIds ?? []);
|
|
758
|
+
const networkIds = new Set(existing?.networkIds ?? []);
|
|
759
|
+
for (const scope of scopes) {
|
|
760
|
+
policyIds.add(scope.policyId);
|
|
761
|
+
networkIds.add(scope.networkId);
|
|
762
|
+
}
|
|
763
|
+
exemptions[key] = {
|
|
764
|
+
advertiserHost: key,
|
|
765
|
+
policyIds: [...policyIds],
|
|
766
|
+
networkIds: [...networkIds],
|
|
767
|
+
grantedAt: existing?.grantedAt ?? now
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
function applySessionExemptions(advertiserHost, detection, record) {
|
|
771
|
+
if (!record) {
|
|
772
|
+
return detection;
|
|
773
|
+
}
|
|
774
|
+
const host = normalizeHost(advertiserHost);
|
|
775
|
+
const policyIds = new Set(record.policyIds);
|
|
776
|
+
const networkIds = new Set(record.networkIds);
|
|
777
|
+
const filtered = detection.matched.filter((match) => {
|
|
778
|
+
if (match.kind === "disabled-host") {
|
|
779
|
+
return true;
|
|
780
|
+
}
|
|
781
|
+
if (normalizeHost(match.advertiserHost) !== host) {
|
|
782
|
+
return true;
|
|
783
|
+
}
|
|
784
|
+
return !(policyIds.has(match.policyId) || networkIds.has(match.networkId));
|
|
785
|
+
});
|
|
786
|
+
if (filtered.length === detection.matched.length) {
|
|
787
|
+
return detection;
|
|
788
|
+
}
|
|
789
|
+
const strongest = filtered[0] ? {
|
|
790
|
+
policyId: filtered[0].policyId,
|
|
791
|
+
advertiserHost: filtered[0].advertiserHost,
|
|
792
|
+
reason: filtered[0].reason
|
|
793
|
+
} : void 0;
|
|
794
|
+
const next = { matched: filtered, selfMatch: detection.selfMatch };
|
|
795
|
+
if (strongest) {
|
|
796
|
+
next.strongest = strongest;
|
|
797
|
+
}
|
|
798
|
+
if (detection.selfExemptScopes) {
|
|
799
|
+
next.selfExemptScopes = detection.selfExemptScopes;
|
|
800
|
+
}
|
|
801
|
+
return next;
|
|
802
|
+
}
|
|
703
803
|
function policiesForDetection(policies, detection) {
|
|
704
804
|
if (detection.strongest === void 0) {
|
|
705
805
|
return [];
|
|
@@ -796,7 +896,7 @@ function auditEntry(value) {
|
|
|
796
896
|
return entry;
|
|
797
897
|
}
|
|
798
898
|
function cloneState(state) {
|
|
799
|
-
|
|
899
|
+
const cloned = {
|
|
800
900
|
sessions: Object.fromEntries(
|
|
801
901
|
Object.entries(state.sessions).map(([host, record]) => [
|
|
802
902
|
host,
|
|
@@ -808,6 +908,19 @@ function cloneState(state) {
|
|
|
808
908
|
),
|
|
809
909
|
auditLog: state.auditLog.map(cloneAuditEntry)
|
|
810
910
|
};
|
|
911
|
+
if (state.exemptions) {
|
|
912
|
+
cloned.exemptions = Object.fromEntries(
|
|
913
|
+
Object.entries(state.exemptions).map(([host, record]) => [
|
|
914
|
+
host,
|
|
915
|
+
{
|
|
916
|
+
...record,
|
|
917
|
+
policyIds: [...record.policyIds],
|
|
918
|
+
networkIds: [...record.networkIds]
|
|
919
|
+
}
|
|
920
|
+
])
|
|
921
|
+
);
|
|
922
|
+
}
|
|
923
|
+
return cloned;
|
|
811
924
|
}
|
|
812
925
|
function cloneAuditEntry(entry) {
|
|
813
926
|
const cloned = {
|
|
@@ -825,6 +938,11 @@ function cloneAuditEntry(entry) {
|
|
|
825
938
|
if (entry.detection.strongest !== void 0) {
|
|
826
939
|
detection.strongest = { ...entry.detection.strongest };
|
|
827
940
|
}
|
|
941
|
+
if (entry.detection.selfExemptScopes !== void 0) {
|
|
942
|
+
detection.selfExemptScopes = entry.detection.selfExemptScopes.map(
|
|
943
|
+
(scope) => ({ ...scope })
|
|
944
|
+
);
|
|
945
|
+
}
|
|
828
946
|
if (entry.detection.failClosedReason !== void 0) {
|
|
829
947
|
detection.failClosedReason = entry.detection.failClosedReason;
|
|
830
948
|
}
|
|
@@ -853,5 +971,5 @@ function messageFromError(error) {
|
|
|
853
971
|
}
|
|
854
972
|
|
|
855
973
|
export { MemoryStateStore, StanddownSession, classifyReferrer, detect, domainRuleMatchesUrl, validatePolicies, validatePolicy };
|
|
856
|
-
//# sourceMappingURL=chunk-
|
|
857
|
-
//# sourceMappingURL=chunk-
|
|
974
|
+
//# sourceMappingURL=chunk-VE7YBR5A.mjs.map
|
|
975
|
+
//# sourceMappingURL=chunk-VE7YBR5A.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/validation.ts","../src/detect.ts","../src/session.ts"],"names":["hostFromUrl"],"mappings":"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","file":"chunk-VE7YBR5A.mjs","sourcesContent":["import type {\n Behavior,\n CookieRule,\n DomainRule,\n InitiatorRule,\n StanddownPolicy,\n} from './types';\n\nconst BEHAVIORS = new Set<Behavior>([\n 'suppress-prompts',\n 'no-cookie-write',\n 'no-redirect',\n 'no-background-tracking',\n]);\n\nconst PARAM_MATCHES = new Set(['exists', 'equals', 'contains']);\nconst COOKIE_MATCHES = new Set(['exact', 'substring']);\nconst DOMAIN_KINDS = new Set(['suffix', 'regex']);\nconst REFERRER_CLASSES = new Set([\n 'own-site',\n 'organic',\n 'direct',\n 'advertiser-internal',\n 'other',\n]);\nconst ACTIVATION_REFERRER_CLASSES = new Set(['own-site', 'organic', 'direct']);\n\nexport function validatePolicy(value: unknown): asserts value is StanddownPolicy {\n const policy = object(value, 'policy');\n\n string(policy.id, 'policy.id');\n literal(policy.schemaVersion, 3, 'policy.schemaVersion');\n string(policy.policyVersion, 'policy.policyVersion');\n\n const network = object(policy.network, 'policy.network');\n string(network.id, 'policy.network.id');\n string(network.name, 'policy.network.name');\n\n if (network.policyUrl !== undefined) {\n urlString(network.policyUrl, 'policy.network.policyUrl');\n }\n\n const detection = object(policy.detection, 'policy.detection');\n optionalArray(detection.advertiserHosts, 'policy.detection.advertiserHosts').forEach(\n validateDomainRule,\n );\n optionalArray(detection.landingParams, 'policy.detection.landingParams').forEach(\n validateParamRule,\n );\n optionalArray(detection.redirectDomains, 'policy.detection.redirectDomains').forEach(\n validateDomainRule,\n );\n optionalArray(detection.cookiePatterns, 'policy.detection.cookiePatterns').forEach(\n validateCookieRule,\n );\n optionalArray(detection.initiatorRules, 'policy.detection.initiatorRules').forEach(\n validateInitiatorRule,\n );\n optionalArray(detection.disableHosts, 'policy.detection.disableHosts').forEach(\n validateDomainRule,\n );\n\n const standdown = object(policy.standdown, 'policy.standdown');\n literal(standdown.scope, 'advertiser', 'policy.standdown.scope');\n\n if (\n standdown.sessionRule !== 'session-or-min' &&\n standdown.sessionRule !== 'inactivity-window'\n ) {\n throw new TypeError('policy.standdown.sessionRule is invalid');\n }\n\n nonNegativeFiniteNumber(\n standdown.minDurationMs,\n 'policy.standdown.minDurationMs',\n );\n\n if (standdown.inactivityMs !== undefined) {\n nonNegativeFiniteNumber(\n standdown.inactivityMs,\n 'policy.standdown.inactivityMs',\n );\n }\n\n const behaviors = array(standdown.behaviors, 'policy.standdown.behaviors');\n for (const behavior of behaviors) {\n if (!BEHAVIORS.has(behavior as Behavior)) {\n throw new TypeError(`policy.standdown.behaviors contains invalid behavior`);\n }\n }\n\n const activation = object(policy.activation, 'policy.activation');\n\n if (activation.mode !== 'user-click' && activation.mode !== 'never') {\n throw new TypeError('policy.activation.mode is invalid');\n }\n\n for (const referrerClass of optionalArray(\n activation.allowedReferrerClasses,\n 'policy.activation.allowedReferrerClasses',\n )) {\n if (!ACTIVATION_REFERRER_CLASSES.has(referrerClass as string)) {\n throw new TypeError(\n 'policy.activation.allowedReferrerClasses contains invalid class',\n );\n }\n }\n\n const metadata = object(policy.metadata, 'policy.metadata');\n urlString(metadata.sourceUrl, 'policy.metadata.sourceUrl');\n dateString(metadata.lastVerified, 'policy.metadata.lastVerified');\n\n if (metadata.notes !== undefined) {\n string(metadata.notes, 'policy.metadata.notes');\n }\n}\n\nexport function validatePolicies(\n values: readonly unknown[],\n): asserts values is readonly StanddownPolicy[] {\n values.forEach(validatePolicy);\n}\n\nfunction validateParamRule(ruleValue: unknown): void {\n const rule = object(ruleValue, 'ParamRule');\n const anyOf = array(rule.anyOf, 'ParamRule.anyOf');\n\n if (anyOf.length === 0) {\n throw new TypeError('ParamRule.anyOf must not be empty');\n }\n\n for (const groupValue of anyOf) {\n const group = object(groupValue, 'ParamRule.anyOf[]');\n const allOf = array(group.allOf, 'ParamRule.anyOf[].allOf');\n\n if (allOf.length === 0) {\n throw new TypeError('ParamRule.anyOf[].allOf must not be empty');\n }\n\n allOf.forEach(validateParamMatcher);\n }\n\n if (rule.reason !== undefined) {\n string(rule.reason, 'ParamRule.reason');\n }\n}\n\nfunction validateParamMatcher(matcherValue: unknown): void {\n const matcher = object(matcherValue, 'ParamMatcher');\n string(matcher.name, 'ParamMatcher.name');\n\n if (matcher.name.trim() === '') {\n throw new TypeError('ParamMatcher.name must not be empty');\n }\n\n if (matcher.value !== undefined) {\n string(matcher.value, 'ParamMatcher.value');\n }\n\n if (matcher.match !== undefined && !PARAM_MATCHES.has(matcher.match as string)) {\n throw new TypeError('ParamMatcher.match is invalid');\n }\n\n if (\n (matcher.match === 'equals' || matcher.match === 'contains') &&\n matcher.value === undefined\n ) {\n throw new TypeError('ParamMatcher.value is required for equals/contains');\n }\n}\n\nfunction validateDomainRule(ruleValue: unknown): void {\n const rule = object(ruleValue, 'DomainRule') as Record<string, unknown> & DomainRule;\n string(rule.pattern, 'DomainRule.pattern');\n\n if (!DOMAIN_KINDS.has(rule.kind)) {\n throw new TypeError('DomainRule.kind is invalid');\n }\n\n if (rule.kind === 'regex') {\n try {\n new RegExp(rule.pattern);\n } catch {\n throw new TypeError('DomainRule.pattern must be a valid regex');\n }\n }\n\n if (rule.comment !== undefined) {\n string(rule.comment, 'DomainRule.comment');\n }\n}\n\nfunction validateCookieRule(ruleValue: unknown): void {\n const rule = object(ruleValue, 'CookieRule') as Record<string, unknown> & CookieRule;\n string(rule.name, 'CookieRule.name');\n\n if (!COOKIE_MATCHES.has(rule.match)) {\n throw new TypeError('CookieRule.match is invalid');\n }\n\n if (rule.reason !== undefined) {\n string(rule.reason, 'CookieRule.reason');\n }\n}\n\nfunction validateInitiatorRule(ruleValue: unknown): void {\n const rule = object(ruleValue, 'InitiatorRule') as Record<string, unknown> &\n InitiatorRule;\n\n if (!REFERRER_CLASSES.has(rule.referrerClass)) {\n throw new TypeError('InitiatorRule.referrerClass is invalid');\n }\n\n if (rule.reason !== undefined) {\n string(rule.reason, 'InitiatorRule.reason');\n }\n}\n\nfunction object(value: unknown, path: string): Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new TypeError(`${path} must be an object`);\n }\n\n return value as Record<string, unknown>;\n}\n\nfunction string(value: unknown, path: string): asserts value is string {\n if (typeof value !== 'string' || value.trim() === '') {\n throw new TypeError(`${path} must be a non-empty string`);\n }\n}\n\nfunction literal<T>(value: unknown, expected: T, path: string): asserts value is T {\n if (value !== expected) {\n throw new TypeError(`${path} must be ${String(expected)}`);\n }\n}\n\nfunction array(value: unknown, path: string): readonly unknown[] {\n if (!Array.isArray(value)) {\n throw new TypeError(`${path} must be an array`);\n }\n\n return value;\n}\n\nfunction optionalArray(value: unknown, path: string): readonly unknown[] {\n if (value === undefined) {\n return [];\n }\n\n return array(value, path);\n}\n\nfunction nonNegativeFiniteNumber(value: unknown, path: string): void {\n if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) {\n throw new TypeError(`${path} must be a non-negative finite number`);\n }\n}\n\nfunction urlString(value: unknown, path: string): void {\n string(value, path);\n\n try {\n new URL(value);\n } catch {\n throw new TypeError(`${path} must be an absolute URL`);\n }\n}\n\nfunction dateString(value: unknown, path: string): void {\n string(value, path);\n\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) {\n throw new TypeError(`${path} must be YYYY-MM-DD`);\n }\n}\n","import type {\n CookieRule,\n Detection,\n DomainRule,\n InitiatorRule,\n MatchedRule,\n ParamMatcher,\n ParamRule,\n ReferrerClass,\n SelfExemption,\n SelfExemptScope,\n Signals,\n StanddownPolicy,\n} from './types';\n\nconst ORGANIC_REFERRER_SUFFIXES = [\n 'google.com',\n 'bing.com',\n 'duckduckgo.com',\n 'yahoo.com',\n 'ecosia.org',\n 'baidu.com',\n 'yandex.com',\n] as const;\n\nexport function detect(\n signals: Signals,\n policies: readonly StanddownPolicy[],\n): Detection {\n const currentUrl = parseUrl(signals.url);\n\n if (!currentUrl) {\n return {\n matched: [],\n selfMatch: false,\n failClosedReason: 'invalid-url',\n };\n }\n\n const advertiserHost = currentUrl.hostname.toLowerCase();\n const matched: MatchedRule[] = [];\n const selfExemptScopes: SelfExemptScope[] = [];\n let selfMatch = false;\n\n for (const policy of policies) {\n const disabledHostRule = (policy.detection.disableHosts ?? []).find((rule) =>\n domainRuleMatchesUrl(rule, advertiserHost),\n );\n\n if (disabledHostRule) {\n matched.push(\n matchedRule(\n policy,\n 'disabled-host',\n `${disabledHostRule.kind}:${disabledHostRule.pattern}`,\n advertiserHost,\n disabledHostRule.comment ?? 'host disabled for this network',\n ),\n );\n continue;\n }\n\n const scopedSelfMatch = hasScopedSelfExemption(\n currentUrl,\n signals.selfPatterns,\n policy,\n );\n const unscopedSelfMatch = hasUnscopedSelfExemption(\n currentUrl,\n signals.selfPatterns,\n );\n\n if (scopedSelfMatch || unscopedSelfMatch) {\n selfMatch = true;\n }\n\n if (scopedSelfMatch) {\n selfExemptScopes.push({\n policyId: policy.id,\n networkId: policy.network.id,\n });\n continue;\n }\n\n matched.push(\n ...collectPolicyMatches(policy, signals, currentUrl, advertiserHost),\n );\n }\n\n matched.sort((left, right) => kindPriority(left.kind) - kindPriority(right.kind));\n\n const strongest = matched[0]\n ? {\n policyId: matched[0].policyId,\n advertiserHost: matched[0].advertiserHost,\n reason: matched[0].reason,\n }\n : undefined;\n\n const base: Detection = { matched, selfMatch };\n\n if (strongest) {\n base.strongest = strongest;\n }\n\n if (selfExemptScopes.length > 0) {\n base.selfExemptScopes = selfExemptScopes;\n }\n\n return base;\n}\n\nexport function classifyReferrer(\n signals: Pick<Signals, 'referrer' | 'initiator' | 'publisherSites'>,\n advertiserHost: string,\n): ReferrerClass {\n const candidate = signals.initiator ?? signals.referrer;\n\n if (!candidate) {\n return 'direct';\n }\n\n const referrerHost = hostFromUrl(candidate);\n\n if (!referrerHost) {\n return 'other';\n }\n\n if (\n (signals.publisherSites ?? []).some((site) =>\n domainSuffixMatches(referrerHost, site),\n )\n ) {\n return 'own-site';\n }\n\n if (domainSuffixMatches(referrerHost, advertiserHost)) {\n return 'advertiser-internal';\n }\n\n if (\n ORGANIC_REFERRER_SUFFIXES.some((suffix) =>\n domainSuffixMatches(referrerHost, suffix),\n )\n ) {\n return 'organic';\n }\n\n return 'other';\n}\n\nexport function domainRuleMatchesUrl(rule: DomainRule, value: string): boolean {\n const url = parseUrl(value);\n const host = url?.hostname.toLowerCase() ?? value.toLowerCase();\n\n if (rule.kind === 'suffix') {\n return domainSuffixMatches(host, rule.pattern);\n }\n\n try {\n const regex = new RegExp(rule.pattern, 'i');\n return regex.test(host) || (url ? regex.test(url.href) : regex.test(value));\n } catch {\n return false;\n }\n}\n\nfunction collectPolicyMatches(\n policy: StanddownPolicy,\n signals: Signals,\n currentUrl: URL,\n advertiserHost: string,\n): MatchedRule[] {\n const matches: MatchedRule[] = [];\n const advertiserHostMatches =\n policy.detection.advertiserHosts === undefined ||\n policy.detection.advertiserHosts.some((rule) =>\n domainRuleMatchesUrl(rule, advertiserHost),\n );\n\n if (advertiserHostMatches) {\n for (const rule of policy.detection.landingParams ?? []) {\n if (paramRuleMatches(rule, currentUrl.searchParams)) {\n matches.push(\n matchedRule(\n policy,\n 'landing-param',\n describeParamRule(rule),\n advertiserHost,\n rule.reason ?? 'landing parameter matched',\n ),\n );\n }\n }\n }\n\n for (const rule of policy.detection.redirectDomains ?? []) {\n if ((signals.redirectChain ?? []).some((url) => domainRuleMatchesUrl(rule, url))) {\n matches.push(\n matchedRule(\n policy,\n 'redirect-domain',\n `${rule.kind}:${rule.pattern}`,\n advertiserHost,\n rule.comment ?? 'redirect domain matched',\n ),\n );\n }\n }\n\n if (advertiserHostMatches) {\n for (const rule of policy.detection.cookiePatterns ?? []) {\n if (cookieRuleMatches(rule, signals.cookieNames ?? [])) {\n matches.push(\n matchedRule(\n policy,\n 'cookie',\n `${rule.match}:${rule.name}`,\n advertiserHost,\n rule.reason ?? 'first-party cookie name matched',\n ),\n );\n }\n }\n }\n\n if (advertiserHostMatches) {\n for (const rule of policy.detection.initiatorRules ?? []) {\n if (initiatorRuleMatches(rule, signals, advertiserHost)) {\n matches.push(\n matchedRule(\n policy,\n 'initiator',\n `referrer-class:${rule.referrerClass}`,\n advertiserHost,\n rule.reason ?? 'initiator/referrer class matched',\n ),\n );\n }\n }\n }\n\n return matches;\n}\n\nfunction matchedRule(\n policy: StanddownPolicy,\n kind: MatchedRule['kind'],\n rule: string,\n advertiserHost: string,\n reason: string,\n): MatchedRule {\n return {\n policyId: policy.id,\n networkId: policy.network.id,\n networkName: policy.network.name,\n kind,\n rule,\n advertiserHost,\n reason,\n sourceUrl: policy.metadata.sourceUrl,\n };\n}\n\nfunction kindPriority(kind: MatchedRule['kind']): number {\n if (kind === 'disabled-host') {\n return 0;\n }\n\n if (kind === 'redirect-domain') {\n return 1;\n }\n\n if (kind === 'landing-param') {\n return 2;\n }\n\n if (kind === 'cookie') {\n return 3;\n }\n\n return 4;\n}\n\nfunction paramRuleMatches(rule: ParamRule, params: URLSearchParams): boolean {\n return rule.anyOf.some((group) =>\n group.allOf.every((matcher) => paramMatcherMatches(matcher, params)),\n );\n}\n\nfunction paramMatcherMatches(\n matcher: ParamMatcher,\n params: URLSearchParams,\n): boolean {\n const values = params.getAll(matcher.name);\n const mode = matcher.match ?? (matcher.value === undefined ? 'exists' : 'equals');\n\n if (mode === 'exists') {\n return values.length > 0;\n }\n\n const expectedValue = matcher.value;\n\n if (expectedValue === undefined) {\n return false;\n }\n\n if (mode === 'equals') {\n return values.some((value) => value === expectedValue);\n }\n\n return values.some((value) => value.includes(expectedValue));\n}\n\nfunction cookieRuleMatches(\n rule: CookieRule,\n cookieNames: readonly string[],\n): boolean {\n if (rule.match === 'exact') {\n return cookieNames.some((name) => name === rule.name);\n }\n\n return cookieNames.some((name) => name.includes(rule.name));\n}\n\nfunction initiatorRuleMatches(\n rule: InitiatorRule,\n signals: Signals,\n advertiserHost: string,\n): boolean {\n return classifyReferrer(signals, advertiserHost) === rule.referrerClass;\n}\n\nfunction hasScopedSelfExemption(\n currentUrl: URL,\n selfPatterns: readonly SelfExemption[] | undefined,\n policy: StanddownPolicy,\n): boolean {\n return (selfPatterns ?? []).some((pattern) => {\n const scopedToPolicy = pattern.policyId === policy.id;\n const scopedToNetwork = pattern.networkId === policy.network.id;\n\n return (\n (scopedToPolicy || scopedToNetwork) &&\n paramMatcherMatches(pattern, currentUrl.searchParams)\n );\n });\n}\n\nfunction hasUnscopedSelfExemption(\n currentUrl: URL,\n selfPatterns: readonly SelfExemption[] | undefined,\n): boolean {\n return (selfPatterns ?? []).some(\n (pattern) =>\n pattern.policyId === undefined &&\n pattern.networkId === undefined &&\n paramMatcherMatches(pattern, currentUrl.searchParams),\n );\n}\n\nfunction domainSuffixMatches(host: string, pattern: string): boolean {\n const normalizedHost = host.toLowerCase().replace(/\\.$/, '');\n const normalizedPattern = pattern.toLowerCase().replace(/^\\./, '').replace(/\\.$/, '');\n\n return (\n normalizedHost === normalizedPattern ||\n normalizedHost.endsWith(`.${normalizedPattern}`)\n );\n}\n\nfunction describeParamRule(rule: ParamRule): string {\n return rule.anyOf\n .map((group) =>\n group.allOf\n .map((matcher) => {\n const mode = matcher.match ?? (matcher.value === undefined ? 'exists' : 'equals');\n return matcher.value === undefined\n ? `${matcher.name}:${mode}`\n : `${matcher.name}:${mode}:${matcher.value}`;\n })\n .join('&'),\n )\n .join('|');\n}\n\nfunction parseUrl(value: string): URL | undefined {\n try {\n return new URL(value);\n } catch {\n return undefined;\n }\n}\n\nfunction hostFromUrl(value: string): string | undefined {\n return parseUrl(value)?.hostname.toLowerCase();\n}\n","import { classifyReferrer, detect } from './detect';\nimport type {\n AuditEntry,\n Decision,\n Detection,\n ExemptionRecord,\n SessionRecord,\n Signals,\n StanddownPolicy,\n StanddownState,\n StateStore,\n} from './types';\nimport { validatePolicies } from './validation';\n\nexport class MemoryStateStore implements StateStore {\n #state: StanddownState | undefined;\n\n constructor(initialState?: StanddownState) {\n this.#state = initialState ? cloneState(initialState) : undefined;\n }\n\n async load(): Promise<StanddownState | undefined> {\n return this.#state ? cloneState(this.#state) : undefined;\n }\n\n async save(state: StanddownState): Promise<void> {\n this.#state = cloneState(state);\n }\n}\n\nexport class StanddownSession {\n readonly #store: StateStore;\n readonly #auditLog: boolean;\n readonly #maxAuditEntries: number;\n readonly #selfExemptionScope: 'policy' | 'session';\n readonly #readOnlyAuditLog: AuditEntry[] = [];\n\n constructor(\n store: StateStore,\n opts?: {\n auditLog?: boolean;\n maxAuditEntries?: number;\n /**\n * How long a `selfPatterns` match suppresses stand-down for its\n * advertiser host. `'policy'` (default) exempts only the navigation that\n * carries the param. `'session'` persists the exemption for the host and\n * re-applies it to that same network's detections on later param-less\n * navigations — Dupe's `ignore_param` semantics. A session exemption never\n * lifts an already-active stand-down and never covers a `disabled-host`.\n */\n selfExemptionScope?: 'policy' | 'session';\n },\n ) {\n this.#store = store;\n this.#auditLog = opts?.auditLog ?? true;\n this.#maxAuditEntries = Math.max(0, opts?.maxAuditEntries ?? 1_000);\n this.#selfExemptionScope = opts?.selfExemptionScope ?? 'policy';\n }\n\n async ingest(\n signals: Signals,\n policies: readonly StanddownPolicy[],\n ): Promise<Decision> {\n const advertiserHost = hostFromUrl(signals.url);\n\n try {\n validatePolicies(policies);\n } catch (error) {\n return this.#failClosedWithAudit(\n signals.now,\n 'ingest',\n advertiserHost,\n `malformed-policy: ${messageFromError(error)}`,\n );\n }\n\n const detection = detect(signals, policies);\n\n if (detection.failClosedReason) {\n return this.#failClosedWithAudit(\n signals.now,\n 'ingest',\n advertiserHost,\n detection.failClosedReason,\n detection,\n );\n }\n\n return this.#withState(signals.now, (state) => {\n pruneExpiredSessions(state, signals.now);\n\n let effective = detection;\n\n if (this.#selfExemptionScope === 'session' && advertiserHost) {\n recordSessionExemptions(state, advertiserHost, detection, signals.now);\n effective = applySessionExemptions(\n advertiserHost,\n detection,\n state.exemptions?.[advertiserHost],\n );\n }\n\n if (effective.strongest) {\n const matchedPolicies = policiesForDetection(policies, effective);\n\n if (matchedPolicies.length === 0) {\n return {\n decision: failClosedDecision('matched-policy-missing'),\n detection: effective,\n };\n }\n\n const record = upsertSessionRecord(\n state,\n effective.strongest.advertiserHost,\n effective.strongest.policyId,\n matchedPolicies,\n signals.now,\n );\n\n return {\n decision: decisionFromRecord(record, signals.now, {\n reason: effective.strongest.reason,\n referrerClass: classifyReferrer(signals, record.advertiserHost),\n }),\n detection: effective,\n };\n }\n\n const activeDecision = advertiserHost\n ? activeDecisionForHost(state, advertiserHost, signals.now)\n : undefined;\n\n // A session exemption filtered out what would otherwise have stood down.\n const sessionExempted =\n detection.strongest !== undefined && effective.strongest === undefined;\n\n return {\n decision:\n activeDecision ??\n ({\n standDown: false,\n reason: sessionExempted\n ? 'self-exempted-session'\n : detection.selfMatch\n ? 'self-exempted-no-active-standdown'\n : 'no-active-standdown',\n behaviors: [],\n referrerClass: advertiserHost\n ? classifyReferrer(signals, advertiserHost)\n : 'other',\n ...(signals.signalCoverage === 'partial' ? { degraded: true } : {}),\n } satisfies Decision),\n detection: effective,\n };\n }, 'ingest');\n }\n\n async shouldStandDown(\n advertiserHost: string,\n now: number,\n ): Promise<Decision> {\n return this.#withState(\n now,\n (state) => {\n pruneExpiredSessions(state, now);\n\n return {\n decision:\n activeDecisionForHost(state, advertiserHost, now) ??\n ({\n standDown: false,\n reason: 'no-active-standdown',\n behaviors: [],\n } satisfies Decision),\n };\n },\n 'shouldStandDown',\n normalizeHost(advertiserHost),\n { persist: false },\n );\n }\n\n async recordActivity(now: number): Promise<void> {\n await this.#withState(\n now,\n (state) => {\n pruneExpiredSessions(state, now);\n\n for (const record of Object.values(state.sessions)) {\n if (record.sessionRule === 'inactivity-window') {\n record.lastActivityAt = now;\n const expiresAt = computeExpiresAt(record);\n\n if (expiresAt !== undefined) {\n record.expiresAt = expiresAt;\n }\n }\n }\n\n return {\n decision: {\n standDown: false,\n reason: 'activity-recorded',\n behaviors: [],\n },\n };\n },\n 'recordActivity',\n );\n }\n\n async exportAuditLog(): Promise<AuditEntry[]> {\n const state = await this.#loadState();\n return trimAuditLog(\n [...state.auditLog, ...this.#readOnlyAuditLog],\n this.#maxAuditEntries,\n ).map(cloneAuditEntry);\n }\n\n async #withState(\n now: number,\n fn: (state: StanddownState) => {\n decision: Decision;\n detection?: Detection;\n },\n action: AuditEntry['action'],\n advertiserHost?: string,\n opts: { persist?: boolean } = {},\n ): Promise<Decision> {\n let state: StanddownState;\n\n try {\n state = await this.#loadState();\n } catch {\n return failClosedDecision('store-error');\n }\n\n const result = fn(state);\n\n if (this.#auditLog) {\n const entry = auditEntry({\n time: now,\n action,\n advertiserHost:\n advertiserHost ?? result.detection?.strongest?.advertiserHost,\n detection: result.detection,\n decision: result.decision,\n });\n\n if (opts.persist === false) {\n appendAuditEntry(this.#readOnlyAuditLog, entry, this.#maxAuditEntries);\n } else {\n appendAuditEntry(state.auditLog, entry, this.#maxAuditEntries);\n }\n }\n\n if (opts.persist === false) {\n return result.decision;\n }\n\n try {\n await this.#store.save(state);\n } catch {\n return failClosedDecision('store-error');\n }\n\n return result.decision;\n }\n\n async #failClosedWithAudit(\n now: number,\n action: AuditEntry['action'],\n advertiserHost: string | undefined,\n reason: string,\n detection?: Detection,\n ): Promise<Decision> {\n const decision = failClosedDecision(reason);\n\n if (!this.#auditLog) {\n return decision;\n }\n\n try {\n const state = await this.#loadState();\n appendAuditEntry(\n state.auditLog,\n auditEntry({\n time: now,\n action,\n advertiserHost,\n detection,\n decision,\n }),\n this.#maxAuditEntries,\n );\n await this.#store.save(state);\n } catch {\n return failClosedDecision('store-error');\n }\n\n return decision;\n }\n\n async #loadState(): Promise<StanddownState> {\n return (await this.#store.load()) ?? { sessions: {}, auditLog: [] };\n }\n}\n\nfunction appendAuditEntry(\n auditLog: AuditEntry[],\n entry: AuditEntry,\n maxEntries: number,\n): void {\n if (maxEntries === 0) {\n auditLog.length = 0;\n return;\n }\n\n auditLog.push(entry);\n\n if (auditLog.length > maxEntries) {\n auditLog.splice(0, auditLog.length - maxEntries);\n }\n}\n\nfunction trimAuditLog(\n auditLog: readonly AuditEntry[],\n maxEntries: number,\n): AuditEntry[] {\n if (maxEntries === 0) {\n return [];\n }\n\n return auditLog.slice(Math.max(0, auditLog.length - maxEntries));\n}\n\nfunction upsertSessionRecord(\n state: StanddownState,\n advertiserHost: string,\n primaryPolicyId: string,\n policies: readonly StanddownPolicy[],\n now: number,\n): SessionRecord {\n const key = normalizeHost(advertiserHost);\n const existing = state.sessions[key];\n const startedAt = existing?.startedAt ?? now;\n const lastActivityAt = now;\n const sessionRule =\n existing?.sessionRule === 'session-or-min' ||\n policies.some((policy) => policy.standdown.sessionRule === 'session-or-min')\n ? 'session-or-min'\n : 'inactivity-window';\n const baseRecord: SessionRecord = {\n advertiserHost: key,\n policyId: primaryPolicyId,\n startedAt,\n lastActivityAt,\n sessionRule,\n minDurationMs: Math.max(\n existing?.minDurationMs ?? 0,\n ...policies.map((policy) => policy.standdown.minDurationMs),\n ),\n behaviors: unionBehaviors([\n ...(existing?.behaviors ?? []),\n ...policies.flatMap((policy) => policy.standdown.behaviors),\n ]),\n };\n\n if (sessionRule === 'inactivity-window') {\n const inactivityMs = Math.max(\n existing?.inactivityMs ?? 0,\n ...policies.flatMap((policy) =>\n policy.standdown.inactivityMs === undefined\n ? []\n : [policy.standdown.inactivityMs],\n ),\n );\n\n if (inactivityMs > 0) {\n baseRecord.inactivityMs = inactivityMs;\n }\n }\n\n const computedExpiresAt = computeExpiresAt(baseRecord);\n\n if (computedExpiresAt !== undefined) {\n baseRecord.expiresAt = Math.max(existing?.expiresAt ?? 0, computedExpiresAt);\n }\n\n state.sessions[key] = baseRecord;\n\n return baseRecord;\n}\n\n/**\n * Persist scoped self-exemptions seen on this navigation for the host, so later\n * param-less navigations re-apply them. Monotone: never grant an exemption while\n * a stand-down is already active for the host (that would reduce existing\n * suppression, which a self-exemption may never do).\n */\nfunction recordSessionExemptions(\n state: StanddownState,\n advertiserHost: string,\n detection: Detection,\n now: number,\n): void {\n const scopes = detection.selfExemptScopes;\n\n if (!scopes || scopes.length === 0) {\n return;\n }\n\n if (activeDecisionForHost(state, advertiserHost, now) !== undefined) {\n return;\n }\n\n const key = normalizeHost(advertiserHost);\n\n if (state.exemptions === undefined) {\n state.exemptions = {};\n }\n\n const exemptions = state.exemptions;\n const existing = exemptions[key];\n const policyIds = new Set(existing?.policyIds ?? []);\n const networkIds = new Set(existing?.networkIds ?? []);\n\n for (const scope of scopes) {\n policyIds.add(scope.policyId);\n networkIds.add(scope.networkId);\n }\n\n exemptions[key] = {\n advertiserHost: key,\n policyIds: [...policyIds],\n networkIds: [...networkIds],\n grantedAt: existing?.grantedAt ?? now,\n };\n}\n\n/**\n * Re-apply a host's persisted session exemptions: drop matched rules whose\n * policy/network was exempted for this host, then recompute the strongest match.\n * `disabled-host` matches are never dropped — a hard-disabled host stands down\n * regardless of any self-exemption.\n */\nfunction applySessionExemptions(\n advertiserHost: string,\n detection: Detection,\n record: ExemptionRecord | undefined,\n): Detection {\n if (!record) {\n return detection;\n }\n\n const host = normalizeHost(advertiserHost);\n const policyIds = new Set(record.policyIds);\n const networkIds = new Set(record.networkIds);\n\n const filtered = detection.matched.filter((match) => {\n if (match.kind === 'disabled-host') {\n return true;\n }\n\n if (normalizeHost(match.advertiserHost) !== host) {\n return true;\n }\n\n return !(policyIds.has(match.policyId) || networkIds.has(match.networkId));\n });\n\n if (filtered.length === detection.matched.length) {\n return detection;\n }\n\n const strongest = filtered[0]\n ? {\n policyId: filtered[0].policyId,\n advertiserHost: filtered[0].advertiserHost,\n reason: filtered[0].reason,\n }\n : undefined;\n\n const next: Detection = { matched: filtered, selfMatch: detection.selfMatch };\n\n if (strongest) {\n next.strongest = strongest;\n }\n\n if (detection.selfExemptScopes) {\n next.selfExemptScopes = detection.selfExemptScopes;\n }\n\n return next;\n}\n\nfunction policiesForDetection(\n policies: readonly StanddownPolicy[],\n detection: Detection,\n): StanddownPolicy[] {\n if (detection.strongest === undefined) {\n return [];\n }\n\n const matchingPolicyIds = new Set(\n detection.matched\n .filter(\n (match) => match.advertiserHost === detection.strongest?.advertiserHost,\n )\n .map((match) => match.policyId),\n );\n\n return policies.filter((policy) => matchingPolicyIds.has(policy.id));\n}\n\nfunction unionBehaviors(behaviors: readonly SessionRecord['behaviors'][number][]) {\n return [...new Set(behaviors)];\n}\n\nfunction activeDecisionForHost(\n state: StanddownState,\n advertiserHost: string,\n now: number,\n): Decision | undefined {\n const record = state.sessions[normalizeHost(advertiserHost)];\n\n if (!record || !isActive(record, now)) {\n return undefined;\n }\n\n return decisionFromRecord(record, now);\n}\n\nfunction decisionFromRecord(\n record: SessionRecord,\n now: number,\n overrides?: { reason?: string; referrerClass?: Decision['referrerClass'] },\n): Decision {\n const expiresAt = computeExpiresAt(record);\n const decision: Decision = {\n standDown: true,\n policyId: record.policyId,\n reason: overrides?.reason ?? `active-standdown:${record.policyId}`,\n behaviors: [...record.behaviors],\n };\n\n if (expiresAt !== undefined) {\n decision.expiresAt = expiresAt;\n }\n\n if (overrides?.referrerClass !== undefined) {\n decision.referrerClass = overrides.referrerClass;\n }\n\n if (!isActive({ ...record, ...(expiresAt === undefined ? {} : { expiresAt }) }, now)) {\n return {\n standDown: false,\n reason: 'standdown-expired',\n behaviors: [],\n };\n }\n\n return decision;\n}\n\nfunction computeExpiresAt(record: SessionRecord): number | undefined {\n if (\n record.sessionRule === 'inactivity-window' &&\n record.inactivityMs !== undefined\n ) {\n return Math.max(\n record.startedAt + record.minDurationMs,\n record.lastActivityAt + record.inactivityMs,\n );\n }\n\n return record.expiresAt;\n}\n\nfunction isActive(record: SessionRecord, now: number): boolean {\n if (record.sessionRule === 'session-or-min') {\n return true;\n }\n\n const expiresAt = computeExpiresAt(record);\n\n return expiresAt === undefined ? false : now < expiresAt;\n}\n\nfunction pruneExpiredSessions(state: StanddownState, now: number): void {\n for (const [host, record] of Object.entries(state.sessions)) {\n if (!isActive(record, now)) {\n delete state.sessions[host];\n }\n }\n}\n\nfunction failClosedDecision(reason: string): Decision {\n return {\n standDown: true,\n reason,\n behaviors: [\n 'suppress-prompts',\n 'no-cookie-write',\n 'no-redirect',\n 'no-background-tracking',\n ],\n };\n}\n\nfunction auditEntry(value: {\n time: number;\n action: AuditEntry['action'];\n advertiserHost: string | undefined;\n detection: Detection | undefined;\n decision: Decision | undefined;\n}): AuditEntry {\n const entry: AuditEntry = {\n time: value.time,\n action: value.action,\n };\n\n if (value.advertiserHost !== undefined) {\n entry.advertiserHost = value.advertiserHost;\n }\n\n if (value.detection !== undefined) {\n entry.detection = value.detection;\n }\n\n if (value.decision !== undefined) {\n entry.decision = value.decision;\n }\n\n return entry;\n}\n\nfunction cloneState(state: StanddownState): StanddownState {\n const cloned: StanddownState = {\n sessions: Object.fromEntries(\n Object.entries(state.sessions).map(([host, record]) => [\n host,\n {\n ...record,\n behaviors: [...record.behaviors],\n },\n ]),\n ),\n auditLog: state.auditLog.map(cloneAuditEntry),\n };\n\n if (state.exemptions) {\n cloned.exemptions = Object.fromEntries(\n Object.entries(state.exemptions).map(([host, record]) => [\n host,\n {\n ...record,\n policyIds: [...record.policyIds],\n networkIds: [...record.networkIds],\n },\n ]),\n );\n }\n\n return cloned;\n}\n\nfunction cloneAuditEntry(entry: AuditEntry): AuditEntry {\n const cloned: AuditEntry = {\n time: entry.time,\n action: entry.action,\n };\n\n if (entry.advertiserHost !== undefined) {\n cloned.advertiserHost = entry.advertiserHost;\n }\n\n if (entry.detection !== undefined) {\n const detection: Detection = {\n matched: entry.detection.matched.map((match) => ({ ...match })),\n selfMatch: entry.detection.selfMatch,\n };\n\n if (entry.detection.strongest !== undefined) {\n detection.strongest = { ...entry.detection.strongest };\n }\n\n if (entry.detection.selfExemptScopes !== undefined) {\n detection.selfExemptScopes = entry.detection.selfExemptScopes.map(\n (scope) => ({ ...scope }),\n );\n }\n\n if (entry.detection.failClosedReason !== undefined) {\n detection.failClosedReason = entry.detection.failClosedReason;\n }\n\n cloned.detection = detection;\n }\n\n if (entry.decision !== undefined) {\n cloned.decision = {\n ...entry.decision,\n behaviors: [...entry.decision.behaviors],\n };\n }\n\n return cloned;\n}\n\nfunction normalizeHost(host: string): string {\n return host.toLowerCase().replace(/\\.$/, '');\n}\n\nfunction hostFromUrl(value: string): string | undefined {\n try {\n return normalizeHost(new URL(value).hostname);\n } catch {\n return undefined;\n }\n}\n\nfunction messageFromError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"]}
|