@antseed/cli 0.1.168 → 0.1.169
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/buyer-identities/loader.d.ts +28 -0
- package/dist/buyer-identities/loader.d.ts.map +1 -0
- package/dist/buyer-identities/loader.js +58 -0
- package/dist/buyer-identities/loader.js.map +1 -0
- package/dist/buyer-identities/store.d.ts +41 -0
- package/dist/buyer-identities/store.d.ts.map +1 -0
- package/dist/buyer-identities/store.js +171 -0
- package/dist/buyer-identities/store.js.map +1 -0
- package/dist/buyer-identities/store.test.d.ts +2 -0
- package/dist/buyer-identities/store.test.d.ts.map +1 -0
- package/dist/buyer-identities/store.test.js +122 -0
- package/dist/buyer-identities/store.test.js.map +1 -0
- package/dist/cli/commands/buyer/identity.d.ts +3 -0
- package/dist/cli/commands/buyer/identity.d.ts.map +1 -0
- package/dist/cli/commands/buyer/identity.js +115 -0
- package/dist/cli/commands/buyer/identity.js.map +1 -0
- package/dist/cli/commands/buyer/index.d.ts.map +1 -1
- package/dist/cli/commands/buyer/index.js +2 -0
- package/dist/cli/commands/buyer/index.js.map +1 -1
- package/dist/cli/commands/buyer/start.d.ts.map +1 -1
- package/dist/cli/commands/buyer/start.js +30 -2
- package/dist/cli/commands/buyer/start.js.map +1 -1
- package/dist/cli/commands/gateway/index.d.ts +3 -0
- package/dist/cli/commands/gateway/index.d.ts.map +1 -0
- package/dist/cli/commands/gateway/index.js +43 -0
- package/dist/cli/commands/gateway/index.js.map +1 -0
- package/dist/cli/commands/gateway/key.d.ts +3 -0
- package/dist/cli/commands/gateway/key.d.ts.map +1 -0
- package/dist/cli/commands/gateway/key.js +240 -0
- package/dist/cli/commands/gateway/key.js.map +1 -0
- package/dist/cli/commands/gateway/shared.d.ts +29 -0
- package/dist/cli/commands/gateway/shared.d.ts.map +1 -0
- package/dist/cli/commands/gateway/shared.js +90 -0
- package/dist/cli/commands/gateway/shared.js.map +1 -0
- package/dist/cli/commands/tunnel/start.d.ts.map +1 -1
- package/dist/cli/commands/tunnel/start.js +25 -14
- package/dist/cli/commands/tunnel/start.js.map +1 -1
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/gateway/accounting.d.ts +45 -0
- package/dist/gateway/accounting.d.ts.map +1 -0
- package/dist/gateway/accounting.js +94 -0
- package/dist/gateway/accounting.js.map +1 -0
- package/dist/gateway/cdp-auth.d.ts +12 -0
- package/dist/gateway/cdp-auth.d.ts.map +1 -0
- package/dist/gateway/cdp-auth.js +53 -0
- package/dist/gateway/cdp-auth.js.map +1 -0
- package/dist/gateway/cdp-auth.test.d.ts +2 -0
- package/dist/gateway/cdp-auth.test.d.ts.map +1 -0
- package/dist/gateway/cdp-auth.test.js +96 -0
- package/dist/gateway/cdp-auth.test.js.map +1 -0
- package/dist/gateway/gateway.test.d.ts.map +1 -0
- package/dist/gateway/gateway.test.js +709 -0
- package/dist/gateway/gateway.test.js.map +1 -0
- package/dist/gateway/keys.d.ts +13 -0
- package/dist/gateway/keys.d.ts.map +1 -0
- package/dist/gateway/keys.js +24 -0
- package/dist/gateway/keys.js.map +1 -0
- package/dist/gateway/limits.d.ts +25 -0
- package/dist/gateway/limits.d.ts.map +1 -0
- package/dist/gateway/limits.js +45 -0
- package/dist/gateway/limits.js.map +1 -0
- package/dist/gateway/money.d.ts +9 -0
- package/dist/gateway/money.d.ts.map +1 -0
- package/dist/gateway/money.js +37 -0
- package/dist/gateway/money.js.map +1 -0
- package/dist/gateway/runtime.d.ts +38 -0
- package/dist/gateway/runtime.d.ts.map +1 -0
- package/dist/gateway/runtime.js +144 -0
- package/dist/gateway/runtime.js.map +1 -0
- package/dist/gateway/server.d.ts +49 -0
- package/dist/gateway/server.d.ts.map +1 -0
- package/dist/gateway/server.js +460 -0
- package/dist/gateway/server.js.map +1 -0
- package/dist/gateway/spend-feed.d.ts +32 -0
- package/dist/gateway/spend-feed.d.ts.map +1 -0
- package/dist/gateway/spend-feed.js +86 -0
- package/dist/gateway/spend-feed.js.map +1 -0
- package/dist/gateway/store.d.ts +114 -0
- package/dist/gateway/store.d.ts.map +1 -0
- package/dist/gateway/store.js +253 -0
- package/dist/gateway/store.js.map +1 -0
- package/dist/gateway/x402.d.ts +95 -0
- package/dist/gateway/x402.d.ts.map +1 -0
- package/dist/gateway/x402.js +120 -0
- package/dist/gateway/x402.js.map +1 -0
- package/dist/proxy/buyer-proxy.d.ts +13 -0
- package/dist/proxy/buyer-proxy.d.ts.map +1 -1
- package/dist/proxy/buyer-proxy.js +99 -11
- package/dist/proxy/buyer-proxy.js.map +1 -1
- package/dist/proxy/request-utils.d.ts +3 -0
- package/dist/proxy/request-utils.d.ts.map +1 -1
- package/dist/proxy/request-utils.js +3 -0
- package/dist/proxy/request-utils.js.map +1 -1
- package/dist/proxy/spend-attribution.d.ts +63 -0
- package/dist/proxy/spend-attribution.d.ts.map +1 -0
- package/dist/proxy/spend-attribution.js +97 -0
- package/dist/proxy/spend-attribution.js.map +1 -0
- package/package.json +8 -6
- package/dist/tunnel/gateway.d.ts +0 -16
- package/dist/tunnel/gateway.d.ts.map +0 -1
- package/dist/tunnel/gateway.js +0 -146
- package/dist/tunnel/gateway.js.map +0 -1
- package/dist/tunnel/gateway.test.d.ts.map +0 -1
- package/dist/tunnel/gateway.test.js +0 -89
- package/dist/tunnel/gateway.test.js.map +0 -1
- /package/dist/{tunnel → gateway}/gateway.test.d.ts +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buyer-proxy.d.ts","sourceRoot":"","sources":["../../src/proxy/buyer-proxy.ts"],"names":[],"mappings":"AAKA,OAAO,
|
|
1
|
+
{"version":3,"file":"buyer-proxy.d.ts","sourceRoot":"","sources":["../../src/proxy/buyer-proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,15 +3,17 @@ import { randomUUID } from 'node:crypto';
|
|
|
3
3
|
import { watchFile, unwatchFile } from 'node:fs';
|
|
4
4
|
import { readFile, writeFile, rename, mkdir, readdir, stat, unlink } from 'node:fs/promises';
|
|
5
5
|
import { join } from 'node:path';
|
|
6
|
-
import { ANTSEED_BUYER_FAULT_ERROR_CODE, ANTSEED_FAULT_ATTRIBUTION_HEADER, ANTSEED_ATTEST_PATH, adaptPeerFaultErrorResponse, computeTrustScore, decodeSweepRequest, faultAttributionOf, faultCodeOf, isModelRouteEligible, modelRouteTotalPrice, normalizedModelReputationScore, peerSupportsCooperativeClose, rankModelRoutes, sanitizePeerDisplayName, } from '@antseed/node';
|
|
6
|
+
import { ANTSEED_BUYER_FAULT_ERROR_CODE, ANTSEED_FAULT_ATTRIBUTION_HEADER, ANTSEED_ATTEST_PATH, adaptPeerFaultErrorResponse, computeTrustScore, decodeSweepRequest, faultAttributionOf, faultCodeOf, isModelRouteEligible, modelRouteTotalPrice, normalizedModelReputationScore, peerSupportsCooperativeClose, DEFAULT_BUYER_IDENTITY, rankModelRoutes, sanitizePeerDisplayName, } from '@antseed/node';
|
|
7
7
|
import { canonicalModelKey } from '@antseed/node/model-identity';
|
|
8
8
|
import { createStreamingAdapter, detectRequestServiceApiProtocol, transformRequest, transformResponse, } from './service-api-adapter.js';
|
|
9
|
-
import { DEBUG, log, extractRequestedService, summarizeRequestShape, summarizeErrorResponse, requestWantsStreaming, parsePeerPinnedService, rewritePeerPinnedServiceInBody, substituteRoutedModelAlias, overrideRoutedModelInBody, ROUTED_MODEL_ALIAS, SYSTEM_PROXY_SOURCE_HEADER, SYSTEM_ROUTED_MODEL_HEADER, normalizePeerId, } from './request-utils.js';
|
|
9
|
+
import { DEBUG, log, extractRequestedService, summarizeRequestShape, summarizeErrorResponse, requestWantsStreaming, parsePeerPinnedService, rewritePeerPinnedServiceInBody, substituteRoutedModelAlias, overrideRoutedModelInBody, ROUTED_MODEL_ALIAS, SYSTEM_PROXY_SOURCE_HEADER, SYSTEM_ROUTED_MODEL_HEADER, BUYER_IDENTITY_HEADER, normalizePeerId, } from './request-utils.js';
|
|
10
|
+
import { BuyerIdentityLoader } from '../buyer-identities/loader.js';
|
|
10
11
|
import { buildNetworkModels, effectiveModelReputationScore, parseModelTypeFilter, } from './network-models.js';
|
|
11
12
|
import { findMissingRequiredParameters, findUnannouncedRequestParameters, findAdvertisedServiceOffer, findAdvertisedServiceProtocols, getExplicitProviderOverride, getExplicitPeerIdOverride, parseRequiredParametersHeader, REQUIRED_PARAMETERS_HEADER, resolvePeerRoutePlan, selectCandidatePeersForRouting, } from './routing.js';
|
|
12
13
|
import { computeResponseTelemetry, attachAntseedTelemetryHeaders, attachStreamingAntseedHeaders, } from './telemetry.js';
|
|
13
14
|
import { DEFAULT_BUYER_PEER_REFRESH_INTERVAL_MS } from '../config/defaults.js';
|
|
14
15
|
import { extractConversationIdentity, extractFirstUserSnippet, isCompletionRequestPath, isTitleGenerationRequest, parseRequestBodyObject, } from './conversation-identity.js';
|
|
16
|
+
import { SPEND_ATTRIBUTION_HEADER, SpendAttributionFeed, parseSpendAttributionTag } from './spend-attribution.js';
|
|
15
17
|
import { ConversationStore } from './conversation-store.js';
|
|
16
18
|
import { recordPeerFailureEntry, clearPeerHealthEntry, isCoolingDown, parsePersistedPeerHealth, prunePeerHealth, serializePeerHealth, reasonEscalates, } from './peer-health.js';
|
|
17
19
|
import { PeerAttributionTracker, HEARTBEAT_MS } from './peer-attribution.js';
|
|
@@ -595,6 +597,10 @@ export async function mergeJsonStateFile(stateDir, stateFile, patch) {
|
|
|
595
597
|
throw err;
|
|
596
598
|
}
|
|
597
599
|
}
|
|
600
|
+
function sendUnknownBuyerIdentity(res) {
|
|
601
|
+
res.writeHead(404, { 'content-type': 'application/json' });
|
|
602
|
+
res.end(JSON.stringify({ ok: false, error: 'Unknown buyer identity' }));
|
|
603
|
+
}
|
|
598
604
|
export class BuyerProxy {
|
|
599
605
|
_server;
|
|
600
606
|
_node;
|
|
@@ -623,6 +629,7 @@ export class BuyerProxy {
|
|
|
623
629
|
*/
|
|
624
630
|
_lastModelActivityAt = 0;
|
|
625
631
|
_verifier;
|
|
632
|
+
_buyerIdentities;
|
|
626
633
|
_teeVerification;
|
|
627
634
|
_teeControl;
|
|
628
635
|
_stateWatchDebounce = null;
|
|
@@ -669,9 +676,12 @@ export class BuyerProxy {
|
|
|
669
676
|
* deltas (buyer- and seller-initiated auth both advance the cumulative).
|
|
670
677
|
*/
|
|
671
678
|
_requestConversations = new Map();
|
|
679
|
+
/** Signed spend for requests a local gateway tagged, polled over the control plane. */
|
|
680
|
+
_spendAttribution = new SpendAttributionFeed();
|
|
672
681
|
constructor(config) {
|
|
673
682
|
this._node = config.node;
|
|
674
683
|
this._verifier = config.verifier;
|
|
684
|
+
this._buyerIdentities = config.buyerIdentities ?? new BuyerIdentityLoader(config.node, config.dataDir);
|
|
675
685
|
this._teeVerification = new TeeVerification(config.verifier);
|
|
676
686
|
this._teeControl = new TeeControl(this._teeVerification.sessionId);
|
|
677
687
|
this._port = config.port;
|
|
@@ -714,6 +724,7 @@ export class BuyerProxy {
|
|
|
714
724
|
if (typeof spendEventNode.on === 'function') {
|
|
715
725
|
spendEventNode.on('payment:spend', (event) => {
|
|
716
726
|
this._attributeSpend(event);
|
|
727
|
+
this._spendAttribution.record(event);
|
|
717
728
|
});
|
|
718
729
|
}
|
|
719
730
|
const eventNode = this._node;
|
|
@@ -741,6 +752,25 @@ export class BuyerProxy {
|
|
|
741
752
|
}, !entry.counted);
|
|
742
753
|
entry.counted = true;
|
|
743
754
|
}
|
|
755
|
+
/**
|
|
756
|
+
* Identity named by a request: null for the default, the name when it is
|
|
757
|
+
* (or can be) loaded, undefined when no stored identity has that name.
|
|
758
|
+
*/
|
|
759
|
+
async _resolveBuyerIdentity(header) {
|
|
760
|
+
const name = header?.trim().toLowerCase() ?? '';
|
|
761
|
+
if (!name || name === DEFAULT_BUYER_IDENTITY)
|
|
762
|
+
return null;
|
|
763
|
+
const loaded = await this._buyerIdentities.ensure(name).catch((err) => {
|
|
764
|
+
log(`Buyer identity "${name}" failed to load: ${err instanceof Error ? err.message : String(err)}`);
|
|
765
|
+
return false;
|
|
766
|
+
});
|
|
767
|
+
return loaded ? name : undefined;
|
|
768
|
+
}
|
|
769
|
+
/** `?identity=` on control-plane reads; undefined when it names no stored identity. */
|
|
770
|
+
async _controlPlaneIdentity(path) {
|
|
771
|
+
const param = new URL(path, 'http://localhost').searchParams.get('identity');
|
|
772
|
+
return this._resolveBuyerIdentity(param ?? undefined);
|
|
773
|
+
}
|
|
744
774
|
/**
|
|
745
775
|
* Remember which chat a request belongs to for the life of the request plus
|
|
746
776
|
* a grace window — the seller-initiated auth path can land just after the
|
|
@@ -868,7 +898,10 @@ export class BuyerProxy {
|
|
|
868
898
|
await this._writeStateFile('stopped');
|
|
869
899
|
await this._conversations.flush();
|
|
870
900
|
return new Promise((resolve) => {
|
|
871
|
-
this._server.close(() =>
|
|
901
|
+
this._server.close(() => {
|
|
902
|
+
this._spendAttribution.close();
|
|
903
|
+
resolve();
|
|
904
|
+
});
|
|
872
905
|
});
|
|
873
906
|
}
|
|
874
907
|
_watchStateFile() {
|
|
@@ -1682,11 +1715,20 @@ export class BuyerProxy {
|
|
|
1682
1715
|
}
|
|
1683
1716
|
return;
|
|
1684
1717
|
}
|
|
1718
|
+
if (path.startsWith('/_antseed/buyer-identities') && method === 'GET') {
|
|
1719
|
+
await this._buyerIdentities.loadAll();
|
|
1720
|
+
res.writeHead(200, { 'content-type': 'application/json' });
|
|
1721
|
+
res.end(JSON.stringify({ ok: true, identities: this._node.buyerIdentities() }));
|
|
1722
|
+
return;
|
|
1723
|
+
}
|
|
1685
1724
|
if (path.startsWith('/_antseed/channels') && method === 'GET') {
|
|
1686
1725
|
const all = /[?&]all=1/.test(path);
|
|
1726
|
+
const identity = await this._controlPlaneIdentity(path);
|
|
1727
|
+
if (identity === undefined)
|
|
1728
|
+
return sendUnknownBuyerIdentity(res);
|
|
1687
1729
|
const channels = all
|
|
1688
|
-
? this._node.getAllBuyerChannels()
|
|
1689
|
-
: this._node.getActiveBuyerChannels();
|
|
1730
|
+
? this._node.getAllBuyerChannels(identity ?? undefined)
|
|
1731
|
+
: this._node.getActiveBuyerChannels(identity ?? undefined);
|
|
1690
1732
|
const peers = await this._getPeers();
|
|
1691
1733
|
const peersById = new Map(peers.map((peer) => [peer.peerId, peer]));
|
|
1692
1734
|
const channelsWithCapabilities = channels.map((channel) => {
|
|
@@ -1701,16 +1743,30 @@ export class BuyerProxy {
|
|
|
1701
1743
|
res.end(JSON.stringify({ ok: true, channels: channelsWithCapabilities }));
|
|
1702
1744
|
return;
|
|
1703
1745
|
}
|
|
1746
|
+
// Unauthenticated like every /_antseed route: it relies on the buyer
|
|
1747
|
+
// listening on 127.0.0.1 only, since it exposes per-seller spend and tags.
|
|
1748
|
+
if (path.startsWith('/_antseed/attributed-spend') && method === 'GET') {
|
|
1749
|
+
const after = Number(new URL(path, 'http://localhost').searchParams.get('after') ?? '0');
|
|
1750
|
+
res.writeHead(200, { 'content-type': 'application/json' });
|
|
1751
|
+
res.end(JSON.stringify({ ok: true, ...this._spendAttribution.page(Number.isFinite(after) ? after : 0) }));
|
|
1752
|
+
return;
|
|
1753
|
+
}
|
|
1704
1754
|
if (path.startsWith('/_antseed/buyer-usage') && method === 'GET') {
|
|
1705
|
-
const
|
|
1755
|
+
const identity = await this._controlPlaneIdentity(path);
|
|
1756
|
+
if (identity === undefined)
|
|
1757
|
+
return sendUnknownBuyerIdentity(res);
|
|
1758
|
+
const totals = this._node.getBuyerUsageTotals(identity ?? undefined);
|
|
1706
1759
|
res.writeHead(200, { 'content-type': 'application/json' });
|
|
1707
1760
|
res.end(JSON.stringify({ ok: true, totals, lastActivityAt: this._lastModelActivityAt || null }));
|
|
1708
1761
|
return;
|
|
1709
1762
|
}
|
|
1710
|
-
const meteringMatch = path.match(/^\/_antseed\/metering\/(
|
|
1763
|
+
const meteringMatch = path.match(/^\/_antseed\/metering\/([^?]+)/);
|
|
1711
1764
|
if (meteringMatch && method === 'GET') {
|
|
1712
1765
|
const sellerPeerId = decodeURIComponent(meteringMatch[1]);
|
|
1713
|
-
const
|
|
1766
|
+
const identity = await this._controlPlaneIdentity(path);
|
|
1767
|
+
if (identity === undefined)
|
|
1768
|
+
return sendUnknownBuyerIdentity(res);
|
|
1769
|
+
const stats = this._node.getMeteringStatsByPeer(sellerPeerId, identity ?? undefined);
|
|
1714
1770
|
res.writeHead(200, { 'content-type': 'application/json' });
|
|
1715
1771
|
res.end(JSON.stringify(stats));
|
|
1716
1772
|
return;
|
|
@@ -1764,11 +1820,14 @@ export class BuyerProxy {
|
|
|
1764
1820
|
}
|
|
1765
1821
|
let peerId;
|
|
1766
1822
|
let includeAuth = true;
|
|
1823
|
+
let identityParam;
|
|
1767
1824
|
try {
|
|
1768
1825
|
const body = JSON.parse(Buffer.concat(chunks).toString());
|
|
1769
1826
|
peerId = String(body.peerId ?? '');
|
|
1770
1827
|
if (body.includeAuth === false)
|
|
1771
1828
|
includeAuth = false;
|
|
1829
|
+
if (typeof body.identity === 'string')
|
|
1830
|
+
identityParam = body.identity;
|
|
1772
1831
|
}
|
|
1773
1832
|
catch {
|
|
1774
1833
|
res.writeHead(400, { 'content-type': 'application/json' });
|
|
@@ -1781,7 +1840,10 @@ export class BuyerProxy {
|
|
|
1781
1840
|
return;
|
|
1782
1841
|
}
|
|
1783
1842
|
try {
|
|
1784
|
-
const
|
|
1843
|
+
const identity = await this._resolveBuyerIdentity(identityParam);
|
|
1844
|
+
if (identity === undefined)
|
|
1845
|
+
throw new Error('Unknown buyer identity');
|
|
1846
|
+
const result = await this._node.requestChannelClose(peerId, { includeAuth, ...(identity ? { buyerIdentity: identity } : {}) });
|
|
1785
1847
|
log(`Cooperative close of ${result.channelId.slice(0, 18)}... with ${peerId.slice(0, 12)}...: ` +
|
|
1786
1848
|
`${result.status}${result.code ? ` (${result.code})` : ''}`);
|
|
1787
1849
|
res.writeHead(200, { 'content-type': 'application/json' });
|
|
@@ -1986,6 +2048,29 @@ export class BuyerProxy {
|
|
|
1986
2048
|
// it never reaches a seller.
|
|
1987
2049
|
const systemRoutedModel = headers[SYSTEM_ROUTED_MODEL_HEADER] === '1';
|
|
1988
2050
|
delete headers[SYSTEM_ROUTED_MODEL_HEADER];
|
|
2051
|
+
// Internal marker from the API-key gateway: report this request's signed
|
|
2052
|
+
// spend under the gateway's tag. Stripped so it never reaches a seller.
|
|
2053
|
+
const spendAttributionTag = parseSpendAttributionTag(headers[SPEND_ATTRIBUTION_HEADER]);
|
|
2054
|
+
delete headers[SPEND_ATTRIBUTION_HEADER];
|
|
2055
|
+
// The paying identity rides on the internal headers through routing, like
|
|
2056
|
+
// a peer pin, and is stripped when the request is built for the seller.
|
|
2057
|
+
const buyerIdentity = await this._resolveBuyerIdentity(headers[BUYER_IDENTITY_HEADER]);
|
|
2058
|
+
if (buyerIdentity === undefined) {
|
|
2059
|
+
res.writeHead(400, { 'content-type': 'application/json' });
|
|
2060
|
+
res.end(JSON.stringify({
|
|
2061
|
+
error: {
|
|
2062
|
+
type: 'invalid_request_error',
|
|
2063
|
+
code: 'unknown_buyer_identity',
|
|
2064
|
+
message: `${BUYER_IDENTITY_HEADER} names no stored buyer identity. Create one with \`antseed buyer identity create <name>\`.`,
|
|
2065
|
+
param: BUYER_IDENTITY_HEADER,
|
|
2066
|
+
},
|
|
2067
|
+
}));
|
|
2068
|
+
return;
|
|
2069
|
+
}
|
|
2070
|
+
if (buyerIdentity)
|
|
2071
|
+
headers[BUYER_IDENTITY_HEADER] = buyerIdentity;
|
|
2072
|
+
else
|
|
2073
|
+
delete headers[BUYER_IDENTITY_HEADER];
|
|
1989
2074
|
let serializedReq = {
|
|
1990
2075
|
requestId: randomUUID(),
|
|
1991
2076
|
method,
|
|
@@ -1993,6 +2078,8 @@ export class BuyerProxy {
|
|
|
1993
2078
|
headers,
|
|
1994
2079
|
body: new Uint8Array(body),
|
|
1995
2080
|
};
|
|
2081
|
+
if (spendAttributionTag)
|
|
2082
|
+
this._spendAttribution.track(serializedReq.requestId, spendAttributionTag);
|
|
1996
2083
|
const requiredParameters = parseRequiredParametersHeader(serializedReq.headers[REQUIRED_PARAMETERS_HEADER]);
|
|
1997
2084
|
if (requiredParameters === null) {
|
|
1998
2085
|
res.writeHead(400, { 'content-type': 'application/json' });
|
|
@@ -2593,7 +2680,7 @@ export class BuyerProxy {
|
|
|
2593
2680
|
+ `did not announce for this service: ${unannounced.join(', ')} — the upstream may ignore or reject them`);
|
|
2594
2681
|
}
|
|
2595
2682
|
}
|
|
2596
|
-
const { 'x-antseed-pin-peer': _pinPeer, 'x-antseed-prefer-peer': _preferPeer, [REQUIRED_PARAMETERS_HEADER]: _requiredParameters, 'x-vpr-session-id': _vprSession,
|
|
2683
|
+
const { 'x-antseed-pin-peer': _pinPeer, 'x-antseed-prefer-peer': _preferPeer, [BUYER_IDENTITY_HEADER]: buyerIdentity, [REQUIRED_PARAMETERS_HEADER]: _requiredParameters, 'x-vpr-session-id': _vprSession,
|
|
2597
2684
|
// Legacy desktop builds (pre AntStation → VPR rename) still send this.
|
|
2598
2685
|
'x-antstation-session-id': _antstationSession, ...headersForPeer } = serializedReq.headers;
|
|
2599
2686
|
let requestForPeer = {
|
|
@@ -2701,7 +2788,7 @@ export class BuyerProxy {
|
|
|
2701
2788
|
}
|
|
2702
2789
|
}
|
|
2703
2790
|
},
|
|
2704
|
-
}, { signal: requestSignal, pinned });
|
|
2791
|
+
}, { signal: requestSignal, pinned, ...(buyerIdentity ? { buyerIdentity } : {}) });
|
|
2705
2792
|
let responseForClient = adaptBuyerFaultErrorResponse(response, requestProtocol);
|
|
2706
2793
|
responseForClient = adaptPeerResponse(responseForClient);
|
|
2707
2794
|
if (!streamed
|
|
@@ -2768,6 +2855,7 @@ export class BuyerProxy {
|
|
|
2768
2855
|
const upstreamResponse = await this._node.sendRequest(selectedPeer, requestForPeer, {
|
|
2769
2856
|
signal: requestSignal,
|
|
2770
2857
|
pinned,
|
|
2858
|
+
...(buyerIdentity ? { buyerIdentity } : {}),
|
|
2771
2859
|
});
|
|
2772
2860
|
if (upstreamResponse.statusCode >= 400 && !adaptResponse) {
|
|
2773
2861
|
log(`Upstream raw error detail: ${summarizeErrorResponse(upstreamResponse)}`);
|