@agentcentral/cli 0.1.0 → 0.1.2
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/dist/index.js +2808 -40
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -17,11 +17,12 @@ var CliError = class extends Error {
|
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
// src/constants.ts
|
|
20
|
-
var CLI_VERSION = "0.1.
|
|
20
|
+
var CLI_VERSION = "0.1.2";
|
|
21
21
|
var DEFAULT_MCP_ENDPOINT = "https://mcp.agentcentral.to/mcp";
|
|
22
22
|
var ENV_API_KEY = "AGENT_CENTRAL_API_KEY";
|
|
23
23
|
var ENV_API_KEY_LEGACY = "AGENTCENTRAL_API_KEY";
|
|
24
24
|
var ENV_ENDPOINT = "AGENT_CENTRAL_ENDPOINT";
|
|
25
|
+
var ENV_ALLOW_INSECURE = "AGENT_CENTRAL_ALLOW_INSECURE";
|
|
25
26
|
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
26
27
|
var USER_AGENT = "agentcentral-cli";
|
|
27
28
|
var DEFAULT_RETRY = {
|
|
@@ -32,7 +33,16 @@ var DEFAULT_RETRY = {
|
|
|
32
33
|
var API_KEY_PREFIX = "ac_live_";
|
|
33
34
|
|
|
34
35
|
// src/config.ts
|
|
35
|
-
import {
|
|
36
|
+
import {
|
|
37
|
+
chmodSync,
|
|
38
|
+
closeSync,
|
|
39
|
+
existsSync,
|
|
40
|
+
fstatSync,
|
|
41
|
+
mkdirSync,
|
|
42
|
+
openSync,
|
|
43
|
+
readFileSync,
|
|
44
|
+
writeFileSync
|
|
45
|
+
} from "fs";
|
|
36
46
|
import { homedir } from "os";
|
|
37
47
|
import { dirname, join } from "path";
|
|
38
48
|
import { z } from "zod";
|
|
@@ -60,16 +70,23 @@ function loadConfig(env = process.env) {
|
|
|
60
70
|
if (!existsSync(path)) {
|
|
61
71
|
return { profiles: [] };
|
|
62
72
|
}
|
|
63
|
-
const stat = statSync(path);
|
|
64
|
-
if (process.platform !== "win32" && (stat.mode & 63) !== 0) {
|
|
65
|
-
throw new CliError(
|
|
66
|
-
1 /* GeneralFailure */,
|
|
67
|
-
`config ${path} is group/world-accessible; run: chmod 600 ${path}`
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
73
|
let parsed;
|
|
74
|
+
let raw;
|
|
75
|
+
const fd = openSync(path, "r");
|
|
71
76
|
try {
|
|
72
|
-
|
|
77
|
+
const stat = fstatSync(fd);
|
|
78
|
+
if (process.platform !== "win32" && (stat.mode & 63) !== 0) {
|
|
79
|
+
throw new CliError(
|
|
80
|
+
1 /* GeneralFailure */,
|
|
81
|
+
`config ${path} is group/world-accessible; run: chmod 600 ${path}`
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
raw = readFileSync(fd, "utf8");
|
|
85
|
+
} finally {
|
|
86
|
+
closeSync(fd);
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
parsed = JSON.parse(raw);
|
|
73
90
|
} catch (error) {
|
|
74
91
|
throw new CliError(
|
|
75
92
|
1 /* GeneralFailure */,
|
|
@@ -116,15 +133,44 @@ function setActiveProfile(config, name) {
|
|
|
116
133
|
|
|
117
134
|
// src/auth.ts
|
|
118
135
|
function redactKey(key) {
|
|
119
|
-
const last4 = key.slice(-4);
|
|
120
136
|
if (key.startsWith(API_KEY_PREFIX)) {
|
|
121
|
-
|
|
137
|
+
const secret = key.slice(API_KEY_PREFIX.length);
|
|
138
|
+
if (secret.length < 8) {
|
|
139
|
+
return `${API_KEY_PREFIX}***`;
|
|
140
|
+
}
|
|
141
|
+
return `${API_KEY_PREFIX}***${secret.slice(-4)}`;
|
|
122
142
|
}
|
|
123
|
-
|
|
143
|
+
if (key.length < 8) {
|
|
144
|
+
return "***";
|
|
145
|
+
}
|
|
146
|
+
return `***${key.slice(-4)}`;
|
|
124
147
|
}
|
|
125
148
|
function looksLikeApiKey(key) {
|
|
126
149
|
return key.startsWith(API_KEY_PREFIX);
|
|
127
150
|
}
|
|
151
|
+
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1", "[::1]"]);
|
|
152
|
+
function assertSecureEndpoint(endpoint, env) {
|
|
153
|
+
let url;
|
|
154
|
+
try {
|
|
155
|
+
url = new URL(endpoint);
|
|
156
|
+
} catch {
|
|
157
|
+
throw new CliError(2 /* UsageError */, `invalid endpoint URL: ${endpoint}`);
|
|
158
|
+
}
|
|
159
|
+
if (url.protocol === "https:") {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const host = url.hostname.toLowerCase();
|
|
163
|
+
if (url.protocol === "http:" && LOOPBACK_HOSTS.has(host)) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (env[ENV_ALLOW_INSECURE] === "1") {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
throw new CliError(
|
|
170
|
+
2 /* UsageError */,
|
|
171
|
+
`refusing to send the API key over a non-https endpoint (${endpoint}); set ${ENV_ALLOW_INSECURE}=1 to override`
|
|
172
|
+
);
|
|
173
|
+
}
|
|
128
174
|
async function resolveKey(input) {
|
|
129
175
|
const { flags, env, config, readKeyFromStdin: readKeyFromStdin2 } = input;
|
|
130
176
|
if (flags.apiKeyStdin === true) {
|
|
@@ -188,6 +234,7 @@ async function resolveAuth(input) {
|
|
|
188
234
|
warn("API key does not start with ac_live_; continuing.");
|
|
189
235
|
}
|
|
190
236
|
const endpoint = resolution.profile?.endpoint ?? env[ENV_ENDPOINT] ?? DEFAULT_MCP_ENDPOINT;
|
|
237
|
+
assertSecureEndpoint(endpoint, env);
|
|
191
238
|
return {
|
|
192
239
|
apiKey,
|
|
193
240
|
endpoint,
|
|
@@ -345,7 +392,2663 @@ function createClient(auth, opts = {}) {
|
|
|
345
392
|
// src/commands/tools.ts
|
|
346
393
|
import { readFile, writeFile } from "fs/promises";
|
|
347
394
|
import { existsSync as existsSync2 } from "fs";
|
|
348
|
-
|
|
395
|
+
|
|
396
|
+
// ../shared/dist/index.js
|
|
397
|
+
import { z as z2 } from "zod";
|
|
398
|
+
import { z as z22 } from "zod";
|
|
399
|
+
import { z as z3 } from "zod";
|
|
400
|
+
import { z as z4 } from "zod";
|
|
401
|
+
var TABLES = {
|
|
402
|
+
// Ads API tables
|
|
403
|
+
campaigns: "amzn_ads_sp_campaigns_v3",
|
|
404
|
+
campaignSnapshots: "amzn_ads_sp_campaign_snapshots_v1",
|
|
405
|
+
adsChangeHistory: "amzn_ads_change_history_v1",
|
|
406
|
+
budgetUsage: "amzn_ads_sp_budget_usage_v1",
|
|
407
|
+
adgroups: "amzn_ads_sp_campaigns_by_adgroup_v2",
|
|
408
|
+
placements: "amzn_ads_sp_campaigns_by_placement_v3",
|
|
409
|
+
advertisedProducts: "amzn_ads_sp_advertised_products_v3",
|
|
410
|
+
purchasedProducts: "amzn_ads_sp_purchased_products_v3",
|
|
411
|
+
searchTerms: "amzn_ads_sp_search_terms_v2",
|
|
412
|
+
targeting: "amzn_ads_sp_targeting_v4",
|
|
413
|
+
profiles: "amzn_ads_profiles_v2",
|
|
414
|
+
sqp: "sqp_search_query_by_week",
|
|
415
|
+
brandMetrics: "amzn_ads_brand_metrics_v1",
|
|
416
|
+
attributionPerformance: "amzn_ads_attribution_performance_v1",
|
|
417
|
+
dspPerformance: "amzn_ads_dsp_performance_v1",
|
|
418
|
+
storeInsights: "amzn_ads_store_insights_v1",
|
|
419
|
+
sbCampaigns: "amzn_ads_sb_campaigns_v1",
|
|
420
|
+
sdCampaigns: "amzn_ads_sd_campaigns_v1",
|
|
421
|
+
sdAdvertisedProducts: "amzn_ads_sd_advertised_products_v1",
|
|
422
|
+
sdTargeting: "amzn_ads_sd_targeting_v1",
|
|
423
|
+
agentActions: "agent_actions",
|
|
424
|
+
writeSubmissions: "write_submissions",
|
|
425
|
+
// SP-API tables (shared across ads + inventory)
|
|
426
|
+
salesAndTraffic: "sp_sales_and_traffic_v1",
|
|
427
|
+
activeListings: "sp_active_listings_v1",
|
|
428
|
+
suppressedListings: "sp_suppressed_listings_v1",
|
|
429
|
+
settlements: "sp_settlements_v1",
|
|
430
|
+
// FBA inventory tables
|
|
431
|
+
fbaInventory: "sp_fba_inventory_summaries_v1",
|
|
432
|
+
inventoryHealth: "sp_fba_inventory_health_v1",
|
|
433
|
+
inventoryLedger: "sp_inventory_ledger_v1",
|
|
434
|
+
inventoryLedgerSummary: "sp_inventory_ledger_summary_v1",
|
|
435
|
+
// AWD tables
|
|
436
|
+
awdInventory: "awd_inventory_v1",
|
|
437
|
+
awdShipments: "awd_shipments_v1",
|
|
438
|
+
awdShipmentItems: "awd_shipment_items_v1",
|
|
439
|
+
// FBA Inbound tables
|
|
440
|
+
fbaInboundShipments: "sp_fba_inbound_shipments_v1",
|
|
441
|
+
fbaInboundShipmentItems: "sp_fba_inbound_shipment_items_v1",
|
|
442
|
+
// SP-API: Orders, returns, reimbursements, financial events, catalog
|
|
443
|
+
orders: "sp_orders_v1",
|
|
444
|
+
orderItems: "sp_order_items_v1",
|
|
445
|
+
returns: "sp_fba_returns_v1",
|
|
446
|
+
reimbursements: "sp_fba_reimbursements_v1",
|
|
447
|
+
financialEvents: "sp_financial_events_v1",
|
|
448
|
+
catalogItems: "sp_catalog_items_v1",
|
|
449
|
+
listingQuality: "sp_listing_quality_v1",
|
|
450
|
+
pricingSnapshots: "sp_pricing_v1",
|
|
451
|
+
replenishmentOffers: "sp_replenishment_offers_v1",
|
|
452
|
+
customerFeedbackSnapshots: "sp_customer_feedback_snapshots_v1",
|
|
453
|
+
// SP-API: Fees
|
|
454
|
+
referralFees: "sp_referral_fees_v1",
|
|
455
|
+
fbaStorageFeeCharges: "sp_fba_storage_fee_charges_v1",
|
|
456
|
+
fbaLongTermStorageFeeCharges: "sp_fba_longterm_storage_fee_charges_v1",
|
|
457
|
+
// Brand Analytics tables
|
|
458
|
+
baSearchTerms: "ba_search_terms_v1",
|
|
459
|
+
baMarketBasket: "ba_market_basket_v1",
|
|
460
|
+
baRepeatPurchase: "ba_repeat_purchase_v1",
|
|
461
|
+
baSearchCatalog: "ba_search_catalog_v1",
|
|
462
|
+
// SB (Sponsored Brands) ads tables
|
|
463
|
+
sbAds: "amzn_ads_sb_ads_v1",
|
|
464
|
+
sbSearchTerms: "amzn_ads_sb_search_terms_v1",
|
|
465
|
+
sbTargeting: "amzn_ads_sb_targeting_v1",
|
|
466
|
+
sbPurchasedProducts: "amzn_ads_sb_purchased_products_v1",
|
|
467
|
+
sbGrossAndInvalids: "amzn_ads_sb_gross_and_invalids_v1",
|
|
468
|
+
// SD (Sponsored Display) ads tables
|
|
469
|
+
sdPurchasedProducts: "amzn_ads_sd_purchased_products_v1",
|
|
470
|
+
sdGrossAndInvalids: "amzn_ads_sd_gross_and_invalids_v1",
|
|
471
|
+
// SP (Sponsored Products) gross & invalids
|
|
472
|
+
spGrossAndInvalids: "amzn_ads_sp_gross_and_invalids_v1",
|
|
473
|
+
// Infrastructure tables
|
|
474
|
+
tenants: "tenants",
|
|
475
|
+
agencies: "agencies",
|
|
476
|
+
appUsers: "app_users",
|
|
477
|
+
agencyMemberships: "agency_memberships",
|
|
478
|
+
tenantMemberships: "tenant_memberships",
|
|
479
|
+
tenantAdsProfiles: "tenant_ads_profiles",
|
|
480
|
+
tenantMarketplaceConnections: "tenant_marketplace_connections",
|
|
481
|
+
apiKeys: "api_keys",
|
|
482
|
+
apiUsageEvents: "api_usage_events",
|
|
483
|
+
signupAttribution: "signup_attribution",
|
|
484
|
+
adLifecycleEvents: "ad_lifecycle_events",
|
|
485
|
+
adConversionUploads: "ad_conversion_uploads",
|
|
486
|
+
landingVisits: "landing_visits",
|
|
487
|
+
alertEvents: "alert_events",
|
|
488
|
+
remediationActions: "remediation_actions",
|
|
489
|
+
emailEvents: "email_events",
|
|
490
|
+
emailVerificationTokens: "email_verification_tokens",
|
|
491
|
+
passwordResetTokens: "password_reset_tokens",
|
|
492
|
+
onboardingInvites: "onboarding_invites",
|
|
493
|
+
tenantDeletionTombstones: "tenant_deletion_tombstones",
|
|
494
|
+
ingestionMetadata: "sp_ingestion_metadata",
|
|
495
|
+
asinRegistry: "asin_registry",
|
|
496
|
+
syncRuns: "sync_runs",
|
|
497
|
+
syncLeases: "sync_leases",
|
|
498
|
+
paginationCheckpoints: "pagination_checkpoints",
|
|
499
|
+
tenantCapabilities: "tenant_capabilities",
|
|
500
|
+
bqUsageDaily: "bq_usage_daily",
|
|
501
|
+
workerUsageDaily: "worker_usage_daily",
|
|
502
|
+
pendingReports: "pending_reports",
|
|
503
|
+
reportJobs: "report_jobs",
|
|
504
|
+
shareableReports: "shareable_reports",
|
|
505
|
+
conversationFeedback: "conversation_feedback",
|
|
506
|
+
dataCoverage: "data_coverage",
|
|
507
|
+
sellerAccountMarketplaceRegistry: "seller_account_marketplace_registry",
|
|
508
|
+
sellerAccountBillingState: "seller_account_billing_state",
|
|
509
|
+
sellerAccountBillingMeasurements: "seller_account_billing_measurements",
|
|
510
|
+
sellerAccountBillingEvents: "seller_account_billing_events",
|
|
511
|
+
/** @deprecated Use sellerAccountBillingState. */
|
|
512
|
+
marketplaceBillingState: "seller_account_billing_state",
|
|
513
|
+
/** @deprecated Use sellerAccountBillingMeasurements. */
|
|
514
|
+
marketplaceBillingMeasurements: "seller_account_billing_measurements",
|
|
515
|
+
/** @deprecated Use sellerAccountBillingEvents. */
|
|
516
|
+
marketplaceBillingEvents: "seller_account_billing_events",
|
|
517
|
+
// Computed tables
|
|
518
|
+
seasonalityIndex: "seasonality_index_v1",
|
|
519
|
+
keywordRanks: "sp_keyword_ranks_v1",
|
|
520
|
+
// Sales metrics (aggregated)
|
|
521
|
+
orderMetrics: "sp_order_metrics_v1",
|
|
522
|
+
// Dashboard tables
|
|
523
|
+
asinCogs: "asin_cogs",
|
|
524
|
+
inventoryConfig: "inventory_config"
|
|
525
|
+
};
|
|
526
|
+
var SHARED_ONLY_TABLES = [
|
|
527
|
+
"agencies",
|
|
528
|
+
"agency_memberships",
|
|
529
|
+
"alert_events",
|
|
530
|
+
"amzn_ads_profiles_v2",
|
|
531
|
+
"app_users",
|
|
532
|
+
"remediation_actions",
|
|
533
|
+
"api_keys",
|
|
534
|
+
"api_usage_events",
|
|
535
|
+
"ad_lifecycle_events",
|
|
536
|
+
"ad_conversion_uploads",
|
|
537
|
+
"landing_visits",
|
|
538
|
+
"asin_registry",
|
|
539
|
+
"data_coverage",
|
|
540
|
+
"seller_account_marketplace_registry",
|
|
541
|
+
"seller_account_billing_state",
|
|
542
|
+
"seller_account_billing_measurements",
|
|
543
|
+
"seller_account_billing_events",
|
|
544
|
+
"email_events",
|
|
545
|
+
"email_verification_tokens",
|
|
546
|
+
"onboarding_invites",
|
|
547
|
+
"password_reset_tokens",
|
|
548
|
+
"pending_reports",
|
|
549
|
+
"report_jobs",
|
|
550
|
+
"shareable_reports",
|
|
551
|
+
"conversation_feedback",
|
|
552
|
+
"signup_attribution",
|
|
553
|
+
"sp_ingestion_metadata",
|
|
554
|
+
"sync_leases",
|
|
555
|
+
"sync_runs",
|
|
556
|
+
"pagination_checkpoints",
|
|
557
|
+
"tenant_capabilities",
|
|
558
|
+
"bq_usage_daily",
|
|
559
|
+
"worker_usage_daily",
|
|
560
|
+
"tenant_ads_profiles",
|
|
561
|
+
"tenant_marketplace_connections",
|
|
562
|
+
"tenant_deletion_tombstones",
|
|
563
|
+
"tenant_memberships",
|
|
564
|
+
"tenants"
|
|
565
|
+
];
|
|
566
|
+
var SHARED_ONLY_TABLE_SET = new Set(SHARED_ONLY_TABLES);
|
|
567
|
+
var METRIC_EXPRESSIONS = {
|
|
568
|
+
acos: "CASE WHEN COALESCE(SUM(sales14d), 0) = 0 THEN NULL ELSE ROUND(SAFE_DIVIDE(SUM(cost), SUM(sales14d)) * 100, 2) END",
|
|
569
|
+
roas: "CASE WHEN COALESCE(SUM(sales14d), 0) = 0 OR COALESCE(SUM(cost), 0) = 0 THEN NULL ELSE ROUND(SAFE_DIVIDE(SUM(sales14d), SUM(cost)), 2) END",
|
|
570
|
+
ctr: "ROUND(SAFE_DIVIDE(SUM(clicks), SUM(impressions)) * 100, 2)",
|
|
571
|
+
cpc: "ROUND(SAFE_DIVIDE(SUM(cost), SUM(clicks)), 2)",
|
|
572
|
+
cvr: "CASE WHEN COALESCE(SUM(purchases14d), 0) = 0 OR COALESCE(SUM(clicks), 0) = 0 THEN NULL ELSE ROUND(SAFE_DIVIDE(SUM(purchases14d), SUM(clicks)) * 100, 2) END"
|
|
573
|
+
};
|
|
574
|
+
var STANDARD_METRICS = `
|
|
575
|
+
SUM(impressions) AS impressions,
|
|
576
|
+
SUM(clicks) AS clicks,
|
|
577
|
+
ROUND(SUM(cost), 2) AS spend,
|
|
578
|
+
ROUND(SUM(sales14d), 2) AS sales,
|
|
579
|
+
SUM(purchases14d) AS orders,
|
|
580
|
+
SUM(units_sold_clicks14d) AS units_sold,
|
|
581
|
+
${METRIC_EXPRESSIONS.acos} AS acos,
|
|
582
|
+
${METRIC_EXPRESSIONS.roas} AS roas,
|
|
583
|
+
${METRIC_EXPRESSIONS.ctr} AS ctr,
|
|
584
|
+
${METRIC_EXPRESSIONS.cpc} AS cpc,
|
|
585
|
+
${METRIC_EXPRESSIONS.cvr} AS cvr`;
|
|
586
|
+
var DEFAULT_MARKETPLACE_ID = "ATVPDKIKX0DER";
|
|
587
|
+
var DEFAULT_REPORTING_TIME_ZONE = "America/Los_Angeles";
|
|
588
|
+
var SP_API_BASE_URLS = {
|
|
589
|
+
NA: "https://sellingpartnerapi-na.amazon.com",
|
|
590
|
+
EU: "https://sellingpartnerapi-eu.amazon.com",
|
|
591
|
+
FE: "https://sellingpartnerapi-fe.amazon.com"
|
|
592
|
+
};
|
|
593
|
+
var ADS_API_BASE_URLS = {
|
|
594
|
+
NA: "https://advertising-api.amazon.com",
|
|
595
|
+
EU: "https://advertising-api-eu.amazon.com",
|
|
596
|
+
FE: "https://advertising-api-fe.amazon.com"
|
|
597
|
+
};
|
|
598
|
+
var ENABLED_ROLLOUT = {
|
|
599
|
+
rolloutStatus: "enabled",
|
|
600
|
+
phase1Enabled: true,
|
|
601
|
+
oauthConnectEnabled: true
|
|
602
|
+
};
|
|
603
|
+
var MARKETPLACE_DEFINITIONS = [
|
|
604
|
+
{
|
|
605
|
+
marketplaceId: "ATVPDKIKX0DER",
|
|
606
|
+
countryCode: "US",
|
|
607
|
+
countryName: "United States",
|
|
608
|
+
amazonDomain: "Amazon.com",
|
|
609
|
+
currencyCode: "USD",
|
|
610
|
+
defaultReportingTimeZone: DEFAULT_REPORTING_TIME_ZONE,
|
|
611
|
+
spApiRegion: "NA",
|
|
612
|
+
spApiBaseUrl: SP_API_BASE_URLS.NA,
|
|
613
|
+
sellerCentralBaseUrl: "https://sellercentral.amazon.com",
|
|
614
|
+
adsRegion: "NA",
|
|
615
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.NA,
|
|
616
|
+
rolloutStatus: "foundation",
|
|
617
|
+
phase1Enabled: true
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
marketplaceId: "A1F83G8C2ARO7P",
|
|
621
|
+
countryCode: "GB",
|
|
622
|
+
countryName: "United Kingdom",
|
|
623
|
+
amazonDomain: "Amazon.co.uk",
|
|
624
|
+
currencyCode: "GBP",
|
|
625
|
+
defaultReportingTimeZone: "Europe/London",
|
|
626
|
+
spApiRegion: "EU",
|
|
627
|
+
spApiBaseUrl: SP_API_BASE_URLS.EU,
|
|
628
|
+
sellerCentralBaseUrl: "https://sellercentral-europe.amazon.com",
|
|
629
|
+
adsRegion: "EU",
|
|
630
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.EU,
|
|
631
|
+
rolloutStatus: "foundation",
|
|
632
|
+
phase1Enabled: true
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
marketplaceId: "A17E79C6D8DWNP",
|
|
636
|
+
countryCode: "SA",
|
|
637
|
+
countryName: "Saudi Arabia",
|
|
638
|
+
amazonDomain: "Amazon.sa",
|
|
639
|
+
currencyCode: "SAR",
|
|
640
|
+
defaultReportingTimeZone: "Asia/Riyadh",
|
|
641
|
+
spApiRegion: "EU",
|
|
642
|
+
spApiBaseUrl: SP_API_BASE_URLS.EU,
|
|
643
|
+
sellerCentralBaseUrl: "https://sellercentral.amazon.sa",
|
|
644
|
+
adsRegion: "EU",
|
|
645
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.EU,
|
|
646
|
+
rolloutStatus: "foundation",
|
|
647
|
+
phase1Enabled: true
|
|
648
|
+
},
|
|
649
|
+
{
|
|
650
|
+
marketplaceId: "A2EUQ1WTGCTBG2",
|
|
651
|
+
countryCode: "CA",
|
|
652
|
+
countryName: "Canada",
|
|
653
|
+
amazonDomain: "Amazon.ca",
|
|
654
|
+
currencyCode: "CAD",
|
|
655
|
+
defaultReportingTimeZone: "America/Toronto",
|
|
656
|
+
spApiRegion: "NA",
|
|
657
|
+
spApiBaseUrl: SP_API_BASE_URLS.NA,
|
|
658
|
+
sellerCentralBaseUrl: "https://sellercentral.amazon.ca",
|
|
659
|
+
adsRegion: "NA",
|
|
660
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.NA,
|
|
661
|
+
...ENABLED_ROLLOUT
|
|
662
|
+
},
|
|
663
|
+
{
|
|
664
|
+
marketplaceId: "A1AM78C64UM0Y8",
|
|
665
|
+
countryCode: "MX",
|
|
666
|
+
countryName: "Mexico",
|
|
667
|
+
amazonDomain: "Amazon.com.mx",
|
|
668
|
+
currencyCode: "MXN",
|
|
669
|
+
defaultReportingTimeZone: "America/Mexico_City",
|
|
670
|
+
spApiRegion: "NA",
|
|
671
|
+
spApiBaseUrl: SP_API_BASE_URLS.NA,
|
|
672
|
+
sellerCentralBaseUrl: "https://sellercentral.amazon.com.mx",
|
|
673
|
+
adsRegion: "NA",
|
|
674
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.NA,
|
|
675
|
+
...ENABLED_ROLLOUT
|
|
676
|
+
},
|
|
677
|
+
{
|
|
678
|
+
marketplaceId: "A2Q3Y263D00KWC",
|
|
679
|
+
countryCode: "BR",
|
|
680
|
+
countryName: "Brazil",
|
|
681
|
+
amazonDomain: "Amazon.com.br",
|
|
682
|
+
currencyCode: "BRL",
|
|
683
|
+
defaultReportingTimeZone: "America/Sao_Paulo",
|
|
684
|
+
spApiRegion: "NA",
|
|
685
|
+
spApiBaseUrl: SP_API_BASE_URLS.NA,
|
|
686
|
+
sellerCentralBaseUrl: "https://sellercentral.amazon.com.br",
|
|
687
|
+
adsRegion: "NA",
|
|
688
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.NA,
|
|
689
|
+
...ENABLED_ROLLOUT
|
|
690
|
+
},
|
|
691
|
+
{
|
|
692
|
+
marketplaceId: "A28R8C7NBKEWEA",
|
|
693
|
+
countryCode: "IE",
|
|
694
|
+
countryName: "Ireland",
|
|
695
|
+
amazonDomain: "Amazon.ie",
|
|
696
|
+
currencyCode: "EUR",
|
|
697
|
+
defaultReportingTimeZone: "Europe/Dublin",
|
|
698
|
+
spApiRegion: "EU",
|
|
699
|
+
spApiBaseUrl: SP_API_BASE_URLS.EU,
|
|
700
|
+
sellerCentralBaseUrl: "https://sellercentral.amazon.ie",
|
|
701
|
+
adsRegion: "EU",
|
|
702
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.EU,
|
|
703
|
+
...ENABLED_ROLLOUT
|
|
704
|
+
},
|
|
705
|
+
{
|
|
706
|
+
marketplaceId: "A1RKKUPIHCS9HS",
|
|
707
|
+
countryCode: "ES",
|
|
708
|
+
countryName: "Spain",
|
|
709
|
+
amazonDomain: "Amazon.es",
|
|
710
|
+
currencyCode: "EUR",
|
|
711
|
+
defaultReportingTimeZone: "Europe/Madrid",
|
|
712
|
+
spApiRegion: "EU",
|
|
713
|
+
spApiBaseUrl: SP_API_BASE_URLS.EU,
|
|
714
|
+
sellerCentralBaseUrl: "https://sellercentral-europe.amazon.com",
|
|
715
|
+
adsRegion: "EU",
|
|
716
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.EU,
|
|
717
|
+
...ENABLED_ROLLOUT
|
|
718
|
+
},
|
|
719
|
+
{
|
|
720
|
+
marketplaceId: "A13V1IB3VIYZZH",
|
|
721
|
+
countryCode: "FR",
|
|
722
|
+
countryName: "France",
|
|
723
|
+
amazonDomain: "Amazon.fr",
|
|
724
|
+
currencyCode: "EUR",
|
|
725
|
+
defaultReportingTimeZone: "Europe/Paris",
|
|
726
|
+
spApiRegion: "EU",
|
|
727
|
+
spApiBaseUrl: SP_API_BASE_URLS.EU,
|
|
728
|
+
sellerCentralBaseUrl: "https://sellercentral-europe.amazon.com",
|
|
729
|
+
adsRegion: "EU",
|
|
730
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.EU,
|
|
731
|
+
...ENABLED_ROLLOUT
|
|
732
|
+
},
|
|
733
|
+
{
|
|
734
|
+
marketplaceId: "AMEN7PMS3EDWL",
|
|
735
|
+
countryCode: "BE",
|
|
736
|
+
countryName: "Belgium",
|
|
737
|
+
amazonDomain: "Amazon.com.be",
|
|
738
|
+
currencyCode: "EUR",
|
|
739
|
+
defaultReportingTimeZone: "Europe/Brussels",
|
|
740
|
+
spApiRegion: "EU",
|
|
741
|
+
spApiBaseUrl: SP_API_BASE_URLS.EU,
|
|
742
|
+
sellerCentralBaseUrl: "https://sellercentral.amazon.com.be",
|
|
743
|
+
adsRegion: "EU",
|
|
744
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.EU,
|
|
745
|
+
...ENABLED_ROLLOUT
|
|
746
|
+
},
|
|
747
|
+
{
|
|
748
|
+
marketplaceId: "A1805IZSGTT6HS",
|
|
749
|
+
countryCode: "NL",
|
|
750
|
+
countryName: "Netherlands",
|
|
751
|
+
amazonDomain: "Amazon.nl",
|
|
752
|
+
currencyCode: "EUR",
|
|
753
|
+
defaultReportingTimeZone: "Europe/Amsterdam",
|
|
754
|
+
spApiRegion: "EU",
|
|
755
|
+
spApiBaseUrl: SP_API_BASE_URLS.EU,
|
|
756
|
+
sellerCentralBaseUrl: "https://sellercentral.amazon.nl",
|
|
757
|
+
adsRegion: "EU",
|
|
758
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.EU,
|
|
759
|
+
...ENABLED_ROLLOUT
|
|
760
|
+
},
|
|
761
|
+
{
|
|
762
|
+
marketplaceId: "A1PA6795UKMFR9",
|
|
763
|
+
countryCode: "DE",
|
|
764
|
+
countryName: "Germany",
|
|
765
|
+
amazonDomain: "Amazon.de",
|
|
766
|
+
currencyCode: "EUR",
|
|
767
|
+
defaultReportingTimeZone: "Europe/Berlin",
|
|
768
|
+
spApiRegion: "EU",
|
|
769
|
+
spApiBaseUrl: SP_API_BASE_URLS.EU,
|
|
770
|
+
sellerCentralBaseUrl: "https://sellercentral-europe.amazon.com",
|
|
771
|
+
adsRegion: "EU",
|
|
772
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.EU,
|
|
773
|
+
...ENABLED_ROLLOUT
|
|
774
|
+
},
|
|
775
|
+
{
|
|
776
|
+
marketplaceId: "APJ6JRA9NG5V4",
|
|
777
|
+
countryCode: "IT",
|
|
778
|
+
countryName: "Italy",
|
|
779
|
+
amazonDomain: "Amazon.it",
|
|
780
|
+
currencyCode: "EUR",
|
|
781
|
+
defaultReportingTimeZone: "Europe/Rome",
|
|
782
|
+
spApiRegion: "EU",
|
|
783
|
+
spApiBaseUrl: SP_API_BASE_URLS.EU,
|
|
784
|
+
sellerCentralBaseUrl: "https://sellercentral-europe.amazon.com",
|
|
785
|
+
adsRegion: "EU",
|
|
786
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.EU,
|
|
787
|
+
...ENABLED_ROLLOUT
|
|
788
|
+
},
|
|
789
|
+
{
|
|
790
|
+
marketplaceId: "A2NODRKZP88ZB9",
|
|
791
|
+
countryCode: "SE",
|
|
792
|
+
countryName: "Sweden",
|
|
793
|
+
amazonDomain: "Amazon.se",
|
|
794
|
+
currencyCode: "SEK",
|
|
795
|
+
defaultReportingTimeZone: "Europe/Stockholm",
|
|
796
|
+
spApiRegion: "EU",
|
|
797
|
+
spApiBaseUrl: SP_API_BASE_URLS.EU,
|
|
798
|
+
sellerCentralBaseUrl: "https://sellercentral.amazon.se",
|
|
799
|
+
adsRegion: "EU",
|
|
800
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.EU,
|
|
801
|
+
...ENABLED_ROLLOUT
|
|
802
|
+
},
|
|
803
|
+
{
|
|
804
|
+
marketplaceId: "AE08WJ6YKNBMC",
|
|
805
|
+
countryCode: "ZA",
|
|
806
|
+
countryName: "South Africa",
|
|
807
|
+
amazonDomain: "Amazon.co.za",
|
|
808
|
+
currencyCode: "ZAR",
|
|
809
|
+
defaultReportingTimeZone: "Africa/Johannesburg",
|
|
810
|
+
spApiRegion: "EU",
|
|
811
|
+
spApiBaseUrl: SP_API_BASE_URLS.EU,
|
|
812
|
+
sellerCentralBaseUrl: "https://sellercentral.amazon.co.za",
|
|
813
|
+
adsRegion: "EU",
|
|
814
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.EU,
|
|
815
|
+
...ENABLED_ROLLOUT
|
|
816
|
+
},
|
|
817
|
+
{
|
|
818
|
+
marketplaceId: "A1C3SOZRARQ6R3",
|
|
819
|
+
countryCode: "PL",
|
|
820
|
+
countryName: "Poland",
|
|
821
|
+
amazonDomain: "Amazon.pl",
|
|
822
|
+
currencyCode: "PLN",
|
|
823
|
+
defaultReportingTimeZone: "Europe/Warsaw",
|
|
824
|
+
spApiRegion: "EU",
|
|
825
|
+
spApiBaseUrl: SP_API_BASE_URLS.EU,
|
|
826
|
+
sellerCentralBaseUrl: "https://sellercentral.amazon.pl",
|
|
827
|
+
adsRegion: "EU",
|
|
828
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.EU,
|
|
829
|
+
...ENABLED_ROLLOUT
|
|
830
|
+
},
|
|
831
|
+
{
|
|
832
|
+
marketplaceId: "ARBP9OOSHTCHU",
|
|
833
|
+
countryCode: "EG",
|
|
834
|
+
countryName: "Egypt",
|
|
835
|
+
amazonDomain: "Amazon.eg",
|
|
836
|
+
currencyCode: "EGP",
|
|
837
|
+
defaultReportingTimeZone: "Africa/Cairo",
|
|
838
|
+
spApiRegion: "EU",
|
|
839
|
+
spApiBaseUrl: SP_API_BASE_URLS.EU,
|
|
840
|
+
sellerCentralBaseUrl: "https://sellercentral.amazon.eg",
|
|
841
|
+
adsRegion: "EU",
|
|
842
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.EU,
|
|
843
|
+
...ENABLED_ROLLOUT
|
|
844
|
+
},
|
|
845
|
+
{
|
|
846
|
+
marketplaceId: "A33AVAJ2PDY3EV",
|
|
847
|
+
countryCode: "TR",
|
|
848
|
+
countryName: "Turkey",
|
|
849
|
+
amazonDomain: "Amazon.com.tr",
|
|
850
|
+
currencyCode: "TRY",
|
|
851
|
+
defaultReportingTimeZone: "Europe/Istanbul",
|
|
852
|
+
spApiRegion: "EU",
|
|
853
|
+
spApiBaseUrl: SP_API_BASE_URLS.EU,
|
|
854
|
+
sellerCentralBaseUrl: "https://sellercentral.amazon.com.tr",
|
|
855
|
+
adsRegion: "EU",
|
|
856
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.EU,
|
|
857
|
+
...ENABLED_ROLLOUT
|
|
858
|
+
},
|
|
859
|
+
{
|
|
860
|
+
marketplaceId: "A2VIGQ35RCS4UG",
|
|
861
|
+
countryCode: "AE",
|
|
862
|
+
countryName: "United Arab Emirates",
|
|
863
|
+
amazonDomain: "Amazon.ae",
|
|
864
|
+
currencyCode: "AED",
|
|
865
|
+
defaultReportingTimeZone: "Asia/Dubai",
|
|
866
|
+
spApiRegion: "EU",
|
|
867
|
+
spApiBaseUrl: SP_API_BASE_URLS.EU,
|
|
868
|
+
sellerCentralBaseUrl: "https://sellercentral.amazon.ae",
|
|
869
|
+
adsRegion: "EU",
|
|
870
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.EU,
|
|
871
|
+
...ENABLED_ROLLOUT
|
|
872
|
+
},
|
|
873
|
+
{
|
|
874
|
+
marketplaceId: "A21TJRUUN4KGV",
|
|
875
|
+
countryCode: "IN",
|
|
876
|
+
countryName: "India",
|
|
877
|
+
amazonDomain: "Amazon.in",
|
|
878
|
+
currencyCode: "INR",
|
|
879
|
+
defaultReportingTimeZone: "Asia/Kolkata",
|
|
880
|
+
spApiRegion: "EU",
|
|
881
|
+
spApiBaseUrl: SP_API_BASE_URLS.EU,
|
|
882
|
+
sellerCentralBaseUrl: "https://sellercentral.amazon.in",
|
|
883
|
+
adsRegion: "EU",
|
|
884
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.EU,
|
|
885
|
+
...ENABLED_ROLLOUT
|
|
886
|
+
},
|
|
887
|
+
{
|
|
888
|
+
marketplaceId: "A19VAU5U5O7RUS",
|
|
889
|
+
countryCode: "SG",
|
|
890
|
+
countryName: "Singapore",
|
|
891
|
+
amazonDomain: "Amazon.sg",
|
|
892
|
+
currencyCode: "SGD",
|
|
893
|
+
defaultReportingTimeZone: "Asia/Singapore",
|
|
894
|
+
spApiRegion: "FE",
|
|
895
|
+
spApiBaseUrl: SP_API_BASE_URLS.FE,
|
|
896
|
+
sellerCentralBaseUrl: "https://sellercentral.amazon.sg",
|
|
897
|
+
adsRegion: "FE",
|
|
898
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.FE,
|
|
899
|
+
...ENABLED_ROLLOUT
|
|
900
|
+
},
|
|
901
|
+
{
|
|
902
|
+
marketplaceId: "A39IBJ37TRP1C6",
|
|
903
|
+
countryCode: "AU",
|
|
904
|
+
countryName: "Australia",
|
|
905
|
+
amazonDomain: "Amazon.com.au",
|
|
906
|
+
currencyCode: "AUD",
|
|
907
|
+
defaultReportingTimeZone: "Australia/Sydney",
|
|
908
|
+
spApiRegion: "FE",
|
|
909
|
+
spApiBaseUrl: SP_API_BASE_URLS.FE,
|
|
910
|
+
sellerCentralBaseUrl: "https://sellercentral.amazon.com.au",
|
|
911
|
+
adsRegion: "FE",
|
|
912
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.FE,
|
|
913
|
+
...ENABLED_ROLLOUT
|
|
914
|
+
},
|
|
915
|
+
{
|
|
916
|
+
marketplaceId: "A1VC38T7YXB528",
|
|
917
|
+
countryCode: "JP",
|
|
918
|
+
countryName: "Japan",
|
|
919
|
+
amazonDomain: "Amazon.co.jp",
|
|
920
|
+
currencyCode: "JPY",
|
|
921
|
+
defaultReportingTimeZone: "Asia/Tokyo",
|
|
922
|
+
spApiRegion: "FE",
|
|
923
|
+
spApiBaseUrl: SP_API_BASE_URLS.FE,
|
|
924
|
+
sellerCentralBaseUrl: "https://sellercentral.amazon.co.jp",
|
|
925
|
+
adsRegion: "FE",
|
|
926
|
+
adsApiBaseUrl: ADS_API_BASE_URLS.FE,
|
|
927
|
+
...ENABLED_ROLLOUT
|
|
928
|
+
}
|
|
929
|
+
];
|
|
930
|
+
var MARKETPLACES_BY_ID = Object.freeze(
|
|
931
|
+
Object.fromEntries(MARKETPLACE_DEFINITIONS.map((marketplace) => [marketplace.marketplaceId, marketplace]))
|
|
932
|
+
);
|
|
933
|
+
function marketplaceIdsForCountryCodes(countryCodes) {
|
|
934
|
+
return Object.freeze(countryCodes.map((countryCode) => {
|
|
935
|
+
const marketplace = MARKETPLACE_DEFINITIONS.find((entry) => entry.countryCode === countryCode);
|
|
936
|
+
if (!marketplace) {
|
|
937
|
+
throw new Error(`Missing marketplace definition for country code ${countryCode}`);
|
|
938
|
+
}
|
|
939
|
+
return marketplace.marketplaceId;
|
|
940
|
+
}));
|
|
941
|
+
}
|
|
942
|
+
function marketplaceSetForCountryCodes(countryCodes) {
|
|
943
|
+
return Object.freeze(new Set(marketplaceIdsForCountryCodes(countryCodes)));
|
|
944
|
+
}
|
|
945
|
+
var CUSTOMER_FEEDBACK_SUPPORTED_MARKETPLACE_IDS = Object.freeze(
|
|
946
|
+
/* @__PURE__ */ new Set([
|
|
947
|
+
"ATVPDKIKX0DER",
|
|
948
|
+
// US
|
|
949
|
+
"A1F83G8C2ARO7P",
|
|
950
|
+
// UK
|
|
951
|
+
"A1PA6795UKMFR9",
|
|
952
|
+
// DE
|
|
953
|
+
"A1RKKUPIHCS9HS",
|
|
954
|
+
// ES
|
|
955
|
+
"A13V1IB3VIYZZH",
|
|
956
|
+
// FR
|
|
957
|
+
"APJ6JRA9NG5V4",
|
|
958
|
+
// IT
|
|
959
|
+
"A1VC38T7YXB528"
|
|
960
|
+
// JP
|
|
961
|
+
])
|
|
962
|
+
);
|
|
963
|
+
var ADS_SPONSORED_PRODUCTS_CAMPAIGN_MANAGEMENT_SUPPORTED_MARKETPLACE_IDS = marketplaceSetForCountryCodes([
|
|
964
|
+
"US",
|
|
965
|
+
"CA",
|
|
966
|
+
"MX",
|
|
967
|
+
"BR",
|
|
968
|
+
"DE",
|
|
969
|
+
"ES",
|
|
970
|
+
"FR",
|
|
971
|
+
"IT",
|
|
972
|
+
"GB",
|
|
973
|
+
"NL",
|
|
974
|
+
"SE",
|
|
975
|
+
"TR",
|
|
976
|
+
"PL",
|
|
977
|
+
"BE",
|
|
978
|
+
"AE",
|
|
979
|
+
"EG",
|
|
980
|
+
"SA",
|
|
981
|
+
"JP",
|
|
982
|
+
"IN",
|
|
983
|
+
"AU",
|
|
984
|
+
"SG",
|
|
985
|
+
"ZA"
|
|
986
|
+
]);
|
|
987
|
+
var ADS_SPONSORED_PRODUCTS_BID_RECOMMENDATION_SUPPORTED_MARKETPLACE_IDS = marketplaceSetForCountryCodes(["US", "CA", "DE", "ES", "FR", "GB", "JP", "IN"]);
|
|
988
|
+
var ADS_SPONSORED_PRODUCTS_BUDGET_RECOMMENDATION_SUPPORTED_MARKETPLACE_IDS = marketplaceSetForCountryCodes(["US", "CA", "MX", "DE", "ES", "FR", "GB", "IT", "JP", "IN", "AU", "AE"]);
|
|
989
|
+
var ADS_BRAND_METRICS_SUPPORTED_MARKETPLACE_IDS = marketplaceSetForCountryCodes(["US", "CA", "MX", "GB", "DE", "FR", "IN", "IT", "ES", "JP", "AU"]);
|
|
990
|
+
var BRAND_ANALYTICS_REPORT_SUPPORTED_MARKETPLACE_IDS = marketplaceSetForCountryCodes([
|
|
991
|
+
"US",
|
|
992
|
+
"CA",
|
|
993
|
+
"MX",
|
|
994
|
+
"BR",
|
|
995
|
+
"ES",
|
|
996
|
+
"GB",
|
|
997
|
+
"FR",
|
|
998
|
+
"NL",
|
|
999
|
+
"DE",
|
|
1000
|
+
"IT",
|
|
1001
|
+
"SE",
|
|
1002
|
+
"TR",
|
|
1003
|
+
"SA",
|
|
1004
|
+
"AE",
|
|
1005
|
+
"IN",
|
|
1006
|
+
"SG",
|
|
1007
|
+
"AU",
|
|
1008
|
+
"JP"
|
|
1009
|
+
]);
|
|
1010
|
+
var FULFILLMENT_INBOUND_SUPPORTED_MARKETPLACE_IDS = Object.freeze(
|
|
1011
|
+
new Set(MARKETPLACE_DEFINITIONS.filter((marketplace) => marketplace.countryCode !== "BR").map((marketplace) => marketplace.marketplaceId))
|
|
1012
|
+
);
|
|
1013
|
+
var FBA_INVENTORY_PLANNING_UNSUPPORTED_COUNTRY_CODES = /* @__PURE__ */ new Set(["NL", "PL", "SE", "BE"]);
|
|
1014
|
+
var FBA_INVENTORY_PLANNING_SUPPORTED_MARKETPLACE_IDS = Object.freeze(
|
|
1015
|
+
new Set(MARKETPLACE_DEFINITIONS.filter((marketplace) => !FBA_INVENTORY_PLANNING_UNSUPPORTED_COUNTRY_CODES.has(marketplace.countryCode)).map((marketplace) => marketplace.marketplaceId))
|
|
1016
|
+
);
|
|
1017
|
+
var AWD_SUPPORTED_MARKETPLACE_IDS = marketplaceSetForCountryCodes(["US"]);
|
|
1018
|
+
var MARKETPLACE_NAMES = Object.freeze(
|
|
1019
|
+
Object.fromEntries(MARKETPLACE_DEFINITIONS.map((marketplace) => [marketplace.marketplaceId, marketplace.countryName]))
|
|
1020
|
+
);
|
|
1021
|
+
function getMarketplaceDefinition(marketplaceId) {
|
|
1022
|
+
if (!marketplaceId) return void 0;
|
|
1023
|
+
return MARKETPLACES_BY_ID[marketplaceId];
|
|
1024
|
+
}
|
|
1025
|
+
var MARKETPLACE_ORDER_TIER_IDS = [
|
|
1026
|
+
"starter",
|
|
1027
|
+
"growth",
|
|
1028
|
+
"scale",
|
|
1029
|
+
"business",
|
|
1030
|
+
"enterprise"
|
|
1031
|
+
];
|
|
1032
|
+
var SELLER_ACCOUNT_ORDER_TIER_IDS = MARKETPLACE_ORDER_TIER_IDS;
|
|
1033
|
+
var MARKETPLACE_ORDER_TIERS = [
|
|
1034
|
+
{
|
|
1035
|
+
id: "starter",
|
|
1036
|
+
displayName: "Starter",
|
|
1037
|
+
minOrdersInclusive: 0,
|
|
1038
|
+
maxOrdersInclusive: 1e3,
|
|
1039
|
+
monthlyUsd: 39,
|
|
1040
|
+
monthlyPriceCents: 3900
|
|
1041
|
+
},
|
|
1042
|
+
{
|
|
1043
|
+
id: "growth",
|
|
1044
|
+
displayName: "Growth",
|
|
1045
|
+
minOrdersInclusive: 1001,
|
|
1046
|
+
maxOrdersInclusive: 5e3,
|
|
1047
|
+
monthlyUsd: 69,
|
|
1048
|
+
monthlyPriceCents: 6900
|
|
1049
|
+
},
|
|
1050
|
+
{
|
|
1051
|
+
id: "scale",
|
|
1052
|
+
displayName: "Scale",
|
|
1053
|
+
minOrdersInclusive: 5001,
|
|
1054
|
+
maxOrdersInclusive: 1e4,
|
|
1055
|
+
monthlyUsd: 99,
|
|
1056
|
+
monthlyPriceCents: 9900
|
|
1057
|
+
},
|
|
1058
|
+
{
|
|
1059
|
+
id: "business",
|
|
1060
|
+
displayName: "Business",
|
|
1061
|
+
minOrdersInclusive: 10001,
|
|
1062
|
+
maxOrdersInclusive: 25e3,
|
|
1063
|
+
monthlyUsd: 199,
|
|
1064
|
+
monthlyPriceCents: 19900
|
|
1065
|
+
},
|
|
1066
|
+
{
|
|
1067
|
+
id: "enterprise",
|
|
1068
|
+
displayName: "Enterprise",
|
|
1069
|
+
minOrdersInclusive: 25001,
|
|
1070
|
+
maxOrdersInclusive: null,
|
|
1071
|
+
monthlyUsd: null,
|
|
1072
|
+
monthlyPriceCents: null
|
|
1073
|
+
}
|
|
1074
|
+
];
|
|
1075
|
+
var SELLER_ACCOUNT_BILLING_STATUSES = [
|
|
1076
|
+
"trialing",
|
|
1077
|
+
"active",
|
|
1078
|
+
"past_due",
|
|
1079
|
+
"canceled",
|
|
1080
|
+
"provisional",
|
|
1081
|
+
"custom",
|
|
1082
|
+
"disabled"
|
|
1083
|
+
];
|
|
1084
|
+
var SELLER_ACCOUNT_BILLING_MEASUREMENT_SOURCES = [
|
|
1085
|
+
"order_metrics",
|
|
1086
|
+
"raw_orders",
|
|
1087
|
+
"manual",
|
|
1088
|
+
"unavailable"
|
|
1089
|
+
];
|
|
1090
|
+
var SELLER_ACCOUNT_BILLING_MEASUREMENT_CONFIDENCES = [
|
|
1091
|
+
"final",
|
|
1092
|
+
"partial",
|
|
1093
|
+
"provisional",
|
|
1094
|
+
"unavailable",
|
|
1095
|
+
"manual"
|
|
1096
|
+
];
|
|
1097
|
+
var TIER_INDEX_BY_ID = new Map(
|
|
1098
|
+
MARKETPLACE_ORDER_TIERS.map((tier, index) => [tier.id, index])
|
|
1099
|
+
);
|
|
1100
|
+
var TIER_BY_ID = new Map(
|
|
1101
|
+
MARKETPLACE_ORDER_TIERS.map((tier) => [tier.id, tier])
|
|
1102
|
+
);
|
|
1103
|
+
var DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
|
|
1104
|
+
var DATE_ERROR = "Expected date string in YYYY-MM-DD format";
|
|
1105
|
+
var CALENDAR_DATE_ERROR = "Expected valid calendar date in YYYY-MM-DD format";
|
|
1106
|
+
var TIMESTAMP_ERROR = "Expected parseable timestamp";
|
|
1107
|
+
function isLeapYear(year) {
|
|
1108
|
+
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
1109
|
+
}
|
|
1110
|
+
function isValidCalendarDateString(value) {
|
|
1111
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
|
|
1112
|
+
if (!match) {
|
|
1113
|
+
return false;
|
|
1114
|
+
}
|
|
1115
|
+
const year = Number(match[1]);
|
|
1116
|
+
const month = Number(match[2]);
|
|
1117
|
+
const day = Number(match[3]);
|
|
1118
|
+
if (year < 1 || month < 1 || month > 12) {
|
|
1119
|
+
return false;
|
|
1120
|
+
}
|
|
1121
|
+
const daysInMonth = [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
1122
|
+
return day >= 1 && day <= daysInMonth[month - 1];
|
|
1123
|
+
}
|
|
1124
|
+
function isParseableTimestampString(value) {
|
|
1125
|
+
if (!Number.isFinite(Date.parse(value))) {
|
|
1126
|
+
return false;
|
|
1127
|
+
}
|
|
1128
|
+
const leadingDate = /^(\d{4}-\d{2}-\d{2})(?:[T\s]|$)/.exec(value);
|
|
1129
|
+
if (leadingDate && !isValidCalendarDateString(leadingDate[1])) {
|
|
1130
|
+
return false;
|
|
1131
|
+
}
|
|
1132
|
+
return true;
|
|
1133
|
+
}
|
|
1134
|
+
var dateSchema = z2.string({ invalid_type_error: DATE_ERROR }).regex(DATE_PATTERN, DATE_ERROR).describe("Date (YYYY-MM-DD)");
|
|
1135
|
+
var DEFAULT_TOOL_LIMIT = 20;
|
|
1136
|
+
var MAX_TOOL_LIMIT = 1e3;
|
|
1137
|
+
function toolLimitParam(description = `Max rows (1-${MAX_TOOL_LIMIT}, default ${DEFAULT_TOOL_LIMIT}).`, options) {
|
|
1138
|
+
const max = options?.max ?? MAX_TOOL_LIMIT;
|
|
1139
|
+
const defaultValue = options?.defaultValue ?? DEFAULT_TOOL_LIMIT;
|
|
1140
|
+
return z2.number().int().min(1).max(max).default(defaultValue).describe(description);
|
|
1141
|
+
}
|
|
1142
|
+
function optionalDateParam(description) {
|
|
1143
|
+
return z2.preprocess(
|
|
1144
|
+
(value) => value === null ? void 0 : value,
|
|
1145
|
+
z2.string({ invalid_type_error: DATE_ERROR }).regex(DATE_PATTERN, DATE_ERROR).optional()
|
|
1146
|
+
).describe(description);
|
|
1147
|
+
}
|
|
1148
|
+
var AGENCY_STATUSES = ["pilot", "active", "paused", "disabled"];
|
|
1149
|
+
var APP_USER_STATUSES = ["active", "invited", "disabled", "deleted"];
|
|
1150
|
+
var AGENCY_MEMBERSHIP_ROLES = ["owner", "admin", "member"];
|
|
1151
|
+
var TENANT_MEMBERSHIP_ROLES = ["owner", "admin", "member", "read_only"];
|
|
1152
|
+
var MEMBERSHIP_STATUSES = ["invited", "active", "disabled", "deleted"];
|
|
1153
|
+
var TENANT_BILLING_OWNERS = ["self_serve", "agency", "manual"];
|
|
1154
|
+
var TENANT_BILLING_MODES = ["standard", "custom_agency", "covered"];
|
|
1155
|
+
var agencyStatusSchema = z2.enum(AGENCY_STATUSES);
|
|
1156
|
+
var appUserStatusSchema = z2.enum(APP_USER_STATUSES);
|
|
1157
|
+
var agencyMembershipRoleSchema = z2.enum(AGENCY_MEMBERSHIP_ROLES);
|
|
1158
|
+
var tenantMembershipRoleSchema = z2.enum(TENANT_MEMBERSHIP_ROLES);
|
|
1159
|
+
var membershipStatusSchema = z2.enum(MEMBERSHIP_STATUSES);
|
|
1160
|
+
var tenantBillingOwnerSchema = z2.enum(TENANT_BILLING_OWNERS);
|
|
1161
|
+
var tenantBillingModeSchema = z2.enum(TENANT_BILLING_MODES);
|
|
1162
|
+
var nonEmptyStringSchema = z2.string().min(1);
|
|
1163
|
+
var nullableStringSchema = nonEmptyStringSchema.nullable();
|
|
1164
|
+
var timestampStringSchema = nonEmptyStringSchema;
|
|
1165
|
+
var nullableTimestampStringSchema = timestampStringSchema.nullable();
|
|
1166
|
+
var sellerAccountMarketplaceRegistryDateSchema = z2.string({ invalid_type_error: CALENDAR_DATE_ERROR }).regex(DATE_PATTERN, CALENDAR_DATE_ERROR).refine(isValidCalendarDateString, CALENDAR_DATE_ERROR);
|
|
1167
|
+
var nullableSellerAccountMarketplaceRegistryDateSchema = sellerAccountMarketplaceRegistryDateSchema.nullable();
|
|
1168
|
+
var nullableDateSchema = dateSchema.nullable();
|
|
1169
|
+
var sellerAccountMarketplaceRegistryTimestampSchema = z2.string({ invalid_type_error: TIMESTAMP_ERROR }).min(1, TIMESTAMP_ERROR).refine(isParseableTimestampString, TIMESTAMP_ERROR);
|
|
1170
|
+
var nullableSellerAccountMarketplaceRegistryTimestampSchema = sellerAccountMarketplaceRegistryTimestampSchema.nullable();
|
|
1171
|
+
var nonNegativeIntegerSchema = z2.number().int().nonnegative();
|
|
1172
|
+
var nullableNonNegativeIntegerSchema = nonNegativeIntegerSchema.nullable();
|
|
1173
|
+
var sellerAccountOrderTierSchema = z2.enum(SELLER_ACCOUNT_ORDER_TIER_IDS);
|
|
1174
|
+
var sellerAccountBillingStatusSchema = z2.enum(SELLER_ACCOUNT_BILLING_STATUSES);
|
|
1175
|
+
var sellerAccountBillingMeasurementSourceSchema = z2.enum(SELLER_ACCOUNT_BILLING_MEASUREMENT_SOURCES);
|
|
1176
|
+
var sellerAccountBillingMeasurementConfidenceSchema = z2.enum(
|
|
1177
|
+
SELLER_ACCOUNT_BILLING_MEASUREMENT_CONFIDENCES
|
|
1178
|
+
);
|
|
1179
|
+
var SELLER_ACCOUNT_MARKETPLACE_REGISTRY_STATUSES = ["draft", "verified", "superseded"];
|
|
1180
|
+
var SELLER_ACCOUNT_MARKETPLACE_CONNECTION_STATUSES = [
|
|
1181
|
+
"pending",
|
|
1182
|
+
"active",
|
|
1183
|
+
"reconnect_needed",
|
|
1184
|
+
"disconnected",
|
|
1185
|
+
"archived"
|
|
1186
|
+
];
|
|
1187
|
+
var SELLER_ACCOUNT_RAW_ORDERS_COVERAGE_ROLES = ["candidate", "expected", "excluded"];
|
|
1188
|
+
var SELLER_ACCOUNT_MARKETPLACE_VERIFICATION_SOURCES = [
|
|
1189
|
+
"operator_verified",
|
|
1190
|
+
"amazon_discovery",
|
|
1191
|
+
"seller_central_oauth",
|
|
1192
|
+
"migration",
|
|
1193
|
+
"support_override"
|
|
1194
|
+
];
|
|
1195
|
+
var sellerAccountMarketplaceRegistryStatusSchema = z2.enum(
|
|
1196
|
+
SELLER_ACCOUNT_MARKETPLACE_REGISTRY_STATUSES
|
|
1197
|
+
);
|
|
1198
|
+
var sellerAccountMarketplaceConnectionStatusSchema = z2.enum(
|
|
1199
|
+
SELLER_ACCOUNT_MARKETPLACE_CONNECTION_STATUSES
|
|
1200
|
+
);
|
|
1201
|
+
var sellerAccountRawOrdersCoverageRoleSchema = z2.enum(
|
|
1202
|
+
SELLER_ACCOUNT_RAW_ORDERS_COVERAGE_ROLES
|
|
1203
|
+
);
|
|
1204
|
+
var sellerAccountMarketplaceVerificationSourceSchema = z2.enum(
|
|
1205
|
+
SELLER_ACCOUNT_MARKETPLACE_VERIFICATION_SOURCES
|
|
1206
|
+
);
|
|
1207
|
+
var sellerAccountBillingMeasurementRowSchema = z2.object({
|
|
1208
|
+
measurement_id: nonEmptyStringSchema,
|
|
1209
|
+
tenant_id: nonEmptyStringSchema,
|
|
1210
|
+
connection_id: nonEmptyStringSchema,
|
|
1211
|
+
marketplace_id: nonEmptyStringSchema,
|
|
1212
|
+
period_start: dateSchema,
|
|
1213
|
+
period_end: dateSchema,
|
|
1214
|
+
reporting_time_zone: nonEmptyStringSchema,
|
|
1215
|
+
orders_30d: nullableNonNegativeIntegerSchema,
|
|
1216
|
+
units_30d: nullableNonNegativeIntegerSchema,
|
|
1217
|
+
source: sellerAccountBillingMeasurementSourceSchema,
|
|
1218
|
+
confidence: sellerAccountBillingMeasurementConfidenceSchema,
|
|
1219
|
+
computed_tier: sellerAccountOrderTierSchema,
|
|
1220
|
+
computed_at: timestampStringSchema,
|
|
1221
|
+
details_json: nullableStringSchema
|
|
1222
|
+
}).strict();
|
|
1223
|
+
var sellerAccountBillingStateRowSchema = z2.object({
|
|
1224
|
+
billing_state_id: nonEmptyStringSchema,
|
|
1225
|
+
tenant_id: nonEmptyStringSchema,
|
|
1226
|
+
connection_id: nonEmptyStringSchema,
|
|
1227
|
+
marketplace_id: nonEmptyStringSchema,
|
|
1228
|
+
billing_status: sellerAccountBillingStatusSchema,
|
|
1229
|
+
billing_tier: sellerAccountOrderTierSchema,
|
|
1230
|
+
pending_billing_tier: sellerAccountOrderTierSchema.nullable(),
|
|
1231
|
+
stripe_customer_id: nullableStringSchema,
|
|
1232
|
+
stripe_subscription_id: nullableStringSchema,
|
|
1233
|
+
stripe_subscription_item_id: nullableStringSchema,
|
|
1234
|
+
stripe_price_id: nullableStringSchema,
|
|
1235
|
+
last_measured_orders_30d: nullableNonNegativeIntegerSchema,
|
|
1236
|
+
last_measured_units_30d: nullableNonNegativeIntegerSchema,
|
|
1237
|
+
last_measurement_source: sellerAccountBillingMeasurementSourceSchema,
|
|
1238
|
+
last_measurement_confidence: sellerAccountBillingMeasurementConfidenceSchema,
|
|
1239
|
+
last_measured_period_start: nullableDateSchema,
|
|
1240
|
+
last_measured_period_end: nullableDateSchema,
|
|
1241
|
+
last_measured_at: nullableTimestampStringSchema,
|
|
1242
|
+
consecutive_months_below_tier: nonNegativeIntegerSchema,
|
|
1243
|
+
tier_effective_at: nullableTimestampStringSchema,
|
|
1244
|
+
pending_tier_effective_at: nullableTimestampStringSchema,
|
|
1245
|
+
manual_billing_override: z2.boolean(),
|
|
1246
|
+
manual_billing_override_reason: nullableStringSchema,
|
|
1247
|
+
created_at: timestampStringSchema,
|
|
1248
|
+
updated_at: timestampStringSchema
|
|
1249
|
+
}).strict();
|
|
1250
|
+
var sellerAccountBillingEventRowSchema = z2.object({
|
|
1251
|
+
event_id: nonEmptyStringSchema,
|
|
1252
|
+
tenant_id: nonEmptyStringSchema,
|
|
1253
|
+
connection_id: nonEmptyStringSchema,
|
|
1254
|
+
marketplace_id: nonEmptyStringSchema,
|
|
1255
|
+
event_type: nonEmptyStringSchema,
|
|
1256
|
+
from_tier: sellerAccountOrderTierSchema.nullable(),
|
|
1257
|
+
to_tier: sellerAccountOrderTierSchema.nullable(),
|
|
1258
|
+
orders_30d: nullableNonNegativeIntegerSchema,
|
|
1259
|
+
stripe_subscription_id: nullableStringSchema,
|
|
1260
|
+
stripe_subscription_item_id: nullableStringSchema,
|
|
1261
|
+
stripe_price_id: nullableStringSchema,
|
|
1262
|
+
effective_at: nullableTimestampStringSchema,
|
|
1263
|
+
metadata_json: nullableStringSchema,
|
|
1264
|
+
created_at: timestampStringSchema
|
|
1265
|
+
}).strict();
|
|
1266
|
+
var sellerAccountMarketplaceRegistryRowSchema = z2.object({
|
|
1267
|
+
registry_entry_id: nonEmptyStringSchema,
|
|
1268
|
+
registry_version_id: nonEmptyStringSchema,
|
|
1269
|
+
registry_status: sellerAccountMarketplaceRegistryStatusSchema,
|
|
1270
|
+
tenant_id: nonEmptyStringSchema,
|
|
1271
|
+
seller_id: nonEmptyStringSchema,
|
|
1272
|
+
connection_id: nonEmptyStringSchema,
|
|
1273
|
+
marketplace_id: nonEmptyStringSchema,
|
|
1274
|
+
country_code: nonEmptyStringSchema,
|
|
1275
|
+
currency_code: nonEmptyStringSchema,
|
|
1276
|
+
reporting_time_zone: nonEmptyStringSchema,
|
|
1277
|
+
connection_status: sellerAccountMarketplaceConnectionStatusSchema,
|
|
1278
|
+
raw_orders_coverage_role: sellerAccountRawOrdersCoverageRoleSchema,
|
|
1279
|
+
raw_orders_coverage_start_date: nullableSellerAccountMarketplaceRegistryDateSchema,
|
|
1280
|
+
raw_orders_coverage_end_date: nullableSellerAccountMarketplaceRegistryDateSchema,
|
|
1281
|
+
coverage_exclusion_reason: nullableStringSchema,
|
|
1282
|
+
verification_source: sellerAccountMarketplaceVerificationSourceSchema,
|
|
1283
|
+
verified_at: nullableSellerAccountMarketplaceRegistryTimestampSchema,
|
|
1284
|
+
evidence_json: nullableStringSchema,
|
|
1285
|
+
created_at: sellerAccountMarketplaceRegistryTimestampSchema,
|
|
1286
|
+
updated_at: sellerAccountMarketplaceRegistryTimestampSchema
|
|
1287
|
+
}).strict().superRefine((row, ctx) => {
|
|
1288
|
+
if (row.marketplace_id === "seller_account") {
|
|
1289
|
+
ctx.addIssue({
|
|
1290
|
+
code: z2.ZodIssueCode.custom,
|
|
1291
|
+
path: ["marketplace_id"],
|
|
1292
|
+
message: "marketplace_id must be an actual Amazon marketplace ID, not seller_account"
|
|
1293
|
+
});
|
|
1294
|
+
} else if (!getMarketplaceDefinition(row.marketplace_id)) {
|
|
1295
|
+
ctx.addIssue({
|
|
1296
|
+
code: z2.ZodIssueCode.custom,
|
|
1297
|
+
path: ["marketplace_id"],
|
|
1298
|
+
message: "marketplace_id must be a supported canonical Amazon marketplace ID"
|
|
1299
|
+
});
|
|
1300
|
+
}
|
|
1301
|
+
if (row.registry_status === "verified" && row.raw_orders_coverage_role === "candidate") {
|
|
1302
|
+
ctx.addIssue({
|
|
1303
|
+
code: z2.ZodIssueCode.custom,
|
|
1304
|
+
path: ["raw_orders_coverage_role"],
|
|
1305
|
+
message: "verified registry versions cannot contain unresolved candidate marketplaces"
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1308
|
+
if (row.registry_status === "verified" && !row.verified_at) {
|
|
1309
|
+
ctx.addIssue({
|
|
1310
|
+
code: z2.ZodIssueCode.custom,
|
|
1311
|
+
path: ["verified_at"],
|
|
1312
|
+
message: "verified registry rows require verified_at"
|
|
1313
|
+
});
|
|
1314
|
+
}
|
|
1315
|
+
if (row.raw_orders_coverage_role === "expected" && !row.raw_orders_coverage_start_date) {
|
|
1316
|
+
ctx.addIssue({
|
|
1317
|
+
code: z2.ZodIssueCode.custom,
|
|
1318
|
+
path: ["raw_orders_coverage_start_date"],
|
|
1319
|
+
message: "expected raw-orders coverage rows require raw_orders_coverage_start_date"
|
|
1320
|
+
});
|
|
1321
|
+
}
|
|
1322
|
+
if (row.raw_orders_coverage_role === "excluded" && !row.coverage_exclusion_reason) {
|
|
1323
|
+
ctx.addIssue({
|
|
1324
|
+
code: z2.ZodIssueCode.custom,
|
|
1325
|
+
path: ["coverage_exclusion_reason"],
|
|
1326
|
+
message: "excluded raw-orders coverage rows require coverage_exclusion_reason"
|
|
1327
|
+
});
|
|
1328
|
+
}
|
|
1329
|
+
});
|
|
1330
|
+
var baseToolParams = {
|
|
1331
|
+
start_date: optionalDateParam("Optional. YYYY-MM-DD. Defaults to 30 days ago if omitted."),
|
|
1332
|
+
end_date: optionalDateParam("Optional. YYYY-MM-DD. Defaults to today if omitted."),
|
|
1333
|
+
profile_id: z2.string().optional().describe("Filter by profile ID"),
|
|
1334
|
+
campaign_name: z2.string().optional().describe("Filter by campaign name (LIKE match, use % for wildcards)"),
|
|
1335
|
+
sort_order: z2.enum(["asc", "desc"]).default("desc").describe("Sort order"),
|
|
1336
|
+
limit: toolLimitParam()
|
|
1337
|
+
};
|
|
1338
|
+
var baseInventoryParams = {
|
|
1339
|
+
asin: z2.string().optional().describe("Filter by ASIN"),
|
|
1340
|
+
sku: z2.string().optional().describe("Filter by SKU"),
|
|
1341
|
+
sort_order: z2.enum(["asc", "desc"]).default("desc").describe("Sort order"),
|
|
1342
|
+
limit: toolLimitParam()
|
|
1343
|
+
};
|
|
1344
|
+
var DISABLE_WRITE_TOOLS_FOR_DOMAIN_PREFIX = "__write_tools_disabled__:";
|
|
1345
|
+
var TOOL_DOMAINS = [
|
|
1346
|
+
{
|
|
1347
|
+
name: "Ads",
|
|
1348
|
+
serverDomain: "ads",
|
|
1349
|
+
tools: [
|
|
1350
|
+
{ name: "get_campaign_performance", description: "Campaign health, spend, and ACOS metrics" },
|
|
1351
|
+
{ name: "get_campaign_snapshots", description: "Campaign setting history and change detection" },
|
|
1352
|
+
{ name: "get_ads_change_history", description: "Timestamped Amazon Ads entity change events" },
|
|
1353
|
+
{ name: "get_adgroup_performance", description: "Ad group level performance breakdown" },
|
|
1354
|
+
{ name: "get_keyword_performance", description: "Keyword bid and targeting analysis" },
|
|
1355
|
+
{ name: "get_product_performance", description: "Sponsored Products advertised-ASIN performance" },
|
|
1356
|
+
{ name: "get_purchased_products", description: "Products purchased from ad clicks" },
|
|
1357
|
+
{ name: "get_search_terms", description: "SP/SB customer search terms that triggered ads" },
|
|
1358
|
+
{ name: "get_placement_breakdown", description: "Performance by ad placement" },
|
|
1359
|
+
{ name: "get_sb_campaign_performance", description: "Sponsored Brands campaign metrics" },
|
|
1360
|
+
{ name: "get_sd_campaign_performance", description: "Sponsored Display campaign metrics" },
|
|
1361
|
+
{ name: "get_sponsored_ads_report", description: "Consolidated SP/SB/SD retained report views" },
|
|
1362
|
+
{ name: "get_dsp_performance", description: "Amazon DSP order, line item, and creative metrics" },
|
|
1363
|
+
{ name: "get_dsp_advertisers_live", description: "Live Amazon DSP advertiser records" },
|
|
1364
|
+
{ name: "get_dsp_entities_live", description: "Live Amazon DSP campaigns, ad groups, and targets" },
|
|
1365
|
+
{ name: "get_store_performance", description: "Brand Store traffic, page, source, tag, and sales insights" },
|
|
1366
|
+
{ name: "get_portfolio_performance", description: "Sponsored Products portfolio-level performance rollups" },
|
|
1367
|
+
{ name: "get_sales_and_traffic", description: "Sales and traffic by ASIN" },
|
|
1368
|
+
{ name: "get_tacos", description: "Total ad cost of sales per ASIN" },
|
|
1369
|
+
{ name: "get_search_query_performance", description: "Market share and conversion data" },
|
|
1370
|
+
{ name: "get_repeat_purchase_behavior", description: "Brand Analytics repeat-purchase behavior by ASIN" },
|
|
1371
|
+
{ name: "get_search_query_ad_coverage", description: "Search queries with and without ad coverage" },
|
|
1372
|
+
{ name: "diagnose_performance", description: "SP/SB/SD root cause analysis between date ranges" },
|
|
1373
|
+
{ name: "get_sp_entities_live", description: "Live Sponsored Products entity state from Amazon" },
|
|
1374
|
+
{ name: "get_sponsored_ads_entities_live", description: "Live SP/SB/SD entity state from Amazon" },
|
|
1375
|
+
{ name: "get_sp_targeting_options", description: "Targeting candidates, categories, and negative brands" },
|
|
1376
|
+
{ name: "get_sponsored_ads_targeting_options", description: "Live SP/SB/SD targeting options and bid fields" },
|
|
1377
|
+
{ name: "create_sb_campaigns", description: "Preview or create Sponsored Brands campaigns", write: true },
|
|
1378
|
+
{ name: "update_sb_campaign_budget", description: "Preview or update Sponsored Brands campaign budgets", write: true },
|
|
1379
|
+
{ name: "update_sb_campaign_state", description: "Preview or set Sponsored Brands campaign state", write: true },
|
|
1380
|
+
{ name: "archive_sb_campaigns", description: "Preview or archive Sponsored Brands campaigns", write: true },
|
|
1381
|
+
{ name: "create_sb_ad_groups", description: "Preview or create Sponsored Brands ad groups", write: true },
|
|
1382
|
+
{ name: "update_sb_ad_group_state", description: "Preview or set Sponsored Brands ad group state", write: true },
|
|
1383
|
+
{ name: "archive_sb_ad_groups", description: "Preview or archive Sponsored Brands ad groups", write: true },
|
|
1384
|
+
{ name: "create_sb_ads", description: "Preview or create Sponsored Brands ads with caller-supplied creative", write: true },
|
|
1385
|
+
{ name: "update_sb_ad_state", description: "Preview or set Sponsored Brands ad state", write: true },
|
|
1386
|
+
{ name: "archive_sb_ads", description: "Preview or archive Sponsored Brands ads", write: true },
|
|
1387
|
+
{ name: "create_sb_targets", description: "Preview or create Sponsored Brands targets", write: true },
|
|
1388
|
+
{ name: "update_sb_target_bids", description: "Preview or update Sponsored Brands target bids", write: true },
|
|
1389
|
+
{ name: "update_sb_target_state", description: "Preview or set Sponsored Brands target state", write: true },
|
|
1390
|
+
{ name: "archive_sb_targets", description: "Preview or archive Sponsored Brands targets", write: true },
|
|
1391
|
+
{ name: "create_sb_negative_targets", description: "Preview or create Sponsored Brands negative targets", write: true },
|
|
1392
|
+
{ name: "update_sb_negative_target_state", description: "Preview or set Sponsored Brands negative target state", write: true },
|
|
1393
|
+
{ name: "archive_sb_negative_targets", description: "Preview or archive Sponsored Brands negative targets", write: true },
|
|
1394
|
+
{ name: "update_keyword_bids", description: "Preview or adjust keyword bids", write: true },
|
|
1395
|
+
{ name: "update_target_bids", description: "Preview or adjust Sponsored Products target bids", write: true },
|
|
1396
|
+
{ name: "update_keyword_state", description: "Preview or set keyword state", write: true },
|
|
1397
|
+
{ name: "archive_keywords", description: "Preview or archive keywords", write: true },
|
|
1398
|
+
{ name: "update_adgroup_bid", description: "Preview or update ad group default bids", write: true },
|
|
1399
|
+
{ name: "update_campaign_bidding", description: "Preview or adjust placement bid modifiers", write: true },
|
|
1400
|
+
{ name: "update_campaign_budget", description: "Preview or change daily campaign budget", write: true },
|
|
1401
|
+
{ name: "update_campaign_state", description: "Preview or set campaign state", write: true },
|
|
1402
|
+
{ name: "archive_campaigns", description: "Preview or archive Sponsored Products campaigns", write: true },
|
|
1403
|
+
{ name: "create_sd_campaigns", description: "Preview or create Sponsored Display campaigns", write: true },
|
|
1404
|
+
{ name: "update_sd_campaign_budget", description: "Preview or update Sponsored Display campaign budgets", write: true },
|
|
1405
|
+
{ name: "update_sd_campaign_state", description: "Preview or set Sponsored Display campaign state", write: true },
|
|
1406
|
+
{ name: "archive_sd_campaigns", description: "Preview or archive Sponsored Display campaigns", write: true },
|
|
1407
|
+
{ name: "create_sd_ad_groups", description: "Preview or create Sponsored Display ad groups", write: true },
|
|
1408
|
+
{ name: "update_sd_ad_group_bid", description: "Preview or update Sponsored Display ad group default bids", write: true },
|
|
1409
|
+
{ name: "update_sd_ad_group_state", description: "Preview or set Sponsored Display ad group state", write: true },
|
|
1410
|
+
{ name: "archive_sd_ad_groups", description: "Preview or archive Sponsored Display ad groups", write: true },
|
|
1411
|
+
{ name: "create_sd_product_ads", description: "Preview or create Sponsored Display product ads", write: true },
|
|
1412
|
+
{ name: "update_sd_product_ad_state", description: "Preview or set Sponsored Display product ad state", write: true },
|
|
1413
|
+
{ name: "archive_sd_product_ads", description: "Preview or archive Sponsored Display product ads", write: true },
|
|
1414
|
+
{ name: "create_sd_targets", description: "Preview or create Sponsored Display targets", write: true },
|
|
1415
|
+
{ name: "update_sd_target_bids", description: "Preview or update Sponsored Display target bids", write: true },
|
|
1416
|
+
{ name: "update_sd_target_state", description: "Preview or set Sponsored Display target state", write: true },
|
|
1417
|
+
{ name: "archive_sd_targets", description: "Preview or archive Sponsored Display targets", write: true },
|
|
1418
|
+
{ name: "create_sd_negative_targets", description: "Preview or create Sponsored Display negative targets", write: true },
|
|
1419
|
+
{ name: "update_sd_negative_target_state", description: "Preview or set Sponsored Display negative target state", write: true },
|
|
1420
|
+
{ name: "archive_sd_negative_targets", description: "Preview or archive Sponsored Display negative targets", write: true },
|
|
1421
|
+
{ name: "update_campaign_audience_bid_adjustment", description: "Preview or set audience bid adjustments", write: true },
|
|
1422
|
+
{ name: "create_keywords", description: "Preview or add keywords", write: true },
|
|
1423
|
+
{ name: "create_negative_keywords", description: "Preview or add negative keywords", write: true },
|
|
1424
|
+
{ name: "create_sp_campaigns", description: "Preview or create Sponsored Products campaigns", write: true },
|
|
1425
|
+
{ name: "create_sp_ad_groups", description: "Preview or create Sponsored Products ad groups", write: true },
|
|
1426
|
+
{ name: "create_sp_product_ads", description: "Preview or create Sponsored Products product ads", write: true },
|
|
1427
|
+
{ name: "update_sp_ad_entities", description: "Preview or update/archive Sponsored Products ad groups and product ads", write: true },
|
|
1428
|
+
{ name: "create_sp_targets", description: "Preview or create Sponsored Products targeting clauses", write: true },
|
|
1429
|
+
{ name: "update_sp_target_state", description: "Preview or set Sponsored Products target state", write: true },
|
|
1430
|
+
{ name: "archive_sp_targets", description: "Preview or archive Sponsored Products targets", write: true },
|
|
1431
|
+
{ name: "create_sp_negative_targets", description: "Preview or create Sponsored Products negative ASIN/brand targets", write: true },
|
|
1432
|
+
{ name: "update_sp_negative_keyword_state", description: "Preview or set Sponsored Products negative keyword state", write: true },
|
|
1433
|
+
{ name: "archive_sp_negative_keywords", description: "Preview or archive Sponsored Products negative keywords", write: true },
|
|
1434
|
+
{ name: "update_sp_negative_target_state", description: "Preview or set Sponsored Products negative target state", write: true },
|
|
1435
|
+
{ name: "archive_sp_negative_targets", description: "Preview or archive Sponsored Products negative targets", write: true },
|
|
1436
|
+
{ name: "get_bid_recommendations", description: "Live suggested bids from Amazon" },
|
|
1437
|
+
{ name: "get_budget_recommendations", description: "Live Amazon budget suggestion fields" },
|
|
1438
|
+
{ name: "get_budget_pacing", description: "Daily campaign budget usage and pacing snapshots" },
|
|
1439
|
+
{ name: "get_ad_eligibility", description: "Check ASIN eligibility for ad types" },
|
|
1440
|
+
{ name: "get_brand_health", description: "Brand Metrics funnel and peer benchmarks" },
|
|
1441
|
+
{ name: "get_share_of_voice", description: "Brand Metrics visibility and engagement signals" },
|
|
1442
|
+
{ name: "get_attribution_performance", description: "Off-Amazon Amazon Attribution performance" },
|
|
1443
|
+
{ name: "get_audience_segments", description: "Live Amazon Ads audience segment discovery" }
|
|
1444
|
+
]
|
|
1445
|
+
},
|
|
1446
|
+
{
|
|
1447
|
+
name: "Inventory",
|
|
1448
|
+
serverDomain: "inventory",
|
|
1449
|
+
tools: [
|
|
1450
|
+
{ name: "get_fba_inventory", description: "FBA stock levels and quantities" },
|
|
1451
|
+
{ name: "get_inventory_health", description: "Age buckets, weeks of cover, storage fee exposure" },
|
|
1452
|
+
{ name: "get_fba_storage_fees", description: "FBA monthly and long-term storage fee rows by ASIN/FNSKU/SKU" },
|
|
1453
|
+
{ name: "get_inventory_movements", description: "Inventory change history" },
|
|
1454
|
+
{ name: "get_inventory_by_fulfillment_center", description: "Stock levels per fulfillment center" },
|
|
1455
|
+
{ name: "get_awd_inventory", description: "AWD inbound and on-hand stock" },
|
|
1456
|
+
{ name: "get_awd_shipments", description: "AWD shipment tracking" },
|
|
1457
|
+
{ name: "get_awd_shipment_items", description: "Per-SKU AWD shipment quantities" },
|
|
1458
|
+
{ name: "get_inbound_shipments", description: "FBA inbound shipment tracking" },
|
|
1459
|
+
{ name: "get_shipment_receiving_status", description: "Per-SKU receiving progress" },
|
|
1460
|
+
{ name: "get_sales_velocity", description: "Daily sales and traffic time series" },
|
|
1461
|
+
{ name: "get_listing_registry", description: "Active listing registry, search, and brand ASIN views" },
|
|
1462
|
+
{ name: "get_suppressed_listings", description: "Suppressed and stranded listings" },
|
|
1463
|
+
{ name: "get_days_of_cover", description: "Days of stock remaining" },
|
|
1464
|
+
{ name: "get_todays_sales", description: "Today's priced/estimated revenue by ASIN" },
|
|
1465
|
+
{ name: "get_orders", description: "Order list with filters" },
|
|
1466
|
+
{ name: "get_order_details", description: "Per-order line items" },
|
|
1467
|
+
{ name: "get_returns", description: "FBA return records" },
|
|
1468
|
+
{ name: "get_reimbursements", description: "FBA reimbursement records" },
|
|
1469
|
+
{ name: "get_seasonality_index", description: "52-week demand curve with events" },
|
|
1470
|
+
{ name: "get_sales_summary", description: "Daily final/priced revenue and estimates" },
|
|
1471
|
+
{ name: "get_inventory_risk_triage", description: "SKUs at risk: low stock, overstock, aged, or stranded" },
|
|
1472
|
+
{ name: "get_current_rank", description: "Live keyword rank check via catalog search" },
|
|
1473
|
+
{ name: "get_buybox_status", description: "Live Buy Box status plus daily win-rate history" },
|
|
1474
|
+
{ name: "get_competitive_pricing", description: "Live price points plus historical pricing snapshots" },
|
|
1475
|
+
{ name: "get_offer_listings", description: "Live seller offers for an ASIN" },
|
|
1476
|
+
{ name: "get_replenishment_offers", description: "Live and historical Subscribe and Save replenishment offer status" },
|
|
1477
|
+
{ name: "get_fba_eligibility", description: "Check FBA eligibility per ASIN" },
|
|
1478
|
+
{ name: "get_listing_restrictions", description: "Listing restrictions and approvals" }
|
|
1479
|
+
]
|
|
1480
|
+
},
|
|
1481
|
+
{
|
|
1482
|
+
name: "Finance",
|
|
1483
|
+
serverDomain: "finance",
|
|
1484
|
+
tools: [
|
|
1485
|
+
{ name: "get_financial_events", description: "Financial event fee breakdown by ASIN/order and profitability views" },
|
|
1486
|
+
{ name: "get_profitability_review", description: "Per-ASIN profitability across fees, returns, and ad spend" },
|
|
1487
|
+
{ name: "get_payment_transactions", description: "Live Amazon Payments transaction rows and summaries" },
|
|
1488
|
+
{ name: "get_settlement_economics", description: "Settlement-finalized financial data" }
|
|
1489
|
+
]
|
|
1490
|
+
},
|
|
1491
|
+
{
|
|
1492
|
+
name: "Catalog",
|
|
1493
|
+
serverDomain: "catalog",
|
|
1494
|
+
tools: [
|
|
1495
|
+
{ name: "get_product_details", description: "Product info, images, dimensions" },
|
|
1496
|
+
{ name: "get_sales_ranks", description: "Best seller rank by category" },
|
|
1497
|
+
{ name: "get_aplus_status", description: "A+ Content status and associated ASINs" },
|
|
1498
|
+
{ name: "get_variations", description: "Parent/child variation relationships" },
|
|
1499
|
+
{ name: "get_product_reviews", description: "Customer review topics and snippets" },
|
|
1500
|
+
{ name: "get_review_trends", description: "Six-month review topic trends" },
|
|
1501
|
+
{ name: "get_listing_quality", description: "Listing completeness scores and issues" },
|
|
1502
|
+
{ name: "get_catalog_cleanup", description: "Listings with quality issues to fix" },
|
|
1503
|
+
{ name: "create_listing", description: "Validate or submit a listing creation request", write: true },
|
|
1504
|
+
{ name: "update_listing", description: "Update listing attributes with preview and audit trail", write: true },
|
|
1505
|
+
{ name: "update_price", description: "Submit listing price updates through the Listings Items API", write: true },
|
|
1506
|
+
{ name: "update_inventory_quantity", description: "Update seller-fulfilled listing quantities", write: true }
|
|
1507
|
+
]
|
|
1508
|
+
},
|
|
1509
|
+
{
|
|
1510
|
+
name: "Ranking",
|
|
1511
|
+
serverDomain: "ranking",
|
|
1512
|
+
tools: [
|
|
1513
|
+
{ name: "get_keyword_ranks", description: "Keyword rank positions, changes, and SQP volume views" }
|
|
1514
|
+
]
|
|
1515
|
+
},
|
|
1516
|
+
{
|
|
1517
|
+
name: "Fulfillment",
|
|
1518
|
+
serverDomain: "fulfillment",
|
|
1519
|
+
tools: [
|
|
1520
|
+
{ name: "get_shipping_preview", description: "MCF shipping options and cost estimates" },
|
|
1521
|
+
{ name: "get_mcf_orders", description: "Multi-Channel Fulfillment order list" },
|
|
1522
|
+
{ name: "create_mcf_order", description: "Submit MCF order request from FBA inventory", write: true },
|
|
1523
|
+
{ name: "manage_returns", description: "MCF return authorization", write: true }
|
|
1524
|
+
]
|
|
1525
|
+
}
|
|
1526
|
+
];
|
|
1527
|
+
var DISABLED_WRITE_TOOL_MARKERS = TOOL_DOMAINS.map(
|
|
1528
|
+
(domain) => `${DISABLE_WRITE_TOOLS_FOR_DOMAIN_PREFIX}${domain.serverDomain}`
|
|
1529
|
+
);
|
|
1530
|
+
var UTILITY_TOOLS = [
|
|
1531
|
+
{
|
|
1532
|
+
name: "get_account_data_tour",
|
|
1533
|
+
description: "Return a first-run account data tour with trust preflight, business pulse, spotlight products, neutral cross-domain signals, and evidence handles"
|
|
1534
|
+
},
|
|
1535
|
+
{
|
|
1536
|
+
name: "submit_conversation_feedback",
|
|
1537
|
+
description: "Submit a redacted structured product-quality report after the user explicitly asks agentcentral to receive feedback"
|
|
1538
|
+
},
|
|
1539
|
+
{
|
|
1540
|
+
name: "get_account_info",
|
|
1541
|
+
description: "Return the marketplace scope, connection status, tool availability, and next-step guidance for the active API key"
|
|
1542
|
+
},
|
|
1543
|
+
{
|
|
1544
|
+
name: "get_action_history",
|
|
1545
|
+
description: "Return tenant-wide write audit history when the active API key has action-history read permission"
|
|
1546
|
+
}
|
|
1547
|
+
];
|
|
1548
|
+
var TOOL_COUNTS_BY_DOMAIN = TOOL_DOMAINS.reduce(
|
|
1549
|
+
(counts, domain) => {
|
|
1550
|
+
counts[domain.serverDomain] = {
|
|
1551
|
+
domainTools: domain.tools.length,
|
|
1552
|
+
writeTools: domain.tools.filter((tool) => tool.write).length
|
|
1553
|
+
};
|
|
1554
|
+
return counts;
|
|
1555
|
+
},
|
|
1556
|
+
{}
|
|
1557
|
+
);
|
|
1558
|
+
var DATA_DOMAIN_COUNT = TOOL_DOMAINS.length;
|
|
1559
|
+
var DOMAIN_SCOPED_TOOL_COUNT = TOOL_DOMAINS.reduce((sum, domain) => sum + domain.tools.length, 0);
|
|
1560
|
+
var UTILITY_TOOL_COUNT = UTILITY_TOOLS.length;
|
|
1561
|
+
var SHIPPED_TOOL_COUNT = DOMAIN_SCOPED_TOOL_COUNT + UTILITY_TOOL_COUNT;
|
|
1562
|
+
var WRITE_TOOL_COUNT = TOOL_DOMAINS.reduce(
|
|
1563
|
+
(sum, domain) => sum + domain.tools.filter((tool) => tool.write).length,
|
|
1564
|
+
0
|
|
1565
|
+
);
|
|
1566
|
+
var TOOL_NAMES = /* @__PURE__ */ new Set(
|
|
1567
|
+
[
|
|
1568
|
+
...TOOL_DOMAINS.flatMap((d) => d.tools.map((t) => t.name)),
|
|
1569
|
+
...UTILITY_TOOLS.map((t) => t.name)
|
|
1570
|
+
]
|
|
1571
|
+
);
|
|
1572
|
+
var DOMAIN_WRITE_TOOL_NAMES = new Set(
|
|
1573
|
+
TOOL_DOMAINS.flatMap(
|
|
1574
|
+
(domain) => domain.tools.filter((tool) => tool.write).map((tool) => tool.name)
|
|
1575
|
+
)
|
|
1576
|
+
);
|
|
1577
|
+
var VALID_DISABLED_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
1578
|
+
...TOOL_NAMES,
|
|
1579
|
+
...DISABLED_WRITE_TOOL_MARKERS
|
|
1580
|
+
]);
|
|
1581
|
+
var CURRENT_WRITE_TOOL_NAMES_BY_DOMAIN = TOOL_DOMAINS.reduce(
|
|
1582
|
+
(byDomain, domain) => {
|
|
1583
|
+
byDomain[domain.serverDomain] = domain.tools.filter((tool) => tool.write).map((tool) => tool.name);
|
|
1584
|
+
return byDomain;
|
|
1585
|
+
},
|
|
1586
|
+
{}
|
|
1587
|
+
);
|
|
1588
|
+
var DATA_COVERAGE_STATUSES = ["success", "partial", "failure"];
|
|
1589
|
+
var DATA_COVERAGE_GRANULARITIES = ["day", "week", "month", "quarter", "snapshot", "event"];
|
|
1590
|
+
var DataCoverageStatusSchema = z22.enum(DATA_COVERAGE_STATUSES);
|
|
1591
|
+
var DataCoverageGranularitySchema = z22.enum(DATA_COVERAGE_GRANULARITIES);
|
|
1592
|
+
var DataCoverageRowSchema = z22.object({
|
|
1593
|
+
coverage_id: z22.string(),
|
|
1594
|
+
tenant_id: z22.string(),
|
|
1595
|
+
sync_mode: z22.string(),
|
|
1596
|
+
table_name: z22.string(),
|
|
1597
|
+
source_type: z22.string(),
|
|
1598
|
+
coverage_granularity: DataCoverageGranularitySchema,
|
|
1599
|
+
coverage_start_date: z22.string().nullable(),
|
|
1600
|
+
coverage_end_date: z22.string().nullable(),
|
|
1601
|
+
marketplace_id: z22.string().nullable(),
|
|
1602
|
+
connection_id: z22.string().nullable().optional(),
|
|
1603
|
+
profile_id: z22.string().nullable(),
|
|
1604
|
+
status: DataCoverageStatusSchema,
|
|
1605
|
+
rows_loaded: z22.number().int().nonnegative(),
|
|
1606
|
+
checked_at: z22.string(),
|
|
1607
|
+
error_message: z22.string().nullable(),
|
|
1608
|
+
trigger_source: z22.string(),
|
|
1609
|
+
snapshot_date: z22.string()
|
|
1610
|
+
});
|
|
1611
|
+
var ADS_DAILY_LAG_DAYS = 1;
|
|
1612
|
+
var ADS_LOOKBACK_DAYS = 14;
|
|
1613
|
+
var SP_DAILY_LAG_DAYS = 1;
|
|
1614
|
+
var SP_LOOKBACK_DAYS = 14;
|
|
1615
|
+
var SNAPSHOT_FRESHNESS_HOURS = 36;
|
|
1616
|
+
var WEEKLY_LAG_DAYS = 8;
|
|
1617
|
+
var DATA_HEALTH_TABLE_POLICIES = [
|
|
1618
|
+
{ syncMode: "campaign_snapshots", tableName: TABLES.campaignSnapshots, label: "SP campaign entity snapshot", coverageGranularity: "snapshot", required: true, freshnessHours: SNAPSHOT_FRESHNESS_HOURS },
|
|
1619
|
+
{ syncMode: "ad_change_history", tableName: TABLES.adsChangeHistory, label: "Amazon Ads change history", coverageGranularity: "event", required: false, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: 90 },
|
|
1620
|
+
{ syncMode: "budget_usage", tableName: TABLES.budgetUsage, label: "SP budget usage snapshot", coverageGranularity: "snapshot", required: false, freshnessHours: SNAPSHOT_FRESHNESS_HOURS },
|
|
1621
|
+
{ syncMode: "attribution", tableName: TABLES.attributionPerformance, label: "Amazon Attribution", coverageGranularity: "day", required: false, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1622
|
+
{ syncMode: "dsp_reporting", tableName: TABLES.dspPerformance, label: "DSP performance", coverageGranularity: "day", required: false, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1623
|
+
{ syncMode: "store_insights", tableName: TABLES.storeInsights, label: "Brand Store insights", coverageGranularity: "day", required: false, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1624
|
+
{ syncMode: "ads", tableName: TABLES.campaigns, label: "SP campaigns", coverageGranularity: "day", required: true, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1625
|
+
{ syncMode: "ads", tableName: TABLES.adgroups, label: "SP ad groups", coverageGranularity: "day", required: true, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1626
|
+
{ syncMode: "ads", tableName: TABLES.placements, label: "SP placements", coverageGranularity: "day", required: true, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1627
|
+
{ syncMode: "ads", tableName: TABLES.advertisedProducts, label: "SP advertised products", coverageGranularity: "day", required: true, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1628
|
+
{ syncMode: "ads", tableName: TABLES.purchasedProducts, label: "SP purchased products", coverageGranularity: "day", required: true, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1629
|
+
{ syncMode: "ads", tableName: TABLES.searchTerms, label: "SP search terms", coverageGranularity: "day", required: true, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1630
|
+
{ syncMode: "ads", tableName: TABLES.targeting, label: "SP targeting", coverageGranularity: "day", required: true, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1631
|
+
{ syncMode: "ads", tableName: TABLES.spGrossAndInvalids, label: "SP gross and invalid traffic", coverageGranularity: "day", required: false, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1632
|
+
{ syncMode: "sb_ads", tableName: TABLES.sbCampaigns, label: "SB campaigns", coverageGranularity: "day", required: true, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1633
|
+
{ syncMode: "sb_ads", tableName: TABLES.sbAds, label: "SB ads", coverageGranularity: "day", required: true, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1634
|
+
{ syncMode: "sb_ads", tableName: TABLES.sbSearchTerms, label: "SB search terms", coverageGranularity: "day", required: true, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1635
|
+
{ syncMode: "sb_ads", tableName: TABLES.sbTargeting, label: "SB targeting", coverageGranularity: "day", required: true, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1636
|
+
{ syncMode: "sb_ads", tableName: TABLES.sbPurchasedProducts, label: "SB purchased products", coverageGranularity: "day", required: true, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1637
|
+
{ syncMode: "sb_ads", tableName: TABLES.sbGrossAndInvalids, label: "SB gross and invalid traffic", coverageGranularity: "day", required: false, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1638
|
+
{ syncMode: "sd_ads", tableName: TABLES.sdCampaigns, label: "SD campaigns", coverageGranularity: "day", required: true, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1639
|
+
{ syncMode: "sd_ads", tableName: TABLES.sdAdvertisedProducts, label: "SD advertised products", coverageGranularity: "day", required: true, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1640
|
+
{ syncMode: "sd_ads", tableName: TABLES.sdTargeting, label: "SD targeting", coverageGranularity: "day", required: true, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1641
|
+
{ syncMode: "sd_ads", tableName: TABLES.sdPurchasedProducts, label: "SD purchased products", coverageGranularity: "day", required: true, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1642
|
+
{ syncMode: "sd_ads", tableName: TABLES.sdGrossAndInvalids, label: "SD gross and invalid traffic", coverageGranularity: "day", required: false, expectedLagDays: ADS_DAILY_LAG_DAYS, lookbackDays: ADS_LOOKBACK_DAYS },
|
|
1643
|
+
{ syncMode: "business", tableName: TABLES.salesAndTraffic, label: "Sales and traffic", coverageGranularity: "day", required: true, expectedLagDays: SP_DAILY_LAG_DAYS, lookbackDays: SP_LOOKBACK_DAYS },
|
|
1644
|
+
{ syncMode: "inventory", tableName: TABLES.inventoryLedger, label: "Inventory ledger", coverageGranularity: "day", required: true, expectedLagDays: SP_DAILY_LAG_DAYS, lookbackDays: SP_LOOKBACK_DAYS },
|
|
1645
|
+
{ syncMode: "returns", tableName: TABLES.returns, label: "FBA returns", coverageGranularity: "day", required: true, expectedLagDays: 2, lookbackDays: 30 },
|
|
1646
|
+
{ syncMode: "reimbursements", tableName: TABLES.reimbursements, label: "FBA reimbursements", coverageGranularity: "day", required: true, expectedLagDays: 2, lookbackDays: 14 },
|
|
1647
|
+
{ syncMode: "order_metrics", tableName: TABLES.orderMetrics, label: "Order metrics", coverageGranularity: "snapshot", required: true, freshnessHours: SNAPSHOT_FRESHNESS_HOURS },
|
|
1648
|
+
{ syncMode: "sqp", tableName: TABLES.sqp, label: "Search Query Performance", coverageGranularity: "week", required: true, expectedLagDays: WEEKLY_LAG_DAYS, lookbackDays: 35 },
|
|
1649
|
+
{ syncMode: "brand_metrics", tableName: TABLES.brandMetrics, label: "Brand Metrics", coverageGranularity: "week", required: false, expectedLagDays: WEEKLY_LAG_DAYS, lookbackDays: 35 },
|
|
1650
|
+
{ syncMode: "ba_search_terms", tableName: TABLES.baSearchTerms, label: "Brand Analytics search terms", coverageGranularity: "week", required: false, expectedLagDays: WEEKLY_LAG_DAYS, lookbackDays: 35 },
|
|
1651
|
+
{ syncMode: "ba_market_basket", tableName: TABLES.baMarketBasket, label: "Brand Analytics market basket", coverageGranularity: "week", required: false, expectedLagDays: WEEKLY_LAG_DAYS, lookbackDays: 35 },
|
|
1652
|
+
{ syncMode: "ba_repeat_purchase", tableName: TABLES.baRepeatPurchase, label: "Brand Analytics repeat purchase", coverageGranularity: "week", required: false, expectedLagDays: WEEKLY_LAG_DAYS, lookbackDays: 35 },
|
|
1653
|
+
{ syncMode: "ba_search_catalog", tableName: TABLES.baSearchCatalog, label: "Brand Analytics search catalog", coverageGranularity: "week", required: false, expectedLagDays: WEEKLY_LAG_DAYS, lookbackDays: 35 },
|
|
1654
|
+
{ syncMode: "inventory", tableName: TABLES.fbaInventory, label: "FBA inventory snapshot", coverageGranularity: "snapshot", required: true, freshnessHours: SNAPSHOT_FRESHNESS_HOURS },
|
|
1655
|
+
{ syncMode: "inventory", tableName: TABLES.inventoryHealth, label: "Inventory health snapshot", coverageGranularity: "snapshot", required: true, freshnessHours: SNAPSHOT_FRESHNESS_HOURS },
|
|
1656
|
+
{ syncMode: "listings", tableName: TABLES.activeListings, label: "Active listings snapshot", coverageGranularity: "snapshot", required: true, freshnessHours: SNAPSHOT_FRESHNESS_HOURS },
|
|
1657
|
+
{ syncMode: "suppressed_listings", tableName: TABLES.suppressedListings, label: "Suppressed listings snapshot", coverageGranularity: "snapshot", required: false, freshnessHours: SNAPSHOT_FRESHNESS_HOURS },
|
|
1658
|
+
{ syncMode: "awd", tableName: TABLES.awdInventory, label: "AWD inventory snapshot", coverageGranularity: "snapshot", required: false, freshnessHours: SNAPSHOT_FRESHNESS_HOURS },
|
|
1659
|
+
{ syncMode: "fba_inbound", tableName: TABLES.fbaInboundShipments, label: "FBA inbound shipments", coverageGranularity: "snapshot", required: false, freshnessHours: 36 },
|
|
1660
|
+
{ syncMode: "fees", tableName: TABLES.referralFees, label: "Referral fees snapshot", coverageGranularity: "snapshot", required: false, freshnessHours: 168 },
|
|
1661
|
+
{ syncMode: "fees", tableName: TABLES.fbaStorageFeeCharges, label: "FBA storage fee charges", coverageGranularity: "snapshot", required: false, freshnessHours: 168 },
|
|
1662
|
+
{ syncMode: "fees", tableName: TABLES.fbaLongTermStorageFeeCharges, label: "FBA long-term storage fee charges", coverageGranularity: "day", required: false, expectedLagDays: 35, lookbackDays: 45 },
|
|
1663
|
+
{ syncMode: "catalog", tableName: TABLES.catalogItems, label: "Catalog snapshot", coverageGranularity: "snapshot", required: true, freshnessHours: 48 },
|
|
1664
|
+
{ syncMode: "listing_quality", tableName: TABLES.listingQuality, label: "Listing quality snapshot", coverageGranularity: "snapshot", required: false, freshnessHours: 192 },
|
|
1665
|
+
{ syncMode: "pricing", tableName: TABLES.pricingSnapshots, label: "Pricing snapshot", coverageGranularity: "snapshot", required: false, freshnessHours: 48 },
|
|
1666
|
+
{ syncMode: "replenishment", tableName: TABLES.replenishmentOffers, label: "Replenishment offers snapshot", coverageGranularity: "snapshot", required: false, freshnessHours: 48 },
|
|
1667
|
+
{ syncMode: "customer_feedback", tableName: TABLES.customerFeedbackSnapshots, label: "Customer Feedback snapshot", coverageGranularity: "snapshot", required: false, freshnessHours: 192 },
|
|
1668
|
+
{ syncMode: "keyword_rank", tableName: TABLES.keywordRanks, label: "Keyword rank snapshot", coverageGranularity: "snapshot", required: false, freshnessHours: 192 },
|
|
1669
|
+
{ syncMode: "settlements", tableName: TABLES.settlements, label: "Settlements reports", coverageGranularity: "event", required: true, freshnessHours: 72 },
|
|
1670
|
+
{ syncMode: "financial_events", tableName: TABLES.financialEvents, label: "Financial events", coverageGranularity: "event", required: true, freshnessHours: 36 }
|
|
1671
|
+
];
|
|
1672
|
+
var MAX_REPORT_SECTIONS = 12;
|
|
1673
|
+
var MAX_REPORT_KPIS = 12;
|
|
1674
|
+
var MAX_REPORT_TABLE_ROWS = 250;
|
|
1675
|
+
var MAX_REPORT_CHART_ROWS = 120;
|
|
1676
|
+
var MAX_REPORT_CHART_SERIES = 6;
|
|
1677
|
+
var MAX_REPORT_COLUMNS = 12;
|
|
1678
|
+
var MAX_REPORT_SPEC_BYTES = 512 * 1024;
|
|
1679
|
+
var KEY_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]{0,63}$/;
|
|
1680
|
+
var ANCHOR_PATTERN = /^[a-zA-Z][a-zA-Z0-9_-]{0,79}$/;
|
|
1681
|
+
var shortText = (max) => z3.string().trim().min(1).max(max);
|
|
1682
|
+
var optionalText = (max) => z3.preprocess(
|
|
1683
|
+
(value) => value === null || value === "" ? void 0 : value,
|
|
1684
|
+
z3.string().trim().min(1).max(max).optional()
|
|
1685
|
+
);
|
|
1686
|
+
var reportKeySchema = z3.string().regex(KEY_PATTERN, "Use letters, numbers, and underscores; start with a letter or underscore").describe("Row key used by table columns and chart axes");
|
|
1687
|
+
var reportCellValueSchema = z3.union([
|
|
1688
|
+
z3.string().max(1e3),
|
|
1689
|
+
z3.number().finite(),
|
|
1690
|
+
z3.boolean(),
|
|
1691
|
+
z3.null()
|
|
1692
|
+
]);
|
|
1693
|
+
var reportColumnSchema = z3.object({
|
|
1694
|
+
key: reportKeySchema,
|
|
1695
|
+
label: shortText(80),
|
|
1696
|
+
type: z3.enum(["text", "number", "currency", "percent", "date", "boolean", "image"]).default("text")
|
|
1697
|
+
}).strict();
|
|
1698
|
+
var baseSectionSchema = z3.object({
|
|
1699
|
+
id: z3.string().regex(ANCHOR_PATTERN, "Use letters, numbers, dashes, and underscores; start with a letter").optional(),
|
|
1700
|
+
title: optionalText(120),
|
|
1701
|
+
description: optionalText(500)
|
|
1702
|
+
}).strict();
|
|
1703
|
+
var reportToneSchema = z3.enum(["neutral", "info", "good", "warning", "bad"]);
|
|
1704
|
+
var reportKpiSchema = z3.object({
|
|
1705
|
+
label: shortText(80),
|
|
1706
|
+
value: z3.union([z3.string().max(200), z3.number().finite()]),
|
|
1707
|
+
unit: optionalText(24),
|
|
1708
|
+
change: optionalText(120),
|
|
1709
|
+
tone: reportToneSchema.default("neutral")
|
|
1710
|
+
}).strict();
|
|
1711
|
+
var reportKpiGridSectionSchema = baseSectionSchema.extend({
|
|
1712
|
+
type: z3.literal("kpi_grid"),
|
|
1713
|
+
kpis: z3.array(reportKpiSchema).min(1).max(MAX_REPORT_KPIS)
|
|
1714
|
+
});
|
|
1715
|
+
var tableRowsSchema = z3.array(z3.record(reportCellValueSchema)).max(MAX_REPORT_TABLE_ROWS);
|
|
1716
|
+
function isValidReportImageUrl(value) {
|
|
1717
|
+
try {
|
|
1718
|
+
const url = new URL(value);
|
|
1719
|
+
return url.protocol === "https:" && !url.username && !url.password;
|
|
1720
|
+
} catch {
|
|
1721
|
+
return false;
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
var reportTableSectionSchema = baseSectionSchema.extend({
|
|
1725
|
+
type: z3.literal("table"),
|
|
1726
|
+
columns: z3.array(reportColumnSchema).min(1).max(MAX_REPORT_COLUMNS),
|
|
1727
|
+
rows: tableRowsSchema,
|
|
1728
|
+
total_rows: z3.number().int().nonnegative().optional(),
|
|
1729
|
+
truncated: z3.boolean().default(false)
|
|
1730
|
+
}).superRefine((section, ctx) => {
|
|
1731
|
+
const columnKeys = section.columns.map((column) => column.key);
|
|
1732
|
+
const uniqueKeys = new Set(columnKeys);
|
|
1733
|
+
if (uniqueKeys.size !== columnKeys.length) {
|
|
1734
|
+
ctx.addIssue({
|
|
1735
|
+
code: z3.ZodIssueCode.custom,
|
|
1736
|
+
path: ["columns"],
|
|
1737
|
+
message: "Column keys must be unique"
|
|
1738
|
+
});
|
|
1739
|
+
}
|
|
1740
|
+
for (const [rowIndex, row] of section.rows.entries()) {
|
|
1741
|
+
for (const key of Object.keys(row)) {
|
|
1742
|
+
if (!uniqueKeys.has(key)) {
|
|
1743
|
+
ctx.addIssue({
|
|
1744
|
+
code: z3.ZodIssueCode.custom,
|
|
1745
|
+
path: ["rows", rowIndex, key],
|
|
1746
|
+
message: `Unknown table column key: ${key}`
|
|
1747
|
+
});
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
const imageKeys = new Set(section.columns.filter((column) => column.type === "image").map((column) => column.key));
|
|
1752
|
+
for (const [rowIndex, row] of section.rows.entries()) {
|
|
1753
|
+
for (const key of imageKeys) {
|
|
1754
|
+
const value = row[key];
|
|
1755
|
+
if (value === void 0 || value === null) continue;
|
|
1756
|
+
if (typeof value !== "string" || !isValidReportImageUrl(value)) {
|
|
1757
|
+
ctx.addIssue({
|
|
1758
|
+
code: z3.ZodIssueCode.custom,
|
|
1759
|
+
path: ["rows", rowIndex, key],
|
|
1760
|
+
message: "Image columns must contain HTTPS image URLs or null"
|
|
1761
|
+
});
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
if (section.total_rows !== void 0 && section.total_rows < section.rows.length) {
|
|
1766
|
+
ctx.addIssue({
|
|
1767
|
+
code: z3.ZodIssueCode.custom,
|
|
1768
|
+
path: ["total_rows"],
|
|
1769
|
+
message: "total_rows must be greater than or equal to the rendered row count"
|
|
1770
|
+
});
|
|
1771
|
+
}
|
|
1772
|
+
});
|
|
1773
|
+
var chartRowsSchema = z3.array(z3.record(reportCellValueSchema)).min(1).max(MAX_REPORT_CHART_ROWS);
|
|
1774
|
+
var reportChartSeriesSchema = z3.object({
|
|
1775
|
+
key: reportKeySchema,
|
|
1776
|
+
label: shortText(80),
|
|
1777
|
+
tone: reportToneSchema.optional()
|
|
1778
|
+
}).strict();
|
|
1779
|
+
var chartBaseSectionSchema = baseSectionSchema.extend({
|
|
1780
|
+
x_key: reportKeySchema,
|
|
1781
|
+
y_key: reportKeySchema.optional(),
|
|
1782
|
+
series: z3.array(reportChartSeriesSchema).min(1).max(MAX_REPORT_CHART_SERIES).optional(),
|
|
1783
|
+
x_label: optionalText(80),
|
|
1784
|
+
y_label: optionalText(80),
|
|
1785
|
+
value_type: z3.enum(["number", "currency", "percent"]).default("number"),
|
|
1786
|
+
stacked: z3.boolean().default(false),
|
|
1787
|
+
rows: chartRowsSchema
|
|
1788
|
+
});
|
|
1789
|
+
function validateChartRows(section, ctx) {
|
|
1790
|
+
const series = section.series ?? (section.y_key ? [{ key: section.y_key, label: section.y_label ?? section.y_key }] : []);
|
|
1791
|
+
if (series.length === 0) {
|
|
1792
|
+
ctx.addIssue({
|
|
1793
|
+
code: z3.ZodIssueCode.custom,
|
|
1794
|
+
path: ["y_key"],
|
|
1795
|
+
message: "Provide y_key or at least one series entry"
|
|
1796
|
+
});
|
|
1797
|
+
}
|
|
1798
|
+
const seriesKeys = series.map((item) => item.key);
|
|
1799
|
+
if (new Set(seriesKeys).size !== seriesKeys.length) {
|
|
1800
|
+
ctx.addIssue({
|
|
1801
|
+
code: z3.ZodIssueCode.custom,
|
|
1802
|
+
path: ["series"],
|
|
1803
|
+
message: "Series keys must be unique"
|
|
1804
|
+
});
|
|
1805
|
+
}
|
|
1806
|
+
for (const [rowIndex, row] of section.rows.entries()) {
|
|
1807
|
+
if (!(section.x_key in row)) {
|
|
1808
|
+
ctx.addIssue({
|
|
1809
|
+
code: z3.ZodIssueCode.custom,
|
|
1810
|
+
path: ["rows", rowIndex, section.x_key],
|
|
1811
|
+
message: `Missing x_key value: ${section.x_key}`
|
|
1812
|
+
});
|
|
1813
|
+
}
|
|
1814
|
+
for (const item of series) {
|
|
1815
|
+
if (!(item.key in row)) {
|
|
1816
|
+
ctx.addIssue({
|
|
1817
|
+
code: z3.ZodIssueCode.custom,
|
|
1818
|
+
path: ["rows", rowIndex, item.key],
|
|
1819
|
+
message: `Missing chart series value: ${item.key}`
|
|
1820
|
+
});
|
|
1821
|
+
continue;
|
|
1822
|
+
}
|
|
1823
|
+
if (typeof row[item.key] !== "number") {
|
|
1824
|
+
ctx.addIssue({
|
|
1825
|
+
code: z3.ZodIssueCode.custom,
|
|
1826
|
+
path: ["rows", rowIndex, item.key],
|
|
1827
|
+
message: `Chart series must reference numeric values: ${item.key}`
|
|
1828
|
+
});
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
var reportBarChartSectionSchema = chartBaseSectionSchema.extend({
|
|
1834
|
+
type: z3.literal("bar_chart")
|
|
1835
|
+
}).superRefine(validateChartRows);
|
|
1836
|
+
var reportLineChartSectionSchema = chartBaseSectionSchema.extend({
|
|
1837
|
+
type: z3.literal("line_chart")
|
|
1838
|
+
}).superRefine(validateChartRows);
|
|
1839
|
+
var reportNoteSectionSchema = baseSectionSchema.extend({
|
|
1840
|
+
type: z3.literal("note"),
|
|
1841
|
+
body: shortText(2e3),
|
|
1842
|
+
tone: reportToneSchema.default("neutral")
|
|
1843
|
+
});
|
|
1844
|
+
var reportSectionSchema = z3.union([
|
|
1845
|
+
reportKpiGridSectionSchema,
|
|
1846
|
+
reportTableSectionSchema,
|
|
1847
|
+
reportBarChartSectionSchema,
|
|
1848
|
+
reportLineChartSectionSchema,
|
|
1849
|
+
reportNoteSectionSchema
|
|
1850
|
+
]);
|
|
1851
|
+
var reportSpecV1Schema = z3.object({
|
|
1852
|
+
title: shortText(140),
|
|
1853
|
+
summary: optionalText(1e3),
|
|
1854
|
+
source: optionalText(500),
|
|
1855
|
+
sections: z3.array(reportSectionSchema).min(1).max(MAX_REPORT_SECTIONS)
|
|
1856
|
+
}).strict().superRefine((spec, ctx) => {
|
|
1857
|
+
const bytes = Buffer.byteLength(JSON.stringify(spec), "utf8");
|
|
1858
|
+
if (bytes > MAX_REPORT_SPEC_BYTES) {
|
|
1859
|
+
ctx.addIssue({
|
|
1860
|
+
code: z3.ZodIssueCode.custom,
|
|
1861
|
+
path: [],
|
|
1862
|
+
message: `Report spec exceeds ${MAX_REPORT_SPEC_BYTES} bytes`
|
|
1863
|
+
});
|
|
1864
|
+
}
|
|
1865
|
+
});
|
|
1866
|
+
var CURRENCY_MONEY_POLICIES = Object.freeze({
|
|
1867
|
+
USD: { currencyCode: "USD", minorUnit: 2, defaultDisplayLocale: "en-US", minBid: 0.02, maxBid: 100, maxPrice: 1e4 },
|
|
1868
|
+
CAD: { currencyCode: "CAD", minorUnit: 2, defaultDisplayLocale: "en-CA", minBid: 0.02, maxBid: 100, maxPrice: 1e4 },
|
|
1869
|
+
GBP: { currencyCode: "GBP", minorUnit: 2, defaultDisplayLocale: "en-GB", minBid: 0.02, maxBid: 100, maxPrice: 1e4 },
|
|
1870
|
+
EUR: { currencyCode: "EUR", minorUnit: 2, defaultDisplayLocale: "de-DE", minBid: 0.02, maxBid: 100, maxPrice: 1e4 },
|
|
1871
|
+
MXN: { currencyCode: "MXN", minorUnit: 2, defaultDisplayLocale: "es-MX", minBid: 0.1, maxBid: 2e3, maxPrice: 2e5 },
|
|
1872
|
+
BRL: { currencyCode: "BRL", minorUnit: 2, defaultDisplayLocale: "pt-BR", minBid: 0.05, maxBid: 500, maxPrice: 5e4 },
|
|
1873
|
+
SEK: { currencyCode: "SEK", minorUnit: 2, defaultDisplayLocale: "sv-SE", minBid: 0.1, maxBid: 1e3, maxPrice: 1e5 },
|
|
1874
|
+
ZAR: { currencyCode: "ZAR", minorUnit: 2, defaultDisplayLocale: "en-ZA", minBid: 0.1, maxBid: 1500, maxPrice: 15e4 },
|
|
1875
|
+
PLN: { currencyCode: "PLN", minorUnit: 2, defaultDisplayLocale: "pl-PL", minBid: 0.05, maxBid: 400, maxPrice: 4e4 },
|
|
1876
|
+
EGP: { currencyCode: "EGP", minorUnit: 2, defaultDisplayLocale: "ar-EG", minBid: 0.5, maxBid: 3e3, maxPrice: 3e5 },
|
|
1877
|
+
TRY: { currencyCode: "TRY", minorUnit: 2, defaultDisplayLocale: "tr-TR", minBid: 0.1, maxBid: 2e3, maxPrice: 2e5 },
|
|
1878
|
+
AED: { currencyCode: "AED", minorUnit: 2, defaultDisplayLocale: "ar-AE", minBid: 0.1, maxBid: 350, maxPrice: 35e3 },
|
|
1879
|
+
INR: { currencyCode: "INR", minorUnit: 2, defaultDisplayLocale: "en-IN", minBid: 1, maxBid: 5e3, maxPrice: 5e5 },
|
|
1880
|
+
SGD: { currencyCode: "SGD", minorUnit: 2, defaultDisplayLocale: "en-SG", minBid: 0.02, maxBid: 150, maxPrice: 15e3 },
|
|
1881
|
+
JPY: { currencyCode: "JPY", minorUnit: 0, defaultDisplayLocale: "ja-JP", minBid: 2, maxBid: 1e4, maxPrice: 1e6 },
|
|
1882
|
+
AUD: { currencyCode: "AUD", minorUnit: 2, defaultDisplayLocale: "en-AU", minBid: 0.02, maxBid: 150, maxPrice: 15e3 },
|
|
1883
|
+
SAR: { currencyCode: "SAR", minorUnit: 2, defaultDisplayLocale: "ar-SA", minBid: 0.1, maxBid: 350, maxPrice: 35e3 }
|
|
1884
|
+
});
|
|
1885
|
+
function fallbackMoneyPolicyForKnownCurrency(currencyCode) {
|
|
1886
|
+
return {
|
|
1887
|
+
currencyCode,
|
|
1888
|
+
minorUnit: 2,
|
|
1889
|
+
defaultDisplayLocale: "en",
|
|
1890
|
+
minBid: 0.02,
|
|
1891
|
+
maxBid: 100,
|
|
1892
|
+
maxPrice: 1e4
|
|
1893
|
+
};
|
|
1894
|
+
}
|
|
1895
|
+
function getMarketplaceMoneyPolicyForDefinition(marketplace) {
|
|
1896
|
+
return CURRENCY_MONEY_POLICIES[marketplace.currencyCode] ?? fallbackMoneyPolicyForKnownCurrency(marketplace.currencyCode);
|
|
1897
|
+
}
|
|
1898
|
+
var CUSTOMER_FEEDBACK_MARKETPLACE_IDS = [...CUSTOMER_FEEDBACK_SUPPORTED_MARKETPLACE_IDS];
|
|
1899
|
+
var ADS_BRAND_METRICS_MARKETPLACE_IDS = [...ADS_BRAND_METRICS_SUPPORTED_MARKETPLACE_IDS];
|
|
1900
|
+
var ADS_SPONSORED_PRODUCTS_CAMPAIGN_MANAGEMENT_MARKETPLACE_IDS = [
|
|
1901
|
+
...ADS_SPONSORED_PRODUCTS_CAMPAIGN_MANAGEMENT_SUPPORTED_MARKETPLACE_IDS
|
|
1902
|
+
];
|
|
1903
|
+
var ADS_SPONSORED_PRODUCTS_BID_RECOMMENDATION_MARKETPLACE_IDS = [
|
|
1904
|
+
...ADS_SPONSORED_PRODUCTS_BID_RECOMMENDATION_SUPPORTED_MARKETPLACE_IDS
|
|
1905
|
+
];
|
|
1906
|
+
var ADS_SPONSORED_PRODUCTS_BUDGET_RECOMMENDATION_MARKETPLACE_IDS = [
|
|
1907
|
+
...ADS_SPONSORED_PRODUCTS_BUDGET_RECOMMENDATION_SUPPORTED_MARKETPLACE_IDS
|
|
1908
|
+
];
|
|
1909
|
+
var AWD_MARKETPLACE_IDS = [...AWD_SUPPORTED_MARKETPLACE_IDS];
|
|
1910
|
+
var BRAND_ANALYTICS_REPORT_MARKETPLACE_IDS = [...BRAND_ANALYTICS_REPORT_SUPPORTED_MARKETPLACE_IDS];
|
|
1911
|
+
var FBA_INVENTORY_PLANNING_MARKETPLACE_IDS = [...FBA_INVENTORY_PLANNING_SUPPORTED_MARKETPLACE_IDS];
|
|
1912
|
+
var FULFILLMENT_INBOUND_MARKETPLACE_IDS = [...FULFILLMENT_INBOUND_SUPPORTED_MARKETPLACE_IDS];
|
|
1913
|
+
var DEFAULT_SUPPORT_RULE = Object.freeze({ support: "all" });
|
|
1914
|
+
var TOOL_MARKETPLACE_SUPPORT_DECLARED_TOOL_NAMES = [
|
|
1915
|
+
"get_campaign_performance",
|
|
1916
|
+
"get_campaign_snapshots",
|
|
1917
|
+
"get_adgroup_performance",
|
|
1918
|
+
"get_keyword_performance",
|
|
1919
|
+
"get_product_performance",
|
|
1920
|
+
"get_purchased_products",
|
|
1921
|
+
"get_search_terms",
|
|
1922
|
+
"get_placement_breakdown",
|
|
1923
|
+
"get_sb_campaign_performance",
|
|
1924
|
+
"get_sd_campaign_performance",
|
|
1925
|
+
"get_sponsored_ads_report",
|
|
1926
|
+
"get_dsp_performance",
|
|
1927
|
+
"get_dsp_advertisers_live",
|
|
1928
|
+
"get_dsp_entities_live",
|
|
1929
|
+
"get_store_performance",
|
|
1930
|
+
"get_portfolio_performance",
|
|
1931
|
+
"get_sales_and_traffic",
|
|
1932
|
+
"get_tacos",
|
|
1933
|
+
"get_ads_change_history",
|
|
1934
|
+
"get_search_query_performance",
|
|
1935
|
+
"get_repeat_purchase_behavior",
|
|
1936
|
+
"get_search_query_ad_coverage",
|
|
1937
|
+
"diagnose_performance",
|
|
1938
|
+
"get_sp_entities_live",
|
|
1939
|
+
"get_sponsored_ads_entities_live",
|
|
1940
|
+
"get_sp_targeting_options",
|
|
1941
|
+
"get_sponsored_ads_targeting_options",
|
|
1942
|
+
"create_sb_campaigns",
|
|
1943
|
+
"update_sb_campaign_budget",
|
|
1944
|
+
"update_sb_campaign_state",
|
|
1945
|
+
"archive_sb_campaigns",
|
|
1946
|
+
"create_sb_ad_groups",
|
|
1947
|
+
"update_sb_ad_group_state",
|
|
1948
|
+
"archive_sb_ad_groups",
|
|
1949
|
+
"create_sb_ads",
|
|
1950
|
+
"update_sb_ad_state",
|
|
1951
|
+
"archive_sb_ads",
|
|
1952
|
+
"create_sb_targets",
|
|
1953
|
+
"update_sb_target_bids",
|
|
1954
|
+
"update_sb_target_state",
|
|
1955
|
+
"archive_sb_targets",
|
|
1956
|
+
"create_sb_negative_targets",
|
|
1957
|
+
"update_sb_negative_target_state",
|
|
1958
|
+
"archive_sb_negative_targets",
|
|
1959
|
+
"update_keyword_bids",
|
|
1960
|
+
"update_target_bids",
|
|
1961
|
+
"update_keyword_state",
|
|
1962
|
+
"archive_keywords",
|
|
1963
|
+
"update_adgroup_bid",
|
|
1964
|
+
"update_campaign_bidding",
|
|
1965
|
+
"update_campaign_budget",
|
|
1966
|
+
"update_campaign_state",
|
|
1967
|
+
"archive_campaigns",
|
|
1968
|
+
"create_sd_campaigns",
|
|
1969
|
+
"update_sd_campaign_budget",
|
|
1970
|
+
"update_sd_campaign_state",
|
|
1971
|
+
"archive_sd_campaigns",
|
|
1972
|
+
"create_sd_ad_groups",
|
|
1973
|
+
"update_sd_ad_group_bid",
|
|
1974
|
+
"update_sd_ad_group_state",
|
|
1975
|
+
"archive_sd_ad_groups",
|
|
1976
|
+
"create_sd_product_ads",
|
|
1977
|
+
"update_sd_product_ad_state",
|
|
1978
|
+
"archive_sd_product_ads",
|
|
1979
|
+
"create_sd_targets",
|
|
1980
|
+
"update_sd_target_bids",
|
|
1981
|
+
"update_sd_target_state",
|
|
1982
|
+
"archive_sd_targets",
|
|
1983
|
+
"create_sd_negative_targets",
|
|
1984
|
+
"update_sd_negative_target_state",
|
|
1985
|
+
"archive_sd_negative_targets",
|
|
1986
|
+
"update_campaign_audience_bid_adjustment",
|
|
1987
|
+
"create_keywords",
|
|
1988
|
+
"create_negative_keywords",
|
|
1989
|
+
"create_sp_campaigns",
|
|
1990
|
+
"create_sp_ad_groups",
|
|
1991
|
+
"create_sp_product_ads",
|
|
1992
|
+
"update_sp_ad_entities",
|
|
1993
|
+
"create_sp_targets",
|
|
1994
|
+
"update_sp_target_state",
|
|
1995
|
+
"archive_sp_targets",
|
|
1996
|
+
"create_sp_negative_targets",
|
|
1997
|
+
"update_sp_negative_keyword_state",
|
|
1998
|
+
"archive_sp_negative_keywords",
|
|
1999
|
+
"update_sp_negative_target_state",
|
|
2000
|
+
"archive_sp_negative_targets",
|
|
2001
|
+
"get_bid_recommendations",
|
|
2002
|
+
"get_budget_recommendations",
|
|
2003
|
+
"get_budget_pacing",
|
|
2004
|
+
"get_ad_eligibility",
|
|
2005
|
+
"get_brand_health",
|
|
2006
|
+
"get_share_of_voice",
|
|
2007
|
+
"get_attribution_performance",
|
|
2008
|
+
"get_audience_segments",
|
|
2009
|
+
"get_fba_inventory",
|
|
2010
|
+
"get_inventory_health",
|
|
2011
|
+
"get_fba_storage_fees",
|
|
2012
|
+
"get_inventory_movements",
|
|
2013
|
+
"get_inventory_by_fulfillment_center",
|
|
2014
|
+
"get_awd_inventory",
|
|
2015
|
+
"get_awd_shipments",
|
|
2016
|
+
"get_awd_shipment_items",
|
|
2017
|
+
"get_inbound_shipments",
|
|
2018
|
+
"get_shipment_receiving_status",
|
|
2019
|
+
"get_sales_velocity",
|
|
2020
|
+
"get_listing_registry",
|
|
2021
|
+
"get_suppressed_listings",
|
|
2022
|
+
"get_days_of_cover",
|
|
2023
|
+
"get_todays_sales",
|
|
2024
|
+
"get_orders",
|
|
2025
|
+
"get_order_details",
|
|
2026
|
+
"get_returns",
|
|
2027
|
+
"get_reimbursements",
|
|
2028
|
+
"get_seasonality_index",
|
|
2029
|
+
"get_sales_summary",
|
|
2030
|
+
"get_inventory_risk_triage",
|
|
2031
|
+
"get_current_rank",
|
|
2032
|
+
"get_buybox_status",
|
|
2033
|
+
"get_competitive_pricing",
|
|
2034
|
+
"get_offer_listings",
|
|
2035
|
+
"get_replenishment_offers",
|
|
2036
|
+
"get_fba_eligibility",
|
|
2037
|
+
"get_listing_restrictions",
|
|
2038
|
+
"get_financial_events",
|
|
2039
|
+
"get_profitability_review",
|
|
2040
|
+
"get_payment_transactions",
|
|
2041
|
+
"get_settlement_economics",
|
|
2042
|
+
"get_product_details",
|
|
2043
|
+
"get_sales_ranks",
|
|
2044
|
+
"get_aplus_status",
|
|
2045
|
+
"get_variations",
|
|
2046
|
+
"get_product_reviews",
|
|
2047
|
+
"get_review_trends",
|
|
2048
|
+
"get_listing_quality",
|
|
2049
|
+
"get_catalog_cleanup",
|
|
2050
|
+
"create_listing",
|
|
2051
|
+
"update_listing",
|
|
2052
|
+
"update_price",
|
|
2053
|
+
"update_inventory_quantity",
|
|
2054
|
+
"get_keyword_ranks",
|
|
2055
|
+
"get_shipping_preview",
|
|
2056
|
+
"get_mcf_orders",
|
|
2057
|
+
"create_mcf_order",
|
|
2058
|
+
"manage_returns",
|
|
2059
|
+
"get_account_data_tour",
|
|
2060
|
+
"submit_conversation_feedback",
|
|
2061
|
+
"get_account_info",
|
|
2062
|
+
"get_action_history"
|
|
2063
|
+
];
|
|
2064
|
+
var ADS_SPONSORED_PRODUCTS_CAMPAIGN_MANAGEMENT_TOOL_NAMES = [
|
|
2065
|
+
"get_sp_entities_live",
|
|
2066
|
+
"get_sp_targeting_options",
|
|
2067
|
+
"update_keyword_bids",
|
|
2068
|
+
"update_target_bids",
|
|
2069
|
+
"update_keyword_state",
|
|
2070
|
+
"archive_keywords",
|
|
2071
|
+
"update_adgroup_bid",
|
|
2072
|
+
"update_campaign_bidding",
|
|
2073
|
+
"update_campaign_budget",
|
|
2074
|
+
"update_campaign_state",
|
|
2075
|
+
"archive_campaigns",
|
|
2076
|
+
"update_campaign_audience_bid_adjustment",
|
|
2077
|
+
"create_keywords",
|
|
2078
|
+
"create_negative_keywords",
|
|
2079
|
+
"create_sp_campaigns",
|
|
2080
|
+
"create_sp_ad_groups",
|
|
2081
|
+
"create_sp_product_ads",
|
|
2082
|
+
"update_sp_ad_entities",
|
|
2083
|
+
"create_sp_targets",
|
|
2084
|
+
"update_sp_target_state",
|
|
2085
|
+
"archive_sp_targets",
|
|
2086
|
+
"create_sp_negative_targets",
|
|
2087
|
+
"update_sp_negative_keyword_state",
|
|
2088
|
+
"archive_sp_negative_keywords",
|
|
2089
|
+
"update_sp_negative_target_state",
|
|
2090
|
+
"archive_sp_negative_targets"
|
|
2091
|
+
];
|
|
2092
|
+
var ADS_SPONSORED_BRANDS_CAMPAIGN_MANAGEMENT_TOOL_NAMES = [
|
|
2093
|
+
"create_sb_campaigns",
|
|
2094
|
+
"update_sb_campaign_budget",
|
|
2095
|
+
"update_sb_campaign_state",
|
|
2096
|
+
"archive_sb_campaigns",
|
|
2097
|
+
"create_sb_ad_groups",
|
|
2098
|
+
"update_sb_ad_group_state",
|
|
2099
|
+
"archive_sb_ad_groups",
|
|
2100
|
+
"create_sb_ads",
|
|
2101
|
+
"update_sb_ad_state",
|
|
2102
|
+
"archive_sb_ads",
|
|
2103
|
+
"create_sb_targets",
|
|
2104
|
+
"update_sb_target_bids",
|
|
2105
|
+
"update_sb_target_state",
|
|
2106
|
+
"archive_sb_targets",
|
|
2107
|
+
"create_sb_negative_targets",
|
|
2108
|
+
"update_sb_negative_target_state",
|
|
2109
|
+
"archive_sb_negative_targets"
|
|
2110
|
+
];
|
|
2111
|
+
var BRAND_ANALYTICS_REPORT_TOOL_NAMES = [
|
|
2112
|
+
"get_search_query_performance",
|
|
2113
|
+
"get_repeat_purchase_behavior",
|
|
2114
|
+
"get_search_query_ad_coverage",
|
|
2115
|
+
"get_keyword_ranks"
|
|
2116
|
+
];
|
|
2117
|
+
var ADS_BRAND_METRICS_TOOL_NAMES = [
|
|
2118
|
+
"get_brand_health",
|
|
2119
|
+
"get_share_of_voice"
|
|
2120
|
+
];
|
|
2121
|
+
var AWD_TOOL_NAMES = [
|
|
2122
|
+
"get_awd_inventory",
|
|
2123
|
+
"get_awd_shipments",
|
|
2124
|
+
"get_awd_shipment_items"
|
|
2125
|
+
];
|
|
2126
|
+
var FULFILLMENT_INBOUND_TOOL_NAMES = [
|
|
2127
|
+
"get_inbound_shipments",
|
|
2128
|
+
"get_shipment_receiving_status"
|
|
2129
|
+
];
|
|
2130
|
+
function assignMarketplaceRule(rules, toolNames, rule) {
|
|
2131
|
+
for (const toolName of toolNames) {
|
|
2132
|
+
rules[toolName] = rule;
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
2135
|
+
function buildMarketplaceSupportRules() {
|
|
2136
|
+
const rules = {};
|
|
2137
|
+
for (const toolName of TOOL_MARKETPLACE_SUPPORT_DECLARED_TOOL_NAMES) {
|
|
2138
|
+
rules[toolName] = DEFAULT_SUPPORT_RULE;
|
|
2139
|
+
}
|
|
2140
|
+
assignMarketplaceRule(rules, ["get_product_reviews", "get_review_trends"], {
|
|
2141
|
+
support: "marketplaces",
|
|
2142
|
+
marketplaceIds: CUSTOMER_FEEDBACK_MARKETPLACE_IDS,
|
|
2143
|
+
capability: "sp_api_customer_feedback",
|
|
2144
|
+
source: "Amazon Customer Feedback API marketplace validation",
|
|
2145
|
+
note: "Amazon's Customer Feedback API currently accepts US, UK, DE, ES, FR, IT, and JP marketplace IDs."
|
|
2146
|
+
});
|
|
2147
|
+
assignMarketplaceRule(rules, ADS_SPONSORED_PRODUCTS_CAMPAIGN_MANAGEMENT_TOOL_NAMES, {
|
|
2148
|
+
support: "marketplaces",
|
|
2149
|
+
marketplaceIds: ADS_SPONSORED_PRODUCTS_CAMPAIGN_MANAGEMENT_MARKETPLACE_IDS,
|
|
2150
|
+
capability: "amazon_ads_sp_campaign_management",
|
|
2151
|
+
source: "Amazon Ads Sponsored Products feature availability by marketplace",
|
|
2152
|
+
note: "Amazon Ads documents Sponsored Products Campaign Management and Product Recommendations for US, CA, MX, BR, DE, ES, FR, IT, UK, NL, SE, TR, PL, BE, AE, EG, SA, JP, IN, AU, SG, and ZA."
|
|
2153
|
+
});
|
|
2154
|
+
assignMarketplaceRule(rules, ADS_SPONSORED_BRANDS_CAMPAIGN_MANAGEMENT_TOOL_NAMES, {
|
|
2155
|
+
support: "marketplaces",
|
|
2156
|
+
marketplaceIds: ADS_SPONSORED_PRODUCTS_CAMPAIGN_MANAGEMENT_MARKETPLACE_IDS,
|
|
2157
|
+
capability: "amazon_ads_sb_campaign_management",
|
|
2158
|
+
source: "Amazon Ads Common Campaign Management / Sponsored Brands target write availability",
|
|
2159
|
+
note: "Uses the conservative Ads campaign-management marketplace allowlist until a separate Sponsored Brands Common Campaign Management marketplace matrix is pinned."
|
|
2160
|
+
});
|
|
2161
|
+
rules.get_bid_recommendations = {
|
|
2162
|
+
support: "marketplaces",
|
|
2163
|
+
marketplaceIds: ADS_SPONSORED_PRODUCTS_BID_RECOMMENDATION_MARKETPLACE_IDS,
|
|
2164
|
+
capability: "amazon_ads_sp_theme_based_bid_suggestions",
|
|
2165
|
+
source: "Amazon Ads Sponsored Products feature availability by marketplace",
|
|
2166
|
+
note: "Amazon Ads documents Theme-based bid suggestions for US, CA, DE, ES, FR, UK, JP, and IN."
|
|
2167
|
+
};
|
|
2168
|
+
rules.get_budget_recommendations = {
|
|
2169
|
+
support: "marketplaces",
|
|
2170
|
+
marketplaceIds: ADS_SPONSORED_PRODUCTS_BUDGET_RECOMMENDATION_MARKETPLACE_IDS,
|
|
2171
|
+
capability: "amazon_ads_sp_budget_recommendations",
|
|
2172
|
+
source: "Amazon Ads Sponsored Products feature availability by marketplace",
|
|
2173
|
+
note: "Amazon Ads documents budget recommendations for US, CA, MX, DE, ES, FR, UK, IT, JP, IN, AU, and AE."
|
|
2174
|
+
};
|
|
2175
|
+
assignMarketplaceRule(rules, ADS_BRAND_METRICS_TOOL_NAMES, {
|
|
2176
|
+
support: "marketplaces",
|
|
2177
|
+
marketplaceIds: ADS_BRAND_METRICS_MARKETPLACE_IDS,
|
|
2178
|
+
capability: "amazon_ads_brand_metrics",
|
|
2179
|
+
source: "Amazon Ads Brand Metrics API open beta eligibility",
|
|
2180
|
+
note: "Amazon Ads documents Brand Metrics API eligibility for US, CA, MX, UK, DE, FR, IN, IT, ES, JP, and AU."
|
|
2181
|
+
});
|
|
2182
|
+
assignMarketplaceRule(rules, BRAND_ANALYTICS_REPORT_TOOL_NAMES, {
|
|
2183
|
+
support: "marketplaces",
|
|
2184
|
+
marketplaceIds: BRAND_ANALYTICS_REPORT_MARKETPLACE_IDS,
|
|
2185
|
+
capability: "sp_api_brand_analytics_reports",
|
|
2186
|
+
source: "Amazon SP-API Analytics report type marketplace availability",
|
|
2187
|
+
note: "Amazon documents SQP/Search Catalog/Market Basket/Repeat Purchase reports for NA all marketplaces, FE all marketplaces, and ES, UK, FR, NL, DE, IT, SE, TR, SA, AE, and IN in the EU endpoint region."
|
|
2188
|
+
});
|
|
2189
|
+
assignMarketplaceRule(rules, AWD_TOOL_NAMES, {
|
|
2190
|
+
support: "marketplaces",
|
|
2191
|
+
marketplaceIds: AWD_MARKETPLACE_IDS,
|
|
2192
|
+
capability: "sp_api_awd",
|
|
2193
|
+
source: "Amazon SP-API Amazon Warehousing and Distribution API marketplace availability",
|
|
2194
|
+
note: "Amazon documents AWD v2024-05-09 as available in the US marketplace."
|
|
2195
|
+
});
|
|
2196
|
+
assignMarketplaceRule(rules, FULFILLMENT_INBOUND_TOOL_NAMES, {
|
|
2197
|
+
support: "marketplaces",
|
|
2198
|
+
marketplaceIds: FULFILLMENT_INBOUND_MARKETPLACE_IDS,
|
|
2199
|
+
capability: "sp_api_fulfillment_inbound",
|
|
2200
|
+
source: "Amazon SP-API Fulfillment Inbound API marketplace availability",
|
|
2201
|
+
note: "Amazon documents Fulfillment Inbound shipment creation as supported in all marketplaces except Brazil."
|
|
2202
|
+
});
|
|
2203
|
+
rules.get_inventory_health = {
|
|
2204
|
+
support: "marketplaces",
|
|
2205
|
+
marketplaceIds: FBA_INVENTORY_PLANNING_MARKETPLACE_IDS,
|
|
2206
|
+
capability: "sp_api_fba_inventory_planning_report",
|
|
2207
|
+
source: "Amazon SP-API FBA Manage Inventory Health report marketplace availability",
|
|
2208
|
+
note: "Amazon documents GET_FBA_INVENTORY_PLANNING_DATA as unavailable in the NL, PL, SE, and BE marketplaces."
|
|
2209
|
+
};
|
|
2210
|
+
return rules;
|
|
2211
|
+
}
|
|
2212
|
+
var TOOL_MARKETPLACE_SUPPORT = Object.freeze(
|
|
2213
|
+
buildMarketplaceSupportRules()
|
|
2214
|
+
);
|
|
2215
|
+
var DOMAIN_BY_TOOL = /* @__PURE__ */ new Map();
|
|
2216
|
+
var WRITE_TOOL_NAMES = /* @__PURE__ */ new Set();
|
|
2217
|
+
for (const domain of TOOL_DOMAINS) {
|
|
2218
|
+
for (const tool of domain.tools) {
|
|
2219
|
+
DOMAIN_BY_TOOL.set(tool.name, domain.serverDomain);
|
|
2220
|
+
if (tool.write) WRITE_TOOL_NAMES.add(tool.name);
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
for (const tool of UTILITY_TOOLS) {
|
|
2224
|
+
DOMAIN_BY_TOOL.set(tool.name, "utility");
|
|
2225
|
+
if (tool.write) WRITE_TOOL_NAMES.add(tool.name);
|
|
2226
|
+
}
|
|
2227
|
+
var MARKETPLACE_CAPABILITY_POLICY_VERSION = "marketplace-capabilities-v2-enabled-2026-05-26";
|
|
2228
|
+
var US_WRITE_EVIDENCE_VERSION = "phase1-us-write-baseline";
|
|
2229
|
+
var CANADA_CAPABILITY_EVIDENCE_VERSION = "marketplace-capabilities-v2-ca-enabled-2026-05-26";
|
|
2230
|
+
var CANADA_BASE_EVIDENCE_IDS = [
|
|
2231
|
+
"ca.registry-facts.v1",
|
|
2232
|
+
"ca.seller-central-url.v1",
|
|
2233
|
+
"ca.timezone-source.v1",
|
|
2234
|
+
"ca.promotion-effects.v1"
|
|
2235
|
+
];
|
|
2236
|
+
var CANADA_ADS_ENABLED_EVIDENCE_IDS = ["ca.ads-write-enabled.repo-contract.v1"];
|
|
2237
|
+
var CANADA_CATALOG_ENABLED_EVIDENCE_IDS = [
|
|
2238
|
+
"ca.catalog-update-price-cad-preview.repo-proof.v1",
|
|
2239
|
+
"ca.catalog-write-enabled.repo-contract.v1"
|
|
2240
|
+
];
|
|
2241
|
+
var CANADA_FULFILLMENT_ENABLED_EVIDENCE_IDS = ["ca.fulfillment-write-enabled.repo-contract.v1"];
|
|
2242
|
+
function policyKey(marketplaceId, toolFamily) {
|
|
2243
|
+
return `${marketplaceId}:${toolFamily}`;
|
|
2244
|
+
}
|
|
2245
|
+
var MARKETPLACE_CAPABILITY_POLICIES = [
|
|
2246
|
+
{
|
|
2247
|
+
marketplaceId: DEFAULT_MARKETPLACE_ID,
|
|
2248
|
+
toolFamily: "ads_write",
|
|
2249
|
+
requiredConnection: "ads",
|
|
2250
|
+
evidenceVersion: US_WRITE_EVIDENCE_VERSION,
|
|
2251
|
+
evidenceIds: ["existing-us-ads-write-contract-tests"],
|
|
2252
|
+
capabilityRolloutTrack: "foundation",
|
|
2253
|
+
evidenceStatus: "recorded",
|
|
2254
|
+
requiredEvidence: ["existing_foundation_behavior_preserved"],
|
|
2255
|
+
stages: { preview: "enabled", write: "enabled" },
|
|
2256
|
+
notes: "Existing US Ads write behavior remains enabled while v2 policy is introduced."
|
|
2257
|
+
},
|
|
2258
|
+
{
|
|
2259
|
+
marketplaceId: DEFAULT_MARKETPLACE_ID,
|
|
2260
|
+
toolFamily: "catalog_write",
|
|
2261
|
+
requiredConnection: "sp_api",
|
|
2262
|
+
evidenceVersion: US_WRITE_EVIDENCE_VERSION,
|
|
2263
|
+
evidenceIds: ["existing-us-catalog-write-contract-tests"],
|
|
2264
|
+
capabilityRolloutTrack: "foundation",
|
|
2265
|
+
evidenceStatus: "recorded",
|
|
2266
|
+
requiredEvidence: ["existing_foundation_behavior_preserved"],
|
|
2267
|
+
stages: { preview: "enabled", write: "enabled" },
|
|
2268
|
+
notes: "Existing US catalog write behavior remains enabled while v2 policy is introduced."
|
|
2269
|
+
},
|
|
2270
|
+
{
|
|
2271
|
+
marketplaceId: DEFAULT_MARKETPLACE_ID,
|
|
2272
|
+
toolFamily: "fulfillment_write",
|
|
2273
|
+
requiredConnection: "sp_api",
|
|
2274
|
+
evidenceVersion: US_WRITE_EVIDENCE_VERSION,
|
|
2275
|
+
evidenceIds: ["existing-us-fulfillment-write-contract-tests"],
|
|
2276
|
+
capabilityRolloutTrack: "foundation",
|
|
2277
|
+
evidenceStatus: "recorded",
|
|
2278
|
+
requiredEvidence: ["existing_foundation_behavior_preserved"],
|
|
2279
|
+
stages: { write: "enabled" },
|
|
2280
|
+
notes: "Existing US fulfillment write behavior remains enabled while v2 policy is introduced."
|
|
2281
|
+
},
|
|
2282
|
+
{
|
|
2283
|
+
marketplaceId: "A2EUQ1WTGCTBG2",
|
|
2284
|
+
toolFamily: "ads_write",
|
|
2285
|
+
requiredConnection: "ads",
|
|
2286
|
+
evidenceVersion: CANADA_CAPABILITY_EVIDENCE_VERSION,
|
|
2287
|
+
evidenceIds: [...CANADA_BASE_EVIDENCE_IDS, ...CANADA_ADS_ENABLED_EVIDENCE_IDS],
|
|
2288
|
+
capabilityRolloutTrack: "enabled",
|
|
2289
|
+
evidenceStatus: "recorded",
|
|
2290
|
+
requiredEvidence: ["contract_tests_pass"],
|
|
2291
|
+
stages: { preview: "enabled", write: "enabled" },
|
|
2292
|
+
notes: "Canada Ads writes are enabled. Runtime write safety still requires scoped credentials without endpoint mismatch or tenant-key ambiguity."
|
|
2293
|
+
},
|
|
2294
|
+
{
|
|
2295
|
+
marketplaceId: "A2EUQ1WTGCTBG2",
|
|
2296
|
+
toolFamily: "catalog_write",
|
|
2297
|
+
requiredConnection: "sp_api",
|
|
2298
|
+
evidenceVersion: CANADA_CAPABILITY_EVIDENCE_VERSION,
|
|
2299
|
+
evidenceIds: [...CANADA_BASE_EVIDENCE_IDS, ...CANADA_CATALOG_ENABLED_EVIDENCE_IDS],
|
|
2300
|
+
capabilityRolloutTrack: "enabled",
|
|
2301
|
+
evidenceStatus: "recorded",
|
|
2302
|
+
requiredEvidence: ["contract_tests_pass", "currency_safe_previews_and_audits_verified"],
|
|
2303
|
+
stages: { preview: "enabled", write: "enabled" },
|
|
2304
|
+
notes: "Canada catalog previews and writes are enabled with CAD marketplace facts. Runtime write safety still requires scoped SP-API credentials without endpoint mismatch or tenant-key ambiguity."
|
|
2305
|
+
},
|
|
2306
|
+
{
|
|
2307
|
+
marketplaceId: "A2EUQ1WTGCTBG2",
|
|
2308
|
+
toolFamily: "fulfillment_write",
|
|
2309
|
+
requiredConnection: "sp_api",
|
|
2310
|
+
evidenceVersion: CANADA_CAPABILITY_EVIDENCE_VERSION,
|
|
2311
|
+
evidenceIds: [...CANADA_BASE_EVIDENCE_IDS, ...CANADA_FULFILLMENT_ENABLED_EVIDENCE_IDS],
|
|
2312
|
+
capabilityRolloutTrack: "enabled",
|
|
2313
|
+
evidenceStatus: "recorded",
|
|
2314
|
+
requiredEvidence: ["contract_tests_pass"],
|
|
2315
|
+
stages: { write: "enabled" },
|
|
2316
|
+
notes: "Canada fulfillment writes are enabled. Runtime write safety still requires scoped SP-API credentials without endpoint mismatch or tenant-key ambiguity."
|
|
2317
|
+
}
|
|
2318
|
+
];
|
|
2319
|
+
var MARKETPLACE_CAPABILITY_POLICY_BY_KEY = new Map(
|
|
2320
|
+
MARKETPLACE_CAPABILITY_POLICIES.map((policy) => [policyKey(policy.marketplaceId, policy.toolFamily), policy])
|
|
2321
|
+
);
|
|
2322
|
+
var MARKETPLACE_CAPABILITY_CAPSULES = MARKETPLACE_DEFINITIONS.map((marketplace) => {
|
|
2323
|
+
const toolFamilies = MARKETPLACE_CAPABILITY_POLICIES.filter(
|
|
2324
|
+
(policy) => policy.marketplaceId === marketplace.marketplaceId
|
|
2325
|
+
);
|
|
2326
|
+
const hasCandidateCapabilityPolicy = toolFamilies.some(
|
|
2327
|
+
(policy) => policy.capabilityRolloutTrack === "v2_candidate"
|
|
2328
|
+
);
|
|
2329
|
+
const hasEnabledCapabilityPolicy = toolFamilies.some(
|
|
2330
|
+
(policy) => policy.capabilityRolloutTrack === "enabled"
|
|
2331
|
+
);
|
|
2332
|
+
return {
|
|
2333
|
+
marketplaceId: marketplace.marketplaceId,
|
|
2334
|
+
capsuleVersion: MARKETPLACE_CAPABILITY_POLICY_VERSION,
|
|
2335
|
+
base: marketplace,
|
|
2336
|
+
money: getMarketplaceMoneyPolicyForDefinition(marketplace),
|
|
2337
|
+
toolFamilies,
|
|
2338
|
+
rolloutGates: hasCandidateCapabilityPolicy ? [
|
|
2339
|
+
"registry_metadata_verified",
|
|
2340
|
+
"contract_tests_pass",
|
|
2341
|
+
"read_only_smoke_evidence_recorded",
|
|
2342
|
+
"currency_safe_previews_and_audits_verified",
|
|
2343
|
+
"write_evidence_recorded_before_promotion"
|
|
2344
|
+
] : hasEnabledCapabilityPolicy ? ["registry_metadata_verified", "contract_tests_pass", "runtime_write_guardrails_preserved"] : ["existing_foundation_behavior_preserved"]
|
|
2345
|
+
};
|
|
2346
|
+
});
|
|
2347
|
+
var GLOBAL_MARKETPLACE_CAPABILITY_EVIDENCE_SCOPE = "global";
|
|
2348
|
+
var COMMON_MARKETPLACE_CAPABILITY_EVIDENCE_SCOPE = "common";
|
|
2349
|
+
var CANADA_MARKETPLACE_ID = "A2EUQ1WTGCTBG2";
|
|
2350
|
+
var MARKETPLACE_CAPABILITY_EVIDENCE_REGISTRY = [
|
|
2351
|
+
{
|
|
2352
|
+
id: "default-deny",
|
|
2353
|
+
status: "recorded",
|
|
2354
|
+
marketplaceId: GLOBAL_MARKETPLACE_CAPABILITY_EVIDENCE_SCOPE,
|
|
2355
|
+
toolFamily: "all",
|
|
2356
|
+
operation: "all",
|
|
2357
|
+
sourceType: "repo_policy",
|
|
2358
|
+
artifactPath: "packages/shared/src/marketplace-capabilities.ts",
|
|
2359
|
+
supportingArtifactPaths: [
|
|
2360
|
+
"packages/shared/src/marketplace-capabilities.test.ts",
|
|
2361
|
+
"packages/shared/src/marketplace-capabilities.contract.test.ts"
|
|
2362
|
+
],
|
|
2363
|
+
summary: "Default-deny fallback evidence version for unknown marketplaces and marketplace/tool-family combinations without explicit policy rows.",
|
|
2364
|
+
notes: "Recorded deny behavior only; this evidence record does not grant any marketplace capability."
|
|
2365
|
+
},
|
|
2366
|
+
{
|
|
2367
|
+
id: "existing-us-ads-write-contract-tests",
|
|
2368
|
+
status: "recorded",
|
|
2369
|
+
marketplaceId: DEFAULT_MARKETPLACE_ID,
|
|
2370
|
+
toolFamily: "ads_write",
|
|
2371
|
+
operation: "write",
|
|
2372
|
+
sourceType: "repo_contract_test",
|
|
2373
|
+
artifactPath: "packages/shared/src/marketplace-capabilities.test.ts",
|
|
2374
|
+
supportingArtifactPaths: ["packages/shared/src/marketplace-capabilities.contract.test.ts"],
|
|
2375
|
+
summary: "Existing US Ads write-family behavior is covered by shared marketplace capability tests while v2 policy is introduced."
|
|
2376
|
+
},
|
|
2377
|
+
{
|
|
2378
|
+
id: "existing-us-catalog-write-contract-tests",
|
|
2379
|
+
status: "recorded",
|
|
2380
|
+
marketplaceId: DEFAULT_MARKETPLACE_ID,
|
|
2381
|
+
toolFamily: "catalog_write",
|
|
2382
|
+
operation: "write",
|
|
2383
|
+
sourceType: "repo_contract_test",
|
|
2384
|
+
artifactPath: "packages/shared/src/marketplace-capabilities.test.ts",
|
|
2385
|
+
supportingArtifactPaths: ["packages/shared/src/marketplace-capabilities.contract.test.ts"],
|
|
2386
|
+
summary: "Existing US catalog write-family behavior is covered by shared marketplace capability tests while v2 policy is introduced."
|
|
2387
|
+
},
|
|
2388
|
+
{
|
|
2389
|
+
id: "existing-us-fulfillment-write-contract-tests",
|
|
2390
|
+
status: "recorded",
|
|
2391
|
+
marketplaceId: DEFAULT_MARKETPLACE_ID,
|
|
2392
|
+
toolFamily: "fulfillment_write",
|
|
2393
|
+
operation: "write",
|
|
2394
|
+
sourceType: "repo_contract_test",
|
|
2395
|
+
artifactPath: "packages/shared/src/marketplace-capabilities.test.ts",
|
|
2396
|
+
supportingArtifactPaths: ["packages/shared/src/marketplace-capabilities.contract.test.ts"],
|
|
2397
|
+
summary: "Existing US fulfillment write-family behavior is covered by shared marketplace capability tests while v2 policy is introduced."
|
|
2398
|
+
},
|
|
2399
|
+
{
|
|
2400
|
+
id: "ca.registry-facts.v1",
|
|
2401
|
+
status: "recorded",
|
|
2402
|
+
marketplaceId: CANADA_MARKETPLACE_ID,
|
|
2403
|
+
toolFamily: "all",
|
|
2404
|
+
operation: "all",
|
|
2405
|
+
sourceType: "repo_registry",
|
|
2406
|
+
artifactPath: "packages/shared/src/marketplaces.ts",
|
|
2407
|
+
supportingArtifactPaths: [
|
|
2408
|
+
"packages/shared/src/marketplaces.test.ts",
|
|
2409
|
+
"docs/internal/runbooks/marketplace-capabilities-v2.md"
|
|
2410
|
+
],
|
|
2411
|
+
summary: "Canada marketplace registry facts are code-owned: marketplace ID, country, domain, currency, reporting timezone, Seller Central host, SP-API endpoint, and Ads endpoint."
|
|
2412
|
+
},
|
|
2413
|
+
{
|
|
2414
|
+
id: "ca.seller-central-url.v1",
|
|
2415
|
+
status: "recorded",
|
|
2416
|
+
marketplaceId: CANADA_MARKETPLACE_ID,
|
|
2417
|
+
toolFamily: "all",
|
|
2418
|
+
operation: "all",
|
|
2419
|
+
sourceType: "repo_registry",
|
|
2420
|
+
artifactPath: "packages/shared/src/marketplaces.ts",
|
|
2421
|
+
supportingArtifactPaths: ["docs/internal/runbooks/marketplace-capabilities-v2.md"],
|
|
2422
|
+
summary: "Canada Seller Central base URL is recorded as https://sellercentral.amazon.ca in the marketplace registry."
|
|
2423
|
+
},
|
|
2424
|
+
{
|
|
2425
|
+
id: "ca.timezone-source.v1",
|
|
2426
|
+
status: "recorded",
|
|
2427
|
+
marketplaceId: CANADA_MARKETPLACE_ID,
|
|
2428
|
+
toolFamily: "all",
|
|
2429
|
+
operation: "all",
|
|
2430
|
+
sourceType: "repo_registry",
|
|
2431
|
+
artifactPath: "packages/shared/src/marketplaces.ts",
|
|
2432
|
+
supportingArtifactPaths: [
|
|
2433
|
+
"packages/shared/src/marketplaces.test.ts",
|
|
2434
|
+
"docs/internal/runbooks/marketplace-capabilities-v2.md"
|
|
2435
|
+
],
|
|
2436
|
+
summary: "Canada default reporting timezone is recorded as America/Toronto and validated through shared marketplace registry tests."
|
|
2437
|
+
},
|
|
2438
|
+
{
|
|
2439
|
+
id: "ca.promotion-effects.v1",
|
|
2440
|
+
status: "recorded",
|
|
2441
|
+
marketplaceId: CANADA_MARKETPLACE_ID,
|
|
2442
|
+
toolFamily: "all",
|
|
2443
|
+
operation: "all",
|
|
2444
|
+
sourceType: "repo_policy",
|
|
2445
|
+
artifactPath: "packages/shared/src/marketplace-capabilities.ts",
|
|
2446
|
+
supportingArtifactPaths: [
|
|
2447
|
+
"packages/shared/src/marketplace-capabilities.test.ts",
|
|
2448
|
+
"packages/shared/src/marketplace-capabilities.contract.test.ts",
|
|
2449
|
+
"docs/internal/runbooks/marketplace-capabilities-v2.md"
|
|
2450
|
+
],
|
|
2451
|
+
summary: "Canada policy effects are explicit: Canada Ads, catalog, and fulfillment write-family rows are enabled; UK, Saudi Arabia, unknown marketplaces, and unconfigured marketplace/tool-family combinations remain default-denied."
|
|
2452
|
+
},
|
|
2453
|
+
{
|
|
2454
|
+
id: "ca.ads-write-enabled.repo-contract.v1",
|
|
2455
|
+
status: "recorded",
|
|
2456
|
+
marketplaceId: CANADA_MARKETPLACE_ID,
|
|
2457
|
+
toolFamily: "ads_write",
|
|
2458
|
+
operation: "write",
|
|
2459
|
+
sourceType: "repo_contract_test",
|
|
2460
|
+
artifactPath: "packages/shared/src/marketplace-capabilities.test.ts",
|
|
2461
|
+
supportingArtifactPaths: [
|
|
2462
|
+
"packages/shared/src/marketplace-capabilities.contract.test.ts",
|
|
2463
|
+
"packages/hosted-server/src/util/marketplace-write-safety.test.ts"
|
|
2464
|
+
],
|
|
2465
|
+
summary: "Repo tests cover Canada Ads write-family policy as enabled with CAD marketplace facts, Ads connection requirements, and runtime endpoint/marketplace-scope write safety preserved."
|
|
2466
|
+
},
|
|
2467
|
+
{
|
|
2468
|
+
id: "ca.catalog-write-enabled.repo-contract.v1",
|
|
2469
|
+
status: "recorded",
|
|
2470
|
+
marketplaceId: CANADA_MARKETPLACE_ID,
|
|
2471
|
+
toolFamily: "catalog_write",
|
|
2472
|
+
operation: "write",
|
|
2473
|
+
sourceType: "repo_contract_test",
|
|
2474
|
+
artifactPath: "packages/shared/src/marketplace-capabilities.test.ts",
|
|
2475
|
+
supportingArtifactPaths: [
|
|
2476
|
+
"packages/shared/src/marketplace-capabilities.contract.test.ts",
|
|
2477
|
+
"packages/hosted-server/src/util/marketplace-write-safety.test.ts",
|
|
2478
|
+
"packages/hosted-server/src/tools/catalog/update-price.test.ts"
|
|
2479
|
+
],
|
|
2480
|
+
summary: "Repo tests cover Canada catalog preview and write policy as enabled with CAD marketplace facts and runtime endpoint/marketplace-scope write safety preserved."
|
|
2481
|
+
},
|
|
2482
|
+
{
|
|
2483
|
+
id: "ca.fulfillment-write-enabled.repo-contract.v1",
|
|
2484
|
+
status: "recorded",
|
|
2485
|
+
marketplaceId: CANADA_MARKETPLACE_ID,
|
|
2486
|
+
toolFamily: "fulfillment_write",
|
|
2487
|
+
operation: "write",
|
|
2488
|
+
sourceType: "repo_contract_test",
|
|
2489
|
+
artifactPath: "packages/shared/src/marketplace-capabilities.test.ts",
|
|
2490
|
+
supportingArtifactPaths: [
|
|
2491
|
+
"packages/shared/src/marketplace-capabilities.contract.test.ts",
|
|
2492
|
+
"packages/hosted-server/src/util/marketplace-write-safety.test.ts"
|
|
2493
|
+
],
|
|
2494
|
+
summary: "Repo tests cover Canada fulfillment write-family policy as enabled with CAD marketplace facts, SP-API connection requirements, and runtime endpoint/marketplace-scope write safety preserved."
|
|
2495
|
+
},
|
|
2496
|
+
{
|
|
2497
|
+
id: "ca.ads-readonly-smoke.pending",
|
|
2498
|
+
status: "pending",
|
|
2499
|
+
marketplaceId: CANADA_MARKETPLACE_ID,
|
|
2500
|
+
toolFamily: "ads_write",
|
|
2501
|
+
operation: "read",
|
|
2502
|
+
sourceType: "live_smoke",
|
|
2503
|
+
artifactPath: "docs/internal/evidence/marketplace-capabilities/canada-ads-readonly-smoke-template.md",
|
|
2504
|
+
supportingArtifactPaths: ["docs/internal/runbooks/marketplace-capabilities-v2.md"],
|
|
2505
|
+
summary: "Controlled read-only Canada Ads smoke evidence is pending and has not been performed in this repo-only enablement change.",
|
|
2506
|
+
notes: "Optional live evidence; requires explicit approval, controlled credentials, and no mutation calls before it can be changed to recorded."
|
|
2507
|
+
},
|
|
2508
|
+
{
|
|
2509
|
+
id: "ca.spapi-readonly-smoke.pending",
|
|
2510
|
+
status: "pending",
|
|
2511
|
+
marketplaceId: CANADA_MARKETPLACE_ID,
|
|
2512
|
+
toolFamily: "all",
|
|
2513
|
+
operation: "read",
|
|
2514
|
+
sourceType: "live_smoke",
|
|
2515
|
+
artifactPath: "docs/internal/evidence/marketplace-capabilities/canada-spapi-readonly-smoke-template.md",
|
|
2516
|
+
supportingArtifactPaths: ["docs/internal/runbooks/marketplace-capabilities-v2.md"],
|
|
2517
|
+
summary: "Controlled read-only Canada SP-API smoke evidence is pending and has not been performed in this repo-only enablement change.",
|
|
2518
|
+
notes: "Optional live evidence; requires explicit approval, controlled credentials, and no mutation calls before it can be changed to recorded."
|
|
2519
|
+
},
|
|
2520
|
+
{
|
|
2521
|
+
id: "ca.catalog-update-price-cad-preview.repo-proof.v1",
|
|
2522
|
+
status: "recorded",
|
|
2523
|
+
marketplaceId: CANADA_MARKETPLACE_ID,
|
|
2524
|
+
toolFamily: "catalog_write",
|
|
2525
|
+
operation: "preview",
|
|
2526
|
+
sourceType: "repo_tool_test",
|
|
2527
|
+
artifactPath: "packages/shared/src/marketplace-capabilities.test.ts",
|
|
2528
|
+
supportingArtifactPaths: [
|
|
2529
|
+
"packages/shared/src/marketplace-capabilities.contract.test.ts",
|
|
2530
|
+
"packages/hosted-server/src/util/marketplace-write-safety.test.ts",
|
|
2531
|
+
"packages/hosted-server/src/tools/catalog/update-price.test.ts",
|
|
2532
|
+
"docs/internal/runbooks/marketplace-capabilities-v2.md"
|
|
2533
|
+
],
|
|
2534
|
+
summary: "Repo tests prove Canada update_price validation preview is CAD-scoped and uses Canada marketplace facts while Canada catalog write-family policy is enabled."
|
|
2535
|
+
}
|
|
2536
|
+
];
|
|
2537
|
+
var MARKETPLACE_CAPABILITY_EVIDENCE_BY_ID = new Map(
|
|
2538
|
+
MARKETPLACE_CAPABILITY_EVIDENCE_REGISTRY.map((record) => [record.id, record])
|
|
2539
|
+
);
|
|
2540
|
+
function getMarketplaceCapabilityEvidenceRecord(id) {
|
|
2541
|
+
return MARKETPLACE_CAPABILITY_EVIDENCE_BY_ID.get(id);
|
|
2542
|
+
}
|
|
2543
|
+
var MARKETPLACE_CAPABILITY_EVIDENCE_CAPTURE_SCHEMA_VERSION = "marketplace-capability-evidence-capture.v1";
|
|
2544
|
+
var MARKETPLACE_CAPABILITY_EVIDENCE_CAPTURE_STATUSES = ["example", "captured", "failed"];
|
|
2545
|
+
var MARKETPLACE_CAPABILITY_EVIDENCE_CAPTURE_SOURCE_TYPES = [
|
|
2546
|
+
"ads_api_readonly_smoke",
|
|
2547
|
+
"sp_api_readonly_smoke"
|
|
2548
|
+
];
|
|
2549
|
+
var READ_ONLY_HTTP_METHODS = ["GET", "HEAD", "OPTIONS"];
|
|
2550
|
+
var AMAZON_REGIONS = ["NA", "EU", "FE"];
|
|
2551
|
+
var API_SERVICES = ["ads", "sp_api"];
|
|
2552
|
+
var EVIDENCE_FACT_SOURCES = [
|
|
2553
|
+
"response_body",
|
|
2554
|
+
"response_header",
|
|
2555
|
+
"request_context",
|
|
2556
|
+
"amazon_marketplace_metadata",
|
|
2557
|
+
"repo_registry_fallback",
|
|
2558
|
+
"operator_observation"
|
|
2559
|
+
];
|
|
2560
|
+
var CAPTURED_AT_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/;
|
|
2561
|
+
var REPO_RELATIVE_PATH_PATTERN = /^(?!\/)(?![a-z][a-z\d+.-]*:)[\w./@-]+$/i;
|
|
2562
|
+
var REDACTION_PLACEHOLDER_PATTERN = /(?:\[(?:redacted|masked)\]|<(?:redacted|masked)>|\b(?:redacted|masked)(?:[_-][a-z0-9]+)*\b|\*{3,})/i;
|
|
2563
|
+
var REDACTED_PATH_SEGMENT = "[redacted-key]";
|
|
2564
|
+
var REDACTED_VALUE_SEGMENT = "[redacted-value]";
|
|
2565
|
+
var EXAMPLE_DOMAIN_PATTERN = /(?:^|\.)example\.(?:invalid|com|net|org)$/i;
|
|
2566
|
+
var BEARER_TOKEN_PATTERN = /\bBearer\s+([^\s"',;]+)/gi;
|
|
2567
|
+
var AUTHORIZATION_HEADER_PATTERN = /\bauthorization\b\s*[:=]\s*["']?(?:(?:Bearer|Basic|AWS4-HMAC-SHA256)\s+)?([^\s"',;]+)/gi;
|
|
2568
|
+
var SENSITIVE_ASSIGNMENT_PATTERN = /\b(?:access[_-]?token|refresh[_-]?token|id[_-]?token|client[_-]?secret|api[_-]?key)\b\s*[:=]\s*["']?([^\s"',;&]+)/gi;
|
|
2569
|
+
var AGENTCENTRAL_API_KEY_PATTERN = /\bac_(?:live|test|dev)_[A-Za-z0-9_-]{8,}\b/g;
|
|
2570
|
+
var AMAZON_TOKEN_PATTERN = /\bamz_[A-Za-z0-9_-]{8,}\b/gi;
|
|
2571
|
+
var AWS_ACCESS_KEY_PATTERN = /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g;
|
|
2572
|
+
var EMAIL_ADDRESS_PATTERN = /\b[A-Z0-9._%+-]+@([A-Z0-9.-]+\.[A-Z]{2,})\b/gi;
|
|
2573
|
+
var PHONE_NUMBER_PATTERN = /(?:\+?\d{1,3}[\s.-]*)?(?:\(\d{3}\)|\d{3})[\s.-]\d{3}[\s.-]\d{4}\b/g;
|
|
2574
|
+
var INTERNATIONAL_PHONE_NUMBER_PATTERN = /\+\d{10,15}\b/g;
|
|
2575
|
+
var LONG_KEY_LIKE_PATTERN = /(?<![A-Za-z0-9_+=/-])(?:[A-Za-z0-9_+=/-]{32,})(?![A-Za-z0-9_+=/-])/g;
|
|
2576
|
+
var httpsUrlSchema = z4.string().url().refine((value) => {
|
|
2577
|
+
try {
|
|
2578
|
+
return new URL(value).protocol === "https:";
|
|
2579
|
+
} catch {
|
|
2580
|
+
return false;
|
|
2581
|
+
}
|
|
2582
|
+
}, "Expected an HTTPS URL");
|
|
2583
|
+
var capturedAtSchema = z4.string().regex(CAPTURED_AT_PATTERN, "Expected an ISO-8601 UTC timestamp, for example 2026-05-17T12:34:56.000Z").refine((value) => !Number.isNaN(Date.parse(value)), "Expected a parseable UTC timestamp");
|
|
2584
|
+
var registryEvidenceIdSchema = z4.string().min(1);
|
|
2585
|
+
var evidenceFactSchema = z4.object({
|
|
2586
|
+
expected: z4.string().min(1),
|
|
2587
|
+
observed: z4.string().min(1).nullable(),
|
|
2588
|
+
source: z4.enum(EVIDENCE_FACT_SOURCES),
|
|
2589
|
+
matchesExpected: z4.boolean(),
|
|
2590
|
+
notes: z4.string().min(1).optional()
|
|
2591
|
+
}).strict();
|
|
2592
|
+
var readOnlyCallSummarySchema = z4.object({
|
|
2593
|
+
operationName: z4.string().min(1),
|
|
2594
|
+
method: z4.enum(READ_ONLY_HTTP_METHODS),
|
|
2595
|
+
endpointPath: z4.string().min(1),
|
|
2596
|
+
redactedUrl: z4.string().min(1),
|
|
2597
|
+
responseStatus: z4.number().int().min(100).max(599).optional(),
|
|
2598
|
+
returnedFieldNames: z4.array(z4.string().min(1)).min(1),
|
|
2599
|
+
redactedResponseShape: z4.record(z4.unknown()).optional(),
|
|
2600
|
+
notes: z4.string().min(1).optional()
|
|
2601
|
+
}).strict();
|
|
2602
|
+
var noMutationAttestationSchema = z4.object({
|
|
2603
|
+
requestSetReadOnly: z4.literal(true),
|
|
2604
|
+
noMutationEndpointsCalled: z4.literal(true),
|
|
2605
|
+
noMcpWriteToolsRun: z4.literal(true),
|
|
2606
|
+
noSyncsTriggered: z4.literal(true),
|
|
2607
|
+
noApiKeyMutations: z4.literal(true),
|
|
2608
|
+
noDeployments: z4.literal(true),
|
|
2609
|
+
noProductionOrCustomerDataMutated: z4.literal(true),
|
|
2610
|
+
statement: z4.string().min(1)
|
|
2611
|
+
}).strict();
|
|
2612
|
+
var redactionAttestationSchema = z4.object({
|
|
2613
|
+
tokensAndSecretsRedacted: z4.literal(true),
|
|
2614
|
+
authorizationHeadersRedacted: z4.literal(true),
|
|
2615
|
+
refreshTokensRedacted: z4.literal(true),
|
|
2616
|
+
customerPiiRedacted: z4.literal(true),
|
|
2617
|
+
accountIdentifiersRedacted: z4.literal(true),
|
|
2618
|
+
rawPayloadsMinimized: z4.literal(true),
|
|
2619
|
+
statement: z4.string().min(1)
|
|
2620
|
+
}).strict();
|
|
2621
|
+
var approvalReferenceSchema = z4.object({
|
|
2622
|
+
reference: z4.string().min(1),
|
|
2623
|
+
approvedBy: z4.string().min(1),
|
|
2624
|
+
approvedAt: capturedAtSchema.optional(),
|
|
2625
|
+
approvedReadOnlyEndpoints: z4.array(z4.string().min(1)).min(1),
|
|
2626
|
+
notes: z4.string().min(1).optional()
|
|
2627
|
+
}).strict();
|
|
2628
|
+
var operatorContextSchema = z4.object({
|
|
2629
|
+
environment: z4.string().min(1),
|
|
2630
|
+
commitSha: z4.string().min(1),
|
|
2631
|
+
command: z4.string().min(1),
|
|
2632
|
+
notes: z4.string().min(1).optional()
|
|
2633
|
+
}).strict();
|
|
2634
|
+
var endpointObservationSchema = z4.object({
|
|
2635
|
+
service: z4.enum(API_SERVICES),
|
|
2636
|
+
region: z4.enum(AMAZON_REGIONS),
|
|
2637
|
+
expectedBaseUrl: httpsUrlSchema,
|
|
2638
|
+
observedBaseUrl: httpsUrlSchema,
|
|
2639
|
+
observedHost: z4.string().min(1),
|
|
2640
|
+
notes: z4.string().min(1).optional()
|
|
2641
|
+
}).strict();
|
|
2642
|
+
var artifactReferenceSchema = z4.object({
|
|
2643
|
+
path: z4.string().regex(REPO_RELATIVE_PATH_PATTERN, "Expected a repository-relative artifact path"),
|
|
2644
|
+
kind: z4.enum(["example_fixture", "captured_artifact"]),
|
|
2645
|
+
notes: z4.string().min(1)
|
|
2646
|
+
}).strict();
|
|
2647
|
+
var marketplaceCapabilityEvidenceCaptureBaseSchema = z4.object({
|
|
2648
|
+
schemaVersion: z4.literal(MARKETPLACE_CAPABILITY_EVIDENCE_CAPTURE_SCHEMA_VERSION),
|
|
2649
|
+
captureId: z4.string().min(1),
|
|
2650
|
+
evidenceId: registryEvidenceIdSchema,
|
|
2651
|
+
registryEvidenceIds: z4.array(registryEvidenceIdSchema).min(1),
|
|
2652
|
+
marketplaceId: z4.string().min(1),
|
|
2653
|
+
sourceType: z4.enum(MARKETPLACE_CAPABILITY_EVIDENCE_CAPTURE_SOURCE_TYPES),
|
|
2654
|
+
status: z4.enum(MARKETPLACE_CAPABILITY_EVIDENCE_CAPTURE_STATUSES),
|
|
2655
|
+
capturedAt: capturedAtSchema.optional(),
|
|
2656
|
+
approvalReference: approvalReferenceSchema,
|
|
2657
|
+
operator: operatorContextSchema,
|
|
2658
|
+
endpoint: endpointObservationSchema,
|
|
2659
|
+
observedFacts: z4.object({
|
|
2660
|
+
marketplaceId: evidenceFactSchema,
|
|
2661
|
+
countryCode: evidenceFactSchema,
|
|
2662
|
+
currencyCode: evidenceFactSchema,
|
|
2663
|
+
reportingTimeZone: evidenceFactSchema
|
|
2664
|
+
}).strict(),
|
|
2665
|
+
readOnlyCalls: z4.array(readOnlyCallSummarySchema).min(1),
|
|
2666
|
+
noMutationAttestation: noMutationAttestationSchema,
|
|
2667
|
+
redactionAttestation: redactionAttestationSchema,
|
|
2668
|
+
artifact: artifactReferenceSchema,
|
|
2669
|
+
notes: z4.string().min(1).optional()
|
|
2670
|
+
}).strict();
|
|
2671
|
+
function addIssue(ctx, path, message) {
|
|
2672
|
+
ctx.addIssue({ code: z4.ZodIssueCode.custom, path: sanitizeIssuePath(path), message: safeIssueDisplay(message) });
|
|
2673
|
+
}
|
|
2674
|
+
function hostForUrl(value) {
|
|
2675
|
+
try {
|
|
2676
|
+
return new URL(value).host;
|
|
2677
|
+
} catch {
|
|
2678
|
+
return null;
|
|
2679
|
+
}
|
|
2680
|
+
}
|
|
2681
|
+
function pathToString(path) {
|
|
2682
|
+
const safePath = sanitizeRedactionPath(path);
|
|
2683
|
+
if (safePath.length === 0) {
|
|
2684
|
+
return "capture";
|
|
2685
|
+
}
|
|
2686
|
+
return safePath.reduce((formattedPath, segment) => {
|
|
2687
|
+
if (typeof segment === "number") {
|
|
2688
|
+
return `${formattedPath}[${segment}]`;
|
|
2689
|
+
}
|
|
2690
|
+
return formattedPath ? `${formattedPath}.${segment}` : segment;
|
|
2691
|
+
}, "");
|
|
2692
|
+
}
|
|
2693
|
+
function stripTokenWrapper(value) {
|
|
2694
|
+
return value.trim().replace(/^["'`]+|["'`,.;]+$/g, "");
|
|
2695
|
+
}
|
|
2696
|
+
function hasRedactionPlaceholder(value) {
|
|
2697
|
+
return REDACTION_PLACEHOLDER_PATTERN.test(value);
|
|
2698
|
+
}
|
|
2699
|
+
function isExampleDomain(domain) {
|
|
2700
|
+
return EXAMPLE_DOMAIN_PATTERN.test(domain.toLowerCase());
|
|
2701
|
+
}
|
|
2702
|
+
function isAllowedPlaceholderValue(value) {
|
|
2703
|
+
const trimmed = stripTokenWrapper(value);
|
|
2704
|
+
const lower = trimmed.toLowerCase();
|
|
2705
|
+
return hasRedactionPlaceholder(trimmed) || /^0{12,}$/.test(trimmed) || /^x{6,}$/i.test(trimmed) || /^(?:example|synthetic|fixture)(?:[._:/ -][a-z0-9-]+)*$/i.test(trimmed) || lower === "example_only_no_approval" || lower === "example fixture only" || lower.startsWith("not run - offline example");
|
|
2706
|
+
}
|
|
2707
|
+
function isSensitiveFieldName(segment) {
|
|
2708
|
+
const normalized = segment.replace(/[^a-z0-9]/gi, "").toLowerCase();
|
|
2709
|
+
if (normalized.includes("redacted") || normalized.includes("masked") || normalized.includes("placeholder")) {
|
|
2710
|
+
return false;
|
|
2711
|
+
}
|
|
2712
|
+
return normalized === "authorization" || normalized === "proxyauthorization" || normalized === "apikey" || normalized === "xapikey" || normalized === "apitoken" || normalized === "accesstoken" || normalized === "refreshtoken" || normalized === "idtoken" || normalized === "clientsecret" || normalized === "secret" || normalized.endsWith("apikey") || normalized.endsWith("token") || normalized.endsWith("secret");
|
|
2713
|
+
}
|
|
2714
|
+
function lastStringPathSegment(path) {
|
|
2715
|
+
for (let index = path.length - 1; index >= 0; index -= 1) {
|
|
2716
|
+
const segment = path[index];
|
|
2717
|
+
if (typeof segment === "string") {
|
|
2718
|
+
return segment;
|
|
2719
|
+
}
|
|
2720
|
+
}
|
|
2721
|
+
return null;
|
|
2722
|
+
}
|
|
2723
|
+
function isSensitiveFieldPath(path) {
|
|
2724
|
+
const segment = lastStringPathSegment(path);
|
|
2725
|
+
return segment ? isSensitiveFieldName(segment) : false;
|
|
2726
|
+
}
|
|
2727
|
+
function isCommitShaPath(path) {
|
|
2728
|
+
return lastStringPathSegment(path) === "commitSha";
|
|
2729
|
+
}
|
|
2730
|
+
function shouldSkipGenericLongKeyScan(path) {
|
|
2731
|
+
const segment = lastStringPathSegment(path);
|
|
2732
|
+
return segment === "schemaVersion" || segment === "captureId" || segment === "evidenceId" || segment === "marketplaceId" || segment === "sourceType" || segment === "endpointPath" || segment === "redactedUrl" || segment === "expectedBaseUrl" || segment === "observedBaseUrl" || segment === "observedHost" || segment === "path" || path.includes("registryEvidenceIds") || path.includes("approvedReadOnlyEndpoints") || path.includes("returnedFieldNames");
|
|
2733
|
+
}
|
|
2734
|
+
function isAllowedEmailAddress(value) {
|
|
2735
|
+
const domain = value.split("@").pop();
|
|
2736
|
+
return Boolean(domain && isExampleDomain(domain)) || hasRedactionPlaceholder(value);
|
|
2737
|
+
}
|
|
2738
|
+
function isAllowedPhoneNumber(value) {
|
|
2739
|
+
const digits = value.replace(/\D/g, "");
|
|
2740
|
+
return /^0+$/.test(digits) || /^1?\d{3}55501\d{2}$/.test(digits) || hasRedactionPlaceholder(value);
|
|
2741
|
+
}
|
|
2742
|
+
function looksLikeLongKey(candidate) {
|
|
2743
|
+
if (isAllowedPlaceholderValue(candidate)) {
|
|
2744
|
+
return false;
|
|
2745
|
+
}
|
|
2746
|
+
const hasLetter = /[A-Za-z]/.test(candidate);
|
|
2747
|
+
const hasDigit = /\d/.test(candidate);
|
|
2748
|
+
const hasCredentialSeparator = /[_+=]/.test(candidate);
|
|
2749
|
+
const hasMixedCase = /[a-z]/.test(candidate) && /[A-Z]/.test(candidate);
|
|
2750
|
+
const isHexBlob = /^[a-f0-9]{32,}$/i.test(candidate);
|
|
2751
|
+
return hasLetter && hasDigit && (hasCredentialSeparator || hasMixedCase || isHexBlob);
|
|
2752
|
+
}
|
|
2753
|
+
function addUniqueRedactionCategory(categories, category) {
|
|
2754
|
+
if (!categories.includes(category)) {
|
|
2755
|
+
categories.push(category);
|
|
2756
|
+
}
|
|
2757
|
+
}
|
|
2758
|
+
function collectRedactionIssueCategories(value, path, options = {}) {
|
|
2759
|
+
const categories = [];
|
|
2760
|
+
const checkSensitiveFieldPath = options.checkSensitiveFieldPath ?? true;
|
|
2761
|
+
const checkGenericLongKey = options.checkGenericLongKey ?? true;
|
|
2762
|
+
if (checkSensitiveFieldPath && isSensitiveFieldPath(path) && !isAllowedPlaceholderValue(value)) {
|
|
2763
|
+
addUniqueRedactionCategory(categories, "sensitive field value");
|
|
2764
|
+
}
|
|
2765
|
+
for (const match of value.matchAll(BEARER_TOKEN_PATTERN)) {
|
|
2766
|
+
const token = match[1];
|
|
2767
|
+
if (token && !isAllowedPlaceholderValue(token)) {
|
|
2768
|
+
addUniqueRedactionCategory(categories, "bearer token");
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
for (const match of value.matchAll(AUTHORIZATION_HEADER_PATTERN)) {
|
|
2772
|
+
const headerValue = match[1];
|
|
2773
|
+
if (headerValue && !isAllowedPlaceholderValue(headerValue)) {
|
|
2774
|
+
addUniqueRedactionCategory(categories, "authorization header value");
|
|
2775
|
+
}
|
|
2776
|
+
}
|
|
2777
|
+
for (const match of value.matchAll(SENSITIVE_ASSIGNMENT_PATTERN)) {
|
|
2778
|
+
const assignedValue = match[1];
|
|
2779
|
+
if (assignedValue && !isAllowedPlaceholderValue(assignedValue)) {
|
|
2780
|
+
addUniqueRedactionCategory(categories, "token or secret assignment");
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
for (const match of value.matchAll(AGENTCENTRAL_API_KEY_PATTERN)) {
|
|
2784
|
+
if (!isAllowedPlaceholderValue(match[0])) {
|
|
2785
|
+
addUniqueRedactionCategory(categories, "agentcentral API key");
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2788
|
+
for (const match of value.matchAll(AMAZON_TOKEN_PATTERN)) {
|
|
2789
|
+
if (!isAllowedPlaceholderValue(match[0])) {
|
|
2790
|
+
addUniqueRedactionCategory(categories, "Amazon token");
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2793
|
+
for (const match of value.matchAll(AWS_ACCESS_KEY_PATTERN)) {
|
|
2794
|
+
if (!isAllowedPlaceholderValue(match[0])) {
|
|
2795
|
+
addUniqueRedactionCategory(categories, "AWS access key");
|
|
2796
|
+
}
|
|
2797
|
+
}
|
|
2798
|
+
for (const match of value.matchAll(EMAIL_ADDRESS_PATTERN)) {
|
|
2799
|
+
if (!isAllowedEmailAddress(match[0])) {
|
|
2800
|
+
addUniqueRedactionCategory(categories, "email address");
|
|
2801
|
+
}
|
|
2802
|
+
}
|
|
2803
|
+
for (const match of value.matchAll(PHONE_NUMBER_PATTERN)) {
|
|
2804
|
+
if (!isAllowedPhoneNumber(match[0])) {
|
|
2805
|
+
addUniqueRedactionCategory(categories, "phone number");
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2808
|
+
for (const match of value.matchAll(INTERNATIONAL_PHONE_NUMBER_PATTERN)) {
|
|
2809
|
+
if (!isAllowedPhoneNumber(match[0])) {
|
|
2810
|
+
addUniqueRedactionCategory(categories, "phone number");
|
|
2811
|
+
}
|
|
2812
|
+
}
|
|
2813
|
+
if (!checkGenericLongKey || isCommitShaPath(path) || shouldSkipGenericLongKeyScan(path)) {
|
|
2814
|
+
return categories;
|
|
2815
|
+
}
|
|
2816
|
+
for (const match of value.matchAll(LONG_KEY_LIKE_PATTERN)) {
|
|
2817
|
+
if (looksLikeLongKey(match[0])) {
|
|
2818
|
+
addUniqueRedactionCategory(categories, "long key-like string");
|
|
2819
|
+
}
|
|
2820
|
+
}
|
|
2821
|
+
return categories;
|
|
2822
|
+
}
|
|
2823
|
+
function shouldRedactCapturedCredentialValue(value) {
|
|
2824
|
+
const normalized = stripTokenWrapper(value).toLowerCase();
|
|
2825
|
+
return normalized !== "token" && normalized !== "secret" && normalized !== "value" && normalized !== "key" && normalized !== "credential" && normalized !== "credentials" && !isAllowedPlaceholderValue(value);
|
|
2826
|
+
}
|
|
2827
|
+
function replaceSensitiveSubstrings(value, placeholder) {
|
|
2828
|
+
let sanitized = value;
|
|
2829
|
+
sanitized = sanitized.replace(BEARER_TOKEN_PATTERN, (match, token) => {
|
|
2830
|
+
if (!token || !shouldRedactCapturedCredentialValue(token)) {
|
|
2831
|
+
return match;
|
|
2832
|
+
}
|
|
2833
|
+
return match.replace(token, placeholder);
|
|
2834
|
+
});
|
|
2835
|
+
sanitized = sanitized.replace(AUTHORIZATION_HEADER_PATTERN, (match, headerValue) => {
|
|
2836
|
+
if (!headerValue || !shouldRedactCapturedCredentialValue(headerValue)) {
|
|
2837
|
+
return match;
|
|
2838
|
+
}
|
|
2839
|
+
return match.replace(headerValue, placeholder);
|
|
2840
|
+
});
|
|
2841
|
+
sanitized = sanitized.replace(SENSITIVE_ASSIGNMENT_PATTERN, (match, assignedValue) => {
|
|
2842
|
+
if (!assignedValue || !shouldRedactCapturedCredentialValue(assignedValue)) {
|
|
2843
|
+
return match;
|
|
2844
|
+
}
|
|
2845
|
+
return match.replace(assignedValue, placeholder);
|
|
2846
|
+
});
|
|
2847
|
+
sanitized = sanitized.replace(AGENTCENTRAL_API_KEY_PATTERN, (match) => {
|
|
2848
|
+
return isAllowedPlaceholderValue(match) ? match : placeholder;
|
|
2849
|
+
});
|
|
2850
|
+
sanitized = sanitized.replace(AMAZON_TOKEN_PATTERN, (match) => {
|
|
2851
|
+
return isAllowedPlaceholderValue(match) ? match : placeholder;
|
|
2852
|
+
});
|
|
2853
|
+
sanitized = sanitized.replace(AWS_ACCESS_KEY_PATTERN, (match) => {
|
|
2854
|
+
return isAllowedPlaceholderValue(match) ? match : placeholder;
|
|
2855
|
+
});
|
|
2856
|
+
sanitized = sanitized.replace(EMAIL_ADDRESS_PATTERN, (match) => {
|
|
2857
|
+
return isAllowedEmailAddress(match) ? match : placeholder;
|
|
2858
|
+
});
|
|
2859
|
+
sanitized = sanitized.replace(PHONE_NUMBER_PATTERN, (match) => {
|
|
2860
|
+
return isAllowedPhoneNumber(match) ? match : placeholder;
|
|
2861
|
+
});
|
|
2862
|
+
sanitized = sanitized.replace(INTERNATIONAL_PHONE_NUMBER_PATTERN, (match) => {
|
|
2863
|
+
return isAllowedPhoneNumber(match) ? match : placeholder;
|
|
2864
|
+
});
|
|
2865
|
+
sanitized = sanitized.replace(LONG_KEY_LIKE_PATTERN, (match) => {
|
|
2866
|
+
return looksLikeLongKey(match) ? placeholder : match;
|
|
2867
|
+
});
|
|
2868
|
+
return sanitized;
|
|
2869
|
+
}
|
|
2870
|
+
function safeIssueDisplay(value) {
|
|
2871
|
+
return replaceSensitiveSubstrings(value, REDACTED_VALUE_SEGMENT);
|
|
2872
|
+
}
|
|
2873
|
+
function safeIssueKeyDisplay(value) {
|
|
2874
|
+
return replaceSensitiveSubstrings(value, REDACTED_PATH_SEGMENT);
|
|
2875
|
+
}
|
|
2876
|
+
function sanitizeIssuePath(path) {
|
|
2877
|
+
return path.map((segment) => {
|
|
2878
|
+
if (typeof segment === "string") {
|
|
2879
|
+
return safeIssueKeyDisplay(segment);
|
|
2880
|
+
}
|
|
2881
|
+
return segment;
|
|
2882
|
+
});
|
|
2883
|
+
}
|
|
2884
|
+
function pathSegmentContainsSensitiveEvidence(segment) {
|
|
2885
|
+
return collectRedactionIssueCategories(segment, [segment], {
|
|
2886
|
+
checkSensitiveFieldPath: false,
|
|
2887
|
+
checkGenericLongKey: true
|
|
2888
|
+
}).length > 0;
|
|
2889
|
+
}
|
|
2890
|
+
function sanitizeRedactionPath(path) {
|
|
2891
|
+
return path.map((segment) => {
|
|
2892
|
+
if (typeof segment === "string" && pathSegmentContainsSensitiveEvidence(segment)) {
|
|
2893
|
+
return REDACTED_PATH_SEGMENT;
|
|
2894
|
+
}
|
|
2895
|
+
return segment;
|
|
2896
|
+
});
|
|
2897
|
+
}
|
|
2898
|
+
function addRedactionIssue(ctx, path, category) {
|
|
2899
|
+
const safePath = sanitizeRedactionPath(path);
|
|
2900
|
+
addIssue(
|
|
2901
|
+
ctx,
|
|
2902
|
+
safePath,
|
|
2903
|
+
`Potential unredacted ${category} in evidence capture at ${pathToString(safePath)}; replace the value or dynamic key with [REDACTED], <redacted>, ***, REDACTED, an example.invalid address, or another explicit synthetic placeholder.`
|
|
2904
|
+
);
|
|
2905
|
+
}
|
|
2906
|
+
function validateEvidenceStringRedaction(value, path, ctx) {
|
|
2907
|
+
collectRedactionIssueCategories(value, path).forEach((category) => {
|
|
2908
|
+
addRedactionIssue(ctx, path, category);
|
|
2909
|
+
});
|
|
2910
|
+
}
|
|
2911
|
+
function validateEvidenceObjectKeyRedaction(key, path, ctx) {
|
|
2912
|
+
const keyPath = [...path, key];
|
|
2913
|
+
collectRedactionIssueCategories(key, keyPath, {
|
|
2914
|
+
checkSensitiveFieldPath: false,
|
|
2915
|
+
checkGenericLongKey: true
|
|
2916
|
+
}).forEach((category) => {
|
|
2917
|
+
addRedactionIssue(ctx, keyPath, `object key ${category}`);
|
|
2918
|
+
});
|
|
2919
|
+
}
|
|
2920
|
+
function validateEvidenceRedactionGuardrails(value, ctx, path = []) {
|
|
2921
|
+
if (typeof value === "string") {
|
|
2922
|
+
validateEvidenceStringRedaction(value, path, ctx);
|
|
2923
|
+
return;
|
|
2924
|
+
}
|
|
2925
|
+
if (Array.isArray(value)) {
|
|
2926
|
+
value.forEach((item, index) => validateEvidenceRedactionGuardrails(item, ctx, [...path, index]));
|
|
2927
|
+
return;
|
|
2928
|
+
}
|
|
2929
|
+
if (value && typeof value === "object") {
|
|
2930
|
+
Object.entries(value).forEach(([key, nestedValue]) => {
|
|
2931
|
+
validateEvidenceObjectKeyRedaction(key, path, ctx);
|
|
2932
|
+
validateEvidenceRedactionGuardrails(nestedValue, ctx, [...path, key]);
|
|
2933
|
+
});
|
|
2934
|
+
}
|
|
2935
|
+
}
|
|
2936
|
+
function validateRegistryLinks(capture, ctx) {
|
|
2937
|
+
const uniqueEvidenceIds = new Set(capture.registryEvidenceIds);
|
|
2938
|
+
if (uniqueEvidenceIds.size !== capture.registryEvidenceIds.length) {
|
|
2939
|
+
addIssue(ctx, ["registryEvidenceIds"], "Expected registry evidence IDs to be unique");
|
|
2940
|
+
}
|
|
2941
|
+
if (!uniqueEvidenceIds.has(capture.evidenceId)) {
|
|
2942
|
+
addIssue(ctx, ["evidenceId"], "Primary evidence ID must also appear in registryEvidenceIds");
|
|
2943
|
+
}
|
|
2944
|
+
const primaryRecord = getMarketplaceCapabilityEvidenceRecord(capture.evidenceId);
|
|
2945
|
+
if (!primaryRecord) {
|
|
2946
|
+
addIssue(ctx, ["evidenceId"], `Unknown marketplace capability evidence ID: ${safeIssueDisplay(capture.evidenceId)}`);
|
|
2947
|
+
} else {
|
|
2948
|
+
if (primaryRecord.sourceType !== "live_smoke") {
|
|
2949
|
+
addIssue(ctx, ["evidenceId"], "Capture artifacts are only valid for live_smoke registry records");
|
|
2950
|
+
}
|
|
2951
|
+
if (primaryRecord.operation !== "read") {
|
|
2952
|
+
addIssue(ctx, ["evidenceId"], "Capture artifacts are only valid for read-only registry records");
|
|
2953
|
+
}
|
|
2954
|
+
}
|
|
2955
|
+
const nonMarketplaceScopes = /* @__PURE__ */ new Set([
|
|
2956
|
+
GLOBAL_MARKETPLACE_CAPABILITY_EVIDENCE_SCOPE,
|
|
2957
|
+
COMMON_MARKETPLACE_CAPABILITY_EVIDENCE_SCOPE
|
|
2958
|
+
]);
|
|
2959
|
+
capture.registryEvidenceIds.forEach((evidenceId, index) => {
|
|
2960
|
+
const record = getMarketplaceCapabilityEvidenceRecord(evidenceId);
|
|
2961
|
+
if (!record) {
|
|
2962
|
+
addIssue(ctx, ["registryEvidenceIds", index], `Unknown marketplace capability evidence ID: ${safeIssueDisplay(evidenceId)}`);
|
|
2963
|
+
return;
|
|
2964
|
+
}
|
|
2965
|
+
if (!nonMarketplaceScopes.has(record.marketplaceId) && record.marketplaceId !== capture.marketplaceId) {
|
|
2966
|
+
addIssue(
|
|
2967
|
+
ctx,
|
|
2968
|
+
["registryEvidenceIds", index],
|
|
2969
|
+
`Evidence ID ${safeIssueDisplay(evidenceId)} is scoped to ${safeIssueDisplay(record.marketplaceId)}, not ${safeIssueDisplay(capture.marketplaceId)}`
|
|
2970
|
+
);
|
|
2971
|
+
}
|
|
2972
|
+
});
|
|
2973
|
+
}
|
|
2974
|
+
function validateStatusFields(capture, ctx) {
|
|
2975
|
+
if (capture.status === "example") {
|
|
2976
|
+
if (capture.capturedAt) {
|
|
2977
|
+
addIssue(ctx, ["capturedAt"], "Example captures must omit capturedAt so they are not mistaken for recorded evidence");
|
|
2978
|
+
}
|
|
2979
|
+
if (capture.artifact.kind !== "example_fixture") {
|
|
2980
|
+
addIssue(ctx, ["artifact", "kind"], "Example captures must use artifact.kind=example_fixture");
|
|
2981
|
+
}
|
|
2982
|
+
return;
|
|
2983
|
+
}
|
|
2984
|
+
if (!capture.capturedAt) {
|
|
2985
|
+
addIssue(ctx, ["capturedAt"], "Captured or failed real smoke captures must include capturedAt");
|
|
2986
|
+
}
|
|
2987
|
+
if (capture.artifact.kind !== "captured_artifact") {
|
|
2988
|
+
addIssue(ctx, ["artifact", "kind"], "Real smoke captures must use artifact.kind=captured_artifact");
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
function validateMarketplaceFacts(capture, ctx) {
|
|
2992
|
+
const marketplace = getMarketplaceDefinition(capture.marketplaceId);
|
|
2993
|
+
if (!marketplace) {
|
|
2994
|
+
addIssue(ctx, ["marketplaceId"], `Unknown marketplace ID: ${safeIssueDisplay(capture.marketplaceId)}`);
|
|
2995
|
+
return;
|
|
2996
|
+
}
|
|
2997
|
+
const expectedFactValues = {
|
|
2998
|
+
marketplaceId: capture.marketplaceId,
|
|
2999
|
+
countryCode: marketplace.countryCode,
|
|
3000
|
+
currencyCode: marketplace.currencyCode,
|
|
3001
|
+
reportingTimeZone: marketplace.defaultReportingTimeZone
|
|
3002
|
+
};
|
|
3003
|
+
for (const [factName, expectedValue] of Object.entries(expectedFactValues)) {
|
|
3004
|
+
const fact = capture.observedFacts[factName];
|
|
3005
|
+
const factPath = ["observedFacts", factName];
|
|
3006
|
+
if (fact.expected !== expectedValue) {
|
|
3007
|
+
addIssue(ctx, [...factPath, "expected"], `Expected ${factName} to match marketplace registry value ${expectedValue}`);
|
|
3008
|
+
}
|
|
3009
|
+
if (fact.observed === null && fact.matchesExpected) {
|
|
3010
|
+
addIssue(ctx, [...factPath, "matchesExpected"], `Cannot mark ${factName} as matching when observed is null`);
|
|
3011
|
+
}
|
|
3012
|
+
if (fact.observed !== null && fact.matchesExpected !== (fact.observed === fact.expected)) {
|
|
3013
|
+
addIssue(ctx, [...factPath, "matchesExpected"], `matchesExpected must reflect whether observed equals expected for ${factName}`);
|
|
3014
|
+
}
|
|
3015
|
+
if (capture.status !== "failed" && (!fact.observed || !fact.matchesExpected)) {
|
|
3016
|
+
addIssue(ctx, factPath, `Non-failed captures must include matching observed ${factName} evidence`);
|
|
3017
|
+
}
|
|
3018
|
+
}
|
|
3019
|
+
const expectedEndpoint = capture.sourceType === "ads_api_readonly_smoke" ? {
|
|
3020
|
+
service: "ads",
|
|
3021
|
+
region: marketplace.adsRegion,
|
|
3022
|
+
baseUrl: marketplace.adsApiBaseUrl
|
|
3023
|
+
} : {
|
|
3024
|
+
service: "sp_api",
|
|
3025
|
+
region: marketplace.spApiRegion,
|
|
3026
|
+
baseUrl: marketplace.spApiBaseUrl
|
|
3027
|
+
};
|
|
3028
|
+
if (capture.endpoint.service !== expectedEndpoint.service) {
|
|
3029
|
+
addIssue(ctx, ["endpoint", "service"], `Expected endpoint.service=${expectedEndpoint.service} for ${capture.sourceType}`);
|
|
3030
|
+
}
|
|
3031
|
+
if (capture.endpoint.region !== expectedEndpoint.region) {
|
|
3032
|
+
addIssue(ctx, ["endpoint", "region"], `Expected endpoint.region=${safeIssueDisplay(expectedEndpoint.region)} for marketplace ${safeIssueDisplay(capture.marketplaceId)}`);
|
|
3033
|
+
}
|
|
3034
|
+
if (capture.endpoint.expectedBaseUrl !== expectedEndpoint.baseUrl) {
|
|
3035
|
+
addIssue(ctx, ["endpoint", "expectedBaseUrl"], `Expected endpoint base URL to match registry value ${expectedEndpoint.baseUrl}`);
|
|
3036
|
+
}
|
|
3037
|
+
const observedHostFromUrl = hostForUrl(capture.endpoint.observedBaseUrl);
|
|
3038
|
+
if (observedHostFromUrl && observedHostFromUrl !== capture.endpoint.observedHost) {
|
|
3039
|
+
addIssue(ctx, ["endpoint", "observedHost"], "observedHost must match observedBaseUrl host");
|
|
3040
|
+
}
|
|
3041
|
+
const expectedHost = hostForUrl(expectedEndpoint.baseUrl);
|
|
3042
|
+
if (capture.status !== "failed" && expectedHost && capture.endpoint.observedHost !== expectedHost) {
|
|
3043
|
+
addIssue(ctx, ["endpoint", "observedHost"], `Non-failed captures must observe expected host ${expectedHost}`);
|
|
3044
|
+
}
|
|
3045
|
+
}
|
|
3046
|
+
var marketplaceCapabilityEvidenceCaptureSchema = marketplaceCapabilityEvidenceCaptureBaseSchema.superRefine((capture, ctx) => {
|
|
3047
|
+
validateRegistryLinks(capture, ctx);
|
|
3048
|
+
validateStatusFields(capture, ctx);
|
|
3049
|
+
validateMarketplaceFacts(capture, ctx);
|
|
3050
|
+
validateEvidenceRedactionGuardrails(capture, ctx);
|
|
3051
|
+
});
|
|
349
3052
|
|
|
350
3053
|
// src/format.ts
|
|
351
3054
|
function isTabular(value) {
|
|
@@ -460,9 +3163,12 @@ function writeEnvelopeFrom(result) {
|
|
|
460
3163
|
return structured;
|
|
461
3164
|
}
|
|
462
3165
|
function toolClassification(def) {
|
|
3166
|
+
const hint = def.annotations;
|
|
3167
|
+
const annotationWrite = hint?.destructiveHint === true || hint?.readOnlyHint === false;
|
|
463
3168
|
const properties = def.inputSchema.properties;
|
|
464
3169
|
const props = properties && typeof properties === "object" ? properties : {};
|
|
465
|
-
const
|
|
3170
|
+
const schemaWrite = "confirm" in props && "idempotency_key" in props;
|
|
3171
|
+
const isWrite = annotationWrite || schemaWrite;
|
|
466
3172
|
return {
|
|
467
3173
|
isWrite,
|
|
468
3174
|
supportsPreview: isWrite
|
|
@@ -613,6 +3319,11 @@ var TOOL_DOMAIN_BY_NAME = TOOL_DOMAINS.reduce(
|
|
|
613
3319
|
},
|
|
614
3320
|
{}
|
|
615
3321
|
);
|
|
3322
|
+
function toolDomain(def) {
|
|
3323
|
+
const metaDomain = def._meta?.["agentcentral/domain"];
|
|
3324
|
+
if (typeof metaDomain === "string") return metaDomain;
|
|
3325
|
+
return TOOL_DOMAIN_BY_NAME[def.name];
|
|
3326
|
+
}
|
|
616
3327
|
function requireTool(tools, name) {
|
|
617
3328
|
const def = tools.find((tool) => tool.name === name);
|
|
618
3329
|
if (!def) {
|
|
@@ -632,7 +3343,7 @@ async function toolsList(ctx) {
|
|
|
632
3343
|
const client = await ctx.getClient();
|
|
633
3344
|
const tools = await client.listTools({ timeoutMs: ctx.flags.timeoutMs });
|
|
634
3345
|
const domainFilter = ctx.flags.domain;
|
|
635
|
-
const filtered = domainFilter ? tools.filter((def) =>
|
|
3346
|
+
const filtered = domainFilter ? tools.filter((def) => toolDomain(def) === domainFilter) : tools;
|
|
636
3347
|
const rows = filtered.map((def) => ({
|
|
637
3348
|
name: def.name,
|
|
638
3349
|
write: toolClassification(def).isWrite,
|
|
@@ -750,7 +3461,7 @@ async function toolsCall(ctx, name, inputSpec) {
|
|
|
750
3461
|
const value = selectOutputValue(result);
|
|
751
3462
|
const rendered = formatOutput(value, ctx.flags.format);
|
|
752
3463
|
if (ctx.flags.output) {
|
|
753
|
-
await writeFile(ctx.flags.output, rendered, "utf8");
|
|
3464
|
+
await writeFile(ctx.flags.output, rendered, { encoding: "utf8", mode: 384 });
|
|
754
3465
|
ctx.err(`wrote result to ${ctx.flags.output}`);
|
|
755
3466
|
} else {
|
|
756
3467
|
ctx.out(rendered);
|
|
@@ -766,9 +3477,8 @@ async function readStdinOnce() {
|
|
|
766
3477
|
}
|
|
767
3478
|
|
|
768
3479
|
// src/commands/mcp.ts
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
TOOL_DOMAINS2.flatMap(
|
|
3480
|
+
var DOMAIN_BY_TOOL2 = new Map(
|
|
3481
|
+
TOOL_DOMAINS.flatMap(
|
|
772
3482
|
(domain) => domain.tools.map((tool) => [tool.name, domain.serverDomain])
|
|
773
3483
|
)
|
|
774
3484
|
);
|
|
@@ -779,7 +3489,7 @@ function filterToolsList(tools, opts) {
|
|
|
779
3489
|
return false;
|
|
780
3490
|
}
|
|
781
3491
|
if (domainSet) {
|
|
782
|
-
const domain =
|
|
3492
|
+
const domain = DOMAIN_BY_TOOL2.get(def.name);
|
|
783
3493
|
if (domain !== void 0 && !domainSet.has(domain)) {
|
|
784
3494
|
return false;
|
|
785
3495
|
}
|
|
@@ -963,7 +3673,7 @@ async function mcpTest(ctx) {
|
|
|
963
3673
|
}
|
|
964
3674
|
|
|
965
3675
|
// src/commands/diagnostics.ts
|
|
966
|
-
import { statSync
|
|
3676
|
+
import { statSync } from "fs";
|
|
967
3677
|
function payloadFromResult(result) {
|
|
968
3678
|
if (result.structuredContent) {
|
|
969
3679
|
return result.structuredContent;
|
|
@@ -1054,7 +3764,7 @@ function renderMarkdownReport(checks) {
|
|
|
1054
3764
|
function checkConfigPerms(env) {
|
|
1055
3765
|
const path = configPath(env);
|
|
1056
3766
|
try {
|
|
1057
|
-
const stat =
|
|
3767
|
+
const stat = statSync(path);
|
|
1058
3768
|
if (process.platform === "win32") {
|
|
1059
3769
|
return { name: "config perms", status: "ok", detail: `${path} (POSIX perms not enforced on Windows)` };
|
|
1060
3770
|
}
|
|
@@ -1071,7 +3781,7 @@ function checkConfigPerms(env) {
|
|
|
1071
3781
|
return { name: "config perms", status: "info", detail: `no config file (${path})` };
|
|
1072
3782
|
}
|
|
1073
3783
|
}
|
|
1074
|
-
async function checkHealth(origin, timeoutMs) {
|
|
3784
|
+
async function checkHealth(origin, timeoutMs, redact) {
|
|
1075
3785
|
if (!origin) {
|
|
1076
3786
|
return {
|
|
1077
3787
|
reachable: false,
|
|
@@ -1079,6 +3789,7 @@ async function checkHealth(origin, timeoutMs) {
|
|
|
1079
3789
|
};
|
|
1080
3790
|
}
|
|
1081
3791
|
const url = `${origin}/health`;
|
|
3792
|
+
const shown = redact ? "/health" : url;
|
|
1082
3793
|
try {
|
|
1083
3794
|
const res = await fetch(url, {
|
|
1084
3795
|
method: "GET",
|
|
@@ -1088,7 +3799,7 @@ async function checkHealth(origin, timeoutMs) {
|
|
|
1088
3799
|
if (!res.ok) {
|
|
1089
3800
|
return {
|
|
1090
3801
|
reachable: false,
|
|
1091
|
-
check: { name: "hosted /health", status: "fail", detail: `${
|
|
3802
|
+
check: { name: "hosted /health", status: "fail", detail: `${shown} -> HTTP ${res.status}` }
|
|
1092
3803
|
};
|
|
1093
3804
|
}
|
|
1094
3805
|
let status;
|
|
@@ -1099,14 +3810,14 @@ async function checkHealth(origin, timeoutMs) {
|
|
|
1099
3810
|
status = void 0;
|
|
1100
3811
|
}
|
|
1101
3812
|
if (status === "ok") {
|
|
1102
|
-
return { reachable: true, check: { name: "hosted /health", status: "ok", detail:
|
|
3813
|
+
return { reachable: true, check: { name: "hosted /health", status: "ok", detail: shown } };
|
|
1103
3814
|
}
|
|
1104
3815
|
return {
|
|
1105
3816
|
reachable: false,
|
|
1106
3817
|
check: {
|
|
1107
3818
|
name: "hosted /health",
|
|
1108
3819
|
status: "warn",
|
|
1109
|
-
detail: `${
|
|
3820
|
+
detail: `${shown} reachable but status=${String(status)}`
|
|
1110
3821
|
}
|
|
1111
3822
|
};
|
|
1112
3823
|
} catch (error) {
|
|
@@ -1115,28 +3826,29 @@ async function checkHealth(origin, timeoutMs) {
|
|
|
1115
3826
|
check: {
|
|
1116
3827
|
name: "hosted /health",
|
|
1117
3828
|
status: "fail",
|
|
1118
|
-
detail: `${
|
|
3829
|
+
detail: `${shown} unreachable: ${error instanceof Error ? error.message : String(error)}`
|
|
1119
3830
|
}
|
|
1120
3831
|
};
|
|
1121
3832
|
}
|
|
1122
3833
|
}
|
|
1123
|
-
async function checkAuth(ctx) {
|
|
3834
|
+
async function checkAuth(ctx, redact) {
|
|
1124
3835
|
try {
|
|
1125
3836
|
const auth = await ctx.resolveAuth();
|
|
1126
3837
|
const profile = auth.profileName ? ` profile=${auth.profileName}` : "";
|
|
3838
|
+
const endpoint = redact ? "" : ` endpoint=${auth.endpoint}`;
|
|
1127
3839
|
return {
|
|
1128
3840
|
auth,
|
|
1129
3841
|
check: {
|
|
1130
3842
|
name: "auth",
|
|
1131
3843
|
status: "ok",
|
|
1132
|
-
detail: `${redactKey(auth.apiKey)} (source=${auth.source}${profile})
|
|
3844
|
+
detail: `${redactKey(auth.apiKey)} (source=${auth.source}${profile})${endpoint}`
|
|
1133
3845
|
}
|
|
1134
3846
|
};
|
|
1135
3847
|
} catch {
|
|
1136
3848
|
return { auth: void 0, check: { name: "auth", status: "fail", detail: "no API key" } };
|
|
1137
3849
|
}
|
|
1138
3850
|
}
|
|
1139
|
-
function accountCheckFromPayload(payload) {
|
|
3851
|
+
function accountCheckFromPayload(payload, redact) {
|
|
1140
3852
|
const info = payload;
|
|
1141
3853
|
const mp = info.marketplace;
|
|
1142
3854
|
const where = mp ? mp.country_name ?? mp.country_code ?? mp.marketplace_id ?? "unknown" : "(none)";
|
|
@@ -1145,23 +3857,27 @@ function accountCheckFromPayload(payload) {
|
|
|
1145
3857
|
const domains = info.enabled_domains ?? [];
|
|
1146
3858
|
const reads = info.tools?.read_enabled ?? 0;
|
|
1147
3859
|
const writes = info.tools?.write_enabled ?? 0;
|
|
3860
|
+
const prefix = redact ? "" : `${where} \xB7 `;
|
|
1148
3861
|
return {
|
|
1149
3862
|
name: "account",
|
|
1150
3863
|
status: "ok",
|
|
1151
|
-
detail: `${
|
|
3864
|
+
detail: `${prefix}seller_central=${sc}, amazon_ads=${ads} \xB7 domains=${domains.length} \xB7 ${reads} read / ${writes} write tools`
|
|
1152
3865
|
};
|
|
1153
3866
|
}
|
|
1154
3867
|
async function doctor(ctx) {
|
|
3868
|
+
const redact = ctx.flags.redact === true;
|
|
1155
3869
|
const checks = [];
|
|
1156
3870
|
checks.push({ name: "cli version", status: "info", detail: CLI_VERSION });
|
|
1157
3871
|
checks.push({ name: "node version", status: "info", detail: process.version });
|
|
1158
3872
|
checks.push({ name: "platform", status: "info", detail: process.platform });
|
|
1159
|
-
|
|
1160
|
-
|
|
3873
|
+
if (!redact) {
|
|
3874
|
+
checks.push({ name: "install path", status: "info", detail: process.argv[1] ?? "(unknown)" });
|
|
3875
|
+
}
|
|
3876
|
+
const { auth, check: authCheck } = await checkAuth(ctx, redact);
|
|
1161
3877
|
const authed = auth !== void 0;
|
|
1162
3878
|
const checksWithAuth = [...checks, authCheck, checkConfigPerms(ctx.env)];
|
|
1163
3879
|
const origin = auth ? originFromEndpoint(auth.endpoint) : void 0;
|
|
1164
|
-
const { reachable, check: healthCheck } = await checkHealth(origin, ctx.flags.timeoutMs);
|
|
3880
|
+
const { reachable, check: healthCheck } = await checkHealth(origin, ctx.flags.timeoutMs, redact);
|
|
1165
3881
|
const checksWithHealth = auth ? [...checksWithAuth, healthCheck] : checksWithAuth;
|
|
1166
3882
|
const finalChecks = await (async () => {
|
|
1167
3883
|
if (!authed) {
|
|
@@ -1171,7 +3887,7 @@ async function doctor(ctx) {
|
|
|
1171
3887
|
const client = await ctx.getClient();
|
|
1172
3888
|
const result = await client.callTool("get_account_info", {});
|
|
1173
3889
|
const payload = payloadFromResult(result);
|
|
1174
|
-
return [...checksWithHealth, accountCheckFromPayload(payload)];
|
|
3890
|
+
return [...checksWithHealth, accountCheckFromPayload(payload, redact)];
|
|
1175
3891
|
} catch (error) {
|
|
1176
3892
|
const detail = error instanceof Error ? error.message : String(error);
|
|
1177
3893
|
return [
|
|
@@ -1180,7 +3896,6 @@ async function doctor(ctx) {
|
|
|
1180
3896
|
];
|
|
1181
3897
|
}
|
|
1182
3898
|
})();
|
|
1183
|
-
void ctx.flags.redact;
|
|
1184
3899
|
const markdown = ctx.flags.format === "markdown";
|
|
1185
3900
|
const report = markdown ? renderMarkdownReport(finalChecks) : renderTextReport(finalChecks);
|
|
1186
3901
|
ctx.out(report);
|
|
@@ -1455,9 +4170,25 @@ function extraFlags(ctx) {
|
|
|
1455
4170
|
return {
|
|
1456
4171
|
since: flags.since,
|
|
1457
4172
|
groupBy: flags.groupBy,
|
|
1458
|
-
asin: flags.asin
|
|
4173
|
+
asin: flags.asin,
|
|
4174
|
+
fulfillmentChannel: flags.fulfillmentChannel
|
|
1459
4175
|
};
|
|
1460
4176
|
}
|
|
4177
|
+
var FULFILLMENT_CHANNELS = ["AFN", "MFN"];
|
|
4178
|
+
function parseFulfillmentChannel(value) {
|
|
4179
|
+
if (value === void 0) {
|
|
4180
|
+
return void 0;
|
|
4181
|
+
}
|
|
4182
|
+
const normalized = value.trim().toUpperCase();
|
|
4183
|
+
const match = FULFILLMENT_CHANNELS.find((channel) => channel === normalized);
|
|
4184
|
+
if (!match) {
|
|
4185
|
+
throw new CliError(
|
|
4186
|
+
2 /* UsageError */,
|
|
4187
|
+
`invalid --fulfillment-channel: ${value} (expected AFN or MFN)`
|
|
4188
|
+
);
|
|
4189
|
+
}
|
|
4190
|
+
return match;
|
|
4191
|
+
}
|
|
1461
4192
|
function selectOutputValue2(result) {
|
|
1462
4193
|
if (result.structuredContent !== void 0) {
|
|
1463
4194
|
return result.structuredContent;
|
|
@@ -1491,7 +4222,7 @@ async function emit(ctx, name, args) {
|
|
|
1491
4222
|
const value = selectOutputValue2(result);
|
|
1492
4223
|
const rendered = formatOutput(value, ctx.flags.format);
|
|
1493
4224
|
if (ctx.flags.output) {
|
|
1494
|
-
await writeFile2(ctx.flags.output, rendered, "utf8");
|
|
4225
|
+
await writeFile2(ctx.flags.output, rendered, { encoding: "utf8", mode: 384 });
|
|
1495
4226
|
ctx.err(`wrote result to ${ctx.flags.output}`);
|
|
1496
4227
|
} else {
|
|
1497
4228
|
ctx.out(rendered);
|
|
@@ -1519,6 +4250,25 @@ async function actionsHistory(ctx) {
|
|
|
1519
4250
|
const dates = parseSince(since);
|
|
1520
4251
|
return emit(ctx, "get_action_history", { ...dates, ...limitArg(ctx) });
|
|
1521
4252
|
}
|
|
4253
|
+
async function todaysSales(ctx) {
|
|
4254
|
+
const { fulfillmentChannel } = extraFlags(ctx);
|
|
4255
|
+
const channel = parseFulfillmentChannel(fulfillmentChannel);
|
|
4256
|
+
const channelArg = channel ? { fulfillment_channel: channel } : {};
|
|
4257
|
+
return emit(ctx, "get_todays_sales", { ...channelArg, ...limitArg(ctx) });
|
|
4258
|
+
}
|
|
4259
|
+
async function orders(ctx) {
|
|
4260
|
+
const { since, asin, fulfillmentChannel } = extraFlags(ctx);
|
|
4261
|
+
const dates = parseSince(since);
|
|
4262
|
+
const asinArg = asin ? { asin } : {};
|
|
4263
|
+
const channel = parseFulfillmentChannel(fulfillmentChannel);
|
|
4264
|
+
const channelArg = channel ? { fulfillment_channel: channel } : {};
|
|
4265
|
+
return emit(ctx, "get_orders", { ...dates, ...asinArg, ...channelArg, ...limitArg(ctx) });
|
|
4266
|
+
}
|
|
4267
|
+
async function inventoryRisk(ctx) {
|
|
4268
|
+
const { asin } = extraFlags(ctx);
|
|
4269
|
+
const asinArg = asin ? { asin } : {};
|
|
4270
|
+
return emit(ctx, "get_inventory_risk_triage", { ...asinArg, ...limitArg(ctx) });
|
|
4271
|
+
}
|
|
1522
4272
|
|
|
1523
4273
|
// src/cli.ts
|
|
1524
4274
|
var FORMATS = ["json", "ndjson", "table", "csv", "markdown"];
|
|
@@ -1538,6 +4288,7 @@ var COMMAND_NAMES = [
|
|
|
1538
4288
|
"auth status",
|
|
1539
4289
|
"auth logout",
|
|
1540
4290
|
"inventory health",
|
|
4291
|
+
"inventory risk",
|
|
1541
4292
|
"ads performance",
|
|
1542
4293
|
"catalog quality",
|
|
1543
4294
|
"actions history",
|
|
@@ -1750,7 +4501,7 @@ async function run(argv) {
|
|
|
1750
4501
|
);
|
|
1751
4502
|
withGlobalOptions(cli.command("ads performance", "summarize campaign performance")).option("--since <dur>", "lookback window: a relative duration like 30d or a YYYY-MM-DD date").option("--group-by <field>", "advisory grain hint (documented; not wired server-side)").action(
|
|
1752
4503
|
(options) => dispatch((ctx) => adsPerformance(ctx), options, {
|
|
1753
|
-
extra: { since: asString(options.since), groupBy: asString(options
|
|
4504
|
+
extra: { since: asString(options.since), groupBy: asString(options.groupBy) }
|
|
1754
4505
|
})
|
|
1755
4506
|
);
|
|
1756
4507
|
withGlobalOptions(cli.command("catalog quality", "summarize listing quality")).option("--asin <asin>", "scope to a single ASIN").action(
|
|
@@ -1759,6 +4510,23 @@ async function run(argv) {
|
|
|
1759
4510
|
withGlobalOptions(cli.command("actions history", "list write-action history")).option("--since <dur>", "lookback window: a relative duration like 30d or a YYYY-MM-DD date").action(
|
|
1760
4511
|
(options) => dispatch((ctx) => actionsHistory(ctx), options, { extra: { since: asString(options.since) } })
|
|
1761
4512
|
);
|
|
4513
|
+
withGlobalOptions(cli.command("today", "summarize today's sales")).option("--fulfillment-channel <channel>", "filter by fulfillment channel: AFN or MFN").action(
|
|
4514
|
+
(options) => dispatch((ctx) => todaysSales(ctx), options, {
|
|
4515
|
+
extra: { fulfillmentChannel: asString(options.fulfillmentChannel) }
|
|
4516
|
+
})
|
|
4517
|
+
);
|
|
4518
|
+
withGlobalOptions(cli.command("orders", "list orders")).option("--since <dur>", "lookback window: a relative duration like 30d or a YYYY-MM-DD date").option("--asin <asin>", "scope to a single ASIN").option("--fulfillment-channel <channel>", "filter by fulfillment channel: AFN or MFN").action(
|
|
4519
|
+
(options) => dispatch((ctx) => orders(ctx), options, {
|
|
4520
|
+
extra: {
|
|
4521
|
+
since: asString(options.since),
|
|
4522
|
+
asin: asString(options.asin),
|
|
4523
|
+
fulfillmentChannel: asString(options.fulfillmentChannel)
|
|
4524
|
+
}
|
|
4525
|
+
})
|
|
4526
|
+
);
|
|
4527
|
+
withGlobalOptions(cli.command("inventory risk", "triage inventory risk")).option("--asin <asin>", "scope to a single ASIN").action(
|
|
4528
|
+
(options) => dispatch((ctx) => inventoryRisk(ctx), options, { extra: { asin: asString(options.asin) } })
|
|
4529
|
+
);
|
|
1762
4530
|
cli.help();
|
|
1763
4531
|
cli.version(CLI_VERSION);
|
|
1764
4532
|
try {
|