@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.
Files changed (75) hide show
  1. package/README.md +17 -0
  2. package/dist/lib/conformance/index.d.mts +2 -0
  3. package/dist/lib/conformance/index.d.ts +2 -0
  4. package/dist/lib/conformance/index.js +3 -0
  5. package/dist/lib/conformance/index.mjs +2 -0
  6. package/dist/lib/conformance/property-lists.d.mts +14 -0
  7. package/dist/lib/conformance/property-lists.d.ts +14 -0
  8. package/dist/lib/conformance/property-lists.js +45 -0
  9. package/dist/lib/conformance/property-lists.mjs +21 -0
  10. package/dist/lib/conformance/runConformance.js +20 -1
  11. package/dist/lib/conformance/runConformance.mjs +20 -1
  12. package/dist/lib/conformance/types.d.mts +3 -0
  13. package/dist/lib/conformance/types.d.ts +3 -0
  14. package/dist/lib/core/SingleAgentClient.d.mts +13 -3
  15. package/dist/lib/core/SingleAgentClient.d.ts +13 -3
  16. package/dist/lib/core/SingleAgentClient.js +109 -21
  17. package/dist/lib/core/SingleAgentClient.mjs +112 -22
  18. package/dist/lib/identifiers.d.mts +53 -0
  19. package/dist/lib/identifiers.d.ts +53 -0
  20. package/dist/lib/identifiers.js +212 -0
  21. package/dist/lib/identifiers.mjs +163 -0
  22. package/dist/lib/index.d.mts +3 -1
  23. package/dist/lib/index.d.ts +3 -1
  24. package/dist/lib/index.js +2 -0
  25. package/dist/lib/index.mjs +1 -0
  26. package/dist/lib/media-buy/index.d.mts +1 -1
  27. package/dist/lib/media-buy/index.d.ts +1 -1
  28. package/dist/lib/media-buy/property-policy.d.mts +15 -1
  29. package/dist/lib/media-buy/property-policy.d.ts +15 -1
  30. package/dist/lib/media-buy/property-policy.js +135 -3
  31. package/dist/lib/media-buy/property-policy.mjs +134 -3
  32. package/dist/lib/registry/index.d.mts +12 -0
  33. package/dist/lib/registry/index.d.ts +12 -0
  34. package/dist/lib/registry/index.js +159 -5
  35. package/dist/lib/registry/index.mjs +156 -4
  36. package/dist/lib/registry/types.d.mts +23 -0
  37. package/dist/lib/registry/types.d.ts +23 -0
  38. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  39. package/dist/lib/server/decisioning/specialisms/lists.d.mts +4 -4
  40. package/dist/lib/server/decisioning/specialisms/lists.d.ts +4 -4
  41. package/dist/lib/server/index.d.mts +3 -0
  42. package/dist/lib/server/index.d.ts +3 -0
  43. package/dist/lib/server/index.js +8 -1
  44. package/dist/lib/server/index.mjs +4 -0
  45. package/dist/lib/server/property-lists.d.mts +36 -0
  46. package/dist/lib/server/property-lists.d.ts +36 -0
  47. package/dist/lib/server/property-lists.js +154 -0
  48. package/dist/lib/server/property-lists.mjs +129 -0
  49. package/dist/lib/server/targeting-helpers.d.mts +2 -0
  50. package/dist/lib/server/targeting-helpers.d.ts +2 -0
  51. package/dist/lib/server/targeting-helpers.js +28 -1
  52. package/dist/lib/server/targeting-helpers.mjs +18 -1
  53. package/dist/lib/signing/parser.js +2 -2
  54. package/dist/lib/signing/parser.mjs +2 -2
  55. package/dist/lib/signing/server.d.mts +1 -1
  56. package/dist/lib/signing/server.d.ts +1 -1
  57. package/dist/lib/signing/server.mjs +5 -1
  58. package/dist/lib/signing/webhook-verifier.d.mts +11 -0
  59. package/dist/lib/signing/webhook-verifier.d.ts +11 -0
  60. package/dist/lib/signing/webhook-verifier.js +11 -3
  61. package/dist/lib/signing/webhook-verifier.mjs +11 -3
  62. package/dist/lib/supply-path/verify.js +12 -2
  63. package/dist/lib/supply-path/verify.mjs +2 -2
  64. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  65. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  66. package/dist/lib/version.d.mts +3 -3
  67. package/dist/lib/version.d.ts +3 -3
  68. package/dist/lib/version.js +3 -3
  69. package/dist/lib/version.mjs +3 -3
  70. package/docs/TYPE-SUMMARY.md +2 -2
  71. package/docs/guides/PROPERTY-LISTS.md +264 -0
  72. package/docs/guides/SIGNING-GUIDE.md +25 -0
  73. package/docs/llms.txt +2 -2
  74. package/docs/migration-14.x-rc-worksheet.md +4 -4
  75. 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
+ };
@@ -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';
@@ -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'),
@@ -1,3 +1,4 @@
1
+ export * from "./identifiers.mjs";
1
2
  import {
2
3
  RegistryClient,
3
4
  RegistryRequestError,
@@ -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 type ProductPropertyPolicyDiagnosticCode = 'outside_property_list' | 'excluded_domain' | 'excluded_property_id' | 'missing_publisher_properties' | 'unresolved_tag_selector' | 'unknown_selector' | 'malformed_publisher_domain';
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 type ProductPropertyPolicyDiagnosticCode = 'outside_property_list' | 'excluded_domain' | 'excluded_property_id' | 'missing_publisher_properties' | 'unresolved_tag_selector' | 'unknown_selector' | 'malformed_publisher_domain';
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
- if (options.enforceEveryDomainInAllowedScope && hasAllowedPropertyScope(policy) && !matchedAllowedDomain) {
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
  });