@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 CHANGED
@@ -105,35 +105,109 @@ if (result.verified && result.accessLevel !== 'none') {
105
105
 
106
106
  ### Agent Registration
107
107
 
108
- Register an AI agent with the KYA backend in code (the `astrasync` CLI does the same thing from a shell).
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 { AstraSync } from '@astrasyncai/verification-gateway/registration';
128
+ import {
129
+ AstraSync,
130
+ RegistrationDeniedError,
131
+ RegistrationTimeoutError,
132
+ } from '@astrasyncai/verification-gateway/registration';
112
133
 
113
- const astrasync = new AstraSync({
114
- apiKey: process.env.ASTRASYNC_API_KEY, // or { email, password }
115
- // Optional: privateKey for secp256k1 request signing
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
- const result = await astrasync.register({
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
- description: 'Reconciles AP/AR across accounting systems.',
122
- agentType: 'autonomous',
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
- console.log(`Agent registered: ${result.agent.astraId}`);
136
- console.log(`Trust score: ${result.agent.trustScore}`); // dynamic; recomputed on every verify-access call
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
- --pdlss '{"purpose":{"allowed":["accounting.read","accounting.write"]}, ...}'
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.
@@ -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
- * Sends full payload including model, framework, PDLSS, and metadata.
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
- return this.request("POST", "/api/agents/register", body);
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
- /** Response from agent registration. */
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
- * Sends full payload including model, framework, PDLSS, and metadata.
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<RegistrationResponse>;
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
- /** Response from agent registration. */
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
- * Sends full payload including model, framework, PDLSS, and metadata.
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<RegistrationResponse>;
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
- * Sends full payload including model, framework, PDLSS, and metadata.
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
- return this.request("POST", "/api/agents/register", body);
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
- * Sends full payload including model, framework, PDLSS, and metadata.
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
- return this.request("POST", "/api/agents/register", body);
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":";AAGO,IAAM,iBAAN,cAA6B,MAAM;AAAA,EAIxC,YAAY,SAAiB,YAAoB,MAAe;AAC9D,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,aAAa;AAClB,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,mBAAN,cAA+B,eAAe;AAAA,EAInD,YAAY,UAA4B;AACtC,UAAM,SAAS,SAAS,UAAU;AAClC;AAAA,MACE;AAAA,gCAAuF,MAAM;AAAA,MAC7F;AAAA,MACA;AAAA,IACF;AACA,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,gBAAgB,SAAS,iBAAiB;AAAA,EACjD;AACF;AAGO,IAAM,sBAAN,cAAkC,eAAe;AAAA,EACtD,YAAY,SAAiB;AAC3B,UAAM,SAAS,KAAK,aAAa;AACjC,SAAK,OAAO;AAAA,EACd;AACF;AAOO,IAAM,0BAAN,cAAsC,eAAe;AAAA,EAI1D,YAAY,WAAmB,QAAiB;AAC9C;AAAA,MACE,wBAAwB,SAAS,oCAAoC,SAAS,YAAY,MAAM,KAAK,EAAE;AAAA,MACvG;AAAA,MACA;AAAA,IACF;AACA,SAAK,OAAO;AACZ,SAAK,YAAY;AACjB,SAAK,SAAS;AAAA,EAChB;AACF;AAMO,IAAM,2BAAN,cAAuC,eAAe;AAAA,EAG3D,YAAY,WAAmB;AAC7B;AAAA,MACE,wBAAwB,SAAS;AAAA,MACjC;AAAA,MACA;AAAA,IACF;AACA,SAAK,OAAO;AACZ,SAAK,YAAY;AAAA,EACnB;AACF;AAQO,IAAM,2BAAN,cAAuC,eAAe;AAAA,EAG3D,YAAY,WAAmB;AAC7B;AAAA,MACE,gEAAgE,SAAS;AAAA,MACzE;AAAA,MACA;AAAA,IACF;AACA,SAAK,OAAO;AACZ,SAAK,YAAY;AAAA,EACnB;AACF;;;AC5EA,IAAM,mBAAmB;AAEzB,IAAM,QAAQ,CAAC,OAA8B,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC;AAgB1E,IAAM,YAAN,MAAgB;AAAA,EASrB,YAAY,SAA0B,CAAC,GAAG;AACxC,SAAK,WAAW,OAAO,WAAW,QAAQ,IAAI,qBAAqB,kBAAkB;AAAA,MACnF;AAAA,MACA;AAAA,IACF;AAEA,SAAK,SAAS,OAAO,UAAU,QAAQ,IAAI;AAC3C,SAAK,QAAQ,OAAO;AACpB,SAAK,WAAW,OAAO;AACvB,SAAK,aAAa,OAAO;AAEzB,QAAI,CAAC,KAAK,UAAU,CAAC,KAAK,OAAO;AAC/B,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AAEA,QAAI,KAAK,SAAS,CAAC,KAAK,UAAU;AAChC,YAAM,IAAI,oBAAoB,uDAAuD;AAAA,IACvF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmCA,MAAM,SACJ,SACuC;AACvC,UAAM,OAAgC;AAAA,MACpC,MAAM,QAAQ;AAAA,MACd,GAAI,QAAQ,eAAe,EAAE,aAAa,QAAQ,YAAY;AAAA,MAC9D,GAAI,QAAQ,aAAa,EAAE,WAAW,QAAQ,UAAU;AAAA,MACxD,GAAI,QAAQ,eAAe,EAAE,aAAa,QAAQ,YAAY;AAAA,MAC9D,GAAI,QAAQ,SAAS,EAAE,OAAO,QAAQ,MAAM;AAAA,MAC5C,GAAI,QAAQ,aAAa,EAAE,WAAW,QAAQ,UAAU;AAAA,MACxD,GAAI,QAAQ,aAAa,EAAE,WAAW,QAAQ,UAAU;AAAA,MACxD,GAAI,QAAQ,YAAY,EAAE,UAAU,QAAQ,SAAS;AAAA,MACrD,GAAI,QAAQ,SAAS,EAAE,OAAO,QAAQ,MAAM;AAAA,IAC9C;AAEA,UAAM,EAAE,QAAQ,MAAM,IAAI,IAAI,MAAM,KAAK,kBAEvC,QAAQ,wBAAwB,IAAI;AAEtC,QAAI,WAAW,KAAK;AAClB,YAAM,SAAyB;AAAA,QAC7B,QAAQ;AAAA,QACR,OAAQ,IAA6B,KAAK;AAAA,MAC5C;AACA,aAAO;AAAA,IACT;AAGA,UAAM,cAAc;AACpB,UAAM,UAA0B;AAAA,MAC9B,QAAQ;AAAA,MACR,WAAW,YAAY;AAAA,MACvB,WAAW,YAAY;AAAA,MACvB,SAAS,YAAY;AAAA,MACrB,SAAS,YAAY;AAAA,IACvB;AAEA,QAAI,CAAC,QAAQ,gBAAiB,QAAO;AAErC,WAAO,KAAK,gBAAgB,YAAY,WAAW,OAAO;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,iBAAiB,WAAoD;AACzE,UAAM,MAAM,GAAG,KAAK,OAAO,oCAAoC,SAAS;AACxE,UAAM,MAAM,MAAM,MAAM,KAAK,EAAE,SAAS,EAAE,QAAQ,mBAAmB,EAAE,CAAC;AACxE,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,UAAW,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAClD,YAAM,IAAI;AAAA,QACR,QAAQ,SAAS,4BAA4B,IAAI,MAAM;AAAA,QACvD,IAAI;AAAA,QACJ,QAAQ;AAAA,MACV;AAAA,IACF;AACA,WAAQ,MAAM,IAAI,KAAK;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,gBACJ,WACA,UAAkC,CAAC,GACb;AACtB,UAAM,YAAY,QAAQ,aAAa,KAAK,KAAK;AACjD,UAAM,iBAAiB,QAAQ,kBAAkB;AACjD,UAAM,QAAQ,KAAK,IAAI;AACvB,UAAM,WAAW,QAAQ;AAEzB,WAAO,KAAK,IAAI,IAAI,UAAU;AAC5B,YAAM,SAAS,MAAM,KAAK,iBAAiB,SAAS;AACpD,YAAM,QAAQ,KAAK,IAAI,IAAI;AAC3B,cAAQ,YAAY,EAAE,WAAW,MAAM,CAAC;AAExC,UAAI,OAAO,UAAU,YAAY;AAC/B,YAAI,CAAC,OAAO,OAAO;AACjB,gBAAM,IAAI;AAAA,YACR,gBAAgB,SAAS;AAAA,YACzB;AAAA,UACF;AAAA,QACF;AACA,eAAO,OAAO;AAAA,MAChB;AACA,UAAI,OAAO,UAAU,UAAU;AAC7B,cAAM,IAAI,wBAAwB,WAAW,OAAO,MAAM;AAAA,MAC5D;AACA,UAAI,OAAO,UAAU,WAAW;AAC9B,cAAM,IAAI,yBAAyB,SAAS;AAAA,MAC9C;AACA,YAAM,MAAM,cAAc;AAAA,IAC5B;AACA,UAAM,IAAI,yBAAyB,SAAS;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,SAA0C;AACrD,WAAO,KAAK,QAAwB,OAAO,sBAAsB,OAAO,EAAE;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAkC;AACtC,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,OAAO,cAAc;AACrD,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,IAAI,eAAe,wBAAwB,IAAI,MAAM,IAAI,IAAI,MAAM;AAAA,IAC3E;AACA,WAAO,IAAI,KAAK;AAAA,EAClB;AAAA;AAAA,EAIA,MAAc,QAAW,QAAgB,UAAkB,MAA4B;AACrF,UAAM,EAAE,MAAM,OAAO,IAAI,MAAM,KAAK,kBAAqB,QAAQ,UAAU,IAAI;AAC/E,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,kBACZ,QACA,UACA,MACsC;AACtC,UAAM,MAAM,GAAG,KAAK,OAAO,GAAG,QAAQ;AACtC,UAAM,UAAkC;AAAA,MACtC,gBAAgB;AAAA,IAClB;AAGA,UAAM,QAAQ,MAAM,KAAK,aAAa;AACtC,YAAQ,eAAe,IAAI,UAAU,KAAK;AAG1C,QAAI,KAAK,YAAY;AACnB,YAAM,YAAY,MAAM,KAAK,YAAY,QAAQ,UAAU,QAAQ,CAAC,CAAC;AACrE,cAAQ,uBAAuB,IAAI;AAAA,IACrC;AAEA,UAAM,MAAM,MAAM,MAAM,KAAK;AAAA,MAC3B;AAAA,MACA;AAAA,MACA,GAAI,OAAO,EAAE,MAAM,KAAK,UAAU,IAAI,EAAE,IAAI,CAAC;AAAA,IAC/C,CAAC;AAED,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,YAAa,MAAM,IACtB,KAAK,EACL,MAAM,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE;AAG1C,UAAI,IAAI,WAAW,OAAO,UAAU,SAAS,gBAAgB;AAC3D,cAAM,IAAI,iBAAiB,SAAS;AAAA,MACtC;AAEA,YAAM,IAAI;AAAA,QACR,UAAU,SAAS,mBAAmB,IAAI,MAAM;AAAA,QAChD,IAAI;AAAA,QACJ,UAAU;AAAA,MACZ;AAAA,IACF;AAEA,WAAO,EAAE,QAAQ,IAAI,QAAQ,MAAO,MAAM,IAAI,KAAK,EAAQ;AAAA,EAC7D;AAAA,EAEA,MAAc,eAAgC;AAE5C,QAAI,KAAK,QAAQ;AACf,aAAO,KAAK;AAAA,IACd;AAGA,QAAI,KAAK,aAAa,KAAK,gBAAgB,KAAK,IAAI,IAAI,KAAK,cAAc;AACzE,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,OAAO,mBAAmB;AAAA,MACxD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,OAAO,KAAK,OAAO,UAAU,KAAK,SAAS,CAAC;AAAA,IACrE,CAAC;AAED,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,YAAa,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AACpD,YAAM,IAAI;AAAA,QACP,UAAU,WAAuB,UAAU,SAAoB;AAAA,MAClE;AAAA,IACF;AAEA,UAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,SAAK,YAAY,KAAK,KAAK;AAE3B,SAAK,eAAe,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,KAAK;AAEpD,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,YAAY,QAAgB,UAAkB,MAAgC;AAC1F,UAAM,EAAE,OAAO,IAAI,MAAM,OAAO,QAAQ;AACxC,UAAM,SAAS,KAAK,eAAe,IAAI;AACvC,UAAM,YAAY,GAAG,MAAM,IAAI,QAAQ,IAAI,KAAK,UAAU,MAAM,CAAC;AACjE,UAAM,SAAS,IAAI,OAAO,KAAK,UAAW;AAC1C,WAAO,OAAO,YAAY,SAAS;AAAA,EACrC;AAAA;AAAA,EAGQ,eAAe,KAAuB;AAC5C,QAAI,QAAQ,QAAQ,OAAO,QAAQ,UAAU;AAC3C,aAAO;AAAA,IACT;AACA,QAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,aAAO,IAAI,IAAI,CAAC,SAAS,KAAK,eAAe,IAAI,CAAC;AAAA,IACpD;AACA,UAAM,SAAkC,CAAC;AACzC,eAAW,OAAO,OAAO,KAAK,GAAG,EAAE,KAAK,GAAG;AACzC,aAAO,GAAG,IAAI,KAAK,eAAgB,IAAgC,GAAG,CAAC;AAAA,IACzE;AACA,WAAO;AAAA,EACT;AACF;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrasyncai/verification-gateway",
3
- "version": "2.4.0",
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",