@astrasyncai/sdk
Version:
Official Node.js SDK for the AstraSync KYA Platform — register and manage AI agents with verified identities
168 lines (167 loc) • 5.69 kB
JavaScript
// src/errors.ts
var AstraSyncError = class extends Error {
constructor(message, statusCode, code) {
super(message);
this.name = "AstraSyncError";
this.statusCode = statusCode;
this.code = code;
}
};
var KYDRequiredError = class extends AstraSyncError {
constructor(response) {
const kydUrl = response.kydUrl || "https://app.kya.astrasync.ai/developer-profile";
super(
`KYD verification required before registering agents.
Complete your KYD profile at: ${kydUrl}`,
403,
"KYD_REQUIRED"
);
this.name = "KYDRequiredError";
this.kydUrl = kydUrl;
this.ownerNotified = response.ownerNotified || false;
}
};
var AuthenticationError = class extends AstraSyncError {
constructor(message) {
super(message, 401, "AUTH_FAILED");
this.name = "AuthenticationError";
}
};
// src/api.ts
var DEFAULT_BASE_URL = "https://api.kya.astrasync.ai";
var AstraSync = class {
constructor(config = {}) {
this.baseUrl = (config.baseUrl || process.env.ASTRASYNC_API_URL || DEFAULT_BASE_URL).replace(/\/+$/, "");
this.apiKey = config.apiKey || process.env.ASTRASYNC_API_KEY;
this.email = config.email;
this.password = config.password;
this.privateKey = config.privateKey;
if (!this.apiKey && !this.email) {
throw new AuthenticationError(
"Authentication required. Provide apiKey, or email+password. Set ASTRASYNC_API_KEY env var or pass config to constructor."
);
}
if (this.email && !this.password) {
throw new AuthenticationError("Password is required when using email authentication.");
}
}
/**
* Register a new AI agent on the AstraSync KYA Platform.
* Sends full payload including model, framework, PDLSS, and metadata.
*/
async register(options) {
const body = {
name: options.name,
...options.description && { description: options.description },
...options.agentType && { agentType: options.agentType },
...options.apiEndpoint && { apiEndpoint: options.apiEndpoint },
...options.model && { model: options.model },
...options.framework && { framework: options.framework },
...options.metadata && { metadata: options.metadata },
...options.pdlss && { pdlss: options.pdlss }
};
return this.request("POST", "/api/agents/register", body);
}
/**
* Look up an agent's public profile by ASTRA ID or UUID.
*/
async verify(agentId) {
return this.request("GET", `/api/agents/verify/${agentId}`);
}
/**
* Check API health.
*/
async health() {
const res = await fetch(`${this.baseUrl}/api/health/`);
if (!res.ok) {
throw new AstraSyncError(`Health check failed: ${res.status}`, res.status);
}
return res.json();
}
// ── Private helpers ──────────────────────────────────────────────
async request(method, endpoint, body) {
const url = `${this.baseUrl}${endpoint}`;
const headers = {
"Content-Type": "application/json"
};
const token = await this.getAuthToken();
headers["Authorization"] = `Bearer ${token}`;
if (this.privateKey) {
const signature = await this.signRequest(method, endpoint, body || {});
headers["X-AstraSync-Signature"] = signature;
}
const res = await fetch(url, {
method,
headers,
...body ? { body: JSON.stringify(body) } : {}
});
if (!res.ok) {
const errorBody = await res.json().catch(() => ({ error: res.statusText }));
if (res.status === 403 && errorBody.code === "KYD_REQUIRED") {
throw new KYDRequiredError(errorBody);
}
throw new AstraSyncError(
errorBody.error || `Request failed: ${res.status}`,
res.status,
errorBody.code
);
}
return res.json();
}
async getAuthToken() {
if (this.apiKey) {
return this.apiKey;
}
if (this.cachedJwt && this.jwtExpiresAt && Date.now() < this.jwtExpiresAt) {
return this.cachedJwt;
}
const res = await fetch(`${this.baseUrl}/api/auth/login`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: this.email, password: this.password })
});
if (!res.ok) {
const errorBody = await res.json().catch(() => ({}));
throw new AuthenticationError(
errorBody.message || errorBody.error || "Login failed"
);
}
const data = await res.json();
this.cachedJwt = data.data.token;
this.jwtExpiresAt = Date.now() + 6 * 24 * 60 * 60 * 1e3;
return this.cachedJwt;
}
/**
* Sign a request using secp256k1 (ethers.js).
* Canonical message format: METHOD:ENDPOINT:SORTED_JSON_BODY
* Must match apps/backend/src/services/signature-verify.service.ts exactly.
*/
async signRequest(method, endpoint, body) {
const { Wallet } = await import("ethers");
const sorted = this.sortObjectKeys(body);
const canonical = `${method}:${endpoint}:${JSON.stringify(sorted)}`;
const wallet = new Wallet(this.privateKey);
return wallet.signMessage(canonical);
}
/** Recursively sort object keys for canonical JSON representation. */
sortObjectKeys(obj) {
if (obj === null || typeof obj !== "object") {
return obj;
}
if (Array.isArray(obj)) {
return obj.map((item) => this.sortObjectKeys(item));
}
const sorted = {};
for (const key of Object.keys(obj).sort()) {
sorted[key] = this.sortObjectKeys(obj[key]);
}
return sorted;
}
};
export {
AstraSync,
AstraSyncError,
AuthenticationError,
KYDRequiredError
};
//# sourceMappingURL=index.mjs.map