@regardio/js 0.7.9 → 0.8.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.
package/README.md CHANGED
@@ -74,15 +74,49 @@ HTTP, cookie, and routing utilities.
74
74
 
75
75
  ```ts
76
76
  import {
77
- getCookieValue,
78
- setCookieValue,
77
+ // Client-side cookies (async - Cookie Store API + fallback)
78
+ getCookie,
79
+ setCookie,
80
+ deleteCookie,
81
+ // Client-side cookies (sync - document.cookie only)
82
+ getCookieSync,
83
+ setCookieSync,
84
+ deleteCookieSync,
85
+ // Server-side cookies (Request/Response)
86
+ parseCookies,
87
+ serializeCookie,
88
+ getCookieFromRequest,
89
+ setCookieOnResponse,
90
+ deleteCookieFromResponse,
91
+ getAllCookiesFromRequest,
92
+ // HTTP utilities
79
93
  createDomain,
80
94
  getCleanUrl,
81
95
  isRouteActive,
82
96
  } from '@regardio/js/http';
83
97
 
84
- setCookieValue('theme', 'dark', { path: '/', secure: true });
85
- const theme = getCookieValue('theme');
98
+ // Client-side async: Cookie Store API with document.cookie fallback
99
+ await setCookie('theme', 'dark', { path: '/', secure: true, sameSite: 'lax' });
100
+ const theme = await getCookie('theme');
101
+ await setCookie('theme', 'light', { path: '/' }); // Update by setting again
102
+ await deleteCookie('theme', { path: '/' });
103
+
104
+ // Client-side sync: document.cookie only (no async/await needed)
105
+ setCookieSync('theme', 'dark', { path: '/', secure: true, sameSite: 'lax' });
106
+ const themeSync = getCookieSync('theme');
107
+ setCookieSync('theme', 'light', { path: '/' }); // Update by setting again
108
+ deleteCookieSync('theme', { path: '/' });
109
+
110
+ // Server-side: Request/Response cookie handling
111
+ const session = getCookieFromRequest(request, 'session');
112
+ const allCookies = getAllCookiesFromRequest(request);
113
+ const response = setCookieOnResponse(
114
+ new Response('OK'),
115
+ 'session',
116
+ 'abc123',
117
+ { httpOnly: true, secure: true, sameSite: 'lax' }
118
+ );
119
+
86
120
  const domain = createDomain(request); // "https://example.com"
87
121
  isRouteActive('/account', '/account/settings', false); // true
88
122
  ```
@@ -38,7 +38,6 @@ function invariantResponse(condition, message, responseInit) {
38
38
  ...responseInit
39
39
  });
40
40
  }
41
-
42
41
  //#endregion
43
42
  //#region src/assert/verify-file-accept.ts
44
43
  /**
@@ -52,6 +51,5 @@ function verifyAccept(type, accept) {
52
51
  const allowed = accept.split(",").map((x) => x.trim());
53
52
  return allowed.includes(type) || allowed.includes(`${type.split("/")[0]}/*`);
54
53
  }
55
-
56
54
  //#endregion
57
- export { invariant, invariantResponse, verifyAccept };
55
+ export { invariant, invariantResponse, verifyAccept };
@@ -20,6 +20,5 @@ function generateRandomBase64() {
20
20
  crypto.getRandomValues(array);
21
21
  return btoa(String.fromCharCode(...array));
22
22
  }
23
-
24
23
  //#endregion
25
- export { generateRandomBase64, urlBase64ToUint8Array };
24
+ export { generateRandomBase64, urlBase64ToUint8Array };
@@ -1,23 +1,93 @@
1
1
  //#region src/http/cookie.d.ts
2
+ interface CookieOptions {
3
+ domain?: string;
4
+ expires?: Date;
5
+ path?: string;
6
+ sameSite?: "strict" | "lax" | "none";
7
+ secure?: boolean;
8
+ }
2
9
  /**
3
- * Helper function to set cookies in a more controlled way
10
+ * Set a cookie using Cookie Store API with document.cookie fallback
4
11
  * @param name - The name of the cookie
5
12
  * @param value - The value to set
6
13
  * @param options - Cookie options
7
14
  */
