celestya 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -107,6 +107,11 @@ interface IAuthContext<U> {
107
107
  }) => Promise<Result<T, BaseError>>;
108
108
  setHeader: (key: string, value: string) => void;
109
109
  removeHeader: (key: string) => void;
110
+ augmentToken: (opts: {
111
+ url: string;
112
+ method?: "GET" | "POST" | "DELETE";
113
+ body?: object;
114
+ }) => Promise<Result<any, BaseError>>;
110
115
  }
111
116
  interface IAuthContextOptions {
112
117
  children: React.ReactNode;
@@ -107,6 +107,11 @@ interface IAuthContext<U> {
107
107
  }) => Promise<Result<T, BaseError>>;
108
108
  setHeader: (key: string, value: string) => void;
109
109
  removeHeader: (key: string) => void;
110
+ augmentToken: (opts: {
111
+ url: string;
112
+ method?: "GET" | "POST" | "DELETE";
113
+ body?: object;
114
+ }) => Promise<Result<any, BaseError>>;
110
115
  }
111
116
  interface IAuthContextOptions {
112
117
  children: React.ReactNode;
@@ -231,6 +231,19 @@ var AuthContextProvider = ({
231
231
  headers: { ...customHeaders.current, ...headers }
232
232
  });
233
233
  };
234
+ const augmentToken = async ({
235
+ url,
236
+ method = "POST",
237
+ body
238
+ }) => {
239
+ const res = await clientSideFetch({
240
+ method: "POST",
241
+ url: `${routePrefix}/augment`,
242
+ body: { url, method, body }
243
+ });
244
+ if (res.isOk()) await refreshUser(true);
245
+ return res;
246
+ };
234
247
  (0, import_react.useEffect)(() => {
235
248
  if (!ready) refreshUser();
236
249
  }, []);
@@ -247,7 +260,8 @@ var AuthContextProvider = ({
247
260
  post,
248
261
  del,
249
262
  setHeader,
250
- removeHeader
263
+ removeHeader,
264
+ augmentToken
251
265
  /* upload, */
252
266
  };
253
267
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AuthContext.Provider, { value: provider, children });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/client/index.ts","../../src/client/contextProvider.tsx","../../src/types/response.ts","../../src/client/request.ts","../../src/client/Logout.tsx","../../src/client/useAuth.ts","../../src/client/useAPIWrapper.tsx"],"sourcesContent":["import AuthContextProvider from \"./contextProvider\";\nimport LogoutComponent from \"./Logout\";\n\nexport const AuthProvider = AuthContextProvider;\nexport const Logout = LogoutComponent;\n\nexport { useAuth } from \"./useAuth\";\nexport { APIWrapper } from \"./useAPIWrapper\";\n","\"use client\";\n\nimport { createContext, useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n IAuthContext,\n IAuthContextOptions,\n ILoginData,\n IOAuthData,\n IRegisterData,\n} from \"../types/internal\";\n\nimport { type Result } from \"../types/response\";\n\nimport { clientSideFetch } from \"./request\";\n\nimport { useRouter } from \"next/navigation\";\nimport { BaseError } from \"../types/response\";\n/* +\n Frontend context for providing login, logout, register and refresh\n 'use client' needed for using -> client components only\n server components need to use useSession()\n*/\n\nexport const AuthContext = createContext<IAuthContext<any>>(null as any);\n\nconst AuthContextProvider = <IU,>({\n children,\n routePrefix = \"/api\",\n}: IAuthContextOptions) => {\n const [isLoggedIn, setIsLoggedIn] = useState(false);\n const [ready, setReady] = useState(false);\n const [user, setUser] = useState<IU | {}>({});\n\n const router = useRouter();\n const customHeaders = useRef<Record<string, string>>({});\n\n const setHeader = useCallback((key: string, value: string) => {\n customHeaders.current[key] = value;\n }, []);\n\n const removeHeader = useCallback((key: string) => {\n delete customHeaders.current[key];\n }, []);\n\n // POST /session/login\n const loginRoute = routePrefix + \"/login\";\n\n // POST /session/refresh\n const registerRoute = routePrefix + \"/register\";\n\n // GET /session/logout\n const logoutRoute = routePrefix + \"/logout\";\n\n // GET /session\n const userRoute = routePrefix + \"/user\";\n\n // GET /session/oauth/API_OAUTH_URL\n const oAuthRoute = routePrefix + \"/oauth\";\n\n // GET/POST/DELETE /proxy/URL\n const proxyRoute = routePrefix + \"/proxy\";\n\n const login = async (loginData: ILoginData): Promise<string> => {\n const res = await clientSideFetch({\n url: loginRoute,\n body: loginData.data,\n });\n if (res.isErr()) {\n return `${loginData.onErrorUrl || \"/\"}?error=${res.error.error}`;\n }\n\n setIsLoggedIn(true);\n\n return loginData.redirect || \"/\";\n };\n\n const register = async (registerData: IRegisterData): Promise<string> => {\n const res = await clientSideFetch<{ redirect: string }>({\n url: registerRoute,\n body: registerData.data,\n });\n\n if (res.isErr()) {\n return `${registerData.onErrorUrl || \"/\"}?error=${res.error.error}`;\n }\n return `${registerData.redirect || \"/\"}?success=true`;\n };\n\n const oAuth = async ({\n state,\n oAuthUrl,\n onErrorUrl,\n }: IOAuthData): Promise<string> => {\n const url = new URL(oAuthRoute, \"http://localhost/\");\n url.searchParams.set(\"authUrl\", oAuthUrl);\n\n if (state && state !== \"/\") url.searchParams.set(\"state\", state);\n\n const response = await clientSideFetch<string>({\n url: url.pathname + url.search,\n });\n if (response.isErr()) {\n return `${onErrorUrl || \"/\"}?error=${response.error.message}`;\n }\n\n return response.value.data;\n };\n\n const logout = async (): Promise<string> => {\n const data = await clientSideFetch<string>({\n url: logoutRoute,\n cache: \"no-store\",\n });\n\n if (data.isErr()) {\n return \"/\";\n }\n\n setIsLoggedIn(false);\n setUser({});\n\n return data.value.data;\n };\n\n const refreshUser = async (force?: boolean): Promise<void> => {\n const data = await clientSideFetch<IU>({\n url: `${userRoute}${force ? \"?force=true\" : \"\"}`,\n cache: \"no-store\",\n });\n\n if (data.isErr()) {\n setUser({});\n setIsLoggedIn(false);\n } else {\n setUser(data.value.data);\n }\n\n setReady(true);\n\n router.refresh();\n };\n\n const get = async <T,>({\n url,\n headers,\n }: {\n url: string;\n headers?: Record<string, string>;\n }): Promise<Result<T, BaseError>> => {\n return clientSideFetch({\n url: `${proxyRoute}${url}`,\n headers: { ...customHeaders.current, ...headers },\n });\n };\n\n const post = async <T,>({\n url,\n body,\n headers,\n }: {\n url: string;\n body: object;\n headers?: Record<string, string>;\n }): Promise<Result<T, BaseError>> => {\n return clientSideFetch({\n method: \"POST\",\n url: `${proxyRoute}${url}`,\n body,\n headers: { ...customHeaders.current, ...headers },\n });\n };\n\n const del = async <T,>({\n url,\n headers,\n }: {\n url: string;\n headers?: Record<string, string>;\n }): Promise<Result<T, BaseError>> => {\n return clientSideFetch({\n method: \"DELETE\",\n url: `${proxyRoute}${url}`,\n headers: { ...customHeaders.current, ...headers },\n });\n };\n\n /**\n * Can only be used if user is logged in! and already initialised\n * @param url url for upload\n * @param formData form data\n * @param setProgress progress dispatch\n * @returns object with data or error\n */\n /* const upload = async <T, U = any>(\n url: string,\n formName: string,\n files: File[],\n setProgress: (p: number) => void,\n ): Promise<TRequest<T, U>> => {\n try {\n if (!user.token) throw new Error('user not logged in')\n \n const res: Error | XMLHttpRequest = await new Promise(\n (resolve, reject) => {\n try {\n const xhr = new XMLHttpRequest()\n const formData = new FormData()\n \n for (let i = 0; i < files.length; i++)\n formData.append(formName, files[i])\n \n xhr.open('POST', `${API_URL}${url}`, true)\n xhr.setRequestHeader('Authorization', `Bearer ${user.token}`)\n xhr.upload.onprogress = (ev: ProgressEvent<EventTarget>) => {\n if (ev.lengthComputable) {\n const percentComplete = (ev.loaded / ev.total) * 100\n setProgress(percentComplete)\n }\n }\n \n xhr.onload = function () {\n console.log('break3?', this)\n return this.status === 200\n ? resolve(this)\n : reject(new Error('Error while uploading: ' + this.status))\n }\n \n xhr.onerror = (ev: ProgressEvent<EventTarget>) => {\n console.log('break2', ev.target)\n reject(ev)\n }\n \n xhr.send(formData)\n } catch (e) {\n console.log('break1', e)\n reject(e)\n }\n },\n )\n \n if (res instanceof Error) throw res\n \n const data: any = JSON.parse(res.responseText)\n \n if (data.error) throw new Error(data.data)\n \n return { data: data.data }\n } catch (e) {\n console.log('break4', e)\n return { error: e.message || 'upload error' }\n }\n }\n \n const getContext = () => {\n let context = user.id\n \n if (!user.id) {\n // if not logged in\n const cookie = document.cookie\n .split(';')\n .find((c) => c.includes('cycle_cid'))\n \n if (cookie) {\n // use cookie value\n context = cookie.split('=')[1]\n } else {\n // set new cookie\n context =\n Math.random().toString(36).substring(2, 15) +\n Math.random().toString(36).substring(2, 15)\n \n document.cookie = `cycle_cid=${context};path=/;max-age=31536000`\n }\n }\n \n return context\n }\n \n const event = async (name: string, value?: any): Promise<boolean> => {\n try {\n const contextId = getContext()\n \n const r = await fetch(NOFY_API_URL + '/event', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: 'Basic ' + ANALYTICS_KEY,\n },\n body: JSON.stringify({\n source: IS_PROD ? 'cycle-frontend' : 'cycle-frontend-dev',\n contextId,\n name,\n value,\n }),\n })\n \n const res = await r.json()\n if (res.error) throw new Error(res.error)\n \n return true\n } catch (e) {\n console.log('#> event error: ', e)\n return false\n }\n }\n \n const pageView = async (url: string, referer?: string): Promise<boolean> => {\n try {\n const contextId = getContext()\n \n const r = await fetch(NOFY_API_URL + '/log/count', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: 'Basic ' + ANALYTICS_KEY,\n },\n body: JSON.stringify({\n meta: {\n contextId,\n type: 'pageview',\n },\n referer,\n identifier: url,\n }),\n })\n \n const res = await r.json()\n if (res.error) throw new Error(res.error)\n \n return true\n } catch (e) {\n console.log('#> event error: ', e)\n return false\n }\n } */\n\n useEffect(() => {\n if (!ready) refreshUser();\n }, []);\n\n const provider = {\n ready,\n login,\n register,\n logout,\n isLoggedIn,\n refreshUser,\n user,\n oAuth,\n get,\n post,\n del,\n setHeader,\n removeHeader,\n /* upload, */\n };\n\n return (\n <AuthContext.Provider value={provider}>{children}</AuthContext.Provider>\n );\n};\n\nexport default AuthContextProvider;\n","export type BaseError = {\n error: string;\n message: string;\n};\n\nexport type Success<S> = {\n data: S;\n};\n\n/**\n * A Result type that represents either a successful value (Ok) or an error (Err).\n * This is a discriminated union type that helps handle errors in a type-safe way.\n *\n * @template T - The type of the successful value\n * @template E - The type of the error, must extend BaseError\n */\nexport type Result<T, E extends BaseError> = Ok<T, E> | Err<T, E>;\n\ntype IResult<T, E extends BaseError> = {\n /**\n * Checks if the `Result` is an `Ok` instance\n */\n isOk: () => this is Ok<T, E>;\n\n /**\n * Checks if the `Result` is an `Err` instance.\n */\n isErr: () => this is Err<T, E>;\n};\n\n/**\n * Represents a successful `Result` value.\n *\n * @template T - The type of the successful value.\n * @template E - The type of the error, must extend `BaseError`.\n */\nexport class Ok<T, E extends BaseError> implements IResult<T, E> {\n value: Success<T>;\n\n constructor(value: Success<T>) {\n this.value = value;\n }\n\n isOk(): this is Ok<T, E> {\n return true;\n }\n\n isErr(): this is Err<T, E> {\n return false;\n }\n}\n\n/**\n * Represents an error `Result` value.\n *\n * @template T - The type of the successful value.\n * @template E - The type of the error, must extend `BaseError`.\n */\nexport class Err<T, E extends BaseError> implements IResult<T, E> {\n error: E;\n\n constructor(error: E) {\n this.error = error;\n }\n\n isOk(): this is Ok<T, E> {\n return false;\n }\n\n isErr(): this is Err<T, E> {\n return true;\n }\n}\n\n/**\n * Creates a new successful `Result` (i.e., an instance of `Ok`).\n *\n * @template T - The type of the successful value\n * @param value - The successful value\n * @returns A new `Ok` instance.\n */\nexport function ok<const T>(value: Success<T>): Result<T, never> {\n return new Ok(value);\n}\n\n/**\n * Creates a new error `Result` (i.e., an instance of `Err`).\n *\n * @template E - The type of the error, must extend `BaseError`.\n * @param error - The error value.\n * @returns A new `Err` instance.\n */\nexport function err<const E extends BaseError>(error: E): Result<never, E> {\n return new Err(error);\n}\n","import { BaseError, err, ok, Result, Success } from \"../types/response\";\n\nexport const clientSideFetch = async <T>({\n url,\n method = \"GET\",\n body,\n ...options\n}: {\n url: string;\n method?: \"GET\" | \"POST\" | \"DELETE\";\n body?: object;\n} & Omit<RequestInit, \"body\" | \"method\">): Promise<Result<T, BaseError>> => {\n const opts: RequestInit = {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n ...options.headers,\n },\n ...options,\n };\n\n try {\n if (body) opts.body = JSON.stringify(body);\n } catch (e) {\n return err({\n error: \"PARSE_ERROR\",\n message: \"Failed to parse request body as JSON\",\n });\n }\n\n try {\n const response: Response = await fetch(url, opts);\n if (!response.ok) {\n return err({\n error: \"RESPONSE_ERROR\",\n message: `HTTP error! status: ${response.status}`,\n });\n }\n\n try {\n const res = await response.json();\n if (res.error !== undefined) {\n return err(res);\n }\n\n return ok(res as Success<T>);\n } catch (e) {\n return err({\n error: \"PARSE_ERROR\",\n message: \"Failed to parse response as JSON\",\n });\n }\n } catch (e) {\n return err({\n error: \"FETCH_ERROR\",\n message: \"Failed to fetch the resource: \" + String(e),\n });\n }\n};\n","\"use client\";\n\nimport { useAuth } from \".\";\nimport { IChildProps } from \"../types/internal\";\n\nexport type LogoutProps = React.FC<React.ComponentProps<\"div\"> & IChildProps>;\n\nconst LogoutComponent: LogoutProps = ({ children, ...props }) => {\n const { logout } = useAuth();\n\n const handleLogout = async (e: any) => {\n e.preventDefault();\n await logout();\n };\n\n return (\n <div onClick={handleLogout} {...props}>\n {children}\n </div>\n );\n};\n\nexport default LogoutComponent;\n","import { useContext } from \"react\";\nimport { AuthContext } from \"./contextProvider\";\n\nexport const useAuth = () => {\n return useContext(AuthContext);\n};\n","import { useContext } from \"react\";\nimport { AuthContext } from \"./contextProvider\";\nimport { CallbackOptions, WrapperFunction } from \"../types\";\n\nexport const APIWrapper = <T,>(wrapperFunction: (cb: WrapperFunction) => T) => {\n return () => {\n const { get, post, del } = useContext(AuthContext);\n return wrapperFunction(async (data: CallbackOptions) => {\n const { method, url, body } = data;\n\n switch (method) {\n case \"GET\":\n return get({ url });\n case \"POST\":\n return post({ url, body: body ?? {} });\n case \"DELETE\":\n return del({ url });\n default:\n throw new Error(\"Unsupported method type\");\n }\n });\n };\n};\n"],"mappings":"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","names":["import_jsx_runtime","import_react","import_react"]}
1
+ {"version":3,"sources":["../../src/client/index.ts","../../src/client/contextProvider.tsx","../../src/types/response.ts","../../src/client/request.ts","../../src/client/Logout.tsx","../../src/client/useAuth.ts","../../src/client/useAPIWrapper.tsx"],"sourcesContent":["import AuthContextProvider from \"./contextProvider\";\nimport LogoutComponent from \"./Logout\";\n\nexport const AuthProvider = AuthContextProvider;\nexport const Logout = LogoutComponent;\n\nexport { useAuth } from \"./useAuth\";\nexport { APIWrapper } from \"./useAPIWrapper\";\n","\"use client\";\n\nimport { createContext, useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n IAuthContext,\n IAuthContextOptions,\n ILoginData,\n IOAuthData,\n IRegisterData,\n} from \"../types/internal\";\n\nimport { type Result } from \"../types/response\";\n\nimport { clientSideFetch } from \"./request\";\n\nimport { useRouter } from \"next/navigation\";\nimport { BaseError } from \"../types/response\";\n/* +\n Frontend context for providing login, logout, register and refresh\n 'use client' needed for using -> client components only\n server components need to use useSession()\n*/\n\nexport const AuthContext = createContext<IAuthContext<any>>(null as any);\n\nconst AuthContextProvider = <IU,>({\n children,\n routePrefix = \"/api\",\n}: IAuthContextOptions) => {\n const [isLoggedIn, setIsLoggedIn] = useState(false);\n const [ready, setReady] = useState(false);\n const [user, setUser] = useState<IU | {}>({});\n\n const router = useRouter();\n const customHeaders = useRef<Record<string, string>>({});\n\n const setHeader = useCallback((key: string, value: string) => {\n customHeaders.current[key] = value;\n }, []);\n\n const removeHeader = useCallback((key: string) => {\n delete customHeaders.current[key];\n }, []);\n\n // POST /session/login\n const loginRoute = routePrefix + \"/login\";\n\n // POST /session/refresh\n const registerRoute = routePrefix + \"/register\";\n\n // GET /session/logout\n const logoutRoute = routePrefix + \"/logout\";\n\n // GET /session\n const userRoute = routePrefix + \"/user\";\n\n // GET /session/oauth/API_OAUTH_URL\n const oAuthRoute = routePrefix + \"/oauth\";\n\n // GET/POST/DELETE /proxy/URL\n const proxyRoute = routePrefix + \"/proxy\";\n\n const login = async (loginData: ILoginData): Promise<string> => {\n const res = await clientSideFetch({\n url: loginRoute,\n body: loginData.data,\n });\n if (res.isErr()) {\n return `${loginData.onErrorUrl || \"/\"}?error=${res.error.error}`;\n }\n\n setIsLoggedIn(true);\n\n return loginData.redirect || \"/\";\n };\n\n const register = async (registerData: IRegisterData): Promise<string> => {\n const res = await clientSideFetch<{ redirect: string }>({\n url: registerRoute,\n body: registerData.data,\n });\n\n if (res.isErr()) {\n return `${registerData.onErrorUrl || \"/\"}?error=${res.error.error}`;\n }\n return `${registerData.redirect || \"/\"}?success=true`;\n };\n\n const oAuth = async ({\n state,\n oAuthUrl,\n onErrorUrl,\n }: IOAuthData): Promise<string> => {\n const url = new URL(oAuthRoute, \"http://localhost/\");\n url.searchParams.set(\"authUrl\", oAuthUrl);\n\n if (state && state !== \"/\") url.searchParams.set(\"state\", state);\n\n const response = await clientSideFetch<string>({\n url: url.pathname + url.search,\n });\n if (response.isErr()) {\n return `${onErrorUrl || \"/\"}?error=${response.error.message}`;\n }\n\n return response.value.data;\n };\n\n const logout = async (): Promise<string> => {\n const data = await clientSideFetch<string>({\n url: logoutRoute,\n cache: \"no-store\",\n });\n\n if (data.isErr()) {\n return \"/\";\n }\n\n setIsLoggedIn(false);\n setUser({});\n\n return data.value.data;\n };\n\n const refreshUser = async (force?: boolean): Promise<void> => {\n const data = await clientSideFetch<IU>({\n url: `${userRoute}${force ? \"?force=true\" : \"\"}`,\n cache: \"no-store\",\n });\n\n if (data.isErr()) {\n setUser({});\n setIsLoggedIn(false);\n } else {\n setUser(data.value.data);\n }\n\n setReady(true);\n\n router.refresh();\n };\n\n const get = async <T,>({\n url,\n headers,\n }: {\n url: string;\n headers?: Record<string, string>;\n }): Promise<Result<T, BaseError>> => {\n return clientSideFetch({\n url: `${proxyRoute}${url}`,\n headers: { ...customHeaders.current, ...headers },\n });\n };\n\n const post = async <T,>({\n url,\n body,\n headers,\n }: {\n url: string;\n body: object;\n headers?: Record<string, string>;\n }): Promise<Result<T, BaseError>> => {\n return clientSideFetch({\n method: \"POST\",\n url: `${proxyRoute}${url}`,\n body,\n headers: { ...customHeaders.current, ...headers },\n });\n };\n\n const del = async <T,>({\n url,\n headers,\n }: {\n url: string;\n headers?: Record<string, string>;\n }): Promise<Result<T, BaseError>> => {\n return clientSideFetch({\n method: \"DELETE\",\n url: `${proxyRoute}${url}`,\n headers: { ...customHeaders.current, ...headers },\n });\n };\n\n /**\n * Can only be used if user is logged in! and already initialised\n * @param url url for upload\n * @param formData form data\n * @param setProgress progress dispatch\n * @returns object with data or error\n */\n /* const upload = async <T, U = any>(\n url: string,\n formName: string,\n files: File[],\n setProgress: (p: number) => void,\n ): Promise<TRequest<T, U>> => {\n try {\n if (!user.token) throw new Error('user not logged in')\n \n const res: Error | XMLHttpRequest = await new Promise(\n (resolve, reject) => {\n try {\n const xhr = new XMLHttpRequest()\n const formData = new FormData()\n \n for (let i = 0; i < files.length; i++)\n formData.append(formName, files[i])\n \n xhr.open('POST', `${API_URL}${url}`, true)\n xhr.setRequestHeader('Authorization', `Bearer ${user.token}`)\n xhr.upload.onprogress = (ev: ProgressEvent<EventTarget>) => {\n if (ev.lengthComputable) {\n const percentComplete = (ev.loaded / ev.total) * 100\n setProgress(percentComplete)\n }\n }\n \n xhr.onload = function () {\n console.log('break3?', this)\n return this.status === 200\n ? resolve(this)\n : reject(new Error('Error while uploading: ' + this.status))\n }\n \n xhr.onerror = (ev: ProgressEvent<EventTarget>) => {\n console.log('break2', ev.target)\n reject(ev)\n }\n \n xhr.send(formData)\n } catch (e) {\n console.log('break1', e)\n reject(e)\n }\n },\n )\n \n if (res instanceof Error) throw res\n \n const data: any = JSON.parse(res.responseText)\n \n if (data.error) throw new Error(data.data)\n \n return { data: data.data }\n } catch (e) {\n console.log('break4', e)\n return { error: e.message || 'upload error' }\n }\n }\n \n const getContext = () => {\n let context = user.id\n \n if (!user.id) {\n // if not logged in\n const cookie = document.cookie\n .split(';')\n .find((c) => c.includes('cycle_cid'))\n \n if (cookie) {\n // use cookie value\n context = cookie.split('=')[1]\n } else {\n // set new cookie\n context =\n Math.random().toString(36).substring(2, 15) +\n Math.random().toString(36).substring(2, 15)\n \n document.cookie = `cycle_cid=${context};path=/;max-age=31536000`\n }\n }\n \n return context\n }\n \n const event = async (name: string, value?: any): Promise<boolean> => {\n try {\n const contextId = getContext()\n \n const r = await fetch(NOFY_API_URL + '/event', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: 'Basic ' + ANALYTICS_KEY,\n },\n body: JSON.stringify({\n source: IS_PROD ? 'cycle-frontend' : 'cycle-frontend-dev',\n contextId,\n name,\n value,\n }),\n })\n \n const res = await r.json()\n if (res.error) throw new Error(res.error)\n \n return true\n } catch (e) {\n console.log('#> event error: ', e)\n return false\n }\n }\n \n const pageView = async (url: string, referer?: string): Promise<boolean> => {\n try {\n const contextId = getContext()\n \n const r = await fetch(NOFY_API_URL + '/log/count', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: 'Basic ' + ANALYTICS_KEY,\n },\n body: JSON.stringify({\n meta: {\n contextId,\n type: 'pageview',\n },\n referer,\n identifier: url,\n }),\n })\n \n const res = await r.json()\n if (res.error) throw new Error(res.error)\n \n return true\n } catch (e) {\n console.log('#> event error: ', e)\n return false\n }\n } */\n\n const augmentToken = async ({\n url,\n method = \"POST\",\n body,\n }: {\n url: string;\n method?: \"GET\" | \"POST\" | \"DELETE\";\n body?: object;\n }) => {\n const res = await clientSideFetch({\n method: \"POST\",\n url: `${routePrefix}/augment`,\n body: { url, method, body },\n });\n if (res.isOk()) await refreshUser(true);\n return res;\n };\n\n useEffect(() => {\n if (!ready) refreshUser();\n }, []);\n\n const provider = {\n ready,\n login,\n register,\n logout,\n isLoggedIn,\n refreshUser,\n user,\n oAuth,\n get,\n post,\n del,\n setHeader,\n removeHeader,\n augmentToken,\n /* upload, */\n };\n\n return (\n <AuthContext.Provider value={provider}>{children}</AuthContext.Provider>\n );\n};\n\nexport default AuthContextProvider;\n","export type BaseError = {\n error: string;\n message: string;\n};\n\nexport type Success<S> = {\n data: S;\n};\n\n/**\n * A Result type that represents either a successful value (Ok) or an error (Err).\n * This is a discriminated union type that helps handle errors in a type-safe way.\n *\n * @template T - The type of the successful value\n * @template E - The type of the error, must extend BaseError\n */\nexport type Result<T, E extends BaseError> = Ok<T, E> | Err<T, E>;\n\ntype IResult<T, E extends BaseError> = {\n /**\n * Checks if the `Result` is an `Ok` instance\n */\n isOk: () => this is Ok<T, E>;\n\n /**\n * Checks if the `Result` is an `Err` instance.\n */\n isErr: () => this is Err<T, E>;\n};\n\n/**\n * Represents a successful `Result` value.\n *\n * @template T - The type of the successful value.\n * @template E - The type of the error, must extend `BaseError`.\n */\nexport class Ok<T, E extends BaseError> implements IResult<T, E> {\n value: Success<T>;\n\n constructor(value: Success<T>) {\n this.value = value;\n }\n\n isOk(): this is Ok<T, E> {\n return true;\n }\n\n isErr(): this is Err<T, E> {\n return false;\n }\n}\n\n/**\n * Represents an error `Result` value.\n *\n * @template T - The type of the successful value.\n * @template E - The type of the error, must extend `BaseError`.\n */\nexport class Err<T, E extends BaseError> implements IResult<T, E> {\n error: E;\n\n constructor(error: E) {\n this.error = error;\n }\n\n isOk(): this is Ok<T, E> {\n return false;\n }\n\n isErr(): this is Err<T, E> {\n return true;\n }\n}\n\n/**\n * Creates a new successful `Result` (i.e., an instance of `Ok`).\n *\n * @template T - The type of the successful value\n * @param value - The successful value\n * @returns A new `Ok` instance.\n */\nexport function ok<const T>(value: Success<T>): Result<T, never> {\n return new Ok(value);\n}\n\n/**\n * Creates a new error `Result` (i.e., an instance of `Err`).\n *\n * @template E - The type of the error, must extend `BaseError`.\n * @param error - The error value.\n * @returns A new `Err` instance.\n */\nexport function err<const E extends BaseError>(error: E): Result<never, E> {\n return new Err(error);\n}\n","import { BaseError, err, ok, Result, Success } from \"../types/response\";\n\nexport const clientSideFetch = async <T>({\n url,\n method = \"GET\",\n body,\n ...options\n}: {\n url: string;\n method?: \"GET\" | \"POST\" | \"DELETE\";\n body?: object;\n} & Omit<RequestInit, \"body\" | \"method\">): Promise<Result<T, BaseError>> => {\n const opts: RequestInit = {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n ...options.headers,\n },\n ...options,\n };\n\n try {\n if (body) opts.body = JSON.stringify(body);\n } catch (e) {\n return err({\n error: \"PARSE_ERROR\",\n message: \"Failed to parse request body as JSON\",\n });\n }\n\n try {\n const response: Response = await fetch(url, opts);\n if (!response.ok) {\n return err({\n error: \"RESPONSE_ERROR\",\n message: `HTTP error! status: ${response.status}`,\n });\n }\n\n try {\n const res = await response.json();\n if (res.error !== undefined) {\n return err(res);\n }\n\n return ok(res as Success<T>);\n } catch (e) {\n return err({\n error: \"PARSE_ERROR\",\n message: \"Failed to parse response as JSON\",\n });\n }\n } catch (e) {\n return err({\n error: \"FETCH_ERROR\",\n message: \"Failed to fetch the resource: \" + String(e),\n });\n }\n};\n","\"use client\";\n\nimport { useAuth } from \".\";\nimport { IChildProps } from \"../types/internal\";\n\nexport type LogoutProps = React.FC<React.ComponentProps<\"div\"> & IChildProps>;\n\nconst LogoutComponent: LogoutProps = ({ children, ...props }) => {\n const { logout } = useAuth();\n\n const handleLogout = async (e: any) => {\n e.preventDefault();\n await logout();\n };\n\n return (\n <div onClick={handleLogout} {...props}>\n {children}\n </div>\n );\n};\n\nexport default LogoutComponent;\n","import { useContext } from \"react\";\nimport { AuthContext } from \"./contextProvider\";\n\nexport const useAuth = () => {\n return useContext(AuthContext);\n};\n","import { useContext } from \"react\";\nimport { AuthContext } from \"./contextProvider\";\nimport { CallbackOptions, WrapperFunction } from \"../types\";\n\nexport const APIWrapper = <T,>(wrapperFunction: (cb: WrapperFunction) => T) => {\n return () => {\n const { get, post, del } = useContext(AuthContext);\n return wrapperFunction(async (data: CallbackOptions) => {\n const { method, url, body } = data;\n\n switch (method) {\n case \"GET\":\n return get({ url });\n case \"POST\":\n return post({ url, body: body ?? {} });\n case \"DELETE\":\n return del({ url });\n default:\n throw new Error(\"Unsupported method type\");\n }\n });\n };\n};\n"],"mappings":"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","names":["import_jsx_runtime","import_react","import_react"]}
@@ -203,6 +203,19 @@ var AuthContextProvider = ({
203
203
  headers: { ...customHeaders.current, ...headers }
204
204
  });
