@carvajalconsultants/headstart 1.0.4 → 1.0.5
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/cookies.ts +86 -0
- package/package.json +4 -2
- package/serverCookies.ts +160 -0
package/cookies.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import Cookies from "js-cookie";
|
|
2
|
+
|
|
3
|
+
import { getServerCookie, setServerCookie } from "./serverCookies";
|
|
4
|
+
|
|
5
|
+
import type { CookieSetOptions } from "./serverCookies";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Retrieves a cookie value by its name, working seamlessly in both client and server environments.
|
|
9
|
+
* This is crucial for applications that need to maintain state or user preferences across page loads
|
|
10
|
+
* and server-side rendering scenarios.
|
|
11
|
+
*
|
|
12
|
+
* @param name - The unique identifier of the cookie you want to retrieve (e.g., 'user_session', 'theme_preference')
|
|
13
|
+
* @returns The value stored in the cookie if it exists, or undefined if the cookie is not found
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // Get user's theme preference
|
|
17
|
+
* const theme = getCookie('theme_preference');
|
|
18
|
+
* if (theme === 'dark') {
|
|
19
|
+
* // Apply dark theme
|
|
20
|
+
* }
|
|
21
|
+
*/
|
|
22
|
+
export const getCookie = async (name: string): Promise<string | undefined> => {
|
|
23
|
+
// Check if code is running in browser
|
|
24
|
+
if (typeof window !== "undefined") {
|
|
25
|
+
// Client-side cookie retrieval
|
|
26
|
+
return Cookies.get(name);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Server-side cookie retrieval
|
|
30
|
+
return getServerCookie(name);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Sets a cookie with the specified name, value, and optional configuration parameters.
|
|
35
|
+
* Essential for storing user preferences, session tokens, or any client-side state that
|
|
36
|
+
* needs to persist across page reloads or browser sessions.
|
|
37
|
+
*
|
|
38
|
+
* @param name - The unique identifier for the cookie (e.g., 'auth_token', 'language_preference')
|
|
39
|
+
* @param value - The data to be stored in the cookie
|
|
40
|
+
* @param options - Configuration object for the cookie
|
|
41
|
+
* @param options.domain - Specifies which domains can access the cookie
|
|
42
|
+
* @param options.expires - When the cookie should expire, either as a Date object or days from now
|
|
43
|
+
* @param options.secure - If true, cookie will only be transmitted over HTTPS
|
|
44
|
+
* @param options.sameSite - Controls how the cookie behaves with cross-site requests
|
|
45
|
+
* @param options.path - The path on the server the cookie is valid for
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* // Set a session cookie that expires in 7 days
|
|
49
|
+
* setCookie('session_id', 'abc123', {
|
|
50
|
+
* expires: 7,
|
|
51
|
+
* secure: true,
|
|
52
|
+
* sameSite: 'strict'
|
|
53
|
+
* });
|
|
54
|
+
*/
|
|
55
|
+
export const setCookie = async (name: string, value: string, options?: CookieSetOptions) => {
|
|
56
|
+
if (typeof window !== "undefined") {
|
|
57
|
+
// Set cookie on the client side without hitting the server
|
|
58
|
+
Cookies.set(name, value, options);
|
|
59
|
+
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Set cookie on the server side
|
|
64
|
+
await setServerCookie(name, value, options);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Removes a cookie from the browser, effectively logging out users or clearing stored preferences.
|
|
69
|
+
* Useful for scenarios like user logout, clearing cached data, or resetting user preferences.
|
|
70
|
+
*
|
|
71
|
+
* @param name - The name of the cookie to remove (e.g., 'auth_token', 'user_session')
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* // Clear user session during logout
|
|
75
|
+
* removeCookie('auth_token');
|
|
76
|
+
* removeCookie('user_preferences');
|
|
77
|
+
*/
|
|
78
|
+
export const removeCookie = async (name: string) => {
|
|
79
|
+
if (typeof window !== "undefined") {
|
|
80
|
+
// Remove cookie on the client side without hitting the server
|
|
81
|
+
return Cookies.remove(name);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Remove cookie on the server side
|
|
85
|
+
return setCookie(name, "", { expires: new Date(0) });
|
|
86
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@carvajalconsultants/headstart",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Library to assist in integrating PostGraphile with Tanstack Start and URQL.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Miguel Carvajal <omar@carvajalonline.com>",
|
|
@@ -9,9 +9,11 @@
|
|
|
9
9
|
"main": "server.ts",
|
|
10
10
|
"files": [
|
|
11
11
|
"client.ts",
|
|
12
|
+
"cookies.ts",
|
|
12
13
|
"grafastExchange.ts",
|
|
13
14
|
"graphQLRouteHandler.ts",
|
|
14
|
-
"server.ts"
|
|
15
|
+
"server.ts",
|
|
16
|
+
"serverCookies.ts"
|
|
15
17
|
],
|
|
16
18
|
"scripts": {
|
|
17
19
|
"lint": "biome check --write"
|
package/serverCookies.ts
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
export interface CookieSetOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Specifies the value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.3|Domain Set-Cookie attribute}. By default, no
|
|
4
|
+
* domain is set, and most clients will consider the cookie to apply to only
|
|
5
|
+
* the current domain.
|
|
6
|
+
*/
|
|
7
|
+
domain?: string | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* Specifies a function that will be used to encode a cookie's value. Since
|
|
10
|
+
* value of a cookie has a limited character set (and must be a simple
|
|
11
|
+
* string), this function can be used to encode a value into a string suited
|
|
12
|
+
* for a cookie's value.
|
|
13
|
+
*
|
|
14
|
+
* The default function is the global `encodeURIComponent`, which will
|
|
15
|
+
* encode a JavaScript string into UTF-8 byte sequences and then URL-encode
|
|
16
|
+
* any that fall outside of the cookie range.
|
|
17
|
+
*/
|
|
18
|
+
encode?(value: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Specifies the `Date` object to be the value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.1|`Expires` `Set-Cookie` attribute}. By default,
|
|
21
|
+
* no expiration is set, and most clients will consider this a "non-persistent cookie" and will delete
|
|
22
|
+
* it on a condition like exiting a web browser application.
|
|
23
|
+
*
|
|
24
|
+
* *Note* the {@link https://tools.ietf.org/html/rfc6265#section-5.3|cookie storage model specification}
|
|
25
|
+
* states that if both `expires` and `maxAge` are set, then `maxAge` takes precedence, but it is
|
|
26
|
+
* possible not all clients by obey this, so if both are set, they should
|
|
27
|
+
* point to the same date and time.
|
|
28
|
+
*/
|
|
29
|
+
expires?: Date | number | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Specifies the boolean value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.6|`HttpOnly` `Set-Cookie` attribute}.
|
|
32
|
+
* When truthy, the `HttpOnly` attribute is set, otherwise it is not. By
|
|
33
|
+
* default, the `HttpOnly` attribute is not set.
|
|
34
|
+
*
|
|
35
|
+
* *Note* be careful when setting this to true, as compliant clients will
|
|
36
|
+
* not allow client-side JavaScript to see the cookie in `document.cookie`.
|
|
37
|
+
*/
|
|
38
|
+
httpOnly?: boolean | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Specifies the number (in seconds) to be the value for the `Max-Age`
|
|
41
|
+
* `Set-Cookie` attribute. The given number will be converted to an integer
|
|
42
|
+
* by rounding down. By default, no maximum age is set.
|
|
43
|
+
*
|
|
44
|
+
* *Note* the {@link https://tools.ietf.org/html/rfc6265#section-5.3|cookie storage model specification}
|
|
45
|
+
* states that if both `expires` and `maxAge` are set, then `maxAge` takes precedence, but it is
|
|
46
|
+
* possible not all clients by obey this, so if both are set, they should
|
|
47
|
+
* point to the same date and time.
|
|
48
|
+
*/
|
|
49
|
+
maxAge?: number | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* Specifies the value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.4|`Path` `Set-Cookie` attribute}.
|
|
52
|
+
* By default, the path is considered the "default path".
|
|
53
|
+
*/
|
|
54
|
+
path?: string | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* Specifies the `string` to be the value for the [`Priority` `Set-Cookie` attribute][rfc-west-cookie-priority-00-4.1].
|
|
57
|
+
*
|
|
58
|
+
* - `'low'` will set the `Priority` attribute to `Low`.
|
|
59
|
+
* - `'medium'` will set the `Priority` attribute to `Medium`, the default priority when not set.
|
|
60
|
+
* - `'high'` will set the `Priority` attribute to `High`.
|
|
61
|
+
*
|
|
62
|
+
* More information about the different priority levels can be found in
|
|
63
|
+
* [the specification][rfc-west-cookie-priority-00-4.1].
|
|
64
|
+
*
|
|
65
|
+
* **note** This is an attribute that has not yet been fully standardized, and may change in the future.
|
|
66
|
+
* This also means many clients may ignore this attribute until they understand it.
|
|
67
|
+
*/
|
|
68
|
+
priority?: "low" | "medium" | "high" | undefined;
|
|
69
|
+
/**
|
|
70
|
+
* Specifies the boolean or string to be the value for the {@link https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7|`SameSite` `Set-Cookie` attribute}.
|
|
71
|
+
*
|
|
72
|
+
* - `true` will set the `SameSite` attribute to `Strict` for strict same
|
|
73
|
+
* site enforcement.
|
|
74
|
+
* - `false` will not set the `SameSite` attribute.
|
|
75
|
+
* - `'lax'` will set the `SameSite` attribute to Lax for lax same site
|
|
76
|
+
* enforcement.
|
|
77
|
+
* - `'strict'` will set the `SameSite` attribute to Strict for strict same
|
|
78
|
+
* site enforcement.
|
|
79
|
+
* - `'none'` will set the SameSite attribute to None for an explicit
|
|
80
|
+
* cross-site cookie.
|
|
81
|
+
*
|
|
82
|
+
* More information about the different enforcement levels can be found in {@link https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7|the specification}.
|
|
83
|
+
*
|
|
84
|
+
* *note* This is an attribute that has not yet been fully standardized, and may change in the future. This also means many clients may ignore this attribute until they understand it.
|
|
85
|
+
*/
|
|
86
|
+
sameSite?: "lax" | "strict" | "none" | undefined;
|
|
87
|
+
/**
|
|
88
|
+
* Specifies the boolean value for the {@link https://tools.ietf.org/html/rfc6265#section-5.2.5|`Secure` `Set-Cookie` attribute}. When truthy, the
|
|
89
|
+
* `Secure` attribute is set, otherwise it is not. By default, the `Secure` attribute is not set.
|
|
90
|
+
*
|
|
91
|
+
* *Note* be careful when setting this to `true`, as compliant clients will
|
|
92
|
+
* not send the cookie back to the server in the future if the browser does
|
|
93
|
+
* not have an HTTPS connection.
|
|
94
|
+
*/
|
|
95
|
+
secure?: boolean | undefined;
|
|
96
|
+
/**
|
|
97
|
+
* Specifies the `boolean` value for the [`Partitioned` `Set-Cookie`](https://datatracker.ietf.org/doc/html/draft-cutler-httpbis-partitioned-cookies#section-2.1)
|
|
98
|
+
* attribute. When truthy, the `Partitioned` attribute is set, otherwise it is not. By default, the
|
|
99
|
+
* `Partitioned` attribute is not set.
|
|
100
|
+
*
|
|
101
|
+
* **note** This is an attribute that has not yet been fully standardized, and may change in the future.
|
|
102
|
+
* This also means many clients may ignore this attribute until they understand it.
|
|
103
|
+
*
|
|
104
|
+
* More information can be found in the [proposal](https://github.com/privacycg/CHIPS).
|
|
105
|
+
*/
|
|
106
|
+
partitioned?: boolean;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Retrieves a cookie value during server-side rendering (SSR)
|
|
111
|
+
* This is useful when you need to access cookies that were set by the server
|
|
112
|
+
* before the page is sent to the client, such as authentication tokens or user preferences
|
|
113
|
+
*
|
|
114
|
+
* @param name - The name of the cookie to retrieve
|
|
115
|
+
* @returns The cookie value if running on the server, undefined if on the client
|
|
116
|
+
*/
|
|
117
|
+
export const getServerCookie = async (name: string) => {
|
|
118
|
+
// Only execute this logic during server-side rendering: https://v3.vitejs.dev/guide/ssr.html#conditional-logic
|
|
119
|
+
if (import.meta.env.SSR) {
|
|
120
|
+
// Dynamically import the cookie getter to avoid loading it on the client bundle
|
|
121
|
+
const { getCookie } = await import("@tanstack/react-start-server");
|
|
122
|
+
|
|
123
|
+
return getCookie(name);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return undefined;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Sets a cookie during server-side rendering (SSR)
|
|
131
|
+
* This is essential for scenarios where you need to set cookies before the initial page load,
|
|
132
|
+
* such as storing session tokens, user preferences, or other server-determined values
|
|
133
|
+
*
|
|
134
|
+
* @param name - The name of the cookie to set
|
|
135
|
+
* @param value - The value to store in the cookie
|
|
136
|
+
* @param options - Cookie configuration options
|
|
137
|
+
* @param options.expires - Expiration date or time in days from now
|
|
138
|
+
* @param options.path - Path where the cookie is valid
|
|
139
|
+
* @param options.domain - Domain where the cookie is valid
|
|
140
|
+
* @param options.secure - Whether the cookie should only be transmitted over HTTPS
|
|
141
|
+
* @param options.httpOnly - Whether the cookie should be inaccessible to JavaScript
|
|
142
|
+
* @param options.sameSite - Controls how the cookie behaves with cross-site requests
|
|
143
|
+
*/
|
|
144
|
+
export const setServerCookie = async (name: string, value: string, options?: CookieSetOptions) => {
|
|
145
|
+
// Only execute this logic during server-side rendering: https://v3.vitejs.dev/guide/ssr.html#conditional-logic
|
|
146
|
+
if (import.meta.env.SSR) {
|
|
147
|
+
// Dynamically import the cookie setter to avoid loading it on the client bundle
|
|
148
|
+
const { setCookie: setStartCookie } = await import("@tanstack/react-start-server");
|
|
149
|
+
|
|
150
|
+
// Set the cookie with provided options, converting numeric expiry to actual date
|
|
151
|
+
// This handles both relative (days from now) and absolute date expiration times
|
|
152
|
+
setStartCookie(name, value, {
|
|
153
|
+
...options,
|
|
154
|
+
expires:
|
|
155
|
+
typeof options?.expires === "number"
|
|
156
|
+
? new Date(Date.now() + options.expires * 864e5) // Convert days to milliseconds (864e5 = 24 * 60 * 60 * 1000)
|
|
157
|
+
: options?.expires,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
};
|