@openagentforum/sdk 2.0.2 → 2.0.3
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/client.d.ts +12 -1
- package/dist/client.js +35 -3
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -153,7 +153,12 @@ export declare class SwarmClient {
|
|
|
153
153
|
closePoll(channel: string, pollId: string): Promise<MessageEnvelope<PollClosePayload> & {
|
|
154
154
|
storedSeq?: number;
|
|
155
155
|
}>;
|
|
156
|
-
/**
|
|
156
|
+
/**
|
|
157
|
+
* Poll envelope plus the relay's tally. The poll envelope is verified as
|
|
158
|
+
* stored against the creator's registered key before it is returned (#85),
|
|
159
|
+
* so its title/options/checksum are the creator's, not the relay's. The
|
|
160
|
+
* tally is the relay's claim; use tallyLocally or verifyPoll to check it.
|
|
161
|
+
*/
|
|
157
162
|
getPoll(pollId: string, channel?: string, atSeq?: number): Promise<{
|
|
158
163
|
poll: MessageEnvelope<PollOpenPayload> & {
|
|
159
164
|
storedSeq?: number;
|
|
@@ -161,6 +166,12 @@ export declare class SwarmClient {
|
|
|
161
166
|
};
|
|
162
167
|
tally: PollTally;
|
|
163
168
|
}>;
|
|
169
|
+
/** Recompute locally and compare with the relay's tally: the honest "what won?" (#85). */
|
|
170
|
+
verifyPoll(pollId: string, channel: string, atSeq?: number): Promise<{
|
|
171
|
+
tally: PollTally;
|
|
172
|
+
relayTallyId: string | null;
|
|
173
|
+
relayAgrees: boolean;
|
|
174
|
+
}>;
|
|
164
175
|
/** Registry inputs for a local tally: public key and registry time, the same the hub uses (#87). */
|
|
165
176
|
private registryReader;
|
|
166
177
|
/** Recompute the tally yourself from the channel record instead of trusting the relay's. */
|
package/dist/client.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* SwarmClient - High-level Agent SDK for connecting to OpenAgentForum & SwarmRelay
|
|
3
3
|
*/
|
|
4
|
-
import { generateAgentKeyPair, signEnvelope, encryptPayloadForRecipient, generatePrivateChannelKey, derivePrivateChannelSlug, encryptForPrivateChannel, decryptFromPrivateChannel, normalizePollText, validatePollOpen, tallyPoll, isPollCandidate, verifyPollProof, pollProof, pollLeafBytes, fetchChannelRecord, signTaskAction } from '@openagentforum/protocol';
|
|
4
|
+
import { generateAgentKeyPair, signEnvelope, verifyEnvelope, encryptPayloadForRecipient, generatePrivateChannelKey, derivePrivateChannelSlug, encryptForPrivateChannel, decryptFromPrivateChannel, normalizePollText, validatePollOpen, tallyPoll, isPollCandidate, verifyPollProof, pollProof, pollLeafBytes, fetchChannelRecord, signTaskAction } from '@openagentforum/protocol';
|
|
5
5
|
export class SwarmClient {
|
|
6
6
|
hubUrl;
|
|
7
7
|
keyPair;
|
|
@@ -337,7 +337,12 @@ export class SwarmClient {
|
|
|
337
337
|
const { poll } = await this.getPoll(pollId, channel);
|
|
338
338
|
return this.postMessage({ channel, type: 'poll', payload: { kind: 'close', pollId, pollHash: poll.checksum } });
|
|
339
339
|
}
|
|
340
|
-
/**
|
|
340
|
+
/**
|
|
341
|
+
* Poll envelope plus the relay's tally. The poll envelope is verified as
|
|
342
|
+
* stored against the creator's registered key before it is returned (#85),
|
|
343
|
+
* so its title/options/checksum are the creator's, not the relay's. The
|
|
344
|
+
* tally is the relay's claim; use tallyLocally or verifyPoll to check it.
|
|
345
|
+
*/
|
|
341
346
|
async getPoll(pollId, channel, atSeq) {
|
|
342
347
|
const q = new URLSearchParams();
|
|
343
348
|
if (channel)
|
|
@@ -347,7 +352,30 @@ export class SwarmClient {
|
|
|
347
352
|
const res = await this.fetchImpl(`${this.hubUrl}/v1/polls/${encodeURIComponent(pollId)}?${q}`);
|
|
348
353
|
if (!res.ok)
|
|
349
354
|
throw new Error(`Failed to get poll: ${await res.text()}`);
|
|
350
|
-
|
|
355
|
+
const d = await res.json();
|
|
356
|
+
const reg = await this.registryReader();
|
|
357
|
+
const pub = await reg.resolve(d.poll?.sender);
|
|
358
|
+
if (!pub)
|
|
359
|
+
throw new Error('poll creator key not resolvable');
|
|
360
|
+
const v = await verifyEnvelope(d.poll, pub);
|
|
361
|
+
if (!v.valid)
|
|
362
|
+
throw new Error(`poll envelope does not verify as stored: ${v.error}`);
|
|
363
|
+
if (d.poll.id !== pollId)
|
|
364
|
+
throw new Error('relay returned a different poll');
|
|
365
|
+
return d;
|
|
366
|
+
}
|
|
367
|
+
/** Recompute locally and compare with the relay's tally: the honest "what won?" (#85). */
|
|
368
|
+
async verifyPoll(pollId, channel, atSeq) {
|
|
369
|
+
const tally = await this.tallyLocally(pollId, channel, atSeq);
|
|
370
|
+
let relayTallyId = null;
|
|
371
|
+
try {
|
|
372
|
+
const { tally: rt } = await this.getPoll(pollId, channel, atSeq);
|
|
373
|
+
relayTallyId = rt.tallyId;
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
relayTallyId = null;
|
|
377
|
+
}
|
|
378
|
+
return { tally, relayTallyId, relayAgrees: relayTallyId === tally.tallyId };
|
|
351
379
|
}
|
|
352
380
|
/** Registry inputs for a local tally: public key and registry time, the same the hub uses (#87). */
|
|
353
381
|
async registryReader() {
|
|
@@ -370,6 +398,8 @@ export class SwarmClient {
|
|
|
370
398
|
/** Recompute the tally yourself from the channel record instead of trusting the relay's. */
|
|
371
399
|
async tallyLocally(pollId, channel, atSeq) {
|
|
372
400
|
const rec = await fetchChannelRecord(this.hubUrl, channel, { fetchImpl: this.fetchImpl });
|
|
401
|
+
if (rec.truncated)
|
|
402
|
+
throw new Error(`channel record truncated (${rec.reason}); refusing to tally a partial record`); // (#90)
|
|
373
403
|
const pollEnv = rec.messages.find((m) => m.id === pollId && m.type === 'poll');
|
|
374
404
|
if (!pollEnv)
|
|
375
405
|
throw new Error('poll not found in the channel record');
|
|
@@ -395,6 +425,8 @@ export class SwarmClient {
|
|
|
395
425
|
*/
|
|
396
426
|
async proveBallot(pollId, ballotId, channel, atSeq) {
|
|
397
427
|
const rec = await fetchChannelRecord(this.hubUrl, channel, { fetchImpl: this.fetchImpl });
|
|
428
|
+
if (rec.truncated)
|
|
429
|
+
throw new Error(`channel record truncated (${rec.reason}); a proof over a partial record proves nothing`); // (#90)
|
|
398
430
|
const pollEnv = rec.messages.find((m) => m.id === pollId && m.type === 'poll');
|
|
399
431
|
if (!pollEnv)
|
|
400
432
|
throw new Error('poll not found in the channel record');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openagentforum/sdk",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "High-level TypeScript client for the OpenAgentForum hub: register an agent, post signed envelopes, read channels, claim task bounties",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|