@zerox1/sdk 0.2.1 → 0.2.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/index.d.ts CHANGED
@@ -205,6 +205,27 @@ export declare class Zerox1Agent {
205
205
  */
206
206
  encodeBidValue(value: bigint, rest?: Buffer): Buffer;
207
207
  private _connectInbox;
208
+ /**
209
+ * Upload a media blob to the aggregator.
210
+ * Enforces reputation-based size limits:
211
+ * - Claimed/Rep 100+: 10 MB
212
+ * - Rep 50-99: 2 MB
213
+ * - Rep 10-49: 512 KB
214
+ *
215
+ * Every upload is signed by the agent's keypair for authentication.
216
+ *
217
+ * @param data - Buffer or Uint8Array of the media.
218
+ * @param aggregatorUrl - Aggregator base URL.
219
+ * @returns Hex-encoded CID (Keccak-256 hash).
220
+ */
221
+ uploadBlob(data: Buffer | Uint8Array, aggregatorUrl?: string): Promise<string>;
222
+ /**
223
+ * Download a media blob from the aggregator.
224
+ *
225
+ * @param cid - Hex-encoded CID.
226
+ * @param aggregatorUrl - Aggregator base URL.
227
+ */
228
+ downloadBlob(cid: string, aggregatorUrl?: string): Promise<Buffer>;
208
229
  }
209
230
  /**
210
231
  * A hosted agent that delegates signing and routing to a host node.
package/dist/index.js CHANGED
@@ -43,6 +43,7 @@ const os = __importStar(require("os"));
43
43
  const path = __importStar(require("path"));
44
44
  const child_process_1 = require("child_process");
45
45
  const ws_1 = __importDefault(require("ws"));
46
+ const ed = __importStar(require("@noble/ed25519"));
46
47
  // ============================================================================
47
48
  // CBOR encoding for FEEDBACK payload
48
49
  //
@@ -458,6 +459,70 @@ class Zerox1Agent {
458
459
  });
459
460
  ws.on('error', () => { });
460
461
  }
462
+ // ── Blobs (Media Relay) ───────────────────────────────────────────────────
463
+ /**
464
+ * Upload a media blob to the aggregator.
465
+ * Enforces reputation-based size limits:
466
+ * - Claimed/Rep 100+: 10 MB
467
+ * - Rep 50-99: 2 MB
468
+ * - Rep 10-49: 512 KB
469
+ *
470
+ * Every upload is signed by the agent's keypair for authentication.
471
+ *
472
+ * @param data - Buffer or Uint8Array of the media.
473
+ * @param aggregatorUrl - Aggregator base URL.
474
+ * @returns Hex-encoded CID (Keccak-256 hash).
475
+ */
476
+ async uploadBlob(data, aggregatorUrl = 'https://api.0x01.world') {
477
+ const timestamp = Math.floor(Date.now() / 1000);
478
+ const body = Buffer.from(data);
479
+ // Signing payload: body + timestamp (8-byte Little Endian)
480
+ const tsBuf = Buffer.alloc(8);
481
+ tsBuf.writeBigUInt64LE(BigInt(timestamp), 0);
482
+ const msg = Buffer.concat([body, tsBuf]);
483
+ const secretKeyHex = fs.readFileSync(resolveKeypairPath(this._config.keypair), 'hex');
484
+ const secretKey = Buffer.from(secretKeyHex, 'hex').slice(0, 32);
485
+ const pubKey = await ed.getPublicKey(secretKey);
486
+ const signature = await ed.sign(msg, secretKey);
487
+ // In dev mode agent_id == verifying key (same hex).
488
+ // In SATI mode agent_id is the SATI mint address (different key).
489
+ // The aggregator uses X-0x01-Agent-Id for reputation lookup and
490
+ // X-0x01-Signer for signature verification — always the Ed25519 key.
491
+ const signerHex = Buffer.from(pubKey).toString('hex');
492
+ const agentIdHex = this._config.satiMint ?? signerHex;
493
+ const res = await fetch(`${aggregatorUrl}/blobs`, {
494
+ method: 'POST',
495
+ headers: {
496
+ 'Content-Type': 'application/octet-stream',
497
+ 'X-0x01-Agent-Id': agentIdHex,
498
+ 'X-0x01-Signer': signerHex,
499
+ 'X-0x01-Timestamp': timestamp.toString(),
500
+ 'X-0x01-Signature': Buffer.from(signature).toString('hex'),
501
+ },
502
+ body: body,
503
+ });
504
+ if (!res.ok) {
505
+ const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
506
+ throw new Error(`uploadBlob failed: ${err.error ?? res.status}`);
507
+ }
508
+ const { cid } = await res.json();
509
+ return cid;
510
+ }
511
+ /**
512
+ * Download a media blob from the aggregator.
513
+ *
514
+ * @param cid - Hex-encoded CID.
515
+ * @param aggregatorUrl - Aggregator base URL.
516
+ */
517
+ async downloadBlob(cid, aggregatorUrl = 'https://api.0x01.world') {
518
+ const res = await fetch(`${aggregatorUrl}/blobs/${cid}`);
519
+ if (res.status === 404)
520
+ throw new Error('Blob not found');
521
+ if (!res.ok)
522
+ throw new Error(`downloadBlob failed: HTTP ${res.status}`);
523
+ const arrayBuffer = await res.arrayBuffer();
524
+ return Buffer.from(arrayBuffer);
525
+ }
461
526
  }
462
527
  exports.Zerox1Agent = Zerox1Agent;
463
528
  // ============================================================================
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerox1/sdk",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "0x01 mesh agent SDK — zero-config, binary bundled, works on every platform",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -10,13 +10,14 @@
10
10
  "dev": "tsc --watch"
11
11
  },
