import Axios, {AxiosInstance, AxiosRequestConfig} from "axios"; import {parseCookies} from "nookies"; import "reflect-metadata"; import {getUserTokens} from "./browser_auth/auth"; import {Config} from "./Config"; import {Content} from "./resources/Content"; import {Contribute} from "./resources/Contribute"; import {Search} from "./resources/Search"; const rateLimit = require("axios-rate-limit"); const requireLogin = (args: any, loginRedirect: any) => { const redirect_path = args.req ? `${args.req.protocol}://${args.req.get("host")}${args.req.path}` : `${window.location.protocol}//${window.location.host}${window.location.pathname}`; const destination = `${loginRedirect}?redirect_to=${encodeURI(redirect_path)}`; if (args.res) { args.res.redirect(destination); } else { window.location.href = destination; } }; export interface IClientArgs { org: string; token: string; rootMapId: string; timeout?: number; scheme?: string; hostname?: string; env?: string; deploymentId?: string; content_root?: string; loginRedirect?: string; loginRequired?: boolean; interceptors?: Array<(axios: AxiosInstance) => void>; rateLimit?: { maxRequests?: number; maxRPS: number; } } const EZD_CLIENT_VERSION = "0.1.0"; const API_VERSION = "v1"; export default class Client { public readonly base_url: string; public readonly deploy_api_base_url: string; public content_axios: AxiosInstance; public contribute_axios: AxiosInstance; public content: Content; public search: Search; public contribute: Contribute; public content_service_token: string; public initial_args: IClientArgs; private readonly new_api: boolean = false; constructor(args: IClientArgs) { const { org, token, rootMapId, timeout = 3000, scheme = "https://", hostname = "content.easydita.com", env = "latest", deploymentId, content_root = "content", interceptors = [], rateLimit: rateLimitConfig = { maxRPS: 5, maxRequests: 2 }, } = args; if (deploymentId) { this.new_api = true; } else { this.new_api = false; } this.initial_args = args; if (!org) { throw new Error("easyDITA org not set"); } if (!token) { throw new Error("easyDITA token not set"); } if (!rootMapId) { throw new Error("easyDITA rootMapId not set"); } this.base_url = `${scheme}${hostname}/org/${org}/env/${env}/map/${rootMapId}/` if (this.new_api) { this.deploy_api_base_url = `${scheme}${hostname}/org/${org}/deployments/${deploymentId}/`; } this.content_service_token = token; const config: AxiosRequestConfig = { baseURL: this.base_url, timeout, // withCredentials: true, headers: { // "X-EZD-Client": "JS/" + EZD_CLIENT_VERSION, }, }; const deploy_api_config: AxiosRequestConfig = { baseURL: this.deploy_api_base_url, timeout, // withCredentials: true, headers: { "Accept-Language": "en" // "X-EZD-Client": "JS/" + EZD_CLIENT_VERSION, }, }; this.content_axios = rateLimit(this.new_api ? Axios.create(deploy_api_config) : Axios.create(config), rateLimitConfig); this.content_axios.interceptors.request.use(intercepted_config => { if (!intercepted_config.params) { intercepted_config.params = {}; } // intercepted_config.headers["Content-Type"] = "application/text"; intercepted_config.params.token = this.user_token() ? this.user_token() : this.content_service_token; intercepted_config.params.link_root = content_root; return intercepted_config; }); interceptors.forEach(interceptor => interceptor(this.content_axios)); this.contribute_axios = Axios.create(config); this.contribute_axios.interceptors.request.use(intercepted_config => { if (!intercepted_config.params) { intercepted_config.params = {}; } intercepted_config.params.rootMapId = rootMapId; intercepted_config.params.token = this.user_token(); return intercepted_config; }); const portal_config = new Config(this.content_axios); this.content = new Content({ axios: this.content_axios, config: portal_config }); this.search = new Search({ axios: this.content_axios, rootMapId, config: portal_config }); this.contribute = new Contribute({ axios: this.contribute_axios, config: portal_config }); } public iframe_url() { let s = this.base_url; s = s.replace("https://", ""); s = s.replace("http://", ""); return s; } public user_token() { if (typeof window !== "undefined") { return getUserTokens().idToken; } else { return null; } } public async login() { // create an ezd session so the editor will load without asking user to login first const response = await this.content_axios.post("/auth"); } public async prepare(args): Promise { const cookies = args.req ? args.req.cookies : parseCookies(); const token = (args.req && args.req.query.portal_auth_token) || (cookies && cookies.portal_auth_token); // Make sure to keep this order -- query param overrides cookie if (this.initial_args.loginRequired) { try { this.content_service_token = token; await this.content.getSections(); args.res && args.res.cookie("portal_auth_token", token, {path: "/", domain: args.req.hostname}); } catch (e) { if (e.response && (e.response.status === 403 || e.response.status === 401)) { args.res && args.res.clearCookie("portal_auth_token"); requireLogin(args, this.initial_args.loginRedirect); } else { console.log(e); throw e; } } } return this; } }