@adcp/sdk 16.0.0-beta.7 → 16.0.0-beta.8
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 +17 -0
- package/dist/lib/conformance/index.d.mts +2 -0
- package/dist/lib/conformance/index.d.ts +2 -0
- package/dist/lib/conformance/index.js +3 -0
- package/dist/lib/conformance/index.mjs +2 -0
- package/dist/lib/conformance/property-lists.d.mts +14 -0
- package/dist/lib/conformance/property-lists.d.ts +14 -0
- package/dist/lib/conformance/property-lists.js +45 -0
- package/dist/lib/conformance/property-lists.mjs +21 -0
- package/dist/lib/conformance/runConformance.js +20 -1
- package/dist/lib/conformance/runConformance.mjs +20 -1
- package/dist/lib/conformance/types.d.mts +3 -0
- package/dist/lib/conformance/types.d.ts +3 -0
- package/dist/lib/core/SingleAgentClient.d.mts +13 -3
- package/dist/lib/core/SingleAgentClient.d.ts +13 -3
- package/dist/lib/core/SingleAgentClient.js +109 -21
- package/dist/lib/core/SingleAgentClient.mjs +112 -22
- package/dist/lib/identifiers.d.mts +53 -0
- package/dist/lib/identifiers.d.ts +53 -0
- package/dist/lib/identifiers.js +212 -0
- package/dist/lib/identifiers.mjs +163 -0
- package/dist/lib/index.d.mts +3 -1
- package/dist/lib/index.d.ts +3 -1
- package/dist/lib/index.js +2 -0
- package/dist/lib/index.mjs +1 -0
- package/dist/lib/media-buy/index.d.mts +1 -1
- package/dist/lib/media-buy/index.d.ts +1 -1
- package/dist/lib/media-buy/property-policy.d.mts +15 -1
- package/dist/lib/media-buy/property-policy.d.ts +15 -1
- package/dist/lib/media-buy/property-policy.js +135 -3
- package/dist/lib/media-buy/property-policy.mjs +134 -3
- package/dist/lib/registry/index.d.mts +12 -0
- package/dist/lib/registry/index.d.ts +12 -0
- package/dist/lib/registry/index.js +159 -5
- package/dist/lib/registry/index.mjs +156 -4
- package/dist/lib/registry/types.d.mts +23 -0
- package/dist/lib/registry/types.d.ts +23 -0
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/decisioning/specialisms/lists.d.mts +4 -4
- package/dist/lib/server/decisioning/specialisms/lists.d.ts +4 -4
- package/dist/lib/server/index.d.mts +3 -0
- package/dist/lib/server/index.d.ts +3 -0
- package/dist/lib/server/index.js +8 -1
- package/dist/lib/server/index.mjs +4 -0
- package/dist/lib/server/property-lists.d.mts +36 -0
- package/dist/lib/server/property-lists.d.ts +36 -0
- package/dist/lib/server/property-lists.js +154 -0
- package/dist/lib/server/property-lists.mjs +129 -0
- package/dist/lib/server/targeting-helpers.d.mts +2 -0
- package/dist/lib/server/targeting-helpers.d.ts +2 -0
- package/dist/lib/server/targeting-helpers.js +28 -1
- package/dist/lib/server/targeting-helpers.mjs +18 -1
- package/dist/lib/signing/parser.js +2 -2
- package/dist/lib/signing/parser.mjs +2 -2
- package/dist/lib/signing/server.d.mts +1 -1
- package/dist/lib/signing/server.d.ts +1 -1
- package/dist/lib/signing/server.mjs +5 -1
- package/dist/lib/signing/webhook-verifier.d.mts +11 -0
- package/dist/lib/signing/webhook-verifier.d.ts +11 -0
- package/dist/lib/signing/webhook-verifier.js +11 -3
- package/dist/lib/signing/webhook-verifier.mjs +11 -3
- package/dist/lib/supply-path/verify.js +12 -2
- package/dist/lib/supply-path/verify.mjs +2 -2
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.mjs +3 -3
- package/docs/TYPE-SUMMARY.md +2 -2
- package/docs/guides/PROPERTY-LISTS.md +264 -0
- package/docs/guides/SIGNING-GUIDE.md +25 -0
- package/docs/llms.txt +2 -2
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/package.json +1 -1
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { isIP } from "node:net";
|
|
2
|
+
import { domainToASCII } from "node:url";
|
|
3
|
+
class IdentifierValidationError extends TypeError {
|
|
4
|
+
constructor(code, identifierType, message) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.code = code;
|
|
7
|
+
this.identifierType = identifierType;
|
|
8
|
+
}
|
|
9
|
+
code;
|
|
10
|
+
identifierType;
|
|
11
|
+
name = "IdentifierValidationError";
|
|
12
|
+
}
|
|
13
|
+
const PUBLISHER_DOMAIN = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/;
|
|
14
|
+
function isDomain(value) {
|
|
15
|
+
if (value.length > 253 || !PUBLISHER_DOMAIN.test(value) || value.split(".").some((label) => label.length > 63) || isIP(value))
|
|
16
|
+
return false;
|
|
17
|
+
try {
|
|
18
|
+
return !isIP(new URL(`https://${value}`).hostname);
|
|
19
|
+
} catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function accepted(input, value) {
|
|
24
|
+
return { ok: true, value, ...input === value ? {} : { rewrite: { from: input, to: value } } };
|
|
25
|
+
}
|
|
26
|
+
function rejected(type, code = "invalid_identifier") {
|
|
27
|
+
return {
|
|
28
|
+
ok: false,
|
|
29
|
+
error: new IdentifierValidationError(
|
|
30
|
+
code,
|
|
31
|
+
type,
|
|
32
|
+
code === "invalid_publisher_domain" ? "publisher_domain must be a canonical lowercase hostname without wildcards, URLs, or IP addresses" : `Invalid ${type} identifier`
|
|
33
|
+
)
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function validatePublisherDomain(value) {
|
|
37
|
+
return typeof value === "string" && isDomain(value) ? accepted(value, value) : rejected("publisher_domain", "invalid_publisher_domain");
|
|
38
|
+
}
|
|
39
|
+
function normalizeHostname(input, type) {
|
|
40
|
+
if (typeof input !== "string") return rejected(type);
|
|
41
|
+
let value = input.trim();
|
|
42
|
+
if (/^https?:\/\//i.test(value)) {
|
|
43
|
+
try {
|
|
44
|
+
const url = new URL(value);
|
|
45
|
+
if (url.username || url.password) return rejected(type);
|
|
46
|
+
value = url.hostname;
|
|
47
|
+
} catch {
|
|
48
|
+
return rejected(type);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const wildcard = value.startsWith("*.");
|
|
52
|
+
if (wildcard && type !== "domain") return rejected(type);
|
|
53
|
+
if (/[\s/\\:@?#%]/.test(wildcard ? value.slice(2) : value)) return rejected(type);
|
|
54
|
+
const host = domainToASCII((wildcard ? value.slice(2) : value).toLowerCase().replace(/\.$/, ""));
|
|
55
|
+
if (!isDomain(host)) return rejected(type);
|
|
56
|
+
return accepted(input, `${wildcard ? "*." : ""}${host}`);
|
|
57
|
+
}
|
|
58
|
+
const normalizeDomainIdentifier = (value) => normalizeHostname(value, "domain");
|
|
59
|
+
const normalizeSubdomainIdentifier = (value) => normalizeHostname(value, "subdomain");
|
|
60
|
+
function normalizePattern(type, input, pattern, uppercase = false) {
|
|
61
|
+
if (typeof input !== "string") return rejected(type);
|
|
62
|
+
const value = uppercase ? input.trim().toUpperCase() : input.trim();
|
|
63
|
+
return pattern.test(value) ? accepted(input, value) : rejected(type);
|
|
64
|
+
}
|
|
65
|
+
const normalizeIosBundleIdentifier = (value) => normalizePattern("ios_bundle", value, /^[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)+$/);
|
|
66
|
+
const normalizeAndroidPackageIdentifier = (value) => normalizePattern("android_package", value, /^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)+$/);
|
|
67
|
+
const normalizeAppleAppStoreIdentifier = (value) => normalizePattern("apple_app_store_id", value, /^[1-9][0-9]*$/);
|
|
68
|
+
const normalizeGooglePlayIdentifier = (value) => normalizePattern("google_play_id", value, /^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)+$/);
|
|
69
|
+
const normalizeRokuStoreIdentifier = (value) => normalizePattern("roku_store_id", value, /^[1-9][0-9]*$/);
|
|
70
|
+
const normalizeFireTvAsinIdentifier = (value) => normalizePattern("fire_tv_asin", value, /^[A-Z0-9]{10}$/, true);
|
|
71
|
+
const normalizeSamsungAppIdentifier = (value) => normalizePattern("samsung_app_id", value, /^[A-Za-z0-9._-]+$/);
|
|
72
|
+
const normalizeAppleTvBundleIdentifier = (value) => normalizePattern("apple_tv_bundle", value, /^[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)+$/);
|
|
73
|
+
const normalizeBundleIdentifier = (value) => normalizePattern("bundle_id", value, /^[A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)+$/);
|
|
74
|
+
function normalizePropertyIdentifier(type, value) {
|
|
75
|
+
switch (type) {
|
|
76
|
+
case "domain":
|
|
77
|
+
return normalizeDomainIdentifier(value);
|
|
78
|
+
case "subdomain":
|
|
79
|
+
return normalizeSubdomainIdentifier(value);
|
|
80
|
+
case "ios_bundle":
|
|
81
|
+
return normalizeIosBundleIdentifier(value);
|
|
82
|
+
case "android_package":
|
|
83
|
+
return normalizeAndroidPackageIdentifier(value);
|
|
84
|
+
case "apple_app_store_id":
|
|
85
|
+
return normalizeAppleAppStoreIdentifier(value);
|
|
86
|
+
case "google_play_id":
|
|
87
|
+
return normalizeGooglePlayIdentifier(value);
|
|
88
|
+
case "roku_store_id":
|
|
89
|
+
return normalizeRokuStoreIdentifier(value);
|
|
90
|
+
case "fire_tv_asin":
|
|
91
|
+
return normalizeFireTvAsinIdentifier(value);
|
|
92
|
+
case "samsung_app_id":
|
|
93
|
+
return normalizeSamsungAppIdentifier(value);
|
|
94
|
+
case "apple_tv_bundle":
|
|
95
|
+
return normalizeAppleTvBundleIdentifier(value);
|
|
96
|
+
case "bundle_id":
|
|
97
|
+
return normalizeBundleIdentifier(value);
|
|
98
|
+
case "apple_podcast_id":
|
|
99
|
+
return normalizePattern(type, value, /^[1-9][0-9]*$/);
|
|
100
|
+
case "rss_url": {
|
|
101
|
+
if (typeof value !== "string") return rejected(type);
|
|
102
|
+
try {
|
|
103
|
+
const url = new URL(value.trim());
|
|
104
|
+
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || !isDomain(url.hostname))
|
|
105
|
+
return rejected(type);
|
|
106
|
+
return accepted(value, url.toString());
|
|
107
|
+
} catch {
|
|
108
|
+
return rejected(type);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
case "network_id":
|
|
112
|
+
case "venue_id":
|
|
113
|
+
case "screen_id":
|
|
114
|
+
case "openooh_venue_type":
|
|
115
|
+
case "spotify_collection_id":
|
|
116
|
+
case "podcast_guid":
|
|
117
|
+
case "station_id":
|
|
118
|
+
case "facility_id":
|
|
119
|
+
return normalizePattern(type, value, /^[^\x00-\x1f\x7f]+$/);
|
|
120
|
+
default:
|
|
121
|
+
return rejected(type, "unsupported_identifier_type");
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const validatePropertyIdentifier = normalizePropertyIdentifier;
|
|
125
|
+
const validateDomainIdentifier = normalizeDomainIdentifier;
|
|
126
|
+
const validateSubdomainIdentifier = normalizeSubdomainIdentifier;
|
|
127
|
+
const validateIosBundleIdentifier = normalizeIosBundleIdentifier;
|
|
128
|
+
const validateAndroidPackageIdentifier = normalizeAndroidPackageIdentifier;
|
|
129
|
+
const validateAppleAppStoreIdentifier = normalizeAppleAppStoreIdentifier;
|
|
130
|
+
const validateGooglePlayIdentifier = normalizeGooglePlayIdentifier;
|
|
131
|
+
const validateRokuStoreIdentifier = normalizeRokuStoreIdentifier;
|
|
132
|
+
const validateFireTvAsinIdentifier = normalizeFireTvAsinIdentifier;
|
|
133
|
+
const validateSamsungAppIdentifier = normalizeSamsungAppIdentifier;
|
|
134
|
+
const validateAppleTvBundleIdentifier = normalizeAppleTvBundleIdentifier;
|
|
135
|
+
const validateBundleIdentifier = normalizeBundleIdentifier;
|
|
136
|
+
export {
|
|
137
|
+
IdentifierValidationError,
|
|
138
|
+
normalizeAndroidPackageIdentifier,
|
|
139
|
+
normalizeAppleAppStoreIdentifier,
|
|
140
|
+
normalizeAppleTvBundleIdentifier,
|
|
141
|
+
normalizeBundleIdentifier,
|
|
142
|
+
normalizeDomainIdentifier,
|
|
143
|
+
normalizeFireTvAsinIdentifier,
|
|
144
|
+
normalizeGooglePlayIdentifier,
|
|
145
|
+
normalizeIosBundleIdentifier,
|
|
146
|
+
normalizePropertyIdentifier,
|
|
147
|
+
normalizeRokuStoreIdentifier,
|
|
148
|
+
normalizeSamsungAppIdentifier,
|
|
149
|
+
normalizeSubdomainIdentifier,
|
|
150
|
+
validateAndroidPackageIdentifier,
|
|
151
|
+
validateAppleAppStoreIdentifier,
|
|
152
|
+
validateAppleTvBundleIdentifier,
|
|
153
|
+
validateBundleIdentifier,
|
|
154
|
+
validateDomainIdentifier,
|
|
155
|
+
validateFireTvAsinIdentifier,
|
|
156
|
+
validateGooglePlayIdentifier,
|
|
157
|
+
validateIosBundleIdentifier,
|
|
158
|
+
validatePropertyIdentifier,
|
|
159
|
+
validatePublisherDomain,
|
|
160
|
+
validateRokuStoreIdentifier,
|
|
161
|
+
validateSamsungAppIdentifier,
|
|
162
|
+
validateSubdomainIdentifier
|
|
163
|
+
};
|
package/dist/lib/index.d.mts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export * from './identifiers.mjs';
|
|
2
|
+
export type { ResolveIdentifiersAllOptions, ResolveIdentifierOutcome } from './registry/index.mjs';
|
|
1
3
|
export { RegistryClient, RegistryRequestError, isRegistryRequestError, RegistrySync, PropertyRegistry, InMemoryCursorStore, FileCursorStore, buildCommunityMirrorAdagents, } from './registry/index.mjs';
|
|
2
4
|
export type { RegistrySyncConfig, RegistrySyncState, RegistrySyncTransport, RegistrySyncEvents, AgentFilter, RegistrySyncProperty, CursorStore, PropertyRegistryConfig, FeedStreamQuery, FeedStreamMessage, FeedHeartbeat, FeedStreamErrorData, OpenFeedStreamOptions, FeedFreshness, } from './registry/index.mjs';
|
|
3
5
|
export { openFeedStream, parseSseStream, sanitizeStreamText, DEFAULT_MAX_SSE_FRAME_BYTES, FeedStreamError, FeedStreamUnsupportedError, FeedStreamCursorExpiredError, FeedStreamHttpError, FeedStreamParseError, } from './registry/index.mjs';
|
|
@@ -57,7 +59,7 @@ export { MemoryStorage, createMemoryStorage, createMemoryStorageConfig } from '.
|
|
|
57
59
|
export { ADCPError, TaskTimeoutError, MaxClarificationError, DeferredTaskError, TaskAbortedError, AgentNotFoundError, UnsupportedTaskError, ProtocolError, ValidationError as ADCPValidationError, // Rename to avoid conflict
|
|
58
60
|
MissingInputHandlerError, InvalidContextError, ConfigurationError, AuthenticationCredentialsRejectedError, AuthenticationRequiredError, FeatureUnsupportedError, ProtocolFeatureUnsupportedError, UnsupportedBuyingModeError, AccountRequiredError, AccountPendingApprovalError, AccountAmbiguousError, BuyerSetupError, AccountNotFoundError, AccountSetupRequiredError, AccountPaymentRequiredError, AccountNotProvisionedError, SDK_ERROR_TO_PROTOCOL_ERROR_CODE, VersionUnsupportedError, IdempotencyConflictError, IdempotencyExpiredError, ResponseTooLargeError, ActionNotAllowedError, adcpErrorToTypedError, getClientPreflightAdcpError, isADCPError, isErrorOfType, extractErrorInfo, is401Error, mapSdkErrorCodeToProtocolErrorCode, } from './errors/index.mjs';
|
|
59
61
|
export type { OAuthMetadataInfo, ClientPreflightAdcpErrorInfo, ClientPreflightAdcpErrorRecovery, FeatureUnsupportedErrorOptions, ProtocolFeatureUnsupportedErrorOptions, ActionNotAllowedErrorDetails, ActionNotAllowedReasonValue, ActionNotAllowedAttemptedAction, ActionNotAllowedAvailableAction, ActionNotAllowedRecovery, } from './errors/index.mjs';
|
|
60
|
-
export type { ActionNotAllowedDetails, ActionNotAllowedReason, AvailableActionsResult, AvailableActionsSource, DecomposedUpdateMediaBuy, DecomposedUpdateMediaBuyMutation, LegacyCoarseAction, MediaBuyActionContext, MediaBuyActionId, MediaBuyActionMode, MediaBuyAvailableAction, MediaBuyMutationDirection, MediaBuyMutationScope, MediaBuyUpdateFieldAction, MediaBuyValidAction, ModeMismatchRecovery, PreflightAllowed, PreflightDenial, PreflightDenied, BuyerPropertyPolicy, NormalizedPolicyDomain, ProductPolicyProductLike, ProductPropertyPolicyDiagnostic, ProductPropertyPolicyDiagnosticCode, ProductPropertyPolicyDiagnosticSeverity, ProductPropertyPolicyMode, ProductPropertyPolicySelectorBehavior, ProductPropertyPolicyValidationResult, PreflightResult, ResolvedAction, SLAWindow, SlaWindow, StructuredOnlyMediaBuyAction, ResolvedTargetingInput, TargetingInputFor, ValidateProductsAgainstPropertyPolicyOptions, UpdateFieldEntry, UpdateMediaBuyRequestLike, } from './media-buy/index.mjs';
|
|
62
|
+
export type { ActionNotAllowedDetails, ActionNotAllowedReason, AvailableActionsResult, AvailableActionsSource, DecomposedUpdateMediaBuy, DecomposedUpdateMediaBuyMutation, LegacyCoarseAction, MediaBuyActionContext, MediaBuyActionId, MediaBuyActionMode, MediaBuyAvailableAction, MediaBuyMutationDirection, MediaBuyMutationScope, MediaBuyUpdateFieldAction, MediaBuyValidAction, ModeMismatchRecovery, PreflightAllowed, PreflightDenial, PreflightDenied, BuyerPropertyPolicy, NormalizedPolicyDomain, ProductPolicyProductLike, ProductPolicyResolvedProperty, ProductPropertyPolicyIdentifier, ProductPropertyPolicyDiagnostic, ProductPropertyPolicyDiagnosticCode, ProductPropertyPolicyDiagnosticSeverity, ProductPropertyPolicyMode, ProductPropertyPolicySelectorBehavior, ProductPropertyPolicyValidationResult, PreflightResult, ResolvedAction, SLAWindow, SlaWindow, StructuredOnlyMediaBuyAction, ResolvedTargetingInput, TargetingInputFor, ValidateProductsAgainstPropertyPolicyOptions, UpdateFieldEntry, UpdateMediaBuyRequestLike, } from './media-buy/index.mjs';
|
|
61
63
|
export { ACTIONS_BY_FIELD, LEGACY_COARSE_ACTIONS, STRUCTURED_ONLY_MEDIA_BUY_ACTIONS, UPDATE_FIELDS_BY_ACTION, applyTargetingInput, hasTargetingClears, resolveTargetingInput, canAddPackages, canCancel, canDecreaseBudget, canExtendFlight, canIncreaseBudget, canPause, canReallocateBudget, canRemoveCreative, canRemovePackages, canReplaceCreative, canResume, canShortenFlight, canUpdateCreativeAssignments, canUpdateFlightDates, canUpdateFrequencyCaps, canUpdatePacing, canUpdateTargeting, decomposeUpdateMediaBuy, findAvailableAction, getActionForMutation, getAvailableActions, getRollupParent, ProductPropertyPolicyError, normalizeDomainForPropertyPolicy, preflightUpdateMediaBuy, recoveryForModeMismatch, validateProductsAgainstPropertyPolicy, } from './media-buy/index.mjs';
|
|
62
64
|
export { InputRequiredError } from './core/TaskExecutor.mjs';
|
|
63
65
|
export { generateIdempotencyKey, isMutatingTask, requestUsesIdempotency, isValidIdempotencyKey, useIdempotencyKey, redactIdempotencyKey, IDEMPOTENCY_KEY_PATTERN, MUTATING_TASKS, } from './utils/idempotency.mjs';
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export * from './identifiers';
|
|
2
|
+
export type { ResolveIdentifiersAllOptions, ResolveIdentifierOutcome } from './registry';
|
|
1
3
|
export { RegistryClient, RegistryRequestError, isRegistryRequestError, RegistrySync, PropertyRegistry, InMemoryCursorStore, FileCursorStore, buildCommunityMirrorAdagents, } from './registry';
|
|
2
4
|
export type { RegistrySyncConfig, RegistrySyncState, RegistrySyncTransport, RegistrySyncEvents, AgentFilter, RegistrySyncProperty, CursorStore, PropertyRegistryConfig, FeedStreamQuery, FeedStreamMessage, FeedHeartbeat, FeedStreamErrorData, OpenFeedStreamOptions, FeedFreshness, } from './registry';
|
|
3
5
|
export { openFeedStream, parseSseStream, sanitizeStreamText, DEFAULT_MAX_SSE_FRAME_BYTES, FeedStreamError, FeedStreamUnsupportedError, FeedStreamCursorExpiredError, FeedStreamHttpError, FeedStreamParseError, } from './registry';
|
|
@@ -57,7 +59,7 @@ export { MemoryStorage, createMemoryStorage, createMemoryStorageConfig } from '.
|
|
|
57
59
|
export { ADCPError, TaskTimeoutError, MaxClarificationError, DeferredTaskError, TaskAbortedError, AgentNotFoundError, UnsupportedTaskError, ProtocolError, ValidationError as ADCPValidationError, // Rename to avoid conflict
|
|
58
60
|
MissingInputHandlerError, InvalidContextError, ConfigurationError, AuthenticationCredentialsRejectedError, AuthenticationRequiredError, FeatureUnsupportedError, ProtocolFeatureUnsupportedError, UnsupportedBuyingModeError, AccountRequiredError, AccountPendingApprovalError, AccountAmbiguousError, BuyerSetupError, AccountNotFoundError, AccountSetupRequiredError, AccountPaymentRequiredError, AccountNotProvisionedError, SDK_ERROR_TO_PROTOCOL_ERROR_CODE, VersionUnsupportedError, IdempotencyConflictError, IdempotencyExpiredError, ResponseTooLargeError, ActionNotAllowedError, adcpErrorToTypedError, getClientPreflightAdcpError, isADCPError, isErrorOfType, extractErrorInfo, is401Error, mapSdkErrorCodeToProtocolErrorCode, } from './errors';
|
|
59
61
|
export type { OAuthMetadataInfo, ClientPreflightAdcpErrorInfo, ClientPreflightAdcpErrorRecovery, FeatureUnsupportedErrorOptions, ProtocolFeatureUnsupportedErrorOptions, ActionNotAllowedErrorDetails, ActionNotAllowedReasonValue, ActionNotAllowedAttemptedAction, ActionNotAllowedAvailableAction, ActionNotAllowedRecovery, } from './errors';
|
|
60
|
-
export type { ActionNotAllowedDetails, ActionNotAllowedReason, AvailableActionsResult, AvailableActionsSource, DecomposedUpdateMediaBuy, DecomposedUpdateMediaBuyMutation, LegacyCoarseAction, MediaBuyActionContext, MediaBuyActionId, MediaBuyActionMode, MediaBuyAvailableAction, MediaBuyMutationDirection, MediaBuyMutationScope, MediaBuyUpdateFieldAction, MediaBuyValidAction, ModeMismatchRecovery, PreflightAllowed, PreflightDenial, PreflightDenied, BuyerPropertyPolicy, NormalizedPolicyDomain, ProductPolicyProductLike, ProductPropertyPolicyDiagnostic, ProductPropertyPolicyDiagnosticCode, ProductPropertyPolicyDiagnosticSeverity, ProductPropertyPolicyMode, ProductPropertyPolicySelectorBehavior, ProductPropertyPolicyValidationResult, PreflightResult, ResolvedAction, SLAWindow, SlaWindow, StructuredOnlyMediaBuyAction, ResolvedTargetingInput, TargetingInputFor, ValidateProductsAgainstPropertyPolicyOptions, UpdateFieldEntry, UpdateMediaBuyRequestLike, } from './media-buy';
|
|
62
|
+
export type { ActionNotAllowedDetails, ActionNotAllowedReason, AvailableActionsResult, AvailableActionsSource, DecomposedUpdateMediaBuy, DecomposedUpdateMediaBuyMutation, LegacyCoarseAction, MediaBuyActionContext, MediaBuyActionId, MediaBuyActionMode, MediaBuyAvailableAction, MediaBuyMutationDirection, MediaBuyMutationScope, MediaBuyUpdateFieldAction, MediaBuyValidAction, ModeMismatchRecovery, PreflightAllowed, PreflightDenial, PreflightDenied, BuyerPropertyPolicy, NormalizedPolicyDomain, ProductPolicyProductLike, ProductPolicyResolvedProperty, ProductPropertyPolicyIdentifier, ProductPropertyPolicyDiagnostic, ProductPropertyPolicyDiagnosticCode, ProductPropertyPolicyDiagnosticSeverity, ProductPropertyPolicyMode, ProductPropertyPolicySelectorBehavior, ProductPropertyPolicyValidationResult, PreflightResult, ResolvedAction, SLAWindow, SlaWindow, StructuredOnlyMediaBuyAction, ResolvedTargetingInput, TargetingInputFor, ValidateProductsAgainstPropertyPolicyOptions, UpdateFieldEntry, UpdateMediaBuyRequestLike, } from './media-buy';
|
|
61
63
|
export { ACTIONS_BY_FIELD, LEGACY_COARSE_ACTIONS, STRUCTURED_ONLY_MEDIA_BUY_ACTIONS, UPDATE_FIELDS_BY_ACTION, applyTargetingInput, hasTargetingClears, resolveTargetingInput, canAddPackages, canCancel, canDecreaseBudget, canExtendFlight, canIncreaseBudget, canPause, canReallocateBudget, canRemoveCreative, canRemovePackages, canReplaceCreative, canResume, canShortenFlight, canUpdateCreativeAssignments, canUpdateFlightDates, canUpdateFrequencyCaps, canUpdatePacing, canUpdateTargeting, decomposeUpdateMediaBuy, findAvailableAction, getActionForMutation, getAvailableActions, getRollupParent, ProductPropertyPolicyError, normalizeDomainForPropertyPolicy, preflightUpdateMediaBuy, recoveryForModeMismatch, validateProductsAgainstPropertyPolicy, } from './media-buy';
|
|
62
64
|
export { InputRequiredError } from './core/TaskExecutor';
|
|
63
65
|
export { generateIdempotencyKey, isMutatingTask, requestUsesIdempotency, isValidIdempotencyKey, useIdempotencyKey, redactIdempotencyKey, IDEMPOTENCY_KEY_PATTERN, MUTATING_TASKS, } from './utils/idempotency';
|
package/dist/lib/index.js
CHANGED
|
@@ -735,6 +735,7 @@ __export(index_exports, {
|
|
|
735
735
|
withSpan: () => import_observability.withSpan
|
|
736
736
|
});
|
|
737
737
|
module.exports = __toCommonJS(index_exports);
|
|
738
|
+
__reExport(index_exports, require('./identifiers.js'), module.exports);
|
|
738
739
|
var import_registry = require('./registry/index.js');
|
|
739
740
|
var import_registry2 = require('./registry/index.js');
|
|
740
741
|
var import_brand = require('./brand/index.js');
|
|
@@ -1583,6 +1584,7 @@ function createAdCPClientFromEnv() {
|
|
|
1583
1584
|
withAdditiveCanonicalFormatOptions,
|
|
1584
1585
|
withMCPConnectionScope,
|
|
1585
1586
|
withSpan,
|
|
1587
|
+
...require('./identifiers.js'),
|
|
1586
1588
|
...require('./principal/index.js'),
|
|
1587
1589
|
...require('./handlers/types.js'),
|
|
1588
1590
|
...require('./negotiation/index.js'),
|
package/dist/lib/index.mjs
CHANGED
|
@@ -4,7 +4,7 @@ export { LEGACY_COARSE_ACTIONS } from './types.mjs';
|
|
|
4
4
|
export type { LiveMediaBuyAction } from './action-types.mjs';
|
|
5
5
|
export type { AvailableActionsResult, AvailableActionsSource } from './available-actions.mjs';
|
|
6
6
|
export { findAvailableAction, getAvailableActions, getRollupParent, __resetValidActionsWarningForTests, } from './available-actions.mjs';
|
|
7
|
-
export type { BuyerPropertyPolicy, NormalizedPolicyDomain, ProductPolicyProductLike, ProductPropertyPolicyDiagnostic, ProductPropertyPolicyDiagnosticCode, ProductPropertyPolicyDiagnosticSeverity, ProductPropertyPolicyMode, ProductPropertyPolicySelectorBehavior, ProductPropertyPolicyValidationResult, ValidateProductsAgainstPropertyPolicyOptions, } from './property-policy.mjs';
|
|
7
|
+
export type { BuyerPropertyPolicy, NormalizedPolicyDomain, ProductPolicyProductLike, ProductPolicyResolvedProperty, ProductPropertyPolicyIdentifier, ProductPropertyPolicyDiagnostic, ProductPropertyPolicyDiagnosticCode, ProductPropertyPolicyDiagnosticSeverity, ProductPropertyPolicyMode, ProductPropertyPolicySelectorBehavior, ProductPropertyPolicyValidationResult, ValidateProductsAgainstPropertyPolicyOptions, } from './property-policy.mjs';
|
|
8
8
|
export { ProductPropertyPolicyError, normalizeDomainForPropertyPolicy, validateProductsAgainstPropertyPolicy, } from './property-policy.mjs';
|
|
9
9
|
export type { DecomposedUpdateMediaBuy, DecomposedUpdateMediaBuyMutation, MediaBuyMutationDirection, MediaBuyMutationScope, ModeMismatchRecovery, PreflightAllowed, PreflightDenial, PreflightDenied, PreflightResult, ResolvedAction, } from './preflight.mjs';
|
|
10
10
|
export { canAddPackages, canCancel, canDecreaseBudget, canExtendFlight, canIncreaseBudget, canPause, canReallocateBudget, canRemoveCreative, canRemovePackages, canReplaceCreative, canResume, canShortenFlight, canUpdateCreativeAssignments, canUpdateFlightDates, canUpdateFrequencyCaps, canUpdatePacing, canUpdateTargeting, decomposeUpdateMediaBuy, getActionForMutation, preflightUpdateMediaBuy, recoveryForModeMismatch, } from './preflight.mjs';
|
|
@@ -4,7 +4,7 @@ export { LEGACY_COARSE_ACTIONS } from './types';
|
|
|
4
4
|
export type { LiveMediaBuyAction } from './action-types';
|
|
5
5
|
export type { AvailableActionsResult, AvailableActionsSource } from './available-actions';
|
|
6
6
|
export { findAvailableAction, getAvailableActions, getRollupParent, __resetValidActionsWarningForTests, } from './available-actions';
|
|
7
|
-
export type { BuyerPropertyPolicy, NormalizedPolicyDomain, ProductPolicyProductLike, ProductPropertyPolicyDiagnostic, ProductPropertyPolicyDiagnosticCode, ProductPropertyPolicyDiagnosticSeverity, ProductPropertyPolicyMode, ProductPropertyPolicySelectorBehavior, ProductPropertyPolicyValidationResult, ValidateProductsAgainstPropertyPolicyOptions, } from './property-policy';
|
|
7
|
+
export type { BuyerPropertyPolicy, NormalizedPolicyDomain, ProductPolicyProductLike, ProductPolicyResolvedProperty, ProductPropertyPolicyIdentifier, ProductPropertyPolicyDiagnostic, ProductPropertyPolicyDiagnosticCode, ProductPropertyPolicyDiagnosticSeverity, ProductPropertyPolicyMode, ProductPropertyPolicySelectorBehavior, ProductPropertyPolicyValidationResult, ValidateProductsAgainstPropertyPolicyOptions, } from './property-policy';
|
|
8
8
|
export { ProductPropertyPolicyError, normalizeDomainForPropertyPolicy, validateProductsAgainstPropertyPolicy, } from './property-policy';
|
|
9
9
|
export type { DecomposedUpdateMediaBuy, DecomposedUpdateMediaBuyMutation, MediaBuyMutationDirection, MediaBuyMutationScope, ModeMismatchRecovery, PreflightAllowed, PreflightDenial, PreflightDenied, PreflightResult, ResolvedAction, } from './preflight';
|
|
10
10
|
export { canAddPackages, canCancel, canDecreaseBudget, canExtendFlight, canIncreaseBudget, canPause, canReallocateBudget, canRemoveCreative, canRemovePackages, canReplaceCreative, canResume, canShortenFlight, canUpdateCreativeAssignments, canUpdateFlightDates, canUpdateFrequencyCaps, canUpdatePacing, canUpdateTargeting, decomposeUpdateMediaBuy, getActionForMutation, preflightUpdateMediaBuy, recoveryForModeMismatch, } from './preflight';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export declare function isSupportedPropertyIdentifierType(type: string): boolean;
|
|
1
2
|
export type ProductPropertyPolicyMode = 'audit' | 'filter' | 'reject_response';
|
|
2
3
|
export type ProductPropertyPolicySelectorBehavior = 'allow' | 'flag' | 'reject';
|
|
3
4
|
export interface BuyerPropertyPolicy {
|
|
@@ -10,6 +11,13 @@ export interface BuyerPropertyPolicy {
|
|
|
10
11
|
* `*.example.com` matches subdomains only).
|
|
11
12
|
*/
|
|
12
13
|
allowedPropertyIdentifiers?: readonly ProductPropertyPolicyIdentifier[];
|
|
14
|
+
/**
|
|
15
|
+
* Complete publisher catalogs, keyed by canonical publisher domain. Enables
|
|
16
|
+
* app/CTV identifier matching for all/by_id/by_tag selectors. Omitted keys
|
|
17
|
+
* mean unresolved metadata; an empty array means a known empty catalog.
|
|
18
|
+
* Property IDs remain publisher-scoped and are never treated as app IDs.
|
|
19
|
+
*/
|
|
20
|
+
publisherProperties?: Readonly<Record<string, readonly ProductPolicyResolvedProperty[] | undefined>>;
|
|
13
21
|
/**
|
|
14
22
|
* Require products to match the allowed domain/identifier set even when that
|
|
15
23
|
* set is empty. Used when a request property_list resolves successfully to
|
|
@@ -56,7 +64,12 @@ export interface ProductPropertyPolicyIdentifier {
|
|
|
56
64
|
type: string;
|
|
57
65
|
value: string;
|
|
58
66
|
}
|
|
59
|
-
export
|
|
67
|
+
export interface ProductPolicyResolvedProperty {
|
|
68
|
+
property_id?: string;
|
|
69
|
+
identifiers: readonly ProductPropertyPolicyIdentifier[];
|
|
70
|
+
tags?: readonly string[];
|
|
71
|
+
}
|
|
72
|
+
export type ProductPropertyPolicyDiagnosticCode = 'outside_property_list' | 'excluded_domain' | 'excluded_property_id' | 'missing_publisher_properties' | 'unresolved_tag_selector' | 'unknown_selector' | 'malformed_publisher_domain' | 'unresolved_property_identifiers' | 'excluded_resolved_property';
|
|
60
73
|
export type ProductPropertyPolicyDiagnosticSeverity = 'rejected' | 'flagged';
|
|
61
74
|
export interface ProductPropertyPolicyDiagnostic {
|
|
62
75
|
code: ProductPropertyPolicyDiagnosticCode;
|
|
@@ -75,6 +88,7 @@ export interface ProductPropertyPolicyDiagnostic {
|
|
|
75
88
|
matched_excluded_domain?: string;
|
|
76
89
|
property_ids?: string[];
|
|
77
90
|
matched_property_ids?: string[];
|
|
91
|
+
identifier_types?: string[];
|
|
78
92
|
}
|
|
79
93
|
export interface ProductPropertyPolicyValidationResult<TProduct extends ProductPolicyProductLike> {
|
|
80
94
|
mode: ProductPropertyPolicyMode;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export declare function isSupportedPropertyIdentifierType(type: string): boolean;
|
|
1
2
|
export type ProductPropertyPolicyMode = 'audit' | 'filter' | 'reject_response';
|
|
2
3
|
export type ProductPropertyPolicySelectorBehavior = 'allow' | 'flag' | 'reject';
|
|
3
4
|
export interface BuyerPropertyPolicy {
|
|
@@ -10,6 +11,13 @@ export interface BuyerPropertyPolicy {
|
|
|
10
11
|
* `*.example.com` matches subdomains only).
|
|
11
12
|
*/
|
|
12
13
|
allowedPropertyIdentifiers?: readonly ProductPropertyPolicyIdentifier[];
|
|
14
|
+
/**
|
|
15
|
+
* Complete publisher catalogs, keyed by canonical publisher domain. Enables
|
|
16
|
+
* app/CTV identifier matching for all/by_id/by_tag selectors. Omitted keys
|
|
17
|
+
* mean unresolved metadata; an empty array means a known empty catalog.
|
|
18
|
+
* Property IDs remain publisher-scoped and are never treated as app IDs.
|
|
19
|
+
*/
|
|
20
|
+
publisherProperties?: Readonly<Record<string, readonly ProductPolicyResolvedProperty[] | undefined>>;
|
|
13
21
|
/**
|
|
14
22
|
* Require products to match the allowed domain/identifier set even when that
|
|
15
23
|
* set is empty. Used when a request property_list resolves successfully to
|
|
@@ -56,7 +64,12 @@ export interface ProductPropertyPolicyIdentifier {
|
|
|
56
64
|
type: string;
|
|
57
65
|
value: string;
|
|
58
66
|
}
|
|
59
|
-
export
|
|
67
|
+
export interface ProductPolicyResolvedProperty {
|
|
68
|
+
property_id?: string;
|
|
69
|
+
identifiers: readonly ProductPropertyPolicyIdentifier[];
|
|
70
|
+
tags?: readonly string[];
|
|
71
|
+
}
|
|
72
|
+
export type ProductPropertyPolicyDiagnosticCode = 'outside_property_list' | 'excluded_domain' | 'excluded_property_id' | 'missing_publisher_properties' | 'unresolved_tag_selector' | 'unknown_selector' | 'malformed_publisher_domain' | 'unresolved_property_identifiers' | 'excluded_resolved_property';
|
|
60
73
|
export type ProductPropertyPolicyDiagnosticSeverity = 'rejected' | 'flagged';
|
|
61
74
|
export interface ProductPropertyPolicyDiagnostic {
|
|
62
75
|
code: ProductPropertyPolicyDiagnosticCode;
|
|
@@ -75,6 +88,7 @@ export interface ProductPropertyPolicyDiagnostic {
|
|
|
75
88
|
matched_excluded_domain?: string;
|
|
76
89
|
property_ids?: string[];
|
|
77
90
|
matched_property_ids?: string[];
|
|
91
|
+
identifier_types?: string[];
|
|
78
92
|
}
|
|
79
93
|
export interface ProductPropertyPolicyValidationResult<TProduct extends ProductPolicyProductLike> {
|
|
80
94
|
mode: ProductPropertyPolicyMode;
|
|
@@ -19,10 +19,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
var property_policy_exports = {};
|
|
20
20
|
__export(property_policy_exports, {
|
|
21
21
|
ProductPropertyPolicyError: () => ProductPropertyPolicyError,
|
|
22
|
+
isSupportedPropertyIdentifierType: () => isSupportedPropertyIdentifierType,
|
|
22
23
|
normalizeDomainForPropertyPolicy: () => normalizeDomainForPropertyPolicy,
|
|
23
24
|
validateProductsAgainstPropertyPolicy: () => validateProductsAgainstPropertyPolicy
|
|
24
25
|
});
|
|
25
26
|
module.exports = __toCommonJS(property_policy_exports);
|
|
27
|
+
var import_enums = require('../types/enums.generated.js');
|
|
28
|
+
function isSupportedPropertyIdentifierType(type) {
|
|
29
|
+
return import_enums.PropertyIdentifierTypesValues.includes(type);
|
|
30
|
+
}
|
|
26
31
|
class ProductPropertyPolicyError extends Error {
|
|
27
32
|
constructor(result) {
|
|
28
33
|
super(
|
|
@@ -82,6 +87,8 @@ function compilePolicy(policy) {
|
|
|
82
87
|
}
|
|
83
88
|
return {
|
|
84
89
|
allowedDomains,
|
|
90
|
+
publisherCatalogsConfigured: policy.publisherProperties !== void 0,
|
|
91
|
+
publisherProperties: policy.publisherProperties ?? {},
|
|
85
92
|
allowedPropertyIdentifiers: [...policy.allowedPropertyIdentifiers ?? []],
|
|
86
93
|
requireAllowedPropertyMatch: policy.requireAllowedPropertyMatch ?? Boolean(policy.allowedDomains?.length || policy.allowedPropertyIdentifiers?.length),
|
|
87
94
|
excludedDomainsByComparable,
|
|
@@ -116,6 +123,18 @@ function diagnosticsForProduct(product, productIndex, policy) {
|
|
|
116
123
|
hasEligibleSubsetSelector = true;
|
|
117
124
|
}
|
|
118
125
|
});
|
|
126
|
+
if (requiresSubsetMatch) {
|
|
127
|
+
const scopes = publisherProperties.flatMap(
|
|
128
|
+
(selector) => selector && typeof selector === "object" && !Array.isArray(selector) ? [identifierScopeForSelector(selector, policy)] : []
|
|
129
|
+
);
|
|
130
|
+
if (scopes.some((scope) => scope?.hasNonMatch) && !scopes.some((scope) => scope?.hasMatch))
|
|
131
|
+
hasEligibleSubsetSelector = false;
|
|
132
|
+
}
|
|
133
|
+
if (requiresSubsetMatch && hasEligibleSubsetSelector) {
|
|
134
|
+
for (const diagnostic of diagnostics) {
|
|
135
|
+
if (diagnostic.code === "unresolved_property_identifiers") diagnostic.severity = "flagged";
|
|
136
|
+
}
|
|
137
|
+
}
|
|
119
138
|
if (requiresSubsetMatch && !hasEligibleSubsetSelector) {
|
|
120
139
|
diagnostics.push({
|
|
121
140
|
code: "outside_property_list",
|
|
@@ -141,6 +160,7 @@ function diagnosticsForSelector(rawSelector, productIndex, selectorIndex, produc
|
|
|
141
160
|
});
|
|
142
161
|
}
|
|
143
162
|
const selector = rawSelector;
|
|
163
|
+
const identifierScope = identifierScopeForSelector(selector, policy);
|
|
144
164
|
const selectionType = typeof selector.selection_type === "string" ? selector.selection_type : void 0;
|
|
145
165
|
const domainCandidates = publisherDomainCandidates(selector, path);
|
|
146
166
|
const normalizedDomains = domainCandidates.map((candidate) => ({ candidate, normalized: normalizeDomainForPropertyPolicy(candidate.raw) })).filter(
|
|
@@ -192,7 +212,27 @@ function diagnosticsForSelector(rawSelector, productIndex, selectorIndex, produc
|
|
|
192
212
|
}
|
|
193
213
|
for (const { candidate, normalized: normalizedDomain } of normalizedDomains) {
|
|
194
214
|
const matchedAllowedDomain = matchedAllowedDomainForCandidate(normalizedDomain, policy);
|
|
195
|
-
|
|
215
|
+
const needsCatalogForExclusions = policy.publisherCatalogsConfigured && (policy.excludedDomainsByComparable.size > 0 || selectionType !== "by_id" && policy.excludedPropertyIds.size > 0);
|
|
216
|
+
if ((hasAllowedPropertyScope(policy) || selectionType === "by_tag" || needsCatalogForExclusions) && identifierScope?.unknown) {
|
|
217
|
+
diagnostics.push(
|
|
218
|
+
...diagnosticForBehavior(policy.unknownSelectorBehavior, {
|
|
219
|
+
code: "unresolved_property_identifiers",
|
|
220
|
+
identifier_types: [
|
|
221
|
+
...new Set(
|
|
222
|
+
policy.allowedPropertyIdentifiers.filter((identifier) => identifier.type !== "domain" && identifier.type !== "subdomain").map((identifier) => identifier.type)
|
|
223
|
+
)
|
|
224
|
+
],
|
|
225
|
+
message: "Publisher property identifiers could not be resolved; property-list membership is unknown.",
|
|
226
|
+
product_index: productIndex,
|
|
227
|
+
product_id: productId,
|
|
228
|
+
path,
|
|
229
|
+
publisher_property_index: selectorIndex,
|
|
230
|
+
selection_type: selectionType,
|
|
231
|
+
publisher_domain: candidate.raw
|
|
232
|
+
})
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
if (options.enforceEveryDomainInAllowedScope && hasAllowedPropertyScope(policy) && (identifierScope ? identifierScope.hasNonMatch : !matchedAllowedDomain)) {
|
|
196
236
|
diagnostics.push({
|
|
197
237
|
code: "outside_property_list",
|
|
198
238
|
severity: "rejected",
|
|
@@ -227,6 +267,19 @@ function diagnosticsForSelector(rawSelector, productIndex, selectorIndex, produc
|
|
|
227
267
|
});
|
|
228
268
|
}
|
|
229
269
|
}
|
|
270
|
+
if (options.enforceExclusions && identifierScope?.hasExcludedProperty) {
|
|
271
|
+
diagnostics.push({
|
|
272
|
+
code: "excluded_resolved_property",
|
|
273
|
+
severity: "rejected",
|
|
274
|
+
message: "Resolved publisher properties include a buyer-excluded property.",
|
|
275
|
+
product_index: productIndex,
|
|
276
|
+
product_id: productId,
|
|
277
|
+
path,
|
|
278
|
+
publisher_property_index: selectorIndex,
|
|
279
|
+
selection_type: selectionType,
|
|
280
|
+
publisher_domain: domainCandidates[0]?.raw
|
|
281
|
+
});
|
|
282
|
+
}
|
|
230
283
|
if (selectionType === "by_id") {
|
|
231
284
|
const propertyIds = stringArray(selector.property_ids);
|
|
232
285
|
const matchedPropertyIds = propertyIds.filter((id) => policy.excludedPropertyIds.has(id));
|
|
@@ -248,7 +301,7 @@ function diagnosticsForSelector(rawSelector, productIndex, selectorIndex, produc
|
|
|
248
301
|
matched_property_ids: matchedPropertyIds
|
|
249
302
|
});
|
|
250
303
|
}
|
|
251
|
-
} else if (selectionType === "by_tag") {
|
|
304
|
+
} else if (selectionType === "by_tag" && !identifierScope) {
|
|
252
305
|
diagnostics.push(
|
|
253
306
|
...diagnosticForBehavior(policy.unknownSelectorBehavior, {
|
|
254
307
|
code: "unresolved_tag_selector",
|
|
@@ -264,7 +317,7 @@ function diagnosticsForSelector(rawSelector, productIndex, selectorIndex, produc
|
|
|
264
317
|
normalized_domains: normalizedDomains.map((entry) => entry.normalized.host)
|
|
265
318
|
})
|
|
266
319
|
);
|
|
267
|
-
} else if (selectionType !== "all") {
|
|
320
|
+
} else if (selectionType !== "all" && selectionType !== "by_tag") {
|
|
268
321
|
diagnostics.push(
|
|
269
322
|
...diagnosticForBehavior(policy.unknownSelectorBehavior, {
|
|
270
323
|
code: "unknown_selector",
|
|
@@ -291,6 +344,14 @@ function selectorIsEligibleForSubsetTargeting(rawSelector, productIndex, selecto
|
|
|
291
344
|
if (!rawSelector || typeof rawSelector !== "object" || Array.isArray(rawSelector)) return false;
|
|
292
345
|
const selector = rawSelector;
|
|
293
346
|
if (selector.publisher_domains !== void 0) return false;
|
|
347
|
+
const identifierScope = identifierScopeForSelector(selector, policy);
|
|
348
|
+
if (identifierScope) {
|
|
349
|
+
const domain = typeof selector.publisher_domain === "string" ? normalizeDomainForPropertyPolicy(selector.publisher_domain) : void 0;
|
|
350
|
+
if (!domain || policy.excludedDomainsByComparable.has(domain.comparable)) return false;
|
|
351
|
+
if (selector.selection_type !== "all" && selector.selection_type !== "by_id" && selector.selection_type !== "by_tag")
|
|
352
|
+
return false;
|
|
353
|
+
return identifierScope.hasMatch || identifierScope.unknown && !identifierScope.hasNonMatch && policy.unknownSelectorBehavior !== "reject";
|
|
354
|
+
}
|
|
294
355
|
if (selector.selection_type === "by_tag") return false;
|
|
295
356
|
if (selector.selection_type !== "all" && selector.selection_type !== "by_id") return false;
|
|
296
357
|
const hasEligibleDomain = publisherDomainCandidates(selector, path).some((candidate) => {
|
|
@@ -317,6 +378,76 @@ function matchedAllowedDomainForCandidate(candidate, policy) {
|
|
|
317
378
|
}
|
|
318
379
|
return void 0;
|
|
319
380
|
}
|
|
381
|
+
function identifierScopeForSelector(selector, policy) {
|
|
382
|
+
if (!policy.allowedPropertyIdentifiers.some((id) => id.type !== "domain" && id.type !== "subdomain") && !policy.publisherCatalogsConfigured)
|
|
383
|
+
return void 0;
|
|
384
|
+
const propertyIds = selector.selection_type === "by_id" ? stringArray(selector.property_ids) : [];
|
|
385
|
+
const hasExcludedId = propertyIds.some((id) => policy.excludedPropertyIds.has(id));
|
|
386
|
+
const allIdsExcluded = propertyIds.length > 0 && propertyIds.every((id) => policy.excludedPropertyIds.has(id));
|
|
387
|
+
if (allIdsExcluded) return { allMatch: false, hasMatch: false, hasNonMatch: true, unknown: false };
|
|
388
|
+
const domain = typeof selector.publisher_domain === "string" ? normalizeDomainForPropertyPolicy(selector.publisher_domain) : void 0;
|
|
389
|
+
if (!domain) return { allMatch: false, hasMatch: false, hasNonMatch: hasExcludedId, unknown: true };
|
|
390
|
+
if (policy.excludedDomainsByComparable.has(domain.comparable))
|
|
391
|
+
return { allMatch: false, hasMatch: false, hasNonMatch: true, unknown: false };
|
|
392
|
+
const properties = Object.hasOwn(policy.publisherProperties, domain.host) ? policy.publisherProperties[domain.host] : void 0;
|
|
393
|
+
if (!properties && policy.publisherCatalogsConfigured)
|
|
394
|
+
return { allMatch: false, hasMatch: false, hasNonMatch: hasExcludedId, unknown: true };
|
|
395
|
+
if (!properties) {
|
|
396
|
+
const matchedDomain = !allIdsExcluded && Boolean(matchedAllowedDomainForCandidate(domain, policy));
|
|
397
|
+
const unknown2 = !matchedDomain && !allIdsExcluded || selector.selection_type === "by_tag";
|
|
398
|
+
return {
|
|
399
|
+
allMatch: matchedDomain && !unknown2 && !hasExcludedId,
|
|
400
|
+
hasMatch: matchedDomain && !unknown2,
|
|
401
|
+
hasNonMatch: hasExcludedId,
|
|
402
|
+
unknown: unknown2
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
if (!Array.isArray(properties) || properties.some(
|
|
406
|
+
(property) => !property || typeof property !== "object" || !Array.isArray(property.identifiers) || property.identifiers.some(
|
|
407
|
+
(identifier) => !identifier || typeof identifier.type !== "string" || typeof identifier.value !== "string"
|
|
408
|
+
) || property.tags !== void 0 && (!Array.isArray(property.tags) || property.tags.some((tag) => typeof tag !== "string"))
|
|
409
|
+
)) {
|
|
410
|
+
return { allMatch: false, hasMatch: false, hasNonMatch: hasExcludedId, unknown: true };
|
|
411
|
+
}
|
|
412
|
+
let selected = [...properties];
|
|
413
|
+
let missingIds = false;
|
|
414
|
+
if (selector.selection_type === "by_id") {
|
|
415
|
+
const ids = stringArray(selector.property_ids);
|
|
416
|
+
missingIds = !ids.length || ids.some((id) => !properties.some((property) => property.property_id === id));
|
|
417
|
+
selected = selected.filter((property) => property.property_id && ids.includes(property.property_id));
|
|
418
|
+
} else if (selector.selection_type === "by_tag") {
|
|
419
|
+
const tags = stringArray(selector.property_tags);
|
|
420
|
+
if (!tags.length) return { allMatch: false, hasMatch: false, hasNonMatch: false, unknown: true };
|
|
421
|
+
selected = selected.filter((property) => property.tags?.some((tag) => tags.includes(tag)));
|
|
422
|
+
} else if (selector.selection_type !== "all") {
|
|
423
|
+
return { allMatch: false, hasMatch: false, hasNonMatch: false, unknown: true };
|
|
424
|
+
}
|
|
425
|
+
const excluded = selected.map(
|
|
426
|
+
(property) => policy.excludedPropertyIds.has(property.property_id ?? "") || property.identifiers.some(
|
|
427
|
+
(identifier) => (identifier.type === "domain" || identifier.type === "subdomain") && policy.excludedDomainsByComparable.has(normalizeDomainForPropertyPolicy(identifier.value)?.comparable ?? "")
|
|
428
|
+
)
|
|
429
|
+
);
|
|
430
|
+
const matches = selected.map(
|
|
431
|
+
(property, index) => !excluded[index] && (!hasAllowedPropertyScope(policy) || property.identifiers.some(
|
|
432
|
+
(candidate) => policy.allowedPropertyIdentifiers.some(
|
|
433
|
+
(allowed) => allowed.type === "domain" || allowed.type === "subdomain" ? (candidate.type === "domain" || candidate.type === "subdomain") && propertyListDomainMatches(candidate.value, allowed.value, allowed.type) : isSupportedPropertyIdentifierType(allowed.type) && candidate.type === allowed.type && candidate.value === allowed.value
|
|
434
|
+
) || (candidate.type === "domain" || candidate.type === "subdomain") && policy.allowedDomains.some((allowed) => propertyListDomainMatches(candidate.value, allowed.input))
|
|
435
|
+
))
|
|
436
|
+
);
|
|
437
|
+
const undecidable = selected.map(
|
|
438
|
+
(property, index) => !excluded[index] && (property.identifiers.length === 0 || property.identifiers.some(
|
|
439
|
+
(candidate) => !isSupportedPropertyIdentifierType(candidate.type) && policy.allowedPropertyIdentifiers.some((allowed) => allowed.type === candidate.type)
|
|
440
|
+
))
|
|
441
|
+
);
|
|
442
|
+
const unknown = matches.some((match, index) => !match && undecidable[index]);
|
|
443
|
+
return {
|
|
444
|
+
allMatch: matches.length > 0 && matches.every(Boolean) && !unknown,
|
|
445
|
+
hasMatch: matches.some(Boolean),
|
|
446
|
+
hasNonMatch: missingIds || !selected.length || matches.some((match, index) => !match && !undecidable[index]),
|
|
447
|
+
hasExcludedProperty: excluded.some(Boolean),
|
|
448
|
+
unknown
|
|
449
|
+
};
|
|
450
|
+
}
|
|
320
451
|
function publisherDomainCandidates(selector, path) {
|
|
321
452
|
const candidates = [];
|
|
322
453
|
if (typeof selector.publisher_domain === "string") {
|
|
@@ -382,6 +513,7 @@ function isUsableHostname(host) {
|
|
|
382
513
|
// Annotate the CommonJS export names for ESM import in node:
|
|
383
514
|
0 && (module.exports = {
|
|
384
515
|
ProductPropertyPolicyError,
|
|
516
|
+
isSupportedPropertyIdentifierType,
|
|
385
517
|
normalizeDomainForPropertyPolicy,
|
|
386
518
|
validateProductsAgainstPropertyPolicy
|
|
387
519
|
});
|