8
- declare function setCookieValue(name: string, value: string, options?: {
15
+ declare function setCookie(name: string, value: string, options?: CookieOptions): Promise<void>;
16
+ /**
17
+ * Get a cookie by name using Cookie Store API with document.cookie fallback
18
+ * @param name - The name of the cookie to get
19
+ * @returns The cookie value or null if not found
20
+ */
21
+ declare function getCookie(name: string): Promise<string | null>;
22
+ /**
23
+ * Update a cookie (alias for setCookie for clarity)
24
+ * @param name - The name of the cookie
25
+ * @param value - The new value to set
26
+ * @param options - Cookie options
27
+ */
28
+ declare function updateCookie(name: string, value: string, options?: CookieOptions): Promise<void>;
29
+ /**
30
+ * Delete a cookie by name using Cookie Store API with document.cookie fallback
31
+ * @param name - The name of the cookie to delete
32
+ * @param options - Cookie options (path and domain should match the original cookie)
33
+ */
34
+ declare function deleteCookie(name: string, options?: Pick<CookieOptions, "path" | "domain">): Promise<void>;
35
+ //#endregion
36
+ //#region src/http/cookie.server.d.ts
37
+ interface CookieSerializeOptions {
38
+ domain?: string;
39
+ encode?: (value: string) => string;
9
40
  expires?: Date;
41
+ httpOnly?: boolean;
42
+ maxAge?: number;
10
43
  path?: string;
11
- sameSite?: string;
44
+ sameSite?: "strict" | "lax" | "none" | boolean;
12
45
  secure?: boolean;
13
- domain?: string;
14
- }): void;
46
+ }
15
47
  /**
16
- * Get a cookie value by name
17
- * @param name - The name of the cookie to get
48
+ * Parse cookies from a Cookie header string
49
+ * @param cookieHeader - The Cookie header value (e.g., "session=abc123; theme=dark")
50
+ * @returns Object with cookie name-value pairs
51
+ */
52
+ declare function parseCookies(cookieHeader: string | null | undefined): Record<string, string>;
53
+ /**
54
+ * Serialize a cookie into a Set-Cookie header value
55
+ * @param name - The cookie name
56
+ * @param value - The cookie value
57
+ * @param options - Cookie options
58
+ * @returns Set-Cookie header value
59
+ */
60
+ declare function serializeCookie(name: string, value: string, options?: CookieSerializeOptions): string;
61
+ /**
62
+ * Get a cookie value from a Request object
63
+ * @param request - The Request object
64
+ * @param name - The cookie name to retrieve
18
65
  * @returns The cookie value or null if not found
19
66
  */
20
- declare function getCookieValue(name: string): string | null;
67
+ declare function getCookieFromRequest(request: Request, name: string): string | null;
68
+ /**
69
+ * Set a cookie on a Response object by adding a Set-Cookie header
70
+ * @param response - The Response object to modify
71
+ * @param name - The cookie name
72
+ * @param value - The cookie value
73
+ * @param options - Cookie options
74
+ * @returns A new Response with the Set-Cookie header added
75
+ */
76
+ declare function setCookieOnResponse(response: Response, name: string, value: string, options?: CookieSerializeOptions): Response;
77
+ /**
78
+ * Delete a cookie on a Response object by setting it with an expired date
79
+ * @param response - The Response object to modify
80
+ * @param name - The cookie name to delete
81
+ * @param options - Cookie options (path and domain should match the original cookie)
82
+ * @returns A new Response with the Set-Cookie header to delete the cookie
83
+ */
84
+ declare function deleteCookieFromResponse(response: Response, name: string, options?: Pick<CookieSerializeOptions, "path" | "domain">): Response;
85
+ /**
86
+ * Get all cookies from a Request object
87
+ * @param request - The Request object
88
+ * @returns Object with all cookie name-value pairs
89
+ */
90
+ declare function getAllCookiesFromRequest(request: Request): Record<string, string>;
21
91
  //#endregion
22
92
  //#region src/http/domain.d.ts
