import { AttributeTypes, CollectibleBindingTypes, CollectibleNature, CollectiblePageOrders, Collections, RichTextContent, } from "./constants"; import { Currency, Language } from "./types/collections"; // END MOCKING SECTION export type EndpointFolderPreview = { id: string; slug: string; icon?: string; translations: { language: string; title: string; }[]; }; export type EndpointFolder = Omit & { translations: (EndpointFolderPreview["translations"][number] & { description?: RichTextContent; })[]; sections: | { type: "single"; subfolders: EndpointFolderPreview[] } | { type: "multiple"; sections: { translations: { language: string; name: string }[]; subfolders: EndpointFolderPreview[]; }[]; }; files: ( | { relationTo: Collections.Collectibles; value: EndpointCollectiblePreview; } | { relationTo: Collections.Pages; value: EndpointPagePreview; } | { relationTo: Collections.Images; value: EndpointImagePreview; } | { relationTo: Collections.Audios; value: EndpointAudioPreview; } | { relationTo: Collections.Videos; value: EndpointVideoPreview; } | { relationTo: Collections.Files; value: EndpointFilePreview; } )[]; parentPages: EndpointSource[]; }; export type EndpointWebsiteConfig = { home: { backgroundImage?: EndpointPayloadImage; folders: (EndpointFolderPreview & { lightThumbnail?: EndpointPayloadImage; darkThumbnail?: EndpointPayloadImage; })[]; }; timeline: { backgroundImage?: EndpointPayloadImage; breaks: number[]; eventCount: number; eras: { startingYear: number; endingYear: number; name: string; }[]; }; defaultOpenGraphImage?: EndpointPayloadImage; }; export type EndpointRecorderPreview = { id: string; username: string; }; export type EndpointRecorder = EndpointRecorderPreview & { avatar?: EndpointPayloadImage; translations: { language: string; biography: RichTextContent; }[]; languages: string[]; }; export type EndpointWording = { name: string; translations: { language: string; name: string; }[]; }; export type EndpointTag = { id: string; slug: string; page?: { slug: string }; translations: { language: string; name: string; }[]; }; export type EndpointGenericAttribute = { id: string; slug: string; icon: string; translations: { language: string; name: string; }[]; }; export type EndpointNumberAttribute = EndpointGenericAttribute & { type: AttributeTypes.Number; value: number; }; export type EndpointTextAttribute = EndpointGenericAttribute & { type: AttributeTypes.Text; value: string; }; export type EndpointTagsAttribute = EndpointGenericAttribute & { type: AttributeTypes.Tags; value: EndpointTag[]; }; export type EndpointAttribute = | EndpointNumberAttribute | EndpointTextAttribute | EndpointTagsAttribute; export type EndpointRole = { id: string; icon: string; translations: { language: string; name: string; }[]; }; export type EndpointCredit = { role: EndpointRole; recorders: EndpointRecorderPreview[]; }; export type EndpointPagePreview = { id: string; slug: string; thumbnail?: EndpointPayloadImage; attributes: EndpointAttribute[]; translations: { language: string; pretitle?: string; title: string; subtitle?: string; }[]; updatedAt: string; }; export type EndpointPage = Omit & { backgroundImage?: EndpointPayloadImage; translations: (EndpointPagePreview["translations"][number] & { sourceLanguage: string; summary?: RichTextContent; content: RichTextContent; credits: EndpointCredit[]; toc: TableOfContentEntry[]; })[]; createdAt: string; updatedBy?: EndpointRecorderPreview; parentPages: EndpointSource[]; }; export type EndpointCollectiblePreview = { id: string; slug: string; thumbnail?: EndpointPayloadImage; translations: { language: string; pretitle?: string; title: string; subtitle?: string; }[]; attributes: EndpointAttribute[]; releaseDate?: string; languages: string[]; price?: { amount: number; currency: string; }; }; export type EndpointCollectible = Omit & { translations: (EndpointCollectiblePreview["translations"][number] & { description?: RichTextContent; })[]; backgroundImage?: EndpointPayloadImage; nature: CollectibleNature; gallery?: { count: number; thumbnail: EndpointPayloadImage }; scans?: { count: number; thumbnail: EndpointPayloadImage }; urls: { url: string; label: string }[]; size?: { width: number; height: number; thickness?: number; }; weight?: number; pageInfo?: { pageCount: number; bindingType?: CollectibleBindingTypes; pageOrder?: CollectiblePageOrders; }; subitems: EndpointCollectiblePreview[]; files: EndpointFilePreview[]; contents: { content: | { relationTo: Collections.Pages; value: EndpointPagePreview; } | { relationTo: Collections.Audios; value: EndpointAudioPreview; } | { relationTo: Collections.Videos; value: EndpointVideoPreview; } | { relationTo: Collections.GenericContents; value: { translations: { language: string; name: string; }[]; }; }; range?: | { type: "pageRange"; start: number; end: number; } | { type: "timeRange"; start: string; end: string; } | { type: "other"; translations: { language: string; note: RichTextContent; }[]; }; }[]; createdAt: string; updatedAt: string; updatedBy?: EndpointRecorderPreview; parentPages: EndpointSource[]; }; export type EndpointCollectibleScans = { slug: string; thumbnail?: EndpointPayloadImage; translations: { language: string; pretitle?: string; title: string; subtitle?: string; description?: RichTextContent; }[]; credits: EndpointCredit[]; cover?: { front?: EndpointScanImage; spine?: EndpointScanImage; back?: EndpointScanImage; insideFront?: EndpointScanImage; insideBack?: EndpointScanImage; flapFront?: EndpointScanImage; flapBack?: EndpointScanImage; insideFlapFront?: EndpointScanImage; insideFlapBack?: EndpointScanImage; }; dustjacket?: { front?: EndpointScanImage; spine?: EndpointScanImage; back?: EndpointScanImage; insideFront?: EndpointScanImage; insideSpine?: EndpointScanImage; insideBack?: EndpointScanImage; flapFront?: EndpointScanImage; flapBack?: EndpointScanImage; insideFlapFront?: EndpointScanImage; insideFlapBack?: EndpointScanImage; }; obi?: { front?: EndpointScanImage; spine?: EndpointScanImage; back?: EndpointScanImage; insideFront?: EndpointScanImage; insideSpine?: EndpointScanImage; insideBack?: EndpointScanImage; flapFront?: EndpointScanImage; flapBack?: EndpointScanImage; insideFlapFront?: EndpointScanImage; insideFlapBack?: EndpointScanImage; }; pages: EndpointScanImage[]; parentPages: EndpointSource[]; }; export type EndpointCollectibleGallery = { slug: string; thumbnail?: EndpointPayloadImage; translations: { language: string; pretitle?: string; title: string; subtitle?: string; description?: RichTextContent; }[]; images: EndpointPayloadImage[]; parentPages: EndpointSource[]; }; export type EndpointCollectibleGalleryImage = { slug: string; translations: { language: string; pretitle?: string; title: string; subtitle?: string; description?: RichTextContent; }[]; image: EndpointImage; previousIndex?: string; nextIndex?: string; parentPages: EndpointSource[]; }; export type EndpointCollectibleScanPage = { slug: string; translations: { language: string; pretitle?: string; title: string; subtitle?: string; description?: RichTextContent; }[]; image: EndpointScanImage; previousIndex?: string; nextIndex?: string; parentPages: EndpointSource[]; }; export type EndpointScanImage = PayloadImage & { index: string; sizes: PayloadImage[]; }; export type TableOfContentEntry = { prefix: string; title: string; type: "sceneBreak" | "break" | "section"; index: number; children: TableOfContentEntry[]; }; export type EndpointChronologyEvent = { id: string; date: { year: number; month?: number; day?: number; }; events: { sources: EndpointSource[]; translations: { language: string; sourceLanguage: string; title?: string; description?: RichTextContent; notes?: RichTextContent; credits: EndpointCredit[]; }[]; }[]; }; export type EndpointSourcePreview = { id: string; slug: string; translations: { language: string; pretitle?: string; title: string; subtitle?: string }[]; }; export type EndpointSource = | { type: "url"; url: string; label: string } | { type: "collectible"; collectible: EndpointSourcePreview; range?: | { type: "page"; page: number } | { type: "timestamp"; timestamp: string } | { type: "custom"; translations: { language: string; note: string }[] }; } | { type: "page"; page: EndpointSourcePreview } | { type: "folder"; folder: EndpointSourcePreview } | { type: "scans"; collectible: EndpointSourcePreview } | { type: "gallery"; collectible: EndpointSourcePreview }; export type EndpointMediaPreview = { id: string; url: string; filename: string; mimeType: string; attributes: EndpointAttribute[]; translations: { language: string; pretitle?: string; title: string; subtitle?: string; }[]; }; export type EndpointMedia = Omit & { filesize: number; updatedAt: string; createdAt: string; translations: (EndpointMediaPreview["translations"][number] & { description?: RichTextContent; })[]; credits: EndpointCredit[]; }; export type EndpointImagePreview = EndpointMediaPreview & { width: number; height: number; sizes: PayloadImage[]; openGraph?: PayloadImage; }; export type EndpointImage = EndpointMedia & { width: number; height: number; sizes: PayloadImage[]; openGraph?: PayloadImage; }; export type EndpointAudioPreview = EndpointMediaPreview & { thumbnail?: EndpointPayloadImage; duration: number; }; export type EndpointAudio = EndpointMedia & { thumbnail?: EndpointPayloadImage; duration: number; }; export type EndpointVideoPreview = EndpointMediaPreview & { thumbnail?: EndpointPayloadImage; subtitles: { language: string; url: string; }[]; duration: number; }; export type EndpointVideo = EndpointMedia & { thumbnail?: EndpointPayloadImage; subtitles: { language: string; url: string; }[]; platform?: { channel: { url: string; title: string; subscribers: number; }; views?: number; likes?: number; dislikes?: number; url: string; publishedDate: string; }; duration: number; }; export type EndpointFilePreview = EndpointMediaPreview & { filesize: number; thumbnail?: EndpointPayloadImage; }; export type EndpointFile = EndpointMedia & { filesize: number; thumbnail?: EndpointPayloadImage; }; export type EndpointPayloadImage = PayloadImage & { sizes: PayloadImage[]; openGraph?: PayloadImage; }; export type PayloadMedia = { id: string; url: string; mimeType: string; filename: string; filesize: number; }; export type PayloadImage = PayloadMedia & { width: number; height: number; }; export type EndpointAllSDKUrls = { urls: string[]; }; export type EndpointAllIds = { collectibles: { slugs: string[] }; pages: { slugs: string[] }; folders: { slugs: string[] }; videos: { ids: string[] }; audios: { ids: string[] }; images: { ids: string[] }; files: { ids: string[] }; recorders: { ids: string[] }; chronologyEvents: { ids: string[] }; }; // SDK export const getSDKEndpoint = { getConfigEndpoint: () => `/globals/${Collections.WebsiteConfig}/config`, getFolderEndpoint: (slug: string) => `/${Collections.Folders}/slug/${slug}`, getLanguagesEndpoint: () => `/${Collections.Languages}/all`, getCurrenciesEndpoint: () => `/${Collections.Currencies}/all`, getWordingsEndpoint: () => `/${Collections.Wordings}/all`, getPageEndpoint: (slug: string) => `/${Collections.Pages}/slug/${slug}`, getCollectibleEndpoint: (slug: string) => `/${Collections.Collectibles}/slug/${slug}`, getCollectibleScansEndpoint: (slug: string) => `/${Collections.Collectibles}/slug/${slug}/scans`, getCollectibleScanPageEndpoint: (slug: string, index: string) => `/${Collections.Collectibles}/slug/${slug}/scans/${index}`, getCollectibleGalleryEndpoint: (slug: string) => `/${Collections.Collectibles}/slug/${slug}/gallery`, getCollectibleGalleryImageEndpoint: (slug: string, index: string) => `/${Collections.Collectibles}/slug/${slug}/gallery/${index}`, getChronologyEventsEndpoint: () => `/${Collections.ChronologyEvents}/all`, getChronologyEventByIDEndpoint: (id: string) => `/${Collections.ChronologyEvents}/id/${id}`, getImageByIDEndpoint: (id: string) => `/${Collections.Images}/id/${id}`, getAudioByIDEndpoint: (id: string) => `/${Collections.Audios}/id/${id}`, getVideoByIDEndpoint: (id: string) => `/${Collections.Videos}/id/${id}`, getFileByIDEndpoint: (id: string) => `/${Collections.Files}/id/${id}`, getRecorderByIDEndpoint: (id: string) => `/${Collections.Recorders}/id/${id}`, getAllSDKUrlsEndpoint: () => `/all-sdk-urls`, getAllIds: () => `/all-ids`, getLoginEndpoint: () => `/${Collections.Recorders}/login`, }; type PayloadSDKResponse = { data: T; endpointCalled: string; }; type PayloadTokenCache = { set: (token: string, expirationTimestamp: number) => void; get: () => string | undefined; }; type PayloadDataCache = { set: (url: string, response: any) => void; get: (url: string) => any | undefined; }; export class PayloadSDK { private tokenCache: PayloadTokenCache | undefined; private dataCache: PayloadDataCache | undefined; constructor( private readonly apiURL: string, private readonly email: string, private readonly password: string ) {} addTokenCache(tokenCache: PayloadTokenCache) { this.tokenCache = tokenCache; } addDataCache(dataCache: PayloadDataCache) { this.dataCache = dataCache; } private logResponse(res: Response) { console.log(res.status, res.statusText, res.url); } private async refreshToken() { const loginUrl = `${this.apiURL}${getSDKEndpoint.getLoginEndpoint()}`; const loginResult = await fetch(loginUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: this.email, password: this.password }), }); this.logResponse(loginResult); if (loginResult.status !== 200) { throw new Error("Unable to login"); } const { token, exp } = (await loginResult.json()) as { token: string; exp: number; }; this.tokenCache?.set(token, exp); return token; } async request(endpoint: string): Promise> { const cachedResponse = this.dataCache?.get(endpoint); if (cachedResponse) { return cachedResponse; } const result = await fetch(`${this.apiURL}${endpoint}`, { headers: { Authorization: `JWT ${this.tokenCache?.get() ?? (await this.refreshToken())}`, }, }); this.logResponse(result); if (!result.ok) { throw new Error("Unhandled fetch error"); } const response = { data: await result.json(), endpointCalled: endpoint }; this.dataCache?.set(endpoint, response); return response; } async getConfig(): Promise> { return await this.request(getSDKEndpoint.getConfigEndpoint()); } async getFolder(slug: string): Promise> { return await this.request(getSDKEndpoint.getFolderEndpoint(slug)); } async getLanguages(): Promise> { return await this.request(getSDKEndpoint.getLanguagesEndpoint()); } async getCurrencies(): Promise> { return await this.request(getSDKEndpoint.getCurrenciesEndpoint()); } async getWordings(): Promise> { return await this.request(getSDKEndpoint.getWordingsEndpoint()); } async getPage(slug: string): Promise> { return await this.request(getSDKEndpoint.getPageEndpoint(slug)); } async getCollectible(slug: string): Promise> { return await this.request(getSDKEndpoint.getCollectibleEndpoint(slug)); } async getCollectibleScans(slug: string): Promise> { return await this.request(getSDKEndpoint.getCollectibleScansEndpoint(slug)); } async getCollectibleScanPage( slug: string, index: string ): Promise> { return await this.request(getSDKEndpoint.getCollectibleScanPageEndpoint(slug, index)); } async getCollectibleGallery( slug: string ): Promise> { return await this.request(getSDKEndpoint.getCollectibleGalleryEndpoint(slug)); } async getCollectibleGalleryImage( slug: string, index: string ): Promise> { return await this.request(getSDKEndpoint.getCollectibleGalleryImageEndpoint(slug, index)); } async getChronologyEvents(): Promise> { return await this.request(getSDKEndpoint.getChronologyEventsEndpoint()); } async getChronologyEventByID(id: string): Promise> { return await this.request(getSDKEndpoint.getChronologyEventByIDEndpoint(id)); } async getImageByID(id: string): Promise> { return await this.request(getSDKEndpoint.getImageByIDEndpoint(id)); } async getAudioByID(id: string): Promise> { return await this.request(getSDKEndpoint.getAudioByIDEndpoint(id)); } async getVideoByID(id: string): Promise> { return await this.request(getSDKEndpoint.getVideoByIDEndpoint(id)); } async getFileByID(id: string): Promise> { return await this.request(getSDKEndpoint.getFileByIDEndpoint(id)); } async getRecorderByID(id: string): Promise> { return await this.request(getSDKEndpoint.getRecorderByIDEndpoint(id)); } async getAllSdkUrls(): Promise> { return await this.request(getSDKEndpoint.getAllSDKUrlsEndpoint()); } async getAllIds(): Promise> { return await this.request(getSDKEndpoint.getAllIds()); } }