@goralys/core 1.1.3 → 1.2.1

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +20 -19
  2. package/dist/index.js +218 -221
  3. package/package.json +3 -1
package/dist/index.d.ts CHANGED
@@ -5,14 +5,18 @@ declare function configureGoralysClient(cfg: GoralysClientConfig): void;
5
5
  declare function getGoralysClientConfig(): GoralysClientConfig;
6
6
 
7
7
  interface StorageAdapter {
8
- getItem(key: string): string | null | Promise<string | null>;
9
- setItem(key: string, value: string): void | Promise<void>;
10
- removeItem(key: string): void | Promise<void>;
8
+ getItem(key: string): string | null;
9
+ getSize(): number;
10
+ keyAt(ids: number): string | undefined;
11
+ setItem(key: string, value: string): void;
12
+ removeItem(key: string): void;
11
13
  }
12
14
  declare function configureStorage(customAdapter: StorageAdapter): void;
13
- declare function storageGet(key: string): Promise<string | null>;
14
- declare function storageSet(key: string, value: string): Promise<void>;
15
- declare function storageRemove(key: string): Promise<void>;
15
+ declare const storageGet: (key: string) => string | null;
16
+ declare const storageSet: (key: string, value: string) => void;
17
+ declare const storageSize: () => number;
18
+ declare const storageKeyAt: (idx: number) => string | undefined;
19
+ declare const storageRemove: (key: string) => void;
16
20
 