205
205
  };
206
+ const augmentToken = async ({
207
+ url,
208
+ method = "POST",
209
+ body
210
+ }) => {
211
+ const res = await clientSideFetch({
212
+ method: "POST",
213
+ url: `${routePrefix}/augment`,
214
+ body: { url, method, body }
215
+ });
216
+ if (res.isOk()) await refreshUser(true);
217
+ return res;
218
+ };
206
219
  useEffect(() => {
207
220
  if (!ready) refreshUser();
208
221
  }, []);
@@ -219,7 +232,8 @@ var AuthContextProvider = ({
219
232
  post,
220
233
  del,
221
234
  setHeader,
222
- removeHeader
235
+ removeHeader,
236
+ augmentToken
223
237
  /* upload, */
224
238
  };
225
239
  return /* @__PURE__ */ jsx(AuthContext.Provider, { value: provider, children });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/client/contextProvider.tsx","../../src/types/response.ts","../../src/client/request.ts","../../src/client/Logout.tsx","../../src/client/useAuth.ts","../../src/client/useAPIWrapper.tsx","../../src/client/index.ts"],"sourcesContent":["\"use client\";\n\nimport { createContext, useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n IAuthContext,\n IAuthContextOptions,\n ILoginData,\n IOAuthData,\n IRegisterData,\n} from \"../types/internal\";\n\nimport { type Result } from \"../types/response\";\n\nimport { clientSideFetch } from \"./request\";\n\nimport { useRouter } from \"next/navigation\";\nimport { BaseError } from \"../types/response\";\n/* +\n Frontend context for providing login, logout, register and refresh\n 'use client' needed for using -> client components only\n server components need to use useSession()\n*/\n\nexport const AuthContext = createContext<IAuthContext<any>>(null as any);\n\nconst AuthContextProvider = <IU,>({\n children,\n routePrefix = \"/api\",\n}: IAuthContextOptions) => {\n const [isLoggedIn, setIsLoggedIn] = useState(false);\n const [ready, setReady] = useState(false);\n const [user, setUser] = useState<IU | {}>({});\n\n const router = useRouter();\n const customHeaders = useRef<Record<string, string>>({});\n\n const setHeader = useCallback((key: string, value: string) => {\n customHeaders.current[key] = value;\n }, []);\n\n const removeHeader = useCallback((key: string) => {\n delete customHeaders.current[key];\n }, []);\n\n // POST /session/login\n const loginRoute = routePrefix + \"/login\";\n\n // POST /session/refresh\n const registerRoute = routePrefix + \"/register\";\n\n // GET /session/logout\n const logoutRoute = routePrefix + \"/logout\";\n\n // GET /session\n const userRoute = routePrefix + \"/user\";\n\n // GET /session/oauth/API_OAUTH_URL\n const oAuthRoute = routePrefix + \"/oauth\";\n\n // GET/POST/DELETE /proxy/URL\n const proxyRoute = routePrefix + \"/proxy\";\n\n const login = async (loginData: ILoginData): Promise<string> => {\n const res = await clientSideFetch({\n url: loginRoute,\n body: loginData.data,\n });\n if (res.isErr()) {\n return `${loginData.onErrorUrl || \"/\"}?error=${res.error.error}`;\n }\n\n setIsLoggedIn(true);\n\n return loginData.redirect || \"/\";\n };\n\n const register = async (registerData: IRegisterData): Promise<string> => {\n const res = await clientSideFetch<{ redirect: string }>({\n url: registerRoute,\n body: registerData.data,\n });\n\n if (res.isErr()) {\n return `${registerData.onErrorUrl || \"/\"}?error=${res.error.error}`;\n }\n return `${registerData.redirect || \"/\"}?success=true`;\n };\n\n const oAuth = async ({\n state,\n oAuthUrl,\n onErrorUrl,\n }: IOAuthData): Promise<string> => {\n const url = new URL(oAuthRoute, \"http://localhost/\");\n url.searchParams.set(\"authUrl\", oAuthUrl);\n\n if (state && state !== \"/\") url.searchParams.set(\"state\", state);\n\n const response = await clientSideFetch<string>({\n url: url.pathname + url.search,\n });\n if (response.isErr()) {\n return `${onErrorUrl || \"/\"}?error=${response.error.message}`;\n }\n\n return response.value.data;\n };\n\n const logout = async (): Promise<string> => {\n const data = await clientSideFetch<string>({\n url: logoutRoute,\n cache: \"no-store\",\n });\n\n if (data.isErr()) {\n return \"/\";\n }\n\n setIsLoggedIn(false);\n setUser({});\n\n return data.value.data;\n };\n\n const refreshUser = async (force?: boolean): Promise<void> => {\n const data = await clientSideFetch<IU>({\n url: `${userRoute}${force ? \"?force=true\" : \"\"}`,\n cache: \"no-store\",\n });\n\n if (data.isErr()) {\n setUser({});\n setIsLoggedIn(false);\n } else {\n setUser(data.value.data);\n }\n\n setReady(true);\n\n router.refresh();\n };\n\n const get = async <T,>({\n url,\n headers,\n }: {\n url: string;\n headers?: Record<string, string>;\n }): Promise<Result<T, BaseError>> => {\n return clientSideFetch({\n url: `${proxyRoute}${url}`,\n headers: { ...customHeaders.current, ...headers },\n });\n };\n\n const post = async <T,>({\n url,\n body,\n headers,\n }: {\n url: string;\n body: object;\n headers?: Record<string, string>;\n }): Promise<Result<T, BaseError>> => {\n return clientSideFetch({\n method: \"POST\",\n url: `${proxyRoute}${url}`,\n body,\n headers: { ...customHeaders.current, ...headers },\n });\n };\n\n const del = async <T,>({\n url,\n headers,\n }: {\n url: string;\n headers?: Record<string, string>;\n }): Promise<Result<T, BaseError>> => {\n return clientSideFetch({\n method: \"DELETE\",\n url: `${proxyRoute}${url}`,\n headers: { ...customHeaders.current, ...headers },\n });\n };\n\n /**\n * Can only be used if user is logged in! and already initialised\n * @param url url for upload\n * @param formData form data\n * @param setProgress progress dispatch\n * @returns object with data or error\n */\n /* const upload = async <T, U = any>(\n url: string,\n formName: string,\n files: File[],\n setProgress: (p: number) => void,\n ): Promise<TRequest<T, U>> => {\n try {\n if (!user.token) throw new Error('user not logged in')\n \n const res: Error | XMLHttpRequest = await new Promise(\n (resolve, reject) => {\n try {\n const xhr = new XMLHttpRequest()\n const formData = new FormData()\n \n for (let i = 0; i < files.length; i++)\n formData.append(formName, files[i])\n \n xhr.open('POST', `${API_URL}${url}`, true)\n xhr.setRequestHeader('Authorization', `Bearer ${user.token}`)\n xhr.upload.onprogress = (ev: ProgressEvent<EventTarget>) => {\n if (ev.lengthComputable) {\n const percentComplete = (ev.loaded / ev.total) * 100\n setProgress(percentComplete)\n }\n }\n \n xhr.onload = function () {\n console.log('break3?', this)\n return this.status === 200\n ? resolve(this)\n : reject(new Error('Error while uploading: ' + this.status))\n }\n \n xhr.onerror = (ev: ProgressEvent<EventTarget>) => {\n console.log('break2', ev.target)\n reject(ev)\n }\n \n xhr.send(formData)\n } catch (e) {\n console.log('break1', e)\n reject(e)\n }\n },\n )\n \n if (res instanceof Error) throw res\n \n const data: any = JSON.parse(res.responseText)\n \n if (data.error) throw new Error(data.data)\n \n return { data: data.data }\n } catch (e) {\n console.log('break4', e)\n return { error: e.message || 'upload error' }\n }\n }\n \n const getContext = () => {\n let context = user.id\n \n if (!user.id) {\n // if not logged in\n const cookie = document.cookie\n .split(';')\n .find((c) => c.includes('cycle_cid'))\n \n if (cookie) {\n // use cookie value\n context = cookie.split('=')[1]\n } else {\n // set new cookie\n context =\n Math.random().toString(36).substring(2, 15) +\n Math.random().toString(36).substring(2, 15)\n \n document.cookie = `cycle_cid=${context};path=/;max-age=31536000`\n }\n }\n \n return context\n }\n \n const event = async (name: string, value?: any): Promise<boolean> => {\n try {\n const contextId = getContext()\n \n const r = await fetch(NOFY_API_URL + '/event', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: 'Basic ' + ANALYTICS_KEY,\n },\n body: JSON.stringify({\n source: IS_PROD ? 'cycle-frontend' : 'cycle-frontend-dev',\n contextId,\n name,\n value,\n }),\n })\n \n const res = await r.json()\n if (res.error) throw new Error(res.error)\n \n return true\n } catch (e) {\n console.log('#> event error: ', e)\n return false\n }\n }\n \n const pageView = async (url: string, referer?: string): Promise<boolean> => {\n try {\n const contextId = getContext()\n \n const r = await fetch(NOFY_API_URL + '/log/count', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: 'Basic ' + ANALYTICS_KEY,\n },\n body: JSON.stringify({\n meta: {\n contextId,\n type: 'pageview',\n },\n referer,\n identifier: url,\n }),\n })\n \n const res = await r.json()\n if (res.error) throw new Error(res.error)\n \n return true\n } catch (e) {\n console.log('#> event error: ', e)\n return false\n }\n } */\n\n useEffect(() => {\n if (!ready) refreshUser();\n }, []);\n\n const provider = {\n ready,\n login,\n register,\n logout,\n isLoggedIn,\n refreshUser,\n user,\n oAuth,\n get,\n post,\n del,\n setHeader,\n removeHeader,\n /* upload, */\n };\n\n return (\n <AuthContext.Provider value={provider}>{children}</AuthContext.Provider>\n );\n};\n\nexport default AuthContextProvider;\n","export type BaseError = {\n error: string;\n message: string;\n};\n\nexport type Success<S> = {\n data: S;\n};\n\n/**\n * A Result type that represents either a successful value (Ok) or an error (Err).\n * This is a discriminated union type that helps handle errors in a type-safe way.\n *\n * @template T - The type of the successful value\n * @template E - The type of the error, must extend BaseError\n */\nexport type Result<T, E extends BaseError> = Ok<T, E> | Err<T, E>;\n\ntype IResult<T, E extends BaseError> = {\n /**\n * Checks if the `Result` is an `Ok` instance\n */\n isOk: () => this is Ok<T, E>;\n\n /**\n * Checks if the `Result` is an `Err` instance.\n */\n isErr: () => this is Err<T, E>;\n};\n\n/**\n * Represents a successful `Result` value.\n *\n * @template T - The type of the successful value.\n * @template E - The type of the error, must extend `BaseError`.\n */\nexport class Ok<T, E extends BaseError> implements IResult<T, E> {\n value: Success<T>;\n\n constructor(value: Success<T>) {\n this.value = value;\n }\n\n isOk(): this is Ok<T, E> {\n return true;\n }\n\n isErr(): this is Err<T, E> {\n return false;\n }\n}\n\n/**\n * Represents an error `Result` value.\n *\n * @template T - The type of the successful value.\n * @template E - The type of the error, must extend `BaseError`.\n */\nexport class Err<T, E extends BaseError> implements IResult<T, E> {\n error: E;\n\n constructor(error: E) {\n this.error = error;\n }\n\n isOk(): this is Ok<T, E> {\n return false;\n }\n\n isErr(): this is Err<T, E> {\n return true;\n }\n}\n\n/**\n * Creates a new successful `Result` (i.e., an instance of `Ok`).\n *\n * @template T - The type of the successful value\n * @param value - The successful value\n * @returns A new `Ok` instance.\n */\nexport function ok<const T>(value: Success<T>): Result<T, never> {\n return new Ok(value);\n}\n\n/**\n * Creates a new error `Result` (i.e., an instance of `Err`).\n *\n * @template E - The type of the error, must extend `BaseError`.\n * @param error - The error value.\n * @returns A new `Err` instance.\n */\nexport function err<const E extends BaseError>(error: E): Result<never, E> {\n return new Err(error);\n}\n","import { BaseError, err, ok, Result, Success } from \"../types/response\";\n\nexport const clientSideFetch = async <T>({\n url,\n method = \"GET\",\n body,\n ...options\n}: {\n url: string;\n method?: \"GET\" | \"POST\" | \"DELETE\";\n body?: object;\n} & Omit<RequestInit, \"body\" | \"method\">): Promise<Result<T, BaseError>> => {\n const opts: RequestInit = {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n ...options.headers,\n },\n ...options,\n };\n\n try {\n if (body) opts.body = JSON.stringify(body);\n } catch (e) {\n return err({\n error: \"PARSE_ERROR\",\n message: \"Failed to parse request body as JSON\",\n });\n }\n\n try {\n const response: Response = await fetch(url, opts);\n if (!response.ok) {\n return err({\n error: \"RESPONSE_ERROR\",\n message: `HTTP error! status: ${response.status}`,\n });\n }\n\n try {\n const res = await response.json();\n if (res.error !== undefined) {\n return err(res);\n }\n\n return ok(res as Success<T>);\n } catch (e) {\n return err({\n error: \"PARSE_ERROR\",\n message: \"Failed to parse response as JSON\",\n });\n }\n } catch (e) {\n return err({\n error: \"FETCH_ERROR\",\n message: \"Failed to fetch the resource: \" + String(e),\n });\n }\n};\n","\"use client\";\n\nimport { useAuth } from \".\";\nimport { IChildProps } from \"../types/internal\";\n\nexport type LogoutProps = React.FC<React.ComponentProps<\"div\"> & IChildProps>;\n\nconst LogoutComponent: LogoutProps = ({ children, ...props }) => {\n const { logout } = useAuth();\n\n const handleLogout = async (e: any) => {\n e.preventDefault();\n await logout();\n };\n\n return (\n <div onClick={handleLogout} {...props}>\n {children}\n </div>\n );\n};\n\nexport default LogoutComponent;\n","import { useContext } from \"react\";\nimport { AuthContext } from \"./contextProvider\";\n\nexport const useAuth = () => {\n return useContext(AuthContext);\n};\n","import { useContext } from \"react\";\nimport { AuthContext } from \"./contextProvider\";\nimport { CallbackOptions, WrapperFunction } from \"../types\";\n\nexport const APIWrapper = <T,>(wrapperFunction: (cb: WrapperFunction) => T) => {\n return () => {\n const { get, post, del } = useContext(AuthContext);\n return wrapperFunction(async (data: CallbackOptions) => {\n const { method, url, body } = data;\n\n switch (method) {\n case \"GET\":\n return get({ url });\n case \"POST\":\n return post({ url, body: body ?? {} });\n case \"DELETE\":\n return del({ url });\n default:\n throw new Error(\"Unsupported method type\");\n }\n });\n };\n};\n","import AuthContextProvider from \"./contextProvider\";\nimport LogoutComponent from \"./Logout\";\n\nexport const AuthProvider = AuthContextProvider;\nexport const Logout = LogoutComponent;\n\nexport { useAuth } from \"./useAuth\";\nexport { APIWrapper } from \"./useAPIWrapper\";\n"],"mappings":"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","names":["jsx","useContext","useContext"]}
