voicegate 0.1.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 ADDED
@@ -0,0 +1,23 @@
1
+ # voicegate (Node.js)
2
+
3
+ Node.js SDK for [VoiceGate](https://aivoicegate.com) — voice infrastructure for AI agents, with KYA agent identity (by CallsFlow Ltd).
4
+
5
+ ```bash
6
+ npm install voicegate
7
+ ```
8
+
9
+ ```js
10
+ const { VoiceGate, AgentKey } = require('voicegate');
11
+
12
+ const vg = new VoiceGate({ kyaUrl: 'https://aivoicegate.com' });
13
+ const key = AgentKey.generate();
14
+ const reg = await vg.kyaRegister(key, 'ops@your-company.com', 'your-agent.com');
15
+ const credential = await vg.kyaGetCredential(key, reg.agent_id);
16
+ await vg.kyaLogin(key, credential);
17
+ console.log(await vg.me());
18
+ ```
19
+
20
+ Full docs and the voice-call quick start: see the [repository README](../README.md).
21
+ Runnable examples: [`examples/`](examples).
22
+
23
+ Requires Node.js 18+ (global `fetch`). Zero runtime dependencies.
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "voicegate",
3
+ "version": "0.1.0",
4
+ "description": "Node.js SDK for VoiceGate — voice infrastructure for AI agents, with KYA agent identity (by CallsFlow Ltd)",
5
+ "main": "src/index.js",
6
+ "types": "src/index.d.ts",
7
+ "files": ["src"],
8
+ "scripts": {
9
+ "test": "node examples/kya_identity.js || true"
10
+ },
11
+ "keywords": [
12
+ "ai agents",
13
+ "voice api",
14
+ "telephony",
15
+ "verifiable credentials",
16
+ "erc-8004",
17
+ "kya",
18
+ "voicegate"
19
+ ],
20
+ "author": "CallsFlow Ltd",
21
+ "license": "MIT",
22
+ "homepage": "https://aivoicegate.com",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/IgorSokhinov/voicegate-sdk.git"
26
+ },
27
+ "engines": {
28
+ "node": ">=18"
29
+ }
30
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,39 @@
1
+ export interface VoiceGateOptions {
2
+ baseUrl?: string;
3
+ kyaUrl?: string;
4
+ apiKey?: string | null;
5
+ timeout?: number;
6
+ }
7
+
8
+ export interface CallParams {
9
+ to: string;
10
+ agentWebhook: string;
11
+ voice?: 'female' | 'male';
12
+ language?: string;
13
+ initialMessage?: string;
14
+ }
15
+
16
+ /** An agent's Ed25519 keypair — its cryptographic identity. */
17
+ export class AgentKey {
18
+ static generate(): AgentKey;
19
+ static fromSeedB64(seedB64: string): AgentKey;
20
+ seedB64(): string;
21
+ rawPub(): Buffer;
22
+ readonly did: string;
23
+ signB64url(message: string): string;
24
+ }
25
+
26
+ export class VoiceGateError extends Error {
27
+ status: number;
28
+ body: string;
29
+ }
30
+
31
+ export class VoiceGate {
32
+ constructor(opts?: VoiceGateOptions);
33
+ call(params: CallParams): Promise<unknown>;
34
+ kyaRegister(key: AgentKey, operatorEmail: string, domain?: string): Promise<{ agent_id: string; kyc_status: string; [k: string]: unknown }>;
35
+ kyaGetCredential(key: AgentKey, agentId: string): Promise<Record<string, unknown>>;
36
+ kyaLogin(key: AgentKey, credential: Record<string, unknown>): Promise<{ access_token: string; [k: string]: unknown }>;
37
+ me(): Promise<Record<string, unknown>>;
38
+ issuer(): Promise<Record<string, unknown>>;
39
+ }
package/src/index.js ADDED
@@ -0,0 +1,171 @@
1
+ 'use strict';
2
+ /**
3
+ * VoiceGate — Node.js SDK for the voice gateway for AI agents (by CallsFlow Ltd).
4
+ *
5
+ * - `client.call(...)` asks the gateway to place a phone call for your agent.
6
+ * - `client.kyaRegister / kyaGetCredential / kyaLogin / me` run the Know Your
7
+ * Agent flow: register, get a Verifiable Credential, log in with it, read the
8
+ * cabinet (balance + reputation).
9
+ *
10
+ * KYA endpoints are live today. The voice-call endpoint is in private beta —
11
+ * point `baseUrl` at the host you were given, or run your own gateway.
12
+ *
13
+ * No dependencies: Node 18+ (global fetch) and the built-in `crypto` module.
14
+ */
15
+ const crypto = require('crypto');
16
+
17
+ const B58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
18
+
19
+ function b58encode(buf) {
20
+ let n = BigInt('0x' + (buf.toString('hex') || '0'));
21
+ let out = '';
22
+ while (n > 0n) {
23
+ const r = n % 58n;
24
+ n = n / 58n;
25
+ out = B58[Number(r)] + out;
26
+ }
27
+ for (const b of buf) {
28
+ if (b === 0) out = '1' + out;
29
+ else break;
30
+ }
31
+ return out;
32
+ }
33
+
34
+ function b64url(buf) {
35
+ return buf.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
36
+ }
37
+
38
+ // PKCS8 DER prefix for a raw 32-byte Ed25519 seed.
39
+ const PKCS8_ED25519_PREFIX = Buffer.from('302e020100300506032b657004220420', 'hex');
40
+
41
+ function keyObjectsFromSeed(seed32) {
42
+ const der = Buffer.concat([PKCS8_ED25519_PREFIX, seed32]);
43
+ const privateKey = crypto.createPrivateKey({ key: der, format: 'der', type: 'pkcs8' });
44
+ const publicKey = crypto.createPublicKey(privateKey);
45
+ return { privateKey, publicKey };
46
+ }
47
+
48
+ /** An agent's Ed25519 keypair — its cryptographic identity. */
49
+ class AgentKey {
50
+ constructor(seed32) {
51
+ this._seed = seed32;
52
+ const { privateKey, publicKey } = keyObjectsFromSeed(seed32);
53
+ this._priv = privateKey;
54
+ this._pub = publicKey;
55
+ }
56
+
57
+ static generate() {
58
+ const { privateKey } = crypto.generateKeyPairSync('ed25519');
59
+ const seed = Buffer.from(privateKey.export({ format: 'jwk' }).d, 'base64url');
60
+ return new AgentKey(seed);
61
+ }
62
+
63
+ static fromSeedB64(seedB64) {
64
+ return new AgentKey(Buffer.from(seedB64, 'base64'));
65
+ }
66
+
67
+ seedB64() {
68
+ return this._seed.toString('base64');
69
+ }
70
+
71
+ rawPub() {
72
+ return Buffer.from(this._pub.export({ format: 'jwk' }).x, 'base64url');
73
+ }
74
+
75
+ get did() {
76
+ // did:key for Ed25519 = base58btc('z' + multicodec 0xed01 + raw public key)
77
+ return 'did:key:z' + b58encode(Buffer.concat([Buffer.from([0xed, 0x01]), this.rawPub()]));
78
+ }
79
+
80
+ signB64url(message) {
81
+ return b64url(crypto.sign(null, Buffer.from(message, 'utf8'), this._priv));
82
+ }
83
+ }
84
+
85
+ class VoiceGateError extends Error {
86
+ constructor(status, body) {
87
+ super(`VoiceGate API error ${status}: ${body}`);
88
+ this.status = status;
89
+ this.body = body;
90
+ }
91
+ }
92
+
93
+ class VoiceGate {
94
+ constructor(opts = {}) {
95
+ this.base = (opts.baseUrl || 'https://api.aivoicegate.com').replace(/\/+$/, '');
96
+ this.kya = (opts.kyaUrl || opts.baseUrl || this.base).replace(/\/+$/, '');
97
+ this.apiKey = opts.apiKey || null;
98
+ this.timeout = opts.timeout || 30000;
99
+ this._session = null;
100
+ }
101
+
102
+ async _request(method, url, body, auth) {
103
+ const headers = { 'Content-Type': 'application/json' };
104
+ if (auth) headers['Authorization'] = 'Bearer ' + auth;
105
+ const ctrl = new AbortController();
106
+ const t = setTimeout(() => ctrl.abort(), this.timeout);
107
+ let resp;
108
+ try {
109
+ resp = await fetch(url, {
110
+ method,
111
+ headers,
112
+ body: body != null ? JSON.stringify(body) : undefined,
113
+ signal: ctrl.signal,
114
+ });
115
+ } finally {
116
+ clearTimeout(t);
117
+ }
118
+ const text = await resp.text();
119
+ if (!resp.ok) throw new VoiceGateError(resp.status, text);
120
+ return text ? JSON.parse(text) : null;
121
+ }
122
+
123
+ // ── voice call (private beta) ──────────────────────────────────────────────
124
+ async call({ to, agentWebhook, voice = 'female', language = 'en', initialMessage } = {}) {
125
+ const body = { to, voice, language, agent_webhook: agentWebhook, pay: 'usdc:base' };
126
+ if (initialMessage) body.initial_message = initialMessage;
127
+ return this._request('POST', this.base + '/v1/agent-call', body, this.apiKey);
128
+ }
129
+
130
+ // ── KYA — Know Your Agent (live) ───────────────────────────────────────────
131
+ async kyaRegister(key, operatorEmail, domain) {
132
+ return this._request('POST', this.kya + '/v1/agents/register', {
133
+ operator_email: operatorEmail,
134
+ operator_kind: 'business',
135
+ domain: domain || null,
136
+ public_key: key.did,
137
+ });
138
+ }
139
+
140
+ async kyaGetCredential(key, agentId) {
141
+ const proof = key.signB64url('kya-credential:' + agentId);
142
+ const res = await this._request('POST', `${this.kya}/v1/agents/${agentId}/credential`, {
143
+ public_key: key.did,
144
+ proof,
145
+ });
146
+ return res.credential;
147
+ }
148
+
149
+ async kyaLogin(key, credential) {
150
+ const challenge = await this._request('POST', this.kya + '/v1/auth/challenge', { did: key.did });
151
+ const signature = key.signB64url(challenge.nonce);
152
+ const res = await this._request('POST', this.kya + '/v1/auth/verify', {
153
+ credential,
154
+ nonce: challenge.nonce,
155
+ signature,
156
+ });
157
+ this._session = res.access_token;
158
+ return res;
159
+ }
160
+
161
+ async me() {
162
+ if (!this._session) throw new VoiceGateError(0, 'not logged in — call kyaLogin() first');
163
+ return this._request('GET', this.kya + '/v1/me', null, this._session);
164
+ }
165
+
166
+ async issuer() {
167
+ return this._request('GET', this.kya + '/v1/issuer');
168
+ }
169
+ }
170
+
171
+ module.exports = { VoiceGate, AgentKey, VoiceGateError };