23
93
  /**
@@ -50,4 +120,4 @@ declare function checkIfRouteIsActive(targetLink: string, currentRoute: string,
50
120
  //#region src/http/request-helpers.d.ts
51
121
  declare function getCleanUrl(request: Request): string;
52
122
  //#endregion
53
- export { checkIfRouteIsActive, createDomain, getCleanUrl, getCookieValue, isRouteActive, setCookieValue };
123
+ export { type CookieOptions, type CookieSerializeOptions, checkIfRouteIsActive, createDomain, deleteCookie, deleteCookieFromResponse, getAllCookiesFromRequest, getCleanUrl, getCookie, getCookieFromRequest, isRouteActive, parseCookies, serializeCookie, setCookie, setCookieOnResponse, updateCookie };
@@ -1,46 +1,198 @@
1
+ import { parse, serialize } from "cookie-es";
1
2
  //#region src/http/cookie.ts
3
+ function hasCookieStore() {
4
+ return typeof window !== "undefined" && "cookieStore" in window;
5
+ }
6
+ function buildCookieString(name, value, options) {
7
+ let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
8
+ if (options.expires) cookieString += `; expires=${options.expires.toUTCString()}`;
9
+ if (options.path) cookieString += `; path=${options.path}`;
10
+ if (options.sameSite) cookieString += `; SameSite=${options.sameSite}`;
11
+ if (options.secure) cookieString += "; Secure";
12
+ if (options.domain) cookieString += `; domain=${options.domain}`;
13
+ return cookieString;
14
+ }
15
+ function setViaCookieStore(name, value, options) {
16
+ const cookieInit = {
17
+ domain: options.domain,
18
+ name,
19
+ path: options.path,
20
+ sameSite: options.sameSite,
21
+ value
22
+ };
23
+ if (options.expires) cookieInit.expires = options.expires.getTime();
24
+ return window.cookieStore.set(cookieInit);
25
+ }
26
+ function setViaDocumentCookie(name, value, options) {
27
+ const cookieString = buildCookieString(name, value, options);
28
+ document.cookie = cookieString;
29
+ }
30
+ async function getViaCookieStore(name) {
31
+ return (await window.cookieStore.get(name))?.value ?? null;
32
+ }
33
+ function getViaDocumentCookie(name) {
34
+ const parts = `; ${document.cookie}`.split(`; ${name}=`);
35
+ if (parts.length === 2) {
36
+ const cookieValue = parts.pop()?.split(";").shift();
37
+ return cookieValue ? decodeURIComponent(cookieValue) : null;
38
+ }
39
+ return null;
40
+ }
2
41
  /**
3
- * Helper function to set cookies in a more controlled way
42
+ * Set a cookie using Cookie Store API with document.cookie fallback
4
43
  * @param name - The name of the cookie
5
44
  * @param value - The value to set
6
45
  * @param options - Cookie options
7
46
  */
