celestya 0.2.0 → 0.3.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.
package/README.md CHANGED
@@ -136,6 +136,10 @@ const Home = async () => {
136
136
  export default Navbar;
137
137
  ```
138
138
 
139
+ ## How to upload to npm
140
+
141
+
142
+
139
143
  ## Todo
140
144
 
141
145
  - [x]: Change returns at error
@@ -145,4 +149,4 @@ export default Navbar;
145
149
  - [x]: Fix issue with api endpoints if no layout has been loaded (if accessing api directly)
146
150
  - [X]: Refresh logic
147
151
  - [X]: Fix Response types
148
- - [ ]: Upload request with worker as helper (?)
152
+ - [ ]: Upload request with worker as helper (?)
@@ -94,14 +94,19 @@ interface IAuthContext<U> {
94
94
  refreshUser: (force?: boolean) => Promise<void>;
95
95
  get: <T>(props: {
96
96
  url: string;
97
+ headers?: Record<string, string>;
97
98
  }) => Promise<Result<T, BaseError>>;
98
99
  post: <T>(props: {
99
100
  url: string;
100
101
  body: object;
102
+ headers?: Record<string, string>;
101
103
  }) => Promise<Result<T, BaseError>>;
102
104
  del: <T>(props: {
103
105
  url: string;
106
+ headers?: Record<string, string>;
104
107
  }) => Promise<Result<T, BaseError>>;
108
+ setHeader: (key: string, value: string) => void;
109
+ removeHeader: (key: string) => void;
105
110
  }
106
111
  interface IAuthContextOptions {
107
112
  children: React.ReactNode;
@@ -94,14 +94,19 @@ interface IAuthContext<U> {
94
94
  refreshUser: (force?: boolean) => Promise<void>;
95
95
  get: <T>(props: {
96
96
  url: string;
97
+ headers?: Record<string, string>;
97
98
  }) => Promise<Result<T, BaseError>>;
98
99
  post: <T>(props: {
99
100
  url: string;
100
101
  body: object;
102
+ headers?: Record<string, string>;
101
103
  }) => Promise<Result<T, BaseError>>;
102
104
  del: <T>(props: {
103
105
  url: string;
106
+ headers?: Record<string, string>;
104
107
  }) => Promise<Result<T, BaseError>>;
108
+ setHeader: (key: string, value: string) => void;
109
+ removeHeader: (key: string) => void;
105
110
  }
106
111
  interface IAuthContextOptions {
107
112
  children: React.ReactNode;
@@ -124,6 +124,13 @@ var AuthContextProvider = ({
124
124
  const [ready, setReady] = (0, import_react.useState)(false);
125
125
  const [user, setUser] = (0, import_react.useState)({});
126
126
  const router = (0, import_navigation.useRouter)();
127
+ const customHeaders = (0, import_react.useRef)({});
128
+ const setHeader = (0, import_react.useCallback)((key, value) => {
129
+ customHeaders.current[key] = value;
130
+ }, []);
131
+ const removeHeader = (0, import_react.useCallback)((key) => {
132
+ delete customHeaders.current[key];
133
+ }, []);
127
134
  const loginRoute = routePrefix + "/login";
128
135
  const registerRoute = routePrefix + "/register";
129
136
  const logoutRoute = routePrefix + "/logout";
@@ -194,24 +201,35 @@ var AuthContextProvider = ({
194
201
  router.refresh();
195
202
  };
196
203
  const get = async ({
197
- url
204
+ url,
205
+ headers
198
206
  }) => {
199
- return clientSideFetch({ url: `${proxyRoute}${url}` });
207
+ return clientSideFetch({
208
+ url: `${proxyRoute}${url}`,
209
+ headers: { ...customHeaders.current, ...headers }
210
+ });
200
211
  };
201
212
  const post = async ({
202
213
  url,
203
- body
214
+ body,
215
+ headers
204
216
  }) => {
205
217
  return clientSideFetch({
206
218
  method: "POST",
207
219
  url: `${proxyRoute}${url}`,
208
- body
220
+ body,
221
+ headers: { ...customHeaders.current, ...headers }
209
222
  });
210
223
  };
211
224
  const del = async ({
212
- url
225
+ url,
226
+ headers
213
227
  }) => {
214
- return clientSideFetch({ method: "DELETE", url: `${proxyRoute}${url}` });
228
+ return clientSideFetch({
229
+ method: "DELETE",
230
+ url: `${proxyRoute}${url}`,
231
+ headers: { ...customHeaders.current, ...headers }
232
+ });
215
233
  };
216
234
  (0, import_react.useEffect)(() => {
217
235
  if (!ready) refreshUser();
@@ -227,7 +245,9 @@ var AuthContextProvider = ({
227
245
  oAuth,
228
246
  get,
229
247
  post,
230
- del
248
+ del,
249
+ setHeader,
250
+ removeHeader
231
251
  /* upload, */
232
252
  };
233
253
  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, useEffect, 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\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 }: {\n url: string;\n }): Promise<Result<T, BaseError>> => {\n return clientSideFetch({ url: `${proxyRoute}${url}` });\n };\n\n const post = async <T,>({\n url,\n body,\n }: {\n url: string;\n body: object;\n }): Promise<Result<T, BaseError>> => {\n return clientSideFetch({\n method: \"POST\",\n url: `${proxyRoute}${url}`,\n body,\n });\n };\n\n const del = async <T,>({\n url,\n }: {\n url: string;\n }): Promise<Result<T, BaseError>> => {\n return clientSideFetch({ method: \"DELETE\", url: `${proxyRoute}${url}` });\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 /* 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 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,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  // src/client/contextProvider.tsx
4
- import { createContext, useEffect, useState } from "react";
4
+ import { createContext, useCallback, useEffect, useRef, useState } from "react";
5
5
 
6
6
  // src/types/response.ts
7
7
  var Ok = class {
@@ -96,6 +96,13 @@ var AuthContextProvider = ({
96
96
  const [ready, setReady] = useState(false);
97
97
  const [user, setUser] = useState({});
98
98
  const router = useRouter();
99
+ const customHeaders = useRef({});
100
+ const setHeader = useCallback((key, value) => {
101
+ customHeaders.current[key] = value;
102
+ }, []);
103
+ const removeHeader = useCallback((key) => {
104
+ delete customHeaders.current[key];
105
+ }, []);
99
106
  const loginRoute = routePrefix + "/login";
100
107
  const registerRoute = routePrefix + "/register";
101
108
  const logoutRoute = routePrefix + "/logout";
@@ -166,24 +173,35 @@ var AuthContextProvider = ({
166
173
  router.refresh();
167
174
  };
168
175
  const get = async ({
169
- url
176
+ url,
177
+ headers
170
178
  }) => {
171
- return clientSideFetch({ url: `${proxyRoute}${url}` });
179
+ return clientSideFetch({
180
+ url: `${proxyRoute}${url}`,
181
+ headers: { ...customHeaders.current, ...headers }
182
+ });
172
183
  };
173
184
  const post = async ({
174
185
  url,
175
- body
186
+ body,
187
+ headers
176
188
  }) => {
177
189
  return clientSideFetch({
178
190
  method: "POST",
179
191
  url: `${proxyRoute}${url}`,
180
- body
192
+ body,
193
+ headers: { ...customHeaders.current, ...headers }
181
194
  });
182
195
  };
183
196
  const del = async ({
184
- url
197
+ url,
198
+ headers
185
199
  }) => {
186
- return clientSideFetch({ method: "DELETE", url: `${proxyRoute}${url}` });
200
+ return clientSideFetch({
201
+ method: "DELETE",
202
+ url: `${proxyRoute}${url}`,
203
+ headers: { ...customHeaders.current, ...headers }
204
+ });
187
205
  };
188
206
  useEffect(() => {
189
207
  if (!ready) refreshUser();
@@ -199,7 +217,9 @@ var AuthContextProvider = ({
199
217
  oAuth,
200
218
  get,
201
219
  post,
202
- del
220
+ del,
221
+ setHeader,
222
+ removeHeader
203
223
  /* upload, */
204
224
  };
205
225
  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, useEffect, 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\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 }: {\n url: string;\n }): Promise<Result<T, BaseError>> => {\n return clientSideFetch({ url: `${proxyRoute}${url}` });\n };\n\n const post = async <T,>({\n url,\n body,\n }: {\n url: string;\n body: object;\n }): Promise<Result<T, BaseError>> => {\n return clientSideFetch({\n method: \"POST\",\n url: `${proxyRoute}${url}`,\n body,\n });\n };\n\n const del = async <T,>({\n url,\n }: {\n url: string;\n }): Promise<Result<T, BaseError>> => {\n return clientSideFetch({ method: \"DELETE\", url: `${proxyRoute}${url}` });\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 /* 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 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"]}
package/dist/index.js CHANGED
@@ -121,8 +121,8 @@ var serverSideFetch = async ({
121
121
  }
122
122
  const opts = {
123
123
  method,
124
- headers,
125
- ...options
124
+ ...options,
125
+ headers
126
126
  };
127
127
  try {
128
128
  if (body) opts.body = JSON.stringify(body);
@@ -380,11 +380,18 @@ async function refresh(request, config) {
380
380
  }
381
381
  async function proxyFunction(method, request, config, options) {
382
382
  options.shift();
383
+ const forwardHeaders = {};
384
+ request.headers.forEach((value, key) => {
385
+ if (key.startsWith("x-") && key !== "x-forwarded-for" && key !== "x-forwarded-host" && key !== "x-forwarded-proto") {
386
+ forwardHeaders[key] = value;
387
+ }
388
+ });
383
389
  const res = await serverSideFetch({
384
390
  method,
385
391
  url: `/${options.join("/")}${request.nextUrl.search}`,
386
392
  body: method === "POST" ? await request.json() : void 0,
387
- config
393
+ config,
394
+ headers: forwardHeaders
388
395
  });
389
396
  if (config.debug) console.log("#> proxyFunction", res);
390
397
  if (res.isErr()) {
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 const res = await serverSideFetch({\n method,\n url: `/${options.join(\"/\")}${request.nextUrl.search}`,\n body: method === \"POST\" ? await request.json() : undefined,\n config,\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,\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 headers,\n ...options,\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 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"]}
package/dist/index.mjs CHANGED
@@ -79,8 +79,8 @@ var serverSideFetch = async ({
79
79
  }
80
80
  const opts = {
81
81
  method,
82
- headers,
83
- ...options
82
+ ...options,
83
+ headers
84
84
  };
85
85
  try {
86
86
  if (body) opts.body = JSON.stringify(body);
@@ -338,11 +338,18 @@ async function refresh(request, config) {
338
338
  }
339
339
  async function proxyFunction(method, request, config, options) {
340
340
  options.shift();
341
+ const forwardHeaders = {};
342
+ request.headers.forEach((value, key) => {
343
+ if (key.startsWith("x-") && key !== "x-forwarded-for" && key !== "x-forwarded-host" && key !== "x-forwarded-proto") {
344
+ forwardHeaders[key] = value;
345
+ }
346
+ });
341
347
  const res = await serverSideFetch({
342
348
  method,
343
349
  url: `/${options.join("/")}${request.nextUrl.search}`,
344
350
  body: method === "POST" ? await request.json() : void 0,
345
- config
351
+ config,
352
+ headers: forwardHeaders
346
353
  });
347
354
  if (config.debug) console.log("#> proxyFunction", res);
348
355
  if (res.isErr()) {
@@ -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 const res = await serverSideFetch({\n method,\n url: `/${options.join(\"/\")}${request.nextUrl.search}`,\n body: method === \"POST\" ? await request.json() : undefined,\n config,\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,\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 headers,\n ...options,\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 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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "celestya",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Highly opinionated session management tool for NextJS",
5
5
  "main": "./dist/index.js",
6
6
  "exports": {