@evomap/evolver-adapter-public 2.0.0-beta.5 → 2.0.0-beta.7
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/hubCapability.d.ts +7 -4
- package/dist/hubCapability.js +49 -9
- package/package.json +2 -2
package/dist/hubCapability.d.ts
CHANGED
|
@@ -81,6 +81,12 @@ export interface PublicHelloResult {
|
|
|
81
81
|
httpStatus?: number;
|
|
82
82
|
secretDiverged?: boolean;
|
|
83
83
|
}
|
|
84
|
+
export interface PublicHelloOptions {
|
|
85
|
+
rotate: boolean;
|
|
86
|
+
evolverVersion?: string;
|
|
87
|
+
/** Keep trust probes from adopting or clearing local credential state. */
|
|
88
|
+
preserveCredentials?: boolean;
|
|
89
|
+
}
|
|
84
90
|
export interface PublicHeartbeatOptions {
|
|
85
91
|
evolverVersion?: string;
|
|
86
92
|
lastUpdate?: PublicLastUpdatePayload;
|
|
@@ -129,10 +135,7 @@ export declare class PublicHubCapability implements hub.HubCapability {
|
|
|
129
135
|
readonly auth: hub.AuthProvider;
|
|
130
136
|
readonly recipes: hub.RecipeCapability;
|
|
131
137
|
constructor(opts: PublicHubOptions);
|
|
132
|
-
hello(opts:
|
|
133
|
-
rotate: boolean;
|
|
134
|
-
evolverVersion?: string;
|
|
135
|
-
}): Promise<PublicHelloResult>;
|
|
138
|
+
hello(opts: PublicHelloOptions): Promise<PublicHelloResult>;
|
|
136
139
|
heartbeat(opts?: PublicHeartbeatOptions): Promise<PublicHeartbeatResult>;
|
|
137
140
|
private heartbeatMeta;
|
|
138
141
|
publish(bundle: hub.AssetRecord[]): Promise<hub.PublishReceipt>;
|
package/dist/hubCapability.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { hub as hubNs } from '@evomap/evolver-core';
|
|
1
|
+
import { bootstrap, hub as hubNs } from '@evomap/evolver-core';
|
|
2
2
|
import { AuthError, HubFetch, HubClientError, isHubUnreachableError } from './hubFetch.js';
|
|
3
3
|
import { isNodeSecret, parseNodeSecretVersion } from './auth/legacyShim.js';
|
|
4
4
|
import { inboundToAgentEvent, agentEventToOutbound, publishRespToReceipt, searchQueryToFetchWire } from './wireMap.js';
|
|
@@ -103,6 +103,11 @@ export class PublicHubCapability {
|
|
|
103
103
|
timestamp: new Date().toISOString(),
|
|
104
104
|
...(sender ? { node_id: sender } : {}),
|
|
105
105
|
...(opts.evolverVersion ? { evolver_version: opts.evolverVersion } : {}),
|
|
106
|
+
// v1 parity (a2aProtocol.js buildHello): every hello carries the env fingerprint — it is how the
|
|
107
|
+
// hub builds node/IP trust for its anti-abuse layer. v2 had moved it to heartbeat-only meta, which
|
|
108
|
+
// one-shot CLI paths never send; the hub then answers heartbeats with resend_hello
|
|
109
|
+
// `missing_env_fingerprint` and 403-antibodies /a2a/fetch (#555).
|
|
110
|
+
env_fingerprint: bootstrap.captureEnvFingerprint({ env: this.opts.antiAbuse?.env ?? process.env }),
|
|
106
111
|
}));
|
|
107
112
|
const payload = asRecord(body['payload']) ?? body;
|
|
108
113
|
const retryAfterMs = numberField(payload, 'retry_after_ms') ?? numberField(payload, 'retryAfterMs');
|
|
@@ -115,10 +120,12 @@ export class PublicHubCapability {
|
|
|
115
120
|
// cleanly; retrying with the diverged secret never can. Signals the caller NOT to arm reauth
|
|
116
121
|
// backoff. Only legacy node_secret auth exposes this hook — enterprise_token is a no-op.
|
|
117
122
|
if (isSecretDivergenceRejection(body, payload)) {
|
|
118
|
-
|
|
123
|
+
if (!opts.preserveCredentials) {
|
|
124
|
+
this.auth.notifyNodeSecretDiverged?.();
|
|
125
|
+
}
|
|
119
126
|
return {
|
|
120
127
|
ok: false,
|
|
121
|
-
error: 'secret_diverged_cleared',
|
|
128
|
+
error: opts.preserveCredentials ? 'secret_diverged' : 'secret_diverged_cleared',
|
|
122
129
|
secretDiverged: true,
|
|
123
130
|
...(rateLimitUntilMs !== undefined ? { rateLimitUntilMs } : {}),
|
|
124
131
|
...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
|
|
@@ -134,11 +141,13 @@ export class PublicHubCapability {
|
|
|
134
141
|
?? this.opts.senderId();
|
|
135
142
|
const nodeSecret = stringField(payload, 'node_secret') ?? stringField(payload, 'nodeSecret');
|
|
136
143
|
const nodeSecretVersion = parseNodeSecretVersion(payload['node_secret_version'] ?? payload['nodeSecretVersion']);
|
|
137
|
-
if (
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
144
|
+
if (!opts.preserveCredentials) {
|
|
145
|
+
if (nodeSecret && isNodeSecret(nodeSecret)) {
|
|
146
|
+
this.auth.adoptNodeSecret?.(nodeSecret, nodeSecretVersion);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
this.auth.adoptNodeSecretVersion?.(nodeSecretVersion);
|
|
150
|
+
}
|
|
142
151
|
}
|
|
143
152
|
return {
|
|
144
153
|
ok: payload['ok'] !== false && Boolean(nodeId),
|
|
@@ -710,7 +719,38 @@ function assetsFromBody(body) {
|
|
|
710
719
|
...(Array.isArray(payload?.['assets']) ? payload['assets'] : []),
|
|
711
720
|
...(Array.isArray(payload?.['results']) ? payload['results'] : []),
|
|
712
721
|
];
|
|
713
|
-
return candidates
|
|
722
|
+
return candidates
|
|
723
|
+
.filter((candidate) => Boolean(candidate && typeof candidate === 'object' && !Array.isArray(candidate)))
|
|
724
|
+
.map(unwrapFetchDeliveryRow);
|
|
725
|
+
}
|
|
726
|
+
// Delivery-row ranking metadata carried over onto the unwrapped GEP record: hubReuse's candidate
|
|
727
|
+
// ranking reads these from the row (toRankedCandidate), and reuse's ingest strips them before
|
|
728
|
+
// hashing, so carrying them is both useful and integrity-safe. Do not carry `confidence`: it is
|
|
729
|
+
// transport metadata on Gene rows but canonical content on Capsules, so overloading it here can
|
|
730
|
+
// either poison a Gene hash or overwrite the meaning of Capsule content (#565).
|
|
731
|
+
const FETCH_ROW_CARRYOVER_KEYS = ['gdi_score', 'success_rate', 'reuse_count', 'source_node_id'];
|
|
732
|
+
/**
|
|
733
|
+
* The live hub's /a2a/fetch results are DELIVERY ROWS, not raw GEP records (#565, observed on
|
|
734
|
+
* evomap.ai 2026-07-22): the record itself nests under `payload`, while the row's own keys are
|
|
735
|
+
* delivery metadata (asset_type, bundle_id, confidence, gdi_score_mean, callable, …). Treating the
|
|
736
|
+
* row as the asset made reuse's integrity check (computeAssetId over the row) fail on every
|
|
737
|
+
* delivered asset. A GEP record always carries a string `type`; delivery rows carry `asset_type`
|
|
738
|
+
* instead — so unwrap exactly when the row has no `type` and nests an object payload that looks
|
|
739
|
+
* like a GEP record. Rows that already ARE raw records (older hubs, tests) pass through unchanged.
|
|
740
|
+
*/
|
|
741
|
+
function unwrapFetchDeliveryRow(row) {
|
|
742
|
+
const record = row;
|
|
743
|
+
if (typeof record['type'] === 'string')
|
|
744
|
+
return row;
|
|
745
|
+
const inner = asRecord(record['payload']);
|
|
746
|
+
if (!inner || typeof inner['type'] !== 'string' || typeof inner['asset_id'] !== 'string')
|
|
747
|
+
return row;
|
|
748
|
+
const carryover = {};
|
|
749
|
+
for (const key of FETCH_ROW_CARRYOVER_KEYS) {
|
|
750
|
+
if (record[key] !== undefined && inner[key] === undefined)
|
|
751
|
+
carryover[key] = record[key];
|
|
752
|
+
}
|
|
753
|
+
return { ...inner, ...carryover };
|
|
714
754
|
}
|
|
715
755
|
function accountAssetsFromPayload(payload) {
|
|
716
756
|
const candidates = [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evomap/evolver-adapter-public",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.7",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "公版 hub 适配器 (积分/治理)",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@evomap/atp-sdk": "^0.1.0",
|
|
17
|
-
"@evomap/evolver-core": "2.0.0-beta.
|
|
17
|
+
"@evomap/evolver-core": "2.0.0-beta.7",
|
|
18
18
|
"undici": "^6.27.0"
|
|
19
19
|
},
|
|
20
20
|
"optionalDependencies": {
|