8
- function setCookieValue(name, value, options = {}) {
47
+ async function setCookie(name, value, options = {}) {
9
48
  if (typeof window === "undefined") {
10
49
  console.warn("Cannot set cookie on server side");
11
50
  return;
12
51
  }
13
- let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
14
- if (options.expires) cookieString += `; expires=${options.expires.toUTCString()}`;
15
- if (options.path) cookieString += `; path=${options.path}`;
16
- if (options.sameSite) cookieString += `; SameSite=${options.sameSite}`;
17
- if (options.secure) cookieString += "; Secure";
18
- if (options.domain) cookieString += `; domain=${options.domain}`;
19
52
  try {
20
- document.cookie = cookieString;
53
+ if (hasCookieStore()) await setViaCookieStore(name, value, options);
54
+ else setViaDocumentCookie(name, value, options);
21
55
  } catch (error) {
22
56
  if (error instanceof Error) console.error(`Failed to set cookie '${name}':`, error.message);
23
57
  else console.error(`Failed to set cookie '${name}': Unknown error`);
24
58
  }
25
59
  }
26
60
  /**
27
- * Get a cookie value by name
61
+ * Get a cookie by name using Cookie Store API with document.cookie fallback
28
62
  * @param name - The name of the cookie to get
29
63
  * @returns The cookie value or null if not found
30
64
  */
31
- function getCookieValue(name) {
65
+ async function getCookie(name) {
32
66
  if (typeof window === "undefined") {
33
67
  console.warn("Cannot get cookie on server side");
34
68
  return null;
35
69
  }
36
- const parts = `; ${document.cookie}`.split(`; ${name}=`);
37
- if (parts.length === 2) {
38
- const cookieValue = parts.pop()?.split(";").shift();
39
- return cookieValue ? decodeURIComponent(cookieValue) : null;
70
+ try {
71
+ if (hasCookieStore()) return await getViaCookieStore(name);
72
+ return getViaDocumentCookie(name);
73
+ } catch (error) {
74
+ if (error instanceof Error) console.error(`Failed to get cookie '${name}':`, error.message);
75
+ else console.error(`Failed to get cookie '${name}': Unknown error`);
76
+ return null;
40
77
  }
41
- return null;
42
78
  }
43
-
79
+ /**
80
+ * Update a cookie (alias for setCookie for clarity)
81
+ * @param name - The name of the cookie
82
+ * @param value - The new value to set
83
+ * @param options - Cookie options
84
+ */
85
+ function updateCookie(name, value, options = {}) {
86
+ return setCookie(name, value, options);
87
+ }
88
+ /**
89
+ * Delete a cookie by name using Cookie Store API with document.cookie fallback
90
+ * @param name - The name of the cookie to delete
91
+ * @param options - Cookie options (path and domain should match the original cookie)
92
+ */
93
+ async function deleteCookie(name, options = {}) {
94
+ if (typeof window === "undefined") {
95
+ console.warn("Cannot delete cookie on server side");
96
+ return;
97
+ }
98
+ try {
99
+ if (hasCookieStore()) await window.cookieStore.delete({
100
+ domain: options.domain,
101
+ name,
102
+ path: options.path
103
+ });
104
+ else {
105
+ const expires = /* @__PURE__ */ new Date(0);
106
+ setViaDocumentCookie(name, "", {
107
+ ...options,
108
+ expires
109
+ });
110
+ }
111
+ } catch (error) {
112
+ if (error instanceof Error) console.error(`Failed to delete cookie '${name}':`, error.message);
113
+ else console.error(`Failed to delete cookie '${name}': Unknown error`);
114
+ }
115
+ }
116
+ //#endregion
117
+ //#region src/http/cookie.server.ts
118
+ /**
119
+ * Parse cookies from a Cookie header string
120
+ * @param cookieHeader - The Cookie header value (e.g., "session=abc123; theme=dark")
121
+ * @returns Object with cookie name-value pairs
122
+ */
123
+ function parseCookies(cookieHeader) {
124
+ if (!cookieHeader) return {};
125
+ try {
126
+ return parse(cookieHeader);
127
+ } catch (error) {
128
+ if (error instanceof Error) console.error("Failed to parse cookies:", error.message);
129
+ return {};
130
+ }
131
+ }
132
+ /**
133
+ * Serialize a cookie into a Set-Cookie header value
134
+ * @param name - The cookie name
135
+ * @param value - The cookie value
136
+ * @param options - Cookie options
137
+ * @returns Set-Cookie header value
138
+ */
139
+ function serializeCookie(name, value, options = {}) {
140
+ try {
141
+ return serialize(name, value, options);
142
+ } catch (error) {
143
+ if (error instanceof Error) console.error(`Failed to serialize cookie '${name}':`, error.message);
144
+ throw error;
145
+ }
146
+ }
147
+ /**
148
+ * Get a cookie value from a Request object
149
+ * @param request - The Request object
150
+ * @param name - The cookie name to retrieve
151
+ * @returns The cookie value or null if not found
152
+ */
153
+ function getCookieFromRequest(request, name) {
154
+ return parseCookies(request.headers.get("Cookie"))[name] ?? null;
155
+ }
156
+ /**
157
+ * Set a cookie on a Response object by adding a Set-Cookie header
158
+ * @param response - The Response object to modify
159
+ * @param name - The cookie name
160
+ * @param value - The cookie value
161
+ * @param options - Cookie options
162
+ * @returns A new Response with the Set-Cookie header added
163
+ */
164
+ function setCookieOnResponse(response, name, value, options = {}) {
165
+ const setCookieValue = serializeCookie(name, value, options);
166
+ const headers = new Headers(response.headers);
167
+ headers.append("Set-Cookie", setCookieValue);
168
+ return new Response(response.body, {
169
+ headers,
170
+ status: response.status,
171
+ statusText: response.statusText
172
+ });
173
+ }
174
+ /**
175
+ * Delete a cookie on a Response object by setting it with an expired date
176
+ * @param response - The Response object to modify
177
+ * @param name - The cookie name to delete
178
+ * @param options - Cookie options (path and domain should match the original cookie)
179
+ * @returns A new Response with the Set-Cookie header to delete the cookie
180
+ */
181
+ function deleteCookieFromResponse(response, name, options = {}) {
182
+ return setCookieOnResponse(response, name, "", {
183
+ ...options,
184
+ expires: /* @__PURE__ */ new Date(0),
185
+ maxAge: 0
186
+ });
187
+ }
188
+ /**
189
+ * Get all cookies from a Request object
190
+ * @param request - The Request object
191
+ * @returns Object with all cookie name-value pairs
192
+ */
193
+ function getAllCookiesFromRequest(request) {
194
+ return parseCookies(request.headers.get("Cookie"));
195
+ }
44
196
  //#endregion
45
197
  //#region src/http/domain.ts
46
198
  /**
@@ -58,7 +210,6 @@ const createDomain = (request) => {
58
210
  if (url.hostname === "localhost") return `http://${url.host}`;
59
211
  return `https://${url.host}`;
60
212
  };
61
-
62
213
  //#endregion
63
214
  //#region src/http/is-route-active.ts
64
215
  const ROOT_PATH = "/";
@@ -107,7 +258,6 @@ function numberOfMatchingSegments(href, segments) {
107
258
  function isRoot(path) {
108
259
  return path === ROOT_PATH;
109
260
  }
110
-
111
261
  //#endregion
112
262
  //#region src/http/request-helpers.ts
113
263
  function getCleanUrl(request) {
@@ -117,6 +267,5 @@ function getCleanUrl(request) {
117
267
  });
118
268
  return url.toString();
119
269
  }
120
-
121
270
  //#endregion
122
- export { checkIfRouteIsActive, createDomain, getCleanUrl, getCookieValue, isRouteActive, setCookieValue };
271
+ export { checkIfRouteIsActive, createDomain, deleteCookie, deleteCookieFromResponse, getAllCookiesFromRequest, getCleanUrl, getCookie, getCookieFromRequest, isRouteActive, parseCookies, serializeCookie, setCookie, setCookieOnResponse, updateCookie };
@@ -1,5 +1,4 @@
1
1
  import { parseAcceptLanguage } from "intl-parse-accept-language";
2
-
3
2
  //#region src/intl/language-detector.ts
4
3
  var LanguageDetectorLingui = class {
5
4
  detector;
@@ -119,6 +118,5 @@ function getHeaders(requestOrHeaders) {
119
118
  if (requestOrHeaders instanceof Request) return requestOrHeaders.headers;
120
119
  return requestOrHeaders;
121
120
  }
122
-
123
121
  //#endregion
124
- export { LanguageDetector, LanguageDetectorLingui };
122
+ export { LanguageDetector, LanguageDetectorLingui };
@@ -20,7 +20,6 @@ function formatBytes(bytes, decimals = 2) {
20
20
  const i = Math.floor(Math.log(bytes) / Math.log(k));
21
21
  return `${Number.parseFloat((bytes / k ** i).toFixed(dm))} ${sizes[i]}`;
22
22
  }
23
-
24
23
  //#endregion
25
24
  //#region src/text/text.ts
26
25
  /**
@@ -218,6 +217,5 @@ function parseAuthorString(input) {
218
217
  }
219
218
  return {};
220
219
  }
221
-
222
220
  //#endregion
223
- export { formatBytes, parseAuthorString, replaceShyInString, splitIntoSentences, splitIntoWords, toBoolean, truncateText, typographicQuotes };
221
+ export { formatBytes, parseAuthorString, replaceShyInString, splitIntoSentences, splitIntoWords, toBoolean, truncateText, typographicQuotes };
@@ -8,7 +8,6 @@ function delay(ms) {
8
8
  return setTimeout(resolve, ms);
9
9
  });
10
10
  }
11
-
12
11
  //#endregion
13
12
  //#region src/time/measure.ts
14
13
  async function measure(key, callback) {
@@ -22,7 +21,6 @@ async function measure(key, callback) {
22
21
  console.log(`${key} took ${end - start}ms`);
23
22
  }
24
23
  }
25
-
26
24
  //#endregion
27
25
  //#region src/time/time.ts
28
26
  function timeAgo(input) {
@@ -149,6 +147,5 @@ function friendlyDuration(minutes, locale, short = false) {
149
147
  const dateTimeInUnix = (date) => {
150
148
  return Math.floor(date / 1e3);
151
149
  };
152
-
153
150
  //#endregion
154
- export { dateTimeInUnix, delay, friendlyDuration, measure, oneDayFromNow, oneMinuteFromNow, oneWeekFromNow, timeAgo };
151
+ export { dateTimeInUnix, delay, friendlyDuration, measure, oneDayFromNow, oneMinuteFromNow, oneWeekFromNow, timeAgo };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://www.schemastore.org/package.json",
3
3
  "name": "@regardio/js",
4
- "version": "0.7.9",
4
+ "version": "0.8.1",
5
5
  "private": false,
6
6
  "description": "Regardio JavaScript utilities",
7
7
  "keywords": [
@@ -76,16 +76,17 @@
76
76
  "typecheck": "exec-tsc --noEmit"
77
77
  },
78
78
  "dependencies": {
79
+ "cookie-es": "2.0.0",
79
80
  "intl-parse-accept-language": "1.0.0",
80
81
  "react-router": "7.13.1"
81
82
  },
82
83
  "devDependencies": {
83
- "@regardio/dev": "1.16.0",
84
+ "@regardio/dev": "1.16.2",
84
85
  "@total-typescript/ts-reset": "0.6.1",
85
- "@types/node": "25.3.2",
86
+ "@types/node": "25.4.0",
86
87
  "@vitest/coverage-v8": "4.0.18",
87
88
  "@vitest/ui": "4.0.18",
88
- "tsdown": "0.20.3",
89
+ "tsdown": "0.21.1",
89
90
  "vitest": "4.0.18"
90
91
  }
91
92
  }