@regardio/js 1.0.2 → 1.1.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
@@ -1,26 +1,25 @@
1
1
  # @regardio/js
2
2
 
3
- > **TypeScript utilities for Regardio applications**
3
+ > TypeScript utilities for Regardio applications.
4
4
 
5
- A collection of lightweight, tree-shakeable utility functions for common tasks
6
- like text manipulation, HTTP handling, internationalization, time formatting, and validation.
5
+ A collection of small, tree-shakeable utilities for the everyday work of text, HTTP, internationalisation, time, and validation — the pieces you end up re-implementing in every project.
7
6
 
8
- ## ⚠️ Pre-release Notice
7
+ ## Pre-release notice
9
8
 
10
- **This package is currently in pre-release (v0.x).** While we use these utilities in production across our own projects, the API may still change between minor versions. We recommend:
9
+ This package is currently at v0.x. The utilities run in production across Regardio's own projects, but the API may still move between minor versions. A few habits that help:
11
10
 
12
- - Pinning to exact versions in your `package.json`
13
- - Reviewing changelogs before upgrading
14
- - Expecting potential breaking changes until v1.0
11
+ - Pin to exact versions in `package.json`
12
+ - Read the changelog before upgrading
13
+ - Expect the occasional breaking change until v1.0
15
14
 
16
- ## Why This Package?
15
+ ## What it's for
17
16
 
18
- We created `@regardio/js` to:
17
+ `@regardio/js` exists so a handful of steady utilities don't have to be reinvented:
19
18
 
20
- - **Share battle-tested utilities** — These functions power real Regardio projects and have been refined through actual use
21
- - **Reduce boilerplate** — Common patterns like text formatting, cookie handling, language detection, and time formatting in one place
22
- - **Stay framework-agnostic** — Works with any JavaScript/TypeScript project (React, Node, Deno, etc.)
23
- - **Enable tree-shaking** — Import only what you need; unused utilities won't bloat your bundle
19
+ - **Shared, well-used helpers** — these functions carry real Regardio projects and have been refined through actual use
20
+ - **Less boilerplate** — text formatting, cookie handling, language detection, and time formatting collected in one place
21
+ - **Framework-agnostic** — works with any JavaScript/TypeScript project (React, Node, Deno, and so on)
22
+ - **Tree-shakeable** — import what's needed, leave the rest out of the bundle
24
23
 
25
24
  ## Installation
26
25
 
@@ -30,9 +29,9 @@ pnpm add @regardio/js
30
29
 
31
30
  ## Modules
32
31
 
33
- ### @regardio/js/text
32
+ ### `@regardio/js/text`
34
33
 
35
- String manipulation and formatting utilities.
34
+ String manipulation and formatting.
36
35
 
37
36
  ```ts
38
37
  import {
@@ -49,9 +48,9 @@ formatBytes(1500000); // "1.5 MB"
49
48
  parseAuthorString('John <john@example.com>'); // { name: 'John', email: 'john@example.com' }
50
49
  ```
51
50
 
52
- ### @regardio/js/time
51
+ ### `@regardio/js/time`
53
52
 
54
- Date, time, and async utilities.
53
+ Date, time, and async helpers.
55
54
 
56
55
  ```ts
57
56
  import {
@@ -68,17 +67,17 @@ await delay(1000); // Wait 1 second
68
67
  await measure('fetchData', () => fetch('/api')); // Logs timing
69
68
  ```
70
69
 
71
- ### @regardio/js/http
70
+ ### `@regardio/js/http`
72
71
 
73
72
  HTTP, cookie, and routing utilities.
74
73
 
75
74
  ```ts
76
75
  import {
77
- // Client-side cookies (async - Cookie Store API + fallback)
76
+ // Client-side cookies (async Cookie Store API + fallback)
78
77
  getCookie,
79
78
  setCookie,
80
79
  deleteCookie,
81
- // Client-side cookies (sync - document.cookie only)
80
+ // Client-side cookies (sync document.cookie only)
82
81
  getCookieSync,
83
82
  setCookieSync,
84
83
  deleteCookieSync,
@@ -121,7 +120,7 @@ const domain = createDomain(request); // "https://example.com"
121
120
  isRouteActive('/account', '/account/settings', false); // true
122
121
  ```
