@astrasyncai/sdk
Version:
Official Node.js SDK for the AstraSync KYA Platform — register and manage AI agents with verified identities
345 lines (336 loc) • 11.9 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
// 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;
}
};
// src/cli.ts
function usage() {
console.log(`
astrasync - AstraSync KYA Platform CLI
USAGE:
astrasync [options] <command> [args]
GLOBAL OPTIONS:
--api-key <key> API key (kya_ prefixed). Also reads ASTRASYNC_API_KEY env.
--email <email> Email for login auth
--password <pass> Password for login auth
--private-key <key> secp256k1 private key for crypto signing
--base-url <url> API base URL (default: https://api.kya.astrasync.ai)
--help Show this help message
COMMANDS:
register Register a new AI agent
verify <id> Look up an agent by ASTRA ID or UUID
health Check API health
REGISTER OPTIONS:
--name <name> Agent name (required)
--description <desc> Agent description
--agent-type <type> Agent type (default: general)
--api-endpoint <url> Agent API endpoint URL
--model-name <name> LLM model name (e.g. claude-opus-4.6)
--model-provider <provider> Model provider (e.g. anthropic, openai)
--model-type <type> Model type (default: llm)
--framework-name <name> Framework name (e.g. langchain, crewai)
--framework-version <ver> Framework version
EXAMPLES:
astrasync --api-key kya_xxx register --name "My Agent"
astrasync register --name "My Agent" --model-name gpt-4o --model-provider openai
astrasync verify ASTRA-abc123
astrasync health
`);
}
function parseArgs(args) {
const globals = {};
const commandArgs = {};
let command = "";
let inCommand = false;
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (!inCommand && !arg.startsWith("--")) {
command = arg;
inCommand = true;
continue;
}
if (arg === "--help" || arg === "-h") {
globals["help"] = "true";
continue;
}
if (arg.startsWith("--")) {
const key = arg.slice(2);
const value = args[++i] || "";
if (inCommand) {
commandArgs[key] = value;
} else {
globals[key] = value;
}
}
}
return { globals, command, commandArgs };
}
async function main() {
const { globals, command, commandArgs } = parseArgs(process.argv.slice(2));
if (globals["help"] || !command) {
usage();
process.exit(command ? 0 : 1);
}
const config = {
apiKey: globals["api-key"],
email: globals["email"],
password: globals["password"],
privateKey: globals["private-key"],
baseUrl: globals["base-url"]
};
try {
if (command === "health") {
const client2 = new AstraSync({
apiKey: config.apiKey || "health-check",
baseUrl: config.baseUrl
});
const result = await client2.health();
console.log(JSON.stringify(result, null, 2));
return;
}
const client = new AstraSync({
apiKey: config.apiKey,
email: config.email,
password: config.password,
privateKey: config.privateKey,
baseUrl: config.baseUrl
});
if (command === "register") {
const name = commandArgs["name"];
if (!name) {
console.error("Error: --name is required for register command");
process.exit(1);
}
const options = {
name,
...commandArgs["description"] && { description: commandArgs["description"] },
...commandArgs["agent-type"] && { agentType: commandArgs["agent-type"] },
...commandArgs["api-endpoint"] && { apiEndpoint: commandArgs["api-endpoint"] }
};
if (commandArgs["model-name"] && commandArgs["model-provider"]) {
options.model = {
modelName: commandArgs["model-name"],
modelProvider: commandArgs["model-provider"],
...commandArgs["model-type"] && {
modelType: commandArgs["model-type"]
}
};
}
if (commandArgs["framework-name"] && commandArgs["framework-version"]) {
options.framework = {
frameworkName: commandArgs["framework-name"],
frameworkVersion: commandArgs["framework-version"]
};
}
const result = await client.register(options);
console.log(JSON.stringify(result, null, 2));
} else if (command === "verify") {
const agentId = commandArgs["id"] || process.argv[process.argv.length - 1];
if (!agentId || agentId.startsWith("--")) {
console.error("Error: agent ID is required for verify command");
process.exit(1);
}
const result = await client.verify(agentId);
console.log(JSON.stringify(result, null, 2));
} else {
console.error(`Unknown command: ${command}`);
usage();
process.exit(1);
}
} catch (error) {
if (error instanceof KYDRequiredError) {
console.error(`
Error: ${error.message}`);
if (error.ownerNotified) {
console.error("A reminder email has been sent to your registered email address.");
}
process.exit(1);
}
if (error instanceof AstraSyncError) {
console.error(`
Error [${error.code || error.statusCode}]: ${error.message}`);
process.exit(1);
}
throw error;
}
}
main();