@openfga/sdk
Version:
JavaScript and Node.js SDK for OpenFGA
199 lines (198 loc) • 8.12 kB
JavaScript
"use strict";
/**
* JavaScript and Node.js SDK for OpenFGA
*
* API version: 1.x
* Website: https://openfga.dev
* Documentation: https://openfga.dev/docs
* Support: https://openfga.dev/community
* License: [Apache-2.0](https://github.com/openfga/js-sdk/blob/main/LICENSE)
*
* NOTE: This file was auto generated by OpenAPI Generator (https://openapi-generator.tech). DO NOT EDIT.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.createRequestFunction = exports.toPathString = exports.serializeDataIfNeeded = exports.setSearchParams = exports.setBearerAuthToObject = exports.DUMMY_BASE_URL = void 0;
exports.attemptHttpRequest = attemptHttpRequest;
const errors_1 = require("./errors");
const utils_1 = require("./utils");
const attributes_1 = require("./telemetry/attributes");
const histograms_1 = require("./telemetry/histograms");
/**
*
* @export
*/
exports.DUMMY_BASE_URL = "https://example.com";
/**
*
* @export
*/
const setBearerAuthToObject = async function (object, credentials) {
const accessTokenHeader = await credentials.getAccessTokenHeader();
if (accessTokenHeader && !object[accessTokenHeader.name]) {
object[accessTokenHeader.name] = accessTokenHeader.value;
}
};
exports.setBearerAuthToObject = setBearerAuthToObject;
/**
*
* @export
*/
const setSearchParams = function (url, ...objects) {
const searchParams = new URLSearchParams(url.search);
for (const object of objects) {
for (const key in object) {
if (Array.isArray(object[key])) {
searchParams.delete(key);
for (const item of object[key]) {
searchParams.append(key, item);
}
}
else {
searchParams.set(key, object[key]);
}
}
}
url.search = searchParams.toString();
};
exports.setSearchParams = setSearchParams;
/**
* Check if the given MIME is a JSON MIME.
* JSON MIME examples:
* application/json
* application/json; charset=UTF8
* APPLICATION/JSON
* application/vnd.company+json
* @param mime - MIME (Multipurpose Internet Mail Extensions)
* @return True if the given MIME is JSON, false otherwise.
*/
const isJsonMime = (mime) => {
// eslint-disable-next-line no-control-regex
const jsonMime = new RegExp("^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$", "i");
return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === "application/json-patch+json");
};
/**
*
* @export
*/
const serializeDataIfNeeded = function (value, requestOptions) {
const nonString = typeof value !== "string";
const needsSerialization = nonString
? isJsonMime(requestOptions.headers["Content-Type"])
: nonString;
return needsSerialization
? JSON.stringify(value !== undefined ? value : {})
: (value || "");
};
exports.serializeDataIfNeeded = serializeDataIfNeeded;
/**
*
* @export
*/
const toPathString = function (url) {
return url.pathname + url.search + url.hash;
};
exports.toPathString = toPathString;
/**
* Returns true if this error is returned from axios
* source: https://github.com/axios/axios/blob/21a5ad34c4a5956d81d338059ac0dd34a19ed094/lib/helpers/isAxiosError.js#L12
* @param err
*/
function isAxiosError(err) {
return err && typeof err === "object" && err.isAxiosError === true;
}
function randomTime(loopCount, minWaitInMs) {
const min = Math.ceil(2 ** loopCount * minWaitInMs);
const max = Math.ceil(2 ** (loopCount + 1) * minWaitInMs);
return Math.floor(Math.random() * (max - min) + min); //The maximum is exclusive and the minimum is inclusive
}
async function attemptHttpRequest(request, config, axiosInstance) {
let iterationCount = 0;
do {
iterationCount++;
try {
const response = await axiosInstance(request);
return {
response: response,
retries: iterationCount - 1,
};
}
catch (err) {
if (!isAxiosError(err)) {
throw new errors_1.FgaError(err);
}
const status = err?.response?.status;
if (status === 400 || status === 422) {
throw new errors_1.FgaApiValidationError(err);
}
else if (status === 401 || status === 403) {
throw new errors_1.FgaApiAuthenticationError(err);
}
else if (status === 404) {
throw new errors_1.FgaApiNotFoundError(err);
}
else if (status === 429 || status >= 500) {
if (iterationCount >= config.maxRetry) {
// We have reached the max retry limit
// Thus, we have no choice but to throw
if (status === 429) {
throw new errors_1.FgaApiRateLimitExceededError(err);
}
else {
throw new errors_1.FgaApiInternalError(err);
}
}
await new Promise(r => setTimeout(r, randomTime(iterationCount, config.minWaitInMs)));
}
else {
throw new errors_1.FgaApiError(err);
}
}
} while (iterationCount < config.maxRetry + 1);
}
/**
* creates an axios request function
*/
const createRequestFunction = function (axiosArgs, axiosInstance, configuration, credentials, methodAttributes = {}) {
configuration.isValid();
const retryParams = axiosArgs.options?.retryParams ? axiosArgs.options?.retryParams : configuration.retryParams;
const maxRetry = retryParams ? retryParams.maxRetry : 0;
const minWaitInMs = retryParams ? retryParams.minWaitInMs : 0;
const start = performance.now();
return async (axios = axiosInstance) => {
await (0, exports.setBearerAuthToObject)(axiosArgs.options.headers, credentials);
const url = configuration.getBasePath() + axiosArgs.url;
const axiosRequestArgs = { ...axiosArgs.options, url: url };
const wrappedResponse = await attemptHttpRequest(axiosRequestArgs, {
maxRetry,
minWaitInMs,
}, axios);
const response = wrappedResponse?.response;
const data = typeof response?.data === "undefined" ? {} : response?.data;
const result = { ...data };
(0, utils_1.setNotEnumerableProperty)(result, "$response", response);
let attributes = {};
attributes = attributes_1.TelemetryAttributes.fromRequest({
userAgent: configuration.baseOptions?.headers["User-Agent"],
httpMethod: axiosArgs.options?.method,
url,
resendCount: wrappedResponse?.retries,
start: start,
credentials: credentials,
attributes: methodAttributes,
});
attributes = attributes_1.TelemetryAttributes.fromResponse({
response,
attributes,
});
// only if hisogramQueryDuration set AND if response header contains fga-query-duration-ms
const serverRequestDuration = attributes[attributes_1.TelemetryAttribute.HttpServerRequestDuration];
if (configuration.telemetry?.metrics?.histogramQueryDuration && typeof serverRequestDuration !== "undefined") {
configuration.telemetry.recorder.histogram(histograms_1.TelemetryHistograms.queryDuration, parseInt(attributes[attributes_1.TelemetryAttribute.HttpServerRequestDuration], 10), attributes_1.TelemetryAttributes.prepare(attributes, configuration.telemetry.metrics.histogramQueryDuration.attributes));
}
if (configuration.telemetry?.metrics?.histogramRequestDuration) {
configuration.telemetry.recorder.histogram(histograms_1.TelemetryHistograms.requestDuration, attributes[attributes_1.TelemetryAttribute.HttpClientRequestDuration], attributes_1.TelemetryAttributes.prepare(attributes, configuration.telemetry.metrics.histogramRequestDuration.attributes));
}
return result;
};
};
exports.createRequestFunction = createRequestFunction;