@infactory/infactory-ts
Version:
Infactory TypeScript SDK for use with Infactory Workshop, MCP Server and API
1,507 lines (1,496 loc) • 131 kB
JavaScript
'use strict';
var path = require('path');
var fs = require('fs');
var buffer = require('buffer');
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var path__namespace = /*#__PURE__*/_interopNamespace(path);
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
// src/errors/index.ts
function _process_error_message(message) {
if (message === void 0 || message === null) {
message = "";
} else if (typeof message !== "string") {
message = JSON.stringify(message);
}
return message;
}
var InfactoryAPIError = class _InfactoryAPIError extends Error {
constructor(status, code, message, requestId, details) {
super(message);
this.status = status;
this.code = code;
this.requestId = requestId;
this.details = details;
this.name = "InfactoryAPIError";
Object.setPrototypeOf(this, _InfactoryAPIError.prototype);
}
/**
* Convert error to a plain object for serialization
*/
toJSON() {
return {
name: this.name,
status: this.status,
code: this.code,
message: this.message,
requestId: this.requestId,
details: this.details
};
}
};
var AuthenticationError = class _AuthenticationError extends InfactoryAPIError {
constructor(message, requestId, details) {
super(401, "authentication_error", message, requestId, details);
this.name = "AuthenticationError";
Object.setPrototypeOf(this, _AuthenticationError.prototype);
}
};
var PermissionError = class _PermissionError extends InfactoryAPIError {
constructor(message, requestId, details) {
super(403, "permission_denied", message, requestId, details);
this.name = "PermissionError";
Object.setPrototypeOf(this, _PermissionError.prototype);
}
};
var NotFoundError = class _NotFoundError extends InfactoryAPIError {
constructor(message, requestId, details) {
super(404, "not_found", message, requestId, details);
this.name = "NotFoundError";
Object.setPrototypeOf(this, _NotFoundError.prototype);
}
};
var ValidationError = class _ValidationError extends InfactoryAPIError {
constructor(message, requestId, details) {
super(422, "validation_error", message, requestId, details);
this.name = "ValidationError";
Object.setPrototypeOf(this, _ValidationError.prototype);
}
};
var ConflictError = class _ConflictError extends InfactoryAPIError {
constructor(message, requestId, details) {
super(409, "conflict", message, requestId, details);
this.name = "ConflictError";
Object.setPrototypeOf(this, _ConflictError.prototype);
}
};
var RateLimitError = class _RateLimitError extends InfactoryAPIError {
constructor(message, requestId, details) {
super(429, "rate_limit_exceeded", message, requestId, details);
this.name = "RateLimitError";
Object.setPrototypeOf(this, _RateLimitError.prototype);
}
};
var ServerError = class _ServerError extends InfactoryAPIError {
constructor(message, requestId, details) {
super(500, "server_error", message, requestId, details);
this.name = "ServerError";
Object.setPrototypeOf(this, _ServerError.prototype);
}
};
var ServiceUnavailableError = class _ServiceUnavailableError extends InfactoryAPIError {
constructor(message, requestId, details) {
super(503, "service_unavailable", message, requestId, details);
this.name = "ServiceUnavailableError";
Object.setPrototypeOf(this, _ServiceUnavailableError.prototype);
}
};
var NetworkError = class _NetworkError extends InfactoryAPIError {
constructor(message, details) {
super(0, "network_error", message, void 0, details);
this.name = "NetworkError";
Object.setPrototypeOf(this, _NetworkError.prototype);
}
};
function createErrorFromStatus(status, code = "unknown_error", message, requestId, details) {
message = _process_error_message(message);
switch (status) {
case 400:
return new ValidationError(message, requestId, details);
case 401:
return new AuthenticationError(message, requestId, details);
case 403:
return new PermissionError(message, requestId, details);
case 404:
return new NotFoundError(message, requestId, details);
case 409:
return new ConflictError(message, requestId, details);
case 422:
return new ValidationError(message, requestId, details);
case 429:
return new RateLimitError(message, requestId, details);
case 503:
return new ServiceUnavailableError(message, requestId, details);
default:
if (status >= 500) {
return new ServerError(message, requestId, details);
}
return new InfactoryAPIError(status, code, message, requestId, details);
}
}
// src/core/http-client.ts
var SDK_VERSION = "0.6.4";
var API_BASE_URL = "/api/infactory";
function toSnakeCase(key) {
if (key.includes("-")) {
return key;
}
return key.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
}
function toCamelCase(key) {
return key.replace(
/_([a-z])/g,
(_, letter) => letter.toUpperCase()
);
}
function decamelizeKeys(obj) {
if (Array.isArray(obj)) {
return obj.map(decamelizeKeys);
} else if (obj !== null && typeof obj === "object") {
return Object.keys(obj).reduce((result, key) => {
const newKey = toSnakeCase(key);
const newResult = decamelizeKeys(obj[key]);
result[newKey] = newResult;
return result;
}, {});
}
return obj;
}
function camelizeKeys(obj) {
if (Array.isArray(obj)) {
return obj.map(camelizeKeys);
} else if (obj !== null && typeof obj === "object") {
return Object.keys(obj).reduce(
(result, key) => {
const newKey = key === "_id" ? "id" : toCamelCase(key);
result[newKey] = camelizeKeys(obj[key]);
return result;
},
{}
);
}
return obj;
}
var HttpClient = class {
/**
* Creates a new HTTP client instance.
* @param options - Configuration options for the client.
*/
constructor(options) {
this.requestInterceptors = [];
this.responseInterceptors = [];
this.baseUrl = options.baseUrl.replace(/\/$/, "");
this.apiKey = options.apiKey;
this.fetchImpl = options.fetch || globalThis.fetch;
this.defaultHeaders = options.defaultHeaders || {};
this.isServer = options.isServer ?? typeof window === "undefined";
this.authIn = options.authIn || "header";
this.defaultHeaders["x-infactory-sdk-version"] = SDK_VERSION;
this.addRequestInterceptor((request) => {
if (request.params) {
request.params = decamelizeKeys(request.params) || {};
}
if (request.jsonBody) {
request.jsonBody = decamelizeKeys(request.jsonBody);
}
return request;
});
this.addResponseInterceptor(
async (response, _request) => {
const contentType = response.headers.get("content-type");
if (contentType?.includes("application/json")) {
const clonedResponse = response.clone();
const data = await clonedResponse.json();
const camelizedData = camelizeKeys(data);
return new Response(JSON.stringify(camelizedData), {
status: response.status,
statusText: response.statusText,
headers: response.headers
});
}
return response;
}
);
}
/**
* Gets the configured API key.
* @returns The API key or empty string if not set.
*/
getApiKey() {
return this.apiKey || "";
}
/**
* Gets the configured base URL.
* @returns The base URL.
*/
getBaseUrl() {
return this.baseUrl;
}
getIsServer() {
return this.isServer;
}
/**
* Adds a request interceptor to the chain.
* @param interceptor - The request interceptor function.
* @returns This HTTP client instance for chaining.
*/
addRequestInterceptor(interceptor) {
this.requestInterceptors.push(interceptor);
return this;
}
/**
* Adds a response interceptor to the chain.
* @param interceptor - The response interceptor function.
* @returns This HTTP client instance for chaining.
*/
addResponseInterceptor(interceptor) {
this.responseInterceptors.push(interceptor);
return this;
}
/**
* Executes an HTTP request with the configured settings and interceptors.
* @param request - The HTTP request configuration.
* @returns A promise resolving to the response with data of type T.
*/
async request(request) {
try {
let processedRequest = { ...request };
for (const interceptor of this.requestInterceptors) {
processedRequest = await interceptor(processedRequest);
}
const { url, options } = this.prepareRequest(processedRequest);
let response = await this.fetchImpl(url, options);
for (const interceptor of this.responseInterceptors) {
response = await interceptor(response, processedRequest);
}
return this.processResponse(response);
} catch (error) {
return this.handleRequestError(error);
}
}
/**
* Executes an HTTP GET request.
* @param endpoint - The API endpoint path.
* @param params - Optional query parameters.
* @param options - Optional fetch options.
* @returns A promise resolving to the response with data of type T.
*/
async get(endpoint, params = {}, options = {}) {
return this.request({
url: endpoint,
method: "GET",
params,
...options
});
}
/**
* Executes an HTTP POST request.
* @param endpoint - The API endpoint path.
* @param body - Optional request body (will be JSON serialized).
* @param params - Optional query parameters.
* @param options - Optional fetch options.
* @returns A promise resolving to the response with data of type T.
*/
async post(endpoint, body, options = {}) {
return this.request({
url: endpoint,
method: "POST",
jsonBody: body,
...options
});
}
/**
* Executes an HTTP PUT request.
* @param endpoint - The API endpoint path.
* @param body - Optional request body (will be JSON serialized).
* @param params - Optional query parameters.
* @param options - Optional fetch options.
* @returns A promise resolving to the response with data of type T.
*/
async put(endpoint, body, params = {}, options = {}) {
return this.request({
url: endpoint,
method: "PUT",
params,
jsonBody: body,
...options
});
}
/**
* Executes an HTTP PATCH request.
* @param endpoint - The API endpoint path.
* @param body - Optional request body (will be JSON serialized).
* @param params - Optional query parameters.
* @param options - Optional fetch options.
* @returns A promise resolving to the response with data of type T.
*/
async patch(endpoint, body, options = {}) {
return this.request({
url: endpoint,
method: "PATCH",
jsonBody: body,
...options
});
}
/**
* Executes an HTTP DELETE request.
* @param endpoint - The API endpoint path.
* @param params - Optional query parameters.
* @param options - Optional fetch options.
* @returns A promise resolving to the response with data of type T.
*/
async delete(endpoint, params = {}, options = {}) {
return this.request({
url: endpoint,
method: "DELETE",
params,
...options
});
}
/**
* Uploads a file to the API endpoint.
* @param endpoint - The API endpoint path.
* @param file - The file to upload.
* @param formFields - Additional form fields to include.
* @param params - Optional query parameters.
* @param options - Optional fetch options.
* @returns A promise resolving to the response with data of type T.
*/
async uploadFile(endpoint, file, formFields = {}, params = {}, options = {}) {
const formData = new FormData();
formData.append("file", file);
Object.entries(formFields).forEach(([key, value]) => {
if (value !== void 0 && value !== null) {
formData.append(key, String(value));
}
});
return this.request({
url: endpoint,
method: "POST",
params,
body: formData,
...options
});
}
/**
* Downloads a file from the API endpoint.
* @param endpoint - The API endpoint path.
* @param params - Optional query parameters.
* @param defaultFilename - The default filename to use if not specified in headers.
* @returns A promise resolving to the response with download info of type T.
*/
async downloadFile(endpoint, params = {}, defaultFilename = "download.file", options = {}) {
try {
const { url, options: requestOptions } = this.prepareRequest({
url: endpoint,
method: "GET",
params,
...options
});
if (this.isServer) {
return this.request({
url: endpoint,
method: "GET",
params,
...options
});
}
const response = await this.fetchImpl(url, requestOptions);
if (!response.ok) {
throw new Error(
`Download failed: ${response.status} ${response.statusText}`
);
}
const contentDisposition = response.headers.get("content-disposition");
let filename = defaultFilename;
if (contentDisposition) {
const filenameMatch = contentDisposition.match(/filename="?([^"]+)"?/);
if (filenameMatch && filenameMatch[1]) {
filename = filenameMatch[1];
}
}
const blob = await response.blob();
const objectUrl = window.URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = objectUrl;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(objectUrl);
return { data: { success: true, filename } };
} catch (error) {
return this.handleRequestError(error);
}
}
/**
* Creates a streaming request to the API endpoint.
* @param endpoint - The API endpoint path.
* @param options - The fetch options for the request.
* @param signal - Optional abort signal for cancellation.
* @returns A promise resolving to a readable stream.
*/
async createStream(endpoint, options, signal) {
let processedRequest = { ...options, url: endpoint };
for (const interceptor of this.requestInterceptors) {
processedRequest = await interceptor(processedRequest);
}
const { url, options: requestOptions } = this.prepareRequest(processedRequest);
if (signal) {
requestOptions.signal = signal;
}
const response = await this.fetchImpl(url, requestOptions);
if (!response.ok) {
let errorData = {};
let errorMessage = "";
try {
const contentType = response.headers.get("content-type");
if (contentType && contentType.includes("application/json")) {
const errorBody = await response.json();
errorData = errorBody;
errorMessage = errorBody.message || errorBody.detail || `API request failed with status: ${response.status}`;
} else {
const errorBody = await response.text();
errorMessage = `API ${requestOptions.method} request failed ${response.status}: ${errorBody}`;
}
} catch {
errorMessage = `API request failed with status: ${response.status}`;
}
const requestId = response.headers.get("x-request-id") || void 0;
const error = createErrorFromStatus(
response.status,
errorData.code || "api_error",
errorMessage,
requestId,
errorData.details || errorData
);
if (response.status >= 500) {
throw error;
}
throw error;
}
const stream = response.body;
if (!stream) {
throw new Error("Response does not contain a readable stream");
}
return stream;
}
/**
* Prepares the request URL and options.
* @param request - The HTTP request configuration.
* @returns The prepared URL and fetch options.
*/
prepareRequest(request) {
const {
url: endpoint,
params: requestParams,
jsonBody,
...options
} = request;
let params = requestParams;
options.method = (options.method || "GET").toUpperCase();
const headers = new Headers(this.defaultHeaders);
if (jsonBody) {
headers.set("Content-Type", "application/json");
options.body = JSON.stringify(jsonBody);
}
if (this.authIn === "header") {
if (this.apiKey) {
headers.set("Authorization", `Bearer ${this.apiKey}`);
}
} else if (this.authIn === "query") {
if (this.apiKey) {
params = { ...params || {}, nf_api_key: this.apiKey };
}
} else if (this.authIn === "cookie") {
if (!this.isServer && typeof document !== "undefined" && document.cookie) {
headers.set("Cookie", document.cookie);
} else {
throw new AuthenticationError(
"Cookie-based authentication is only supported in browser environments"
);
}
}
const fullUrl = this.buildUrl(endpoint, params);
return {
url: fullUrl,
options: {
...options,
headers,
credentials: "include"
}
};
}
/**
* Processes an HTTP response.
* @param response - The fetch response object.
* @returns A promise resolving to the processed API response.
*/
async processResponse(response) {
if (!response.ok) {
let errorData = {};
let errorMessage = "";
try {
const contentType2 = response.headers.get("content-type");
if (contentType2 && contentType2.includes("application/json")) {
const errorBody = await response.json();
errorData = errorBody;
errorMessage = errorBody.message || errorBody.detail || `API request failed with status: ${response.status}`;
} else {
const errorBody = await response.text();
errorMessage = `API request failed with status ${response.status}: ${errorBody}`;
}
} catch {
errorMessage = `API request failed with status: ${response.status}`;
}
const requestId = response.headers.get("x-request-id") || void 0;
const error = createErrorFromStatus(
response.status,
errorData.code || "api_error",
errorMessage,
requestId,
errorData.details || errorData
);
if (response.status < 500) {
return { error };
}
throw error;
}
const contentType = response.headers.get("content-type");
if (contentType && contentType.includes("application/json")) {
const data = await response.json();
return { data };
} else {
const text = await response.text();
return { data: text };
}
}
/**
* Handles errors that occur during the request.
* @param error - The error that occurred.
* @returns An API response containing the error.
*/
handleRequestError(error) {
if (error instanceof InfactoryAPIError) {
throw error;
}
console.error("Unexpected error in API request:", error);
const message = error instanceof Error ? error.message : "Unknown error occurred during API request";
const networkError = new NetworkError(message);
return { error: networkError };
}
/**
* Builds a URL with query parameters.
* @param endpoint - The API endpoint path.
* @param params - The query parameters to append.
* @returns The complete URL string.
*/
buildUrl(endpoint, params) {
const apiUrl = this.isServer ? this.baseUrl : API_BASE_URL;
const cleanEndpoint = endpoint.startsWith("/") && apiUrl.endsWith("/") ? endpoint.substring(1) : endpoint;
let fullUrl = `${apiUrl}${cleanEndpoint}`;
if (params && Object.keys(params).length > 0) {
const url = new URL(
fullUrl,
this.isServer ? void 0 : window.location.origin
);
Object.entries(params).forEach(([key, value]) => {
if (value !== void 0 && value !== null) {
url.searchParams.append(key, String(value));
}
});
fullUrl = url.toString();
}
return fullUrl;
}
};
// src/clients/platforms-client.ts
var PlatformsClient = class {
/**
* Creates a new PlatformsClient instance
* @param httpClient - The HTTP client to use for API requests
*/
constructor(httpClient) {
this.httpClient = httpClient;
}
/**
* Get a list of all platforms
* @returns A promise that resolves to an API response containing an array of platforms
*/
async list() {
return this.httpClient.get("/v1/platforms");
}
/**
* Get a platform by ID
* @param id - The ID of the platform to retrieve
* @returns A promise that resolves to an API response containing the platform
*/
async get(id) {
return this.httpClient.get(`/v1/platforms/${id}`);
}
/**
* Create a new platform
* @param params - The parameters for creating the platform
* @returns A promise that resolves to an API response containing the created platform
*/
async create(params) {
return this.httpClient.post("/v1/platforms", params);
}
/**
* Update a platform
* @param id - The ID of the platform to update
* @param params - The parameters for updating the platform
* @returns A promise that resolves to an API response containing the updated platform
*/
async update(id, params) {
return this.httpClient.patch(`/v1/platforms/${id}`, params);
}
/**
* Delete a platform
* @param id - The ID of the platform to delete
* @returns A promise that resolves to an API response containing the deleted platform
*/
async delete(id) {
return this.httpClient.delete(`/v1/platforms/${id}`);
}
};
// src/clients/organizations-client.ts
var OrganizationsClient = class {
/**
* Creates a new OrganizationsClient instance
* @param httpClient - The HTTP client to use for API requests
*/
constructor(httpClient) {
this.httpClient = httpClient;
}
/**
* Get a list of all organizations
* @returns A promise that resolves to an API response containing an array of organizations
*/
async list() {
return this.httpClient.get("/v1/orgs");
}
/**
* Get an organization by ID
* @param id - The ID of the organization to retrieve
* @returns A promise that resolves to an API response containing the organization
*/
async get(id) {
return this.httpClient.get(`/v1/orgs/${id}`);
}
/**
* Get an organization by Clerk ID
* @param clerkOrgId - The Clerk ID of the organization to retrieve
* @returns A promise that resolves to an API response containing the organization
*/
async getByClerkId(clerkOrgId) {
return this.httpClient.get(`/v1/orgs/clerk/${clerkOrgId}`);
}
/**
* Create a new organization
* @param params - The parameters for creating the organization
* @returns A promise that resolves to an API response containing the created organization
*/
async create(params) {
return this.httpClient.post("/v1/orgs", params);
}
/**
* Update an organization
* @param id - The ID of the organization to update
* @param params - The parameters for updating the organization
* @returns A promise that resolves to an API response containing the updated organization
*/
async update(id, params) {
return this.httpClient.patch(`/v1/orgs/${id}`, params);
}
/**
* Delete an organization
* @param id - The ID of the organization to delete
* @returns A promise that resolves to an API response containing the deleted organization
*/
async delete(id) {
return this.httpClient.delete(`/v1/orgs/${id}`);
}
/**
* Move an organization to a new platform
* @param id - The ID of the organization to move
* @param newPlatformId - The ID of the platform to move the organization to
* @returns A promise that resolves to an API response containing the moved organization
*/
async move(id, newPlatformId) {
return this.httpClient.post(`/v1/orgs/${id}/move`, {
new_platform_id: newPlatformId
});
}
};
// src/clients/teams-client.ts
var TeamsClient = class {
/**
* Creates a new TeamsClient instance
* @param httpClient - The HTTP client to use for API requests
*/
constructor(httpClient) {
this.httpClient = httpClient;
}
/**
* Get a list of all teams for an organization
* @param organizationId - The ID of the organization to get teams for
* @returns A promise that resolves to an API response containing an array of teams
*/
async getTeams(organizationId) {
if (!organizationId) {
throw new Error("Organization ID is required");
}
return this.httpClient.get("/v1/teams", {
organization_id: organizationId
});
}
/**
* Get a team by ID
* @param id - The ID of the team to retrieve
* @returns A promise that resolves to an API response containing the team
*/
async getTeam(id) {
return this.httpClient.get(`/v1/teams/${id}`);
}
/**
* Create a new team
* @param params - The parameters for creating the team
* @returns A promise that resolves to an API response containing the created team
*/
async createTeam(params) {
if (!params.name || params.name.trim() === "") {
throw new Error("Team name is required");
}
if (!params.organizationId) {
throw new Error("Organization ID is required");
}
return this.httpClient.post("/v1/teams", {
name: params.name,
organization_id: params.organizationId
});
}
/**
* Update a team
* @param id - The ID of the team to update
* @param params - The parameters for updating the team
* @returns A promise that resolves to an API response containing the updated team
*/
async updateTeam(id, params) {
return this.httpClient.patch(`/v1/teams/${id}`, {
name: params.name
});
}
/**
* Delete a team
* @param id - The ID of the team to delete
* @returns A promise that resolves to an API response
*/
async deleteTeam(id) {
return this.httpClient.delete(`/v1/teams/${id}`);
}
/**
* Move a team to a new organization
* @param id - The ID of the team to move
* @param newOrganizationId - The ID of the organization to move the team to
* @returns A promise that resolves to an API response containing the moved team
*/
async moveTeam(id, newOrganizationId) {
return this.httpClient.post(`/v1/teams/${id}/move`, {
new_organization_id: newOrganizationId
});
}
/**
* Get all memberships for a team
* @param teamId - The ID of the team to get memberships for
* @returns A promise that resolves to an API response containing an array of team memberships
*/
async getTeamMemberships(teamId) {
if (!teamId) {
throw new Error("Team ID is required");
}
return this.httpClient.get(
`/v1/team-memberships/team/${teamId}`
);
}
/**
* Create a team membership
* @param teamId - The ID of the team
* @param userId - The ID of the user
* @param role - The role for the membership
* @returns A promise that resolves to an API response containing the created team membership
*/
async createTeamMembership(teamId, userId, role) {
if (!teamId) {
throw new Error("Team ID is required");
}
if (!userId) {
throw new Error("User ID is required");
}
if (!role) {
throw new Error("Role is required");
}
return this.httpClient.post("/v1/team-memberships", {
teamId,
userId,
role
});
}
/**
* Update a team membership
* @param teamId - The ID of the team
* @param userId - The ID of the user
* @param role - The new role for the membership
* @returns A promise that resolves to an API response containing the updated team membership
*/
async updateTeamMembership(teamId, userId, role) {
if (!teamId) {
throw new Error("Team ID is required");
}
if (!userId) {
throw new Error("User ID is required");
}
if (!role) {
throw new Error("Role is required");
}
return this.httpClient.patch(
`/v1/team-memberships/${userId}/${teamId}`,
{ role }
);
}
/**
* Delete a team membership
* @param teamId - The ID of the team
* @param userId - The ID of the user
* @param permanent - Whether to permanently delete the membership
* @returns A promise that resolves to an API response
*/
async deleteTeamMembership(teamId, userId, permanent = false) {
if (!teamId) {
throw new Error("Team ID is required");
}
if (!userId) {
throw new Error("User ID is required");
}
return this.httpClient.delete(
`/v1/team-memberships/${userId}/${teamId}`,
{
permanent
}
);
}
};
// src/clients/projects-client.ts
var ProjectsClient = class {
/**
* Creates a new ProjectsClient instance
* @param httpClient - The HTTP client to use for API requests
*/
constructor(httpClient) {
this.httpClient = httpClient;
}
/**
* Get a list of all projects
* @param teamId - Optional team ID to filter projects by
* @param includeDeleted - Whether to include deleted projects
* @returns A promise that resolves to an API response containing an array of projects
*/
async getProjects(teamId, includeDeleted = false) {
const params = {};
if (teamId) {
params.teamId = teamId;
}
if (includeDeleted) {
params.includeDeleted = includeDeleted;
}
return this.httpClient.get("/v1/projects", params);
}
/**
* Get projects for a specific team
* @param teamId - The ID of the team to get projects for
* @param includeDeleted - Whether to include deleted projects
* @returns A promise that resolves to an API response containing an array of projects
*/
async getTeamProjects(teamId, includeDeleted = false) {
if (!teamId) {
throw new Error("Team ID is required");
}
return this.getProjects(teamId, includeDeleted);
}
/**
* Get a project by ID
* @param projectId - The ID of the project to retrieve
* @param teamId - Optional team ID for access control
* @returns A promise that resolves to an API response containing the project
*/
async getProject(projectId, teamId) {
const params = {};
if (teamId) {
params.teamId = teamId;
}
return this.httpClient.get(`/v1/projects/${projectId}`, params);
}
/**
* Create a new project
* @param params - The parameters for creating the project
* @returns A promise that resolves to an API response containing the created project
*/
async createProject(params) {
if (!params.name || params.name.trim() === "") {
throw new Error("Project name is required");
}
const payload = {
...params,
teamId: params.teamId
};
return this.httpClient.post("/v1/projects", payload);
}
/**
* Update a project
* @param projectId - The ID of the project to update
* @param params - The parameters for updating the project
* @returns A promise that resolves to an API response containing the updated project
*/
async updateProject(projectId, params) {
return this.httpClient.patch(`/v1/projects/${projectId}`, params);
}
/**
* Delete a project
* @param projectId - The ID of the project to delete
* @param permanent - Whether to permanently delete the project
* @returns A promise that resolves to an API response
*/
async deleteProject(projectId, permanent = false) {
return this.httpClient.delete(`/v1/projects/${projectId}`, {
permanent
});
}
/**
* Move a project to a new team
* @param projectId - The ID of the project to move
* @param newTeamId - The ID of the team to move the project to
* @returns A promise that resolves to an API response containing the moved project
*/
async moveProject(projectId, newTeamId) {
return this.httpClient.post(`/v1/projects/${projectId}/move`, {
new_team_id: newTeamId
});
}
/**
* Export a project
* @param projectId - The ID of the project to export
* @param teamId - The ID of the team the project belongs to
* @returns A promise that resolves to an API response containing the export data
*/
async exportProject(projectId, teamId) {
return this.httpClient.downloadFile(
`/projects/${projectId}/export`,
{ teamId },
`project_export_${projectId}.json`
);
}
/**
* Import a project
* @param teamId - The ID of the team to import the project into
* @param file - The project configuration file to import
* @param conflictStrategy - Strategy for handling naming conflicts
* @param renameSuffix - Custom suffix to use for renaming projects (when conflict_strategy is 'rename')
* @returns A promise that resolves to an API response containing the imported project
*/
/**
* Import a project from a JSON file.
* @param teamId - The ID of the team to import the project into
* @param fileOrFilePath - Either a File object (browser) or a file path string (Node.js)
* @param options - Optional: { conflictStrategy, renameSuffix }
* @returns A promise that resolves to an API response containing the imported project
*/
async importProject(teamId, fileOrFilePath, options) {
try {
if (typeof fileOrFilePath === "string") {
console.info("Importing project using file path...");
const FormData2 = (await import('form-data')).default;
const fs2 = await import('fs');
const path2 = await import('path');
const form = new FormData2();
form.append("file", fs2.createReadStream(fileOrFilePath), {
filename: path2.basename(fileOrFilePath),
contentType: "application/json"
});
form.append("team_id", teamId);
form.append("conflict_strategy", options?.conflictStrategy || "rename");
if (options?.renameSuffix) {
form.append("rename_suffix", options.renameSuffix);
}
const fetch2 = (await import('node-fetch')).default;
const headers = form.getHeaders();
const apiKey = this.httpClient.getApiKey();
if (apiKey) {
headers["Authorization"] = `Bearer ${apiKey}`;
}
const baseURL = this.httpClient.getBaseUrl();
const url = `${baseURL}/projects/import`;
const response = await fetch2(url, {
method: "POST",
body: form,
headers
});
console.info("Response status:", response.status);
const responseText = await response.text();
console.info("Response body:", responseText);
let responseData;
try {
responseData = JSON.parse(responseText);
} catch (e) {
console.error("Error parsing response JSON:", e);
responseData = { error: "Invalid JSON response" };
}
if (response.ok) {
console.info("Import successful!");
return { data: responseData };
} else {
console.error("Import failed with status:", response.status);
return { error: responseData };
}
}
console.info("Importing project using browser File...");
const formData = new FormData();
formData.append("file", fileOrFilePath);
formData.append("team_id", teamId);
formData.append(
"conflict_strategy",
options?.conflictStrategy || "rename"
);
if (options?.renameSuffix) {
formData.append("rename_suffix", options.renameSuffix);
}
return await this.httpClient.request({
url: "/projects/import",
method: "POST",
body: formData
});
} catch (error) {
console.error("Error importing project:", error);
throw error;
}
}
/**
* Validate a project import file without importing it
* @param file - The project configuration file to validate
* @returns A promise that resolves to an API response containing validation info
*/
async validateImport(file) {
try {
const formData = new FormData();
formData.append("file", file);
return await this.httpClient.request({
url: "/projects/validate-import",
method: "POST",
body: formData
});
} catch (error) {
console.error("Error validating import:", error);
throw error;
}
}
/**
* Get coverage information for a project's query programs
* @param projectId - The ID of the project
* @returns A promise that resolves to an API response containing coverage information
*/
async getCoverage(projectId) {
return await this.httpClient.get(
`/v1/coverage/${projectId}`
);
}
};
// src/clients/users-client.ts
var UsersClient = class {
/**
* Creates a new UsersClient instance
* @param httpClient - The HTTP client to use for API requests
*/
constructor(httpClient) {
this.httpClient = httpClient;
}
/**
* Get a list of all users
* @param organizationId - Optional organization ID to filter users
* @returns A promise that resolves to an API response containing an array of users
*/
async getUsers(organizationId) {
const params = {};
if (organizationId) {
params.organization_id = organizationId;
}
return this.httpClient.get("/v1/users", params);
}
/**
* Get a user by ID
* @param userId - The ID of the user to retrieve
* @returns A promise that resolves to an API response containing the user
*/
async getUser(userId) {
return this.httpClient.get(`/v1/users/${userId}`);
}
/**
* Get the current authenticated user
* @returns A promise that resolves to an API response containing the current user with teams and organization
*/
async getCurrentUser() {
return this.httpClient.get(
"/v1/authentication/me"
);
}
/**
* Create a new user
* @param params - Parameters for creating the user
* @returns A promise that resolves to an API response containing the created user
*/
async createUser(params) {
return this.httpClient.post("/v1/users", {
email: params.email,
name: params.name,
organization_id: params.organizationId,
role: params.role
});
}
/**
* Update a user
* @param userId - The ID of the user to update
* @param params - Parameters for updating the user
* @returns A promise that resolves to an API response containing the updated user
*/
async updateUser(userId, params) {
return this.httpClient.patch(`/v1/users/${userId}`, {
email: params.email,
name: params.name,
role: params.role
});
}
/**
* Delete a user
* @param userId - The ID of the user to delete
* @returns A promise that resolves to an API response containing the deleted user
*/
async deleteUser(userId) {
return this.httpClient.delete(`/v1/users/${userId}`);
}
/**
* Move a user to a new organization
* @param userId - The ID of the user to move
* @param newOrganizationId - The ID of the organization to move the user to
* @returns A promise that resolves to an API response containing the moved user
*/
async moveUser(userId, newOrganizationId) {
return this.httpClient.post(`/v1/users/${userId}/move`, {
new_organization_id: newOrganizationId
});
}
/**
* Get or create a user, team, and organization based on Clerk IDs
* @param params - Parameters for getting or creating the user, team, and organization
* @returns A promise that resolves to an API response containing the user
*/
async getOrCreateUserTeamOrganization(params) {
return this.httpClient.post(
"/v1/users/get_or_create_user_team_organization",
{
body: params
}
);
}
/**
* Get teams with organizations and projects for a user
* @param params - Parameters to identify the user
* @returns A promise that resolves to an API response containing teams with organizations and projects
*/
async getTeamsWithOrganizationsAndProjects(params) {
return this.httpClient.get(
`/v1/users/get_teams_with_organizations_and_projects`,
params
);
}
/**
* Get roles for a user
* @param userId - The ID of the user
* @returns A promise that resolves to an API response containing user roles
*/
async getUserRoles(userId) {
return this.httpClient.get(`/v1/users/${userId}/roles`);
}
/**
* Add a role to a user
* @param userId - The ID of the user
* @param roleId - The ID of the role to add
* @returns A promise that resolves to an API response
*/
async addUserRole(userId, roleId) {
return this.httpClient.post(`/v1/users/${userId}/roles/${roleId}/`, {
body: { roleId }
});
}
/**
* Remove a role from a user
* @param userId - The ID of the user
* @param roleId - The ID of the role to remove
* @returns A promise that resolves to an API response
*/
async removeUserRole(userId, roleId) {
return this.httpClient.delete(`/v1/users/${userId}/roles/${roleId}/`);
}
};
// src/clients/queryprograms-client.ts
var QueryProgramsClient = class {
/**
* Creates a new QueryProgramsClient instance
* @param httpClient - The HTTP client to use for API requests
*/
constructor(httpClient) {
this.httpClient = httpClient;
}
/**
* List all query programs for a project
* @param params - Optional pagination parameters
* @returns A promise that resolves to an API response containing an array of query programs
*/
async listQueryPrograms(params) {
return await this.httpClient.get(
`/v1/queryprograms`,
params
);
}
/**
* Get a specific query program by ID
* @param id - The ID of the query program to retrieve
* @returns A promise that resolves to an API response containing the query program
*/
async getQueryProgram(id) {
return await this.httpClient.get(`/v1/queryprograms/${id}`);
}
/**
* Create a new query program
* @param params - Parameters for creating the query program
* @returns A promise that resolves to an API response containing the created query program
*/
async createQueryProgram(params) {
return await this.httpClient.post(
"/v1/queryprograms",
params
);
}
/**
* Update an existing query program
* @param id - The ID of the query program to update
* @param params - Parameters for updating the query program
* @returns A promise that resolves to an API response containing the updated query program
*/
async updateQueryProgram(id, params) {
return await this.httpClient.patch(
`/v1/queryprograms/${id}`,
params
);
}
/**
* Delete a query program
* @param id - The ID of the query program to delete
* @param permanent - Whether to permanently delete the query program (default: false)
* @returns A promise that resolves to an API response with the deletion result
*/
async deleteQueryProgram(id, permanent = false) {
return await this.httpClient.delete(`/v1/queryprograms/${id}`, {
permanent
});
}
// /**
// * Execute a query program synchronously (replacement for executeQueryProgram)
// * @param queryProgramId - The ID of the query program to execute
// * @param inputData - Optional input data for the query program (currently unused)
// * @returns A promise that resolves to an API response containing the query result
// */
// async executeQueryProgram(
// queryProgramId: string,
// // eslint-disable-next-line @typescript-eslint/no-unused-vars
// inputData?: Record<string, any>,
// ): Promise<ApiResponse<QueryResponse> | ReadableStream<any>> {
// // This method now uses evaluateQueryProgramSync internally
// // since the original executeQueryProgram endpoint is returning 404 errors
// // Note: inputData is currently not used because evaluateQueryProgramSync doesn't support it
// // We need to extract the project ID from the query program ID
// // For now, we'll use the queryProgramId for both parameters
// // This should be updated when the proper project ID is available
// return await this.evaluateQueryProgramSync(queryProgramId, queryProgramId);
// }
// /**
// * Execute a query program with streaming response
// * @param id - The ID of the query program to execute
// * @param params - Optional parameters for streaming execution
// * @returns A promise that resolves to a readable stream of execution events
// */
// async executeQueryProgramStream(
// id: string,
// params?: Record<string, any>,
// ): Promise<ReadableStream<Uint8Array>> {
// return await this.httpClient.createStream(
// `/v1/queryprograms/${id}/execute`,
// {
// url: `/v1/queryprograms/${id}/execute`,
// method: 'POST',
// jsonBody: params || {},
// headers: {
// Accept: 'text/event-stream',
// },
// },
// );
// }
/**
* Validate a query program without executing it
* @param params - Parameters of the query program to validate
* @returns A promise that resolves to an API response with validation results
*/
async validateQueryProgram(params) {
const filteredParams = Object.fromEntries(
Object.entries(params).filter(([_, value]) => value != null)
);
return await this.httpClient.post(
"/v1/queryprograms/validate",
filteredParams
);
}
/**
* Get execution history for a query program
* @param id - The ID of the query program
* @param params - Optional pagination and date filter parameters
* @returns A promise that resolves to an API response containing the execution history
*/
async getQueryProgramHistory(id, params) {
return await this.httpClient.get(
`/v1/queryprograms/${id}/history`,
{
params
}
);
}
/**
* Create a model from a query program
* @param queryProgramId - The ID of the query program
* @returns A promise that resolves to an API response containing the updated query program
*/
async createQueryProgramModel(queryProgramId) {
return await this.httpClient.post(
`/v1/queryprograms/${queryProgramId}/create-model`
);
}
/**
* Publish a query program, making it available for API endpoints
* @param id - The ID of the query program to publish
* @param groupSlots - Whether to group slots in the published query program
* @returns A promise that resolves to an API response containing the published query program
*/
async publishQueryProgram(id, groupSlots = false) {
return await this.httpClient.patch(
`/v1/queryprograms/${id}/publish`,
{ group_slots: groupSlots }
);
}
/**
* Unpublish a query program
* @param id - The ID of the query program to unpublish
* @returns A promise that resolves to an API response containing the unpublished query program
*/
async unpublishQueryProgram(id) {
return await this.httpClient.patch(
`/v1/queryprograms/${id}/unpublish`
);
}
/**
* Evaluate a query program with streaming response
* @param projectId - The ID of the project
* @param queryprogramId - The ID of the query program to evaluate
* @returns A promise that resolves to a readable stream of evaluation events
*/
async evaluateQueryProgram(projectId, queryprogramId, params) {
params = params || {};
let url = "/v1/run/queryprogram";
const query_params = new URLSearchParams(params).toString();
if (query_params) {
url = `${url}?${query_params}`;
}
return await this.httpClient.createStream(url, {
url,
method: "POST",
jsonBody: {
projectId,
queryprogramId,
stream: true
// Explicitly set streaming to true
},
headers: {
Accept: "text/event-stream"
}
});
}
/**
* Evaluate a query program with non-streaming response
* @param projectId - The ID of the project
* @param queryprogramId - The ID of the query program to evaluate
* @returns A promise that resolves to an API response containing the evaluation result
*/
async evaluateQueryProgramSync(projectId, queryprogramId, params) {
params = params || {};
let url = "/v1/run/queryprogram";
const query_params = new URLSearchParams(params).toString();
if (query_params) {
url = `${url}?${query_params}`;
}
return await this.httpClient.post(
url,
{
projectId,
queryprogramId,
stream: false
// Explicitly set streaming to false
},
params
);
}
/**
* Analyze a query program to get its graph representation
* @param projectId - The ID of the project
* @param queryprogramId - The ID of the query program to analyze
* @returns A promise that resolves to an API response containing the graph representation
*/
async analyzeQueryProgram(projectId, queryprogramId) {
return await this.httpClient.post(
"/v1/actions/evaluate/queryprogram/graph",
{
projectId,
queryprogramId
}
);
}
/**
* Get readable answer for query response
* @param queryResponseId - The ID of the query response
* @param query - The query to generate a readable answer for
* @returns A promise that resolves to a readable stream of the answer
*/
async getReadableAnswerForQueryResponse(queryResponseId, query) {
return await this.httpClient.createStream(
`/v1/actions/generate/readableanswer-to-queryresponse/${queryResponseId}`,
{
url: `/v1/actions/generate/readableanswer