UNPKG

@cerbos/http

Version:

Client library for interacting with the Cerbos policy decision point service over HTTP from browser-based applications

247 lines 9.25 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Transport = void 0; exports.eachLine = eachLine; const qs_1 = require("qs"); const core_1 = require("@cerbos/core"); const request_1 = require("./protobuf/cerbos/request/v1/request"); const response_1 = require("./protobuf/cerbos/response/v1/response"); const health_1 = require("./protobuf/grpc/health/v1/health"); const services = { admin: { addOrUpdatePolicy: { method: "POST", path: "/admin/policy", requestType: request_1.AddOrUpdatePolicyRequest, responseType: response_1.AddOrUpdatePolicyResponse, serializeRequest: serializeRequestToBody, }, addOrUpdateSchema: { method: "POST", path: "/admin/schema", requestType: request_1.AddOrUpdateSchemaRequest, responseType: response_1.AddOrUpdateSchemaResponse, serializeRequest: serializeRequestToBody, }, deleteSchema: { method: "DELETE", path: "/admin/schema", requestType: request_1.DeleteSchemaRequest, responseType: response_1.DeleteSchemaResponse, serializeRequest: serializeRequestToQueryString, }, disablePolicy: { method: "DELETE", path: "/admin/policy", requestType: request_1.DisablePolicyRequest, responseType: response_1.DisablePolicyResponse, serializeRequest: serializeRequestToQueryString, }, enablePolicy: { method: "POST", path: "/admin/policy/enable", requestType: request_1.EnablePolicyRequest, responseType: response_1.EnablePolicyResponse, serializeRequest: serializeRequestToQueryString, }, getPolicy: { method: "GET", path: "/admin/policy", requestType: request_1.GetPolicyRequest, responseType: response_1.GetPolicyResponse, serializeRequest: serializeRequestToQueryString, }, getSchema: { method: "GET", path: "/admin/schema", requestType: request_1.GetSchemaRequest, responseType: response_1.GetSchemaResponse, serializeRequest: serializeRequestToQueryString, }, inspectPolicies: { method: "GET", path: "/admin/policies/inspect", requestType: request_1.InspectPoliciesRequest, responseType: response_1.InspectPoliciesResponse, serializeRequest: serializeRequestToQueryString, }, listAuditLogEntries: { method: "GET", path: "/admin/auditlog/list/", requestType: request_1.ListAuditLogEntriesRequest, responseType: response_1.ListAuditLogEntriesResponse, serializeRequest: serializeListAuditLogEntriesRequest, }, listPolicies: { method: "GET", path: "/admin/policies", requestType: request_1.ListPoliciesRequest, responseType: response_1.ListPoliciesResponse, serializeRequest: serializeRequestToQueryString, }, listSchemas: { method: "GET", path: "/admin/schemas", requestType: request_1.ListSchemasRequest, responseType: response_1.ListSchemasResponse, serializeRequest: serializeRequestToQueryString, }, reloadStore: { method: "GET", path: "/admin/store/reload", requestType: request_1.ReloadStoreRequest, responseType: response_1.ReloadStoreResponse, serializeRequest: serializeRequestToQueryString, }, }, cerbos: { checkResources: { method: "POST", path: "/api/check/resources", requestType: request_1.CheckResourcesRequest, responseType: response_1.CheckResourcesResponse, serializeRequest: serializeRequestToBody, }, planResources: { method: "POST", path: "/api/plan/resources", requestType: request_1.PlanResourcesRequest, responseType: response_1.PlanResourcesResponse, serializeRequest: serializeRequestToBody, }, serverInfo: { method: "GET", path: "/api/server_info", requestType: request_1.ServerInfoRequest, responseType: response_1.ServerInfoResponse, serializeRequest: serializeRequestToQueryString, }, }, health: { check: { method: "GET", path: "/_cerbos/health", requestType: health_1.HealthCheckRequest, responseType: health_1.HealthCheckResponse, serializeRequest: serializeRequestToQueryString, }, }, }; class Transport { baseUrl; userAgent; constructor(baseUrl, userAgent) { this.baseUrl = baseUrl; this.userAgent = userAgent; } async unary(service, method, request, headers, abortHandler) { const { response, responseType } = await this.fetch(service, method, request, headers, abortHandler); if (!response.ok) { throw core_1.NotOK.fromJSON(await response.text()); } return responseType.fromJSON(await response.json()); } async *serverStream(service, method, request, headers, abortHandler) { const { response, responseType } = await this.fetch(service, method, request, headers, abortHandler); try { if (!response.body) { throw new Error("Missing response body"); } for await (const line of eachLine(response.body)) { const message = JSON.parse(line); if (!(0, core_1._isObject)(message)) { throw new Error(`Unexpected message: wanted object, got ${line}`); } const { result, error } = message; if (error) { throw core_1.NotOK.fromJSON(JSON.stringify(error)); } if (!result) { throw new Error(`Missing result in ${line}`); } yield responseType.fromJSON(result); } } catch (error) { response.body?.cancel().catch(() => { // ignore failure to cancel }); abortHandler.throwIfAborted(); if (error instanceof core_1.NotOK) { throw error; } throw new core_1.NotOK(core_1.Status.INTERNAL, error instanceof Error ? `Invalid stream: ${error.message}` : "Invalid stream", { cause: error }); } } async fetch(service, method, request, headers, abortHandler) { const { method: requestMethod, path, requestType, responseType, serializeRequest, } = services[service][method]; // https://github.com/microsoft/TypeScript/issues/30581 headers.set("User-Agent", this.userAgent); const init = { url: this.baseUrl + path, method: requestMethod, headers, }; if (abortHandler.signal) { init.signal = abortHandler.signal; } const { url, ...rest } = serializeRequest(request, requestType, init); try { return { response: await fetch(url, rest), responseType, }; } catch (error) { abortHandler.throwIfAborted(); throw new core_1.NotOK(core_1.Status.UNKNOWN, error instanceof Error ? `Request failed: ${error.message}` : "Request failed", { cause: error }); } } } exports.Transport = Transport; function serializeRequestToBody(request, requestType, init) { return { ...init, body: JSON.stringify(requestType.toJSON(request)), }; } function serializeRequestToQueryString(request, requestType, { url, ...init }) { return { ...init, url: `${url}?${queryStringifyRequest(requestType, request)}`, }; } function serializeListAuditLogEntriesRequest({ kind, ...rest }, requestType, { url, ...init }) { return { ...init, url: `${url}${request_1.ListAuditLogEntriesRequest_Kind[kind]}?${queryStringifyRequest(requestType, { kind: 0, ...rest })}`, }; } function queryStringifyRequest(requestType, request) { return (0, qs_1.stringify)(requestType.toJSON(request), { allowDots: true, arrayFormat: "repeat", }); } async function* eachLine(stream) { const utf8Decoder = new TextDecoder("utf-8", { fatal: true }); let buffer = ""; let start = 0; for await (const chunk of stream) { buffer += utf8Decoder.decode(chunk, { stream: true }); let end; while ((end = buffer.indexOf("\n", start)) >= 0) { yield buffer.slice(start, end); start = end + 1; } buffer = buffer.slice(start); start = 0; } if (buffer.length > 0) { yield buffer; } } //# sourceMappingURL=transport.js.map