1
+ {"version":3,"sources":["../../src/client/contextProvider.tsx","../../src/types/response.ts","../../src/client/request.ts","../../src/client/Logout.tsx","../../src/client/useAuth.ts","../../src/client/useAPIWrapper.tsx","../../src/client/index.ts"],"sourcesContent":["\"use client\";\n\nimport { createContext, useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n IAuthContext,\n IAuthContextOptions,\n ILoginData,\n IOAuthData,\n IRegisterData,\n} from \"../types/internal\";\n\nimport { type Result } from \"../types/response\";\n\nimport { clientSideFetch } from \"./request\";\n\nimport { useRouter } from \"next/navigation\";\nimport { BaseError } from \"../types/response\";\n/* +\n Frontend context for providing login, logout, register and refresh\n 'use client' needed for using -> client components only\n server components need to use useSession()\n*/\n\nexport const AuthContext = createContext<IAuthContext<any>>(null as any);\n\nconst AuthContextProvider = <IU,>({\n children,\n routePrefix = \"/api\",\n}: IAuthContextOptions) => {\n const [isLoggedIn, setIsLoggedIn] = useState(false);\n const [ready, setReady] = useState(false);\n const [user, setUser] = useState<IU | {}>({});\n\n const router = useRouter();\n const customHeaders = useRef<Record<string, string>>({});\n\n const setHeader = useCallback((key: string, value: string) => {\n customHeaders.current[key] = value;\n }, []);\n\n const removeHeader = useCallback((key: string) => {\n delete customHeaders.current[key];\n }, []);\n\n // POST /session/login\n const loginRoute = routePrefix + \"/login\";\n\n // POST /session/refresh\n const registerRoute = routePrefix + \"/register\";\n\n // GET /session/logout\n const logoutRoute = routePrefix + \"/logout\";\n\n // GET /session\n const userRoute = routePrefix + \"/user\";\n\n // GET /session/oauth/API_OAUTH_URL\n const oAuthRoute = routePrefix + \"/oauth\";\n\n // GET/POST/DELETE /proxy/URL\n const proxyRoute = routePrefix + \"/proxy\";\n\n const login = async (loginData: ILoginData): Promise<string> => {\n const res = await clientSideFetch({\n url: loginRoute,\n body: loginData.data,\n });\n if (res.isErr()) {\n return `${loginData.onErrorUrl || \"/\"}?error=${res.error.error}`;\n }\n\n setIsLoggedIn(true);\n\n return loginData.redirect || \"/\";\n };\n\n const register = async (registerData: IRegisterData): Promise<string> => {\n const res = await clientSideFetch<{ redirect: string }>({\n url: registerRoute,\n body: registerData.data,\n });\n\n if (res.isErr()) {\n return `${registerData.onErrorUrl || \"/\"}?error=${res.error.error}`;\n }\n return `${registerData.redirect || \"/\"}?success=true`;\n };\n\n const oAuth = async ({\n state,\n oAuthUrl,\n onErrorUrl,\n }: IOAuthData): Promise<string> => {\n const url = new URL(oAuthRoute, \"http://localhost/\");\n url.searchParams.set(\"authUrl\", oAuthUrl);\n\n if (state && state !== \"/\") url.searchParams.set(\"state\", state);\n\n const response = await clientSideFetch<string>({\n url: url.pathname + url.search,\n });\n if (response.isErr()) {\n return `${onErrorUrl || \"/\"}?error=${response.error.message}`;\n }\n\n return response.value.data;\n };\n\n const logout = async (): Promise<string> => {\n const data = await clientSideFetch<string>({\n url: logoutRoute,\n cache: \"no-store\",\n });\n\n if (data.isErr()) {\n return \"/\";\n }\n\n setIsLoggedIn(false);\n setUser({});\n\n return data.value.data;\n };\n\n const refreshUser = async (force?: boolean): Promise<void> => {\n const data = await clientSideFetch<IU>({\n url: `${userRoute}${force ? \"?force=true\" : \"\"}`,\n cache: \"no-store\",\n });\n\n if (data.isErr()) {\n setUser({});\n setIsLoggedIn(false);\n } else {\n setUser(data.value.data);\n }\n\n setReady(true);\n\n router.refresh();\n };\n\n const get = async <T,>({\n url,\n headers,\n }: {\n url: string;\n headers?: Record<string, string>;\n }): Promise<Result<T, BaseError>> => {\n return clientSideFetch({\n url: `${proxyRoute}${url}`,\n headers: { ...customHeaders.current, ...headers },\n });\n };\n\n const post = async <T,>({\n url,\n body,\n headers,\n }: {\n url: string;\n body: object;\n headers?: Record<string, string>;\n }): Promise<Result<T, BaseError>> => {\n return clientSideFetch({\n method: \"POST\",\n url: `${proxyRoute}${url}`,\n body,\n headers: { ...customHeaders.current, ...headers },\n });\n };\n\n const del = async <T,>({\n url,\n headers,\n }: {\n url: string;\n headers?: Record<string, string>;\n }): Promise<Result<T, BaseError>> => {\n return clientSideFetch({\n method: \"DELETE\",\n url: `${proxyRoute}${url}`,\n headers: { ...customHeaders.current, ...headers },\n });\n };\n\n /**\n * Can only be used if user is logged in! and already initialised\n * @param url url for upload\n * @param formData form data\n * @param setProgress progress dispatch\n * @returns object with data or error\n */\n /* const upload = async <T, U = any>(\n url: string,\n formName: string,\n files: File[],\n setProgress: (p: number) => void,\n ): Promise<TRequest<T, U>> => {\n try {\n if (!user.token) throw new Error('user not logged in')\n \n const res: Error | XMLHttpRequest = await new Promise(\n (resolve, reject) => {\n try {\n const xhr = new XMLHttpRequest()\n const formData = new FormData()\n \n for (let i = 0; i < files.length; i++)\n formData.append(formName, files[i])\n \n xhr.open('POST', `${API_URL}${url}`, true)\n xhr.setRequestHeader('Authorization', `Bearer ${user.token}`)\n xhr.upload.onprogress = (ev: ProgressEvent<EventTarget>) => {\n if (ev.lengthComputable) {\n const percentComplete = (ev.loaded / ev.total) * 100\n setProgress(percentComplete)\n }\n }\n \n xhr.onload = function () {\n console.log('break3?', this)\n return this.status === 200\n ? resolve(this)\n : reject(new Error('Error while uploading: ' + this.status))\n }\n \n xhr.onerror = (ev: ProgressEvent<EventTarget>) => {\n console.log('break2', ev.target)\n reject(ev)\n }\n \n xhr.send(formData)\n } catch (e) {\n console.log('break1', e)\n reject(e)\n }\n },\n )\n \n if (res instanceof Error) throw res\n \n const data: any = JSON.parse(res.responseText)\n \n if (data.error) throw new Error(data.data)\n \n return { data: data.data }\n } catch (e) {\n console.log('break4', e)\n return { error: e.message || 'upload error' }\n }\n }\n \n const getContext = () => {\n let context = user.id\n \n if (!user.id) {\n // if not logged in\n const cookie = document.cookie\n .split(';')\n .find((c) => c.includes('cycle_cid'))\n \n if (cookie) {\n // use cookie value\n context = cookie.split('=')[1]\n } else {\n // set new cookie\n context =\n Math.random().toString(36).substring(2, 15) +\n Math.random().toString(36).substring(2, 15)\n \n document.cookie = `cycle_cid=${context};path=/;max-age=31536000`\n }\n }\n \n return context\n }\n \n const event = async (name: string, value?: any): Promise<boolean> => {\n try {\n const contextId = getContext()\n \n const r = await fetch(NOFY_API_URL + '/event', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: 'Basic ' + ANALYTICS_KEY,\n },\n body: JSON.stringify({\n source: IS_PROD ? 'cycle-frontend' : 'cycle-frontend-dev',\n contextId,\n name,\n value,\n }),\n })\n \n const res = await r.json()\n if (res.error) throw new Error(res.error)\n \n return true\n } catch (e) {\n console.log('#> event error: ', e)\n return false\n }\n }\n \n const pageView = async (url: string, referer?: string): Promise<boolean> => {\n try {\n const contextId = getContext()\n \n const r = await fetch(NOFY_API_URL + '/log/count', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: 'Basic ' + ANALYTICS_KEY,\n },\n body: JSON.stringify({\n meta: {\n contextId,\n type: 'pageview',\n },\n referer,\n identifier: url,\n }),\n })\n \n const res = await r.json()\n if (res.error) throw new Error(res.error)\n \n return true\n } catch (e) {\n console.log('#> event error: ', e)\n return false\n }\n } */\n\n const augmentToken = async ({\n url,\n method = \"POST\",\n body,\n }: {\n url: string;\n method?: \"GET\" | \"POST\" | \"DELETE\";\n body?: object;\n }) => {\n const res = await clientSideFetch({\n method: \"POST\",\n url: `${routePrefix}/augment`,\n body: { url, method, body },\n });\n if (res.isOk()) await refreshUser(true);\n return res;\n };\n\n useEffect(() => {\n if (!ready) refreshUser();\n }, []);\n\n const provider = {\n ready,\n login,\n register,\n logout,\n isLoggedIn,\n refreshUser,\n user,\n oAuth,\n get,\n post,\n del,\n setHeader,\n removeHeader,\n augmentToken,\n /* upload, */\n };\n\n return (\n <AuthContext.Provider value={provider}>{children}</AuthContext.Provider>\n );\n};\n\nexport default AuthContextProvider;\n","export type BaseError = {\n error: string;\n message: string;\n};\n\nexport type Success<S> = {\n data: S;\n};\n\n/**\n * A Result type that represents either a successful value (Ok) or an error (Err).\n * This is a discriminated union type that helps handle errors in a type-safe way.\n *\n * @template T - The type of the successful value\n * @template E - The type of the error, must extend BaseError\n */\nexport type Result<T, E extends BaseError> = Ok<T, E> | Err<T, E>;\n\ntype IResult<T, E extends BaseError> = {\n /**\n * Checks if the `Result` is an `Ok` instance\n */\n isOk: () => this is Ok<T, E>;\n\n /**\n * Checks if the `Result` is an `Err` instance.\n */\n isErr: () => this is Err<T, E>;\n};\n\n/**\n * Represents a successful `Result` value.\n *\n * @template T - The type of the successful value.\n * @template E - The type of the error, must extend `BaseError`.\n */\nexport class Ok<T, E extends BaseError> implements IResult<T, E> {\n value: Success<T>;\n\n constructor(value: Success<T>) {\n this.value = value;\n }\n\n isOk(): this is Ok<T, E> {\n return true;\n }\n\n isErr(): this is Err<T, E> {\n return false;\n }\n}\n\n/**\n * Represents an error `Result` value.\n *\n * @template T - The type of the successful value.\n * @template E - The type of the error, must extend `BaseError`.\n */\nexport class Err<T, E extends BaseError> implements IResult<T, E> {\n error: E;\n\n constructor(error: E) {\n this.error = error;\n }\n\n isOk(): this is Ok<T, E> {\n return false;\n }\n\n isErr(): this is Err<T, E> {\n return true;\n }\n}\n\n/**\n * Creates a new successful `Result` (i.e., an instance of `Ok`).\n *\n * @template T - The type of the successful value\n * @param value - The successful value\n * @returns A new `Ok` instance.\n */\nexport function ok<const T>(value: Success<T>): Result<T, never> {\n return new Ok(value);\n}\n\n/**\n * Creates a new error `Result` (i.e., an instance of `Err`).\n *\n * @template E - The type of the error, must extend `BaseError`.\n * @param error - The error value.\n * @returns A new `Err` instance.\n */\nexport function err<const E extends BaseError>(error: E): Result<never, E> {\n return new Err(error);\n}\n","import { BaseError, err, ok, Result, Success } from \"../types/response\";\n\nexport const clientSideFetch = async <T>({\n url,\n method = \"GET\",\n body,\n ...options\n}: {\n url: string;\n method?: \"GET\" | \"POST\" | \"DELETE\";\n body?: object;\n} & Omit<RequestInit, \"body\" | \"method\">): Promise<Result<T, BaseError>> => {\n const opts: RequestInit = {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n ...options.headers,\n },\n ...options,\n };\n\n try {\n if (body) opts.body = JSON.stringify(body);\n } catch (e) {\n return err({\n error: \"PARSE_ERROR\",\n message: \"Failed to parse request body as JSON\",\n });\n }\n\n try {\n const response: Response = await fetch(url, opts);\n if (!response.ok) {\n return err({\n error: \"RESPONSE_ERROR\",\n message: `HTTP error! status: ${response.status}`,\n });\n }\n\n try {\n const res = await response.json();\n if (res.error !== undefined) {\n return err(res);\n }\n\n return ok(res as Success<T>);\n } catch (e) {\n return err({\n error: \"PARSE_ERROR\",\n message: \"Failed to parse response as JSON\",\n });\n }\n } catch (e) {\n return err({\n error: \"FETCH_ERROR\",\n message: \"Failed to fetch the resource: \" + String(e),\n });\n }\n};\n","\"use client\";\n\nimport { useAuth } from \".\";\nimport { IChildProps } from \"../types/internal\";\n\nexport type LogoutProps = React.FC<React.ComponentProps<\"div\"> & IChildProps>;\n\nconst LogoutComponent: LogoutProps = ({ children, ...props }) => {\n const { logout } = useAuth();\n\n const handleLogout = async (e: any) => {\n e.preventDefault();\n await logout();\n };\n\n return (\n <div onClick={handleLogout} {...props}>\n {children}\n </div>\n );\n};\n\nexport default LogoutComponent;\n","import { useContext } from \"react\";\nimport { AuthContext } from \"./contextProvider\";\n\nexport const useAuth = () => {\n return useContext(AuthContext);\n};\n","import { useContext } from \"react\";\nimport { AuthContext } from \"./contextProvider\";\nimport { CallbackOptions, WrapperFunction } from \"../types\";\n\nexport const APIWrapper = <T,>(wrapperFunction: (cb: WrapperFunction) => T) => {\n return () => {\n const { get, post, del } = useContext(AuthContext);\n return wrapperFunction(async (data: CallbackOptions) => {\n const { method, url, body } = data;\n\n switch (method) {\n case \"GET\":\n return get({ url });\n case \"POST\":\n return post({ url, body: body ?? {} });\n case \"DELETE\":\n return del({ url });\n default:\n throw new Error(\"Unsupported method type\");\n }\n });\n };\n};\n","import AuthContextProvider from \"./contextProvider\";\nimport LogoutComponent from \"./Logout\";\n\nexport const AuthProvider = AuthContextProvider;\nexport const Logout = LogoutComponent;\n\nexport { useAuth } from \"./useAuth\";\nexport { APIWrapper } from \"./useAPIWrapper\";\n"],"mappings":"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","names":["jsx","useContext","useContext"]}
package/dist/index.d.mts CHANGED
@@ -99,6 +99,16 @@ interface IConfig {
99
99
  apiUrl: string;
100
100
  userEndpoint: string;
101
101
  debug?: boolean;
102
+ /**
103
+ * Map of cookie names to HTTP header names.
104
+ * When set, serverSideFetch will read these cookies server-side and
105
+ * forward their values as the corresponding headers to the backend.
106
+ * Useful for forwarding client-side state (e.g. selected channel) during SSR.
107
+ *
108
+ * @example
109
+ * cookieHeaders: { 'w1nter-editor': 'X-Editor-Channel' }
110
+ */
111
+ cookieHeaders?: Record<string, string>;
102
112
  }
