@octanejs/remix-router 0.1.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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +90 -0
  3. package/package.json +53 -0
  4. package/src/dom.ts +16 -0
  5. package/src/index.ts +267 -0
  6. package/src/internal.ts +37 -0
  7. package/src/lib/Await.tsrx +145 -0
  8. package/src/lib/Await.tsrx.d.ts +6 -0
  9. package/src/lib/DefaultErrorComponent.tsrx +47 -0
  10. package/src/lib/DefaultErrorComponent.tsrx.d.ts +2 -0
  11. package/src/lib/RenderErrorBoundary.tsrx +117 -0
  12. package/src/lib/RenderErrorBoundary.tsrx.d.ts +14 -0
  13. package/src/lib/actions.ts +90 -0
  14. package/src/lib/components/MemoryRouter.tsrx +42 -0
  15. package/src/lib/components/MemoryRouter.tsrx.d.ts +10 -0
  16. package/src/lib/components/Navigate.ts +60 -0
  17. package/src/lib/components/Router.tsrx +88 -0
  18. package/src/lib/components/Router.tsrx.d.ts +13 -0
  19. package/src/lib/components/RouterProvider.tsrx +320 -0
  20. package/src/lib/components/RouterProvider.tsrx.d.ts +21 -0
  21. package/src/lib/components/Routes.tsrx +53 -0
  22. package/src/lib/components/Routes.tsrx.d.ts +7 -0
  23. package/src/lib/components/routes-collector.ts +317 -0
  24. package/src/lib/components/utils.ts +171 -0
  25. package/src/lib/components/with-props.ts +72 -0
  26. package/src/lib/context.ts +129 -0
  27. package/src/lib/dom/Form.tsrx +76 -0
  28. package/src/lib/dom/Form.tsrx.d.ts +22 -0
  29. package/src/lib/dom/Link.tsrx +91 -0
  30. package/src/lib/dom/Link.tsrx.d.ts +22 -0
  31. package/src/lib/dom/NavLink.tsrx +118 -0
  32. package/src/lib/dom/NavLink.tsrx.d.ts +33 -0
  33. package/src/lib/dom/dom.ts +344 -0
  34. package/src/lib/dom/hooks.ts +93 -0
  35. package/src/lib/dom/lib.ts +822 -0
  36. package/src/lib/dom/routers.tsrx +104 -0
  37. package/src/lib/dom/routers.tsrx.d.ts +23 -0
  38. package/src/lib/dom/server.tsrx +350 -0
  39. package/src/lib/dom/server.tsrx.d.ts +25 -0
  40. package/src/lib/errors.ts +84 -0
  41. package/src/lib/framework-stubs.ts +103 -0
  42. package/src/lib/hooks.ts +1797 -0
  43. package/src/lib/href.ts +71 -0
  44. package/src/lib/react-types.ts +10 -0
  45. package/src/lib/router/history.ts +763 -0
  46. package/src/lib/router/instrumentation.ts +496 -0
  47. package/src/lib/router/links.ts +192 -0
  48. package/src/lib/router/router.ts +7165 -0
  49. package/src/lib/router/server-runtime-types.ts +12 -0
  50. package/src/lib/router/url.ts +8 -0
  51. package/src/lib/router/utils.ts +2179 -0
  52. package/src/lib/server-runtime/cookies.ts +240 -0
  53. package/src/lib/server-runtime/crypto.ts +55 -0
  54. package/src/lib/server-runtime/mode.ts +16 -0
  55. package/src/lib/server-runtime/sessions/cookieStorage.ts +54 -0
  56. package/src/lib/server-runtime/sessions/memoryStorage.ts +59 -0
  57. package/src/lib/server-runtime/sessions.ts +291 -0
  58. package/src/lib/server-runtime/warnings.ts +10 -0
  59. package/src/lib/types/future.ts +16 -0
  60. package/src/lib/types/params.ts +8 -0
  61. package/src/lib/types/register.ts +39 -0
  62. package/src/lib/types/route-module.ts +17 -0
  63. package/src/lib/types/utils.ts +37 -0