17
21
  interface PHPDateTime {
18
22
  date: string;
@@ -23,16 +27,17 @@ type CookieValue = string | boolean | number | null | undefined;
23
27
 
24
28
  interface CookiesAdapter {
25
29
  onChange(callback: () => void): () => void;
26
- getCookies(key: string): string | null;
30
+ getCookies(key: string): CookieValue;
31
+ getAll(): Record<string, CookieValue>;
27
32
  setCookies(key: string, value: CookieValue, path: string, maxAge: number): void;
28
- removeCookies(key: string): void;
33
+ removeCookies(key: string, path: string): void;
29
34
  }
30
35
  declare function configureCookies(customAdapter: CookiesAdapter): void;
31
- declare function cookiesGet(key: string): string | null;
32
- declare function cookiesSet(key: string, value: string, path?: string, maxAge?: number): void;
33
- declare function cookiesRemove(key: string): void;
34
- declare function cookiesOnChange(callback: () => void): () => void;
35
- declare function setCookiesExpire(duration: number): void;
36
+ declare const cookiesGet: (key: string) => CookieValue;
37
+ declare const cookiesGetAll: () => Record<string, CookieValue>;
38
+ declare const cookiesSet: (key: string, value: string, path?: string, maxAge?: number) => void;
39
+ declare const cookiesRemove: (key: string, path?: string) => void;
40
+ declare const cookiesOnChange: (callback: () => void) => (() => void);
36
41
 
37
42
  type CheckAuthImpl = () => boolean;
38
43
  declare function configureCheckAuth(impl: CheckAuthImpl): void;
@@ -43,10 +48,6 @@ interface GoralysCoreConfig {
43
48
  storage: StorageAdapter;
44
49
  cookies: CookiesAdapter;
45
50
  auth: CheckAuthImpl;
46
- cache: {
47
- cache: () => Promise<void>;
48
- empty: () => void;
49
- };
50
51
  }
51
52
  declare function configGoralysCore(cfg: GoralysCoreConfig): void;
52
53
 
@@ -169,6 +170,7 @@ declare const LOGO_PATH: {
169
170
  eye: string;
170
171
  };
171
172
 
173
+ declare const COOKIES_DISMISSED_KEY = "cookie-banner-dismissed";
172
174
  declare const PERSISTANT_COOKIES: string[];
173
175
  declare const PERSISTANT_LOCALS: string[];
174
176
  declare const USERNAME_KEY = "username";
@@ -271,7 +273,6 @@ declare function getLongFromShort(short: string): string;
271
273
 
272
274
  declare function fetchSubjectsForRoleClient(role: UserRole): Promise<Response | null>;
273
275
 
274
- declare function configureUserCacheCallbacks(cache: () => Promise<void>, empty: () => void): void;
275
276
  declare function cacheUserDataClient(): Promise<void>;
276
277
  declare function emptyUserCacheClient(): void;
277
278
  declare function fetchUsersClient(): Promise<Response>;
@@ -279,4 +280,4 @@ declare function fetchVirtualUsersClient(): Promise<Response>;
279
280
  declare function fetchAdminsClient(): Promise<Response>;
280
281
  declare function fetchVirtualAdminsClient(): Promise<Response>;
281
282
 
282
- export { ADMIN_CACHE_RADIX, ADMIN_SYNC_RADIX, type AuthEvent, type CheckAuthImpl, type ConfirmOptions, type CookieValue, type CookiesAdapter, type DraftModalResult, EMAIL_KEY, FULL_NAME_KEY, GoralysActionHandler, type GoralysClientConfig, HTTP_METHODS, type HttpMethod, LOGO_PATH, PERSISTANT_COOKIES, PERSISTANT_LOCALS, type PHPDateTime, PUB_ID_KEY, ROLE_KEY, SUBJECT_CACHES, SUBJECT_CACHE_RADIX, SUBJECT_SYNCS, SUBJECT_SYNC_RADIX, SUPPORT_TICKET_CACHE, SUPPORT_TICKET_SYNC, type StorageAdapter, type Subject, type SubjectStatus, SubjectStatusConfig, type SubjectsSearchField, type SupportReasons, type SupportTicket, type Toast, type ToastFn, USERNAME_KEY, USER_CACHES, USER_CACHE_RADIX, USER_ROLES, USER_SYNCS, USER_SYNC_RADIX, type User, type UserData, type UserEvent, type UserRole, type UserType, buildApiUrl, buildArray, cacheUserDataClient, configGoralysCore, configureCheckAuth, configureCookies, configureGoralysClient, configureStorage, configureUserCacheCallbacks, cookiesGet, cookiesOnChange, cookiesRemove, cookiesSet, emitAuthEvent, emitNavigationEvent, emitUserEvent, emptyUserCacheClient, fetchAdminsClient, fetchCsrfClient, fetchSubjectsForRoleClient, fetchUsersClient, fetchVirtualAdminsClient, fetchVirtualUsersClient, getGoralysClientConfig, getLongFromShort, getStatusHelper, getStatusLabel, goralysFetchClient, handleToastRequest, helpContent, isAuthenticated, isFoolsDay, isHTTPMethod, onAuthEvent, onNavigationEvent, onUserEvent, parsePhpDateTime, reasonsConfig, searchFields, setCookiesExpire, storageGet, storageRemove, storageSet, useAdmins, useSubjects, useSupportTickets, useUsers, useVirtualAdmins, useVirtualUsers };
283
+ export { ADMIN_CACHE_RADIX, ADMIN_SYNC_RADIX, type AuthEvent, COOKIES_DISMISSED_KEY, type CheckAuthImpl, type ConfirmOptions, type CookieValue, type CookiesAdapter, type DraftModalResult, EMAIL_KEY, FULL_NAME_KEY, GoralysActionHandler, type GoralysClientConfig, HTTP_METHODS, type HttpMethod, LOGO_PATH, PERSISTANT_COOKIES, PERSISTANT_LOCALS, type PHPDateTime, PUB_ID_KEY, ROLE_KEY, SUBJECT_CACHES, SUBJECT_CACHE_RADIX, SUBJECT_SYNCS, SUBJECT_SYNC_RADIX, SUPPORT_TICKET_CACHE, SUPPORT_TICKET_SYNC, type StorageAdapter, type Subject, type SubjectStatus, SubjectStatusConfig, type SubjectsSearchField, type SupportReasons, type SupportTicket, type Toast, type ToastFn, USERNAME_KEY, USER_CACHES, USER_CACHE_RADIX, USER_ROLES, USER_SYNCS, USER_SYNC_RADIX, type User, type UserData, type UserEvent, type UserRole, type UserType, buildApiUrl, buildArray, cacheUserDataClient, configGoralysCore, configureCheckAuth, configureCookies, configureGoralysClient, configureStorage, cookiesGet, cookiesGetAll, cookiesOnChange, cookiesRemove, cookiesSet, emitAuthEvent, emitNavigationEvent, emitUserEvent, emptyUserCacheClient, fetchAdminsClient, fetchCsrfClient, fetchSubjectsForRoleClient, fetchUsersClient, fetchVirtualAdminsClient, fetchVirtualUsersClient, getGoralysClientConfig, getLongFromShort, getStatusHelper, getStatusLabel, goralysFetchClient, handleToastRequest, helpContent, isAuthenticated, isFoolsDay, isHTTPMethod, onAuthEvent, onNavigationEvent, onUserEvent, parsePhpDateTime, reasonsConfig, searchFields, storageGet, storageKeyAt, storageRemove, storageSet, storageSize, useAdmins, useSubjects, useSupportTickets, useUsers, useVirtualAdmins, useVirtualUsers };
package/dist/index.js CHANGED
@@ -21,15 +21,11 @@ function getAdapter() {
21
21
  }
22
22
  return adapter;
23
23
  }