12
12
  "dependencies": {
13
+ "@noble/ed25519": "^3.0.0",
13
14
  "ws": "^8.18.0"
14
15
  },
15
16
  "optionalDependencies": {
16
- "@zerox1/sdk-darwin-arm64": "0.2.1",
17
- "@zerox1/sdk-darwin-x64": "0.2.1",
18
- "@zerox1/sdk-linux-x64": "0.2.1",
19
- "@zerox1/sdk-win32-x64": "0.2.1"
17
+ "@zerox1/sdk-darwin-arm64": "0.2.3",
18
+ "@zerox1/sdk-darwin-x64": "0.2.3",
19
+ "@zerox1/sdk-linux-x64": "0.2.3",
20
+ "@zerox1/sdk-win32-x64": "0.2.3"
20
21
  },
21
22
  "devDependencies": {
22
23
  "@types/node": "^22.0.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerox1/sdk-darwin-arm64",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "zerox1-node binary for macOS ARM64 (Apple Silicon)",
5
5
  "os": [
6
6
  "darwin"
Binary file
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerox1/sdk-darwin-x64",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "zerox1-node binary for macOS x64 (Intel)",
5
5
  "os": [
6
6
  "darwin"
Binary file
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerox1/sdk-linux-x64",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "zerox1-node binary for Linux x64",
5
5
  "os": [
6
6
  "linux"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerox1/sdk-win32-x64",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "zerox1-node binary for Windows x64",
5
5
  "os": [
6
6
  "win32"
package/src/index.ts CHANGED
@@ -4,6 +4,7 @@ import * as os from 'os'
4
4
  import * as path from 'path'
5
5
  import { spawn, ChildProcess } from 'child_process'
6
6
  import WebSocket from 'ws'
7
+ import * as ed from '@noble/ed25519'
7
8
 
8
9
  // ============================================================================
9
10
  // Public config / types
@@ -623,6 +624,84 @@ export class Zerox1Agent {
623
624
 
624
625
  ws.on('error', () => { /* close event handles reconnect */ })
625
626
  }
627
+
628
+ // ── Blobs (Media Relay) ───────────────────────────────────────────────────
629
+
630
+ /**
631
+ * Upload a media blob to the aggregator.
632
+ * Enforces reputation-based size limits:
633
+ * - Claimed/Rep 100+: 10 MB
634
+ * - Rep 50-99: 2 MB
635
+ * - Rep 10-49: 512 KB
636
+ *
637
+ * Every upload is signed by the agent's keypair for authentication.
638
+ *
639
+ * @param data - Buffer or Uint8Array of the media.
640
+ * @param aggregatorUrl - Aggregator base URL.
641
+ * @returns Hex-encoded CID (Keccak-256 hash).
642
+ */
643
+ async uploadBlob(
644
+ data: Buffer | Uint8Array,
645
+ aggregatorUrl = 'https://api.0x01.world'
646
+ ): Promise<string> {
647
+ const timestamp = Math.floor(Date.now() / 1000)
648
+ const body = Buffer.from(data)
649
+
650
+ // Signing payload: body + timestamp (8-byte Little Endian)
651
+ const tsBuf = Buffer.alloc(8)
652
+ tsBuf.writeBigUInt64LE(BigInt(timestamp), 0)
653
+ const msg = Buffer.concat([body, tsBuf])
654
+
655
+ const secretKeyHex = fs.readFileSync(resolveKeypairPath(this._config.keypair), 'hex')
656
+ const secretKey = Buffer.from(secretKeyHex, 'hex').slice(0, 32)
657
+ const pubKey = await ed.getPublicKey(secretKey)
658
+ const signature = await ed.sign(msg, secretKey)
659
+
660
+ // In dev mode agent_id == verifying key (same hex).
661
+ // In SATI mode agent_id is the SATI mint address (different key).
662
+ // The aggregator uses X-0x01-Agent-Id for reputation lookup and
663
+ // X-0x01-Signer for signature verification — always the Ed25519 key.
664
+ const signerHex = Buffer.from(pubKey).toString('hex')
665
+ const agentIdHex = this._config.satiMint ?? signerHex
666
+
667
+ const res = await fetch(`${aggregatorUrl}/blobs`, {
668
+ method: 'POST',
669
+ headers: {
670
+ 'Content-Type': 'application/octet-stream',
671
+ 'X-0x01-Agent-Id': agentIdHex,
672
+ 'X-0x01-Signer': signerHex,
673
+ 'X-0x01-Timestamp': timestamp.toString(),
674
+ 'X-0x01-Signature': Buffer.from(signature).toString('hex'),
675
+ },
676
+ body: body,
677
+ })
678
+
679
+ if (!res.ok) {
680
+ const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }))
681
+ throw new Error(`uploadBlob failed: ${(err as { error?: string }).error ?? res.status}`)
682
+ }
683
+
684
+ const { cid } = await res.json() as { cid: string }
685
+ return cid
686
+ }
687
+
688
+ /**
689
+ * Download a media blob from the aggregator.
690
+ *
691
+ * @param cid - Hex-encoded CID.
692
+ * @param aggregatorUrl - Aggregator base URL.
693
+ */
694
+ async downloadBlob(
695
+ cid: string,
696
+ aggregatorUrl = 'https://api.0x01.world'
697
+ ): Promise<Buffer> {
698
+ const res = await fetch(`${aggregatorUrl}/blobs/${cid}`)
699
+ if (res.status === 404) throw new Error('Blob not found')
700
+ if (!res.ok) throw new Error(`downloadBlob failed: HTTP ${res.status}`)
701
+
702
+ const arrayBuffer = await res.arrayBuffer()
703
+ return Buffer.from(arrayBuffer)
704
+ }
626
705
  }
627
706
 
628
707
  // ============================================================================