Relegate caching and env variables to the frontend
This commit is contained in:
parent
18781e701c
commit
dcba1b889d
148
src/sdk.ts
148
src/sdk.ts
|
@ -8,97 +8,8 @@ import {
|
||||||
} from "./constants";
|
} from "./constants";
|
||||||
import { Currency, Language } from "./types/collections";
|
import { Currency, Language } from "./types/collections";
|
||||||
|
|
||||||
class NodeCache {
|
|
||||||
constructor(_params: any) {}
|
|
||||||
getTtl(_key: string): number | undefined {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
get<T>(_key: string): T | undefined {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
set<T>(_key: string, _value: T, _ttl: number | string) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// END MOCKING SECTION
|
// END MOCKING SECTION
|
||||||
|
|
||||||
const REFRESH_FREQUENCY_IN_SEC = 60;
|
|
||||||
const CACHE = new NodeCache({
|
|
||||||
checkperiod: REFRESH_FREQUENCY_IN_SEC,
|
|
||||||
deleteOnExpire: true,
|
|
||||||
forceString: true,
|
|
||||||
maxKeys: 1,
|
|
||||||
});
|
|
||||||
const TOKEN_KEY = "token";
|
|
||||||
|
|
||||||
type PayloadLoginResponse = {
|
|
||||||
token: string;
|
|
||||||
exp: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
const refreshToken = async () => {
|
|
||||||
const loginUrl = payloadApiUrl(Collections.Recorders, "login");
|
|
||||||
const loginResult = await fetch(loginUrl, {
|
|
||||||
method: "POST",
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify({
|
|
||||||
email: process.env.PAYLOAD_USER,
|
|
||||||
password: process.env.PAYLOAD_PASSWORD,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
logResponse(loginResult);
|
|
||||||
|
|
||||||
if (loginResult.status !== 200) {
|
|
||||||
throw new Error("Unable to login");
|
|
||||||
}
|
|
||||||
|
|
||||||
const loginJson = (await loginResult.json()) as PayloadLoginResponse;
|
|
||||||
const { token, exp } = loginJson;
|
|
||||||
const now = Math.floor(Date.now() / 1000);
|
|
||||||
const ttl = Math.floor(exp - now - REFRESH_FREQUENCY_IN_SEC * 2);
|
|
||||||
const ttlInMinutes = Math.floor(ttl / 60);
|
|
||||||
console.log("Token was refreshed. TTL is", ttlInMinutes, "minutes.");
|
|
||||||
CACHE.set(TOKEN_KEY, token, ttl);
|
|
||||||
return token;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getToken = async (): Promise<string> => {
|
|
||||||
const cachedToken = CACHE.get<string>(TOKEN_KEY);
|
|
||||||
if (cachedToken !== undefined) {
|
|
||||||
const cachedTokenTtl = CACHE.getTtl(TOKEN_KEY) as number;
|
|
||||||
const diffInMinutes = Math.floor((cachedTokenTtl - Date.now()) / 1000 / 60);
|
|
||||||
console.log("Retrieved token from cache. TTL is", diffInMinutes, "minutes.");
|
|
||||||
return cachedToken;
|
|
||||||
}
|
|
||||||
console.log("Refreshing token");
|
|
||||||
return await refreshToken();
|
|
||||||
};
|
|
||||||
|
|
||||||
const injectAuth = async (init?: RequestInit): Promise<RequestInit> => ({
|
|
||||||
...init,
|
|
||||||
headers: {
|
|
||||||
...init?.headers,
|
|
||||||
Authorization: `JWT ${await getToken()}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const logResponse = (res: Response) => console.log(res.status, res.statusText, res.url);
|
|
||||||
|
|
||||||
const payloadApiUrl = (collection: Collections, endpoint?: string, isGlobal?: boolean): string =>
|
|
||||||
`${process.env.PAYLOAD_API_URL}/${isGlobal === undefined ? "" : "globals/"}${collection}${endpoint === undefined ? "" : `/${endpoint}`}`;
|
|
||||||
|
|
||||||
const request = async (url: string, init?: RequestInit): Promise<Response> => {
|
|
||||||
const result = await fetch(url, await injectAuth(init));
|
|
||||||
logResponse(result);
|
|
||||||
|
|
||||||
if (result.status !== 200) {
|
|
||||||
throw new Error("Unhandled fetch error");
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
// SDK and Types
|
|
||||||
|
|
||||||
export type EndpointFolder = {
|
export type EndpointFolder = {
|
||||||
slug: string;
|
slug: string;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
|
@ -537,7 +448,63 @@ export type PayloadImage = PayloadMedia & {
|
||||||
height: number;
|
height: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const payload = {
|
// SDK
|
||||||
|
|
||||||
|
type GetPayloadSDKParams = {
|
||||||
|
apiURL: string;
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
cache: Cache;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Cache = {
|
||||||
|
set: (token: string, expirationTimestamp: number) => void;
|
||||||
|
get: () => string | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const logResponse = (res: Response) => console.log(res.status, res.statusText, res.url);
|
||||||
|
|
||||||
|
export const getPayloadSDK = ({ apiURL, email, password, cache }: GetPayloadSDKParams) => {
|
||||||
|
const refreshToken = async () => {
|
||||||
|
const loginUrl = payloadApiUrl(Collections.Recorders, "login");
|
||||||
|
const loginResult = await fetch(loginUrl, {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({ email, password }),
|
||||||
|
});
|
||||||
|
logResponse(loginResult);
|
||||||
|
|
||||||
|
if (loginResult.status !== 200) {
|
||||||
|
throw new Error("Unable to login");
|
||||||
|
}
|
||||||
|
|
||||||
|
const { token, exp } = (await loginResult.json()) as {
|
||||||
|
token: string;
|
||||||
|
exp: number;
|
||||||
|
};
|
||||||
|
cache.set(token, exp);
|
||||||
|
return token;
|
||||||
|
};
|
||||||
|
|
||||||
|
const payloadApiUrl = (collection: Collections, endpoint?: string, isGlobal?: boolean): string =>
|
||||||
|
`${apiURL}/${isGlobal === undefined ? "" : "globals/"}${collection}${endpoint === undefined ? "" : `/${endpoint}`}`;
|
||||||
|
|
||||||
|
const request = async (url: string): Promise<Response> => {
|
||||||
|
const result = await fetch(url, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `JWT ${cache.get() ?? (await refreshToken())}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
logResponse(result);
|
||||||
|
|
||||||
|
if (result.status !== 200) {
|
||||||
|
throw new Error("Unhandled fetch error");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
getConfig: async (): Promise<EndpointWebsiteConfig> =>
|
getConfig: async (): Promise<EndpointWebsiteConfig> =>
|
||||||
await (await request(payloadApiUrl(Collections.WebsiteConfig, `config`, true))).json(),
|
await (await request(payloadApiUrl(Collections.WebsiteConfig, `config`, true))).json(),
|
||||||
getFolder: async (slug: string): Promise<EndpointFolder> =>
|
getFolder: async (slug: string): Promise<EndpointFolder> =>
|
||||||
|
@ -582,4 +549,5 @@ export const payload = {
|
||||||
await (await request(payloadApiUrl(Collections.Videos, `id/${id}`))).json(),
|
await (await request(payloadApiUrl(Collections.Videos, `id/${id}`))).json(),
|
||||||
getRecorderByID: async (id: string): Promise<EndpointRecorder> =>
|
getRecorderByID: async (id: string): Promise<EndpointRecorder> =>
|
||||||
await (await request(payloadApiUrl(Collections.Recorders, `id/${id}`))).json(),
|
await (await request(payloadApiUrl(Collections.Recorders, `id/${id}`))).json(),
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -79,7 +79,6 @@ const start = async () => {
|
||||||
result.push(removeMockingSection(readFileSync(path.join(__dirname, "constants.ts"), "utf-8")));
|
result.push(removeMockingSection(readFileSync(path.join(__dirname, "constants.ts"), "utf-8")));
|
||||||
|
|
||||||
result.push("////////////////// SDK //////////////////");
|
result.push("////////////////// SDK //////////////////");
|
||||||
result.push(`import NodeCache from "node-cache";`);
|
|
||||||
result.push(removeMockingSection(readFileSync(path.join(__dirname, "sdk.ts"), "utf-8")));
|
result.push(removeMockingSection(readFileSync(path.join(__dirname, "sdk.ts"), "utf-8")));
|
||||||
|
|
||||||
res.type("text/plain");
|
res.type("text/plain");
|
||||||
|
|
Loading…
Reference in New Issue