UNPKG

@testdog/ai

Version:

SDK for integrating the Testdog AI Video Intelligence API

234 lines (229 loc) 9.77 kB
"use strict"; 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 __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; 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 )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { SdkAuthenticationError: () => SdkAuthenticationError, SdkError: () => SdkError, SdkInputError: () => SdkInputError, SdkRequestError: () => SdkRequestError, testdogAI: () => testdogAI }); module.exports = __toCommonJS(index_exports); // src/client.ts var import_axios = __toESM(require("axios")); var import_jwt_decode = require("jwt-decode"); // src/errors.ts var SdkError = class _SdkError extends Error { constructor(message) { super(message); this.name = "SdkError"; Object.setPrototypeOf(this, _SdkError.prototype); } }; var SdkAuthenticationError = class _SdkAuthenticationError extends SdkError { constructor(message) { super(message); this.name = "SdkAuthenticationError"; Object.setPrototypeOf(this, _SdkAuthenticationError.prototype); } }; var SdkRequestError = class _SdkRequestError extends SdkError { constructor(message, statusCode, details) { super(message); this.name = "SdkRequestError"; this.statusCode = statusCode; this.details = details; Object.setPrototypeOf(this, _SdkRequestError.prototype); } }; var SdkInputError = class _SdkInputError extends SdkError { constructor(message) { super(message); this.name = "SdkInputError"; Object.setPrototypeOf(this, _SdkInputError.prototype); } }; // src/client.ts var DEFAULT_API_BASE_URL = "https://ai.sheryians.com/api/v1"; var DEFAULT_IFRAME_BASE_URL = "https://ai.sheryians.com/source/chat"; var TOKEN_EXPIRY_BUFFER_SECONDS = 60; var testdogAI = class { // Store expiry timestamp (in seconds) /** * Initializes the testdogAI SDK. * @param config - SDK configuration including accessKey and secretKey. * @param config.accessKey - The access key for API authentication. * @param config.secretKey - The secret key for API authentication. * @param config.apiBaseUrl - Optional base URL for the API */ constructor(config) { this.apiAccessToken = null; this.apiAccessTokenExpiry = null; this.accessKey = config.accessKey; this.secretKey = config.secretKey; this.iframeBaseUrl = config.iframeBaseUrl || DEFAULT_IFRAME_BASE_URL; this.apiClient = import_axios.default.create({ baseURL: config.apiBaseUrl || DEFAULT_API_BASE_URL, headers: { "Content-Type": "application/json" }, withCredentials: true // Enable cookies with cross-origin requests }); } /** * Retrieves a valid API Access Token, fetching a new one if necessary. * @returns The API Access Token. * @throws {SdkAuthenticationError} If fetching the token fails due to invalid credentials. * @throws {SdkRequestError} If the API request fails for other reasons. */ async getApiAccessToken() { var _a, _b, _c, _d, _e, _f; const nowInSeconds = Math.floor(Date.now() / 1e3); if (this.apiAccessToken && this.apiAccessTokenExpiry && this.apiAccessTokenExpiry > nowInSeconds + TOKEN_EXPIRY_BUFFER_SECONDS) { return this.apiAccessToken; } console.debug("SDK: API Access Token expired or missing, fetching new token..."); try { const response = await this.apiClient.post( "/customers/generateAccessToken", {}, // Empty body { headers: { // Send keys in headers as expected by your backend endpoint "accessKey": this.accessKey, "secretKey": this.secretKey // Use the stored secret key here }, withCredentials: true // Ensure cookies are sent with this request } ); const token = response.data.token; if (!token) { throw new SdkAuthenticationError("Failed to retrieve API access token from response."); } this.apiAccessToken = token; try { const decoded = (0, import_jwt_decode.jwtDecode)(token); this.apiAccessTokenExpiry = decoded.exp; console.debug(`SDK: New API Access Token obtained, expires at ${new Date(decoded.exp * 1e3).toISOString()}`); } catch (decodeError) { console.error("SDK: Failed to decode new API access token:", decodeError); this.apiAccessToken = null; this.apiAccessTokenExpiry = null; throw new SdkAuthenticationError("Received invalid API access token format."); } return this.apiAccessToken; } catch (error) { this.apiAccessToken = null; this.apiAccessTokenExpiry = null; if (import_axios.default.isAxiosError(error)) { const axiosError = error; if (((_a = axiosError.response) == null ? void 0 : _a.status) === 401 || ((_b = axiosError.response) == null ? void 0 : _b.status) === 400) { console.error("SDK Authentication Error:", ((_c = axiosError.response) == null ? void 0 : _c.data) || axiosError.message); throw new SdkAuthenticationError("Invalid accessKey or secretKey."); } console.error("SDK API Request Error (fetching access token):", ((_d = axiosError.response) == null ? void 0 : _d.data) || axiosError.message); throw new SdkRequestError( `Failed to fetch API access token: ${axiosError.message}`, (_e = axiosError.response) == null ? void 0 : _e.status, (_f = axiosError.response) == null ? void 0 : _f.data ); } console.error("SDK Unexpected Error (fetching access token):", error); throw new SdkError("An unexpected error occurred while fetching the API access token."); } } /** * Generates a secure URL for the AI chat iframe. * @param options - Options including studentId, studentName, sourceId, and optionally iframeBaseUrl. * @returns The generated iframe URL containing a short-lived token. * @throws {SdkInputError} If required options are missing. * @throws {SdkAuthenticationError} If SDK authentication fails. * @throws {SdkRequestError} If the API request to generate the iframe token fails. */ async generateIframeUrl(options) { var _a, _b, _c, _d, _e, _f; const { studentId, studentName, sourceId } = options; if (!studentId || !studentName || !sourceId) { throw new SdkInputError("studentId, studentName, and sourceId are required to generate the iframe URL."); } try { const apiToken = await this.getApiAccessToken(); const response = await this.apiClient.post( "/iframe/generate-url-token", { studentId, studentName, sourceId }, { headers: { "Authorization": `Bearer ${apiToken}` // Use the API Access Token } } ); const iframeToken = response.data.iframeToken; if (!iframeToken) { throw new SdkRequestError("Failed to retrieve iframe token from response."); } const targetIframeBaseUrl = options.iframeBaseUrl || this.iframeBaseUrl; const iframeUrl = `${targetIframeBaseUrl}?token=${encodeURIComponent(iframeToken)}`; return iframeUrl; } catch (error) { if (error instanceof SdkAuthenticationError || error instanceof SdkInputError) { throw error; } if (import_axios.default.isAxiosError(error)) { const axiosError = error; console.error("SDK API Request Error (generating iframe token):", ((_a = axiosError.response) == null ? void 0 : _a.data) || axiosError.message); if (((_b = axiosError.response) == null ? void 0 : _b.status) === 401 || ((_c = axiosError.response) == null ? void 0 : _c.status) === 403) { this.apiAccessToken = null; this.apiAccessTokenExpiry = null; throw new SdkAuthenticationError(`API access token rejected (status: ${(_d = axiosError.response) == null ? void 0 : _d.status}). Please retry.`); } throw new SdkRequestError( `Failed to generate iframe token: ${axiosError.message}`, (_e = axiosError.response) == null ? void 0 : _e.status, (_f = axiosError.response) == null ? void 0 : _f.data ); } console.error("SDK Unexpected Error (generating iframe URL):", error); throw new SdkError("An unexpected error occurred while generating the iframe URL."); } } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { SdkAuthenticationError, SdkError, SdkInputError, SdkRequestError, testdogAI });