UNPKG

@knapsack/app

Version:

Build Design Systems on top of knapsack, by Basalt

332 lines (309 loc) • 7.98 kB
/** * Copyright (C) 2018 Basalt This file is part of Knapsack. Knapsack is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Knapsack is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Knapsack; if not, see <https://www.gnu.org/licenses>. */ import { DocumentNode } from 'graphql'; import md5 from 'md5'; import { apiUrlBase, graphqlBase } from '../lib/constants'; import { createDemoUrl } from '../lib/routes'; import { KnapsackTemplateDemo } from '../schemas/patterns'; import * as Files from '../schemas/api/files'; import * as Plugins from '../schemas/api/plugins'; import { AppState } from './store'; import { KsRenderResults, KsTemplateRenderedMeta, KsTemplateUrls, } from '../schemas/knapsack-config'; import { timer } from '../lib/utils'; import { FileResponse } from '../schemas/misc'; import { PatternRenderData } from '../schemas/api/render'; export { Files }; /** * GraphQL Query Object to String * @param gqlQueryObject - GraphQL query made from `gql` - https://github.com/apollographql/graphql-tag/issues/150 * @return {string} */ export function gqlToString(gqlQueryObject: DocumentNode): string { return gqlQueryObject.loc.source.body; } export interface GraphQlResponse { data?: any; errors?: { message: string; extensions: { code: string; stacktrace: string[]; }; locations: { line: number; column: number; }[]; }[]; } /** * GraphQL Query * Must pass in `query` OR `gqlQuery` */ export function gqlQuery({ query, gqlQueryObj, variables = {}, }: { /** * Plain GraphQL query */ query?: string | DocumentNode; /** * GraphQL query made from `gql` */ gqlQueryObj?: DocumentNode; /** * GraphQL variables */ variables?: object; }): Promise<GraphQlResponse> { if (!query && !gqlQueryObj) { throw new Error('Must provide either "query" or "gqlQueryObj".'); } if (typeof query !== 'string') { if (gqlQueryObj.kind !== 'Document') { throw new Error('"gqlQueryObj" not a valid GraphQL document.'); } // get the plain string from the `gql` parsed object query = gqlToString(gqlQueryObj); // eslint-disable-line no-param-reassign } return window .fetch(graphqlBase, { method: 'POST', headers: { 'Accept-Encoding': 'gzip, deflate, br', 'Content-Type': 'application/json', Accept: 'application/json', Connection: 'keep-alive', Dnt: '1', }, body: JSON.stringify({ query, variables, }), }) .then(res => res.json()) .catch(console.log.bind(console)); } type KnapsackDesignToken = import('@knapsack/core/types').KnapsackDesignToken; export function getDesignTokens(): Promise<KnapsackDesignToken[]> { return window.fetch(`${apiUrlBase}/design-tokens`).then(res => res.json()); } export function files(x: Files.Actions): Promise<Files.ActionResponses> { return window .fetch(Files.endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json', }, body: JSON.stringify(x), }) .then(res => { if (!res.ok) { const { status, statusText } = res; console.error(`Error in calling files endpoint`, { status, statusText, }); } return res.json(); }); } export function getPluginContent({ pluginId, }: { pluginId: string; }): Promise<Plugins.GetContentResponse> { const body: Plugins.GetContentRequest = { pluginId, type: Plugins.ACTIONS.getContent, }; return fetch(Plugins.endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json', }, body: JSON.stringify(body), }).then(res => res.json()); } /** * Save data up on server to be used in template rendering with `dataId` query param later * @returns dataId that is md5 hash */ export function saveData(data: object): Promise<string> { return window .fetch(`${apiUrlBase}/data`, { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json', }, body: JSON.stringify(data), }) .then(res => res.json()) .then(results => { if (!results.ok) { console.error( `Uh oh! Tried to save data by uploading it to '${apiUrlBase}/data' with no luck.`, { data, results, }, ); } return results.data.hash; }) .catch(console.log.bind(console)); } export function uploadFile(file: File): Promise<FileResponse> { const body = new FormData(); body.append('file', file); return window .fetch(`${apiUrlBase}/upload`, { method: 'POST', headers: { Accept: 'application/json', }, body, }) .then(res => res.json()) .then(response => { if (!response.ok) { console.error('uh oh: upload crap out', response); } return response; }); } export function getInitialState(): Promise<AppState> { const getTime = timer(); return window .fetch(`${apiUrlBase}/data-store`) .then(res => res.json()) .then(initialState => { console.debug(`KS: initial state fetch took: ${getTime()}s`); // console.log({ initialState }); return initialState; }) .catch(console.log.bind(console)); } export function renderTemplate( options: PatternRenderData, ): Promise<KsRenderResults> { return window .fetch(`${apiUrlBase}/render`, { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json', }, body: JSON.stringify(options), }) .then(res => res.json()) .catch(console.log.bind(console)); } const prevDataIds = new Map<string, string>(); /** * Get a URL where this Pattern's Template can be viewed */ export async function getTemplateUrls({ patternId, templateId, assetSetId, demo, cacheBuster, }: { patternId: string; templateId?: string; assetSetId?: string; demo: KnapsackTemplateDemo; cacheBuster?: string; }): Promise<{ dataId: string; urls: KsTemplateUrls; }> { const hash = md5(JSON.stringify(demo)); const dataId = prevDataIds.has(hash) ? prevDataIds.get(hash) : await saveData(demo); if (!prevDataIds.has(hash)) { prevDataIds.set(hash, dataId); } return { dataId, urls: { external: createDemoUrl({ patternId, templateId, assetSetId, dataId, cacheBuster, isInIframe: false, wrapHtml: true, }), iframeSrc: createDemoUrl({ patternId, templateId, assetSetId, dataId, cacheBuster, isInIframe: true, wrapHtml: true, }), }, }; } /** * Get a URL where this Pattern's Template can be viewed */ export async function getTemplateInfo({ patternId, templateId, assetSetId, demo, cacheBuster, }: { patternId: string; templateId?: string; assetSetId?: string; demo: KnapsackTemplateDemo; cacheBuster?: string; }): Promise<KsTemplateRenderedMeta> { const { dataId, urls } = await getTemplateUrls({ patternId, templateId, assetSetId, demo, cacheBuster, }); const renderResults = await renderTemplate({ patternId, templateId, dataId, assetSetId, isInIframe: false, wrapHtml: false, }); return { ...renderResults, urls, dataId, }; }