@astrasyncai/verification-gateway 2.4.0 → 2.4.1
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 +99 -22
- package/dist/bin/astrasync.js +153 -3
- package/dist/registration/index.d.mts +155 -4
- package/dist/registration/index.d.ts +155 -4
- package/dist/registration/index.js +161 -5
- package/dist/registration/index.js.map +1 -1
- package/dist/registration/index.mjs +157 -4
- package/dist/registration/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -105,35 +105,109 @@ if (result.verified && result.accessLevel !== 'none') {
|
|
|
105
105
|
|
|
106
106
|
### Agent Registration
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
**Use the SDK for all agent registration**, whether you're a developer firing off a one-shot CLI call or an autonomous agent self-registering on first run. The SDK handles auth-mode routing for you: signature-authenticated callers get synchronous registration; API-key-only callers get an owner-approval handshake (server-side rule, not negotiable).
|
|
109
|
+
|
|
110
|
+
#### `apiEndpoint` — runtime-challenge URL
|
|
111
|
+
|
|
112
|
+
`apiEndpoint` is the URL where your agent's verification-gateway SDK is mounted to receive runtime challenges from counterparties. Optional but recommended — if you omit it, your agent declares no runtime-challenge support, which is included in the verification payload and may cause some counterparties to decline access requests.
|
|
113
|
+
|
|
114
|
+
#### Two registration response modes
|
|
115
|
+
|
|
116
|
+
The same `register()` call returns one of two shapes depending on auth context:
|
|
117
|
+
|
|
118
|
+
- **201 active** — synchronous: returned when the request is signed with a crypto keypair (`privateKey` configured) or when authenticated via email+password. Result: `{ status: 'active', agent }`.
|
|
119
|
+
- **202 pending_approval** — API-key only: the SDK was authenticated with an API key but the request was not signed. The backend emails the account owner a "Sign In to Accept" link, fires a dashboard alert, and returns a tracking token. Result: `{ status: 'pending_approval', requestId, pollUrl, expiresAt }`. The agent becomes active only after the owner approves.
|
|
120
|
+
|
|
121
|
+
This split enforces the platform rule that **API-key registrations always require owner step-up** — registering an agent autonomously with just an API key is not a sufficient authority signal on its own.
|
|
122
|
+
|
|
123
|
+
#### Pattern A — developer / long-running agent (block until approved)
|
|
124
|
+
|
|
125
|
+
Best for CLI tools, dev-machine first-run, and long-running services:
|
|
109
126
|
|
|
110
127
|
```typescript
|
|
111
|
-
import {
|
|
128
|
+
import {
|
|
129
|
+
AstraSync,
|
|
130
|
+
RegistrationDeniedError,
|
|
131
|
+
RegistrationTimeoutError,
|
|
132
|
+
} from '@astrasyncai/verification-gateway/registration';
|
|
112
133
|
|
|
113
|
-
const
|
|
114
|
-
apiKey: process.env.ASTRASYNC_API_KEY,
|
|
115
|
-
//
|
|
116
|
-
privateKey: process.env.ASTRASYNC_PRIVATE_KEY,
|
|
134
|
+
const sdk = new AstraSync({
|
|
135
|
+
apiKey: process.env.ASTRASYNC_API_KEY,
|
|
136
|
+
privateKey: process.env.ASTRASYNC_PRIVATE_KEY, // optional — when set, 201 sync path
|
|
117
137
|
});
|
|
118
138
|
|
|
119
|
-
|
|
139
|
+
try {
|
|
140
|
+
const agent = await sdk.register({
|
|
141
|
+
name: 'invoice-bot',
|
|
142
|
+
description: 'Reconciles AP/AR across accounting systems.',
|
|
143
|
+
agentType: 'autonomous',
|
|
144
|
+
apiEndpoint: 'https://invoice-bot.example.com', // runtime-challenge URL
|
|
145
|
+
model: { modelProvider: 'anthropic', modelName: 'claude-sonnet-4-5' },
|
|
146
|
+
framework: { frameworkName: 'langchain', frameworkVersion: '0.3.0' },
|
|
147
|
+
protocols: ['a2a', 'mcp'],
|
|
148
|
+
pdlss: {
|
|
149
|
+
purpose: {
|
|
150
|
+
categories: ['accounting'],
|
|
151
|
+
allowedActions: ['accounting.read', 'accounting.write'],
|
|
152
|
+
},
|
|
153
|
+
limits: { stepUpThreshold: 1_000, approvalThreshold: 10_000, currency: 'USD' },
|
|
154
|
+
scope: { resources: ['xero.invoices', 'quickbooks.bills'] },
|
|
155
|
+
selfInstantiation: { allowed: false },
|
|
156
|
+
},
|
|
157
|
+
// Blocking mode: poll until the request resolves.
|
|
158
|
+
waitForApproval: true,
|
|
159
|
+
timeoutMs: 10 * 60 * 1000, // 10 minutes default
|
|
160
|
+
onPending: ({ ageMs }) =>
|
|
161
|
+
console.log(`Awaiting owner approval (${(ageMs / 1000).toFixed(0)}s)…`),
|
|
162
|
+
});
|
|
163
|
+
console.log(`Agent registered: ${agent.astrasyncIdLevel1}`);
|
|
164
|
+
} catch (err) {
|
|
165
|
+
if (err instanceof RegistrationDeniedError) {
|
|
166
|
+
console.error('Owner denied:', err.reason);
|
|
167
|
+
} else if (err instanceof RegistrationTimeoutError) {
|
|
168
|
+
console.error(
|
|
169
|
+
'Timed out — request is still active server-side; poll later via sdk.waitForApproval(requestId)'
|
|
170
|
+
);
|
|
171
|
+
} else {
|
|
172
|
+
throw err;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
#### Pattern B — serverless / scheduled agent (non-blocking, exit and resume)
|
|
178
|
+
|
|
179
|
+
Best for Lambda / Cloud Functions / cron-driven self-registration where you can't hold the runtime open for minutes:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
const sdk = new AstraSync({ apiKey: process.env.ASTRASYNC_API_KEY });
|
|
183
|
+
|
|
184
|
+
const result = await sdk.register({
|
|
120
185
|
name: 'invoice-bot',
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
model: { modelProvider: 'anthropic', modelName: 'claude-sonnet-4-5' },
|
|
124
|
-
framework: { frameworkName: 'langchain', frameworkVersion: '0.3.0' },
|
|
125
|
-
protocols: ['a2a', 'mcp'],
|
|
126
|
-
pdlss: {
|
|
127
|
-
purpose: { allowed: ['accounting.read', 'accounting.write'] },
|
|
128
|
-
duration: { requested: 'P30D' },
|
|
129
|
-
limits: { transactionValue: 5000, currency: 'USD' },
|
|
130
|
-
scope: { resources: ['xero.invoices', 'quickbooks.bills'] },
|
|
131
|
-
selfInstantiation: { allowed: false },
|
|
132
|
-
},
|
|
186
|
+
apiEndpoint: 'https://invoice-bot.example.com',
|
|
187
|
+
pdlss: { purpose: { categories: ['accounting'], allowedActions: ['accounting.read'] } },
|
|
133
188
|
});
|
|
134
189
|
|
|
135
|
-
|
|
136
|
-
|
|
190
|
+
if (result.status === 'pending_approval') {
|
|
191
|
+
// Store the requestId in your durable storage (DynamoDB, KV, etc.)
|
|
192
|
+
await store.set('astrasync.pendingRequestId', result.requestId);
|
|
193
|
+
console.log(`Awaiting owner approval at ${result.pollUrl}; will resume on next scheduled run.`);
|
|
194
|
+
return; // function exits — owner has time to approve
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
console.log(`Agent registered as ${result.agent.astrasyncIdLevel1}`);
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
On the next scheduled run, resume by polling:
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
const requestId = await store.get('astrasync.pendingRequestId');
|
|
204
|
+
const status = await sdk.pollRegistration(requestId);
|
|
205
|
+
if (status.state === 'approved') {
|
|
206
|
+
await store.set('astrasync.agentId', status.agent.kyaAgentId);
|
|
207
|
+
await store.delete('astrasync.pendingRequestId');
|
|
208
|
+
} else if (status.state === 'denied' || status.state === 'expired') {
|
|
209
|
+
console.error(`Registration terminated: ${status.state}`);
|
|
210
|
+
}
|
|
137
211
|
```
|
|
138
212
|
|
|
139
213
|
CLI equivalent — same surface from a shell, also via `npx`:
|
|
@@ -143,9 +217,12 @@ npx astrasync register --name invoice-bot --agent-type autonomous \
|
|
|
143
217
|
--model-provider anthropic --model-name claude-sonnet-4-5 \
|
|
144
218
|
--framework-name langchain --framework-version 0.3.0 \
|
|
145
219
|
--protocols a2a,mcp \
|
|
146
|
-
--
|
|
220
|
+
--api-endpoint https://invoice-bot.example.com \
|
|
221
|
+
--pdlss '{"purpose":{"categories":["accounting"],"allowedActions":["accounting.read"]}}'
|
|
147
222
|
```
|
|
148
223
|
|
|
224
|
+
The CLI uses the same response logic — it will print a "Sign in to approve" message and a poll URL when the response is 202 pending, and exit non-zero on deny/expire.
|
|
225
|
+
|
|
149
226
|
> `/registration` is for **one-shot onboarding** — register an agent, look up its public profile, check API health. For **per-request credential injection** (attaching ASTRA-id, sessionId, PDLSS to outgoing HTTP / A2A / MCP calls from an already-registered agent), use `/agent` (`AgentClient`). The two roles are deliberately separate concerns: registration is identity, `/agent` is runtime.
|
|
150
227
|
|
|
151
228
|
> A `PDLSSConfig` type exists in both `/registration` and `/agent`, with **different shapes**. `/registration`'s `PDLSSConfig` is the boundary declaration submitted at register time; `/agent`'s `PDLSSConfig` is the per-request runtime request shape. Disambiguate via the import path — the root export deliberately does not re-export either.
|
package/dist/bin/astrasync.js
CHANGED
|
@@ -52,9 +52,44 @@ var AuthenticationError = class extends AstraSyncError {
|
|
|
52
52
|
this.name = "AuthenticationError";
|
|
53
53
|
}
|
|
54
54
|
};
|
|
55
|
+
var RegistrationDeniedError = class extends AstraSyncError {
|
|
56
|
+
constructor(requestId, reason) {
|
|
57
|
+
super(
|
|
58
|
+
`Registration request ${requestId} was denied by the account owner.${reason ? ` Reason: ${reason}` : ""}`,
|
|
59
|
+
403,
|
|
60
|
+
"REGISTRATION_DENIED"
|
|
61
|
+
);
|
|
62
|
+
this.name = "RegistrationDeniedError";
|
|
63
|
+
this.requestId = requestId;
|
|
64
|
+
this.reason = reason;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
var RegistrationExpiredError = class extends AstraSyncError {
|
|
68
|
+
constructor(requestId) {
|
|
69
|
+
super(
|
|
70
|
+
`Registration request ${requestId} expired before the owner approved it. Submit a new registration request.`,
|
|
71
|
+
410,
|
|
72
|
+
"REGISTRATION_EXPIRED"
|
|
73
|
+
);
|
|
74
|
+
this.name = "RegistrationExpiredError";
|
|
75
|
+
this.requestId = requestId;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
var RegistrationTimeoutError = class extends AstraSyncError {
|
|
79
|
+
constructor(requestId) {
|
|
80
|
+
super(
|
|
81
|
+
`Timed out waiting for owner approval of registration request ${requestId}. The request is still active server-side; poll the request to resume waiting.`,
|
|
82
|
+
408,
|
|
83
|
+
"REGISTRATION_TIMEOUT"
|
|
84
|
+
);
|
|
85
|
+
this.name = "RegistrationTimeoutError";
|
|
86
|
+
this.requestId = requestId;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
55
89
|
|
|
56
90
|
// src/registration/api.ts
|
|
57
91
|
var DEFAULT_BASE_URL = "https://astrasync.ai";
|
|
92
|
+
var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
58
93
|
var AstraSync = class {
|
|
59
94
|
constructor(config = {}) {
|
|
60
95
|
this.baseUrl = (config.baseUrl || process.env.ASTRASYNC_API_URL || DEFAULT_BASE_URL).replace(
|
|
@@ -76,7 +111,36 @@ var AstraSync = class {
|
|
|
76
111
|
}
|
|
77
112
|
/**
|
|
78
113
|
* Register a new AI agent on the AstraSync KYA Platform.
|
|
79
|
-
*
|
|
114
|
+
*
|
|
115
|
+
* The backend response depends on auth context:
|
|
116
|
+
* - **Crypto-keypair signed** (`privateKey` configured): synchronous 201,
|
|
117
|
+
* returns `{ status: 'active', agent }`.
|
|
118
|
+
* - **API-key only** (no signature): 202 pending, returns
|
|
119
|
+
* `{ status: 'pending_approval', requestId, pollUrl, expiresAt }`. The
|
|
120
|
+
* owner is notified by email and a dashboard alert is emitted; the agent
|
|
121
|
+
* becomes active only after the owner approves.
|
|
122
|
+
*
|
|
123
|
+
* Blocking mode: pass `{ waitForApproval: true }` to have the SDK poll the
|
|
124
|
+
* request until it resolves, then return the live agent record. The promise
|
|
125
|
+
* rejects with `RegistrationDeniedError`, `RegistrationExpiredError`, or
|
|
126
|
+
* `RegistrationTimeoutError` on the corresponding terminal states.
|
|
127
|
+
*
|
|
128
|
+
* @example Non-blocking (default — best for serverless / scheduled agents):
|
|
129
|
+
* ```typescript
|
|
130
|
+
* const result = await sdk.register({ name, pdlss });
|
|
131
|
+
* if (result.status === 'pending_approval') {
|
|
132
|
+
* storeRequestId(result.requestId);
|
|
133
|
+
* return; // function exits; resume later via pollRegistration()
|
|
134
|
+
* }
|
|
135
|
+
* ```
|
|
136
|
+
*
|
|
137
|
+
* @example Blocking (best for long-running services + CLI):
|
|
138
|
+
* ```typescript
|
|
139
|
+
* const agent = await sdk.register({
|
|
140
|
+
* name, pdlss, waitForApproval: true, timeoutMs: 600_000,
|
|
141
|
+
* onPending: ({ ageMs }) => console.log(`waiting ${ageMs}ms`),
|
|
142
|
+
* });
|
|
143
|
+
* ```
|
|
80
144
|
*/
|
|
81
145
|
async register(options) {
|
|
82
146
|
const body = {
|
|
@@ -90,7 +154,84 @@ var AstraSync = class {
|
|
|
90
154
|
...options.metadata && { metadata: options.metadata },
|
|
91
155
|
...options.pdlss && { pdlss: options.pdlss }
|
|
92
156
|
};
|
|
93
|
-
|
|
157
|
+
const { status, body: raw } = await this.requestWithStatus("POST", "/api/agents/register", body);
|
|
158
|
+
if (status === 201) {
|
|
159
|
+
const active = {
|
|
160
|
+
status: "active",
|
|
161
|
+
agent: raw.data.agent
|
|
162
|
+
};
|
|
163
|
+
return active;
|
|
164
|
+
}
|
|
165
|
+
const pendingBody = raw;
|
|
166
|
+
const pending = {
|
|
167
|
+
status: "pending_approval",
|
|
168
|
+
requestId: pendingBody.requestId,
|
|
169
|
+
expiresAt: pendingBody.expiresAt,
|
|
170
|
+
pollUrl: pendingBody.pollUrl,
|
|
171
|
+
message: pendingBody.message
|
|
172
|
+
};
|
|
173
|
+
if (!options.waitForApproval) return pending;
|
|
174
|
+
return this.waitForApproval(pendingBody.requestId, options);
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Poll the current state of a pending-approval registration request.
|
|
178
|
+
*
|
|
179
|
+
* Useful for caller-driven polling when `waitForApproval: false` (the
|
|
180
|
+
* default). The endpoint is unauthenticated — pass the `requestId` that
|
|
181
|
+
* was returned from the 202 response.
|
|
182
|
+
*
|
|
183
|
+
* @returns `state: 'pending'` while awaiting; `'approved'` carries the
|
|
184
|
+
* minted agent in `agent`; `'denied'` may carry the owner's
|
|
185
|
+
* `reason`; `'expired'` is terminal after 14 days.
|
|
186
|
+
*/
|
|
187
|
+
async pollRegistration(requestId) {
|
|
188
|
+
const url = `${this.baseUrl}/api/agents/request-registration/${requestId}`;
|
|
189
|
+
const res = await fetch(url, { headers: { Accept: "application/json" } });
|
|
190
|
+
if (!res.ok) {
|
|
191
|
+
const errBody = await res.json().catch(() => ({}));
|
|
192
|
+
throw new AstraSyncError(
|
|
193
|
+
errBody.error || `pollRegistration failed: ${res.status}`,
|
|
194
|
+
res.status,
|
|
195
|
+
errBody.code
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
return await res.json();
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Block until a pending registration request resolves to a terminal state.
|
|
202
|
+
* Resolves to the live `AgentRecord` on approval; rejects with the matching
|
|
203
|
+
* Registration*Error on deny/expire/timeout. Usually called via
|
|
204
|
+
* `register({ waitForApproval: true })`, but exposed for callers that want
|
|
205
|
+
* to fire-and-forget the initial register call and resume waiting later
|
|
206
|
+
* (e.g. after restoring a stored `requestId` on cold start).
|
|
207
|
+
*/
|
|
208
|
+
async waitForApproval(requestId, options = {}) {
|
|
209
|
+
const timeoutMs = options.timeoutMs ?? 10 * 60 * 1e3;
|
|
210
|
+
const pollIntervalMs = options.pollIntervalMs ?? 5e3;
|
|
211
|
+
const start = Date.now();
|
|
212
|
+
const deadline = start + timeoutMs;
|
|
213
|
+
while (Date.now() < deadline) {
|
|
214
|
+
const result = await this.pollRegistration(requestId);
|
|
215
|
+
const ageMs = Date.now() - start;
|
|
216
|
+
options.onPending?.({ requestId, ageMs });
|
|
217
|
+
if (result.state === "approved") {
|
|
218
|
+
if (!result.agent) {
|
|
219
|
+
throw new AstraSyncError(
|
|
220
|
+
`Registration ${requestId} reported approved but no agent payload returned.`,
|
|
221
|
+
500
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
return result.agent;
|
|
225
|
+
}
|
|
226
|
+
if (result.state === "denied") {
|
|
227
|
+
throw new RegistrationDeniedError(requestId, result.reason);
|
|
228
|
+
}
|
|
229
|
+
if (result.state === "expired") {
|
|
230
|
+
throw new RegistrationExpiredError(requestId);
|
|
231
|
+
}
|
|
232
|
+
await sleep(pollIntervalMs);
|
|
233
|
+
}
|
|
234
|
+
throw new RegistrationTimeoutError(requestId);
|
|
94
235
|
}
|
|
95
236
|
/**
|
|
96
237
|
* Look up an agent's public profile by ASTRA ID or UUID.
|
|
@@ -110,6 +251,15 @@ var AstraSync = class {
|
|
|
110
251
|
}
|
|
111
252
|
// ── Private helpers ──────────────────────────────────────────────
|
|
112
253
|
async request(method, endpoint, body) {
|
|
254
|
+
const { body: parsed } = await this.requestWithStatus(method, endpoint, body);
|
|
255
|
+
return parsed;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Variant of {@link request} that also returns the HTTP status code, so
|
|
259
|
+
* callers can branch on 201 vs 202 (or other success codes) without losing
|
|
260
|
+
* type information about the response body.
|
|
261
|
+
*/
|
|
262
|
+
async requestWithStatus(method, endpoint, body) {
|
|
113
263
|
const url = `${this.baseUrl}${endpoint}`;
|
|
114
264
|
const headers = {
|
|
115
265
|
"Content-Type": "application/json"
|
|
@@ -136,7 +286,7 @@ var AstraSync = class {
|
|
|
136
286
|
errorBody.code
|
|
137
287
|
);
|
|
138
288
|
}
|
|
139
|
-
return res.json();
|
|
289
|
+
return { status: res.status, body: await res.json() };
|
|
140
290
|
}
|
|
141
291
|
async getAuthToken() {
|
|
142
292
|
if (this.apiKey) {
|
|
@@ -93,6 +93,12 @@ interface RegisterOptions {
|
|
|
93
93
|
name: string;
|
|
94
94
|
description?: string;
|
|
95
95
|
agentType?: string;
|
|
96
|
+
/**
|
|
97
|
+
* URL where your agent's verification-gateway SDK is mounted for runtime
|
|
98
|
+
* challenges. Optional — if omitted, your agent declares no runtime-challenge
|
|
99
|
+
* support and some counterparties may decline access requests. Mirrors the
|
|
100
|
+
* webUI "API endpoint" field.
|
|
101
|
+
*/
|
|
96
102
|
apiEndpoint?: string;
|
|
97
103
|
model?: ModelConfig;
|
|
98
104
|
framework?: FrameworkConfig;
|
|
@@ -101,7 +107,59 @@ interface RegisterOptions {
|
|
|
101
107
|
metadata?: Record<string, unknown>;
|
|
102
108
|
pdlss?: PDLSSConfig;
|
|
103
109
|
}
|
|
104
|
-
/**
|
|
110
|
+
/**
|
|
111
|
+
* Optional blocking-mode flags for `register()`. When `waitForApproval` is
|
|
112
|
+
* true and the backend returns 202 pending, the SDK polls until the request
|
|
113
|
+
* resolves (approved → returns Agent; denied/expired → throws; timeout →
|
|
114
|
+
* throws). The default is non-blocking: the SDK returns the pending result
|
|
115
|
+
* immediately and the caller handles polling itself.
|
|
116
|
+
*/
|
|
117
|
+
interface WaitForApprovalOptions {
|
|
118
|
+
/** Block until the request resolves. Default: false. */
|
|
119
|
+
waitForApproval?: boolean;
|
|
120
|
+
/** How long to wait in blocking mode. Default: 600_000ms (10 min). */
|
|
121
|
+
timeoutMs?: number;
|
|
122
|
+
/** Poll cadence in blocking mode. Default: 5000ms. */
|
|
123
|
+
pollIntervalMs?: number;
|
|
124
|
+
/** Called once per poll while still pending; useful for progress UX. */
|
|
125
|
+
onPending?: (event: {
|
|
126
|
+
requestId: string;
|
|
127
|
+
ageMs: number;
|
|
128
|
+
}) => void;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Discriminated registration result.
|
|
132
|
+
*
|
|
133
|
+
* - `active`: synchronous path (crypto-keypair signature verified, or
|
|
134
|
+
* email+password auth). `agent` is the live record.
|
|
135
|
+
* - `pending_approval`: API-key auth path. The owner has been notified by
|
|
136
|
+
* email and a dashboard alert. Poll `pollUrl` or call
|
|
137
|
+
* `sdk.pollRegistration(requestId)` to track progress, or re-call
|
|
138
|
+
* `register` with `waitForApproval: true` to block.
|
|
139
|
+
*/
|
|
140
|
+
type RegisterResult = {
|
|
141
|
+
status: 'active';
|
|
142
|
+
agent: AgentRecord;
|
|
143
|
+
} | {
|
|
144
|
+
status: 'pending_approval';
|
|
145
|
+
requestId: string;
|
|
146
|
+
expiresAt: string;
|
|
147
|
+
pollUrl: string;
|
|
148
|
+
message?: string;
|
|
149
|
+
};
|
|
150
|
+
/**
|
|
151
|
+
* Response shape from `pollRegistration(requestId)` and the internal poll
|
|
152
|
+
* loop. State `pending` means still awaiting owner; the others are terminal.
|
|
153
|
+
*/
|
|
154
|
+
interface PollRegistrationResult {
|
|
155
|
+
state: 'pending' | 'approved' | 'denied' | 'expired';
|
|
156
|
+
agent?: AgentRecord;
|
|
157
|
+
reason?: string;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Response from agent registration (raw 201 body). Use {@link RegisterResult}
|
|
161
|
+
* for the consumer-facing shape returned from `sdk.register()`.
|
|
162
|
+
*/
|
|
105
163
|
interface RegistrationResponse {
|
|
106
164
|
success: boolean;
|
|
107
165
|
message: string;
|
|
@@ -109,6 +167,15 @@ interface RegistrationResponse {
|
|
|
109
167
|
agent: AgentRecord;
|
|
110
168
|
};
|
|
111
169
|
}
|
|
170
|
+
/** Raw 202 body — internal type, exposed via {@link RegisterResult}. */
|
|
171
|
+
interface PendingRegistrationResponse {
|
|
172
|
+
success: true;
|
|
173
|
+
status: 'pending_approval';
|
|
174
|
+
requestId: string;
|
|
175
|
+
expiresAt: string;
|
|
176
|
+
pollUrl: string;
|
|
177
|
+
message?: string;
|
|
178
|
+
}
|
|
112
179
|
/** Agent record from the API. */
|
|
113
180
|
interface AgentRecord {
|
|
114
181
|
kyaAgentId: string;
|
|
@@ -175,9 +242,59 @@ declare class AstraSync {
|
|
|
175
242
|
constructor(config?: AstraSyncConfig);
|
|
176
243
|
/**
|
|
177
244
|
* Register a new AI agent on the AstraSync KYA Platform.
|
|
178
|
-
*
|
|
245
|
+
*
|
|
246
|
+
* The backend response depends on auth context:
|
|
247
|
+
* - **Crypto-keypair signed** (`privateKey` configured): synchronous 201,
|
|
248
|
+
* returns `{ status: 'active', agent }`.
|
|
249
|
+
* - **API-key only** (no signature): 202 pending, returns
|
|
250
|
+
* `{ status: 'pending_approval', requestId, pollUrl, expiresAt }`. The
|
|
251
|
+
* owner is notified by email and a dashboard alert is emitted; the agent
|
|
252
|
+
* becomes active only after the owner approves.
|
|
253
|
+
*
|
|
254
|
+
* Blocking mode: pass `{ waitForApproval: true }` to have the SDK poll the
|
|
255
|
+
* request until it resolves, then return the live agent record. The promise
|
|
256
|
+
* rejects with `RegistrationDeniedError`, `RegistrationExpiredError`, or
|
|
257
|
+
* `RegistrationTimeoutError` on the corresponding terminal states.
|
|
258
|
+
*
|
|
259
|
+
* @example Non-blocking (default — best for serverless / scheduled agents):
|
|
260
|
+
* ```typescript
|
|
261
|
+
* const result = await sdk.register({ name, pdlss });
|
|
262
|
+
* if (result.status === 'pending_approval') {
|
|
263
|
+
* storeRequestId(result.requestId);
|
|
264
|
+
* return; // function exits; resume later via pollRegistration()
|
|
265
|
+
* }
|
|
266
|
+
* ```
|
|
267
|
+
*
|
|
268
|
+
* @example Blocking (best for long-running services + CLI):
|
|
269
|
+
* ```typescript
|
|
270
|
+
* const agent = await sdk.register({
|
|
271
|
+
* name, pdlss, waitForApproval: true, timeoutMs: 600_000,
|
|
272
|
+
* onPending: ({ ageMs }) => console.log(`waiting ${ageMs}ms`),
|
|
273
|
+
* });
|
|
274
|
+
* ```
|
|
179
275
|
*/
|
|
180
|
-
register(options: RegisterOptions): Promise<
|
|
276
|
+
register(options: RegisterOptions & WaitForApprovalOptions): Promise<RegisterResult | AgentRecord>;
|
|
277
|
+
/**
|
|
278
|
+
* Poll the current state of a pending-approval registration request.
|
|
279
|
+
*
|
|
280
|
+
* Useful for caller-driven polling when `waitForApproval: false` (the
|
|
281
|
+
* default). The endpoint is unauthenticated — pass the `requestId` that
|
|
282
|
+
* was returned from the 202 response.
|
|
283
|
+
*
|
|
284
|
+
* @returns `state: 'pending'` while awaiting; `'approved'` carries the
|
|
285
|
+
* minted agent in `agent`; `'denied'` may carry the owner's
|
|
286
|
+
* `reason`; `'expired'` is terminal after 14 days.
|
|
287
|
+
*/
|
|
288
|
+
pollRegistration(requestId: string): Promise<PollRegistrationResult>;
|
|
289
|
+
/**
|
|
290
|
+
* Block until a pending registration request resolves to a terminal state.
|
|
291
|
+
* Resolves to the live `AgentRecord` on approval; rejects with the matching
|
|
292
|
+
* Registration*Error on deny/expire/timeout. Usually called via
|
|
293
|
+
* `register({ waitForApproval: true })`, but exposed for callers that want
|
|
294
|
+
* to fire-and-forget the initial register call and resume waiting later
|
|
295
|
+
* (e.g. after restoring a stored `requestId` on cold start).
|
|
296
|
+
*/
|
|
297
|
+
waitForApproval(requestId: string, options?: WaitForApprovalOptions): Promise<AgentRecord>;
|
|
181
298
|
/**
|
|
182
299
|
* Look up an agent's public profile by ASTRA ID or UUID.
|
|
183
300
|
*/
|
|
@@ -187,6 +304,12 @@ declare class AstraSync {
|
|
|
187
304
|
*/
|
|
188
305
|
health(): Promise<HealthResponse>;
|
|
189
306
|
private request;
|
|
307
|
+
/**
|
|
308
|
+
* Variant of {@link request} that also returns the HTTP status code, so
|
|
309
|
+
* callers can branch on 201 vs 202 (or other success codes) without losing
|
|
310
|
+
* type information about the response body.
|
|
311
|
+
*/
|
|
312
|
+
private requestWithStatus;
|
|
190
313
|
private getAuthToken;
|
|
191
314
|
/**
|
|
192
315
|
* Sign a request using secp256k1 (ethers.js).
|
|
@@ -214,5 +337,33 @@ declare class KYDRequiredError extends AstraSyncError {
|
|
|
214
337
|
declare class AuthenticationError extends AstraSyncError {
|
|
215
338
|
constructor(message: string);
|
|
216
339
|
}
|
|
340
|
+
/**
|
|
341
|
+
* Thrown by `register({ waitForApproval: true })` when the owner denies the
|
|
342
|
+
* pending registration request. The `reason` field, when present, mirrors the
|
|
343
|
+
* deny note the owner left in the dashboard.
|
|
344
|
+
*/
|
|
345
|
+
declare class RegistrationDeniedError extends AstraSyncError {
|
|
346
|
+
readonly requestId: string;
|
|
347
|
+
readonly reason?: string;
|
|
348
|
+
constructor(requestId: string, reason?: string);
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Thrown by `register({ waitForApproval: true })` when the pending request
|
|
352
|
+
* passes its 14-day TTL with no owner decision. The agent must re-submit.
|
|
353
|
+
*/
|
|
354
|
+
declare class RegistrationExpiredError extends AstraSyncError {
|
|
355
|
+
readonly requestId: string;
|
|
356
|
+
constructor(requestId: string);
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Thrown by `register({ waitForApproval: true })` when the caller's local
|
|
360
|
+
* `timeoutMs` elapses before the owner makes a decision. The request is still
|
|
361
|
+
* live server-side — poll `pollRegistration(requestId)` to resume waiting, or
|
|
362
|
+
* call `waitForApproval` again with a longer timeout.
|
|
363
|
+
*/
|
|
364
|
+
declare class RegistrationTimeoutError extends AstraSyncError {
|
|
365
|
+
readonly requestId: string;
|
|
366
|
+
constructor(requestId: string);
|
|
367
|
+
}
|
|
217
368
|
|
|
218
|
-
export { type AgentProtocol, type AgentRecord, AstraSync, type AstraSyncConfig, AstraSyncError, AuthenticationError, type FrameworkConfig, type HealthResponse, KYDRequiredError, type ModelConfig, type PDLSSConfig, type PDLSSDuration, type PDLSSLimits, type PDLSSPurpose, type PDLSSScope, type PDLSSSelfInstantiation, type RegisterOptions, type RegistrationResponse, type VerifyResponse };
|
|
369
|
+
export { type AgentProtocol, type AgentRecord, AstraSync, type AstraSyncConfig, AstraSyncError, AuthenticationError, type FrameworkConfig, type HealthResponse, KYDRequiredError, type ModelConfig, type PDLSSConfig, type PDLSSDuration, type PDLSSLimits, type PDLSSPurpose, type PDLSSScope, type PDLSSSelfInstantiation, type PendingRegistrationResponse, type PollRegistrationResult, type RegisterOptions, type RegisterResult, RegistrationDeniedError, RegistrationExpiredError, type RegistrationResponse, RegistrationTimeoutError, type VerifyResponse, type WaitForApprovalOptions };
|
|
@@ -93,6 +93,12 @@ interface RegisterOptions {
|
|
|
93
93
|
name: string;
|
|
94
94
|
description?: string;
|
|
95
95
|
agentType?: string;
|
|
96
|
+
/**
|
|
97
|
+
* URL where your agent's verification-gateway SDK is mounted for runtime
|
|
98
|
+
* challenges. Optional — if omitted, your agent declares no runtime-challenge
|
|
99
|
+
* support and some counterparties may decline access requests. Mirrors the
|
|
100
|
+
* webUI "API endpoint" field.
|
|
101
|
+
*/
|
|
96
102
|
apiEndpoint?: string;
|
|
97
103
|
model?: ModelConfig;
|
|
98
104
|
framework?: FrameworkConfig;
|
|
@@ -101,7 +107,59 @@ interface RegisterOptions {
|
|
|
101
107
|
metadata?: Record<string, unknown>;
|
|
102
108
|
pdlss?: PDLSSConfig;
|
|
103
109
|
}
|
|
104
|
-
/**
|
|
110
|
+
/**
|
|
111
|
+
* Optional blocking-mode flags for `register()`. When `waitForApproval` is
|
|
112
|
+
* true and the backend returns 202 pending, the SDK polls until the request
|
|
113
|
+
* resolves (approved → returns Agent; denied/expired → throws; timeout →
|
|
114
|
+
* throws). The default is non-blocking: the SDK returns the pending result
|
|
115
|
+
* immediately and the caller handles polling itself.
|
|
116
|
+
*/
|
|
117
|
+
interface WaitForApprovalOptions {
|
|
118
|
+
/** Block until the request resolves. Default: false. */
|
|
119
|
+
waitForApproval?: boolean;
|
|
120
|
+
/** How long to wait in blocking mode. Default: 600_000ms (10 min). */
|
|
121
|
+
timeoutMs?: number;
|
|
122
|
+
/** Poll cadence in blocking mode. Default: 5000ms. */
|
|
123
|
+
pollIntervalMs?: number;
|
|
124
|
+
/** Called once per poll while still pending; useful for progress UX. */
|
|
125
|
+
onPending?: (event: {
|
|
126
|
+
requestId: string;
|
|
127
|
+
ageMs: number;
|
|
128
|
+
}) => void;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Discriminated registration result.
|
|
132
|
+
*
|
|
133
|
+
* - `active`: synchronous path (crypto-keypair signature verified, or
|
|
134
|
+
* email+password auth). `agent` is the live record.
|
|
135
|
+
* - `pending_approval`: API-key auth path. The owner has been notified by
|
|
136
|
+
* email and a dashboard alert. Poll `pollUrl` or call
|
|
137
|
+
* `sdk.pollRegistration(requestId)` to track progress, or re-call
|
|
138
|
+
* `register` with `waitForApproval: true` to block.
|
|
139
|
+
*/
|
|
140
|
+
type RegisterResult = {
|
|
141
|
+
status: 'active';
|
|
142
|
+
agent: AgentRecord;
|
|
143
|
+
} | {
|
|
144
|
+
status: 'pending_approval';
|
|
145
|
+
requestId: string;
|
|
146
|
+
expiresAt: string;
|
|
147
|
+
pollUrl: string;
|
|
148
|
+
message?: string;
|
|
149
|
+
};
|
|
150
|
+
/**
|
|
151
|
+
* Response shape from `pollRegistration(requestId)` and the internal poll
|
|
152
|
+
* loop. State `pending` means still awaiting owner; the others are terminal.
|
|
153
|
+
*/
|
|
154
|
+
interface PollRegistrationResult {
|
|
155
|
+
state: 'pending' | 'approved' | 'denied' | 'expired';
|
|
156
|
+
agent?: AgentRecord;
|
|
157
|
+
reason?: string;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Response from agent registration (raw 201 body). Use {@link RegisterResult}
|
|
161
|
+
* for the consumer-facing shape returned from `sdk.register()`.
|
|
162
|
+
*/
|
|
105
163
|
interface RegistrationResponse {
|
|
106
164
|
success: boolean;
|
|
107
165
|
message: string;
|
|
@@ -109,6 +167,15 @@ interface RegistrationResponse {
|
|
|
109
167
|
agent: AgentRecord;
|
|
110
168
|
};
|
|
111
169
|
}
|
|
170
|
+
/** Raw 202 body — internal type, exposed via {@link RegisterResult}. */
|
|
171
|
+
interface PendingRegistrationResponse {
|
|
172
|
+
success: true;
|
|
173
|
+
status: 'pending_approval';
|
|
174
|
+
requestId: string;
|
|
175
|
+
expiresAt: string;
|
|
176
|
+
pollUrl: string;
|
|
177
|
+
message?: string;
|
|
178
|
+
}
|
|
112
179
|
/** Agent record from the API. */
|
|
113
180
|
interface AgentRecord {
|
|
114
181
|
kyaAgentId: string;
|
|
@@ -175,9 +242,59 @@ declare class AstraSync {
|
|
|
175
242
|
constructor(config?: AstraSyncConfig);
|
|
176
243
|
/**
|
|
177
244
|
* Register a new AI agent on the AstraSync KYA Platform.
|
|
178
|
-
*
|
|
245
|
+
*
|
|
246
|
+
* The backend response depends on auth context:
|
|
247
|
+
* - **Crypto-keypair signed** (`privateKey` configured): synchronous 201,
|
|
248
|
+
* returns `{ status: 'active', agent }`.
|
|
249
|
+
* - **API-key only** (no signature): 202 pending, returns
|
|
250
|
+
* `{ status: 'pending_approval', requestId, pollUrl, expiresAt }`. The
|
|
251
|
+
* owner is notified by email and a dashboard alert is emitted; the agent
|
|
252
|
+
* becomes active only after the owner approves.
|
|
253
|
+
*
|
|
254
|
+
* Blocking mode: pass `{ waitForApproval: true }` to have the SDK poll the
|
|
255
|
+
* request until it resolves, then return the live agent record. The promise
|
|
256
|
+
* rejects with `RegistrationDeniedError`, `RegistrationExpiredError`, or
|
|
257
|
+
* `RegistrationTimeoutError` on the corresponding terminal states.
|
|
258
|
+
*
|
|
259
|
+
* @example Non-blocking (default — best for serverless / scheduled agents):
|
|
260
|
+
* ```typescript
|
|
261
|
+
* const result = await sdk.register({ name, pdlss });
|
|
262
|
+
* if (result.status === 'pending_approval') {
|
|
263
|
+
* storeRequestId(result.requestId);
|
|
264
|
+
* return; // function exits; resume later via pollRegistration()
|
|
265
|
+
* }
|
|
266
|
+
* ```
|
|
267
|
+
*
|
|
268
|
+
* @example Blocking (best for long-running services + CLI):
|
|
269
|
+
* ```typescript
|
|
270
|
+
* const agent = await sdk.register({
|
|
271
|
+
* name, pdlss, waitForApproval: true, timeoutMs: 600_000,
|
|
272
|
+
* onPending: ({ ageMs }) => console.log(`waiting ${ageMs}ms`),
|
|
273
|
+
* });
|
|
274
|
+
* ```
|
|
179
275
|
*/
|
|
180
|
-
register(options: RegisterOptions): Promise<
|
|
276
|
+
register(options: RegisterOptions & WaitForApprovalOptions): Promise<RegisterResult | AgentRecord>;
|
|
277
|
+
/**
|
|
278
|
+
* Poll the current state of a pending-approval registration request.
|
|
279
|
+
*
|
|
280
|
+
* Useful for caller-driven polling when `waitForApproval: false` (the
|
|
281
|
+
* default). The endpoint is unauthenticated — pass the `requestId` that
|
|
282
|
+
* was returned from the 202 response.
|
|
283
|
+
*
|
|
284
|
+
* @returns `state: 'pending'` while awaiting; `'approved'` carries the
|
|
285
|
+
* minted agent in `agent`; `'denied'` may carry the owner's
|
|
286
|
+
* `reason`; `'expired'` is terminal after 14 days.
|
|
287
|
+
*/
|
|
288
|
+
pollRegistration(requestId: string): Promise<PollRegistrationResult>;
|
|
289
|
+
/**
|
|
290
|
+
* Block until a pending registration request resolves to a terminal state.
|
|
291
|
+
* Resolves to the live `AgentRecord` on approval; rejects with the matching
|
|
292
|
+
* Registration*Error on deny/expire/timeout. Usually called via
|
|
293
|
+
* `register({ waitForApproval: true })`, but exposed for callers that want
|
|
294
|
+
* to fire-and-forget the initial register call and resume waiting later
|
|
295
|
+
* (e.g. after restoring a stored `requestId` on cold start).
|
|
296
|
+
*/
|
|
297
|
+
waitForApproval(requestId: string, options?: WaitForApprovalOptions): Promise<AgentRecord>;
|
|
181
298
|
/**
|
|
182
299
|
* Look up an agent's public profile by ASTRA ID or UUID.
|
|
183
300
|
*/
|
|
@@ -187,6 +304,12 @@ declare class AstraSync {
|
|
|
187
304
|
*/
|
|
188
305
|
health(): Promise<HealthResponse>;
|
|
189
306
|
private request;
|
|
307
|
+
/**
|
|
308
|
+
* Variant of {@link request} that also returns the HTTP status code, so
|
|
309
|
+
* callers can branch on 201 vs 202 (or other success codes) without losing
|
|
310
|
+
* type information about the response body.
|
|
311
|
+
*/
|
|
312
|
+
private requestWithStatus;
|
|
190
313
|
private getAuthToken;
|
|
191
314
|
/**
|
|
192
315
|
* Sign a request using secp256k1 (ethers.js).
|
|
@@ -214,5 +337,33 @@ declare class KYDRequiredError extends AstraSyncError {
|
|
|
214
337
|
declare class AuthenticationError extends AstraSyncError {
|
|
215
338
|
constructor(message: string);
|
|
216
339
|
}
|
|
340
|
+
/**
|
|
341
|
+
* Thrown by `register({ waitForApproval: true })` when the owner denies the
|
|
342
|
+
* pending registration request. The `reason` field, when present, mirrors the
|
|
343
|
+
* deny note the owner left in the dashboard.
|
|
344
|
+
*/
|
|
345
|
+
declare class RegistrationDeniedError extends AstraSyncError {
|
|
346
|
+
readonly requestId: string;
|
|
347
|
+
readonly reason?: string;
|
|
348
|
+
constructor(requestId: string, reason?: string);
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Thrown by `register({ waitForApproval: true })` when the pending request
|
|
352
|
+
* passes its 14-day TTL with no owner decision. The agent must re-submit.
|
|
353
|
+
*/
|
|
354
|
+
declare class RegistrationExpiredError extends AstraSyncError {
|
|
355
|
+
readonly requestId: string;
|
|
356
|
+
constructor(requestId: string);
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Thrown by `register({ waitForApproval: true })` when the caller's local
|
|
360
|
+
* `timeoutMs` elapses before the owner makes a decision. The request is still
|
|
361
|
+
* live server-side — poll `pollRegistration(requestId)` to resume waiting, or
|
|
362
|
+
* call `waitForApproval` again with a longer timeout.
|
|
363
|
+
*/
|
|
364
|
+
declare class RegistrationTimeoutError extends AstraSyncError {
|
|
365
|
+
readonly requestId: string;
|
|
366
|
+
constructor(requestId: string);
|
|
367
|
+
}
|
|
217
368
|
|
|
218
|
-
export { type AgentProtocol, type AgentRecord, AstraSync, type AstraSyncConfig, AstraSyncError, AuthenticationError, type FrameworkConfig, type HealthResponse, KYDRequiredError, type ModelConfig, type PDLSSConfig, type PDLSSDuration, type PDLSSLimits, type PDLSSPurpose, type PDLSSScope, type PDLSSSelfInstantiation, type RegisterOptions, type RegistrationResponse, type VerifyResponse };
|
|
369
|
+
export { type AgentProtocol, type AgentRecord, AstraSync, type AstraSyncConfig, AstraSyncError, AuthenticationError, type FrameworkConfig, type HealthResponse, KYDRequiredError, type ModelConfig, type PDLSSConfig, type PDLSSDuration, type PDLSSLimits, type PDLSSPurpose, type PDLSSScope, type PDLSSSelfInstantiation, type PendingRegistrationResponse, type PollRegistrationResult, type RegisterOptions, type RegisterResult, RegistrationDeniedError, RegistrationExpiredError, type RegistrationResponse, RegistrationTimeoutError, type VerifyResponse, type WaitForApprovalOptions };
|
|
@@ -33,7 +33,10 @@ __export(registration_exports, {
|
|
|
33
33
|
AstraSync: () => AstraSync,
|
|
34
34
|
AstraSyncError: () => AstraSyncError,
|
|
35
35
|
AuthenticationError: () => AuthenticationError,
|
|
36
|
-
KYDRequiredError: () => KYDRequiredError
|
|
36
|
+
KYDRequiredError: () => KYDRequiredError,
|
|
37
|
+
RegistrationDeniedError: () => RegistrationDeniedError,
|
|
38
|
+
RegistrationExpiredError: () => RegistrationExpiredError,
|
|
39
|
+
RegistrationTimeoutError: () => RegistrationTimeoutError
|
|
37
40
|
});
|
|
38
41
|
module.exports = __toCommonJS(registration_exports);
|
|
39
42
|
|
|
@@ -66,9 +69,44 @@ var AuthenticationError = class extends AstraSyncError {
|
|
|
66
69
|
this.name = "AuthenticationError";
|
|
67
70
|
}
|
|
68
71
|
};
|
|
72
|
+
var RegistrationDeniedError = class extends AstraSyncError {
|
|
73
|
+
constructor(requestId, reason) {
|
|
74
|
+
super(
|
|
75
|
+
`Registration request ${requestId} was denied by the account owner.${reason ? ` Reason: ${reason}` : ""}`,
|
|
76
|
+
403,
|
|
77
|
+
"REGISTRATION_DENIED"
|
|
78
|
+
);
|
|
79
|
+
this.name = "RegistrationDeniedError";
|
|
80
|
+
this.requestId = requestId;
|
|
81
|
+
this.reason = reason;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
var RegistrationExpiredError = class extends AstraSyncError {
|
|
85
|
+
constructor(requestId) {
|
|
86
|
+
super(
|
|
87
|
+
`Registration request ${requestId} expired before the owner approved it. Submit a new registration request.`,
|
|
88
|
+
410,
|
|
89
|
+
"REGISTRATION_EXPIRED"
|
|
90
|
+
);
|
|
91
|
+
this.name = "RegistrationExpiredError";
|
|
92
|
+
this.requestId = requestId;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
var RegistrationTimeoutError = class extends AstraSyncError {
|
|
96
|
+
constructor(requestId) {
|
|
97
|
+
super(
|
|
98
|
+
`Timed out waiting for owner approval of registration request ${requestId}. The request is still active server-side; poll the request to resume waiting.`,
|
|
99
|
+
408,
|
|
100
|
+
"REGISTRATION_TIMEOUT"
|
|
101
|
+
);
|
|
102
|
+
this.name = "RegistrationTimeoutError";
|
|
103
|
+
this.requestId = requestId;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
69
106
|
|
|
70
107
|
// src/registration/api.ts
|
|
71
108
|
var DEFAULT_BASE_URL = "https://astrasync.ai";
|
|
109
|
+
var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
72
110
|
var AstraSync = class {
|
|
73
111
|
constructor(config = {}) {
|
|
74
112
|
this.baseUrl = (config.baseUrl || process.env.ASTRASYNC_API_URL || DEFAULT_BASE_URL).replace(
|
|
@@ -90,7 +128,36 @@ var AstraSync = class {
|
|
|
90
128
|
}
|
|
91
129
|
/**
|
|
92
130
|
* Register a new AI agent on the AstraSync KYA Platform.
|
|
93
|
-
*
|
|
131
|
+
*
|
|
132
|
+
* The backend response depends on auth context:
|
|
133
|
+
* - **Crypto-keypair signed** (`privateKey` configured): synchronous 201,
|
|
134
|
+
* returns `{ status: 'active', agent }`.
|
|
135
|
+
* - **API-key only** (no signature): 202 pending, returns
|
|
136
|
+
* `{ status: 'pending_approval', requestId, pollUrl, expiresAt }`. The
|
|
137
|
+
* owner is notified by email and a dashboard alert is emitted; the agent
|
|
138
|
+
* becomes active only after the owner approves.
|
|
139
|
+
*
|
|
140
|
+
* Blocking mode: pass `{ waitForApproval: true }` to have the SDK poll the
|
|
141
|
+
* request until it resolves, then return the live agent record. The promise
|
|
142
|
+
* rejects with `RegistrationDeniedError`, `RegistrationExpiredError`, or
|
|
143
|
+
* `RegistrationTimeoutError` on the corresponding terminal states.
|
|
144
|
+
*
|
|
145
|
+
* @example Non-blocking (default — best for serverless / scheduled agents):
|
|
146
|
+
* ```typescript
|
|
147
|
+
* const result = await sdk.register({ name, pdlss });
|
|
148
|
+
* if (result.status === 'pending_approval') {
|
|
149
|
+
* storeRequestId(result.requestId);
|
|
150
|
+
* return; // function exits; resume later via pollRegistration()
|
|
151
|
+
* }
|
|
152
|
+
* ```
|
|
153
|
+
*
|
|
154
|
+
* @example Blocking (best for long-running services + CLI):
|
|
155
|
+
* ```typescript
|
|
156
|
+
* const agent = await sdk.register({
|
|
157
|
+
* name, pdlss, waitForApproval: true, timeoutMs: 600_000,
|
|
158
|
+
* onPending: ({ ageMs }) => console.log(`waiting ${ageMs}ms`),
|
|
159
|
+
* });
|
|
160
|
+
* ```
|
|
94
161
|
*/
|
|
95
162
|
async register(options) {
|
|
96
163
|
const body = {
|
|
@@ -104,7 +171,84 @@ var AstraSync = class {
|
|
|
104
171
|
...options.metadata && { metadata: options.metadata },
|
|
105
172
|
...options.pdlss && { pdlss: options.pdlss }
|
|
106
173
|
};
|
|
107
|
-
|
|
174
|
+
const { status, body: raw } = await this.requestWithStatus("POST", "/api/agents/register", body);
|
|
175
|
+
if (status === 201) {
|
|
176
|
+
const active = {
|
|
177
|
+
status: "active",
|
|
178
|
+
agent: raw.data.agent
|
|
179
|
+
};
|
|
180
|
+
return active;
|
|
181
|
+
}
|
|
182
|
+
const pendingBody = raw;
|
|
183
|
+
const pending = {
|
|
184
|
+
status: "pending_approval",
|
|
185
|
+
requestId: pendingBody.requestId,
|
|
186
|
+
expiresAt: pendingBody.expiresAt,
|
|
187
|
+
pollUrl: pendingBody.pollUrl,
|
|
188
|
+
message: pendingBody.message
|
|
189
|
+
};
|
|
190
|
+
if (!options.waitForApproval) return pending;
|
|
191
|
+
return this.waitForApproval(pendingBody.requestId, options);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Poll the current state of a pending-approval registration request.
|
|
195
|
+
*
|
|
196
|
+
* Useful for caller-driven polling when `waitForApproval: false` (the
|
|
197
|
+
* default). The endpoint is unauthenticated — pass the `requestId` that
|
|
198
|
+
* was returned from the 202 response.
|
|
199
|
+
*
|
|
200
|
+
* @returns `state: 'pending'` while awaiting; `'approved'` carries the
|
|
201
|
+
* minted agent in `agent`; `'denied'` may carry the owner's
|
|
202
|
+
* `reason`; `'expired'` is terminal after 14 days.
|
|
203
|
+
*/
|
|
204
|
+
async pollRegistration(requestId) {
|
|
205
|
+
const url = `${this.baseUrl}/api/agents/request-registration/${requestId}`;
|
|
206
|
+
const res = await fetch(url, { headers: { Accept: "application/json" } });
|
|
207
|
+
if (!res.ok) {
|
|
208
|
+
const errBody = await res.json().catch(() => ({}));
|
|
209
|
+
throw new AstraSyncError(
|
|
210
|
+
errBody.error || `pollRegistration failed: ${res.status}`,
|
|
211
|
+
res.status,
|
|
212
|
+
errBody.code
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
return await res.json();
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Block until a pending registration request resolves to a terminal state.
|
|
219
|
+
* Resolves to the live `AgentRecord` on approval; rejects with the matching
|
|
220
|
+
* Registration*Error on deny/expire/timeout. Usually called via
|
|
221
|
+
* `register({ waitForApproval: true })`, but exposed for callers that want
|
|
222
|
+
* to fire-and-forget the initial register call and resume waiting later
|
|
223
|
+
* (e.g. after restoring a stored `requestId` on cold start).
|
|
224
|
+
*/
|
|
225
|
+
async waitForApproval(requestId, options = {}) {
|
|
226
|
+
const timeoutMs = options.timeoutMs ?? 10 * 60 * 1e3;
|
|
227
|
+
const pollIntervalMs = options.pollIntervalMs ?? 5e3;
|
|
228
|
+
const start = Date.now();
|
|
229
|
+
const deadline = start + timeoutMs;
|
|
230
|
+
while (Date.now() < deadline) {
|
|
231
|
+
const result = await this.pollRegistration(requestId);
|
|
232
|
+
const ageMs = Date.now() - start;
|
|
233
|
+
options.onPending?.({ requestId, ageMs });
|
|
234
|
+
if (result.state === "approved") {
|
|
235
|
+
if (!result.agent) {
|
|
236
|
+
throw new AstraSyncError(
|
|
237
|
+
`Registration ${requestId} reported approved but no agent payload returned.`,
|
|
238
|
+
500
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
return result.agent;
|
|
242
|
+
}
|
|
243
|
+
if (result.state === "denied") {
|
|
244
|
+
throw new RegistrationDeniedError(requestId, result.reason);
|
|
245
|
+
}
|
|
246
|
+
if (result.state === "expired") {
|
|
247
|
+
throw new RegistrationExpiredError(requestId);
|
|
248
|
+
}
|
|
249
|
+
await sleep(pollIntervalMs);
|
|
250
|
+
}
|
|
251
|
+
throw new RegistrationTimeoutError(requestId);
|
|
108
252
|
}
|
|
109
253
|
/**
|
|
110
254
|
* Look up an agent's public profile by ASTRA ID or UUID.
|
|
@@ -124,6 +268,15 @@ var AstraSync = class {
|
|
|
124
268
|
}
|
|
125
269
|
// ── Private helpers ──────────────────────────────────────────────
|
|
126
270
|
async request(method, endpoint, body) {
|
|
271
|
+
const { body: parsed } = await this.requestWithStatus(method, endpoint, body);
|
|
272
|
+
return parsed;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Variant of {@link request} that also returns the HTTP status code, so
|
|
276
|
+
* callers can branch on 201 vs 202 (or other success codes) without losing
|
|
277
|
+
* type information about the response body.
|
|
278
|
+
*/
|
|
279
|
+
async requestWithStatus(method, endpoint, body) {
|
|
127
280
|
const url = `${this.baseUrl}${endpoint}`;
|
|
128
281
|
const headers = {
|
|
129
282
|
"Content-Type": "application/json"
|
|
@@ -150,7 +303,7 @@ var AstraSync = class {
|
|
|
150
303
|
errorBody.code
|
|
151
304
|
);
|
|
152
305
|
}
|
|
153
|
-
return res.json();
|
|
306
|
+
return { status: res.status, body: await res.json() };
|
|
154
307
|
}
|
|
155
308
|
async getAuthToken() {
|
|
156
309
|
if (this.apiKey) {
|
|
@@ -207,6 +360,9 @@ var AstraSync = class {
|
|
|
207
360
|
AstraSync,
|
|
208
361
|
AstraSyncError,
|
|
209
362
|
AuthenticationError,
|
|
210
|
-
KYDRequiredError
|
|
363
|
+
KYDRequiredError,
|
|
364
|
+
RegistrationDeniedError,
|
|
365
|
+
RegistrationExpiredError,
|
|
366
|
+
RegistrationTimeoutError
|
|
211
367
|
});
|
|
212
368
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/registration/index.ts","../../src/registration/errors.ts","../../src/registration/api.ts"],"sourcesContent":["export { AstraSync } from './api';\nexport { AstraSyncError, KYDRequiredError, AuthenticationError } from './errors';\nexport type {\n AstraSyncConfig,\n RegisterOptions,\n RegistrationResponse,\n AgentRecord,\n VerifyResponse,\n HealthResponse,\n PDLSSConfig,\n PDLSSPurpose,\n PDLSSDuration,\n PDLSSLimits,\n PDLSSScope,\n PDLSSSelfInstantiation,\n ModelConfig,\n FrameworkConfig,\n AgentProtocol,\n} from './types';\n","import type { ApiErrorResponse } from './types';\n\n/** Base error class for AstraSync SDK errors. */\nexport class AstraSyncError extends Error {\n public readonly code?: string;\n public readonly statusCode: number;\n\n constructor(message: string, statusCode: number, code?: string) {\n super(message);\n this.name = 'AstraSyncError';\n this.statusCode = statusCode;\n this.code = code;\n }\n}\n\n/** Thrown when KYD verification is required before agent registration. */\nexport class KYDRequiredError extends AstraSyncError {\n public readonly kydUrl: string;\n public readonly ownerNotified: boolean;\n\n constructor(response: ApiErrorResponse) {\n const kydUrl = response.kydUrl || 'https://astrasync.ai/developer-profile';\n super(\n `KYD verification required before registering agents.\\nComplete your KYD profile at: ${kydUrl}`,\n 403,\n 'KYD_REQUIRED'\n );\n this.name = 'KYDRequiredError';\n this.kydUrl = kydUrl;\n this.ownerNotified = response.ownerNotified || false;\n }\n}\n\n/** Thrown when authentication fails. */\nexport class AuthenticationError extends AstraSyncError {\n constructor(message: string) {\n super(message, 401, 'AUTH_FAILED');\n this.name = 'AuthenticationError';\n }\n}\n","import type {\n AstraSyncConfig,\n RegisterOptions,\n RegistrationResponse,\n VerifyResponse,\n HealthResponse,\n ApiErrorResponse,\n} from './types';\nimport { AstraSyncError, KYDRequiredError, AuthenticationError } from './errors';\n\nconst DEFAULT_BASE_URL = 'https://astrasync.ai';\n\n/**\n * AstraSync SDK client for registering and managing AI agents.\n *\n * @example\n * ```typescript\n * const client = new AstraSync({ apiKey: 'kya_your_api_key' });\n * const result = await client.register({\n * name: 'My Agent',\n * model: { modelName: 'gpt-4o', modelProvider: 'openai', modelType: 'llm' },\n * });\n * ```\n *\n * For staging, pass `baseUrl: 'https://staging.astrasync.ai'`.\n */\nexport class AstraSync {\n private readonly baseUrl: string;\n private readonly apiKey?: string;\n private readonly email?: string;\n private readonly password?: string;\n private readonly privateKey?: string;\n private cachedJwt?: string;\n private jwtExpiresAt?: number;\n\n constructor(config: AstraSyncConfig = {}) {\n this.baseUrl = (config.baseUrl || process.env.ASTRASYNC_API_URL || DEFAULT_BASE_URL).replace(\n /\\/+$/,\n ''\n );\n\n this.apiKey = config.apiKey || process.env.ASTRASYNC_API_KEY;\n this.email = config.email;\n this.password = config.password;\n this.privateKey = config.privateKey;\n\n if (!this.apiKey && !this.email) {\n throw new AuthenticationError(\n 'Authentication required. Provide apiKey, or email+password. ' +\n 'Set ASTRASYNC_API_KEY env var or pass config to constructor.'\n );\n }\n\n if (this.email && !this.password) {\n throw new AuthenticationError('Password is required when using email authentication.');\n }\n }\n\n /**\n * Register a new AI agent on the AstraSync KYA Platform.\n * Sends full payload including model, framework, PDLSS, and metadata.\n */\n async register(options: RegisterOptions): Promise<RegistrationResponse> {\n const body: Record<string, unknown> = {\n name: options.name,\n ...(options.description && { description: options.description }),\n ...(options.agentType && { agentType: options.agentType }),\n ...(options.apiEndpoint && { apiEndpoint: options.apiEndpoint }),\n ...(options.model && { model: options.model }),\n ...(options.framework && { framework: options.framework }),\n ...(options.protocols && { protocols: options.protocols }),\n ...(options.metadata && { metadata: options.metadata }),\n ...(options.pdlss && { pdlss: options.pdlss }),\n };\n\n return this.request<RegistrationResponse>('POST', '/api/agents/register', body);\n }\n\n /**\n * Look up an agent's public profile by ASTRA ID or UUID.\n */\n async verify(agentId: string): Promise<VerifyResponse> {\n return this.request<VerifyResponse>('GET', `/api/agents/verify/${agentId}`);\n }\n\n /**\n * Check API health.\n */\n async health(): Promise<HealthResponse> {\n const res = await fetch(`${this.baseUrl}/api/health/`);\n if (!res.ok) {\n throw new AstraSyncError(`Health check failed: ${res.status}`, res.status);\n }\n return res.json() as Promise<HealthResponse>;\n }\n\n // ── Private helpers ──────────────────────────────────────────────\n\n private async request<T>(method: string, endpoint: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}${endpoint}`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n // Set auth header\n const token = await this.getAuthToken();\n headers['Authorization'] = `Bearer ${token}`;\n\n // Sign request if private key is configured\n if (this.privateKey) {\n const signature = await this.signRequest(method, endpoint, body || {});\n headers['X-AstraSync-Signature'] = signature;\n }\n\n const res = await fetch(url, {\n method,\n headers,\n ...(body ? { body: JSON.stringify(body) } : {}),\n });\n\n if (!res.ok) {\n const errorBody = (await res\n .json()\n .catch(() => ({ error: res.statusText }))) as ApiErrorResponse;\n\n // Handle KYD_REQUIRED specifically\n if (res.status === 403 && errorBody.code === 'KYD_REQUIRED') {\n throw new KYDRequiredError(errorBody);\n }\n\n throw new AstraSyncError(\n errorBody.error || `Request failed: ${res.status}`,\n res.status,\n errorBody.code\n );\n }\n\n return res.json() as Promise<T>;\n }\n\n private async getAuthToken(): Promise<string> {\n // API key auth — use directly\n if (this.apiKey) {\n return this.apiKey;\n }\n\n // Email+password — login and cache JWT\n if (this.cachedJwt && this.jwtExpiresAt && Date.now() < this.jwtExpiresAt) {\n return this.cachedJwt;\n }\n\n const res = await fetch(`${this.baseUrl}/api/auth/login`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: this.email, password: this.password }),\n });\n\n if (!res.ok) {\n const errorBody = (await res.json().catch(() => ({}))) as Record<string, unknown>;\n throw new AuthenticationError(\n (errorBody.message as string) || (errorBody.error as string) || 'Login failed'\n );\n }\n\n const data = (await res.json()) as { data: { token: string } };\n this.cachedJwt = data.data.token;\n // Cache for 6 days (tokens expire in 7)\n this.jwtExpiresAt = Date.now() + 6 * 24 * 60 * 60 * 1000;\n\n return this.cachedJwt;\n }\n\n /**\n * Sign a request using secp256k1 (ethers.js).\n * Canonical message format: METHOD:ENDPOINT:SORTED_JSON_BODY\n * Must match apps/backend/src/services/signature-verify.service.ts exactly.\n */\n private async signRequest(method: string, endpoint: string, body: unknown): Promise<string> {\n const { Wallet } = await import('ethers');\n const sorted = this.sortObjectKeys(body);\n const canonical = `${method}:${endpoint}:${JSON.stringify(sorted)}`;\n const wallet = new Wallet(this.privateKey!);\n return wallet.signMessage(canonical);\n }\n\n /** Recursively sort object keys for canonical JSON representation. */\n private sortObjectKeys(obj: unknown): unknown {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map((item) => this.sortObjectKeys(item));\n }\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(obj).sort()) {\n sorted[key] = this.sortObjectKeys((obj as Record<string, unknown>)[key]);\n }\n return sorted;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/registration/index.ts","../../src/registration/errors.ts","../../src/registration/api.ts"],"sourcesContent":["export { AstraSync } from './api';\nexport {\n AstraSyncError,\n KYDRequiredError,\n AuthenticationError,\n RegistrationDeniedError,\n RegistrationExpiredError,\n RegistrationTimeoutError,\n} from './errors';\nexport type {\n AstraSyncConfig,\n RegisterOptions,\n RegisterResult,\n WaitForApprovalOptions,\n PendingRegistrationResponse,\n PollRegistrationResult,\n RegistrationResponse,\n AgentRecord,\n VerifyResponse,\n HealthResponse,\n PDLSSConfig,\n PDLSSPurpose,\n PDLSSDuration,\n PDLSSLimits,\n PDLSSScope,\n PDLSSSelfInstantiation,\n ModelConfig,\n FrameworkConfig,\n AgentProtocol,\n} from './types';\n","import type { ApiErrorResponse } from './types';\n\n/** Base error class for AstraSync SDK errors. */\nexport class AstraSyncError extends Error {\n public readonly code?: string;\n public readonly statusCode: number;\n\n constructor(message: string, statusCode: number, code?: string) {\n super(message);\n this.name = 'AstraSyncError';\n this.statusCode = statusCode;\n this.code = code;\n }\n}\n\n/** Thrown when KYD verification is required before agent registration. */\nexport class KYDRequiredError extends AstraSyncError {\n public readonly kydUrl: string;\n public readonly ownerNotified: boolean;\n\n constructor(response: ApiErrorResponse) {\n const kydUrl = response.kydUrl || 'https://astrasync.ai/developer-profile';\n super(\n `KYD verification required before registering agents.\\nComplete your KYD profile at: ${kydUrl}`,\n 403,\n 'KYD_REQUIRED'\n );\n this.name = 'KYDRequiredError';\n this.kydUrl = kydUrl;\n this.ownerNotified = response.ownerNotified || false;\n }\n}\n\n/** Thrown when authentication fails. */\nexport class AuthenticationError extends AstraSyncError {\n constructor(message: string) {\n super(message, 401, 'AUTH_FAILED');\n this.name = 'AuthenticationError';\n }\n}\n\n/**\n * Thrown by `register({ waitForApproval: true })` when the owner denies the\n * pending registration request. The `reason` field, when present, mirrors the\n * deny note the owner left in the dashboard.\n */\nexport class RegistrationDeniedError extends AstraSyncError {\n public readonly requestId: string;\n public readonly reason?: string;\n\n constructor(requestId: string, reason?: string) {\n super(\n `Registration request ${requestId} was denied by the account owner.${reason ? ` Reason: ${reason}` : ''}`,\n 403,\n 'REGISTRATION_DENIED'\n );\n this.name = 'RegistrationDeniedError';\n this.requestId = requestId;\n this.reason = reason;\n }\n}\n\n/**\n * Thrown by `register({ waitForApproval: true })` when the pending request\n * passes its 14-day TTL with no owner decision. The agent must re-submit.\n */\nexport class RegistrationExpiredError extends AstraSyncError {\n public readonly requestId: string;\n\n constructor(requestId: string) {\n super(\n `Registration request ${requestId} expired before the owner approved it. Submit a new registration request.`,\n 410,\n 'REGISTRATION_EXPIRED'\n );\n this.name = 'RegistrationExpiredError';\n this.requestId = requestId;\n }\n}\n\n/**\n * Thrown by `register({ waitForApproval: true })` when the caller's local\n * `timeoutMs` elapses before the owner makes a decision. The request is still\n * live server-side — poll `pollRegistration(requestId)` to resume waiting, or\n * call `waitForApproval` again with a longer timeout.\n */\nexport class RegistrationTimeoutError extends AstraSyncError {\n public readonly requestId: string;\n\n constructor(requestId: string) {\n super(\n `Timed out waiting for owner approval of registration request ${requestId}. The request is still active server-side; poll the request to resume waiting.`,\n 408,\n 'REGISTRATION_TIMEOUT'\n );\n this.name = 'RegistrationTimeoutError';\n this.requestId = requestId;\n }\n}\n","import type {\n AstraSyncConfig,\n RegisterOptions,\n RegisterResult,\n WaitForApprovalOptions,\n PendingRegistrationResponse,\n PollRegistrationResult,\n RegistrationResponse,\n VerifyResponse,\n HealthResponse,\n ApiErrorResponse,\n AgentRecord,\n} from './types';\nimport {\n AstraSyncError,\n KYDRequiredError,\n AuthenticationError,\n RegistrationDeniedError,\n RegistrationExpiredError,\n RegistrationTimeoutError,\n} from './errors';\n\nconst DEFAULT_BASE_URL = 'https://astrasync.ai';\n\nconst sleep = (ms: number): Promise<void> => new Promise((r) => setTimeout(r, ms));\n\n/**\n * AstraSync SDK client for registering and managing AI agents.\n *\n * @example\n * ```typescript\n * const client = new AstraSync({ apiKey: 'kya_your_api_key' });\n * const result = await client.register({\n * name: 'My Agent',\n * model: { modelName: 'gpt-4o', modelProvider: 'openai', modelType: 'llm' },\n * });\n * ```\n *\n * For staging, pass `baseUrl: 'https://staging.astrasync.ai'`.\n */\nexport class AstraSync {\n private readonly baseUrl: string;\n private readonly apiKey?: string;\n private readonly email?: string;\n private readonly password?: string;\n private readonly privateKey?: string;\n private cachedJwt?: string;\n private jwtExpiresAt?: number;\n\n constructor(config: AstraSyncConfig = {}) {\n this.baseUrl = (config.baseUrl || process.env.ASTRASYNC_API_URL || DEFAULT_BASE_URL).replace(\n /\\/+$/,\n ''\n );\n\n this.apiKey = config.apiKey || process.env.ASTRASYNC_API_KEY;\n this.email = config.email;\n this.password = config.password;\n this.privateKey = config.privateKey;\n\n if (!this.apiKey && !this.email) {\n throw new AuthenticationError(\n 'Authentication required. Provide apiKey, or email+password. ' +\n 'Set ASTRASYNC_API_KEY env var or pass config to constructor.'\n );\n }\n\n if (this.email && !this.password) {\n throw new AuthenticationError('Password is required when using email authentication.');\n }\n }\n\n /**\n * Register a new AI agent on the AstraSync KYA Platform.\n *\n * The backend response depends on auth context:\n * - **Crypto-keypair signed** (`privateKey` configured): synchronous 201,\n * returns `{ status: 'active', agent }`.\n * - **API-key only** (no signature): 202 pending, returns\n * `{ status: 'pending_approval', requestId, pollUrl, expiresAt }`. The\n * owner is notified by email and a dashboard alert is emitted; the agent\n * becomes active only after the owner approves.\n *\n * Blocking mode: pass `{ waitForApproval: true }` to have the SDK poll the\n * request until it resolves, then return the live agent record. The promise\n * rejects with `RegistrationDeniedError`, `RegistrationExpiredError`, or\n * `RegistrationTimeoutError` on the corresponding terminal states.\n *\n * @example Non-blocking (default — best for serverless / scheduled agents):\n * ```typescript\n * const result = await sdk.register({ name, pdlss });\n * if (result.status === 'pending_approval') {\n * storeRequestId(result.requestId);\n * return; // function exits; resume later via pollRegistration()\n * }\n * ```\n *\n * @example Blocking (best for long-running services + CLI):\n * ```typescript\n * const agent = await sdk.register({\n * name, pdlss, waitForApproval: true, timeoutMs: 600_000,\n * onPending: ({ ageMs }) => console.log(`waiting ${ageMs}ms`),\n * });\n * ```\n */\n async register(\n options: RegisterOptions & WaitForApprovalOptions\n ): Promise<RegisterResult | AgentRecord> {\n const body: Record<string, unknown> = {\n name: options.name,\n ...(options.description && { description: options.description }),\n ...(options.agentType && { agentType: options.agentType }),\n ...(options.apiEndpoint && { apiEndpoint: options.apiEndpoint }),\n ...(options.model && { model: options.model }),\n ...(options.framework && { framework: options.framework }),\n ...(options.protocols && { protocols: options.protocols }),\n ...(options.metadata && { metadata: options.metadata }),\n ...(options.pdlss && { pdlss: options.pdlss }),\n };\n\n const { status, body: raw } = await this.requestWithStatus<\n RegistrationResponse | PendingRegistrationResponse\n >('POST', '/api/agents/register', body);\n\n if (status === 201) {\n const active: RegisterResult = {\n status: 'active',\n agent: (raw as RegistrationResponse).data.agent,\n };\n return active;\n }\n\n // 202 Accepted — owner approval required.\n const pendingBody = raw as PendingRegistrationResponse;\n const pending: RegisterResult = {\n status: 'pending_approval',\n requestId: pendingBody.requestId,\n expiresAt: pendingBody.expiresAt,\n pollUrl: pendingBody.pollUrl,\n message: pendingBody.message,\n };\n\n if (!options.waitForApproval) return pending;\n\n return this.waitForApproval(pendingBody.requestId, options);\n }\n\n /**\n * Poll the current state of a pending-approval registration request.\n *\n * Useful for caller-driven polling when `waitForApproval: false` (the\n * default). The endpoint is unauthenticated — pass the `requestId` that\n * was returned from the 202 response.\n *\n * @returns `state: 'pending'` while awaiting; `'approved'` carries the\n * minted agent in `agent`; `'denied'` may carry the owner's\n * `reason`; `'expired'` is terminal after 14 days.\n */\n async pollRegistration(requestId: string): Promise<PollRegistrationResult> {\n const url = `${this.baseUrl}/api/agents/request-registration/${requestId}`;\n const res = await fetch(url, { headers: { Accept: 'application/json' } });\n if (!res.ok) {\n const errBody = (await res.json().catch(() => ({}))) as ApiErrorResponse;\n throw new AstraSyncError(\n errBody.error || `pollRegistration failed: ${res.status}`,\n res.status,\n errBody.code\n );\n }\n return (await res.json()) as PollRegistrationResult;\n }\n\n /**\n * Block until a pending registration request resolves to a terminal state.\n * Resolves to the live `AgentRecord` on approval; rejects with the matching\n * Registration*Error on deny/expire/timeout. Usually called via\n * `register({ waitForApproval: true })`, but exposed for callers that want\n * to fire-and-forget the initial register call and resume waiting later\n * (e.g. after restoring a stored `requestId` on cold start).\n */\n async waitForApproval(\n requestId: string,\n options: WaitForApprovalOptions = {}\n ): Promise<AgentRecord> {\n const timeoutMs = options.timeoutMs ?? 10 * 60 * 1000;\n const pollIntervalMs = options.pollIntervalMs ?? 5_000;\n const start = Date.now();\n const deadline = start + timeoutMs;\n\n while (Date.now() < deadline) {\n const result = await this.pollRegistration(requestId);\n const ageMs = Date.now() - start;\n options.onPending?.({ requestId, ageMs });\n\n if (result.state === 'approved') {\n if (!result.agent) {\n throw new AstraSyncError(\n `Registration ${requestId} reported approved but no agent payload returned.`,\n 500\n );\n }\n return result.agent;\n }\n if (result.state === 'denied') {\n throw new RegistrationDeniedError(requestId, result.reason);\n }\n if (result.state === 'expired') {\n throw new RegistrationExpiredError(requestId);\n }\n await sleep(pollIntervalMs);\n }\n throw new RegistrationTimeoutError(requestId);\n }\n\n /**\n * Look up an agent's public profile by ASTRA ID or UUID.\n */\n async verify(agentId: string): Promise<VerifyResponse> {\n return this.request<VerifyResponse>('GET', `/api/agents/verify/${agentId}`);\n }\n\n /**\n * Check API health.\n */\n async health(): Promise<HealthResponse> {\n const res = await fetch(`${this.baseUrl}/api/health/`);\n if (!res.ok) {\n throw new AstraSyncError(`Health check failed: ${res.status}`, res.status);\n }\n return res.json() as Promise<HealthResponse>;\n }\n\n // ── Private helpers ──────────────────────────────────────────────\n\n private async request<T>(method: string, endpoint: string, body?: unknown): Promise<T> {\n const { body: parsed } = await this.requestWithStatus<T>(method, endpoint, body);\n return parsed;\n }\n\n /**\n * Variant of {@link request} that also returns the HTTP status code, so\n * callers can branch on 201 vs 202 (or other success codes) without losing\n * type information about the response body.\n */\n private async requestWithStatus<T>(\n method: string,\n endpoint: string,\n body?: unknown\n ): Promise<{ status: number; body: T }> {\n const url = `${this.baseUrl}${endpoint}`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n // Set auth header\n const token = await this.getAuthToken();\n headers['Authorization'] = `Bearer ${token}`;\n\n // Sign request if private key is configured\n if (this.privateKey) {\n const signature = await this.signRequest(method, endpoint, body || {});\n headers['X-AstraSync-Signature'] = signature;\n }\n\n const res = await fetch(url, {\n method,\n headers,\n ...(body ? { body: JSON.stringify(body) } : {}),\n });\n\n if (!res.ok) {\n const errorBody = (await res\n .json()\n .catch(() => ({ error: res.statusText }))) as ApiErrorResponse;\n\n // Handle KYD_REQUIRED specifically\n if (res.status === 403 && errorBody.code === 'KYD_REQUIRED') {\n throw new KYDRequiredError(errorBody);\n }\n\n throw new AstraSyncError(\n errorBody.error || `Request failed: ${res.status}`,\n res.status,\n errorBody.code\n );\n }\n\n return { status: res.status, body: (await res.json()) as T };\n }\n\n private async getAuthToken(): Promise<string> {\n // API key auth — use directly\n if (this.apiKey) {\n return this.apiKey;\n }\n\n // Email+password — login and cache JWT\n if (this.cachedJwt && this.jwtExpiresAt && Date.now() < this.jwtExpiresAt) {\n return this.cachedJwt;\n }\n\n const res = await fetch(`${this.baseUrl}/api/auth/login`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: this.email, password: this.password }),\n });\n\n if (!res.ok) {\n const errorBody = (await res.json().catch(() => ({}))) as Record<string, unknown>;\n throw new AuthenticationError(\n (errorBody.message as string) || (errorBody.error as string) || 'Login failed'\n );\n }\n\n const data = (await res.json()) as { data: { token: string } };\n this.cachedJwt = data.data.token;\n // Cache for 6 days (tokens expire in 7)\n this.jwtExpiresAt = Date.now() + 6 * 24 * 60 * 60 * 1000;\n\n return this.cachedJwt;\n }\n\n /**\n * Sign a request using secp256k1 (ethers.js).\n * Canonical message format: METHOD:ENDPOINT:SORTED_JSON_BODY\n * Must match apps/backend/src/services/signature-verify.service.ts exactly.\n */\n private async signRequest(method: string, endpoint: string, body: unknown): Promise<string> {\n const { Wallet } = await import('ethers');\n const sorted = this.sortObjectKeys(body);\n const canonical = `${method}:${endpoint}:${JSON.stringify(sorted)}`;\n const wallet = new Wallet(this.privateKey!);\n return wallet.signMessage(canonical);\n }\n\n /** Recursively sort object keys for canonical JSON representation. */\n private sortObjectKeys(obj: unknown): unknown {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map((item) => this.sortObjectKeys(item));\n }\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(obj).sort()) {\n sorted[key] = this.sortObjectKeys((obj as Record<string, unknown>)[key]);\n }\n return sorted;\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -27,9 +27,44 @@ var AuthenticationError = class extends AstraSyncError {
|
|
|
27
27
|
this.name = "AuthenticationError";
|
|
28
28
|
}
|
|
29
29
|
};
|
|
30
|
+
var RegistrationDeniedError = class extends AstraSyncError {
|
|
31
|
+
constructor(requestId, reason) {
|
|
32
|
+
super(
|
|
33
|
+
`Registration request ${requestId} was denied by the account owner.${reason ? ` Reason: ${reason}` : ""}`,
|
|
34
|
+
403,
|
|
35
|
+
"REGISTRATION_DENIED"
|
|
36
|
+
);
|
|
37
|
+
this.name = "RegistrationDeniedError";
|
|
38
|
+
this.requestId = requestId;
|
|
39
|
+
this.reason = reason;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
var RegistrationExpiredError = class extends AstraSyncError {
|
|
43
|
+
constructor(requestId) {
|
|
44
|
+
super(
|
|
45
|
+
`Registration request ${requestId} expired before the owner approved it. Submit a new registration request.`,
|
|
46
|
+
410,
|
|
47
|
+
"REGISTRATION_EXPIRED"
|
|
48
|
+
);
|
|
49
|
+
this.name = "RegistrationExpiredError";
|
|
50
|
+
this.requestId = requestId;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
var RegistrationTimeoutError = class extends AstraSyncError {
|
|
54
|
+
constructor(requestId) {
|
|
55
|
+
super(
|
|
56
|
+
`Timed out waiting for owner approval of registration request ${requestId}. The request is still active server-side; poll the request to resume waiting.`,
|
|
57
|
+
408,
|
|
58
|
+
"REGISTRATION_TIMEOUT"
|
|
59
|
+
);
|
|
60
|
+
this.name = "RegistrationTimeoutError";
|
|
61
|
+
this.requestId = requestId;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
30
64
|
|
|
31
65
|
// src/registration/api.ts
|
|
32
66
|
var DEFAULT_BASE_URL = "https://astrasync.ai";
|
|
67
|
+
var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
33
68
|
var AstraSync = class {
|
|
34
69
|
constructor(config = {}) {
|
|
35
70
|
this.baseUrl = (config.baseUrl || process.env.ASTRASYNC_API_URL || DEFAULT_BASE_URL).replace(
|
|
@@ -51,7 +86,36 @@ var AstraSync = class {
|
|
|
51
86
|
}
|
|
52
87
|
/**
|
|
53
88
|
* Register a new AI agent on the AstraSync KYA Platform.
|
|
54
|
-
*
|
|
89
|
+
*
|
|
90
|
+
* The backend response depends on auth context:
|
|
91
|
+
* - **Crypto-keypair signed** (`privateKey` configured): synchronous 201,
|
|
92
|
+
* returns `{ status: 'active', agent }`.
|
|
93
|
+
* - **API-key only** (no signature): 202 pending, returns
|
|
94
|
+
* `{ status: 'pending_approval', requestId, pollUrl, expiresAt }`. The
|
|
95
|
+
* owner is notified by email and a dashboard alert is emitted; the agent
|
|
96
|
+
* becomes active only after the owner approves.
|
|
97
|
+
*
|
|
98
|
+
* Blocking mode: pass `{ waitForApproval: true }` to have the SDK poll the
|
|
99
|
+
* request until it resolves, then return the live agent record. The promise
|
|
100
|
+
* rejects with `RegistrationDeniedError`, `RegistrationExpiredError`, or
|
|
101
|
+
* `RegistrationTimeoutError` on the corresponding terminal states.
|
|
102
|
+
*
|
|
103
|
+
* @example Non-blocking (default — best for serverless / scheduled agents):
|
|
104
|
+
* ```typescript
|
|
105
|
+
* const result = await sdk.register({ name, pdlss });
|
|
106
|
+
* if (result.status === 'pending_approval') {
|
|
107
|
+
* storeRequestId(result.requestId);
|
|
108
|
+
* return; // function exits; resume later via pollRegistration()
|
|
109
|
+
* }
|
|
110
|
+
* ```
|
|
111
|
+
*
|
|
112
|
+
* @example Blocking (best for long-running services + CLI):
|
|
113
|
+
* ```typescript
|
|
114
|
+
* const agent = await sdk.register({
|
|
115
|
+
* name, pdlss, waitForApproval: true, timeoutMs: 600_000,
|
|
116
|
+
* onPending: ({ ageMs }) => console.log(`waiting ${ageMs}ms`),
|
|
117
|
+
* });
|
|
118
|
+
* ```
|
|
55
119
|
*/
|
|
56
120
|
async register(options) {
|
|
57
121
|
const body = {
|
|
@@ -65,7 +129,84 @@ var AstraSync = class {
|
|
|
65
129
|
...options.metadata && { metadata: options.metadata },
|
|
66
130
|
...options.pdlss && { pdlss: options.pdlss }
|
|
67
131
|
};
|
|
68
|
-
|
|
132
|
+
const { status, body: raw } = await this.requestWithStatus("POST", "/api/agents/register", body);
|
|
133
|
+
if (status === 201) {
|
|
134
|
+
const active = {
|
|
135
|
+
status: "active",
|
|
136
|
+
agent: raw.data.agent
|
|
137
|
+
};
|
|
138
|
+
return active;
|
|
139
|
+
}
|
|
140
|
+
const pendingBody = raw;
|
|
141
|
+
const pending = {
|
|
142
|
+
status: "pending_approval",
|
|
143
|
+
requestId: pendingBody.requestId,
|
|
144
|
+
expiresAt: pendingBody.expiresAt,
|
|
145
|
+
pollUrl: pendingBody.pollUrl,
|
|
146
|
+
message: pendingBody.message
|
|
147
|
+
};
|
|
148
|
+
if (!options.waitForApproval) return pending;
|
|
149
|
+
return this.waitForApproval(pendingBody.requestId, options);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Poll the current state of a pending-approval registration request.
|
|
153
|
+
*
|
|
154
|
+
* Useful for caller-driven polling when `waitForApproval: false` (the
|
|
155
|
+
* default). The endpoint is unauthenticated — pass the `requestId` that
|
|
156
|
+
* was returned from the 202 response.
|
|
157
|
+
*
|
|
158
|
+
* @returns `state: 'pending'` while awaiting; `'approved'` carries the
|
|
159
|
+
* minted agent in `agent`; `'denied'` may carry the owner's
|
|
160
|
+
* `reason`; `'expired'` is terminal after 14 days.
|
|
161
|
+
*/
|
|
162
|
+
async pollRegistration(requestId) {
|
|
163
|
+
const url = `${this.baseUrl}/api/agents/request-registration/${requestId}`;
|
|
164
|
+
const res = await fetch(url, { headers: { Accept: "application/json" } });
|
|
165
|
+
if (!res.ok) {
|
|
166
|
+
const errBody = await res.json().catch(() => ({}));
|
|
167
|
+
throw new AstraSyncError(
|
|
168
|
+
errBody.error || `pollRegistration failed: ${res.status}`,
|
|
169
|
+
res.status,
|
|
170
|
+
errBody.code
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
return await res.json();
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Block until a pending registration request resolves to a terminal state.
|
|
177
|
+
* Resolves to the live `AgentRecord` on approval; rejects with the matching
|
|
178
|
+
* Registration*Error on deny/expire/timeout. Usually called via
|
|
179
|
+
* `register({ waitForApproval: true })`, but exposed for callers that want
|
|
180
|
+
* to fire-and-forget the initial register call and resume waiting later
|
|
181
|
+
* (e.g. after restoring a stored `requestId` on cold start).
|
|
182
|
+
*/
|
|
183
|
+
async waitForApproval(requestId, options = {}) {
|
|
184
|
+
const timeoutMs = options.timeoutMs ?? 10 * 60 * 1e3;
|
|
185
|
+
const pollIntervalMs = options.pollIntervalMs ?? 5e3;
|
|
186
|
+
const start = Date.now();
|
|
187
|
+
const deadline = start + timeoutMs;
|
|
188
|
+
while (Date.now() < deadline) {
|
|
189
|
+
const result = await this.pollRegistration(requestId);
|
|
190
|
+
const ageMs = Date.now() - start;
|
|
191
|
+
options.onPending?.({ requestId, ageMs });
|
|
192
|
+
if (result.state === "approved") {
|
|
193
|
+
if (!result.agent) {
|
|
194
|
+
throw new AstraSyncError(
|
|
195
|
+
`Registration ${requestId} reported approved but no agent payload returned.`,
|
|
196
|
+
500
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
return result.agent;
|
|
200
|
+
}
|
|
201
|
+
if (result.state === "denied") {
|
|
202
|
+
throw new RegistrationDeniedError(requestId, result.reason);
|
|
203
|
+
}
|
|
204
|
+
if (result.state === "expired") {
|
|
205
|
+
throw new RegistrationExpiredError(requestId);
|
|
206
|
+
}
|
|
207
|
+
await sleep(pollIntervalMs);
|
|
208
|
+
}
|
|
209
|
+
throw new RegistrationTimeoutError(requestId);
|
|
69
210
|
}
|
|
70
211
|
/**
|
|
71
212
|
* Look up an agent's public profile by ASTRA ID or UUID.
|
|
@@ -85,6 +226,15 @@ var AstraSync = class {
|
|
|
85
226
|
}
|
|
86
227
|
// ── Private helpers ──────────────────────────────────────────────
|
|
87
228
|
async request(method, endpoint, body) {
|
|
229
|
+
const { body: parsed } = await this.requestWithStatus(method, endpoint, body);
|
|
230
|
+
return parsed;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Variant of {@link request} that also returns the HTTP status code, so
|
|
234
|
+
* callers can branch on 201 vs 202 (or other success codes) without losing
|
|
235
|
+
* type information about the response body.
|
|
236
|
+
*/
|
|
237
|
+
async requestWithStatus(method, endpoint, body) {
|
|
88
238
|
const url = `${this.baseUrl}${endpoint}`;
|
|
89
239
|
const headers = {
|
|
90
240
|
"Content-Type": "application/json"
|
|
@@ -111,7 +261,7 @@ var AstraSync = class {
|
|
|
111
261
|
errorBody.code
|
|
112
262
|
);
|
|
113
263
|
}
|
|
114
|
-
return res.json();
|
|
264
|
+
return { status: res.status, body: await res.json() };
|
|
115
265
|
}
|
|
116
266
|
async getAuthToken() {
|
|
117
267
|
if (this.apiKey) {
|
|
@@ -167,6 +317,9 @@ export {
|
|
|
167
317
|
AstraSync,
|
|
168
318
|
AstraSyncError,
|
|
169
319
|
AuthenticationError,
|
|
170
|
-
KYDRequiredError
|
|
320
|
+
KYDRequiredError,
|
|
321
|
+
RegistrationDeniedError,
|
|
322
|
+
RegistrationExpiredError,
|
|
323
|
+
RegistrationTimeoutError
|
|
171
324
|
};
|
|
172
325
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/registration/errors.ts","../../src/registration/api.ts"],"sourcesContent":["import type { ApiErrorResponse } from './types';\n\n/** Base error class for AstraSync SDK errors. */\nexport class AstraSyncError extends Error {\n public readonly code?: string;\n public readonly statusCode: number;\n\n constructor(message: string, statusCode: number, code?: string) {\n super(message);\n this.name = 'AstraSyncError';\n this.statusCode = statusCode;\n this.code = code;\n }\n}\n\n/** Thrown when KYD verification is required before agent registration. */\nexport class KYDRequiredError extends AstraSyncError {\n public readonly kydUrl: string;\n public readonly ownerNotified: boolean;\n\n constructor(response: ApiErrorResponse) {\n const kydUrl = response.kydUrl || 'https://astrasync.ai/developer-profile';\n super(\n `KYD verification required before registering agents.\\nComplete your KYD profile at: ${kydUrl}`,\n 403,\n 'KYD_REQUIRED'\n );\n this.name = 'KYDRequiredError';\n this.kydUrl = kydUrl;\n this.ownerNotified = response.ownerNotified || false;\n }\n}\n\n/** Thrown when authentication fails. */\nexport class AuthenticationError extends AstraSyncError {\n constructor(message: string) {\n super(message, 401, 'AUTH_FAILED');\n this.name = 'AuthenticationError';\n }\n}\n","import type {\n AstraSyncConfig,\n RegisterOptions,\n RegistrationResponse,\n VerifyResponse,\n HealthResponse,\n ApiErrorResponse,\n} from './types';\nimport { AstraSyncError, KYDRequiredError, AuthenticationError } from './errors';\n\nconst DEFAULT_BASE_URL = 'https://astrasync.ai';\n\n/**\n * AstraSync SDK client for registering and managing AI agents.\n *\n * @example\n * ```typescript\n * const client = new AstraSync({ apiKey: 'kya_your_api_key' });\n * const result = await client.register({\n * name: 'My Agent',\n * model: { modelName: 'gpt-4o', modelProvider: 'openai', modelType: 'llm' },\n * });\n * ```\n *\n * For staging, pass `baseUrl: 'https://staging.astrasync.ai'`.\n */\nexport class AstraSync {\n private readonly baseUrl: string;\n private readonly apiKey?: string;\n private readonly email?: string;\n private readonly password?: string;\n private readonly privateKey?: string;\n private cachedJwt?: string;\n private jwtExpiresAt?: number;\n\n constructor(config: AstraSyncConfig = {}) {\n this.baseUrl = (config.baseUrl || process.env.ASTRASYNC_API_URL || DEFAULT_BASE_URL).replace(\n /\\/+$/,\n ''\n );\n\n this.apiKey = config.apiKey || process.env.ASTRASYNC_API_KEY;\n this.email = config.email;\n this.password = config.password;\n this.privateKey = config.privateKey;\n\n if (!this.apiKey && !this.email) {\n throw new AuthenticationError(\n 'Authentication required. Provide apiKey, or email+password. ' +\n 'Set ASTRASYNC_API_KEY env var or pass config to constructor.'\n );\n }\n\n if (this.email && !this.password) {\n throw new AuthenticationError('Password is required when using email authentication.');\n }\n }\n\n /**\n * Register a new AI agent on the AstraSync KYA Platform.\n * Sends full payload including model, framework, PDLSS, and metadata.\n */\n async register(options: RegisterOptions): Promise<RegistrationResponse> {\n const body: Record<string, unknown> = {\n name: options.name,\n ...(options.description && { description: options.description }),\n ...(options.agentType && { agentType: options.agentType }),\n ...(options.apiEndpoint && { apiEndpoint: options.apiEndpoint }),\n ...(options.model && { model: options.model }),\n ...(options.framework && { framework: options.framework }),\n ...(options.protocols && { protocols: options.protocols }),\n ...(options.metadata && { metadata: options.metadata }),\n ...(options.pdlss && { pdlss: options.pdlss }),\n };\n\n return this.request<RegistrationResponse>('POST', '/api/agents/register', body);\n }\n\n /**\n * Look up an agent's public profile by ASTRA ID or UUID.\n */\n async verify(agentId: string): Promise<VerifyResponse> {\n return this.request<VerifyResponse>('GET', `/api/agents/verify/${agentId}`);\n }\n\n /**\n * Check API health.\n */\n async health(): Promise<HealthResponse> {\n const res = await fetch(`${this.baseUrl}/api/health/`);\n if (!res.ok) {\n throw new AstraSyncError(`Health check failed: ${res.status}`, res.status);\n }\n return res.json() as Promise<HealthResponse>;\n }\n\n // ── Private helpers ──────────────────────────────────────────────\n\n private async request<T>(method: string, endpoint: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}${endpoint}`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n // Set auth header\n const token = await this.getAuthToken();\n headers['Authorization'] = `Bearer ${token}`;\n\n // Sign request if private key is configured\n if (this.privateKey) {\n const signature = await this.signRequest(method, endpoint, body || {});\n headers['X-AstraSync-Signature'] = signature;\n }\n\n const res = await fetch(url, {\n method,\n headers,\n ...(body ? { body: JSON.stringify(body) } : {}),\n });\n\n if (!res.ok) {\n const errorBody = (await res\n .json()\n .catch(() => ({ error: res.statusText }))) as ApiErrorResponse;\n\n // Handle KYD_REQUIRED specifically\n if (res.status === 403 && errorBody.code === 'KYD_REQUIRED') {\n throw new KYDRequiredError(errorBody);\n }\n\n throw new AstraSyncError(\n errorBody.error || `Request failed: ${res.status}`,\n res.status,\n errorBody.code\n );\n }\n\n return res.json() as Promise<T>;\n }\n\n private async getAuthToken(): Promise<string> {\n // API key auth — use directly\n if (this.apiKey) {\n return this.apiKey;\n }\n\n // Email+password — login and cache JWT\n if (this.cachedJwt && this.jwtExpiresAt && Date.now() < this.jwtExpiresAt) {\n return this.cachedJwt;\n }\n\n const res = await fetch(`${this.baseUrl}/api/auth/login`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: this.email, password: this.password }),\n });\n\n if (!res.ok) {\n const errorBody = (await res.json().catch(() => ({}))) as Record<string, unknown>;\n throw new AuthenticationError(\n (errorBody.message as string) || (errorBody.error as string) || 'Login failed'\n );\n }\n\n const data = (await res.json()) as { data: { token: string } };\n this.cachedJwt = data.data.token;\n // Cache for 6 days (tokens expire in 7)\n this.jwtExpiresAt = Date.now() + 6 * 24 * 60 * 60 * 1000;\n\n return this.cachedJwt;\n }\n\n /**\n * Sign a request using secp256k1 (ethers.js).\n * Canonical message format: METHOD:ENDPOINT:SORTED_JSON_BODY\n * Must match apps/backend/src/services/signature-verify.service.ts exactly.\n */\n private async signRequest(method: string, endpoint: string, body: unknown): Promise<string> {\n const { Wallet } = await import('ethers');\n const sorted = this.sortObjectKeys(body);\n const canonical = `${method}:${endpoint}:${JSON.stringify(sorted)}`;\n const wallet = new Wallet(this.privateKey!);\n return wallet.signMessage(canonical);\n }\n\n /** Recursively sort object keys for canonical JSON representation. */\n private sortObjectKeys(obj: unknown): unknown {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map((item) => this.sortObjectKeys(item));\n }\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(obj).sort()) {\n sorted[key] = this.sortObjectKeys((obj as Record<string, unknown>)[key]);\n }\n return sorted;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/registration/errors.ts","../../src/registration/api.ts"],"sourcesContent":["import type { ApiErrorResponse } from './types';\n\n/** Base error class for AstraSync SDK errors. */\nexport class AstraSyncError extends Error {\n public readonly code?: string;\n public readonly statusCode: number;\n\n constructor(message: string, statusCode: number, code?: string) {\n super(message);\n this.name = 'AstraSyncError';\n this.statusCode = statusCode;\n this.code = code;\n }\n}\n\n/** Thrown when KYD verification is required before agent registration. */\nexport class KYDRequiredError extends AstraSyncError {\n public readonly kydUrl: string;\n public readonly ownerNotified: boolean;\n\n constructor(response: ApiErrorResponse) {\n const kydUrl = response.kydUrl || 'https://astrasync.ai/developer-profile';\n super(\n `KYD verification required before registering agents.\\nComplete your KYD profile at: ${kydUrl}`,\n 403,\n 'KYD_REQUIRED'\n );\n this.name = 'KYDRequiredError';\n this.kydUrl = kydUrl;\n this.ownerNotified = response.ownerNotified || false;\n }\n}\n\n/** Thrown when authentication fails. */\nexport class AuthenticationError extends AstraSyncError {\n constructor(message: string) {\n super(message, 401, 'AUTH_FAILED');\n this.name = 'AuthenticationError';\n }\n}\n\n/**\n * Thrown by `register({ waitForApproval: true })` when the owner denies the\n * pending registration request. The `reason` field, when present, mirrors the\n * deny note the owner left in the dashboard.\n */\nexport class RegistrationDeniedError extends AstraSyncError {\n public readonly requestId: string;\n public readonly reason?: string;\n\n constructor(requestId: string, reason?: string) {\n super(\n `Registration request ${requestId} was denied by the account owner.${reason ? ` Reason: ${reason}` : ''}`,\n 403,\n 'REGISTRATION_DENIED'\n );\n this.name = 'RegistrationDeniedError';\n this.requestId = requestId;\n this.reason = reason;\n }\n}\n\n/**\n * Thrown by `register({ waitForApproval: true })` when the pending request\n * passes its 14-day TTL with no owner decision. The agent must re-submit.\n */\nexport class RegistrationExpiredError extends AstraSyncError {\n public readonly requestId: string;\n\n constructor(requestId: string) {\n super(\n `Registration request ${requestId} expired before the owner approved it. Submit a new registration request.`,\n 410,\n 'REGISTRATION_EXPIRED'\n );\n this.name = 'RegistrationExpiredError';\n this.requestId = requestId;\n }\n}\n\n/**\n * Thrown by `register({ waitForApproval: true })` when the caller's local\n * `timeoutMs` elapses before the owner makes a decision. The request is still\n * live server-side — poll `pollRegistration(requestId)` to resume waiting, or\n * call `waitForApproval` again with a longer timeout.\n */\nexport class RegistrationTimeoutError extends AstraSyncError {\n public readonly requestId: string;\n\n constructor(requestId: string) {\n super(\n `Timed out waiting for owner approval of registration request ${requestId}. The request is still active server-side; poll the request to resume waiting.`,\n 408,\n 'REGISTRATION_TIMEOUT'\n );\n this.name = 'RegistrationTimeoutError';\n this.requestId = requestId;\n }\n}\n","import type {\n AstraSyncConfig,\n RegisterOptions,\n RegisterResult,\n WaitForApprovalOptions,\n PendingRegistrationResponse,\n PollRegistrationResult,\n RegistrationResponse,\n VerifyResponse,\n HealthResponse,\n ApiErrorResponse,\n AgentRecord,\n} from './types';\nimport {\n AstraSyncError,\n KYDRequiredError,\n AuthenticationError,\n RegistrationDeniedError,\n RegistrationExpiredError,\n RegistrationTimeoutError,\n} from './errors';\n\nconst DEFAULT_BASE_URL = 'https://astrasync.ai';\n\nconst sleep = (ms: number): Promise<void> => new Promise((r) => setTimeout(r, ms));\n\n/**\n * AstraSync SDK client for registering and managing AI agents.\n *\n * @example\n * ```typescript\n * const client = new AstraSync({ apiKey: 'kya_your_api_key' });\n * const result = await client.register({\n * name: 'My Agent',\n * model: { modelName: 'gpt-4o', modelProvider: 'openai', modelType: 'llm' },\n * });\n * ```\n *\n * For staging, pass `baseUrl: 'https://staging.astrasync.ai'`.\n */\nexport class AstraSync {\n private readonly baseUrl: string;\n private readonly apiKey?: string;\n private readonly email?: string;\n private readonly password?: string;\n private readonly privateKey?: string;\n private cachedJwt?: string;\n private jwtExpiresAt?: number;\n\n constructor(config: AstraSyncConfig = {}) {\n this.baseUrl = (config.baseUrl || process.env.ASTRASYNC_API_URL || DEFAULT_BASE_URL).replace(\n /\\/+$/,\n ''\n );\n\n this.apiKey = config.apiKey || process.env.ASTRASYNC_API_KEY;\n this.email = config.email;\n this.password = config.password;\n this.privateKey = config.privateKey;\n\n if (!this.apiKey && !this.email) {\n throw new AuthenticationError(\n 'Authentication required. Provide apiKey, or email+password. ' +\n 'Set ASTRASYNC_API_KEY env var or pass config to constructor.'\n );\n }\n\n if (this.email && !this.password) {\n throw new AuthenticationError('Password is required when using email authentication.');\n }\n }\n\n /**\n * Register a new AI agent on the AstraSync KYA Platform.\n *\n * The backend response depends on auth context:\n * - **Crypto-keypair signed** (`privateKey` configured): synchronous 201,\n * returns `{ status: 'active', agent }`.\n * - **API-key only** (no signature): 202 pending, returns\n * `{ status: 'pending_approval', requestId, pollUrl, expiresAt }`. The\n * owner is notified by email and a dashboard alert is emitted; the agent\n * becomes active only after the owner approves.\n *\n * Blocking mode: pass `{ waitForApproval: true }` to have the SDK poll the\n * request until it resolves, then return the live agent record. The promise\n * rejects with `RegistrationDeniedError`, `RegistrationExpiredError`, or\n * `RegistrationTimeoutError` on the corresponding terminal states.\n *\n * @example Non-blocking (default — best for serverless / scheduled agents):\n * ```typescript\n * const result = await sdk.register({ name, pdlss });\n * if (result.status === 'pending_approval') {\n * storeRequestId(result.requestId);\n * return; // function exits; resume later via pollRegistration()\n * }\n * ```\n *\n * @example Blocking (best for long-running services + CLI):\n * ```typescript\n * const agent = await sdk.register({\n * name, pdlss, waitForApproval: true, timeoutMs: 600_000,\n * onPending: ({ ageMs }) => console.log(`waiting ${ageMs}ms`),\n * });\n * ```\n */\n async register(\n options: RegisterOptions & WaitForApprovalOptions\n ): Promise<RegisterResult | AgentRecord> {\n const body: Record<string, unknown> = {\n name: options.name,\n ...(options.description && { description: options.description }),\n ...(options.agentType && { agentType: options.agentType }),\n ...(options.apiEndpoint && { apiEndpoint: options.apiEndpoint }),\n ...(options.model && { model: options.model }),\n ...(options.framework && { framework: options.framework }),\n ...(options.protocols && { protocols: options.protocols }),\n ...(options.metadata && { metadata: options.metadata }),\n ...(options.pdlss && { pdlss: options.pdlss }),\n };\n\n const { status, body: raw } = await this.requestWithStatus<\n RegistrationResponse | PendingRegistrationResponse\n >('POST', '/api/agents/register', body);\n\n if (status === 201) {\n const active: RegisterResult = {\n status: 'active',\n agent: (raw as RegistrationResponse).data.agent,\n };\n return active;\n }\n\n // 202 Accepted — owner approval required.\n const pendingBody = raw as PendingRegistrationResponse;\n const pending: RegisterResult = {\n status: 'pending_approval',\n requestId: pendingBody.requestId,\n expiresAt: pendingBody.expiresAt,\n pollUrl: pendingBody.pollUrl,\n message: pendingBody.message,\n };\n\n if (!options.waitForApproval) return pending;\n\n return this.waitForApproval(pendingBody.requestId, options);\n }\n\n /**\n * Poll the current state of a pending-approval registration request.\n *\n * Useful for caller-driven polling when `waitForApproval: false` (the\n * default). The endpoint is unauthenticated — pass the `requestId` that\n * was returned from the 202 response.\n *\n * @returns `state: 'pending'` while awaiting; `'approved'` carries the\n * minted agent in `agent`; `'denied'` may carry the owner's\n * `reason`; `'expired'` is terminal after 14 days.\n */\n async pollRegistration(requestId: string): Promise<PollRegistrationResult> {\n const url = `${this.baseUrl}/api/agents/request-registration/${requestId}`;\n const res = await fetch(url, { headers: { Accept: 'application/json' } });\n if (!res.ok) {\n const errBody = (await res.json().catch(() => ({}))) as ApiErrorResponse;\n throw new AstraSyncError(\n errBody.error || `pollRegistration failed: ${res.status}`,\n res.status,\n errBody.code\n );\n }\n return (await res.json()) as PollRegistrationResult;\n }\n\n /**\n * Block until a pending registration request resolves to a terminal state.\n * Resolves to the live `AgentRecord` on approval; rejects with the matching\n * Registration*Error on deny/expire/timeout. Usually called via\n * `register({ waitForApproval: true })`, but exposed for callers that want\n * to fire-and-forget the initial register call and resume waiting later\n * (e.g. after restoring a stored `requestId` on cold start).\n */\n async waitForApproval(\n requestId: string,\n options: WaitForApprovalOptions = {}\n ): Promise<AgentRecord> {\n const timeoutMs = options.timeoutMs ?? 10 * 60 * 1000;\n const pollIntervalMs = options.pollIntervalMs ?? 5_000;\n const start = Date.now();\n const deadline = start + timeoutMs;\n\n while (Date.now() < deadline) {\n const result = await this.pollRegistration(requestId);\n const ageMs = Date.now() - start;\n options.onPending?.({ requestId, ageMs });\n\n if (result.state === 'approved') {\n if (!result.agent) {\n throw new AstraSyncError(\n `Registration ${requestId} reported approved but no agent payload returned.`,\n 500\n );\n }\n return result.agent;\n }\n if (result.state === 'denied') {\n throw new RegistrationDeniedError(requestId, result.reason);\n }\n if (result.state === 'expired') {\n throw new RegistrationExpiredError(requestId);\n }\n await sleep(pollIntervalMs);\n }\n throw new RegistrationTimeoutError(requestId);\n }\n\n /**\n * Look up an agent's public profile by ASTRA ID or UUID.\n */\n async verify(agentId: string): Promise<VerifyResponse> {\n return this.request<VerifyResponse>('GET', `/api/agents/verify/${agentId}`);\n }\n\n /**\n * Check API health.\n */\n async health(): Promise<HealthResponse> {\n const res = await fetch(`${this.baseUrl}/api/health/`);\n if (!res.ok) {\n throw new AstraSyncError(`Health check failed: ${res.status}`, res.status);\n }\n return res.json() as Promise<HealthResponse>;\n }\n\n // ── Private helpers ──────────────────────────────────────────────\n\n private async request<T>(method: string, endpoint: string, body?: unknown): Promise<T> {\n const { body: parsed } = await this.requestWithStatus<T>(method, endpoint, body);\n return parsed;\n }\n\n /**\n * Variant of {@link request} that also returns the HTTP status code, so\n * callers can branch on 201 vs 202 (or other success codes) without losing\n * type information about the response body.\n */\n private async requestWithStatus<T>(\n method: string,\n endpoint: string,\n body?: unknown\n ): Promise<{ status: number; body: T }> {\n const url = `${this.baseUrl}${endpoint}`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n // Set auth header\n const token = await this.getAuthToken();\n headers['Authorization'] = `Bearer ${token}`;\n\n // Sign request if private key is configured\n if (this.privateKey) {\n const signature = await this.signRequest(method, endpoint, body || {});\n headers['X-AstraSync-Signature'] = signature;\n }\n\n const res = await fetch(url, {\n method,\n headers,\n ...(body ? { body: JSON.stringify(body) } : {}),\n });\n\n if (!res.ok) {\n const errorBody = (await res\n .json()\n .catch(() => ({ error: res.statusText }))) as ApiErrorResponse;\n\n // Handle KYD_REQUIRED specifically\n if (res.status === 403 && errorBody.code === 'KYD_REQUIRED') {\n throw new KYDRequiredError(errorBody);\n }\n\n throw new AstraSyncError(\n errorBody.error || `Request failed: ${res.status}`,\n res.status,\n errorBody.code\n );\n }\n\n return { status: res.status, body: (await res.json()) as T };\n }\n\n private async getAuthToken(): Promise<string> {\n // API key auth — use directly\n if (this.apiKey) {\n return this.apiKey;\n }\n\n // Email+password — login and cache JWT\n if (this.cachedJwt && this.jwtExpiresAt && Date.now() < this.jwtExpiresAt) {\n return this.cachedJwt;\n }\n\n const res = await fetch(`${this.baseUrl}/api/auth/login`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: this.email, password: this.password }),\n });\n\n if (!res.ok) {\n const errorBody = (await res.json().catch(() => ({}))) as Record<string, unknown>;\n throw new AuthenticationError(\n (errorBody.message as string) || (errorBody.error as string) || 'Login failed'\n );\n }\n\n const data = (await res.json()) as { data: { token: string } };\n this.cachedJwt = data.data.token;\n // Cache for 6 days (tokens expire in 7)\n this.jwtExpiresAt = Date.now() + 6 * 24 * 60 * 60 * 1000;\n\n return this.cachedJwt;\n }\n\n /**\n * Sign a request using secp256k1 (ethers.js).\n * Canonical message format: METHOD:ENDPOINT:SORTED_JSON_BODY\n * Must match apps/backend/src/services/signature-verify.service.ts exactly.\n */\n private async signRequest(method: string, endpoint: string, body: unknown): Promise<string> {\n const { Wallet } = await import('ethers');\n const sorted = this.sortObjectKeys(body);\n const canonical = `${method}:${endpoint}:${JSON.stringify(sorted)}`;\n const wallet = new Wallet(this.privateKey!);\n return wallet.signMessage(canonical);\n }\n\n /** Recursively sort object keys for canonical JSON representation. */\n private sortObjectKeys(obj: unknown): unknown {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map((item) => this.sortObjectKeys(item));\n }\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(obj).sort()) {\n sorted[key] = this.sortObjectKeys((obj as Record<string, unknown>)[key]);\n }\n return sorted;\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrasyncai/verification-gateway",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.1",
|
|
4
4
|
"description": "AstraSync KYA Platform SDK — counterparty verification gateway (verify incoming requests) + agent registration (register AI agents with the KYA backend).",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|