const { apiClientBaseURL } = require("../config-client") /** * convert object to string * @param {any} obj object * @returns {string} string */ function obj2str(obj) { if (Array.isArray(obj)) { return JSON.stringify( obj.map(function (idx) { return obj2str(idx) }) ) } else if (typeof obj === "object" && obj !== null) { var elements = Object.keys(obj) .sort() .map(function (key) { var val = obj2str(obj[key]) if (val) { return key + ":" + val } }) var elementsCleaned = [] for (var i = 0; i < elements.length; i++) { if (elements[i]) elementsCleaned.push(elements[i]) } return "{" + elementsCleaned.join("|") + "}" } if (obj) return obj } /** * api request via client or server * server function ssrRequest is called via context.ssrRequest, binded in ssr hook * * @param {string} endpoint * @param {ApiOptions} options * @param {any} body * @param {import("../../../frontend/src/sentry")} sentry * @param {typeof fetch} _fetch * @returns {Promise>} */ function apiRequest(endpoint, options, body, sentry, _fetch) { // TODO cache only for GET // first check cache if on client const cacheKey = obj2str({ endpoint: endpoint, options: options }) console.log("SSR CHECK", cacheKey) let method = options?.method || "GET" // @ts-ignore if (typeof window !== "undefined" && window.__SSR_CACHE__ && method === "GET") { // @ts-ignore const cache = window.__SSR_CACHE__[cacheKey] console.log("SSR HIT:", cacheKey, cache) if (cache) { return Promise.resolve(cache) } } let query = "&count=1" if (options?.filter) query += "&filter=" + encodeURIComponent(JSON.stringify(options.filter)) if (options?.sort) query += "&sort=" + options.sort + "&sort=_id" if (options?.limit) query += "&limit=" + options.limit if (options?.offset) query += "&offset=" + options.offset if (options?.projection) query += "&projection=" + options.projection if (options?.lookup) query += "&lookup=" + options.lookup if (options?.params) { Object.keys(options.params).forEach((p) => { query += "&" + p + "=" + encodeURIComponent(options.params[p]) }) } /** @type {{[key: string]: string}} */ let headers = { "Content-Type": "application/json", } if (options?.headers) headers = { ...headers, ...options.headers } if (typeof window === "undefined" && method === "GET") { // server // reference via context from get hook to tree shake in client // @ts-ignore const d = context.ssrRequest(cacheKey, endpoint, query, Object.assign({}, options, { method, headers })) return d } else { // client let url = apiClientBaseURL + endpoint + (query ? "?" + query : "") const span = sentry.currentTransaction()?.startChild({ op: "fetch", description: method + " " + url, data: Object.assign({}, options, { url }), }) const trace_id = span?.toTraceparent() if (trace_id) { headers["sentry-trace"] = trace_id } /** @type {{[key: string]: any}} */ const requestOptions = { method, mode: "cors", headers, } if (method === "POST" || method === "PUT") { requestOptions.body = JSON.stringify(body) } const response = _fetch(url, requestOptions).then((response) => { return response?.json().then((json) => { if (response?.status < 200 || response?.status >= 400) { return Promise.reject({ response, data: json }) } return Promise.resolve({ data: json || null, count: response.headers?.get("x-results-count") || 0 }) }) }) span?.end() // @ts-ignore return response } } module.exports = { obj2str, apiRequest, }