@noves/intent-typescript-sdk
Version:
Noves Intent Typescript SDK
177 lines (176 loc) • 7.11 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClientSideIntentSDK = void 0;
const base_1 = require("../shared/base");
const errors_1 = require("../shared/errors");
const types_1 = require("../shared/types");
const types_2 = require("../shared/types");
class ClientSideIntentSDK extends base_1.IntentSDKBase {
activeWebSocketConnections = new Map();
wsUrl;
constructor() {
super({
apiUrl: types_1.IntentEndpoints.API_URL,
grpcUrl: types_1.IntentEndpoints.WS_URL
});
this.wsUrl = types_1.IntentEndpoints.WS_URL;
}
async loadIntents() {
try {
const response = await fetch(`${types_1.IntentEndpoints.API_URL}/intents`);
if (!response.ok) {
throw new Error(`Failed to fetch intents: ${response.statusText}`);
}
const serverIntents = await response.json();
this.intents = serverIntents;
}
catch (error) {
console.error('Failed to load intents:', error);
this.intents = [];
}
}
async getValue(intentId, params = {}, pageSize) {
await this.ensureInitialized();
const intent = this.intents.find(i => i.id === intentId);
if (!intent) {
throw new errors_1.IntentSDKError(`Intent ${intentId} not found`);
}
if (!(0, types_2.isValueIntent)(intent)) {
throw new errors_1.IntentSDKError(`Intent ${intentId} is not a value intent`);
}
try {
const response = await fetch(`${types_1.IntentEndpoints.API_URL}/intents`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
id: intentId,
params,
pageSize
}),
});
if (!response.ok) {
throw new errors_1.IntentSDKError(`Failed to fetch intent data: ${response.statusText}`);
}
return await response.json();
}
catch (error) {
console.error('Intent execution error:', error);
throw new errors_1.IntentSDKError(error instanceof Error ? error.message : 'Failed to execute intent');
}
}
async getStream(intentId, params, onData, onError, onComplete) {
await this.ensureInitialized();
const intent = this.intents.find(i => i.id === intentId);
if (!intent) {
throw new errors_1.IntentSDKError(`Intent ${intentId} not found`);
}
if (!(0, types_2.isStreamIntent)(intent)) {
throw new errors_1.IntentSDKError(`Intent ${intentId} is not a stream intent`);
}
if (this.activeWebSocketConnections.has(intentId)) {
throw new errors_1.IntentSDKError(`Stream already exists for intent ${intentId}`);
}
const queryParams = new URLSearchParams({
id: intentId,
cusRateLimit: "1.0",
...this.stringifyParams(params),
});
return new Promise((resolve, reject) => {
try {
const wsUrlWithParams = `${this.wsUrl}?${queryParams.toString()}`;
const ws = new WebSocket(wsUrlWithParams);
let isConnected = false;
ws.onopen = () => {
isConnected = true;
resolve();
};
ws.onmessage = (event) => {
try {
// Handle actual data messages
if (typeof event.data === 'string' &&
(event.data.startsWith('{') || event.data.startsWith('['))) {
const response = JSON.parse(event.data);
if (response.error) {
onError?.(new Error(response.error));
return;
}
onData(response);
}
else {
// Handle other non-JSON data
onData(event.data);
}
}
catch (error) {
console.error('Parse error:', error);
onError?.(error);
}
};
ws.onerror = (error) => {
console.error('WebSocket error:', error);
onError?.(new errors_1.IntentSDKError('WebSocket connection error'));
if (isConnected) {
this.activeWebSocketConnections.delete(intentId);
}
reject(error);
};
ws.onclose = (event) => {
this.activeWebSocketConnections.delete(intentId);
// Only treat it as an error if it wasn't an intentional close
if (event.code === 4000) {
onError?.(new errors_1.IntentSDKError('Invalid message format or protocol error'));
}
else if (event.code !== 1000 && event.code !== 1005) {
// 1005 is also a normal close
onError?.(new errors_1.IntentSDKError(`WebSocket closed unexpectedly with code ${event.code}`));
}
if (isConnected) {
onComplete?.();
}
};
this.activeWebSocketConnections.set(intentId, ws);
}
catch (error) {
console.error('Stream setup error:', error);
onError?.(error);
reject(error);
}
});
}
stringifyParams(params) {
return Object.entries(params).reduce((acc, [key, value]) => ({
...acc,
[key]: String(value)
}), {});
}
stopStream(intentId) {
const ws = this.activeWebSocketConnections.get(intentId);
if (ws) {
ws.close();
this.activeWebSocketConnections.delete(intentId);
}
}
async getIntents() {
await this.ensureInitialized();
return this.intents;
}
async executeIntent(intentId, params) {
const intent = this.intents.find(i => i.id === intentId);
if (!intent) {
throw new errors_1.IntentSDKError("Intent not found");
}
if (intent.mode.includes('value')) {
return this.getValue(intentId, params);
}
else if (intent.mode.includes('stream')) {
return new Promise((resolve, reject) => {
this.getStream(intentId, // Cast to StreamableIntentId since we verified it exists
params, resolve, reject);
});
}
throw new errors_1.IntentSDKError("Invalid intent mode");
}
}
exports.ClientSideIntentSDK = ClientSideIntentSDK;