celestya 0.2.0 → 0.4.0

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