'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var errors = require('@backstage/errors');
var fetch = require('cross-fetch');
var uuid = require('uuid');
var zod = require('zod');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

function _interopNamespace(e) {
  if (e && e.__esModule) return e;
  var n = Object.create(null);
  if (e) {
    Object.keys(e).forEach(function (k) {
      if (k !== 'default') {
        var d = Object.getOwnPropertyDescriptor(e, k);
        Object.defineProperty(n, k, d.get ? d : {
          enumerable: true,
          get: function () { return e[k]; }
        });
      }
    });
  }
  n["default"] = e;
  return Object.freeze(n);
}

var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
var uuid__namespace = /*#__PURE__*/_interopNamespace(uuid);

var AuthorizeResult = /* @__PURE__ */ ((AuthorizeResult2) => {
  AuthorizeResult2["DENY"] = "DENY";
  AuthorizeResult2["ALLOW"] = "ALLOW";
  AuthorizeResult2["CONDITIONAL"] = "CONDITIONAL";
  return AuthorizeResult2;
})(AuthorizeResult || {});

function isPermission(permission, comparedPermission) {
  return permission.name === comparedPermission.name;
}
function isResourcePermission(permission, resourceType) {
  if (!("resourceType" in permission)) {
    return false;
  }
  return !resourceType || permission.resourceType === resourceType;
}
function isCreatePermission(permission) {
  return permission.attributes.action === "create";
}
function isReadPermission(permission) {
  return permission.attributes.action === "read";
}
function isUpdatePermission(permission) {
  return permission.attributes.action === "update";
}
function isDeletePermission(permission) {
  return permission.attributes.action === "delete";
}
function toPermissionEvaluator(permissionAuthorizer) {
  return {
    authorize: async (requests, options) => {
      const response = await permissionAuthorizer.authorize(requests, options);
      return response;
    },
    authorizeConditional(requests, options) {
      const parsedRequests = requests;
      return permissionAuthorizer.authorize(parsedRequests, options);
    }
  };
}

function createPermission({
  name,
  attributes,
  resourceType
}) {
  if (resourceType) {
    return {
      type: "resource",
      name,
      attributes,
      resourceType
    };
  }
  return {
    type: "basic",
    name,
    attributes
  };
}

var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
  return value;
};
const permissionCriteriaSchema = zod.z.lazy(
  () => zod.z.object({
    rule: zod.z.string(),
    resourceType: zod.z.string(),
    params: zod.z.record(zod.z.any()).optional()
  }).or(zod.z.object({ anyOf: zod.z.array(permissionCriteriaSchema).nonempty() })).or(zod.z.object({ allOf: zod.z.array(permissionCriteriaSchema).nonempty() })).or(zod.z.object({ not: permissionCriteriaSchema }))
);
const authorizePermissionResponseSchema = zod.z.object({
  result: zod.z.literal(AuthorizeResult.ALLOW).or(zod.z.literal(AuthorizeResult.DENY))
});
const queryPermissionResponseSchema = zod.z.union([
  zod.z.object({
    result: zod.z.literal(AuthorizeResult.ALLOW).or(zod.z.literal(AuthorizeResult.DENY))
  }),
  zod.z.object({
    result: zod.z.literal(AuthorizeResult.CONDITIONAL),
    pluginId: zod.z.string(),
    resourceType: zod.z.string(),
    conditions: permissionCriteriaSchema
  })
]);
const responseSchema = (itemSchema, ids) => zod.z.object({
  items: zod.z.array(
    zod.z.intersection(
      zod.z.object({
        id: zod.z.string()
      }),
      itemSchema
    )
  ).refine(
    (items) => items.length === ids.size && items.every(({ id }) => ids.has(id)),
    {
      message: "Items in response do not match request"
    }
  )
});
class PermissionClient {
  constructor(options) {
    __publicField(this, "enabled");
    __publicField(this, "discovery");
    var _a;
    this.discovery = options.discovery;
    this.enabled = (_a = options.config.getOptionalBoolean("permission.enabled")) != null ? _a : false;
  }
  /**
   * {@inheritdoc PermissionEvaluator.authorize}
   */
  async authorize(requests, options) {
    return this.makeRequest(
      requests,
      authorizePermissionResponseSchema,
      options
    );
  }
  /**
   * {@inheritdoc PermissionEvaluator.authorizeConditional}
   */
  async authorizeConditional(queries, options) {
    return this.makeRequest(queries, queryPermissionResponseSchema, options);
  }
  async makeRequest(queries, itemSchema, options) {
    if (!this.enabled) {
      return queries.map((_) => ({ result: AuthorizeResult.ALLOW }));
    }
    const request = {
      items: queries.map((query) => ({
        id: uuid__namespace.v4(),
        ...query
      }))
    };
    const permissionApi = await this.discovery.getBaseUrl("permission");
    const response = await fetch__default["default"](`${permissionApi}/authorize`, {
      method: "POST",
      body: JSON.stringify(request),
      headers: {
        ...this.getAuthorizationHeader(options == null ? void 0 : options.token),
        "content-type": "application/json"
      }
    });
    if (!response.ok) {
      throw await errors.ResponseError.fromResponse(response);
    }
    const responseBody = await response.json();
    const parsedResponse = responseSchema(
      itemSchema,
      new Set(request.items.map(({ id }) => id))
    ).parse(responseBody);
    const responsesById = parsedResponse.items.reduce((acc, r) => {
      acc[r.id] = r;
      return acc;
    }, {});
    return request.items.map((query) => responsesById[query.id]);
  }
  getAuthorizationHeader(token) {
    return token ? { Authorization: `Bearer ${token}` } : {};
  }
}

exports.AuthorizeResult = AuthorizeResult;
exports.PermissionClient = PermissionClient;
exports.createPermission = createPermission;
exports.isCreatePermission = isCreatePermission;
exports.isDeletePermission = isDeletePermission;
exports.isPermission = isPermission;
exports.isReadPermission = isReadPermission;
exports.isResourcePermission = isResourcePermission;
exports.isUpdatePermission = isUpdatePermission;
exports.toPermissionEvaluator = toPermissionEvaluator;
//# sourceMappingURL=index.cjs.js.map