24
- async function storageGet(key) {
25
- return getAdapter().getItem(key);
26
- }
27
- async function storageSet(key, value) {
28
- await getAdapter().setItem(key, value);
29
- }
30
- async function storageRemove(key) {
31
- await getAdapter().removeItem(key);
32
- }
24
+ var storageGet = (key) => getAdapter().getItem(key);
25
+ var storageSet = (key, value) => getAdapter().setItem(key, value);
26
+ var storageSize = () => getAdapter().getSize();
27
+ var storageKeyAt = (idx) => getAdapter().keyAt(idx);
28
+ var storageRemove = (key) => getAdapter().removeItem(key);
33
29
 
34
30
  // src/lib/storage/cookies-adapter.ts
35
31
  var adapter2 = null;
@@ -42,21 +38,11 @@ function getAdapter2() {
42
38
  }
43
39
  return adapter2;
44
40
  }
45
- function cookiesGet(key) {
46
- return getAdapter2().getCookies(key);
47
- }
48
- function cookiesSet(key, value, path = "/", maxAge = 1.5 * 60) {
49
- getAdapter2().setCookies(key, value, path, maxAge);
50
- }
51
- function cookiesRemove(key) {
52
- getAdapter2().removeCookies(key);
53
- }
54
- function cookiesOnChange(callback) {
55
- return getAdapter2().onChange(callback);
56
- }
57
- function setCookiesExpire(duration) {
58
- storageSet("goralys-cookies-expire", String(Date.now() + duration * 1e3)).then();
59
- }
41
+ var cookiesGet = (key) => getAdapter2().getCookies(key);
42
+ var cookiesGetAll = () => getAdapter2().getAll();
43
+ var cookiesSet = (key, value, path = "/", maxAge = 1.5 * 60) => getAdapter2().setCookies(key, value, path, maxAge);
44
+ var cookiesRemove = (key, path = "/") => getAdapter2().removeCookies(key, path);
45
+ var cookiesOnChange = (callback) => getAdapter2().onChange(callback);
60
46
 
61
47
  // src/lib/auth/check-auth.ts
62
48
  var checkAuthImpl;
@@ -70,6 +56,17 @@ function isAuthenticated() {
70
56
  return checkAuthImpl();
71
57
  }
72
58
 
59
+ // src/config.ts
60
+ function configGoralysCore(cfg) {
61
+ configureGoralysClient(cfg.client);
62
+ configureCookies(cfg.cookies);
63
+ configureStorage(cfg.storage);
64
+ configureCheckAuth(cfg.auth);
65
+ }
66
+
67
+ // src/hooks/useSubjects.ts
68
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
69
+
73
70
  // src/lib/auth/auth-event.ts
74
71
  var listeners = /* @__PURE__ */ new Set();