123
122
 
124
- ### @regardio/js/intl
123
+ ### `@regardio/js/intl`
125
124
 
126
125
  Server-side language detection for i18n.
127
126
 
@@ -136,9 +135,9 @@ const detector = new LanguageDetector({
136
135
  const locale = await detector.detect(request);
137
136
  ```
138
137
 
139
- ### @regardio/js/assert
138
+ ### `@regardio/js/assert`
140
139
 
141
- Runtime assertion and validation utilities.
140
+ Runtime assertions and validation.
142
141
 
143
142
  ```ts
144
143
  import { invariant, invariantResponse, verifyAccept } from '@regardio/js/assert';
@@ -148,7 +147,7 @@ invariantResponse(user, 'User not found', { status: 404 }); // Throws Response
148
147
  verifyAccept('image/png', 'image/*'); // true
149
148
  ```
150
149
 
151
- ### @regardio/js/encoding
150
+ ### `@regardio/js/encoding`
152
151
 
153
152
  Binary encoding utilities.
154
153
 
@@ -158,7 +157,7 @@ import { urlBase64ToUint8Array } from '@regardio/js/encoding';
158
157
  const bytes = urlBase64ToUint8Array(vapidPublicKey);
159
158
  ```
160
159
 
161
- ## Module Overview
160
+ ## Module overview
162
161
 
163
162
  | Module | Description |
164
163
  |--------|-------------|
@@ -171,17 +170,16 @@ const bytes = urlBase64ToUint8Array(vapidPublicKey);
171
170
 
172
171
  ## Contributing
173
172
 
174
- This package is primarily maintained for Regardio's internal use, but we welcome:
173
+ The package is maintained primarily for Regardio's own work, but contributions from elsewhere are welcome:
175
174
 
176
175
  - Bug reports and fixes
177
176
  - Documentation improvements
178
- - Feature suggestions (though we may not implement all requests)
177
+ - Feature suggestions (not every one will become an implementation)
179
178
 
180
179
  ## License
181
180
 
182
- **MIT License** — Free to use in commercial and open source projects.
181
+ **MIT** — free to use in commercial and open-source projects.
183
182
 
184
183
  ---
185
184
 
186
- *Part of the [Regardio Ensemble](https://regard.io/ensemble) toolkit for
187
- shared well-being.*
185
+ *Part of the [Regardio Ensemble](https://regard.io/ensemble) toolkit for shared well-being.*
@@ -1,5 +1,243 @@
1
- import { Cookie, SessionStorage } from "react-router";
2
-
1
+ //#region ../../node_modules/.pnpm/cookie@1.1.1/node_modules/cookie/dist/index.d.ts
2
+ /**
3
+ * Parse options.
4
+ */
5
+ interface ParseOptions {
6
+ /**
7
+ * Specifies a function that will be used to decode a [cookie-value](https://datatracker.ietf.org/doc/html/rfc6265#section-4.1.1).
8
+ * Since the value of a cookie has a limited character set (and must be a simple string), this function can be used to decode
9
+ * a previously-encoded cookie value into a JavaScript string.
10
+ *
11
+ * The default function is the global `decodeURIComponent`, wrapped in a `try..catch`. If an error
12
+ * is thrown it will return the cookie's original value. If you provide your own encode/decode
13
+ * scheme you must ensure errors are appropriately handled.
14
+ *
15
+ * @default decode
16
+ */
17
+ decode?: (str: string) => string | undefined;
18
+ }
19
+ interface StringifyOptions {
20
+ /**
21
+ * Specifies a function that will be used to encode a [cookie-value](https://datatracker.ietf.org/doc/html/rfc6265#section-4.1.1).
22
+ * Since value of a cookie has a limited character set (and must be a simple string), this function can be used to encode
23
+ * a value into a string suited for a cookie's value, and should mirror `decode` when parsing.
24
+ *
25
+ * @default encodeURIComponent
26
+ */
27
+ encode?: (str: string) => string;
28
+ }
29
+ /**
30
+ * Set-Cookie object.
31
+ */
32
+ interface SetCookie {
33
+ /**
34
+ * Specifies the name of the cookie.
35
+ */
36
+ name: string;
37
+ /**
38
+ * Specifies the string to be the value for the cookie.
39
+ */
40
+ value: string | undefined;
41
+ /**
42
+ * Specifies the `number` (in seconds) to be the value for the [`Max-Age` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.2).
43
+ *
44
+ * The [cookie storage model specification](https://tools.ietf.org/html/rfc6265#section-5.3) states that if both `expires` and
45
+ * `maxAge` are set, then `maxAge` takes precedence, but it is possible not all clients by obey this,
46
+ * so if both are set, they should point to the same date and time.
47
+ */
48
+ maxAge?: number;
49
+ /**
50
+ * Specifies the `Date` object to be the value for the [`Expires` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.1).
51
+ * When no expiration is set, clients consider this a "non-persistent cookie" and delete it when the current session is over.
52
+ *
53
+ * The [cookie storage model specification](https://tools.ietf.org/html/rfc6265#section-5.3) states that if both `expires` and
54
+ * `maxAge` are set, then `maxAge` takes precedence, but it is possible not all clients by obey this,
55
+ * so if both are set, they should point to the same date and time.
56
+ */
57
+ expires?: Date;
58
+ /**
59
+ * Specifies the value for the [`Domain` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.3).
60
+ * When no domain is set, clients consider the cookie to apply to the current domain only.
61
+ */
62
+ domain?: string;
63
+ /**
64
+ * Specifies the value for the [`Path` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.4).
65
+ * When no path is set, the path is considered the ["default path"](https://tools.ietf.org/html/rfc6265#section-5.1.4).
66
+ */
67
+ path?: string;
68
+ /**
69
+ * Enables the [`HttpOnly` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.6).
70
+ * When enabled, clients will not allow client-side JavaScript to see the cookie in `document.cookie`.
71
+ */
72
+ httpOnly?: boolean;
73
+ /**
74
+ * Enables the [`Secure` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.5).
75
+ * When enabled, clients will only send the cookie back if the browser has an HTTPS connection.
76
+ */
77
+ secure?: boolean;
78
+ /**
79
+ * Enables the [`Partitioned` `Set-Cookie` attribute](https://tools.ietf.org/html/draft-cutler-httpbis-partitioned-cookies/).
80
+ * When enabled, clients will only send the cookie back when the current domain _and_ top-level domain matches.
81
+ *
82
+ * This is an attribute that has not yet been fully standardized, and may change in the future.
83
+ * This also means clients may ignore this attribute until they understand it. More information
84
+ * about can be found in [the proposal](https://github.com/privacycg/CHIPS).
85
+ */
86
+ partitioned?: boolean;
87
+ /**
88
+ * Specifies the value for the [`Priority` `Set-Cookie` attribute](https://tools.ietf.org/html/draft-west-cookie-priority-00#section-4.1).
89
+ *
90
+ * - `'low'` will set the `Priority` attribute to `Low`.
91
+ * - `'medium'` will set the `Priority` attribute to `Medium`, the default priority when not set.
92
+ * - `'high'` will set the `Priority` attribute to `High`.
93
+ *
94
+ * More information about priority levels can be found in [the specification](https://tools.ietf.org/html/draft-west-cookie-priority-00#section-4.1).
95
+ */
96
+ priority?: "low" | "medium" | "high";
97
+ /**
98
+ * Specifies the value for the [`SameSite` `Set-Cookie` attribute](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-09#section-5.4.7).
99
+ *
100
+ * - `true` will set the `SameSite` attribute to `Strict` for strict same site enforcement.
101
+ * - `'lax'` will set the `SameSite` attribute to `Lax` for lax same site enforcement.
102
+ * - `'none'` will set the `SameSite` attribute to `None` for an explicit cross-site cookie.
103
+ * - `'strict'` will set the `SameSite` attribute to `Strict` for strict same site enforcement.
104
+ *
105
+ * More information about enforcement levels can be found in [the specification](https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-09#section-5.4.7).
106
+ */
107
+ sameSite?: boolean | "lax" | "strict" | "none";
108
+ }
109
+ /**
110
+ * Backward compatibility serialize options.
111
+ */
112
+ type SerializeOptions = StringifyOptions & Omit<SetCookie, "name" | "value">;
113
+ //#endregion
114
+ //#region ../../node_modules/.pnpm/react-router@7.15.0_react-dom@19.2.5_react@19.2.5__react@19.2.5/node_modules/react-router/dist/development/index.d.mts
115
+ /**
116
+ * A HTTP cookie.
117
+ *
118
+ * A Cookie is a logical container for metadata about a HTTP cookie; its name
119
+ * and options. But it doesn't contain a value. Instead, it has `parse()` and
120
+ * `serialize()` methods that allow a single instance to be reused for
121
+ * parsing/encoding multiple different values.
122
+ *
123
+ * @see https://remix.run/utils/cookies#cookie-api
124
+ */
125
+ interface Cookie {
126
+ /**
127
+ * The name of the cookie, used in the `Cookie` and `Set-Cookie` headers.
128
+ */
129
+ readonly name: string;
130
+ /**
131
+ * True if this cookie uses one or more secrets for verification.
132
+ */
133
+ readonly isSigned: boolean;
134
+ /**
135
+ * The Date this cookie expires.
136
+ *
137
+ * Note: This is calculated at access time using `maxAge` when no `expires`
138
+ * option is provided to `createCookie()`.
139
+ */
140
+ readonly expires?: Date;
141
+ /**
142
+ * Parses a raw `Cookie` header and returns the value of this cookie or
143
+ * `null` if it's not present.
144
+ */
145
+ parse(cookieHeader: string | null, options?: ParseOptions): Promise<any>;
146
+ /**
147
+ * Serializes the given value to a string and returns the `Set-Cookie`
148
+ * header.
149
+ */
150
+ serialize(value: any, options?: SerializeOptions): Promise<string>;
151
+ }
152
+ /**
153
+ * Creates a logical container for managing a browser cookie from the server.
154
+ */
155
+ /**
156
+ * An object of name/value pairs to be used in the session.
157
+ */
158
+ interface SessionData {
159
+ [name: string]: any;
160
+ }
161
+ /**
162
+ * Session persists data across HTTP requests.
163
+ *
164
+ * @see https://reactrouter.com/explanation/sessions-and-cookies#sessions
165
+ */
166
+ interface Session<Data = SessionData, FlashData = Data> {
167
+ /**
168
+ * A unique identifier for this session.
169
+ *
170
+ * Note: This will be the empty string for newly created sessions and
171
+ * sessions that are not backed by a database (i.e. cookie-based sessions).
172
+ */
173
+ readonly id: string;
174
+ /**
175
+ * The raw data contained in this session.
176
+ *
177
+ * This is useful mostly for SessionStorage internally to access the raw
178
+ * session data to persist.
179
+ */
180
+ readonly data: FlashSessionData<Data, FlashData>;
181
+ /**
182
+ * Returns `true` if the session has a value for the given `name`, `false`
183
+ * otherwise.
184
+ */
185
+ has(name: (keyof Data | keyof FlashData) & string): boolean;
186
+ /**
187
+ * Returns the value for the given `name` in this session.
188
+ */
189
+ get<Key extends (keyof Data | keyof FlashData) & string>(name: Key): (Key extends keyof Data ? Data[Key] : undefined) | (Key extends keyof FlashData ? FlashData[Key] : undefined) | undefined;
190
+ /**
191
+ * Sets a value in the session for the given `name`.
192
+ */
193
+ set<Key extends keyof Data & string>(name: Key, value: Data[Key]): void;
194
+ /**
195
+ * Sets a value in the session that is only valid until the next `get()`.
196
+ * This can be useful for temporary values, like error messages.
197
+ */
198
+ flash<Key extends keyof FlashData & string>(name: Key, value: FlashData[Key]): void;
199
+ /**
200
+ * Removes a value from the session.
201
+ */
202
+ unset(name: keyof Data & string): void;
203
+ }
204
+ type FlashSessionData<Data, FlashData> = Partial<Data & { [Key in keyof FlashData as FlashDataKey<Key & string>]: FlashData[Key] }>;
205
+ type FlashDataKey<Key extends string> = `__flash_${Key}__`;
206
+ /**
207
+ * SessionStorage stores session data between HTTP requests and knows how to
208
+ * parse and create cookies.
209
+ *
210
+ * A SessionStorage creates Session objects using a `Cookie` header as input.
211
+ * Then, later it generates the `Set-Cookie` header to be used in the response.
212
+ */
213
+ interface SessionStorage<Data = SessionData, FlashData = Data> {
214
+ /**
215
+ * Parses a Cookie header from a HTTP request and returns the associated
216
+ * Session. If there is no session associated with the cookie, this will
217
+ * return a new Session with no data.
218
+ */
219
+ getSession: (cookieHeader?: string | null, options?: ParseOptions) => Promise<Session<Data, FlashData>>;
220
+ /**
221
+ * Stores all data in the Session and returns the Set-Cookie header to be
222
+ * used in the HTTP response.
223
+ */
224
+ commitSession: (session: Session<Data, FlashData>, options?: SerializeOptions) => Promise<string>;
225
+ /**
226
+ * Deletes all data associated with the Session and returns the Set-Cookie
227
+ * header to be used in the HTTP response.
228
+ */
229
+ destroySession: (session: Session<Data, FlashData>, options?: SerializeOptions) => Promise<string>;
230
+ }
231
+ /**
232
+ * SessionIdStorageStrategy is designed to allow anyone to easily build their
233
+ * own SessionStorage using `createSessionStorage(strategy)`.
234
+ *
235
+ * This strategy describes a common scenario where the session id is stored in
236
+ * a cookie but the actual session data is stored elsewhere, usually in a
237
+ * database or on disk. A set of create, read, update, and delete operations
238
+ * are provided for managing the session data.
239
+ */
240
+ //#endregion
3
241
  //#region src/intl/language-detector.d.ts
4
242
  interface LanguageDetectorOption {
5
243
  /**
@@ -5,7 +5,7 @@ function formatBytes(bytes, decimals = 2) {
5
5
  * In binary - change k to 1024
6
6
  */
7
7
  const k = 1e3;
8
- const dm = decimals < 0 ? 0 : decimals;
8
+ const dm = Math.max(decimals, 0);
9
9
  const sizes = [
10
10
  "Bytes",
11
11
  "KB",
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": "1.0.2",
4
+ "version": "1.1.1",
5
5
  "private": false,
6
6
  "description": "Regardio JavaScript utilities",
7
7
  "keywords": [
@@ -54,27 +54,32 @@
54
54
  }
55
55
  },
56
56
  "files": [
57
- "dist"
57
+ "dist",
58
+ "pnpm-lock.yaml"
58
59
  ],
59
60
  "dependencies": {
60
61
  "cookie-es": "3.1.1",
61
- "intl-parse-accept-language": "1.0.0",
62
- "react-router": "7.14.2"
62
+ "intl-parse-accept-language": "1.0.0"
63
63
  },
64
64
  "devDependencies": {
65
+ "react-router": "7.15.0",
65
66
  "@total-typescript/ts-reset": "0.6.1",
66
67
  "@types/node": "25.6.0",
67
68
  "@vitest/coverage-v8": "4.1.5",
68
69
  "@vitest/ui": "4.1.5",
69
- "tsdown": "0.21.9",
70
+ "tsdown": "0.21.10",
70
71
  "vitest": "4.1.5",
71
- "@regardio/dev": "2.0.2"
72
+ "@regardio/dev": "2.3.0"
72
73
  },
73
74
  "scripts": {
74
75
  "build": "tsdown",
75
76
  "clean": "rimraf .turbo dist",
76
77
  "dev": "tsdown --watch",
77
78
  "fix": "run-s fix:pkg fix:md fix:biome",
79
+ "release": "commit-and-tag-version",
80
+ "release:major": "commit-and-tag-version --release-as major",
81
+ "release:minor": "commit-and-tag-version --release-as minor",
82
+ "release:patch": "commit-and-tag-version --release-as patch",
78
83
  "fix:biome": "biome check --write --unsafe .",
79
84
  "fix:md": "markdownlint-cli2 --config ../../.markdownlint-cli2.jsonc --fix",
80
85
  "fix:pkg": "sort-package-json",