@@ -0,0 +1,291 @@
1
+ // Vendored from react-router@7.18.1 packages/react-router/lib/server-runtime/sessions.ts — unmodified.
2
+ // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
+ import type { ParseOptions, SerializeOptions } from 'cookie';
4
+
5
+ import type { Cookie, CookieOptions } from './cookies';
6
+ import { createCookie, isCookie } from './cookies';
7
+ import { warnOnce } from './warnings';
8
+
9
+ /**
10
+ * An object of name/value pairs to be used in the session.
11
+ */
12
+ export interface SessionData {
13
+ [name: string]: any;
14
+ }
15
+
16
+ /**
17
+ * Session persists data across HTTP requests.
18
+ *
19
+ * @see https://reactrouter.com/explanation/sessions-and-cookies#sessions
20
+ */
21
+ export interface Session<Data = SessionData, FlashData = Data> {
22
+ /**
23
+ * A unique identifier for this session.
24
+ *
25
+ * Note: This will be the empty string for newly created sessions and
26
+ * sessions that are not backed by a database (i.e. cookie-based sessions).
27
+ */
28
+ readonly id: string;
29
+
30
+ /**
31
+ * The raw data contained in this session.
32
+ *
33
+ * This is useful mostly for SessionStorage internally to access the raw
34
+ * session data to persist.
35
+ */
36
+ readonly data: FlashSessionData<Data, FlashData>;
37
+
38
+ /**
39
+ * Returns `true` if the session has a value for the given `name`, `false`
40
+ * otherwise.
41
+ */
42
+ has(name: (keyof Data | keyof FlashData) & string): boolean;
43
+
44
+ /**
45
+ * Returns the value for the given `name` in this session.
46
+ */
47
+ get<Key extends (keyof Data | keyof FlashData) & string>(
48
+ name: Key,
49
+ ):
50
+ | (Key extends keyof Data ? Data[Key] : undefined)
51
+ | (Key extends keyof FlashData ? FlashData[Key] : undefined)
52
+ | undefined;
53
+
54
+ /**
55
+ * Sets a value in the session for the given `name`.
56
+ */
57
+ set<Key extends keyof Data & string>(name: Key, value: Data[Key]): void;
58
+
59
+ /**
60
+ * Sets a value in the session that is only valid until the next `get()`.
61
+ * This can be useful for temporary values, like error messages.
62
+ */
63
+ flash<Key extends keyof FlashData & string>(name: Key, value: FlashData[Key]): void;
64
+
65
+ /**
66
+ * Removes a value from the session.
67
+ */
68
+ unset(name: keyof Data & string): void;
69
+ }
70
+
71
+ export type FlashSessionData<Data, FlashData> = Partial<
72
+ Data & {
73
+ [Key in keyof FlashData as FlashDataKey<Key & string>]: FlashData[Key];
74
+ }
75
+ >;
76
+ type FlashDataKey<Key extends string> = `__flash_${Key}__`;
77
+ function flash<Key extends string>(name: Key): FlashDataKey<Key> {
78
+ return `__flash_${name}__`;
79
+ }
80
+
81
+ export type CreateSessionFunction = <Data = SessionData, FlashData = Data>(
82
+ initialData?: Data,
83
+ id?: string,
84
+ ) => Session<Data, FlashData>;
85
+
86
+ /**
87
+ * Creates a new Session object.
88
+ *
89
+ * Note: This function is typically not invoked directly by application code.
90
+ * Instead, use a `SessionStorage` object's `getSession` method.
91
+ */
92
+ export const createSession: CreateSessionFunction = <Data = SessionData, FlashData = Data>(
93
+ initialData: Partial<Data> = {},
94
+ id = '',
95
+ ): Session<Data, FlashData> => {
96
+ let map = new Map(Object.entries(initialData)) as Map<
97
+ keyof Data | FlashDataKey<keyof FlashData & string>,
98
+ any
99
+ >;
100
+
101
+ return {
102
+ get id() {
103
+ return id;
104
+ },
105
+ get data() {
106
+ return Object.fromEntries(map) as FlashSessionData<Data, FlashData>;
107
+ },
108
+ has(name) {
109
+ return map.has(name as keyof Data) || map.has(flash(name as keyof FlashData & string));
110
+ },
111
+ get(name) {
112
+ if (map.has(name as keyof Data)) return map.get(name as keyof Data);
113
+
114
+ let flashName = flash(name as keyof FlashData & string);
115
+ if (map.has(flashName)) {
116
+ let value = map.get(flashName);
117
+ map.delete(flashName);
118
+ return value;
119
+ }
120
+
121
+ return undefined;
122
+ },
123
+ set(name, value) {
124
+ map.set(name, value);
125
+ },
126
+ flash(name, value) {
127
+ map.set(flash(name), value);
128
+ },
129
+ unset(name) {
130
+ map.delete(name);
131
+ },
132
+ };
133
+ };
134
+
135
+ export type IsSessionFunction = (object: any) => object is Session;
136
+
137
+ /**
138
+ * Returns true if an object is a React Router session.
139
+ *
140
+ * @see https://reactrouter.com/api/utils/isSession
141
+ */
142
+ export const isSession: IsSessionFunction = (object): object is Session => {
143
+ return (
144
+ object != null &&
145
+ typeof object.id === 'string' &&
146
+ typeof object.data !== 'undefined' &&
147
+ typeof object.has === 'function' &&
148
+ typeof object.get === 'function' &&
149
+ typeof object.set === 'function' &&
150
+ typeof object.flash === 'function' &&
151
+ typeof object.unset === 'function'
152
+ );
153
+ };
154
+
155
+ /**
156
+ * SessionStorage stores session data between HTTP requests and knows how to
157
+ * parse and create cookies.
158
+ *
159
+ * A SessionStorage creates Session objects using a `Cookie` header as input.
160
+ * Then, later it generates the `Set-Cookie` header to be used in the response.
161
+ */
162
+ export interface SessionStorage<Data = SessionData, FlashData = Data> {
163
+ /**
164
+ * Parses a Cookie header from a HTTP request and returns the associated
165
+ * Session. If there is no session associated with the cookie, this will
166
+ * return a new Session with no data.
167
+ */
168
+ getSession: (
169
+ cookieHeader?: string | null,
170
+ options?: ParseOptions,
171
+ ) => Promise<Session<Data, FlashData>>;
172
+
173
+ /**
174
+ * Stores all data in the Session and returns the Set-Cookie header to be
175
+ * used in the HTTP response.
176
+ */
177
+ commitSession: (session: Session<Data, FlashData>, options?: SerializeOptions) => Promise<string>;
178
+
179
+ /**
180
+ * Deletes all data associated with the Session and returns the Set-Cookie
181
+ * header to be used in the HTTP response.
182
+ */
183
+ destroySession: (
184
+ session: Session<Data, FlashData>,
185
+ options?: SerializeOptions,
186
+ ) => Promise<string>;
187
+ }
188
+
189
+ /**
190
+ * SessionIdStorageStrategy is designed to allow anyone to easily build their
191
+ * own SessionStorage using `createSessionStorage(strategy)`.
192
+ *
193
+ * This strategy describes a common scenario where the session id is stored in
194
+ * a cookie but the actual session data is stored elsewhere, usually in a
195
+ * database or on disk. A set of create, read, update, and delete operations
196
+ * are provided for managing the session data.
197
+ */
198
+ export interface SessionIdStorageStrategy<Data = SessionData, FlashData = Data> {
199
+ /**
200
+ * The Cookie used to store the session id, or options used to automatically
201
+ * create one.
202
+ */
203
+ cookie?: Cookie | (CookieOptions & { name?: string });
204
+
205
+ /**
206
+ * Creates a new record with the given data and returns the session id.
207
+ */
208
+ createData: (data: FlashSessionData<Data, FlashData>, expires?: Date) => Promise<string>;
209
+
210
+ /**
211
+ * Returns data for a given session id, or `null` if there isn't any.
212
+ */
213
+ readData: (id: string) => Promise<FlashSessionData<Data, FlashData> | null>;
214
+
215
+ /**
216
+ * Updates data for the given session id.
217
+ */
218
+ updateData: (
219
+ id: string,
220
+ data: FlashSessionData<Data, FlashData>,
221
+ expires?: Date,
222
+ ) => Promise<void>;
223
+
224
+ /**
225
+ * Deletes data for a given session id from the data store.
226
+ */
227
+ deleteData: (id: string) => Promise<void>;
228
+ }
229
+
230
+ /**
231
+ * Creates a SessionStorage object using a SessionIdStorageStrategy.
232
+ *
233
+ * Note: This is a low-level API that should only be used if none of the
234
+ * existing session storage options meet your requirements.
235
+ */
236
+ export function createSessionStorage<Data = SessionData, FlashData = Data>({
237
+ cookie: cookieArg,
238
+ createData,
239
+ readData,
240
+ updateData,
241
+ deleteData,
242
+ }: SessionIdStorageStrategy<Data, FlashData>): SessionStorage<Data, FlashData> {
243
+ let cookie = isCookie(cookieArg)
244
+ ? cookieArg
245
+ : createCookie(cookieArg?.name || '__session', cookieArg);
246
+
247
+ warnOnceAboutSigningSessionCookie(cookie);
248
+
249
+ return {
250
+ async getSession(cookieHeader, options) {
251
+ let id = cookieHeader && (await cookie.parse(cookieHeader, options));
252
+ let data = id && (await readData(id));
253
+ return createSession(data || {}, id || '');
254
+ },
255
+ async commitSession(session, options) {
256
+ let { id, data } = session;
257
+ let expires =
258
+ options?.maxAge != null
259
+ ? new Date(Date.now() + options.maxAge * 1000)
260
+ : options?.expires != null
261
+ ? options.expires
262
+ : cookie.expires;
263
+
264
+ if (id) {
265
+ await updateData(id, data, expires);
266
+ } else {
267
+ id = await createData(data, expires);
268
+ }
269
+
270
+ return cookie.serialize(id, options);
271
+ },
272
+ async destroySession(session, options) {
273
+ await deleteData(session.id);
274
+ return cookie.serialize('', {
275
+ ...options,
276
+ maxAge: undefined,
277
+ expires: new Date(0),
278
+ });
279
+ },
280
+ };
281
+ }
282
+
283
+ export function warnOnceAboutSigningSessionCookie(cookie: Cookie) {
284
+ warnOnce(
285
+ cookie.isSigned,
286
+ `The "${cookie.name}" cookie is not signed, but session cookies should be ` +
287
+ `signed to prevent tampering on the client before they are sent back to the ` +
288
+ `server. See https://reactrouter.com/explanation/sessions-and-cookies#signing-cookies ` +
289
+ `for more information.`,
290
+ );
291
+ }
@@ -0,0 +1,10 @@
1
+ // Vendored from react-router@7.18.1 packages/react-router/lib/server-runtime/warnings.ts — unmodified.
2
+ // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
+ const alreadyWarned: { [message: string]: boolean } = {};
4
+
5
+ export function warnOnce(condition: boolean, message: string): void {
6
+ if (!condition && !alreadyWarned[message]) {
7
+ alreadyWarned[message] = true;
8
+ console.warn(message);
9
+ }
10
+ }
@@ -0,0 +1,16 @@
1
+ // Vendored from react-router@7.18.1 packages/react-router/lib/types/future.ts — unmodified.
2
+ // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
+ /**
4
+ * An augmentable interface users can modify in their app-code to opt into
5
+ * future-flag-specific types
6
+ */
7
+ export interface Future {
8
+ // We list the potential fields here in comments strictly for clarity.
9
+ // They will be generated by the react-router/dev/typegen/generate.ts module
10
+ //
11
+ // v8_middleware: boolean
12
+ }
13
+
14
+ // prettier-ignore
15
+ export type MiddlewareEnabled =
16
+ Future extends { v8_middleware: infer T extends boolean; } ? T : false
@@ -0,0 +1,8 @@
1
+ // Vendored from react-router@7.18.1 packages/react-router/lib/types/params.ts — unmodified.
2
+ // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
+ import type { Pages, RouteFiles } from './register';
4
+ import type { Normalize } from './utils';
5
+
6
+ export type Params<RouteFile extends keyof RouteFiles> = Normalize<
7
+ Pages[RouteFiles[RouteFile]['page']]['params']
8
+ >;
@@ -0,0 +1,39 @@
1
+ // Vendored from react-router@7.18.1 packages/react-router/lib/types/register.ts — unmodified.
2
+ // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
+ import type { RouteModule } from './route-module';
4
+
5
+ /**
6
+ * Apps can use this interface to "register" app-wide types for React Router via interface declaration merging and module augmentation.
7
+ * React Router should handle this for you via type generation.
8
+ *
9
+ * For more on declaration merging and module augmentation, see https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation .
10
+ */
11
+ export interface Register {
12
+ // pages
13
+ // routeFiles
14
+ // routeModules
15
+ }
16
+
17
+ // pages
18
+ type AnyParams = Record<string, string | undefined>;
19
+ type AnyPages = Record<string, { params: AnyParams }>;
20
+ export type Pages = Register extends {
21
+ pages: infer Registered extends AnyPages;
22
+ }
23
+ ? Registered
24
+ : AnyPages;
25
+
26
+ // route files
27
+ type AnyRouteFiles = Record<string, { id: string; page: string }>;
28
+ export type RouteFiles = Register extends {
29
+ routeFiles: infer Registered extends AnyRouteFiles;
30
+ }
31
+ ? Registered
32
+ : AnyRouteFiles;
33
+
34
+ type AnyRouteModules = Record<string, RouteModule>;
35
+ export type RouteModules = Register extends {
36
+ routeModules: infer Registered extends AnyRouteModules;
37
+ }
38
+ ? Registered
39
+ : AnyRouteModules;
@@ -0,0 +1,17 @@
1
+ // Vendored from react-router@7.18.1 packages/react-router/lib/types/route-module.ts — unmodified.
2
+ // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
+ import type { Func } from './utils';
4
+
5
+ export type RouteModule = {
6
+ meta?: Func;
7
+ links?: Func;
8
+ headers?: Func;
9
+ loader?: Func;
10
+ clientLoader?: Func;
11
+ action?: Func;
12
+ clientAction?: Func;
13
+ HydrateFallback?: Func;
14
+ default?: Func;
15
+ ErrorBoundary?: Func;
16
+ [key: string]: unknown; // allow user-defined exports
17
+ };
@@ -0,0 +1,37 @@
1
+ // Vendored from react-router@7.18.1 packages/react-router/lib/types/utils.ts — unmodified.
2
+ // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
+ export type Expect<T extends true> = T;
4
+
5
+ // prettier-ignore
6
+ export type Equal<X, Y> =
7
+ (<T>() => T extends X ? 1 : 2) extends
8
+ (<T>() => T extends Y ? 1 : 2) ? true : false
9
+
10
+ export type IsAny<T> = 0 extends 1 & T ? true : false;
11
+
12
+ export type Func = (...args: any[]) => unknown;
13
+
14
+ export type Pretty<T> = { [K in keyof T]: T[K] } & {};
15
+
16
+ // Emulates https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#improved-type-inference-for-object-literals
17
+ export type Normalize<T> = _Normalize<UnionKeys<T>, T>;
18
+ // prettier-ignore
19
+ type _Normalize<Key extends keyof any, T> =
20
+ T extends infer U ?
21
+ Pretty<
22
+ & { [K in Key as K extends keyof U ? undefined extends U[K] ? never : K : never]: K extends keyof U ? U[K] : never }
23
+ & { [K in Key as K extends keyof U ? undefined extends U[K] ? K : never : never]?: K extends keyof U ? U[K] : never }
24
+ & { [K in Key as K extends keyof U ? never : K]?: undefined}
25
+ >
26
+ :
27
+ never
28
+ type UnionKeys<T> = T extends any ? keyof T : never;
29
+
30
+ // prettier-ignore
31
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
32
+ type __tests = [
33
+ Expect<Equal<Normalize<{}>, {}>>,
34
+ Expect<Equal<Normalize<{a: string}>, {a: string}>>,
35
+ Expect<Equal<Normalize<{a: string} | {b: string}>, {a: string, b?: undefined} | {a?: undefined , b: string}>>,
36
+ Expect<Equal<Normalize<{a?: string} | {b?: string}>, {a?: string, b?: undefined} | {a?: undefined , b?: string}>>,
37
+ ]