75
72
  function emitAuthEvent(event) {
@@ -92,191 +89,9 @@ function onNavigationEvent(listener) {
92
89
  return () => listeners2.delete(listener);
93
90
  }
94
91
 
95
- // src/lib/auth/user-event.ts
96
- var listeners3 = /* @__PURE__ */ new Set();
97
- function emitUserEvent(event) {
98
- listeners3.forEach((l) => l(event));
99
- }
100
- function onUserEvent(callback) {
101
- listeners3.add(callback);
102
- return () => {
103
- listeners3.delete(callback);
104
- };
105
- }
106
-
107
- // src/lib/fetch/goralys-action-handler.ts
108
- var GoralysActionHandler = class {
109
- constructor() {
110
- this.handle = async (r) => {
111
- const data = await r.clone().json();
112
- if (!data || !data.action) {
113
- return;
114
- }
115
- const action = data.action;
116
- if (action === "login-success") {
117
- await this.onLogin();
118
- }
119
- return;
120
- };
121
- this.onLogin = async () => {
122
- await cacheUserDataClient();
123
- emitUserEvent("login");
124
- return;
125
- };
126
- }
127
- };
128
-
129
- // src/lib/fetch/fetch.client.ts
130
- var actionHandler = new GoralysActionHandler();
131
- async function goralysFetchClient(method, input, payload, requestOptions) {
132
- const { apiDomain } = getGoralysClientConfig();
133
- const res = await fetch(`${apiDomain}/${input}`, {
134
- credentials: "include",
135
- method: method === "BREW" ? "POST" : method,
136
- headers: method === "BREW" ? { "X-HTTP-Method-Override": method } : {},
137
- body: payload ? payload instanceof FormData ? payload : JSON.stringify(payload) : void 0,
138
- ...requestOptions
139
- });
140
- const clone = res.clone();
141
- const contentType = clone.headers.get("Content-Type");
142
- if (!(contentType && contentType.toLowerCase().trim().includes("application/json")))
143
- return res;
144
- const data = await clone.json();
145
- if (res.status === 401) {
146
- try {
147
- emitAuthEvent(data?.authEvent ?? "unauthenticated");
148
- } catch {
149
- emitAuthEvent("unauthenticated");
150
- }
151
- }
152
- if (res.status === 418) {
153
- const teapotData = await res.clone().json();
154
- emitNavigationEvent({
155
- type: "teapot",
156
- toastType: teapotData.toastType,
157
- toastTitle: teapotData.toastTitle,
158
- toastMessage: teapotData.toastMessage
159
- });
160
- }
161
- await actionHandler.handle(res);
162
- return res;
163
- }
164
- async function fetchCsrfClient(formId) {
165
- const { apiDomain } = getGoralysClientConfig();
166
- const res = await fetch(`${apiDomain}/csrf`, {
167
- method: "POST",
168
- headers: { "Content-Type": "application/json" },
169
- credentials: "include",
170
- body: JSON.stringify({ form: formId })
171
- });
172
- if (!res.ok)
173
- return null;
174
- const json = await res.json();
175
- return json["csrf-token"];
176
- }
177
- function buildQueryString(params) {
178
- return Object.entries(params).filter(([, value]) => value !== null && value !== void 0).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
179
- }
180
- function buildApiUrl(endpoint, params, domain = false) {
181
- const { apiDomain } = getGoralysClientConfig();
182
- const queryString = buildQueryString(params);
183
- return `${domain ? apiDomain + "/" : ""}${endpoint}${queryString ? `?${queryString}` : ""}`;
184
- }
185
- async function handleToastRequest(r, showToast, redirect = true, duration) {
186
- const res = r.clone();
187
- const data = await res.json();
188
- if (data?.toast) {
189
- showToast({ type: data.toastType, title: data.toastTitle, message: data.toastMessage }, duration);
190
- if (data?.redirect && redirect) {
191
- emitNavigationEvent({ type: "redirect", url: data.redirect });
192
- }
193
- return true;
194
- }
195
- return false;
196
- }
197
-
198
- // src/lib/user/user.client.ts
199
- var cacheUserClient;
200
- var emptyCacheUserClient;
201
- function configureUserCacheCallbacks(cache, empty) {
202
- cacheUserClient = cache;
203
- emptyCacheUserClient = empty;
204
- }
205
- async function cacheUserDataClient() {
206
- if (!cacheUserClient) {
207
- throw new Error("User cache not configured. Call configUserCacheCallbacks() first.");
208
- }
209
- return await cacheUserClient();
210
- }
211
- function emptyUserCacheClient() {
212
- if (!emptyCacheUserClient) {
213
- throw new Error("User cache not configured. Call configUserCacheCallbacks() first.");
214
- }
215
- return emptyCacheUserClient();
216
- }
217
- async function fetchUsersClient() {
218
- const csrfToken = await fetchCsrfClient("get-all-users");
219
- return await goralysFetchClient("GET", buildApiUrl("users/all", { "csrf-token": csrfToken }));
220
- }
221
- async function fetchVirtualUsersClient() {
222
- const csrfToken = await fetchCsrfClient("get-virtual-users");
223
- return await goralysFetchClient("GET", buildApiUrl("users/virtual", { "csrf-token": csrfToken }));
224
- }
225
- async function fetchAdminsClient() {
226
- const csrfToken = await fetchCsrfClient("get-all-admins");
227
- return await goralysFetchClient("GET", buildApiUrl("admins/all", { "csrf-token": csrfToken }));
228
- }
229
- async function fetchVirtualAdminsClient() {
230
- const csrfToken = await fetchCsrfClient("get-virtual-admins");
231
- return await goralysFetchClient("GET", buildApiUrl("admins/virtual", { "csrf-token": csrfToken }));
232
- }
233
-
234
- // src/config.ts
235
- function configGoralysCore(cfg) {
236
- configureGoralysClient(cfg.client);
237
- configureCookies(cfg.cookies);
238
- configureStorage(cfg.storage);
239
- configureCheckAuth(cfg.auth);
240
- configureUserCacheCallbacks(cfg.cache.cache, cfg.cache.empty);
241
- }
242
-
243
- // src/hooks/useSubjects.ts
244
- import { useCallback, useEffect, useMemo, useRef, useState } from "react";
245
-
246
- // src/lib/subjects/subjects.client.ts
247
- async function fetchStudentSubjectsClient() {
248
- const csrfToken = await fetchCsrfClient("get-student-subjects");
249
- if (!csrfToken)
250
- return null;
251
- return await goralysFetchClient("GET", buildApiUrl("subjects/student", { "csrf-token": csrfToken }));
252
- }
253
- async function fetchTeacherSubjectsClient() {
254
- const csrfToken = await fetchCsrfClient("get-teacher-subjects");
255
- if (!csrfToken)
256
- return null;
257
- return await goralysFetchClient("GET", buildApiUrl("subjects/teacher", { "csrf-token": csrfToken }));
258
- }
259
- async function fetchAdminSubjectsClient() {
260
- const csrfToken = await fetchCsrfClient("get-admin-subjects");
261
- if (!csrfToken)
262
- return null;
263
- return await goralysFetchClient("GET", buildApiUrl("subjects/admin", { "csrf-token": csrfToken }));
264
- }
265
- async function fetchSubjectsForRoleClient(role) {
266
- switch (role.role) {
267
- case "student":
268
- return await fetchStudentSubjectsClient();
269
- case "teacher":
270
- return await fetchTeacherSubjectsClient();
271
- case "admin":
272
- return await fetchAdminSubjectsClient();
273
- default:
274
- return null;
275
- }
276
- }
277
-
278
92
  // src/lib/config.ts
279
- var PERSISTANT_COOKIES = ["cookie-banner-dismissed"];
93
+ var COOKIES_DISMISSED_KEY = "cookie-banner-dismissed";
94
+ var PERSISTANT_COOKIES = [COOKIES_DISMISSED_KEY, "rate_limit_token"];
280
95
  var PERSISTANT_LOCALS = ["goralys-cookies-expire", "flash_toast"];
281
96
  var USERNAME_KEY = "username";
282
97
  var ROLE_KEY = "user-role";
@@ -516,6 +331,186 @@ Attention : les administrateurs ont acc\xE8s \xE0 toutes les fonctionnalit\xE9s
516
331
  }