103
113
  type Session<U = DefaultUser> = IronSession<ServerSideSession<U>>;
104
114
  type CallbackOptions = {
package/dist/index.d.ts CHANGED
@@ -99,6 +99,16 @@ interface IConfig {
99
99
  apiUrl: string;
100
100
  userEndpoint: string;
101
101
  debug?: boolean;
102
+ /**
103
+ * Map of cookie names to HTTP header names.
104
+ * When set, serverSideFetch will read these cookies server-side and
105
+ * forward their values as the corresponding headers to the backend.
106
+ * Useful for forwarding client-side state (e.g. selected channel) during SSR.
107
+ *
108
+ * @example
109
+ * cookieHeaders: { 'w1nter-editor': 'X-Editor-Channel' }
110
+ */
111
+ cookieHeaders?: Record<string, string>;
102
112
  }
103
113
  type Session<U = DefaultUser> = IronSession<ServerSideSession<U>>;
104
114
  type CallbackOptions = {
package/dist/index.js CHANGED
@@ -96,6 +96,7 @@ var getSession = async (sessionOpts) => {
96
96
  };
97
97
 
98
98
  // src/server/fetch.ts
99
+ var import_headers2 = require("next/headers");
99
100
  var refreshPromise = null;
100
101
  var serverSideFetch = async ({
101
102
  url,
@@ -106,10 +107,26 @@ var serverSideFetch = async ({
106
107
  skipRefresh = false,
107
108
  ...options
108
109
  }) => {
110
+ var _a;
109
111
  const headers = new Headers({
110
112
  "Content-Type": "application/json",
111
113
  ...options.headers
112
114
  });
115
+ if (config.cookieHeaders) {
116
+ try {
117
+ const cookieStore = await (0, import_headers2.cookies)();
118
+ for (const [cookieName, headerName] of Object.entries(
119
+ config.cookieHeaders
120
+ )) {
121
+ if (headers.has(headerName)) continue;
122
+ const value = (_a = cookieStore.get(cookieName)) == null ? void 0 : _a.value;
123
+ if (value) headers.set(headerName, value);
124
+ }
125
+ } catch (e) {
126
+ if (config.debug)
127
+ console.log("#> cookieHeaders: cookies() unavailable", e);
128
+ }
129
+ }
113
130
  const session = await getSession();
114
131
  if (session.token !== void 0) {
115
132
  headers.set("Authorization", `Bearer ${session.token.jwt}`);
@@ -237,9 +254,11 @@ var rHandler = {
237
254
  },
238
255
  POST: {
239
256
  login: ({ request, config }) => login(request, config),
257
+ augment: ({ request, config }) => augment(request, config),
240
258
  proxy: ({ request, config, options }) => proxyFunction("POST", request, config, options)
241
259
  },
242
260
  DELETE: {
261
+ augment: ({ request, config }) => augment(request, config),
243
262
  proxy: ({ request, config, options }) => proxyFunction("DELETE", request, config, options)
244
263
  }
245
264
  };
@@ -399,6 +418,30 @@ async function proxyFunction(method, request, config, options) {
399
418
  }
400
419
  return Response.json(res.value);
401
420
  }
421
+ async function augment(request, config) {
422
+ var _a;
423
+ const { url, method, body } = await request.json();
424
+ const res = await serverSideFetch({
425
+ method: method || "POST",
426
+ url,
427
+ body,
428
+ config
429
+ });
430
+ if (config.debug) console.log("#> augment", res);
431
+ if (res.isErr()) {
432
+ return Response.json(res.error);
433
+ }
434
+ const session = await getSession();
435
+ const dec = (0, import_jwt_decode.jwtDecode)(res.value.data.token);
436
+ session.token = {
437
+ jwt: res.value.data.token,
438
+ refresh: ((_a = session.token) == null ? void 0 : _a.refresh) || "",
439
+ decoded: dec
440
+ };
441
+ session.user = void 0;
442
+ await session.save();
443
+ return Response.json({ data: "ok" });
444
+ }
402
445
 
403
446
  // src/server/index.ts
404
447
  var CelestyaProxy = (config) => {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/types/response.ts","../src/server/api.ts","../src/server/session.ts","../src/server/fetch.ts","../src/server/index.ts","../src/server/wrapper.ts"],"sourcesContent":["export {\n type IConfig,\n type IRequestOptions,\n type Session,\n type WrapperFunction,\n} from \"./types\";\nexport {\n type Result,\n type BaseError,\n type Ok,\n type Err,\n ok,\n err,\n} from \"./types/response\";\n\nexport { CelestyaProxy } from \"./server\";\nexport { serverSideFetch, attemptTokenRefresh } from \"./server/fetch\";\nexport { serverAPIWrapper } from \"./server/wrapper\";\nexport { getSession } from \"./server/session\";\n","export type BaseError = {\n error: string;\n message: string;\n};\n\nexport type Success<S> = {\n data: S;\n};\n\n/**\n * A Result type that represents either a successful value (Ok) or an error (Err).\n * This is a discriminated union type that helps handle errors in a type-safe way.\n *\n * @template T - The type of the successful value\n * @template E - The type of the error, must extend BaseError\n */\nexport type Result<T, E extends BaseError> = Ok<T, E> | Err<T, E>;\n\ntype IResult<T, E extends BaseError> = {\n /**\n * Checks if the `Result` is an `Ok` instance\n */\n isOk: () => this is Ok<T, E>;\n\n /**\n * Checks if the `Result` is an `Err` instance.\n */\n isErr: () => this is Err<T, E>;\n};\n\n/**\n * Represents a successful `Result` value.\n *\n * @template T - The type of the successful value.\n * @template E - The type of the error, must extend `BaseError`.\n */\nexport class Ok<T, E extends BaseError> implements IResult<T, E> {\n value: Success<T>;\n\n constructor(value: Success<T>) {\n this.value = value;\n }\n\n isOk(): this is Ok<T, E> {\n return true;\n }\n\n isErr(): this is Err<T, E> {\n return false;\n }\n}\n\n/**\n * Represents an error `Result` value.\n *\n * @template T - The type of the successful value.\n * @template E - The type of the error, must extend `BaseError`.\n */\nexport class Err<T, E extends BaseError> implements IResult<T, E> {\n error: E;\n\n constructor(error: E) {\n this.error = error;\n }\n\n isOk(): this is Ok<T, E> {\n return false;\n }\n\n isErr(): this is Err<T, E> {\n return true;\n }\n}\n\n/**\n * Creates a new successful `Result` (i.e., an instance of `Ok`).\n *\n * @template T - The type of the successful value\n * @param value - The successful value\n * @returns A new `Ok` instance.\n */\nexport function ok<const T>(value: Success<T>): Result<T, never> {\n return new Ok(value);\n}\n\n/**\n * Creates a new error `Result` (i.e., an instance of `Err`).\n *\n * @template E - The type of the error, must extend `BaseError`.\n * @param error - The error value.\n * @returns A new `Err` instance.\n */\nexport function err<const E extends BaseError>(error: E): Result<never, E> {\n return new Err(error);\n}\n","import { NextRequest } from \"next/server\";\nimport { revalidatePath } from \"next/cache\";\nimport { jwtDecode } from \"jwt-decode\";\nimport { IConfig, IRequestOptions, RouteHandler } from \"../types\";\nimport { DefaultUser, getSession } from \"./session\";\nimport { serverSideFetch, attemptTokenRefresh } from \"./fetch\";\n\nconst rHandler: RouteHandler = {\n GET: {\n user: ({ request, config }) => getUser(request, config),\n refresh: ({ request, config }) => refresh(request, config),\n logout: ({ config }) => logout(config),\n debug: () => debug(),\n oauth: ({ request, config }) => oauth(request, config),\n oauth_callback: ({ request, config }) => oauth_callback(request, config),\n proxy: ({ request, config, options }) =>\n proxyFunction(\"GET\", request, config, options),\n },\n POST: {\n login: ({ request, config }) => login(request, config),\n proxy: ({ request, config, options }) =>\n proxyFunction(\"POST\", request, config, options),\n },\n DELETE: {\n proxy: ({ request, config, options }) =>\n proxyFunction(\"DELETE\", request, config, options),\n },\n};\n\nexport async function Proxy(\n method: string,\n request: NextRequest,\n options: IRequestOptions,\n config: IConfig\n) {\n try {\n const params = await options.params;\n const parameters = {\n request,\n path:\n params.endpoint[0] ||\n request.nextUrl.pathname.replace(config.route, \"\"),\n options: params.endpoint,\n config,\n };\n\n if (config.debug) console.log(\"#> proxy:\", parameters);\n\n if (rHandler[method][parameters.path])\n return await rHandler[method][parameters.path](parameters);\n\n return Response.json({\n error: \"INVALID_ENDPOINT\",\n message: \"the provided endpoint is not valid\",\n });\n } catch (e) {\n console.log(\"#> proxyError:\", e);\n Response.json({\n error: \"REQUEST_ERROR\",\n message: \"error while sending request through frontend-backend proxy\",\n });\n }\n}\n\nasync function login(request: NextRequest, config: IConfig) {\n const formData = await request.json();\n const res = await serverSideFetch<{ token: string; refresh: string }>({\n method: \"POST\",\n url: \"/login\",\n body: formData,\n sessionIsOptional: true,\n config,\n });\n\n if (config.debug) console.log(\"#> login\", res);\n if (res.isErr()) {\n return Response.json(res.error);\n }\n\n const dec = jwtDecode<any>(res.value.data.token);\n\n const session = await getSession();\n session.token = {\n jwt: res.value.data.token,\n refresh: res.value.data.refresh || \"refresh_token\",\n decoded: dec,\n };\n\n await session.save();\n\n return Response.json({\n redirect: \"/\",\n });\n}\n\nasync function getUser(request: NextRequest, config: IConfig) {\n const session = await getSession();\n\n if (session.token === undefined)\n return Response.json({\n error: \"SESSION_ERROR\",\n message: \"Session is required but not found.\",\n });\n\n const force = request.nextUrl.searchParams.get(\"force\") === \"true\";\n\n // * User already exists in session\n if (session.user !== undefined && !force)\n return Response.json({\n data: session.user,\n });\n\n // * User does not exist in session\n const res = await serverSideFetch<DefaultUser>({\n url: `${config.userEndpoint}`,\n config,\n });\n\n if (config.debug) console.log(\"#> getUser\", res);\n if (res.isErr()) {\n return Response.json(res.error);\n }\n\n session.user = res.value.data;\n await session.save();\n\n return Response.json({\n data: session.user,\n });\n}\n\nasync function oauth(request: NextRequest, config: IConfig) {\n const authUrl = request.nextUrl.searchParams.get(\"authUrl\");\n const state = request.nextUrl.searchParams.get(\"state\");\n\n if (!authUrl) throw new Error(\"No authUrl provided\");\n\n const url = new URL(config.route + \"/oauth_callback\", config.host);\n if (state) url.searchParams.set(\"state\", state);\n\n const oAuthUrl = new URL(authUrl, config.apiUrl);\n oAuthUrl.searchParams.set(\"returnUrl\", url.toString());\n\n const res = await serverSideFetch({\n url: oAuthUrl.pathname + oAuthUrl.search,\n config,\n sessionIsOptional: true,\n });\n\n if (res.isErr()) {\n if (config.debug) console.log(\"#> oauthError\", res.error);\n return Response.json(res.error);\n }\n\n return Response.json(res.value);\n}\n\nasync function oauth_callback(request: NextRequest, config: IConfig) {\n const refresh = request.nextUrl.searchParams.get(\"refresh\");\n\n const token = request.nextUrl.searchParams.get(\"token\");\n if (token === null) throw new Error(\"No token provided\");\n\n const dec = jwtDecode<any>(token);\n\n const session = await getSession();\n session.token = {\n jwt: token,\n refresh: refresh || \"refresh_token\",\n decoded: dec,\n };\n\n await session.save();\n\n // redirect to return url if provided\n const state = request.nextUrl.searchParams.get(\"state\");\n if (state !== null)\n return Response.redirect(\n state.includes(\"http\") ? state : config.host + state\n );\n\n return Response.redirect(config.host);\n}\n\nasync function logout(config: IConfig) {\n const session = await getSession();\n session.destroy();\n\n revalidatePath(config.host, \"layout\");\n\n return Response.json({\n redirect: \"/\",\n });\n}\n\nasync function debug() {\n return Response.json(await getSession());\n}\n\nasync function refresh(request: NextRequest, config: IConfig) {\n const result = await attemptTokenRefresh(config);\n\n if (config.debug) console.log(\"#> refresh result\", result);\n\n if (result.isErr()) {\n return Response.json(result.error, { status: 401 });\n }\n\n const url = request.nextUrl;\n url.pathname = decodeURIComponent(url.searchParams.get(\"r\") || \"\");\n url.searchParams.delete(\"r\");\n\n return Response.redirect(url);\n}\n\nasync function proxyFunction(\n method: \"GET\" | \"POST\" | \"DELETE\",\n request: NextRequest,\n config: IConfig,\n options: string[]\n) {\n options.shift(); // remove the first element which is the endpoint\n\n // Forward custom headers (X-*) from the incoming request\n const forwardHeaders: Record<string, string> = {};\n request.headers.forEach((value, key) => {\n if (key.startsWith(\"x-\") && key !== \"x-forwarded-for\" && key !== \"x-forwarded-host\" && key !== \"x-forwarded-proto\") {\n forwardHeaders[key] = value;\n }\n });\n\n const res = await serverSideFetch({\n method,\n url: `/${options.join(\"/\")}${request.nextUrl.search}`,\n body: method === \"POST\" ? await request.json() : undefined,\n config,\n headers: forwardHeaders,\n });\n\n if (config.debug) console.log(\"#> proxyFunction\", res);\n if (res.isErr()) {\n return Response.json(res.error);\n }\n\n return Response.json(res.value);\n}\n","import { SessionOptions } from \"iron-session\";\nimport { getIronSession } from \"iron-session\";\nimport { cookies } from \"next/headers\";\nimport { ServerSideSession } from \"../types/internal\";\nimport { Session } from \"../types\";\n\ndeclare module \"iron-session\" {\n interface IronSessionData<U, T> {\n user?: U;\n token?: {\n jwt: string;\n refresh: string;\n decoded: T;\n };\n }\n}\n\nexport interface DefaultUser {\n [key: string]: unknown;\n}\n\nexport interface Token {\n token: string;\n}\n\nexport const sessionOptions: SessionOptions = {\n password: process.env.CELESTYA_SECRET || \"PLEASE_SET_PASSWORD\",\n cookieName: process.env.CELESTYA_COOKIE_NAME || \"PLEASE_SET_COOKIE_NAME\",\n cookieOptions: { secure: process.env.SECURE === \"true\" },\n};\n\nexport const getSession = async <U = DefaultUser>(\n sessionOpts?: SessionOptions\n) => {\n if (\n sessionOpts === undefined &&\n (!process.env.CELESTYA_SECRET || !process.env.CELESTYA_COOKIE_NAME)\n ) {\n throw new Error(\n \"CELESTYA_SECRET and CELESTYA_COOKIE_NAME must be set in environment variables.\"\n );\n }\n\n const session: Session<U> = await getIronSession<ServerSideSession<U>>(\n await cookies(),\n sessionOpts || sessionOptions\n );\n\n return session;\n};\n","import { IConfig } from \"../types\";\nimport { BaseError, err, ok, Result, Success } from \"../types/response\";\nimport { getSession } from \"./session\";\n\n// Global refresh lock to prevent multiple simultaneous refresh attempts\nlet refreshPromise: Promise<Result<string, BaseError>> | null = null;\n\nexport const serverSideFetch = async <T>({\n url,\n method = \"GET\",\n config,\n body,\n sessionIsOptional = false,\n skipRefresh = false,\n ...options\n}: {\n url: string;\n method?: \"GET\" | \"POST\" | \"DELETE\";\n body?: object;\n config: IConfig;\n sessionIsOptional?: boolean;\n skipRefresh?: boolean;\n} & Omit<RequestInit, \"body\" | \"method\">): Promise<Result<T, BaseError>> => {\n const headers = new Headers({\n \"Content-Type\": \"application/json\",\n ...(options.headers as Record<string, string>),\n });\n\n const session = await getSession();\n\n if (session.token !== undefined) {\n headers.set(\"Authorization\", `Bearer ${session.token.jwt}`);\n } else if (!sessionIsOptional) {\n return err({\n error: \"SESSION_ERROR\",\n message: \"Session is required but not found.\",\n });\n }\n\n const opts: RequestInit = {\n method,\n ...options,\n headers,\n };\n\n try {\n if (body) opts.body = JSON.stringify(body);\n } catch (e) {\n console.log(\"Error stringifying body: \", e);\n }\n\n try {\n const response: Response = await fetch(`${config.apiUrl}${url}`, opts);\n\n // Handle 401 Unauthorized - try to refresh token\n if (response.status === 401 && !skipRefresh && !sessionIsOptional) {\n if (config.debug)\n console.log(\"#> 401 detected, attempting token refresh\");\n\n // Local reference to the refresh promise to prevent race conditions\n let currentRefresh: Promise<Result<string, BaseError>>;\n\n // Check if refresh is already in progress\n if (refreshPromise === null) {\n // Start new refresh process\n refreshPromise = attemptTokenRefresh(config).finally(() => {\n // Clear the lock when done (success or failure)\n refreshPromise = null;\n });\n currentRefresh = refreshPromise;\n } else {\n if (config.debug)\n console.log(\"#> Refresh already in progress, waiting...\");\n currentRefresh = refreshPromise;\n }\n\n // Wait for the refresh to complete (whether we started it or not)\n const refreshResult = await currentRefresh;\n\n if (refreshResult.isOk()) {\n // Retry the original request with refreshed token\n return serverSideFetch<T>({\n url,\n method,\n config,\n body,\n sessionIsOptional,\n skipRefresh: true, // Prevent infinite loop\n ...options,\n });\n }\n\n // Refresh failed, return the error\n return err(refreshResult.error);\n }\n\n if (!response.ok) {\n return err({\n error: \"RESPONSE_ERROR\",\n message: `HTTP error! status: ${response.status}`,\n });\n }\n\n try {\n const res = await response.json();\n if (res.error !== undefined) {\n return err(res);\n }\n\n return ok(res as Success<T>);\n } catch (e) {\n return err({\n error: \"PARSE_ERROR\",\n message: \"Failed to parse response as JSON\",\n });\n }\n } catch (e) {\n return err({\n error: \"FETCH_ERROR\",\n message: \"Failed to fetch the resource: \" + String(e),\n });\n }\n};\n\nexport async function attemptTokenRefresh(\n config: IConfig\n): Promise<Result<string, BaseError>> {\n if (config.debug) console.log(\"#> attemptTokenRefresh called\");\n\n const { jwtDecode } = await import(\"jwt-decode\");\n const session = await getSession();\n\n if (!session.token?.refresh) {\n return err({\n error: \"NO_REFRESH_TOKEN\",\n message: \"No refresh token available in session\",\n });\n }\n\n const res = await serverSideFetch<{ token: string }>({\n method: \"POST\",\n url: \"/refresh\",\n body: {\n refreshToken: session.token.refresh,\n },\n sessionIsOptional: true,\n skipRefresh: true, // Prevent infinite loop\n config,\n });\n\n if (config.debug) console.log(\"#> attemptTokenRefresh\", res);\n if (res.isErr()) {\n // Refresh token is invalid or expired, destroy session\n session.destroy();\n return err(res.error);\n }\n\n // Update session with new JWT\n const decoded = jwtDecode<any>(res.value.data.token);\n const newToken = {\n jwt: res.value.data.token,\n refresh: session.token.refresh, // Keep the same refresh token\n decoded,\n };\n\n session.token = newToken;\n\n await session.save();\n\n return ok({ data: \"success\" });\n}\n","import { NextRequest } from \"next/server\";\nimport { IConfig, IRequestOptions } from \"../types\";\nimport { Proxy } from \"./api\";\n\nexport const CelestyaProxy = (config: IConfig) => {\n return {\n POST: (req: NextRequest, opt: IRequestOptions) =>\n Proxy(\"POST\", req, opt, config),\n GET: (req: NextRequest, opt: IRequestOptions) =>\n Proxy(\"GET\", req, opt, config),\n DELETE: (req: NextRequest, opt: IRequestOptions) =>\n Proxy(\"DELETE\", req, opt, config),\n };\n};\n","import { CallbackOptions, IConfig, WrapperFunction } from \"../types\";\nimport { serverSideFetch } from \"./fetch\";\n\n/**\n * Register new Wrapper for the API.\n *\n * Example Wrapper:\n * ```ts\n * const apiWrapper = (cb: WrapperFunction) => {\n * return {\n * commmands: {\n * get: () => cb<string>({ method: \"GET\", url: \"/command\" }),\n * update: (id: string, body: JSON) =>\n * cb({ method: \"POST\", url: `/command/${id}`, body }),\n * },\n * };\n * };\n * ````\n * @param apiWrapper\n * @param config\n * @returns\n */\nexport const serverAPIWrapper = <T>(\n apiWrapper: (cb: WrapperFunction) => T,\n config: IConfig\n) => {\n return apiWrapper(async (data: CallbackOptions) => {\n const { method, url, body } = data;\n\n return serverSideFetch({\n url,\n method,\n body,\n config,\n });\n });\n};\n"],"mappings":"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","names":["jwtDecode","Proxy","refresh","Proxy"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/types/response.ts","../src/server/api.ts","../src/server/session.ts","../src/server/fetch.ts","../src/server/index.ts","../src/server/wrapper.ts"],"sourcesContent":["export {\n type IConfig,\n type IRequestOptions,\n type Session,\n type WrapperFunction,\n} from \"./types\";\nexport {\n type Result,\n type BaseError,\n type Ok,\n type Err,\n ok,\n err,\n} from \"./types/response\";\n\nexport { CelestyaProxy } from \"./server\";\nexport { serverSideFetch, attemptTokenRefresh } from \"./server/fetch\";\nexport { serverAPIWrapper } from \"./server/wrapper\";\nexport { getSession } from \"./server/session\";\n","export type BaseError = {\n error: string;\n message: string;\n};\n\nexport type Success<S> = {\n data: S;\n};\n\n/**\n * A Result type that represents either a successful value (Ok) or an error (Err).\n * This is a discriminated union type that helps handle errors in a type-safe way.\n *\n * @template T - The type of the successful value\n * @template E - The type of the error, must extend BaseError\n */\nexport type Result<T, E extends BaseError> = Ok<T, E> | Err<T, E>;\n\ntype IResult<T, E extends BaseError> = {\n /**\n * Checks if the `Result` is an `Ok` instance\n */\n isOk: () => this is Ok<T, E>;\n\n /**\n * Checks if the `Result` is an `Err` instance.\n */\n isErr: () => this is Err<T, E>;\n};\n\n/**\n * Represents a successful `Result` value.\n *\n * @template T - The type of the successful value.\n * @template E - The type of the error, must extend `BaseError`.\n */\nexport class Ok<T, E extends BaseError> implements IResult<T, E> {\n value: Success<T>;\n\n constructor(value: Success<T>) {\n this.value = value;\n }\n\n isOk(): this is Ok<T, E> {\n return true;\n }\n\n isErr(): this is Err<T, E> {\n return false;\n }\n}\n\n/**\n * Represents an error `Result` value.\n *\n * @template T - The type of the successful value.\n * @template E - The type of the error, must extend `BaseError`.\n */\nexport class Err<T, E extends BaseError> implements IResult<T, E> {\n error: E;\n\n constructor(error: E) {\n this.error = error;\n }\n\n isOk(): this is Ok<T, E> {\n return false;\n }\n\n isErr(): this is Err<T, E> {\n return true;\n }\n}\n\n/**\n * Creates a new successful `Result` (i.e., an instance of `Ok`).\n *\n * @template T - The type of the successful value\n * @param value - The successful value\n * @returns A new `Ok` instance.\n */\nexport function ok<const T>(value: Success<T>): Result<T, never> {\n return new Ok(value);\n}\n\n/**\n * Creates a new error `Result` (i.e., an instance of `Err`).\n *\n * @template E - The type of the error, must extend `BaseError`.\n * @param error - The error value.\n * @returns A new `Err` instance.\n */\nexport function err<const E extends BaseError>(error: E): Result<never, E> {\n return new Err(error);\n}\n","import { NextRequest } from \"next/server\";\nimport { revalidatePath } from \"next/cache\";\nimport { jwtDecode } from \"jwt-decode\";\nimport { IConfig, IRequestOptions, RouteHandler } from \"../types\";\nimport { DefaultUser, getSession } from \"./session\";\nimport { serverSideFetch, attemptTokenRefresh } from \"./fetch\";\n\nconst rHandler: RouteHandler = {\n GET: {\n user: ({ request, config }) => getUser(request, config),\n refresh: ({ request, config }) => refresh(request, config),\n logout: ({ config }) => logout(config),\n debug: () => debug(),\n oauth: ({ request, config }) => oauth(request, config),\n oauth_callback: ({ request, config }) => oauth_callback(request, config),\n proxy: ({ request, config, options }) =>\n proxyFunction(\"GET\", request, config, options),\n },\n POST: {\n login: ({ request, config }) => login(request, config),\n augment: ({ request, config }) => augment(request, config),\n proxy: ({ request, config, options }) =>\n proxyFunction(\"POST\", request, config, options),\n },\n DELETE: {\n augment: ({ request, config }) => augment(request, config),\n proxy: ({ request, config, options }) =>\n proxyFunction(\"DELETE\", request, config, options),\n },\n};\n\nexport async function Proxy(\n method: string,\n request: NextRequest,\n options: IRequestOptions,\n config: IConfig\n) {\n try {\n const params = await options.params;\n const parameters = {\n request,\n path:\n params.endpoint[0] ||\n request.nextUrl.pathname.replace(config.route, \"\"),\n options: params.endpoint,\n config,\n };\n\n if (config.debug) console.log(\"#> proxy:\", parameters);\n\n if (rHandler[method][parameters.path])\n return await rHandler[method][parameters.path](parameters);\n\n return Response.json({\n error: \"INVALID_ENDPOINT\",\n message: \"the provided endpoint is not valid\",\n });\n } catch (e) {\n console.log(\"#> proxyError:\", e);\n Response.json({\n error: \"REQUEST_ERROR\",\n message: \"error while sending request through frontend-backend proxy\",\n });\n }\n}\n\nasync function login(request: NextRequest, config: IConfig) {\n const formData = await request.json();\n const res = await serverSideFetch<{ token: string; refresh: string }>({\n method: \"POST\",\n url: \"/login\",\n body: formData,\n sessionIsOptional: true,\n config,\n });\n\n if (config.debug) console.log(\"#> login\", res);\n if (res.isErr()) {\n return Response.json(res.error);\n }\n\n const dec = jwtDecode<any>(res.value.data.token);\n\n const session = await getSession();\n session.token = {\n jwt: res.value.data.token,\n refresh: res.value.data.refresh || \"refresh_token\",\n decoded: dec,\n };\n\n await session.save();\n\n return Response.json({\n redirect: \"/\",\n });\n}\n\nasync function getUser(request: NextRequest, config: IConfig) {\n const session = await getSession();\n\n if (session.token === undefined)\n return Response.json({\n error: \"SESSION_ERROR\",\n message: \"Session is required but not found.\",\n });\n\n const force = request.nextUrl.searchParams.get(\"force\") === \"true\";\n\n // * User already exists in session\n if (session.user !== undefined && !force)\n return Response.json({\n data: session.user,\n });\n\n // * User does not exist in session\n const res = await serverSideFetch<DefaultUser>({\n url: `${config.userEndpoint}`,\n config,\n });\n\n if (config.debug) console.log(\"#> getUser\", res);\n if (res.isErr()) {\n return Response.json(res.error);\n }\n\n session.user = res.value.data;\n await session.save();\n\n return Response.json({\n data: session.user,\n });\n}\n\nasync function oauth(request: NextRequest, config: IConfig) {\n const authUrl = request.nextUrl.searchParams.get(\"authUrl\");\n const state = request.nextUrl.searchParams.get(\"state\");\n\n if (!authUrl) throw new Error(\"No authUrl provided\");\n\n const url = new URL(config.route + \"/oauth_callback\", config.host);\n if (state) url.searchParams.set(\"state\", state);\n\n const oAuthUrl = new URL(authUrl, config.apiUrl);\n oAuthUrl.searchParams.set(\"returnUrl\", url.toString());\n\n const res = await serverSideFetch({\n url: oAuthUrl.pathname + oAuthUrl.search,\n config,\n sessionIsOptional: true,\n });\n\n if (res.isErr()) {\n if (config.debug) console.log(\"#> oauthError\", res.error);\n return Response.json(res.error);\n }\n\n return Response.json(res.value);\n}\n\nasync function oauth_callback(request: NextRequest, config: IConfig) {\n const refresh = request.nextUrl.searchParams.get(\"refresh\");\n\n const token = request.nextUrl.searchParams.get(\"token\");\n if (token === null) throw new Error(\"No token provided\");\n\n const dec = jwtDecode<any>(token);\n\n const session = await getSession();\n session.token = {\n jwt: token,\n refresh: refresh || \"refresh_token\",\n decoded: dec,\n };\n\n await session.save();\n\n // redirect to return url if provided\n const state = request.nextUrl.searchParams.get(\"state\");\n if (state !== null)\n return Response.redirect(\n state.includes(\"http\") ? state : config.host + state\n );\n\n return Response.redirect(config.host);\n}\n\nasync function logout(config: IConfig) {\n const session = await getSession();\n session.destroy();\n\n revalidatePath(config.host, \"layout\");\n\n return Response.json({\n redirect: \"/\",\n });\n}\n\nasync function debug() {\n return Response.json(await getSession());\n}\n\nasync function refresh(request: NextRequest, config: IConfig) {\n const result = await attemptTokenRefresh(config);\n\n if (config.debug) console.log(\"#> refresh result\", result);\n\n if (result.isErr()) {\n return Response.json(result.error, { status: 401 });\n }\n\n const url = request.nextUrl;\n url.pathname = decodeURIComponent(url.searchParams.get(\"r\") || \"\");\n url.searchParams.delete(\"r\");\n\n return Response.redirect(url);\n}\n\nasync function proxyFunction(\n method: \"GET\" | \"POST\" | \"DELETE\",\n request: NextRequest,\n config: IConfig,\n options: string[]\n) {\n options.shift(); // remove the first element which is the endpoint\n\n // Forward custom headers (X-*) from the incoming request\n const forwardHeaders: Record<string, string> = {};\n request.headers.forEach((value, key) => {\n if (key.startsWith(\"x-\") && key !== \"x-forwarded-for\" && key !== \"x-forwarded-host\" && key !== \"x-forwarded-proto\") {\n forwardHeaders[key] = value;\n }\n });\n\n const res = await serverSideFetch({\n method,\n url: `/${options.join(\"/\")}${request.nextUrl.search}`,\n body: method === \"POST\" ? await request.json() : undefined,\n config,\n headers: forwardHeaders,\n });\n\n if (config.debug) console.log(\"#> proxyFunction\", res);\n if (res.isErr()) {\n return Response.json(res.error);\n }\n\n return Response.json(res.value);\n}\n\nasync function augment(request: NextRequest, config: IConfig) {\n const { url, method, body } = await request.json();\n\n const res = await serverSideFetch<{ token: string }>({\n method: method || \"POST\",\n url,\n body,\n config,\n });\n\n if (config.debug) console.log(\"#> augment\", res);\n if (res.isErr()) {\n return Response.json(res.error);\n }\n\n // Update iron session with the new JWT\n const session = await getSession();\n const dec = jwtDecode<any>(res.value.data.token);\n session.token = {\n jwt: res.value.data.token,\n refresh: session.token?.refresh || \"\",\n decoded: dec,\n };\n\n // Clear cached user so it gets refetched\n session.user = undefined;\n await session.save();\n\n return Response.json({ data: \"ok\" });\n}\n","import { SessionOptions } from \"iron-session\";\nimport { getIronSession } from \"iron-session\";\nimport { cookies } from \"next/headers\";\nimport { ServerSideSession } from \"../types/internal\";\nimport { Session } from \"../types\";\n\ndeclare module \"iron-session\" {\n interface IronSessionData<U, T> {\n user?: U;\n token?: {\n jwt: string;\n refresh: string;\n decoded: T;\n };\n }\n}\n\nexport interface DefaultUser {\n [key: string]: unknown;\n}\n\nexport interface Token {\n token: string;\n}\n\nexport const sessionOptions: SessionOptions = {\n password: process.env.CELESTYA_SECRET || \"PLEASE_SET_PASSWORD\",\n cookieName: process.env.CELESTYA_COOKIE_NAME || \"PLEASE_SET_COOKIE_NAME\",\n cookieOptions: { secure: process.env.SECURE === \"true\" },\n};\n\nexport const getSession = async <U = DefaultUser>(\n sessionOpts?: SessionOptions\n) => {\n if (\n sessionOpts === undefined &&\n (!process.env.CELESTYA_SECRET || !process.env.CELESTYA_COOKIE_NAME)\n ) {\n throw new Error(\n \"CELESTYA_SECRET and CELESTYA_COOKIE_NAME must be set in environment variables.\"\n );\n }\n\n const session: Session<U> = await getIronSession<ServerSideSession<U>>(\n await cookies(),\n sessionOpts || sessionOptions\n );\n\n return session;\n};\n","import { cookies } from \"next/headers\";\nimport { IConfig } from \"../types\";\nimport { BaseError, err, ok, Result, Success } from \"../types/response\";\nimport { getSession } from \"./session\";\n\n// Global refresh lock to prevent multiple simultaneous refresh attempts\nlet refreshPromise: Promise<Result<string, BaseError>> | null = null;\n\nexport const serverSideFetch = async <T>({\n url,\n method = \"GET\",\n config,\n body,\n sessionIsOptional = false,\n skipRefresh = false,\n ...options\n}: {\n url: string;\n method?: \"GET\" | \"POST\" | \"DELETE\";\n body?: object;\n config: IConfig;\n sessionIsOptional?: boolean;\n skipRefresh?: boolean;\n} & Omit<RequestInit, \"body\" | \"method\">): Promise<Result<T, BaseError>> => {\n const headers = new Headers({\n \"Content-Type\": \"application/json\",\n ...(options.headers as Record<string, string>),\n });\n\n // Forward configured cookies as headers (for SSR)\n if (config.cookieHeaders) {\n try {\n const cookieStore = await cookies();\n for (const [cookieName, headerName] of Object.entries(\n config.cookieHeaders\n )) {\n // Don't overwrite if header was already passed explicitly\n if (headers.has(headerName)) continue;\n const value = cookieStore.get(cookieName)?.value;\n if (value) headers.set(headerName, value);\n }\n } catch (e) {\n // cookies() throws outside of request context — safe to ignore\n if (config.debug)\n console.log(\"#> cookieHeaders: cookies() unavailable\", e);\n }\n }\n\n const session = await getSession();\n\n if (session.token !== undefined) {\n headers.set(\"Authorization\", `Bearer ${session.token.jwt}`);\n } else if (!sessionIsOptional) {\n return err({\n error: \"SESSION_ERROR\",\n message: \"Session is required but not found.\",\n });\n }\n\n const opts: RequestInit = {\n method,\n ...options,\n headers,\n };\n\n try {\n if (body) opts.body = JSON.stringify(body);\n } catch (e) {\n console.log(\"Error stringifying body: \", e);\n }\n\n try {\n const response: Response = await fetch(`${config.apiUrl}${url}`, opts);\n\n // Handle 401 Unauthorized - try to refresh token\n if (response.status === 401 && !skipRefresh && !sessionIsOptional) {\n if (config.debug)\n console.log(\"#> 401 detected, attempting token refresh\");\n\n // Local reference to the refresh promise to prevent race conditions\n let currentRefresh: Promise<Result<string, BaseError>>;\n\n // Check if refresh is already in progress\n if (refreshPromise === null) {\n // Start new refresh process\n refreshPromise = attemptTokenRefresh(config).finally(() => {\n // Clear the lock when done (success or failure)\n refreshPromise = null;\n });\n currentRefresh = refreshPromise;\n } else {\n if (config.debug)\n console.log(\"#> Refresh already in progress, waiting...\");\n currentRefresh = refreshPromise;\n }\n\n // Wait for the refresh to complete (whether we started it or not)\n const refreshResult = await currentRefresh;\n\n if (refreshResult.isOk()) {\n // Retry the original request with refreshed token\n return serverSideFetch<T>({\n url,\n method,\n config,\n body,\n sessionIsOptional,\n skipRefresh: true, // Prevent infinite loop\n ...options,\n });\n }\n\n // Refresh failed, return the error\n return err(refreshResult.error);\n }\n\n if (!response.ok) {\n return err({\n error: \"RESPONSE_ERROR\",\n message: `HTTP error! status: ${response.status}`,\n });\n }\n\n try {\n const res = await response.json();\n if (res.error !== undefined) {\n return err(res);\n }\n\n return ok(res as Success<T>);\n } catch (e) {\n return err({\n error: \"PARSE_ERROR\",\n message: \"Failed to parse response as JSON\",\n });\n }\n } catch (e) {\n return err({\n error: \"FETCH_ERROR\",\n message: \"Failed to fetch the resource: \" + String(e),\n });\n }\n};\n\nexport async function attemptTokenRefresh(\n config: IConfig\n): Promise<Result<string, BaseError>> {\n if (config.debug) console.log(\"#> attemptTokenRefresh called\");\n\n const { jwtDecode } = await import(\"jwt-decode\");\n const session = await getSession();\n\n if (!session.token?.refresh) {\n return err({\n error: \"NO_REFRESH_TOKEN\",\n message: \"No refresh token available in session\",\n });\n }\n\n const res = await serverSideFetch<{ token: string }>({\n method: \"POST\",\n url: \"/refresh\",\n body: {\n refreshToken: session.token.refresh,\n },\n sessionIsOptional: true,\n skipRefresh: true, // Prevent infinite loop\n config,\n });\n\n if (config.debug) console.log(\"#> attemptTokenRefresh\", res);\n if (res.isErr()) {\n // Refresh token is invalid or expired, destroy session\n session.destroy();\n return err(res.error);\n }\n\n // Update session with new JWT\n const decoded = jwtDecode<any>(res.value.data.token);\n const newToken = {\n jwt: res.value.data.token,\n refresh: session.token.refresh, // Keep the same refresh token\n decoded,\n };\n\n session.token = newToken;\n\n await session.save();\n\n return ok({ data: \"success\" });\n}\n","import { NextRequest } from \"next/server\";\nimport { IConfig, IRequestOptions } from \"../types\";\nimport { Proxy } from \"./api\";\n\nexport const CelestyaProxy = (config: IConfig) => {\n return {\n POST: (req: NextRequest, opt: IRequestOptions) =>\n Proxy(\"POST\", req, opt, config),\n GET: (req: NextRequest, opt: IRequestOptions) =>\n Proxy(\"GET\", req, opt, config),\n DELETE: (req: NextRequest, opt: IRequestOptions) =>\n Proxy(\"DELETE\", req, opt, config),\n };\n};\n","import { CallbackOptions, IConfig, WrapperFunction } from \"../types\";\nimport { serverSideFetch } from \"./fetch\";\n\n/**\n * Register new Wrapper for the API.\n *\n * Example Wrapper:\n * ```ts\n * const apiWrapper = (cb: WrapperFunction) => {\n * return {\n * commmands: {\n * get: () => cb<string>({ method: \"GET\", url: \"/command\" }),\n * update: (id: string, body: JSON) =>\n * cb({ method: \"POST\", url: `/command/${id}`, body }),\n * },\n * };\n * };\n * ````\n * @param apiWrapper\n * @param config\n * @returns\n */\nexport const serverAPIWrapper = <T>(\n apiWrapper: (cb: WrapperFunction) => T,\n config: IConfig\n) => {\n return apiWrapper(async (data: CallbackOptions) => {\n const { method, url, body } = data;\n\n return serverSideFetch({\n url,\n method,\n body,\n config,\n });\n });\n};\n"],"mappings":"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","names":["import_headers","jwtDecode","Proxy","refresh","Proxy"]}
package/dist/index.mjs CHANGED
@@ -54,6 +54,7 @@ var getSession = async (sessionOpts) => {
54
54
  };
55
55
 
56
56
  // src/server/fetch.ts
57
+ import { cookies as cookies2 } from "next/headers";
57
58
  var refreshPromise = null;
58
59
  var serverSideFetch = async ({
59
60
  url,
@@ -64,10 +65,26 @@ var serverSideFetch = async ({
64
65
  skipRefresh = false,
65
66
  ...options
66
67
  }) => {
68
+ var _a;
67
69
  const headers = new Headers({
68
70
  "Content-Type": "application/json",
69
71
  ...options.headers
70
72
  });
73
+ if (config.cookieHeaders) {
74
+ try {
75
+ const cookieStore = await cookies2();
76
+ for (const [cookieName, headerName] of Object.entries(
77
+ config.cookieHeaders
78
+ )) {
79
+ if (headers.has(headerName)) continue;
80
+ const value = (_a = cookieStore.get(cookieName)) == null ? void 0 : _a.value;
81
+ if (value) headers.set(headerName, value);
82
+ }
83
+ } catch (e) {
84
+ if (config.debug)
85
+ console.log("#> cookieHeaders: cookies() unavailable", e);
86
+ }
87
+ }
71
88
  const session = await getSession();
72
89
  if (session.token !== void 0) {
73
90
  headers.set("Authorization", `Bearer ${session.token.jwt}`);
@@ -195,9 +212,11 @@ var rHandler = {
195
212
  },
196
213
  POST: {
197
214
  login: ({ request, config }) => login(request, config),
215
+ augment: ({ request, config }) => augment(request, config),
198
216
  proxy: ({ request, config, options }) => proxyFunction("POST", request, config, options)
199
217
  },
200
218
  DELETE: {
219
+ augment: ({ request, config }) => augment(request, config),
201
220
  proxy: ({ request, config, options }) => proxyFunction("DELETE", request, config, options)
202
221
  }
203
222
  };
@@ -357,6 +376,30 @@ async function proxyFunction(method, request, config, options) {
357
376
  }
358
377
  return Response.json(res.value);
359
378
  }
379
+ async function augment(request, config) {
380
+ var _a;
381
+ const { url, method, body } = await request.json();
382
+ const res = await serverSideFetch({
383
+ method: method || "POST",
384
+ url,
385
+ body,
386
+ config
387
+ });
388
+ if (config.debug) console.log("#> augment", res);
389
+ if (res.isErr()) {
390
+ return Response.json(res.error);
391
+ }
392
+ const session = await getSession();
393
+ const dec = jwtDecode(res.value.data.token);
394
+ session.token = {
395
+ jwt: res.value.data.token,
396
+ refresh: ((_a = session.token) == null ? void 0 : _a.refresh) || "",
397
+ decoded: dec
398
+ };
399
+ session.user = void 0;
400
+ await session.save();
401
+ return Response.json({ data: "ok" });
402
+ }
360
403
 
361
404
  // src/server/index.ts
362
405
  var CelestyaProxy = (config) => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types/response.ts","../src/server/api.ts","../src/server/session.ts","../src/server/fetch.ts","../src/server/index.ts","../src/server/wrapper.ts"],"sourcesContent":["export type BaseError = {\n error: string;\n message: string;\n};\n\nexport type Success<S> = {\n data: S;\n};\n\n/**\n * A Result type that represents either a successful value (Ok) or an error (Err).\n * This is a discriminated union type that helps handle errors in a type-safe way.\n *\n * @template T - The type of the successful value\n * @template E - The type of the error, must extend BaseError\n */\nexport type Result<T, E extends BaseError> = Ok<T, E> | Err<T, E>;\n\ntype IResult<T, E extends BaseError> = {\n /**\n * Checks if the `Result` is an `Ok` instance\n */\n isOk: () => this is Ok<T, E>;\n\n /**\n * Checks if the `Result` is an `Err` instance.\n */\n isErr: () => this is Err<T, E>;\n};\n\n/**\n * Represents a successful `Result` value.\n *\n * @template T - The type of the successful value.\n * @template E - The type of the error, must extend `BaseError`.\n */\nexport class Ok<T, E extends BaseError> implements IResult<T, E> {\n value: Success<T>;\n\n constructor(value: Success<T>) {\n this.value = value;\n }\n\n isOk(): this is Ok<T, E> {\n return true;\n }\n\n isErr(): this is Err<T, E> {\n return false;\n }\n}\n\n/**\n * Represents an error `Result` value.\n *\n * @template T - The type of the successful value.\n * @template E - The type of the error, must extend `BaseError`.\n */\nexport class Err<T, E extends BaseError> implements IResult<T, E> {\n error: E;\n\n constructor(error: E) {\n this.error = error;\n }\n\n isOk(): this is Ok<T, E> {\n return false;\n }\n\n isErr(): this is Err<T, E> {\n return true;\n }\n}\n\n/**\n * Creates a new successful `Result` (i.e., an instance of `Ok`).\n *\n * @template T - The type of the successful value\n * @param value - The successful value\n * @returns A new `Ok` instance.\n */\nexport function ok<const T>(value: Success<T>): Result<T, never> {\n return new Ok(value);\n}\n\n/**\n * Creates a new error `Result` (i.e., an instance of `Err`).\n *\n * @template E - The type of the error, must extend `BaseError`.\n * @param error - The error value.\n * @returns A new `Err` instance.\n */\nexport function err<const E extends BaseError>(error: E): Result<never, E> {\n return new Err(error);\n}\n","import { NextRequest } from \"next/server\";\nimport { revalidatePath } from \"next/cache\";\nimport { jwtDecode } from \"jwt-decode\";\nimport { IConfig, IRequestOptions, RouteHandler } from \"../types\";\nimport { DefaultUser, getSession } from \"./session\";\nimport { serverSideFetch, attemptTokenRefresh } from \"./fetch\";\n\nconst rHandler: RouteHandler = {\n GET: {\n user: ({ request, config }) => getUser(request, config),\n refresh: ({ request, config }) => refresh(request, config),\n logout: ({ config }) => logout(config),\n debug: () => debug(),\n oauth: ({ request, config }) => oauth(request, config),\n oauth_callback: ({ request, config }) => oauth_callback(request, config),\n proxy: ({ request, config, options }) =>\n proxyFunction(\"GET\", request, config, options),\n },\n POST: {\n login: ({ request, config }) => login(request, config),\n proxy: ({ request, config, options }) =>\n proxyFunction(\"POST\", request, config, options),\n },\n DELETE: {\n proxy: ({ request, config, options }) =>\n proxyFunction(\"DELETE\", request, config, options),\n },\n};\n\nexport async function Proxy(\n method: string,\n request: NextRequest,\n options: IRequestOptions,\n config: IConfig\n) {\n try {\n const params = await options.params;\n const parameters = {\n request,\n path:\n params.endpoint[0] ||\n request.nextUrl.pathname.replace(config.route, \"\"),\n options: params.endpoint,\n config,\n };\n\n if (config.debug) console.log(\"#> proxy:\", parameters);\n\n if (rHandler[method][parameters.path])\n return await rHandler[method][parameters.path](parameters);\n\n return Response.json({\n error: \"INVALID_ENDPOINT\",\n message: \"the provided endpoint is not valid\",\n });\n } catch (e) {\n console.log(\"#> proxyError:\", e);\n Response.json({\n error: \"REQUEST_ERROR\",\n message: \"error while sending request through frontend-backend proxy\",\n });\n }\n}\n\nasync function login(request: NextRequest, config: IConfig) {\n const formData = await request.json();\n const res = await serverSideFetch<{ token: string; refresh: string }>({\n method: \"POST\",\n url: \"/login\",\n body: formData,\n sessionIsOptional: true,\n config,\n });\n\n if (config.debug) console.log(\"#> login\", res);\n if (res.isErr()) {\n return Response.json(res.error);\n }\n\n const dec = jwtDecode<any>(res.value.data.token);\n\n const session = await getSession();\n session.token = {\n jwt: res.value.data.token,\n refresh: res.value.data.refresh || \"refresh_token\",\n decoded: dec,\n };\n\n await session.save();\n\n return Response.json({\n redirect: \"/\",\n });\n}\n\nasync function getUser(request: NextRequest, config: IConfig) {\n const session = await getSession();\n\n if (session.token === undefined)\n return Response.json({\n error: \"SESSION_ERROR\",\n message: \"Session is required but not found.\",\n });\n\n const force = request.nextUrl.searchParams.get(\"force\") === \"true\";\n\n // * User already exists in session\n if (session.user !== undefined && !force)\n return Response.json({\n data: session.user,\n });\n\n // * User does not exist in session\n const res = await serverSideFetch<DefaultUser>({\n url: `${config.userEndpoint}`,\n config,\n });\n\n if (config.debug) console.log(\"#> getUser\", res);\n if (res.isErr()) {\n return Response.json(res.error);\n }\n\n session.user = res.value.data;\n await session.save();\n\n return Response.json({\n data: session.user,\n });\n}\n\nasync function oauth(request: NextRequest, config: IConfig) {\n const authUrl = request.nextUrl.searchParams.get(\"authUrl\");\n const state = request.nextUrl.searchParams.get(\"state\");\n\n if (!authUrl) throw new Error(\"No authUrl provided\");\n\n const url = new URL(config.route + \"/oauth_callback\", config.host);\n if (state) url.searchParams.set(\"state\", state);\n\n const oAuthUrl = new URL(authUrl, config.apiUrl);\n oAuthUrl.searchParams.set(\"returnUrl\", url.toString());\n\n const res = await serverSideFetch({\n url: oAuthUrl.pathname + oAuthUrl.search,\n config,\n sessionIsOptional: true,\n });\n\n if (res.isErr()) {\n if (config.debug) console.log(\"#> oauthError\", res.error);\n return Response.json(res.error);\n }\n\n return Response.json(res.value);\n}\n\nasync function oauth_callback(request: NextRequest, config: IConfig) {\n const refresh = request.nextUrl.searchParams.get(\"refresh\");\n\n const token = request.nextUrl.searchParams.get(\"token\");\n if (token === null) throw new Error(\"No token provided\");\n\n const dec = jwtDecode<any>(token);\n\n const session = await getSession();\n session.token = {\n jwt: token,\n refresh: refresh || \"refresh_token\",\n decoded: dec,\n };\n\n await session.save();\n\n // redirect to return url if provided\n const state = request.nextUrl.searchParams.get(\"state\");\n if (state !== null)\n return Response.redirect(\n state.includes(\"http\") ? state : config.host + state\n );\n\n return Response.redirect(config.host);\n}\n\nasync function logout(config: IConfig) {\n const session = await getSession();\n session.destroy();\n\n revalidatePath(config.host, \"layout\");\n\n return Response.json({\n redirect: \"/\",\n });\n}\n\nasync function debug() {\n return Response.json(await getSession());\n}\n\nasync function refresh(request: NextRequest, config: IConfig) {\n const result = await attemptTokenRefresh(config);\n\n if (config.debug) console.log(\"#> refresh result\", result);\n\n if (result.isErr()) {\n return Response.json(result.error, { status: 401 });\n }\n\n const url = request.nextUrl;\n url.pathname = decodeURIComponent(url.searchParams.get(\"r\") || \"\");\n url.searchParams.delete(\"r\");\n\n return Response.redirect(url);\n}\n\nasync function proxyFunction(\n method: \"GET\" | \"POST\" | \"DELETE\",\n request: NextRequest,\n config: IConfig,\n options: string[]\n) {\n options.shift(); // remove the first element which is the endpoint\n\n // Forward custom headers (X-*) from the incoming request\n const forwardHeaders: Record<string, string> = {};\n request.headers.forEach((value, key) => {\n if (key.startsWith(\"x-\") && key !== \"x-forwarded-for\" && key !== \"x-forwarded-host\" && key !== \"x-forwarded-proto\") {\n forwardHeaders[key] = value;\n }\n });\n\n const res = await serverSideFetch({\n method,\n url: `/${options.join(\"/\")}${request.nextUrl.search}`,\n body: method === \"POST\" ? await request.json() : undefined,\n config,\n headers: forwardHeaders,\n });\n\n if (config.debug) console.log(\"#> proxyFunction\", res);\n if (res.isErr()) {\n return Response.json(res.error);\n }\n\n return Response.json(res.value);\n}\n","import { SessionOptions } from \"iron-session\";\nimport { getIronSession } from \"iron-session\";\nimport { cookies } from \"next/headers\";\nimport { ServerSideSession } from \"../types/internal\";\nimport { Session } from \"../types\";\n\ndeclare module \"iron-session\" {\n interface IronSessionData<U, T> {\n user?: U;\n token?: {\n jwt: string;\n refresh: string;\n decoded: T;\n };\n }\n}\n\nexport interface DefaultUser {\n [key: string]: unknown;\n}\n\nexport interface Token {\n token: string;\n}\n\nexport const sessionOptions: SessionOptions = {\n password: process.env.CELESTYA_SECRET || \"PLEASE_SET_PASSWORD\",\n cookieName: process.env.CELESTYA_COOKIE_NAME || \"PLEASE_SET_COOKIE_NAME\",\n cookieOptions: { secure: process.env.SECURE === \"true\" },\n};\n\nexport const getSession = async <U = DefaultUser>(\n sessionOpts?: SessionOptions\n) => {\n if (\n sessionOpts === undefined &&\n (!process.env.CELESTYA_SECRET || !process.env.CELESTYA_COOKIE_NAME)\n ) {\n throw new Error(\n \"CELESTYA_SECRET and CELESTYA_COOKIE_NAME must be set in environment variables.\"\n );\n }\n\n const session: Session<U> = await getIronSession<ServerSideSession<U>>(\n await cookies(),\n sessionOpts || sessionOptions\n );\n\n return session;\n};\n","import { IConfig } from \"../types\";\nimport { BaseError, err, ok, Result, Success } from \"../types/response\";\nimport { getSession } from \"./session\";\n\n// Global refresh lock to prevent multiple simultaneous refresh attempts\nlet refreshPromise: Promise<Result<string, BaseError>> | null = null;\n\nexport const serverSideFetch = async <T>({\n url,\n method = \"GET\",\n config,\n body,\n sessionIsOptional = false,\n skipRefresh = false,\n ...options\n}: {\n url: string;\n method?: \"GET\" | \"POST\" | \"DELETE\";\n body?: object;\n config: IConfig;\n sessionIsOptional?: boolean;\n skipRefresh?: boolean;\n} & Omit<RequestInit, \"body\" | \"method\">): Promise<Result<T, BaseError>> => {\n const headers = new Headers({\n \"Content-Type\": \"application/json\",\n ...(options.headers as Record<string, string>),\n });\n\n const session = await getSession();\n\n if (session.token !== undefined) {\n headers.set(\"Authorization\", `Bearer ${session.token.jwt}`);\n } else if (!sessionIsOptional) {\n return err({\n error: \"SESSION_ERROR\",\n message: \"Session is required but not found.\",\n });\n }\n\n const opts: RequestInit = {\n method,\n ...options,\n headers,\n };\n\n try {\n if (body) opts.body = JSON.stringify(body);\n } catch (e) {\n console.log(\"Error stringifying body: \", e);\n }\n\n try {\n const response: Response = await fetch(`${config.apiUrl}${url}`, opts);\n\n // Handle 401 Unauthorized - try to refresh token\n if (response.status === 401 && !skipRefresh && !sessionIsOptional) {\n if (config.debug)\n console.log(\"#> 401 detected, attempting token refresh\");\n\n // Local reference to the refresh promise to prevent race conditions\n let currentRefresh: Promise<Result<string, BaseError>>;\n\n // Check if refresh is already in progress\n if (refreshPromise === null) {\n // Start new refresh process\n refreshPromise = attemptTokenRefresh(config).finally(() => {\n // Clear the lock when done (success or failure)\n refreshPromise = null;\n });\n currentRefresh = refreshPromise;\n } else {\n if (config.debug)\n console.log(\"#> Refresh already in progress, waiting...\");\n currentRefresh = refreshPromise;\n }\n\n // Wait for the refresh to complete (whether we started it or not)\n const refreshResult = await currentRefresh;\n\n if (refreshResult.isOk()) {\n // Retry the original request with refreshed token\n return serverSideFetch<T>({\n url,\n method,\n config,\n body,\n sessionIsOptional,\n skipRefresh: true, // Prevent infinite loop\n ...options,\n });\n }\n\n // Refresh failed, return the error\n return err(refreshResult.error);\n }\n\n if (!response.ok) {\n return err({\n error: \"RESPONSE_ERROR\",\n message: `HTTP error! status: ${response.status}`,\n });\n }\n\n try {\n const res = await response.json();\n if (res.error !== undefined) {\n return err(res);\n }\n\n return ok(res as Success<T>);\n } catch (e) {\n return err({\n error: \"PARSE_ERROR\",\n message: \"Failed to parse response as JSON\",\n });\n }\n } catch (e) {\n return err({\n error: \"FETCH_ERROR\",\n message: \"Failed to fetch the resource: \" + String(e),\n });\n }\n};\n\nexport async function attemptTokenRefresh(\n config: IConfig\n): Promise<Result<string, BaseError>> {\n if (config.debug) console.log(\"#> attemptTokenRefresh called\");\n\n const { jwtDecode } = await import(\"jwt-decode\");\n const session = await getSession();\n\n if (!session.token?.refresh) {\n return err({\n error: \"NO_REFRESH_TOKEN\",\n message: \"No refresh token available in session\",\n });\n }\n\n const res = await serverSideFetch<{ token: string }>({\n method: \"POST\",\n url: \"/refresh\",\n body: {\n refreshToken: session.token.refresh,\n },\n sessionIsOptional: true,\n skipRefresh: true, // Prevent infinite loop\n config,\n });\n\n if (config.debug) console.log(\"#> attemptTokenRefresh\", res);\n if (res.isErr()) {\n // Refresh token is invalid or expired, destroy session\n session.destroy();\n return err(res.error);\n }\n\n // Update session with new JWT\n const decoded = jwtDecode<any>(res.value.data.token);\n const newToken = {\n jwt: res.value.data.token,\n refresh: session.token.refresh, // Keep the same refresh token\n decoded,\n };\n\n session.token = newToken;\n\n await session.save();\n\n return ok({ data: \"success\" });\n}\n","import { NextRequest } from \"next/server\";\nimport { IConfig, IRequestOptions } from \"../types\";\nimport { Proxy } from \"./api\";\n\nexport const CelestyaProxy = (config: IConfig) => {\n return {\n POST: (req: NextRequest, opt: IRequestOptions) =>\n Proxy(\"POST\", req, opt, config),\n GET: (req: NextRequest, opt: IRequestOptions) =>\n Proxy(\"GET\", req, opt, config),\n DELETE: (req: NextRequest, opt: IRequestOptions) =>\n Proxy(\"DELETE\", req, opt, config),\n };\n};\n","import { CallbackOptions, IConfig, WrapperFunction } from \"../types\";\nimport { serverSideFetch } from \"./fetch\";\n\n/**\n * Register new Wrapper for the API.\n *\n * Example Wrapper:\n * ```ts\n * const apiWrapper = (cb: WrapperFunction) => {\n * return {\n * commmands: {\n * get: () => cb<string>({ method: \"GET\", url: \"/command\" }),\n * update: (id: string, body: JSON) =>\n * cb({ method: \"POST\", url: `/command/${id}`, body }),\n * },\n * };\n * };\n * ````\n * @param apiWrapper\n * @param config\n * @returns\n */\nexport const serverAPIWrapper = <T>(\n apiWrapper: (cb: WrapperFunction) => T,\n config: IConfig\n) => {\n return apiWrapper(async (data: CallbackOptions) => {\n const { method, url, body } = data;\n\n return serverSideFetch({\n url,\n method,\n body,\n config,\n });\n });\n};\n"],"mappings":"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","names":["jwtDecode","refresh"]}
1
+ {"version":3,"sources":["../src/types/response.ts","../src/server/api.ts","../src/server/session.ts","../src/server/fetch.ts","../src/server/index.ts","../src/server/wrapper.ts"],"sourcesContent":["export type BaseError = {\n error: string;\n message: string;\n};\n\nexport type Success<S> = {\n data: S;\n};\n\n/**\n * A Result type that represents either a successful value (Ok) or an error (Err).\n * This is a discriminated union type that helps handle errors in a type-safe way.\n *\n * @template T - The type of the successful value\n * @template E - The type of the error, must extend BaseError\n */\nexport type Result<T, E extends BaseError> = Ok<T, E> | Err<T, E>;\n\ntype IResult<T, E extends BaseError> = {\n /**\n * Checks if the `Result` is an `Ok` instance\n */\n isOk: () => this is Ok<T, E>;\n\n /**\n * Checks if the `Result` is an `Err` instance.\n */\n isErr: () => this is Err<T, E>;\n};\n\n/**\n * Represents a successful `Result` value.\n *\n * @template T - The type of the successful value.\n * @template E - The type of the error, must extend `BaseError`.\n */\nexport class Ok<T, E extends BaseError> implements IResult<T, E> {\n value: Success<T>;\n\n constructor(value: Success<T>) {\n this.value = value;\n }\n\n isOk(): this is Ok<T, E> {\n return true;\n }\n\n isErr(): this is Err<T, E> {\n return false;\n }\n}\n\n/**\n * Represents an error `Result` value.\n *\n * @template T - The type of the successful value.\n * @template E - The type of the error, must extend `BaseError`.\n */\nexport class Err<T, E extends BaseError> implements IResult<T, E> {\n error: E;\n\n constructor(error: E) {\n this.error = error;\n }\n\n isOk(): this is Ok<T, E> {\n return false;\n }\n\n isErr(): this is Err<T, E> {\n return true;\n }\n}\n\n/**\n * Creates a new successful `Result` (i.e., an instance of `Ok`).\n *\n * @template T - The type of the successful value\n * @param value - The successful value\n * @returns A new `Ok` instance.\n */\nexport function ok<const T>(value: Success<T>): Result<T, never> {\n return new Ok(value);\n}\n\n/**\n * Creates a new error `Result` (i.e., an instance of `Err`).\n *\n * @template E - The type of the error, must extend `BaseError`.\n * @param error - The error value.\n * @returns A new `Err` instance.\n */\nexport function err<const E extends BaseError>(error: E): Result<never, E> {\n return new Err(error);\n}\n","import { NextRequest } from \"next/server\";\nimport { revalidatePath } from \"next/cache\";\nimport { jwtDecode } from \"jwt-decode\";\nimport { IConfig, IRequestOptions, RouteHandler } from \"../types\";\nimport { DefaultUser, getSession } from \"./session\";\nimport { serverSideFetch, attemptTokenRefresh } from \"./fetch\";\n\nconst rHandler: RouteHandler = {\n GET: {\n user: ({ request, config }) => getUser(request, config),\n refresh: ({ request, config }) => refresh(request, config),\n logout: ({ config }) => logout(config),\n debug: () => debug(),\n oauth: ({ request, config }) => oauth(request, config),\n oauth_callback: ({ request, config }) => oauth_callback(request, config),\n proxy: ({ request, config, options }) =>\n proxyFunction(\"GET\", request, config, options),\n },\n POST: {\n login: ({ request, config }) => login(request, config),\n augment: ({ request, config }) => augment(request, config),\n proxy: ({ request, config, options }) =>\n proxyFunction(\"POST\", request, config, options),\n },\n DELETE: {\n augment: ({ request, config }) => augment(request, config),\n proxy: ({ request, config, options }) =>\n proxyFunction(\"DELETE\", request, config, options),\n },\n};\n\nexport async function Proxy(\n method: string,\n request: NextRequest,\n options: IRequestOptions,\n config: IConfig\n) {\n try {\n const params = await options.params;\n const parameters = {\n request,\n path:\n params.endpoint[0] ||\n request.nextUrl.pathname.replace(config.route, \"\"),\n options: params.endpoint,\n config,\n };\n\n if (config.debug) console.log(\"#> proxy:\", parameters);\n\n if (rHandler[method][parameters.path])\n return await rHandler[method][parameters.path](parameters);\n\n return Response.json({\n error: \"INVALID_ENDPOINT\",\n message: \"the provided endpoint is not valid\",\n });\n } catch (e) {\n console.log(\"#> proxyError:\", e);\n Response.json({\n error: \"REQUEST_ERROR\",\n message: \"error while sending request through frontend-backend proxy\",\n });\n }\n}\n\nasync function login(request: NextRequest, config: IConfig) {\n const formData = await request.json();\n const res = await serverSideFetch<{ token: string; refresh: string }>({\n method: \"POST\",\n url: \"/login\",\n body: formData,\n sessionIsOptional: true,\n config,\n });\n\n if (config.debug) console.log(\"#> login\", res);\n if (res.isErr()) {\n return Response.json(res.error);\n }\n\n const dec = jwtDecode<any>(res.value.data.token);\n\n const session = await getSession();\n session.token = {\n jwt: res.value.data.token,\n refresh: res.value.data.refresh || \"refresh_token\",\n decoded: dec,\n };\n\n await session.save();\n\n return Response.json({\n redirect: \"/\",\n });\n}\n\nasync function getUser(request: NextRequest, config: IConfig) {\n const session = await getSession();\n\n if (session.token === undefined)\n return Response.json({\n error: \"SESSION_ERROR\",\n message: \"Session is required but not found.\",\n });\n\n const force = request.nextUrl.searchParams.get(\"force\") === \"true\";\n\n // * User already exists in session\n if (session.user !== undefined && !force)\n return Response.json({\n data: session.user,\n });\n\n // * User does not exist in session\n const res = await serverSideFetch<DefaultUser>({\n url: `${config.userEndpoint}`,\n config,\n });\n\n if (config.debug) console.log(\"#> getUser\", res);\n if (res.isErr()) {\n return Response.json(res.error);\n }\n\n session.user = res.value.data;\n await session.save();\n\n return Response.json({\n data: session.user,\n });\n}\n\nasync function oauth(request: NextRequest, config: IConfig) {\n const authUrl = request.nextUrl.searchParams.get(\"authUrl\");\n const state = request.nextUrl.searchParams.get(\"state\");\n\n if (!authUrl) throw new Error(\"No authUrl provided\");\n\n const url = new URL(config.route + \"/oauth_callback\", config.host);\n if (state) url.searchParams.set(\"state\", state);\n\n const oAuthUrl = new URL(authUrl, config.apiUrl);\n oAuthUrl.searchParams.set(\"returnUrl\", url.toString());\n\n const res = await serverSideFetch({\n url: oAuthUrl.pathname + oAuthUrl.search,\n config,\n sessionIsOptional: true,\n });\n\n if (res.isErr()) {\n if (config.debug) console.log(\"#> oauthError\", res.error);\n return Response.json(res.error);\n }\n\n return Response.json(res.value);\n}\n\nasync function oauth_callback(request: NextRequest, config: IConfig) {\n const refresh = request.nextUrl.searchParams.get(\"refresh\");\n\n const token = request.nextUrl.searchParams.get(\"token\");\n if (token === null) throw new Error(\"No token provided\");\n\n const dec = jwtDecode<any>(token);\n\n const session = await getSession();\n session.token = {\n jwt: token,\n refresh: refresh || \"refresh_token\",\n decoded: dec,\n };\n\n await session.save();\n\n // redirect to return url if provided\n const state = request.nextUrl.searchParams.get(\"state\");\n if (state !== null)\n return Response.redirect(\n state.includes(\"http\") ? state : config.host + state\n );\n\n return Response.redirect(config.host);\n}\n\nasync function logout(config: IConfig) {\n const session = await getSession();\n session.destroy();\n\n revalidatePath(config.host, \"layout\");\n\n return Response.json({\n redirect: \"/\",\n });\n}\n\nasync function debug() {\n return Response.json(await getSession());\n}\n\nasync function refresh(request: NextRequest, config: IConfig) {\n const result = await attemptTokenRefresh(config);\n\n if (config.debug) console.log(\"#> refresh result\", result);\n\n if (result.isErr()) {\n return Response.json(result.error, { status: 401 });\n }\n\n const url = request.nextUrl;\n url.pathname = decodeURIComponent(url.searchParams.get(\"r\") || \"\");\n url.searchParams.delete(\"r\");\n\n return Response.redirect(url);\n}\n\nasync function proxyFunction(\n method: \"GET\" | \"POST\" | \"DELETE\",\n request: NextRequest,\n config: IConfig,\n options: string[]\n) {\n options.shift(); // remove the first element which is the endpoint\n\n // Forward custom headers (X-*) from the incoming request\n const forwardHeaders: Record<string, string> = {};\n request.headers.forEach((value, key) => {\n if (key.startsWith(\"x-\") && key !== \"x-forwarded-for\" && key !== \"x-forwarded-host\" && key !== \"x-forwarded-proto\") {\n forwardHeaders[key] = value;\n }\n });\n\n const res = await serverSideFetch({\n method,\n url: `/${options.join(\"/\")}${request.nextUrl.search}`,\n body: method === \"POST\" ? await request.json() : undefined,\n config,\n headers: forwardHeaders,\n });\n\n if (config.debug) console.log(\"#> proxyFunction\", res);\n if (res.isErr()) {\n return Response.json(res.error);\n }\n\n return Response.json(res.value);\n}\n\nasync function augment(request: NextRequest, config: IConfig) {\n const { url, method, body } = await request.json();\n\n const res = await serverSideFetch<{ token: string }>({\n method: method || \"POST\",\n url,\n body,\n config,\n });\n\n if (config.debug) console.log(\"#> augment\", res);\n if (res.isErr()) {\n return Response.json(res.error);\n }\n\n // Update iron session with the new JWT\n const session = await getSession();\n const dec = jwtDecode<any>(res.value.data.token);\n session.token = {\n jwt: res.value.data.token,\n refresh: session.token?.refresh || \"\",\n decoded: dec,\n };\n\n // Clear cached user so it gets refetched\n session.user = undefined;\n await session.save();\n\n return Response.json({ data: \"ok\" });\n}\n","import { SessionOptions } from \"iron-session\";\nimport { getIronSession } from \"iron-session\";\nimport { cookies } from \"next/headers\";\nimport { ServerSideSession } from \"../types/internal\";\nimport { Session } from \"../types\";\n\ndeclare module \"iron-session\" {\n interface IronSessionData<U, T> {\n user?: U;\n token?: {\n jwt: string;\n refresh: string;\n decoded: T;\n };\n }\n}\n\nexport interface DefaultUser {\n [key: string]: unknown;\n}\n\nexport interface Token {\n token: string;\n}\n\nexport const sessionOptions: SessionOptions = {\n password: process.env.CELESTYA_SECRET || \"PLEASE_SET_PASSWORD\",\n cookieName: process.env.CELESTYA_COOKIE_NAME || \"PLEASE_SET_COOKIE_NAME\",\n cookieOptions: { secure: process.env.SECURE === \"true\" },\n};\n\nexport const getSession = async <U = DefaultUser>(\n sessionOpts?: SessionOptions\n) => {\n if (\n sessionOpts === undefined &&\n (!process.env.CELESTYA_SECRET || !process.env.CELESTYA_COOKIE_NAME)\n ) {\n throw new Error(\n \"CELESTYA_SECRET and CELESTYA_COOKIE_NAME must be set in environment variables.\"\n );\n }\n\n const session: Session<U> = await getIronSession<ServerSideSession<U>>(\n await cookies(),\n sessionOpts || sessionOptions\n );\n\n return session;\n};\n","import { cookies } from \"next/headers\";\nimport { IConfig } from \"../types\";\nimport { BaseError, err, ok, Result, Success } from \"../types/response\";\nimport { getSession } from \"./session\";\n\n// Global refresh lock to prevent multiple simultaneous refresh attempts\nlet refreshPromise: Promise<Result<string, BaseError>> | null = null;\n\nexport const serverSideFetch = async <T>({\n url,\n method = \"GET\",\n config,\n body,\n sessionIsOptional = false,\n skipRefresh = false,\n ...options\n}: {\n url: string;\n method?: \"GET\" | \"POST\" | \"DELETE\";\n body?: object;\n config: IConfig;\n sessionIsOptional?: boolean;\n skipRefresh?: boolean;\n} & Omit<RequestInit, \"body\" | \"method\">): Promise<Result<T, BaseError>> => {\n const headers = new Headers({\n \"Content-Type\": \"application/json\",\n ...(options.headers as Record<string, string>),\n });\n\n // Forward configured cookies as headers (for SSR)\n if (config.cookieHeaders) {\n try {\n const cookieStore = await cookies();\n for (const [cookieName, headerName] of Object.entries(\n config.cookieHeaders\n )) {\n // Don't overwrite if header was already passed explicitly\n if (headers.has(headerName)) continue;\n const value = cookieStore.get(cookieName)?.value;\n if (value) headers.set(headerName, value);\n }\n } catch (e) {\n // cookies() throws outside of request context — safe to ignore\n if (config.debug)\n console.log(\"#> cookieHeaders: cookies() unavailable\", e);\n }\n }\n\n const session = await getSession();\n\n if (session.token !== undefined) {\n headers.set(\"Authorization\", `Bearer ${session.token.jwt}`);\n } else if (!sessionIsOptional) {\n return err({\n error: \"SESSION_ERROR\",\n message: \"Session is required but not found.\",\n });\n }\n\n const opts: RequestInit = {\n method,\n ...options,\n headers,\n };\n\n try {\n if (body) opts.body = JSON.stringify(body);\n } catch (e) {\n console.log(\"Error stringifying body: \", e);\n }\n\n try {\n const response: Response = await fetch(`${config.apiUrl}${url}`, opts);\n\n // Handle 401 Unauthorized - try to refresh token\n if (response.status === 401 && !skipRefresh && !sessionIsOptional) {\n if (config.debug)\n console.log(\"#> 401 detected, attempting token refresh\");\n\n // Local reference to the refresh promise to prevent race conditions\n let currentRefresh: Promise<Result<string, BaseError>>;\n\n // Check if refresh is already in progress\n if (refreshPromise === null) {\n // Start new refresh process\n refreshPromise = attemptTokenRefresh(config).finally(() => {\n // Clear the lock when done (success or failure)\n refreshPromise = null;\n });\n currentRefresh = refreshPromise;\n } else {\n if (config.debug)\n console.log(\"#> Refresh already in progress, waiting...\");\n currentRefresh = refreshPromise;\n }\n\n // Wait for the refresh to complete (whether we started it or not)\n const refreshResult = await currentRefresh;\n\n if (refreshResult.isOk()) {\n // Retry the original request with refreshed token\n return serverSideFetch<T>({\n url,\n method,\n config,\n body,\n sessionIsOptional,\n skipRefresh: true, // Prevent infinite loop\n ...options,\n });\n }\n\n // Refresh failed, return the error\n return err(refreshResult.error);\n }\n\n if (!response.ok) {\n return err({\n error: \"RESPONSE_ERROR\",\n message: `HTTP error! status: ${response.status}`,\n });\n }\n\n try {\n const res = await response.json();\n if (res.error !== undefined) {\n return err(res);\n }\n\n return ok(res as Success<T>);\n } catch (e) {\n return err({\n error: \"PARSE_ERROR\",\n message: \"Failed to parse response as JSON\",\n });\n }\n } catch (e) {\n return err({\n error: \"FETCH_ERROR\",\n message: \"Failed to fetch the resource: \" + String(e),\n });\n }\n};\n\nexport async function attemptTokenRefresh(\n config: IConfig\n): Promise<Result<string, BaseError>> {\n if (config.debug) console.log(\"#> attemptTokenRefresh called\");\n\n const { jwtDecode } = await import(\"jwt-decode\");\n const session = await getSession();\n\n if (!session.token?.refresh) {\n return err({\n error: \"NO_REFRESH_TOKEN\",\n message: \"No refresh token available in session\",\n });\n }\n\n const res = await serverSideFetch<{ token: string }>({\n method: \"POST\",\n url: \"/refresh\",\n body: {\n refreshToken: session.token.refresh,\n },\n sessionIsOptional: true,\n skipRefresh: true, // Prevent infinite loop\n config,\n });\n\n if (config.debug) console.log(\"#> attemptTokenRefresh\", res);\n if (res.isErr()) {\n // Refresh token is invalid or expired, destroy session\n session.destroy();\n return err(res.error);\n }\n\n // Update session with new JWT\n const decoded = jwtDecode<any>(res.value.data.token);\n const newToken = {\n jwt: res.value.data.token,\n refresh: session.token.refresh, // Keep the same refresh token\n decoded,\n };\n\n session.token = newToken;\n\n await session.save();\n\n return ok({ data: \"success\" });\n}\n","import { NextRequest } from \"next/server\";\nimport { IConfig, IRequestOptions } from \"../types\";\nimport { Proxy } from \"./api\";\n\nexport const CelestyaProxy = (config: IConfig) => {\n return {\n POST: (req: NextRequest, opt: IRequestOptions) =>\n Proxy(\"POST\", req, opt, config),\n GET: (req: NextRequest, opt: IRequestOptions) =>\n Proxy(\"GET\", req, opt, config),\n DELETE: (req: NextRequest, opt: IRequestOptions) =>\n Proxy(\"DELETE\", req, opt, config),\n };\n};\n","import { CallbackOptions, IConfig, WrapperFunction } from \"../types\";\nimport { serverSideFetch } from \"./fetch\";\n\n/**\n * Register new Wrapper for the API.\n *\n * Example Wrapper:\n * ```ts\n * const apiWrapper = (cb: WrapperFunction) => {\n * return {\n * commmands: {\n * get: () => cb<string>({ method: \"GET\", url: \"/command\" }),\n * update: (id: string, body: JSON) =>\n * cb({ method: \"POST\", url: `/command/${id}`, body }),\n * },\n * };\n * };\n * ````\n * @param apiWrapper\n * @param config\n * @returns\n */\nexport const serverAPIWrapper = <T>(\n apiWrapper: (cb: WrapperFunction) => T,\n config: IConfig\n) => {\n return apiWrapper(async (data: CallbackOptions) => {\n const { method, url, body } = data;\n\n return serverSideFetch({\n url,\n method,\n body,\n config,\n });\n });\n};\n"],"mappings":"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","names":["cookies","cookies","jwtDecode","refresh"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "celestya",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Highly opinionated session management tool for NextJS",
5
5
  "main": "./dist/index.js",
6
6
  "exports": {