UNPKG

prismic-javascript

Version:
258 lines (230 loc) 8.83 kB
import { Document } from "./documents"; import { RequestHandler, RequestCallback } from './request'; import { ApiCache } from './cache'; import { Experiment, Experiments } from './experiments'; import { SearchForm, Form } from './form'; import Predicates from './Predicates'; import Cookies from './Cookies'; import ApiSearchResponse from './ApiSearchResponse'; import HttpClient from './HttpClient'; import { Client } from './client'; import { PreviewResolver, createPreviewResolver, LinkResolver } from './PreviewResolver'; export const PREVIEW_COOKIE = 'io.prismic.preview'; export const EXPERIMENT_COOKIE = 'io.prismic.experiment'; export interface Ref { ref: string; label: string; isMasterRef: boolean; scheduledAt: string; id: string; } export interface Language { id: string; name: string; } export interface ApiData { refs: Ref[]; bookmarks: { [key: string]: string }; languages: Language[]; types: { [key: string]: string }; tags: string[]; forms: { [key: string]: Form }; experiments: any; oauth_initiate: string; oauth_token: string; version: string; licence: string; } export interface PreviewResponse { mainDocument?: string; } export interface QueryOptions { [key: string]: string | number | string[]; } export interface ResolvedApiOptions { req?: any; } export default class ResolvedApi implements Client { data: ApiData; masterRef: Ref; experiments: Experiments; options: ResolvedApiOptions; httpClient: HttpClient; bookmarks: { [key: string]: string }; refs: Ref[]; tags: string[]; types: { [key: string]: string }; languages: Language[]; constructor(data: ApiData, httpClient: HttpClient, options: ResolvedApiOptions) { this.data = data; this.masterRef = data.refs.filter(ref => ref.isMasterRef)[0]; this.experiments = new Experiments(data.experiments); this.bookmarks = data.bookmarks; this.httpClient = httpClient; this.options = options; this.refs = data.refs; this.tags = data.tags; this.types = data.types; this.languages = data.languages; } /** * Returns a useable form from its id, as described in the RESTful description of the API. * For instance: api.form("everything") works on every repository (as "everything" exists by default) * You can then chain the calls: api.form("everything").query('[[:d = at(document.id, "UkL0gMuvzYUANCpf")]]').ref(ref).submit() */ form(formId: string): SearchForm | null { const form = this.data.forms[formId]; if (form) { return new SearchForm(form, this.httpClient); } return null; } everything(): SearchForm { const f = this.form('everything'); if (!f) throw new Error('Missing everything form'); return f; } /** * The ID of the master ref on this prismic.io API. * Do not use like this: searchForm.ref(api.master()). * Instead, set your ref once in a variable, and call it when you need it; this will allow to change the ref you're viewing easily for your entire page. */ master(): string { return this.masterRef.ref; } /** * Returns the ref ID for a given ref's label. * Do not use like this: searchForm.ref(api.ref("Future release label")). * Instead, set your ref once in a variable, and call it when you need it; this will allow to change the ref you're viewing easily for your entire page. */ ref(label: string): string | null { const ref = this.data.refs.filter(ref => ref.label === label)[0]; return ref ? ref.ref : null; } currentExperiment(): Experiment | null { return this.experiments.current(); } /** * Query the repository */ query(q: string | string[], optionsOrCallback: QueryOptions | RequestCallback<ApiSearchResponse>, cb: RequestCallback<ApiSearchResponse> = () => {}): Promise<ApiSearchResponse> { const { options, callback } = typeof optionsOrCallback === 'function' ? { options: {} as QueryOptions, callback: optionsOrCallback } : { options: optionsOrCallback || {}, callback: cb }; let form = this.everything(); for (const key in options) { form = form.set(key, options[key]); } if (!options.ref) { // Look in cookies if we have a ref (preview or experiment) let cookieString = ''; if (this.options.req) { // NodeJS cookieString = this.options.req.headers['cookie'] || ''; } else if (typeof window !== 'undefined' && window.document) { // Browser cookieString = window.document.cookie || ''; } const cookies = Cookies.parse(cookieString); const previewRef = cookies[PREVIEW_COOKIE]; const experimentRef = this.experiments.refFromCookie(cookies[EXPERIMENT_COOKIE]); form = form.ref(previewRef || experimentRef || this.masterRef.ref); } if (q) { form.query(q); } return form.submit(callback); } /** * Retrieve the document returned by the given query * @param {string|array|Predicate} the query * @param {object} additional parameters. In NodeJS, pass the request as 'req'. * @param {function} callback(err, doc) */ queryFirst(q: string | string[], optionsOrCallback: QueryOptions | RequestCallback<Document>, cb?: RequestCallback<Document>): Promise<Document> { const { options, callback } = typeof optionsOrCallback === 'function' ? { options: {} as QueryOptions, callback: optionsOrCallback } : { options: {...optionsOrCallback} || {}, callback: cb || (() => {}) }; options.page = 1; options.pageSize = 1; return this.query(q, options).then((response) => { const document = response && response.results && response.results[0]; callback(null, document); return document; }).catch((error) => { callback(error); throw error; }); } /** * Retrieve the document with the given id */ getByID(id: string, maybeOptions?: QueryOptions, cb?: RequestCallback<Document>): Promise<Document> { const options = maybeOptions ? {...maybeOptions} : {}; if (!options.lang) options.lang = '*'; return this.queryFirst(Predicates.at('document.id', id), options, cb); } /** * Retrieve multiple documents from an array of id */ getByIDs(ids: string[], maybeOptions?: QueryOptions, cb?: RequestCallback<ApiSearchResponse>): Promise<ApiSearchResponse> { const options = maybeOptions ? {...maybeOptions} : {}; if (!options.lang) options.lang = '*'; return this.query(Predicates.in('document.id', ids), options, cb); } /** * Retrieve the document with the given uid */ getByUID(type: string, uid: string, maybeOptions?: QueryOptions, cb?: RequestCallback<Document>): Promise<Document> { const options = maybeOptions ? {...maybeOptions} : {}; if(options.lang === "*") throw new Error("FORDIDDEN. You can't use getByUID with *, use the predicates instead.") if(!options.page) options.page = 1; return this.queryFirst(Predicates.at(`my.${type}.uid`, uid), options, cb); } /** * Retrieve the singleton document with the given type */ getSingle(type: string, maybeOptions?: QueryOptions, cb?: RequestCallback<Document>): Promise<Document> { const options = maybeOptions ? {...maybeOptions} : {}; return this.queryFirst(Predicates.at('document.type', type), options, cb); } /** * Retrieve the document with the given bookmark */ getBookmark(bookmark: string, maybeOptions?: QueryOptions, cb?: RequestCallback<Document>): Promise<Document> { const id = this.data.bookmarks[bookmark]; if (id) { return this.getByID(id, maybeOptions, cb); } else { return Promise.reject('Error retrieving bookmarked id'); } } getPreviewResolver(token: string, documentId?: string): PreviewResolver { return createPreviewResolver(token, documentId, this.getByID.bind(this)); } previewSession(token: string, linkResolver: LinkResolver, defaultUrl: string, cb?: RequestCallback<string>): Promise<string> { console.warn('previewSession function is deprecated in favor of getPreviewResolver function.') return new Promise((resolve, reject) => { this.httpClient.request<PreviewResponse>(token, (e, result) => { if (e) { cb && cb(e); reject(e); } else if (result) { if (!result.mainDocument) { cb && cb(null, defaultUrl); resolve(defaultUrl); } else { return this.getByID(result.mainDocument, { ref: token }).then((document) => { if (!document) { cb && cb(null, defaultUrl); resolve(defaultUrl); } else { const url = linkResolver(document); cb && cb(null, url); resolve(url); } }).catch(reject); } } }); }); } }