celestya 0.1.0 → 0.2.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
@@ -143,6 +143,6 @@ export default Navbar;
143
143
  - [x]: POST request with auth
144
144
  - [x]: Fix issue with getSession serverside and config set at layout (If used at api/\_/route.tsx)
145
145
  - [x]: Fix issue with api endpoints if no layout has been loaded (if accessing api directly)
146
- - [ ]: Upload request with worker as helper (?)
147
- - [ ]: Refresh logic
148
- - [ ]: Fix Response types
146
+ - [X]: Refresh logic
147
+ - [X]: Fix Response types
148
+ - [ ]: Upload request with worker as helper (?)
@@ -1,5 +1,62 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
 
3
+ type BaseError = {
4
+ error: string;
5
+ message: string;
6
+ };
7
+ type Success<S> = {
8
+ data: S;
9
+ };
10
+ /**
11
+ * A Result type that represents either a successful value (Ok) or an error (Err).
12
+ * This is a discriminated union type that helps handle errors in a type-safe way.
13
+ *
14
+ * @template T - The type of the successful value
15
+ * @template E - The type of the error, must extend BaseError
16
+ */
17
+ type Result<T, E extends BaseError> = Ok<T, E> | Err<T, E>;
18
+ type IResult<T, E extends BaseError> = {
19
+ /**
20
+ * Checks if the `Result` is an `Ok` instance
21
+ */
22
+ isOk: () => this is Ok<T, E>;
23
+ /**
24
+ * Checks if the `Result` is an `Err` instance.
25
+ */
26
+ isErr: () => this is Err<T, E>;
27
+ };
28
+ /**
29
+ * Represents a successful `Result` value.
30
+ *
31
+ * @template T - The type of the successful value.
32
+ * @template E - The type of the error, must extend `BaseError`.
33
+ */
34
+ declare class Ok<T, E extends BaseError> implements IResult<T, E> {
35
+ value: Success<T>;
36
+ constructor(value: Success<T>);
37
+ isOk(): this is Ok<T, E>;
38
+ isErr(): this is Err<T, E>;
39
+ }
40
+ /**
41
+ * Represents an error `Result` value.
42
+ *
43
+ * @template T - The type of the successful value.
44
+ * @template E - The type of the error, must extend `BaseError`.
45
+ */
46
+ declare class Err<T, E extends BaseError> implements IResult<T, E> {
47
+ error: E;
48
+ constructor(error: E);
49
+ isOk(): this is Ok<T, E>;
50
+ isErr(): this is Err<T, E>;
51
+ }
52
+
53
+ type CallbackOptions = {
54
+ method: "GET" | "POST" | "DELETE";
55
+ url: string;
56
+ body?: object;
57
+ };
58
+ type WrapperFunction = <T>(data: CallbackOptions) => Promise<Result<T, BaseError>>;
59
+
3
60
  declare module "iron-session" {
4
61
  interface IronSessionData<U, T> {
5
62
  user?: U;
@@ -26,15 +83,6 @@ interface IOAuthData {
26
83
  oAuthUrl: string;
27
84
  onErrorUrl?: string;
28
85
  }
29
- interface IResponseError {
30
- error: string;
31
- message: string;
32
- }
33
- interface IResponseSuccess<T, U> {
34
- error: null;
35
- data: T;
36
- details: U;
37
- }
38
86
  interface IAuthContext<U> {
39
87
  isLoggedIn: boolean;
40
88
  ready: boolean;
@@ -44,9 +92,16 @@ interface IAuthContext<U> {
44
92
  oAuth: (data: IOAuthData) => Promise<string>;
45
93
  logout: () => Promise<string>;
46
94
  refreshUser: (force?: boolean) => Promise<void>;
47
- get: <T, U = any>(url: string) => Promise<ResponseType<T, U>>;
48
- post: <T, U = any>(url: string, body: any) => Promise<ResponseType<T, U>>;
49
- del: <T, U = any>(url: string) => Promise<ResponseType<T, U>>;
95
+ get: <T>(props: {
96
+ url: string;
97
+ }) => Promise<Result<T, BaseError>>;
98
+ post: <T>(props: {
99
+ url: string;
100
+ body: object;
101
+ }) => Promise<Result<T, BaseError>>;
102
+ del: <T>(props: {
103
+ url: string;
104
+ }) => Promise<Result<T, BaseError>>;
50
105
  }
51
106
  interface IAuthContextOptions {
52
107
  children: React.ReactNode;
@@ -55,12 +110,14 @@ interface IAuthContextOptions {
55
110
  interface IChildProps {
56
111
  children?: React.ReactNode;
57
112
  }
58
- type ResponseType<T, U = any> = IResponseError | IResponseSuccess<T, U>;
59
113
 
60
- type LogoutProps = React.FC<React.ComponentProps<'div'> & IChildProps>;
114
+ type LogoutProps = React.FC<React.ComponentProps<"div"> & IChildProps>;
115
+
116
+ declare const useAuth: () => IAuthContext<any>;
117
+
118
+ declare const APIWrapper: <T>(wrapperFunction: (cb: WrapperFunction) => T) => () => T;
61
119
 
62
120
  declare const AuthProvider: <IU>({ children, routePrefix, }: IAuthContextOptions) => react_jsx_runtime.JSX.Element;
63
121
  declare const Logout: LogoutProps;
64
- declare const useAuth: () => IAuthContext<any>;
65
122
 
66
- export { AuthProvider, Logout, useAuth };
123
+ export { APIWrapper, AuthProvider, Logout, useAuth };
@@ -1,5 +1,62 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
 
3
+ type BaseError = {
4
+ error: string;
5
+ message: string;
6
+ };
7
+ type Success<S> = {
8
+ data: S;
9
+ };
10
+ /**
11
+ * A Result type that represents either a successful value (Ok) or an error (Err).
12
+ * This is a discriminated union type that helps handle errors in a type-safe way.
13
+ *
14
+ * @template T - The type of the successful value
15
+ * @template E - The type of the error, must extend BaseError
16
+ */
17
+ type Result<T, E extends BaseError> = Ok<T, E> | Err<T, E>;
18
+ type IResult<T, E extends BaseError> = {
19
+ /**
20
+ * Checks if the `Result` is an `Ok` instance
21
+ */
22
+ isOk: () => this is Ok<T, E>;
23
+ /**
24
+ * Checks if the `Result` is an `Err` instance.
25
+ */
26
+ isErr: () => this is Err<T, E>;
27
+ };
28
+ /**
29
+ * Represents a successful `Result` value.
30
+ *
31
+ * @template T - The type of the successful value.
32
+ * @template E - The type of the error, must extend `BaseError`.
33
+ */
34
+ declare class Ok<T, E extends BaseError> implements IResult<T, E> {
35
+ value: Success<T>;
36
+ constructor(value: Success<T>);
37
+ isOk(): this is Ok<T, E>;
38
+ isErr(): this is Err<T, E>;
39
+ }
40
+ /**
41
+ * Represents an error `Result` value.
42
+ *
43
+ * @template T - The type of the successful value.
44
+ * @template E - The type of the error, must extend `BaseError`.
45
+ */
46
+ declare class Err<T, E extends BaseError> implements IResult<T, E> {
47
+ error: E;
48
+ constructor(error: E);
49
+ isOk(): this is Ok<T, E>;
50
+ isErr(): this is Err<T, E>;
51
+ }
52
+
53
+ type CallbackOptions = {
54
+ method: "GET" | "POST" | "DELETE";
55
+ url: string;
56
+ body?: object;
57
+ };
58
+ type WrapperFunction = <T>(data: CallbackOptions) => Promise<Result<T, BaseError>>;
59
+
3
60
  declare module "iron-session" {
4
61
  interface IronSessionData<U, T> {
5
62
  user?: U;
@@ -26,15 +83,6 @@ interface IOAuthData {
26
83
  oAuthUrl: string;
27
84
  onErrorUrl?: string;
28
85
  }
29
- interface IResponseError {
30
- error: string;
31
- message: string;
32
- }
33
- interface IResponseSuccess<T, U> {
34
- error: null;
35
- data: T;
36
- details: U;
37
- }
38
86
  interface IAuthContext<U> {
39
87
  isLoggedIn: boolean;
40
88
  ready: boolean;
@@ -44,9 +92,16 @@ interface IAuthContext<U> {
44
92
  oAuth: (data: IOAuthData) => Promise<string>;
45
93
  logout: () => Promise<string>;
46
94
  refreshUser: (force?: boolean) => Promise<void>;
47
- get: <T, U = any>(url: string) => Promise<ResponseType<T, U>>;
48
- post: <T, U = any>(url: string, body: any) => Promise<ResponseType<T, U>>;
49
- del: <T, U = any>(url: string) => Promise<ResponseType<T, U>>;
95
+ get: <T>(props: {
96
+ url: string;
97
+ }) => Promise<Result<T, BaseError>>;
98
+ post: <T>(props: {
99
+ url: string;
100
+ body: object;
101
+ }) => Promise<Result<T, BaseError>>;
102
+ del: <T>(props: {
103
+ url: string;
104
+ }) => Promise<Result<T, BaseError>>;
50
105
  }
51
106
  interface IAuthContextOptions {
52
107
  children: React.ReactNode;
@@ -55,12 +110,14 @@ interface IAuthContextOptions {
55
110
  interface IChildProps {
56
111
  children?: React.ReactNode;
57
112
  }
58
- type ResponseType<T, U = any> = IResponseError | IResponseSuccess<T, U>;
59
113
 
60
- type LogoutProps = React.FC<React.ComponentProps<'div'> & IChildProps>;
114
+ type LogoutProps = React.FC<React.ComponentProps<"div"> & IChildProps>;
115
+
116
+ declare const useAuth: () => IAuthContext<any>;
117
+
118
+ declare const APIWrapper: <T>(wrapperFunction: (cb: WrapperFunction) => T) => () => T;
61
119
 
62
120
  declare const AuthProvider: <IU>({ children, routePrefix, }: IAuthContextOptions) => react_jsx_runtime.JSX.Element;
63
121
  declare const Logout: LogoutProps;
64
- declare const useAuth: () => IAuthContext<any>;
65
122
 
66
- export { AuthProvider, Logout, useAuth };
123
+ export { APIWrapper, AuthProvider, Logout, useAuth };
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  // src/client/index.ts
22
22
  var client_exports = {};
23
23
  __export(client_exports, {
24
+ APIWrapper: () => APIWrapper,
24
25
  AuthProvider: () => AuthProvider,
25
26
  Logout: () => Logout,
26
27
  useAuth: () => useAuth
@@ -30,38 +31,86 @@ module.exports = __toCommonJS(client_exports);
30
31
  // src/client/contextProvider.tsx
31
32
  var import_react = require("react");
32
33
 
33
- // src/client/request.ts
34
- async function gFetch({
35
- url,
36
- options
37
- }) {
38
- const response = await fetch(url, {
39
- method: "GET",
40
- ...options
41
- });
42
- return await response.json();
34
+ // src/types/response.ts
35
+ var Ok = class {
36
+ constructor(value) {
37
+ this.value = value;
38
+ }
39
+ isOk() {
40
+ return true;
41
+ }
42
+ isErr() {
43
+ return false;
44
+ }
45
+ };
46
+ var Err = class {
47
+ constructor(error) {
48
+ this.error = error;
49
+ }
50
+ isOk() {
51
+ return false;
52
+ }
53
+ isErr() {
54
+ return true;
55
+ }
56
+ };
57
+ function ok(value) {
58
+ return new Ok(value);
43
59
  }
44
- async function pFetch({
45
- url,
46
- body
47
- }) {
48
- const response = await fetch(url, {
49
- method: "POST",
50
- headers: { "Content-Type": "application/json" },
51
- body: JSON.stringify(body)
52
- });
53
- return await response.json();
60
+ function err(error) {
61
+ return new Err(error);
54
62
  }
55
- async function dFetch({
63
+
64
+ // src/client/request.ts
65
+ var clientSideFetch = async ({
56
66
  url,
57
- options
58
- }) {
59
- const response = await fetch(url, {
60
- method: "DELETE",
67
+ method = "GET",
68
+ body,
69
+ ...options
70
+ }) => {
71
+ const opts = {
72
+ method,
73
+ headers: {
74
+ "Content-Type": "application/json",
75
+ ...options.headers
76
+ },
61
77
  ...options
62
- });
63
- return await response.json();
64
- }
78
+ };
79
+ try {
80
+ if (body) opts.body = JSON.stringify(body);
81
+ } catch (e) {
82
+ return err({
83
+ error: "PARSE_ERROR",
84
+ message: "Failed to parse request body as JSON"
85
+ });
86
+ }
87
+ try {
88
+ const response = await fetch(url, opts);
89
+ if (!response.ok) {
90
+ return err({
91
+ error: "RESPONSE_ERROR",
92
+ message: `HTTP error! status: ${response.status}`
93
+ });
94
+ }
95
+ try {
96
+ const res = await response.json();
97
+ if (res.error !== void 0) {
98
+ return err(res);
99
+ }
100
+ return ok(res);
101
+ } catch (e) {
102
+ return err({
103
+ error: "PARSE_ERROR",
104
+ message: "Failed to parse response as JSON"
105
+ });
106
+ }
107
+ } catch (e) {
108
+ return err({
109
+ error: "FETCH_ERROR",
110
+ message: "Failed to fetch the resource: " + String(e)
111
+ });
112
+ }
113
+ };
65
114
 
66
115
  // src/client/contextProvider.tsx
67
116
  var import_navigation = require("next/navigation");
@@ -82,104 +131,87 @@ var AuthContextProvider = ({
82
131
  const oAuthRoute = routePrefix + "/oauth";
83
132
  const proxyRoute = routePrefix + "/proxy";
84
133
  const login = async (loginData) => {
85
- try {
86
- const res = await pFetch({
87
- url: loginRoute,
88
- body: loginData.data
89
- });
90
- setIsLoggedIn(true);
91
- if (res.error) throw new Error(res.message);
92
- return loginData.redirect || "/";
93
- } catch (e) {
94
- return `${loginData.onErrorUrl || "/"}?error=${e.message}`;
134
+ const res = await clientSideFetch({
135
+ url: loginRoute,
136
+ body: loginData.data
137
+ });
138
+ if (res.isErr()) {
139
+ return `${loginData.onErrorUrl || "/"}?error=${res.error.error}`;
95
140
  }
141
+ setIsLoggedIn(true);
142
+ return loginData.redirect || "/";
96
143
  };
97
144
  const register = async (registerData) => {
98
- try {
99
- const res = await pFetch({
100
- url: registerRoute,
101
- body: registerData.data
102
- });
103
- if (res.error) throw new Error(res.message);
104
- return `${registerData.redirect || "/"}?success=true`;
105
- } catch (e) {
106
- return `${registerData.onErrorUrl || "/"}?error=${e.message}`;
145
+ const res = await clientSideFetch({
146
+ url: registerRoute,
147
+ body: registerData.data
148
+ });
149
+ if (res.isErr()) {
150
+ return `${registerData.onErrorUrl || "/"}?error=${res.error.error}`;
107
151
  }
152
+ return `${registerData.redirect || "/"}?success=true`;
108
153
  };
109
154
  const oAuth = async ({
110
155
  state,
111
156
  oAuthUrl,
112
157
  onErrorUrl
113
158
  }) => {
114
- try {
115
- const url = new URL(oAuthRoute, "http://localhost/");
116
- url.searchParams.set("authUrl", oAuthUrl);
117
- if (state && state !== "/") url.searchParams.set("state", state);
118
- const response = await gFetch({ url: url.pathname + url.search });
119
- return response.data;
120
- } catch (e) {
121
- return `${onErrorUrl || "/"}?error=${e.message}`;
159
+ const url = new URL(oAuthRoute, "http://localhost/");
160
+ url.searchParams.set("authUrl", oAuthUrl);
161
+ if (state && state !== "/") url.searchParams.set("state", state);
162
+ const response = await clientSideFetch({
163
+ url: url.pathname + url.search
164
+ });
165
+ if (response.isErr()) {
166
+ return `${onErrorUrl || "/"}?error=${response.error.message}`;
122
167
  }
168
+ return response.value.data;
123
169
  };
124
170
  const logout = async () => {
125
- try {
126
- const data = await gFetch({
127
- url: logoutRoute,
128
- options: { cache: "no-store" }
129
- });
130
- setIsLoggedIn(false);
131
- setUser({});
132
- return data.data;
133
- } catch (e) {
134
- console.log(e);
171
+ const data = await clientSideFetch({
172
+ url: logoutRoute,
173
+ cache: "no-store"
174
+ });
175
+ if (data.isErr()) {
135
176
  return "/";
136
177
  }
178
+ setIsLoggedIn(false);
179
+ setUser({});
180
+ return data.value.data;
137
181
  };
138
182
  const refreshUser = async (force) => {
139
- try {
140
- const data = await gFetch({
141
- url: `${userRoute}${force ? "?force=true" : ""}`,
142
- options: { cache: "no-store" }
143
- });
144
- if (!data.error) {
145
- setUser(data.data);
146
- setIsLoggedIn(true);
147
- } else {
148
- setUser({});
149
- setIsLoggedIn(false);
150
- }
151
- setReady(true);
152
- router.refresh();
153
- } catch (e) {
154
- console.log("refreshUser error: ", e);
183
+ const data = await clientSideFetch({
184
+ url: `${userRoute}${force ? "?force=true" : ""}`,
185
+ cache: "no-store"
186
+ });
187
+ if (data.isErr()) {
188
+ setUser({});
189
+ setIsLoggedIn(false);
190
+ } else {
191
+ setUser(data.value.data);
155
192
  }
193
+ setReady(true);
194
+ router.refresh();
156
195
  };
157
- const get = async (url) => {
158
- try {
159
- const r = await gFetch({ url: `${proxyRoute}${url}` });
160
- return r;
161
- } catch (e) {
162
- return { error: "getRequestError", message: e.message };
163
- }
196
+ const get = async ({
197
+ url
198
+ }) => {
199
+ return clientSideFetch({ url: `${proxyRoute}${url}` });
164
200
  };
165
- const post = async (url, body) => {
166
- try {
167
- const r = await pFetch({
168
- url: `${proxyRoute}${url}`,
169
- body
170
- });
171
- return r;
172
- } catch (e) {
173
- return { error: "getRequestError", message: e.message };
174
- }
201
+ const post = async ({
202
+ url,
203
+ body
204
+ }) => {
205
+ return clientSideFetch({
206
+ method: "POST",
207
+ url: `${proxyRoute}${url}`,
208
+ body
209
+ });
175
210
  };
176
- const del = async (url) => {
177
- try {
178
- const r = await dFetch({ url: `${proxyRoute}${url}` });
179
- return r;
180
- } catch (e) {
181
- return { error: "getRequestError", message: e.message };
182
- }
211
+ const del = async ({
212
+ url
213
+ }) => {
214
+ return clientSideFetch({ method: "DELETE", url: `${proxyRoute}${url}` });
183
215
  };
184
216
  (0, import_react.useEffect)(() => {
185
217
  if (!ready) refreshUser();
@@ -202,17 +234,10 @@ var AuthContextProvider = ({
202
234
  };
203
235
  var contextProvider_default = AuthContextProvider;
204
236
 
205
- // src/client/useAuth.ts
206
- var import_react2 = require("react");
207
- var useAuthContext = () => {
208
- return (0, import_react2.useContext)(AuthContext);
209
- };
210
- var useAuth_default = useAuthContext;
211
-
212
237
  // src/client/Logout.tsx
213
238
  var import_jsx_runtime2 = require("react/jsx-runtime");
214
239
  var LogoutComponent = ({ children, ...props }) => {
215
- const { logout } = useAuth_default();
240
+ const { logout } = useAuth();
216
241
  const handleLogout = async (e) => {
217
242
  e.preventDefault();
218
243
  await logout();
@@ -221,12 +246,39 @@ var LogoutComponent = ({ children, ...props }) => {
221
246
  };
222
247
  var Logout_default = LogoutComponent;
223
248
 
249
+ // src/client/useAuth.ts
250
+ var import_react2 = require("react");
251
+ var useAuth = () => {
252
+ return (0, import_react2.useContext)(AuthContext);
253
+ };
254
+
255
+ // src/client/useAPIWrapper.tsx
256
+ var import_react3 = require("react");
257
+ var APIWrapper = (wrapperFunction) => {
258
+ return () => {
259
+ const { get, post, del } = (0, import_react3.useContext)(AuthContext);
260
+ return wrapperFunction(async (data) => {
261
+ const { method, url, body } = data;
262
+ switch (method) {
263
+ case "GET":
264
+ return get({ url });
265
+ case "POST":
266
+ return post({ url, body: body != null ? body : {} });
267
+ case "DELETE":
268
+ return del({ url });
269
+ default:
270
+ throw new Error("Unsupported method type");
271
+ }
272
+ });
273
+ };
274
+ };
275
+
224
276
  // src/client/index.ts
225
277
  var AuthProvider = contextProvider_default;
226
278
  var Logout = Logout_default;
227
- var useAuth = useAuth_default;
228
279
  // Annotate the CommonJS export names for ESM import in node:
229
280
  0 && (module.exports = {
281
+ APIWrapper,
230
282
  AuthProvider,
231
283
  Logout,
232
284
  useAuth