UNPKG

@saleor/app-sdk

Version:
330 lines (314 loc) 12.1 kB
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _chunkKM2345JLjs = require('../../chunk-KM2345JL.js'); var _chunk3OYW6U6Kjs = require('../../chunk-3OYW6U6K.js'); require('../../chunk-DE4A7PET.js'); // src/APL/saleor-cloud/saleor-cloud-apl.ts var _api = require('@opentelemetry/api'); var _semanticconventions = require('@opentelemetry/semantic-conventions'); // src/has-prop.ts function hasProp(obj, key) { return key != null && obj != null && typeof obj === "object" && key in obj; } // src/APL/has-auth-data.ts var hasAuthData = (data) => hasProp(data, "token") && data.token && hasProp(data, "appId") && data.appId && hasProp(data, "saleorApiUrl") && data.saleorApiUrl; // src/APL/auth-data-from-object.ts var debug = _chunk3OYW6U6Kjs.createAPLDebug.call(void 0, "authDataFromObject"); var authDataFromObject = (parsed) => { if (!hasAuthData(parsed)) { debug("Given object did not contained AuthData"); return void 0; } const { saleorApiUrl, appId, token, jwks } = parsed; return { saleorApiUrl, appId, token, jwks }; }; // src/APL/saleor-cloud/paginator.ts var debug2 = _chunk3OYW6U6Kjs.createAPLDebug.call(void 0, "Paginator"); var Paginator = class { constructor(url, fetchOptions, fetchFn = fetch) { this.url = url; this.fetchOptions = fetchOptions; this.fetchFn = fetchFn; } async fetchAll() { debug2("Fetching all pages for url", this.url); const response = await this.fetchFn(this.url, this.fetchOptions); debug2("%0", response); const json = await response.json(); if (json.next) { const remainingPages = await this.fetchNext(json.next); const allResults = [...json.results, ...remainingPages.flatMap((page) => page.results)]; debug2("Fetched all pages, total length: %d", allResults.length); return { next: null, previous: null, count: allResults.length, results: allResults }; } debug2("No more pages to fetch, returning first page"); return json; } async fetchNext(nextUrl) { debug2("Fetching next page with url %s", nextUrl); const response = await this.fetchFn(nextUrl, this.fetchOptions); debug2("%0", response); const json = await response.json(); if (json.next) { return [json, ...await this.fetchNext(json.next)]; } return [json]; } }; // src/APL/saleor-cloud/saleor-cloud-apl-errors.ts var SaleorCloudAplError = class extends Error { constructor(code, message) { super(message); this.code = code; this.name = "SaleorCloudAplError"; } }; var CloudAplError = { FAILED_TO_REACH_API: "FAILED_TO_REACH_API", RESPONSE_BODY_INVALID: "RESPONSE_BODY_INVALID", RESPONSE_NON_200: "RESPONSE_NON_200", ERROR_SAVING_DATA: "ERROR_SAVING_DATA", ERROR_DELETING_DATA: "ERROR_DELETING_DATA" }; // src/APL/saleor-cloud/saleor-cloud-apl.ts var debug3 = _chunk3OYW6U6Kjs.createAPLDebug.call(void 0, "SaleorCloudAPL"); var validateResponseStatus = (response) => { if (!response.ok) { debug3("Response failed with status %s", response.status); debug3("%O", response); throw new SaleorCloudAplError( CloudAplError.RESPONSE_NON_200, `Fetch returned with non 200 status code ${response.status}` ); } }; var mapAuthDataToAPIBody = (authData) => ({ saleor_app_id: authData.appId, saleor_api_url: authData.saleorApiUrl, jwks: authData.jwks, token: authData.token, domain: new URL(authData.saleorApiUrl).hostname }); var mapAPIResponseToAuthData = (response) => ({ appId: response.saleor_app_id, jwks: response.jwks, saleorApiUrl: response.saleor_api_url, token: response.token }); var extractErrorMessage = (error) => { if (typeof error === "string") { return error; } if (hasProp(error, "message")) { return error.message; } return "Unknown error"; }; var SaleorCloudAPL = class { constructor(config) { this.resourceUrl = config.resourceUrl; this.headers = { Authorization: `Bearer ${config.token}` }; this.tracer = _chunkKM2345JLjs.getOtelTracer.call(void 0, ); this.cacheManager = _optionalChain([config, 'optionalAccess', _ => _.experimental, 'optionalAccess', _2 => _2.cacheManager]); this.pageLimit = _nullishCoalesce(config.pageLimit, () => ( 1e3)); } getUrlForDomain(saleorApiUrl) { return `${this.resourceUrl}/${Buffer.from(saleorApiUrl).toString("base64url")}`; } getUrlWithLimit() { return `${this.resourceUrl}?limit=${this.pageLimit}`; } setToCacheIfExists(saleorApiUrl, authData) { if (!this.cacheManager) { return; } this.cacheManager.set(authData.saleorApiUrl, authData); } deleteFromCacheIfExists(saleorApiUrl) { if (!this.cacheManager) { return; } this.cacheManager.delete(saleorApiUrl); } getFromCacheIfExists(saleorApiUrl) { return _optionalChain([this, 'access', _3 => _3.cacheManager, 'optionalAccess', _4 => _4.get, 'call', _5 => _5(saleorApiUrl)]); } async get(saleorApiUrl) { const cachedData = this.getFromCacheIfExists(saleorApiUrl); if (cachedData) { debug3("Returning authData from cache for saleorApiUrl %s", saleorApiUrl); return cachedData; } debug3("Will fetch data from SaleorCloudAPL for saleorApiUrl %s", saleorApiUrl); return this.tracer.startActiveSpan( "SaleorCloudAPL.get", { attributes: { saleorApiUrl, [_semanticconventions.SemanticAttributes.PEER_SERVICE]: _chunkKM2345JLjs.OTEL_APL_SERVICE_NAME }, kind: _api.SpanKind.CLIENT }, async (span) => { const response = await fetch(this.getUrlForDomain(saleorApiUrl), { method: "GET", headers: { "Content-Type": "application/json", ...this.headers } }).catch((error) => { debug3("Failed to reach API call: %s", extractErrorMessage(error)); debug3("%O", error); span.recordException(CloudAplError.FAILED_TO_REACH_API); span.setStatus({ code: _api.SpanStatusCode.ERROR, message: extractErrorMessage(error) }).end(); throw new SaleorCloudAplError( CloudAplError.FAILED_TO_REACH_API, `${extractErrorMessage(error)}` ); }); if (!response) { debug3("No response from the API"); span.recordException(CloudAplError.FAILED_TO_REACH_API); span.setStatus({ code: _api.SpanStatusCode.ERROR, message: "Response couldn't be resolved" }).end(); throw new SaleorCloudAplError( CloudAplError.FAILED_TO_REACH_API, "Response couldn't be resolved" ); } if (response.status >= 500) { const message = `Api responded with ${response.status}`; span.recordException(CloudAplError.FAILED_TO_REACH_API); span.setStatus({ code: _api.SpanStatusCode.ERROR, message }).end(); throw new SaleorCloudAplError(CloudAplError.FAILED_TO_REACH_API, message); } if (response.status === 404) { debug3("No auth data for given saleorApiUrl"); span.addEvent("Missing auth data for given saleorApiUrl"); span.setStatus({ code: _api.SpanStatusCode.OK }).end(); return void 0; } const parsedResponse = await response.json().catch((e) => { debug3("Failed to parse response: %s", extractErrorMessage(e)); debug3("%O", e); const message = `Cant parse response body: ${extractErrorMessage(e)}`; span.recordException(CloudAplError.RESPONSE_BODY_INVALID); span.setStatus({ code: _api.SpanStatusCode.ERROR, message }).end(); throw new SaleorCloudAplError(CloudAplError.RESPONSE_BODY_INVALID, message); }); const authData = authDataFromObject(mapAPIResponseToAuthData(parsedResponse)); if (!authData) { debug3("No auth data for given saleorApiUrl"); span.addEvent("Missing auth data for given saleorApiUrl"); span.setStatus({ code: _api.SpanStatusCode.OK }).end(); return void 0; } span.setAttribute("appId", authData.appId); this.setToCacheIfExists(authData.saleorApiUrl, authData); span.setStatus({ code: _api.SpanStatusCode.OK }).end(); return authData; } ); } async set(authData) { debug3("Saving data to SaleorCloudAPL for saleorApiUrl: %s", authData.saleorApiUrl); return this.tracer.startActiveSpan( "SaleorCloudAPL.set", { attributes: { saleorApiUrl: authData.saleorApiUrl, appId: authData.appId, [_semanticconventions.SemanticAttributes.PEER_SERVICE]: _chunkKM2345JLjs.OTEL_APL_SERVICE_NAME }, kind: _api.SpanKind.CLIENT }, async (span) => { const response = await fetch(this.resourceUrl, { method: "POST", headers: { "Content-Type": "application/json", ...this.headers }, body: JSON.stringify(mapAuthDataToAPIBody(authData)) }).catch((e) => { debug3("Failed to reach API call: %s", extractErrorMessage(e)); debug3("%O", e); span.recordException(`Failed to reach API call: ${extractErrorMessage(e)}`); span.setStatus({ code: _api.SpanStatusCode.ERROR }).end(); throw new SaleorCloudAplError( CloudAplError.ERROR_SAVING_DATA, `Error during saving the data: ${extractErrorMessage(e)}` ); }); validateResponseStatus(response); debug3("Set command finished successfully for saleorApiUrl: %", authData.saleorApiUrl); this.setToCacheIfExists(authData.saleorApiUrl, authData); span.setStatus({ code: _api.SpanStatusCode.OK }); span.end(); return void 0; } ); } async delete(saleorApiUrl) { debug3("Deleting data from SaleorCloud for saleorApiUrl: %s", saleorApiUrl); try { const response = await fetch(this.getUrlForDomain(saleorApiUrl), { method: "DELETE", headers: { "Content-Type": "application/json", ...this.headers } }); this.deleteFromCacheIfExists(saleorApiUrl); debug3(`Delete responded with ${response.status} code`); } catch (error) { const errorMessage = extractErrorMessage(error); debug3("Error during deleting the data: %s", errorMessage); debug3("%O", error); throw new SaleorCloudAplError( CloudAplError.ERROR_DELETING_DATA, `Error during deleting the data: ${errorMessage}` ); } } async getAll() { debug3("Get all data from SaleorCloud"); try { const paginator = new Paginator(this.getUrlWithLimit(), { method: "GET", headers: { "Content-Type": "application/json", ...this.headers } }); const responses = await paginator.fetchAll(); return responses.results.map(mapAPIResponseToAuthData); } catch (error) { const errorMessage = extractErrorMessage(error); debug3("Error during getting all the data:", errorMessage); debug3("%O", error); } return []; } }; exports.CloudAplError = CloudAplError; exports.SaleorCloudAPL = SaleorCloudAPL; exports.SaleorCloudAplError = SaleorCloudAplError;