517
332
  ];
518
333
 
334
+ // src/lib/user/user.client.ts
335
+ async function cacheUserDataClient() {
336
+ const res = await goralysFetchClient("GET", "user/profile");
337
+ if (!res.ok) {
338
+ return;
339
+ }
340
+ const data = (await res.json())["data"];
341
+ cookiesSet(USERNAME_KEY, data.username, "/", 1.5 * 60 * 60);
342
+ cookiesSet(FULL_NAME_KEY, data.full_name, "/", 1.5 * 60 * 60);
343
+ cookiesSet(ROLE_KEY, data.role, "/", 1.5 * 60 * 60);
344
+ cookiesSet(PUB_ID_KEY, data.public_id, "/", 1.5 * 60 * 60);
345
+ if (data?.email)
346
+ cookiesSet(EMAIL_KEY, data.email, "/", 1.5 * 60 * 60);
347
+ else
348
+ cookiesRemove(EMAIL_KEY);
349
+ }
350
+ function emptyUserCacheClient() {
351
+ for (let i = 0; i < storageSize(); i++) {
352
+ const key = storageKeyAt(i);
353
+ if (!PERSISTANT_LOCALS.includes(key))
354
+ storageRemove(key);
355
+ }
356
+ Object.keys(cookiesGetAll()).forEach((name) => {
357
+ if (PERSISTANT_COOKIES.includes(name.trim()))
358
+ return;
359
+ if (name.startsWith("__next"))
360
+ return;
361
+ cookiesRemove(name);
362
+ });
363
+ }
364
+ async function fetchUsersClient() {
365
+ const csrfToken = await fetchCsrfClient("get-all-users");
366
+ return await goralysFetchClient("GET", buildApiUrl("users/all", { "csrf-token": csrfToken }));
367
+ }
368
+ async function fetchVirtualUsersClient() {
369
+ const csrfToken = await fetchCsrfClient("get-virtual-users");
370
+ return await goralysFetchClient("GET", buildApiUrl("users/virtual", { "csrf-token": csrfToken }));
371
+ }
372
+ async function fetchAdminsClient() {
373
+ const csrfToken = await fetchCsrfClient("get-all-admins");
374
+ return await goralysFetchClient("GET", buildApiUrl("admins/all", { "csrf-token": csrfToken }));
375
+ }
376
+ async function fetchVirtualAdminsClient() {
377
+ const csrfToken = await fetchCsrfClient("get-virtual-admins");
378
+ return await goralysFetchClient("GET", buildApiUrl("admins/virtual", { "csrf-token": csrfToken }));
379
+ }
380
+
381
+ // src/lib/auth/user-event.ts
382
+ var listeners3 = /* @__PURE__ */ new Set();
383
+ function emitUserEvent(event) {
384
+ listeners3.forEach((l) => l(event));
385
+ }
386
+ function onUserEvent(callback) {
387
+ listeners3.add(callback);
388
+ return () => {
389
+ listeners3.delete(callback);
390
+ };
391
+ }
392
+
393
+ // src/lib/fetch/goralys-action-handler.ts
394
+ var GoralysActionHandler = class {
395
+ handle = async (r) => {
396
+ const data = await r.clone().json();
397
+ if (!data || !data.action) {
398
+ return;
399
+ }
400
+ const action = data.action;
401
+ if (action === "login-success") {
402
+ await this.onLogin();
403
+ }
404
+ return;
405
+ };
406
+ onLogin = async () => {
407
+ await cacheUserDataClient();
408
+ emitUserEvent("login");
409
+ return;
410
+ };
411
+ };
412
+
413
+ // src/lib/fetch/fetch.client.ts
414
+ var actionHandler = new GoralysActionHandler();
415
+ async function goralysFetchClient(method, input, payload, requestOptions) {
416
+ const { apiDomain } = getGoralysClientConfig();
417
+ const res = await fetch(`${apiDomain}/${input}`, {
418
+ credentials: "include",
419
+ method: method === "BREW" ? "POST" : method,
420
+ headers: method === "BREW" ? { "X-HTTP-Method-Override": method } : {},
421
+ body: payload ? payload instanceof FormData ? payload : JSON.stringify(payload) : void 0,
422
+ ...requestOptions
423
+ });
424
+ const clone = res.clone();
425
+ const contentType = clone.headers.get("Content-Type");
426
+ if (!(contentType && contentType.toLowerCase().trim().includes("application/json")))
427
+ return res;
428
+ const data = await clone.json();
429
+ if (res.status === 401) {
430
+ try {
431
+ emitAuthEvent(data?.authEvent ?? "unauthenticated");
432
+ } catch {
433
+ emitAuthEvent("unauthenticated");
434
+ }
435
+ }
436
+ if (res.status === 418) {
437
+ const teapotData = await res.clone().json();
438
+ emitNavigationEvent({
439
+ type: "teapot",
440
+ toastType: teapotData.toastType,
441
+ toastTitle: teapotData.toastTitle,
442
+ toastMessage: teapotData.toastMessage
443
+ });
444
+ }
445
+ await actionHandler.handle(res);
446
+ return res;
447
+ }
448
+ async function fetchCsrfClient(formId) {
449
+ const { apiDomain } = getGoralysClientConfig();
450
+ const res = await fetch(`${apiDomain}/csrf`, {
451
+ method: "POST",
452
+ headers: { "Content-Type": "application/json" },
453
+ credentials: "include",
454
+ body: JSON.stringify({ form: formId })
455
+ });
456
+ if (!res.ok)
457
+ return null;
458
+ const json = await res.json();
459
+ return json["csrf-token"];
460
+ }
461
+ function buildQueryString(params) {
462
+ return Object.entries(params).filter(([, value]) => value !== null && value !== void 0).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
463
+ }
464
+ function buildApiUrl(endpoint, params, domain = false) {
465
+ const { apiDomain } = getGoralysClientConfig();
466
+ const queryString = buildQueryString(params);
467
+ return `${domain ? apiDomain + "/" : ""}${endpoint}${queryString ? `?${queryString}` : ""}`;
468
+ }
469
+ async function handleToastRequest(r, showToast, redirect = true, duration) {
470
+ const res = r.clone();
471
+ const data = await res.json();
472
+ if (data?.toast) {
473
+ showToast({ type: data.toastType, title: data.toastTitle, message: data.toastMessage }, duration);
474
+ if (data?.redirect && redirect) {
475
+ emitNavigationEvent({ type: "redirect", url: data.redirect });
476
+ }
477
+ return true;
478
+ }
479
+ return false;
480
+ }
481
+
482
+ // src/lib/subjects/subjects.client.ts
483
+ async function fetchStudentSubjectsClient() {
484
+ const csrfToken = await fetchCsrfClient("get-student-subjects");
485
+ if (!csrfToken)
486
+ return null;
487
+ return await goralysFetchClient("GET", buildApiUrl("subjects/student", { "csrf-token": csrfToken }));
488
+ }
489
+ async function fetchTeacherSubjectsClient() {
490
+ const csrfToken = await fetchCsrfClient("get-teacher-subjects");
491
+ if (!csrfToken)
492
+ return null;
493
+ return await goralysFetchClient("GET", buildApiUrl("subjects/teacher", { "csrf-token": csrfToken }));
494
+ }
495
+ async function fetchAdminSubjectsClient() {
496
+ const csrfToken = await fetchCsrfClient("get-admin-subjects");
497
+ if (!csrfToken)
498
+ return null;
499
+ return await goralysFetchClient("GET", buildApiUrl("subjects/admin", { "csrf-token": csrfToken }));
500
+ }
501
+ async function fetchSubjectsForRoleClient(role) {
502
+ switch (role.role) {
503
+ case "student":
504
+ return await fetchStudentSubjectsClient();
505
+ case "teacher":
506
+ return await fetchTeacherSubjectsClient();
507
+ case "admin":
508
+ return await fetchAdminSubjectsClient();
509
+ default:
510
+ return null;
511
+ }
512
+ }
513
+
519
514
  // src/hooks/useSubjects.ts
