@datanest-earth/nodejs-client
Version:
Datanest API Client to easily create signed requests
768 lines (756 loc) • 30.5 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
DatanestClient: () => DatanestClient3,
DatanestResponseError: () => DatanestResponseError,
default: () => DatanestClient3,
enviro: () => enviro_exports,
files: () => files_exports,
gather: () => gather_exports,
integrations: () => integrations_exports,
projects: () => projects_exports,
teams: () => teams_exports,
user: () => user,
users: () => users_exports,
webhook: () => webhook_exports,
workflows: () => workflows_exports
});
module.exports = __toCommonJS(src_exports);
var import_node_crypto2 = require("crypto");
// src/projects.ts
var projects_exports = {};
__export(projects_exports, {
ProjectType: () => ProjectType,
archiveProject: () => archiveProject,
createProject: () => createProject,
getProject: () => getProject,
listProjects: () => listProjects,
patchProject: () => patchProject,
restoreProject: () => restoreProject,
waitForProjectWorkflow: () => waitForProjectWorkflow
});
var ProjectType = /* @__PURE__ */ ((ProjectType2) => {
ProjectType2[ProjectType2["PROJECT_TYPE_ENVIRO"] = 0] = "PROJECT_TYPE_ENVIRO";
ProjectType2[ProjectType2["PROJECT_TYPE_STANDARD"] = 1] = "PROJECT_TYPE_STANDARD";
return ProjectType2;
})(ProjectType || {});
async function listProjects(client, page = 1, archived = false, filters) {
const response = await client.get("v1/projects", { archived, page, ...filters });
const data = await response.json();
return data;
}
async function getProject(client, projectUuid) {
const response = await client.get("v1/projects/" + projectUuid);
const data = await response.json();
return data;
}
async function createProject(client, projectData) {
const response = await client.post("v1/projects", projectData);
if (response.status !== 201) {
throw new DatanestResponseError(`Failed to create project: ${response.status}`, response.status, await response.json());
}
const data = await response.json();
return data;
}
async function waitForProjectWorkflow(client, projectUuid, timeout = 45e3) {
let projectData = void 0;
const start = Date.now();
while (projectData?.workflow_importing_at !== null) {
await new Promise((resolve) => setTimeout(resolve, 2e3));
projectData = (await getProject(client, projectUuid)).project;
if (Date.now() - start > timeout) {
throw new Error("Timeout waiting for project workflow to complete");
}
}
return projectData;
}
async function patchProject(client, projectUuid, projectData) {
const response = await client.patch("v1/projects/" + projectUuid, projectData);
if (response.status !== 200) {
throw new DatanestResponseError(`Failed to create project: ${response.status}`, response.status, await response.json());
}
const data = await response.json();
return data;
}
async function archiveProject(client, projectUuid, options) {
const response = await client.delete("v1/projects/" + projectUuid + "/archive", options);
if (response.status !== 200) {
throw new DatanestResponseError(`Failed to archive project: ${response.status}`, response.status, await response.json());
}
return true;
}
async function restoreProject(client, projectUuid) {
await client.post("v1/projects/" + projectUuid + "/restore");
return true;
}
// src/workflows.ts
var workflows_exports = {};
__export(workflows_exports, {
assignProjectWorkflowAppUser: () => assignProjectWorkflowAppUser,
getCompanyCustomRoles: () => getCompanyCustomRoles,
getCompanyWorkflows: () => getCompanyWorkflows,
unassignProjectWorkflowAppUser: () => unassignProjectWorkflowAppUser
});
async function getCompanyWorkflows(client, filters) {
const response = await client.get("v1/company-workflows", filters);
return await response.json();
}
async function getCompanyCustomRoles(client) {
const response = await client.get("v1/company-custom-roles");
return await response.json();
}
async function assignProjectWorkflowAppUser(client, projectUuid, userUuidOrEmail, workflowAppId, customRoleId) {
const response = await client.post("v1/projects/" + projectUuid + "/teams/workflow-apps/" + workflowAppId + "/" + userUuidOrEmail, {
custom_role_id: customRoleId
});
return await response.json();
}
async function unassignProjectWorkflowAppUser(client, projectUuid, userUuidOrEmail, workflowAppId) {
const response = await client.delete("v1/projects/" + projectUuid + "/teams/workflow-apps/" + workflowAppId + "/" + userUuidOrEmail);
return await response.json();
}
// src/enviro.ts
var enviro_exports = {};
__export(enviro_exports, {
getAllEnviroChemicals: () => getAllEnviroChemicals,
getAllEnviroMatrices: () => getAllEnviroMatrices,
getCompanyChemicalProfiles: () => getCompanyChemicalProfiles,
getProjectMatrices: () => getProjectMatrices,
getProjectSampleChemicalResults: () => getProjectSampleChemicalResults,
getProjectSampleLocations: () => getProjectSampleLocations,
getProjectSamples: () => getProjectSamples,
getProjectScenarioGuidelines: () => getProjectScenarioGuidelines,
getProjectScenarioStandards: () => getProjectScenarioStandards,
getProjectScenarios: () => getProjectScenarios
});
async function getAllEnviroMatrices(client) {
const response = await client.get("v1/enviro/matrices");
return await response.json();
}
async function getAllEnviroChemicals(client, page = 1, filters) {
const response = await client.get("v1/enviro/chemicals", {
page,
...filters
});
return await response.json();
}
async function getCompanyChemicalProfiles(client) {
const response = await client.get("v1/enviro/chemicals/alias-profiles");
return await response.json();
}
async function getProjectMatrices(client, projectUuid) {
const response = await client.get("v1/projects/" + projectUuid + "/enviro/matrices");
return await response.json();
}
async function getProjectScenarios(client, projectUuid) {
const response = await client.get("v1/projects/" + projectUuid + "/enviro/scenarios");
return await response.json();
}
async function getProjectScenarioStandards(client, projectUuid, scenarioId, filters) {
const response = await client.get("v1/projects/" + projectUuid + "/enviro/scenarios/" + scenarioId + "/standards", filters);
return await response.json();
}
async function getProjectScenarioGuidelines(client, projectUuid, scenarioId, filters) {
const response = await client.get("v1/projects/" + projectUuid + "/enviro/scenarios/" + scenarioId + "/guidelines", filters);
return await response.json();
}
async function getProjectSampleChemicalResults(client, projectUuid, filters) {
const response = await client.get("v1/projects/" + projectUuid + "/enviro/samples/chemical-results", filters);
return await response.json();
}
async function getProjectSampleLocations(client, projectUuid, filters) {
const response = await client.get("v1/projects/" + projectUuid + "/enviro/samples/locations", filters);
return await response.json();
}
async function getProjectSamples(client, projectUuid, filters) {
const response = await client.get("v1/projects/" + projectUuid + "/enviro/samples", filters);
return await response.json();
}
// src/gather.ts
var gather_exports = {};
__export(gather_exports, {
createGatherItem: () => createGatherItem,
deleteItem: () => deleteItem,
getAppSchema: () => getAppSchema,
getProjectItemDetails: () => getProjectItemDetails,
importAppGroup: () => importAppGroup,
listProjectAppItems: () => listProjectAppItems,
listProjectApps: () => listProjectApps,
listProjectItems: () => listProjectItems,
listSharedAppGroups: () => listSharedAppGroups,
updateGatherItem: () => updateGatherItem
});
async function listProjectApps(client, projectUuid) {
const response = await client.get("v1/projects/" + projectUuid + "/apps");
const data = await response.json();
return data;
}
async function listProjectItems(client, projectUuid, page = 1, filters = {}) {
const response = await client.get("v1/projects/" + projectUuid + "/items", { page, ...filters });
const data = await response.json();
return data;
}
async function getProjectItemDetails(client, projectUuid, itemId) {
const response = await client.get("v1/projects/" + projectUuid + "/items/" + itemId);
const data = await response.json();
return data;
}
async function listProjectAppItems(client, projectUuid, appUuid, page = 1, filters) {
const response = await client.get("v1/projects/" + projectUuid + "/apps/" + appUuid + "/items", { page, ...filters });
const data = await response.json();
return data;
}
async function getAppSchema(client, appUuid) {
const response = await client.get("v1/apps/" + appUuid + "/schema");
const data = await response.json();
return data;
}
async function listSharedAppGroups(client, page = 1, filter = "all", filters) {
const response = await client.get("v1/apps/share-groups", { page, filter, ...filters });
const data = await response.json();
return data;
}
async function importAppGroup(client, projectUuid, shareGroup) {
const response = await client.post("v1/projects/" + projectUuid + "/apps/import-share-group", {
share_group: shareGroup
});
return await response.json();
}
async function createGatherItem(client, projectUuid, appUuid, data) {
data.app_uuid = appUuid;
const response = await client.post("v1/projects/" + projectUuid + "/items", data);
const responseData = await response.json();
return responseData;
}
async function updateGatherItem(client, projectUuid, itemId, data) {
const response = await client.patch("v1/projects/" + projectUuid + "/items/" + itemId, data);
const responseData = await response.json();
return responseData;
}
async function deleteItem(client, projectUuid, itemId) {
const response = await client.delete("v1/projects/" + projectUuid + "/items/" + itemId);
await response.json();
return true;
}
// src/integrations.ts
var integrations_exports = {};
__export(integrations_exports, {
IntegrationKey: () => IntegrationKey,
removeIntegration: () => removeIntegration,
setupIntegration: () => setupIntegration
});
var IntegrationKey = /* @__PURE__ */ ((IntegrationKey2) => {
IntegrationKey2["BORE_DM"] = "boredm";
return IntegrationKey2;
})(IntegrationKey || {});
async function setupIntegration(client, integrationKey, integrationSetupData) {
const response = await client.post("v1/integrations/" + integrationKey, integrationSetupData);
if (response.status !== 200) {
throw new DatanestResponseError(`Failed to setup integration: ${response.status}`, response.status, await response.json());
}
const data = await response.json();
return data;
}
async function removeIntegration(client, integrationKey) {
await client.delete("v1/integrations/" + integrationKey);
return true;
}
// src/teams.ts
var teams_exports = {};
__export(teams_exports, {
addExternalUserToProject: () => addExternalUserToProject,
addProjectTeamMember: () => addProjectTeamMember,
assignProjectWorkflowUser: () => assignProjectWorkflowAppUser,
getProjectTeam: () => getProjectTeam,
removeExternalUserToProject: () => removeExternalUserToProject,
removeProjectTeamMember: () => removeProjectTeamMember,
unassignProjectWorkflowUser: () => unassignProjectWorkflowAppUser,
updateProjectMemberRole: () => updateProjectMemberRole
});
async function getProjectTeam(client, projectUuid) {
const response = await client.get("v1/projects/" + projectUuid + "/teams");
const data = await response.json();
return data;
}
async function addProjectTeamMember(client, projectUuid, userUuid, customRoleId) {
const response = await client.post("v1/projects/" + projectUuid + "/teams/members/" + userUuid, {
custom_role_id: customRoleId
});
const data = await response.json();
return data.user;
}
async function removeProjectTeamMember(client, projectUuid, userUuid) {
const response = await client.delete("v1/projects/" + projectUuid + "/teams/members/" + userUuid);
const data = await response.json();
return data.user;
}
async function addExternalUserToProject(client, projectUuid, userData) {
const response = await client.post("v1/projects/" + projectUuid + "/teams/external-users", userData);
const data = await response.json();
return data.user;
}
async function removeExternalUserToProject(client, projectUuid, userUuidOrEmail) {
const response = await client.delete("v1/projects/" + projectUuid + "/teams/external-users/" + userUuidOrEmail);
const data = await response.json();
return data.user;
}
async function updateProjectMemberRole(client, projectUuid, userUuid, customRoleId) {
const response = await client.patch("v1/projects/" + projectUuid + "/teams/members/" + userUuid + "/custom-role", {
custom_role_id: customRoleId
});
const data = await response.json();
return data.user;
}
// src/users.ts
var users_exports = {};
__export(users_exports, {
deleteCompanyUser: () => deleteCompanyUser,
getCompanyExternalUserProjects: () => getCompanyExternalUserProjects,
getCompanyExternalUsers: () => getCompanyExternalUsers,
getCompanyUsers: () => getCompanyUsers,
inviteCompanyUser: () => inviteCompanyUser,
patchCompanyUser: () => patchCompanyUser,
purgeCompanyExternalUser: () => purgeCompanyExternalUser
});
async function getCompanyUsers(client, params) {
const response = await client.get("v1/users", params);
const data = await response.json();
return data;
}
async function inviteCompanyUser(client, userData) {
const response = await client.post("v1/users", userData);
const data = await response.json();
return data.user;
}
async function patchCompanyUser(client, userUuid, userData) {
const response = await client.patch("v1/users/" + userUuid, userData);
const data = await response.json();
return data.user;
}
async function deleteCompanyUser(client, userUuid) {
const response = await client.delete("v1/users/" + userUuid);
const data = await response.json();
return data;
}
async function getCompanyExternalUsers(client, params) {
const response = await client.get("v1/company/external-users", params);
return await response.json();
}
async function getCompanyExternalUserProjects(client, externalUserUuid, params) {
const response = await client.get("v1/company/external-users/" + externalUserUuid + "/projects", params);
return await response.json();
}
async function purgeCompanyExternalUser(client, externalUserUuid) {
const response = await client.delete("v1/company/external-users/" + externalUserUuid);
return await response.json();
}
// src/files.ts
var files_exports = {};
__export(files_exports, {
ReviewStatus: () => ReviewStatus,
VirusStatus: () => VirusStatus,
acceptFile: () => acceptFile,
createNewFileUploadUrl: () => createNewFileUploadUrl,
deleteFile: () => deleteFile,
getProjectFile: () => getProjectFile,
getProjectFileHistory: () => getProjectFileHistory,
getProjectFileVersionUrl: () => getProjectFileVersionUrl,
getProjectFiles: () => getProjectFiles,
getRecentNotifications: () => getRecentNotifications,
uploadFile: () => uploadFile
});
var VirusStatus = /* @__PURE__ */ ((VirusStatus2) => {
VirusStatus2[VirusStatus2["PENDING"] = 0] = "PENDING";
VirusStatus2[VirusStatus2["PASSED"] = 1] = "PASSED";
VirusStatus2[VirusStatus2["FAILED"] = 2] = "FAILED";
VirusStatus2[VirusStatus2["UNABLE"] = 3] = "UNABLE";
VirusStatus2[VirusStatus2["SKIP"] = 4] = "SKIP";
return VirusStatus2;
})(VirusStatus || {});
var ReviewStatus = /* @__PURE__ */ ((ReviewStatus2) => {
ReviewStatus2[ReviewStatus2["WIP"] = 0] = "WIP";
ReviewStatus2[ReviewStatus2["AWAITING_REVIEW"] = 1] = "AWAITING_REVIEW";
ReviewStatus2[ReviewStatus2["REVIEW_PASSED"] = 2] = "REVIEW_PASSED";
ReviewStatus2[ReviewStatus2["REVIEW_FAILED"] = 3] = "REVIEW_FAILED";
ReviewStatus2[ReviewStatus2["AWAITING_FORMATTING"] = 4] = "AWAITING_FORMATTING";
ReviewStatus2[ReviewStatus2["FORMATTING_FAILED"] = 5] = "FORMATTING_FAILED";
ReviewStatus2[ReviewStatus2["READY"] = 6] = "READY";
ReviewStatus2[ReviewStatus2["SENT"] = 7] = "SENT";
return ReviewStatus2;
})(ReviewStatus || {});
async function getProjectFiles(client, projectUuid, page = 1, options) {
const response = await client.get("v1/projects/" + projectUuid + "/files", { page, ...options });
const data = await response.json();
return data;
}
async function getProjectFile(client, projectUuid, fileUuid) {
const response = await client.get("v1/projects/" + projectUuid + "/files/" + fileUuid);
const data = await response.json();
return data;
}
async function getProjectFileHistory(client, projectUuid, fileUuid) {
const response = await client.get("v1/projects/" + projectUuid + "/files/" + fileUuid + "/history");
const data = await response.json();
return data;
}
async function getProjectFileVersionUrl(client, projectUuid, fileUuid, version) {
const response = await client.get("v1/projects/" + projectUuid + "/files/" + fileUuid + "/history/" + version + "/temporary-url");
const data = await response.json();
return data;
}
async function uploadFile(client, projectUuid, path, name, file, options) {
const uploadUrl = await createNewFileUploadUrl(client, projectUuid, path, name, options);
const response = await fetch(uploadUrl.upload_put_url, {
method: "PUT",
headers: uploadUrl.upload_put_headers,
body: file
});
if (!response.ok) {
throw new Error("Failed to upload file: " + response.status + " " + await response.text());
}
return await acceptFile(client, projectUuid, uploadUrl.uuid);
}
async function createNewFileUploadUrl(client, projectUuid, path, name, options) {
const response = await client.post("v1/projects/" + projectUuid + "/files/upload-url", {
path,
name,
create_notification: options?.create_notification
});
const data = await response.json();
return data;
}
async function acceptFile(client, projectUuid, fileUuid) {
const response = await client.post("v1/projects/" + projectUuid + "/files/" + fileUuid + "/accept-upload");
const data = await response.json();
return data;
}
async function deleteFile(client, projectUuid, fileUuid) {
await client.delete("v1/projects/" + projectUuid + "/files/" + fileUuid);
}
async function getRecentNotifications(client, projectUuid, page = 1, filters) {
const response = await client.get("v1/projects/" + projectUuid + "/notifications", { page, ...filters });
const data = await response.json();
return data;
}
// src/webhook.ts
var webhook_exports = {};
__export(webhook_exports, {
WebhookAuthorizationStatus: () => WebhookAuthorizationStatus,
authenticateWebhook: () => authenticateWebhook,
formatAuthorizationStatus: () => formatAuthorizationStatus
});
var import_node_crypto = require("crypto");
var WebhookAuthorizationStatus = /* @__PURE__ */ ((WebhookAuthorizationStatus2) => {
WebhookAuthorizationStatus2[WebhookAuthorizationStatus2["Success"] = 0] = "Success";
WebhookAuthorizationStatus2[WebhookAuthorizationStatus2["TimestampError"] = 1] = "TimestampError";
WebhookAuthorizationStatus2[WebhookAuthorizationStatus2["SignatureError"] = 2] = "SignatureError";
WebhookAuthorizationStatus2[WebhookAuthorizationStatus2["MissingTimestamp"] = 3] = "MissingTimestamp";
WebhookAuthorizationStatus2[WebhookAuthorizationStatus2["MissingSignature"] = 4] = "MissingSignature";
WebhookAuthorizationStatus2[WebhookAuthorizationStatus2["InvalidApiKey"] = 5] = "InvalidApiKey";
WebhookAuthorizationStatus2[WebhookAuthorizationStatus2["MissingApiKey"] = 6] = "MissingApiKey";
return WebhookAuthorizationStatus2;
})(WebhookAuthorizationStatus || {});
function formatAuthorizationStatus(status) {
return {
[0 /* Success */]: "Success",
[1 /* TimestampError */]: "Timestamp Error",
[2 /* SignatureError */]: "Signature Error",
[5 /* InvalidApiKey */]: "Invalid API Key",
[3 /* MissingTimestamp */]: "Missing Timestamp",
[4 /* MissingSignature */]: "Missing Signature",
[6 /* MissingApiKey */]: "Missing API Key"
}[status];
}
async function authenticateWebhook(request, requestBody, apiKey, secretKey, disableTimestampCheck = false) {
const signature = request.headers.get("X-Signature");
const timestamp = request.headers.get("X-Timestamp");
const apiKeyFromRequest = request.headers.get("X-Api-Key");
if (apiKeyFromRequest !== apiKey) {
return 5 /* InvalidApiKey */;
}
const currentTimestamp = Math.floor(Date.now() / 1e3);
if (!signature) {
return 4 /* MissingSignature */;
}
if (!timestamp) {
return 3 /* MissingTimestamp */;
}
if (!disableTimestampCheck && Math.abs(currentTimestamp - parseInt(timestamp)) > 60) {
return 1 /* TimestampError */;
}
const content = `${request.method}:${request.url}:${requestBody ? requestBody + ":" : ""}${timestamp}`;
const hmac = (0, import_node_crypto.createHmac)("sha256", secretKey);
const hash = hmac.update(content).digest("hex");
return hash === signature ? 0 /* Success */ : 2 /* SignatureError */;
}
// src/index.ts
var user = users_exports;
var DatanestClient3 = class _DatanestClient {
/**
* Create a new Datanest API client
* Note: You can use environment variables instead of using
* the constructor params `apiKey` and `apiSecret`
* ENV:
* - `DATANEST_API_KEY`
* - `DATANEST_API_SECRET`
* - `DATANEST_API_BASE_URL` (optional) Default: https://app.datanest.earth/api
*/
constructor(apiKey, apiSecret) {
this.clientId = null;
this.logErrors = true;
this.logTrace = false;
this.apiKey = apiKey || process.env.DATANEST_API_KEY || "";
this.apiSecret = apiSecret || process.env.DATANEST_API_SECRET || "";
this.baseUrl = process.env.DATANEST_API_BASE_URL || "https://app.datanest.earth/api";
this.baseUrl = this.baseUrl.replace(/\/$/, "");
if (!this.baseUrl.endsWith("/api")) {
throw new Error('Invalid base URL. Must end with "/api"');
}
if (this.apiKey === "" || this.apiSecret === "") {
throw new Error("API key and secret are required.");
}
}
static {
// Static rate limiter properties (shared across all instances)
this.rateLimitMax = 120 / 8;
}
static {
// Divide by 8 to allow for shorter max delays
this.rateLimitIntervalMs = 6e4 / 8;
}
static {
this.requestTimestamps = [];
}
static disableRateLimit() {
_DatanestClient.rateLimitMax = 1e8;
_DatanestClient.rateLimitIntervalMs = 0;
}
/** Datanest accepts up to 60 requests per minute, default limit is less for typical use */
static setRateLimit(maxRequests, intervalMs = 6e4) {
_DatanestClient.rateLimitMax = maxRequests;
_DatanestClient.rateLimitIntervalMs = intervalMs;
}
static async checkRateLimit(logWarning = false) {
while (_DatanestClient.requestTimestamps.length >= _DatanestClient.rateLimitMax) {
const now = Date.now();
_DatanestClient.requestTimestamps = _DatanestClient.requestTimestamps.filter((timestamp) => now - timestamp < _DatanestClient.rateLimitIntervalMs);
const waitTime = _DatanestClient.rateLimitIntervalMs - (now - _DatanestClient.requestTimestamps[0]);
if (logWarning) {
console.debug("Waiting for rate limit window to expire", waitTime);
}
await new Promise((resolve) => setTimeout(resolve, waitTime));
}
_DatanestClient.requestTimestamps.push(Date.now());
}
setLogErrors(logErrors) {
this.logErrors = logErrors;
}
setLogTrace(logTrace) {
this.logTrace = logTrace;
}
signRequest(url, requestOptions) {
const hmac = (0, import_node_crypto2.createHmac)("sha256", this.apiSecret);
const timestamp = Date.now() / 1e3;
if (!requestOptions.headers) {
requestOptions.headers = {};
}
const headers = requestOptions.headers;
headers["X-Timestamp"] = timestamp.toFixed(0);
const content = `${requestOptions.method}:${url}:${requestOptions.body ? requestOptions.body + ":" : ""}${timestamp.toFixed(0)}`;
headers["X-Signature"] = hmac.update(content).digest("hex");
}
/**
* Send a request to the Datanest API
* @param method
* @param path
* @param params
* @param fetchOptions
* @throws DatanestResponseError Request HTTP server or validation error
* @returns Fetch response with readable stream.
*/
async sendRequest(method, path, params, fetchOptions) {
if (_DatanestClient.rateLimitIntervalMs > 0 && _DatanestClient.rateLimitMax !== Infinity) {
await _DatanestClient.checkRateLimit(this.logErrors);
}
method = method.toUpperCase();
path = path.replace(/^\//, "");
if (path.startsWith("api/")) {
throw new Error('Invalid endpoint, must not start with "api/"');
}
const headers = {
...fetchOptions?.headers ?? {},
"Accept": "application/json",
"Content-Type": "application/json",
"X-API-Key": this.apiKey
};
if (this.clientId) {
headers["X-Client-ID"] = this.clientId;
}
const options = {
redirect: "error",
mode: method !== "DELETE" && method !== "PATCH" ? "no-cors" : void 0,
...fetchOptions,
method,
headers
};
let url = `${this.baseUrl}/${path}`;
if (params) {
if (method === "GET" || method === "DELETE") {
const queryParams = new URLSearchParams(params);
if (queryParams.size) {
queryParams.sort();
url += `?${queryParams.toString().replace(/\+/g, "%20")}`;
}
} else {
options.body = JSON.stringify(params);
}
}
this.signRequest(url, options);
const response = await fetch(url, options);
if (response.status > 299) {
const error = new DatanestResponseError(`Datanest API Failed: ${path}: ${response.status}`, response.status, await response.json());
if (this.logErrors) {
console.error(error.message, error.data);
} else {
this.traceRequest(method, url, params, options, response);
}
throw error;
}
this.traceRequest(method, url, params, options, response);
return response;
}
traceRequest(method, url, params, options, response) {
if (!this.logTrace) {
return;
}
const sanitizedOptions = options ? structuredClone(options) : void 0;
if (sanitizedOptions?.headers) {
sanitizedOptions.headers = {
...sanitizedOptions.headers,
"X-API-Key": "(REDACTED)",
"X-Signature": "(REDACTED)"
};
}
if (method === "GET" || method === "DELETE") {
console.log(method, url, sanitizedOptions, response?.status, response?.statusText);
return;
}
console.log(method, url, params, sanitizedOptions, response?.status, response?.statusText);
}
/**
* Send a GET request to the Datanest API
* @param path e.g. `v1/projects`
* @param params Query parameters
* @param fetchOptions
* @throws DatanestResponseError Request HTTP server or validation error
* @returns Fetch response with readable stream.
*/
async get(path, params, fetchOptions) {
return await this.sendRequest("GET", path, params, fetchOptions);
}
/**
* Send a POST request to the Datanest API
* @param path e.g. `v1/projects`
* @param params Will be converted to JSON in request body
* @param fetchOptions
* @throws DatanestResponseError Request HTTP server or validation error
* @returns Fetch response with readable stream.
*/
async post(path, params, fetchOptions) {
return await this.sendRequest("POST", path, params, fetchOptions);
}
/**
* Send a PATCH request to the Datanest API
* @param path e.g. `v1/projects/{uuid}`
* @param params Will be converted to JSON in request body
* @param fetchOptions
* @throws DatanestResponseError Request HTTP server or validation error
* @returns Fetch response with readable stream.
*/
async patch(path, params, fetchOptions) {
return await this.sendRequest("PATCH", path, params, fetchOptions);
}
/**
* Send a PUT request to the Datanest API
* @param path e.g. `v1/projects/{uuid}`
* @param params Will be converted to JSON in request body
* @param fetchOptions
* @throws DatanestResponseError Request HTTP server or validation error
* @returns Fetch response with readable stream.
*/
async put(path, params, fetchOptions) {
return await this.sendRequest("PUT", path, params, fetchOptions);
}
/**
* Send a DELETE request to the Datanest API
* @param path e.g. `v1/projects/{uuid}`
* @param params Query parameters
* @param fetchOptions
* @throws DatanestResponseError Request HTTP server or validation error
* @returns Fetch response with readable stream.
*/
async delete(path, params, fetchOptions) {
return await this.sendRequest("DELETE", path, params, fetchOptions);
}
/**
* Set the base URL for the Datanest API
* @param baseUrl e.g. `https://app.datanest.earth/api`
*/
setBaseUrl(baseUrl) {
this.baseUrl = baseUrl;
if (!this.baseUrl.endsWith("/api")) {
throw new Error('Invalid base URL. Must end with "/api"');
}
}
/**
* Set your client ID for the Datanest API
* This will append the `X-Client-ID` header to all requests
* @param clientId Your application identifier, this can assist Datanest for debugging assistance
*/
setClientId(clientId) {
this.clientId = clientId;
}
removeClientId() {
this.clientId = null;
}
};
var DatanestResponseError = class extends Error {
constructor(message, status, data) {
super(message);
this.status = status;
this.data = data;
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
DatanestClient,
DatanestResponseError,
enviro,
files,
gather,
integrations,
projects,
teams,
user,
users,
webhook,
workflows
});