ebay-mcp-remote-edition 3.3.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -9
- package/build/validation/effective-context.js +77 -0
- package/build/validation/providers/ebay-research.js +904 -0
- package/build/validation/providers/ebay-sold.js +361 -44
- package/build/validation/providers/query-utils.js +331 -52
- package/build/validation/providers/research.js +3 -1
- package/build/validation/providers/social.js +23 -2
- package/build/validation/providers/terapeak.js +780 -26
- package/build/validation/recommendation.js +85 -12
- package/build/validation/run-validation.js +102 -41
- package/build/validation/schemas.js +53 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -458,11 +458,13 @@ The hosted backend now includes a deployment-oriented validation pipeline for no
|
|
|
458
458
|
Current module layout:
|
|
459
459
|
|
|
460
460
|
- [`src/validation/types.ts`](src/validation/types.ts) — request/response contracts for validation runs, decision payloads, debug payloads, and provider signal types
|
|
461
|
+
- [`src/validation/effective-context.ts`](src/validation/effective-context.ts) — source-aware normalization layer that converts raw request payloads into a first-class effective validation context for item and event runs
|
|
461
462
|
- [`src/validation/run-validation.ts`](src/validation/run-validation.ts) — orchestration entrypoint that validates input, queries providers, merges signals, and returns writes/decision/debug output
|
|
462
463
|
- [`src/validation/recommendation.ts`](src/validation/recommendation.ts) — recommendation and automation decision logic
|
|
463
464
|
- [`src/validation/providers/ebay.ts`](src/validation/providers/ebay.ts) — live eBay browse-market snapshot provider using the server's existing user-scoped eBay API client
|
|
464
465
|
- [`src/validation/providers/ebay-sold.ts`](src/validation/providers/ebay-sold.ts) — temporary sold-data provider backed by an external API via `SOLD_ITEMS_API_URL` and `SOLD_ITEMS_API_KEY`
|
|
465
|
-
- [`src/validation/providers/terapeak.ts`](src/validation/providers/terapeak.ts) —
|
|
466
|
+
- [`src/validation/providers/terapeak.ts`](src/validation/providers/terapeak.ts) — authenticated eBay Research provider orchestration for current-market and previous-POB metrics, including candidate scoring, fallback diagnostics, and sold-velocity bucketing
|
|
467
|
+
- [`src/validation/providers/ebay-research.ts`](src/validation/providers/ebay-research.ts) — low-level authenticated eBay Research fetcher with session-cookie sourcing, response parsing, and auth-aware cache invalidation
|
|
466
468
|
- [`src/validation/providers/query-utils.ts`](src/validation/providers/query-utils.ts) — shared multi-tier query candidate and fallback helpers used by browse and sold providers
|
|
467
469
|
- [`src/validation/providers/social.ts`](src/validation/providers/social.ts) — phase-1 social provider for recent Twitter/X activity, YouTube view-rate proxy data, and Reddit recent-post counts with graceful degradation
|
|
468
470
|
- [`src/validation/providers/chart.ts`](src/validation/providers/chart.ts) — chart-signal stub reserved for later implementation
|
|
@@ -489,8 +491,26 @@ Operationally, validation works like this:
|
|
|
489
491
|
3. The route looks up the configured validation runner user ID for that environment.
|
|
490
492
|
4. The server loads that user's stored refresh-token-backed credentials from the existing hosted auth store.
|
|
491
493
|
5. The validation orchestrator calls all six provider domains and gathers browse/current-market, sold enrichment, Terapeak/research contract data, social support signals, chart stub output, and previous-comeback research output.
|
|
492
|
-
6. [`runValidation()`](src/validation/run-validation.ts
|
|
493
|
-
7.
|
|
494
|
+
6. Before provider execution, [`runValidation()`](src/validation/run-validation.ts) builds a normalized `effectiveContext` so downstream logic consumes a source-aware model (`item` or `event`) instead of relying on empty item placeholders.
|
|
495
|
+
7. [`runValidation()`](src/validation/run-validation.ts) deterministically merges the provider outputs into normalized field writes.
|
|
496
|
+
8. The response returns those writes, a conservative buy/track decision block, and provider debug metadata for downstream systems.
|
|
497
|
+
|
|
498
|
+
#### Effective validation context
|
|
499
|
+
|
|
500
|
+
Validation runs now normalize incoming request data into an internal effective context before provider query planning and recommendation logic execute.
|
|
501
|
+
|
|
502
|
+
- **Item-scope runs** normalize to an item-oriented context with the resolved artist, album/item phrase, location, and resolved search query.
|
|
503
|
+
- **Event-scope runs** normalize to an event-oriented context with `searchArtist`, `searchEvent`, `searchItem`, `searchLocation`, timing metadata, and a derived `effectiveSearchQuery` when no direct resolved query is present.
|
|
504
|
+
- Providers and recommendation logic consume that normalized context rather than reasoning about blank `item.recordId` or `item.name` fields.
|
|
505
|
+
- Debug output now exposes `effectiveSourceType`, `effectiveContextMode`, `effectiveSearchQuery`, `hasItem`, and `hasEvent` so operators can confirm whether an event run was normalized correctly.
|
|
506
|
+
|
|
507
|
+
The request schema also now accepts source-aware query-context fields for hosted validation runs:
|
|
508
|
+
|
|
509
|
+
- `resolvedSearchArtist`
|
|
510
|
+
- `resolvedSearchItem`
|
|
511
|
+
- `resolvedSearchEvent`
|
|
512
|
+
- `resolvedSearchLocation`
|
|
513
|
+
- `resolvedSearchQuery`
|
|
494
514
|
|
|
495
515
|
The validation contract is intentionally split between stable route orchestration and swappable providers. That is why the current sold-data source can be replaced later without changing downstream orchestration or the hosted route contract implemented in [`src/validation/run-validation.ts`](src/validation/run-validation.ts).
|
|
496
516
|
|
|
@@ -500,7 +520,7 @@ The current merge order is fixed in [`runValidation()`](src/validation/run-valid
|
|
|
500
520
|
|
|
501
521
|
- **Watchers / preorder count / shipping / competition** prefer Terapeak contract output when available, then fall back to the browse/current-market provider.
|
|
502
522
|
- **Market price** prefers Terapeak contract output, then the sold provider's median sold price, then the browse/current-market provider.
|
|
503
|
-
- **Sold day buckets** (`day1Sold` through `day5Sold`, plus `daysTracked`) prefer the sold provider
|
|
523
|
+
- **Sold day buckets** (`day1Sold` through `day5Sold`, plus `daysTracked`) prefer the sold provider, then authenticated eBay Research sold-row bucketing, then the browse/current-market provider.
|
|
504
524
|
- **Previous POB metrics** (`previousPobAvgPriceUsd`, `previousPobSellThroughPct`) are written from the Terapeak contract output when available.
|
|
505
525
|
- **Previous comeback first-week sales** (`previousComebackFirstWeekSales`) is written from the orchestration-side research provider when available.
|
|
506
526
|
- **Supportive social fields** are only written when a value is actually resolved, so the pipeline avoids blanking previously stored downstream data.
|
|
@@ -546,7 +566,7 @@ Runs the validation pipeline for the target environment.
|
|
|
546
566
|
|
|
547
567
|
The request/response contract is defined in [`src/validation/types.ts`](src/validation/types.ts), and the orchestration behavior is implemented in [`src/validation/run-validation.ts`](src/validation/run-validation.ts).
|
|
548
568
|
|
|
549
|
-
The `writes` payload is intentionally non-destructive for supportive and
|
|
569
|
+
The `writes` payload is intentionally non-destructive for supportive and optional fields: if a social, authenticated eBay Research, or previous-comeback research provider cannot resolve data, the orchestration omits those optional writes instead of overwriting existing downstream values with empty placeholders.
|
|
550
570
|
|
|
551
571
|
#### `GET /validation/health`
|
|
552
572
|
|
|
@@ -591,17 +611,19 @@ Current backend status:
|
|
|
591
611
|
|
|
592
612
|
- eBay live market snapshot support is implemented and wired into orchestration.
|
|
593
613
|
- Sold-data enrichment is implemented through a **temporary external provider** abstraction.
|
|
594
|
-
-
|
|
614
|
+
- Authenticated eBay Research is wired into orchestration for current-market and previous-POB retrieval, while previous-comeback research remains a separate placeholder contract.
|
|
595
615
|
- Social support signals are implemented in phase 1.
|
|
596
616
|
- Chart data remains a stub.
|
|
597
617
|
- Validation is currently an **admin-operated hosted backend workflow**, not an MCP tool surface.
|
|
618
|
+
- Event-scope validations are now handled as first-class normalized runs instead of as item-shaped requests with null item identity tolerated for compatibility.
|
|
598
619
|
|
|
599
620
|
Provider behavior:
|
|
600
621
|
|
|
601
|
-
- **Browse/eBay provider:** [`src/validation/providers/ebay.ts`](src/validation/providers/ebay.ts) uses the eBay Browse API plus shared query fallback logic from [`src/validation/providers/query-utils.ts`](src/validation/providers/query-utils.ts). It walks multiple query candidates, records the selected query and tier in debug output, and uses heuristic matching rather than a strict catalog identity join.
|
|
622
|
+
- **Browse/eBay provider:** [`src/validation/providers/ebay.ts`](src/validation/providers/ebay.ts) uses the eBay Browse API plus shared query fallback logic from [`src/validation/providers/query-utils.ts`](src/validation/providers/query-utils.ts). It walks multiple query candidates, records the selected query and tier in debug output, and uses heuristic matching rather than a strict catalog identity join. Event-driven runs now build those fallback queries from normalized event context instead of raw item title assumptions.
|
|
602
623
|
- **Browse debug semantics:** validation debug now keeps browse candidate generation, selected query/tier, browse-specific sample size, and per-candidate result counts separate from sold-provider result counts so operators can tell whether the browse layer contributed a field, fell back to a weaker query, or returned no usable match.
|
|
603
624
|
- **Sold provider:** [`src/validation/providers/ebay-sold.ts`](src/validation/providers/ebay-sold.ts) uses a temporary external sold-data source configured by `SOLD_ITEMS_API_URL` and `SOLD_ITEMS_API_KEY`. It uses the same query-fallback strategy as the browse provider and returns sold-price ranges, sample sold items, and recent sold-velocity buckets when available.
|
|
604
|
-
- **Terapeak / eBay research provider:** [`src/validation/providers/terapeak.ts`](src/validation/providers/terapeak.ts)
|
|
625
|
+
- **Terapeak / eBay research provider:** [`src/validation/providers/terapeak.ts`](src/validation/providers/terapeak.ts) now evaluates authenticated eBay Research candidates for both current-market and previous-POB contexts, scores them against title alignment and subtype coverage, preserves per-candidate diagnostics in debug output, and derives sold-day buckets from sold-row timestamps when available.
|
|
626
|
+
- **Authenticated research session source:** [`src/validation/providers/ebay-research.ts`](src/validation/providers/ebay-research.ts) can source eBay Research authentication from cookie JSON, persisted KV-backed session state, Playwright storage state, or a browser profile directory. Parsed ACTIVE and SOLD tab responses are cached, but automatically invalidated when the authenticated cookie fingerprint changes.
|
|
605
627
|
- **Social provider:** [`src/validation/providers/social.ts`](src/validation/providers/social.ts) supports phase-1 Twitter/X recent activity, YouTube average-daily-views proxy data exposed through the `youtubeViews24hMillions` field, and Reddit recent post counts. These signals degrade gracefully on provider/API failure and are used as supportive indicators rather than authoritative demand truth.
|
|
606
628
|
- **Chart provider:** [`src/validation/providers/chart.ts`](src/validation/providers/chart.ts) is still a stub and does not currently contribute chart-based metrics.
|
|
607
629
|
- **Previous comeback research provider:** [`src/validation/providers/research.ts`](src/validation/providers/research.ts) is currently a stable placeholder contract for orchestration-side historical research. It returns the future-facing `previousComebackFirstWeekSales` field shape, and it documents `PERPLEXITY_API_KEY` for a later external-research implementation, but it does not yet perform live historical lookup.
|
|
@@ -609,6 +631,8 @@ Provider behavior:
|
|
|
609
631
|
Recommendation behavior:
|
|
610
632
|
|
|
611
633
|
- [`src/validation/recommendation.ts`](src/validation/recommendation.ts) now accepts Terapeak and research inputs alongside browse, sold, social, and chart signals.
|
|
634
|
+
- Recommendation generation also consumes the normalized effective context so event runs can carry source-aware monitoring notes and avoid item-only assumptions when no usable item identity exists.
|
|
635
|
+
- Automatic tracking now pauses when the validation is still nominally in a watch state but the required source context or a usable derived query is missing.
|
|
612
636
|
- The decisioning remains intentionally conservative: Terapeak and research data can improve monitoring notes and confidence context, but the system still avoids aggressive automatic buy-state changes from partial or proxy signals alone.
|
|
613
637
|
|
|
614
638
|
Known limitations in the current implementation:
|
|
@@ -616,7 +640,7 @@ Known limitations in the current implementation:
|
|
|
616
640
|
- The sold-data provider depends on external configuration via `SOLD_ITEMS_API_URL` and `SOLD_ITEMS_API_KEY`.
|
|
617
641
|
- If those sold-data variables are missing, validation still runs but sold enrichment degrades to an unavailable/error state rather than providing full historical-sales signals.
|
|
618
642
|
- The sold-data provider is temporary and intended to be replaced by an internal implementation later.
|
|
619
|
-
-
|
|
643
|
+
- Authenticated eBay Research requires a valid session source such as `EBAY_RESEARCH_COOKIES_JSON`, a persisted KV session, Playwright storage state, or a browser profile directory; without one, the provider degrades to diagnostic-only output.
|
|
620
644
|
- The previous-comeback research provider contract is present, but no live historical inference or Perplexity-backed lookup is implemented yet even when `PERPLEXITY_API_KEY` is configured.
|
|
621
645
|
- The browse provider still relies on heuristic query selection and fallback matching.
|
|
622
646
|
- The YouTube-backed `youtubeViews24hMillions` field is currently an **average daily views proxy**, not a true trailing 24-hour delta.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
function sanitizeText(value) {
|
|
2
|
+
if (typeof value !== 'string') {
|
|
3
|
+
return null;
|
|
4
|
+
}
|
|
5
|
+
const trimmed = value.trim();
|
|
6
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
7
|
+
}
|
|
8
|
+
function buildCompactText(...parts) {
|
|
9
|
+
const compact = parts
|
|
10
|
+
.map((part) => sanitizeText(part))
|
|
11
|
+
.filter((part) => part !== null)
|
|
12
|
+
.join(' ')
|
|
13
|
+
.replace(/\s+/g, ' ')
|
|
14
|
+
.trim();
|
|
15
|
+
return compact.length > 0 ? compact : null;
|
|
16
|
+
}
|
|
17
|
+
function getQueryContext(request) {
|
|
18
|
+
return request.validation.queryContext;
|
|
19
|
+
}
|
|
20
|
+
function getFallbackArtist(request) {
|
|
21
|
+
return sanitizeText(request.item.canonicalArtists[0]);
|
|
22
|
+
}
|
|
23
|
+
function getFallbackAlbum(request) {
|
|
24
|
+
return sanitizeText(request.item.relatedAlbums[0]);
|
|
25
|
+
}
|
|
26
|
+
function getFallbackItem(request) {
|
|
27
|
+
return sanitizeText(request.item.name);
|
|
28
|
+
}
|
|
29
|
+
export function buildValidationEffectiveContext(request) {
|
|
30
|
+
const queryContext = getQueryContext(request);
|
|
31
|
+
const sourceType = request.sourceContext?.sourceType ?? 'item';
|
|
32
|
+
const searchArtist = sanitizeText(queryContext?.resolvedSearchArtist) ?? getFallbackArtist(request);
|
|
33
|
+
const searchAlbum = sanitizeText(getFallbackAlbum(request));
|
|
34
|
+
const searchItem = sanitizeText(queryContext?.resolvedSearchItem) ??
|
|
35
|
+
(sourceType === 'item' ? getFallbackItem(request) : null);
|
|
36
|
+
const searchEvent = sanitizeText(queryContext?.resolvedSearchEvent);
|
|
37
|
+
const searchLocation = sanitizeText(queryContext?.resolvedSearchLocation);
|
|
38
|
+
const resolvedSearchQuery = sanitizeText(queryContext?.resolvedSearchQuery);
|
|
39
|
+
const itemRecordId = sanitizeText(request.item.recordId);
|
|
40
|
+
const eventRecordId = sanitizeText(request.sourceContext?.eventRecordId);
|
|
41
|
+
const itemName = getFallbackItem(request);
|
|
42
|
+
const hasItem = sourceType === 'item'
|
|
43
|
+
? (request.sourceContext?.hasItem ?? itemRecordId !== null) || itemName !== null
|
|
44
|
+
: request.sourceContext?.hasItem === true || itemRecordId !== null;
|
|
45
|
+
const hasEvent = sourceType === 'event'
|
|
46
|
+
? true
|
|
47
|
+
: request.sourceContext?.hasEvent === true || searchEvent !== null || eventRecordId !== null;
|
|
48
|
+
const effectiveSearchQuery = resolvedSearchQuery ??
|
|
49
|
+
(sourceType === 'event'
|
|
50
|
+
? buildCompactText(searchArtist, searchEvent, searchItem, searchLocation)
|
|
51
|
+
: buildCompactText(searchArtist, searchAlbum ?? searchItem, searchLocation));
|
|
52
|
+
return {
|
|
53
|
+
sourceType,
|
|
54
|
+
mode: sourceType,
|
|
55
|
+
validationScope: sanitizeText(queryContext?.validationScope),
|
|
56
|
+
queryScope: sanitizeText(queryContext?.queryScope),
|
|
57
|
+
directQueryActive: queryContext?.directQueryActive === true,
|
|
58
|
+
resolvedSearchQuery,
|
|
59
|
+
effectiveSearchQuery,
|
|
60
|
+
searchArtist,
|
|
61
|
+
searchAlbum,
|
|
62
|
+
searchItem,
|
|
63
|
+
searchEvent,
|
|
64
|
+
searchLocation,
|
|
65
|
+
hasItem,
|
|
66
|
+
hasEvent,
|
|
67
|
+
itemRecordId,
|
|
68
|
+
eventRecordId,
|
|
69
|
+
itemName,
|
|
70
|
+
eventDate: sanitizeText(request.item.releaseDate),
|
|
71
|
+
dDay: request.validation.dDay,
|
|
72
|
+
requestTimestamp: request.timestamp,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export function getValidationEffectiveContext(request) {
|
|
76
|
+
return request.effectiveContext ?? buildValidationEffectiveContext(request);
|
|
77
|
+
}
|