520
515
  function useSubjects(role, showToast) {
521
516
  const [subjects, setSubjects] = useState(null);
@@ -543,10 +538,10 @@ function useSubjects(role, showToast) {
543
538
  try {
544
539
  const syncValue = cookiesGet(syncKey);
545
540
  if (syncValue == "1") {
546
- const raw = await storageGet(cacheKey);
541
+ const raw = storageGet(cacheKey);
547
542
  if (raw === null || raw === void 0) {
548
543
  cookiesSet(syncKey, "0");
549
- await storageRemove(cacheKey);
544
+ storageRemove(cacheKey);
550
545
  await fetchSubjects();
551
546
  return;
552
547
  }
@@ -563,7 +558,7 @@ function useSubjects(role, showToast) {
563
558
  await handleToastRequest(res, showToastRef.current, false);
564
559
  const data = await res?.json();
565
560
  cookiesSet(syncKey, "1");
566
- await storageSet(cacheKey, JSON.stringify(data));
561
+ storageSet(cacheKey, JSON.stringify(data));
567
562
  console.log("[useSubjects] set syncKey and cached to localStorage");
568
563
  const result = Array.isArray(data) ? data : null;
569
564
  setSubjects((prev) => {
@@ -575,7 +570,7 @@ function useSubjects(role, showToast) {
575
570
  inFlightRef.current = null;
576
571
  resolve();
577
572
  }
578
- }, [role]);
573
+ }, [role, showToastRef]);
579
574
  useEffect(() => {
580
575
  const onChange = () => {
581
576
  if (inFlightRef.current)
@@ -623,10 +618,10 @@ function useSupportTickets(showToast) {
623
618
  try {
624
619
  const syncValue = cookiesGet(syncKey);
625
620
  if (syncValue == "1") {
626
- const raw = await storageGet(cacheKey);
621
+ const raw = storageGet(cacheKey);
627
622
  if (raw === null || raw === void 0) {
628
623
  cookiesSet(syncKey, "0");
629
- await storageRemove(cacheKey);
624
+ storageRemove(cacheKey);
630
625
  await fetchSupportTickets();
631
626
  return;
632
627
  }
@@ -643,7 +638,7 @@ function useSupportTickets(showToast) {
643
638
  await handleToastRequest(res, showToastRef.current, false);
644
639
  const data = await res?.json();
645
640
  cookiesSet(syncKey, "1");
646
- await storageSet(cacheKey, JSON.stringify(data));
641
+ storageSet(cacheKey, JSON.stringify(data));
647
642
  const result = Array.isArray(data) ? data : null;
648
643
  setSupportTickets((prev) => {
649
644
  if (JSON.stringify(prev) === JSON.stringify(result))
@@ -654,7 +649,7 @@ function useSupportTickets(showToast) {
654
649
  inFlightRef.current = null;
655
650
  resolve();
656
651
  }
657
- }, []);
652
+ }, [showToastRef]);
658
653
  useEffect2(() => {
659
654
  const onChange = () => {
660
655
  if (inFlightRef.current)
@@ -700,10 +695,10 @@ function useUserCollection(fetchFn, type, showToast) {
700
695
  try {
701
696
  const syncValue = cookiesGet(syncKey);
702
697
  if (syncValue == "1") {
703
- const raw = await storageGet(cacheKey);
698
+ const raw = storageGet(cacheKey);
704
699
  if (raw === null || raw === void 0) {
705
700
  cookiesSet(syncKey, "0");
706
- await storageRemove(cacheKey);
701
+ storageRemove(cacheKey);
707
702
  await fetchUsers();
708
703
  return;
709
704
  }
@@ -721,7 +716,7 @@ function useUserCollection(fetchFn, type, showToast) {
721
716
  const data = await res?.json();
722
717
  if (res?.ok) {
723
718
  cookiesSet(syncKey, "1");
724
- await storageSet(cacheKey, JSON.stringify(data));
719
+ storageSet(cacheKey, JSON.stringify(data));
725
720
  }
726
721
  const result = Array.isArray(data) ? data : null;
727
722
  setUsers((prev) => {
@@ -881,6 +876,7 @@ var USER_ROLES = ["admin", "teacher", "student", "none"];
881
876
  export {
882
877
  ADMIN_CACHE_RADIX,
883
878
  ADMIN_SYNC_RADIX,
879
+ COOKIES_DISMISSED_KEY,
884
880
  EMAIL_KEY,
885
881
  FULL_NAME_KEY,
886
882
  GoralysActionHandler,
@@ -910,8 +906,8 @@ export {
910
906
  configureCookies,
911
907
  configureGoralysClient,
912
908
  configureStorage,
913
- configureUserCacheCallbacks,
914
909
  cookiesGet,
910
+ cookiesGetAll,
915
911
  cookiesOnChange,
916
912
  cookiesRemove,
917
913
  cookiesSet,
@@ -940,10 +936,11 @@ export {
940
936
  parsePhpDateTime,
941
937
  reasonsConfig,
942
938
  searchFields,
943
- setCookiesExpire,
944
939
  storageGet,
940
+ storageKeyAt,
945
941
  storageRemove,
946
942
  storageSet,
943
+ storageSize,
947
944
  useAdmins,
948
945
  useSubjects,
949
946
  useSupportTickets,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goralys/core",
3
- "version": "1.1.3",
3
+ "version": "1.2.1",
4
4
  "license": "LGPL-2.1-or-later",
5
5
  "description": "Shared business logic for the Goralys web application",
6
6
  "repository": {
@@ -28,12 +28,14 @@
28
28
  },
29
29
  "scripts": {
30
30
  "build": "tsup",
31
+ "typeCheck": "tsgo --noEmit",
31
32
  "dev": "tsup --watch"
32
33
  },
33
34
  "peerDependencies": {
34
35
  "react": ">=18"
35
36
  },
36
37
  "devDependencies": {
38
+ "@typescript/native-preview": "7.0.0-dev.20260705.1",
37
39
  "barrelsby": "^2.8.1",
38
40
  "esbuild-plugin-tsconfig-paths": "^1.0.2",
39
41
  "react": "^18.0.0",