@real-router/persistent-params-plugin 0.1.1 → 0.1.3
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 +53 -385
- package/dist/cjs/index.d.ts +1556 -5
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/metafile-cjs.json +1 -1
- package/dist/esm/index.d.mts +1556 -5
- package/dist/esm/index.mjs +1 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/metafile-esm.json +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -3,31 +3,21 @@
|
|
|
3
3
|
[](https://opensource.org/licenses/MIT)
|
|
4
4
|
[](https://www.typescriptlang.org/)
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Automatically persists query parameters across all navigation transitions.
|
|
7
7
|
|
|
8
|
-
## Problem
|
|
9
|
-
|
|
10
|
-
In SPA applications, certain query parameters should persist between routes:
|
|
8
|
+
## Problem & Solution
|
|
11
9
|
|
|
12
10
|
```typescript
|
|
13
11
|
// Without plugin:
|
|
14
|
-
router.navigate("products", {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
router.navigate("cart", { id: "2" });
|
|
18
|
-
// URL: /cart/2 ← lang and theme are lost
|
|
19
|
-
```
|
|
12
|
+
router.navigate("products", { lang: "en", theme: "dark" });
|
|
13
|
+
router.navigate("cart");
|
|
14
|
+
// URL: /cart ← lang and theme are lost
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
```typescript
|
|
16
|
+
// With plugin:
|
|
24
17
|
router.usePlugin(persistentParamsPluginFactory(["lang", "theme"]));
|
|
25
|
-
|
|
26
|
-
router.navigate("
|
|
27
|
-
// URL: /
|
|
28
|
-
|
|
29
|
-
router.navigate("cart", { id: "2" });
|
|
30
|
-
// URL: /cart/2?lang=en&theme=dark ← automatically added
|
|
18
|
+
router.navigate("products", { lang: "en", theme: "dark" });
|
|
19
|
+
router.navigate("cart");
|
|
20
|
+
// URL: /cart?lang=en&theme=dark ← automatically preserved
|
|
31
21
|
```
|
|
32
22
|
|
|
33
23
|
## Installation
|
|
@@ -48,16 +38,12 @@ bun add @real-router/persistent-params-plugin
|
|
|
48
38
|
import { createRouter } from "@real-router/core";
|
|
49
39
|
import { persistentParamsPluginFactory } from "@real-router/persistent-params-plugin";
|
|
50
40
|
|
|
51
|
-
const router = createRouter(
|
|
52
|
-
{ name: "home", path: "/" },
|
|
53
|
-
{ name: "products", path: "/products/:id" },
|
|
54
|
-
{ name: "cart", path: "/cart" },
|
|
55
|
-
]);
|
|
41
|
+
const router = createRouter(routes);
|
|
56
42
|
|
|
57
|
-
// Option 1:
|
|
43
|
+
// Option 1: Parameter names (values set on first use)
|
|
58
44
|
router.usePlugin(persistentParamsPluginFactory(["lang", "theme"]));
|
|
59
45
|
|
|
60
|
-
// Option 2:
|
|
46
|
+
// Option 2: With default values
|
|
61
47
|
router.usePlugin(
|
|
62
48
|
persistentParamsPluginFactory({
|
|
63
49
|
lang: "en",
|
|
@@ -68,334 +54,65 @@ router.usePlugin(
|
|
|
68
54
|
router.start();
|
|
69
55
|
```
|
|
70
56
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
### `persistentParamsPluginFactory(config?)`
|
|
74
|
-
|
|
75
|
-
#### Parameters
|
|
76
|
-
|
|
77
|
-
**`config`**: `string[] | Record<string, string | number | boolean>` (optional, defaults to `{}`)
|
|
78
|
-
|
|
79
|
-
- **Array of strings**: parameter names to persist (initial values are `undefined`)
|
|
80
|
-
- **Object**: parameter names with default values
|
|
81
|
-
|
|
82
|
-
#### Returns
|
|
83
|
-
|
|
84
|
-
`PluginFactory` — plugin factory for `router.usePlugin()`
|
|
85
|
-
|
|
86
|
-
#### Throws
|
|
87
|
-
|
|
88
|
-
- `TypeError`: invalid configuration (not an array of strings or object with primitives)
|
|
89
|
-
- `Error`: plugin already initialized on this router
|
|
90
|
-
|
|
91
|
-
### Configuration
|
|
92
|
-
|
|
93
|
-
#### Array of Parameters
|
|
94
|
-
|
|
95
|
-
```typescript
|
|
96
|
-
persistentParamsPluginFactory(["mode", "debug", "apiUrl"]);
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
Parameters are saved after first use:
|
|
57
|
+
---
|
|
100
58
|
|
|
101
|
-
|
|
102
|
-
router.navigate("route1", { mode: "dev" });
|
|
103
|
-
// Saved: mode=dev
|
|
104
|
-
|
|
105
|
-
router.navigate("route2", {});
|
|
106
|
-
// URL includes: ?mode=dev
|
|
107
|
-
```
|
|
59
|
+
## Configuration
|
|
108
60
|
|
|
109
|
-
|
|
61
|
+
| Config Type | Description | Example |
|
|
62
|
+
| --------------------------- | ------------------------------------------- | ------------------- |
|
|
63
|
+
| `string[]` | Parameter names, initial values `undefined` | `["lang", "theme"]` |
|
|
64
|
+
| `Record<string, primitive>` | Parameter names with defaults | `{ lang: "en" }` |
|
|
110
65
|
|
|
111
|
-
|
|
112
|
-
persistentParamsPluginFactory({
|
|
113
|
-
mode: "prod",
|
|
114
|
-
lang: "en",
|
|
115
|
-
debug: false,
|
|
116
|
-
});
|
|
117
|
-
```
|
|
66
|
+
**Allowed value types:** `string`, `number`, `boolean`, `undefined` (to remove)
|
|
118
67
|
|
|
119
|
-
|
|
68
|
+
See [Wiki](https://github.com/greydragon888/real-router/wiki/persistent-params-plugin#3-configuration-options) for details.
|
|
120
69
|
|
|
121
|
-
|
|
122
|
-
router.start();
|
|
123
|
-
router.navigate("route1", {});
|
|
124
|
-
// URL: /route1?mode=prod&lang=en&debug=false
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
#### Empty Configuration
|
|
128
|
-
|
|
129
|
-
```typescript
|
|
130
|
-
// Valid but does nothing
|
|
131
|
-
persistentParamsPluginFactory([]);
|
|
132
|
-
persistentParamsPluginFactory({});
|
|
133
|
-
```
|
|
70
|
+
---
|
|
134
71
|
|
|
135
72
|
## Behavior
|
|
136
73
|
|
|
137
|
-
###
|
|
138
|
-
|
|
139
|
-
Parameters are automatically added to all transitions:
|
|
140
|
-
|
|
141
|
-
```typescript
|
|
142
|
-
router.usePlugin(persistentParamsPluginFactory(["lang"]));
|
|
143
|
-
|
|
144
|
-
router.navigate("products", { id: "1", lang: "en" });
|
|
145
|
-
// Saved: lang=en
|
|
146
|
-
|
|
147
|
-
router.navigate("cart", { id: "2" });
|
|
148
|
-
// URL: /cart/2?lang=en
|
|
149
|
-
|
|
150
|
-
router.navigate("checkout", {});
|
|
151
|
-
// URL: /checkout?lang=en
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
### Updating Values
|
|
155
|
-
|
|
156
|
-
New value overwrites the saved one:
|
|
157
|
-
|
|
158
|
-
```typescript
|
|
159
|
-
router.navigate("route1", { mode: "dev" });
|
|
160
|
-
// Saved: mode=dev
|
|
161
|
-
|
|
162
|
-
router.navigate("route2", { mode: "prod" });
|
|
163
|
-
// Saved: mode=prod (updated)
|
|
164
|
-
|
|
165
|
-
router.navigate("route3", {});
|
|
166
|
-
// URL: /route3?mode=prod
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
### Removing Parameters
|
|
170
|
-
|
|
171
|
-
Explicitly passing `undefined` removes the parameter:
|
|
172
|
-
|
|
173
|
-
```typescript
|
|
174
|
-
router.navigate("route1", { mode: "dev", lang: "en" });
|
|
175
|
-
// Saved: mode=dev, lang=en
|
|
176
|
-
|
|
177
|
-
router.navigate("route2", { lang: undefined });
|
|
178
|
-
// Saved: mode=dev (lang removed)
|
|
179
|
-
|
|
180
|
-
router.navigate("route3", {});
|
|
181
|
-
// URL: /route3?mode=dev
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
### Value Priority
|
|
185
|
-
|
|
186
|
-
Explicitly passed value takes precedence:
|
|
187
|
-
|
|
188
|
-
```typescript
|
|
189
|
-
// Saved: mode=dev
|
|
190
|
-
router.navigate("route", { mode: "test" });
|
|
191
|
-
// URL: /route?mode=test (explicit value used)
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
### Non-Tracked Parameters
|
|
195
|
-
|
|
196
|
-
Parameters outside configuration are not saved:
|
|
197
|
-
|
|
198
|
-
```typescript
|
|
199
|
-
router.usePlugin(persistentParamsPluginFactory(["mode"]));
|
|
200
|
-
|
|
201
|
-
router.navigate("route1", { mode: "dev", temp: "value" });
|
|
202
|
-
// Saved: mode=dev
|
|
203
|
-
// temp is ignored
|
|
204
|
-
|
|
205
|
-
router.navigate("route2", {});
|
|
206
|
-
// URL: /route2?mode=dev (temp absent)
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
### Extraction from URL
|
|
210
|
-
|
|
211
|
-
Parameters are extracted from initial URL:
|
|
212
|
-
|
|
213
|
-
```typescript
|
|
214
|
-
router.usePlugin(persistentParamsPluginFactory(["lang", "theme"]));
|
|
215
|
-
router.start("/products/1?lang=fr&theme=dark");
|
|
216
|
-
// Saved: lang=fr, theme=dark
|
|
217
|
-
|
|
218
|
-
router.navigate("cart", {});
|
|
219
|
-
// URL: /cart?lang=fr&theme=dark
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
## Integration with Router API
|
|
223
|
-
|
|
224
|
-
The plugin intercepts two router methods:
|
|
225
|
-
|
|
226
|
-
### `router.buildPath()`
|
|
227
|
-
|
|
228
|
-
```typescript
|
|
229
|
-
router.usePlugin(persistentParamsPluginFactory({ mode: "dev" }));
|
|
230
|
-
|
|
231
|
-
router.buildPath("products", { id: "1" });
|
|
232
|
-
// Returns: '/products/1?mode=dev'
|
|
233
|
-
|
|
234
|
-
router.buildPath("products", { id: "1", mode: "test" });
|
|
235
|
-
// Returns: '/products/1?mode=test' (explicit value)
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
### `router.forwardState()`
|
|
239
|
-
|
|
240
|
-
The plugin intercepts `forwardState()` which is used internally by `buildState()`, `buildStateWithSegments()`, and `navigate()`. This ensures persistent parameters are applied to all state-building operations.
|
|
241
|
-
|
|
242
|
-
```typescript
|
|
243
|
-
router.usePlugin(persistentParamsPluginFactory({ mode: "dev" }));
|
|
244
|
-
|
|
245
|
-
// All of these include persistent params:
|
|
246
|
-
router.buildState("products", { id: "1" });
|
|
247
|
-
// state.params: { id: '1', mode: 'dev' }
|
|
248
|
-
|
|
249
|
-
router.navigate("products", { id: "1" });
|
|
250
|
-
// URL: /products/1?mode=dev
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
## Type Validation
|
|
254
|
-
|
|
255
|
-
### Allowed Types
|
|
256
|
-
|
|
257
|
-
Only primitives: `string`, `number`, `boolean`:
|
|
258
|
-
|
|
259
|
-
```typescript
|
|
260
|
-
// ✅ Valid
|
|
261
|
-
router.navigate("route", { mode: "dev" }); // string
|
|
262
|
-
router.navigate("route", { page: 42 }); // number
|
|
263
|
-
router.navigate("route", { debug: true }); // boolean
|
|
264
|
-
router.navigate("route", { mode: undefined }); // removal
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
### Forbidden Types
|
|
74
|
+
### Persistence
|
|
268
75
|
|
|
269
76
|
```typescript
|
|
270
|
-
//
|
|
271
|
-
router.navigate("
|
|
272
|
-
router.navigate("route", { items: [1, 2, 3] }); // array
|
|
273
|
-
router.navigate("route", { fn: () => {} }); // function
|
|
274
|
-
router.navigate("route", { date: new Date() }); // Date
|
|
275
|
-
router.navigate("route", { mode: null }); // null
|
|
77
|
+
router.navigate("page1", { lang: "en" }); // Saved: lang=en
|
|
78
|
+
router.navigate("page2"); // URL: /page2?lang=en
|
|
276
79
|
```
|
|
277
80
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
### Parameter Name Validation
|
|
281
|
-
|
|
282
|
-
Parameter names must not contain special characters that could cause URL confusion:
|
|
81
|
+
### Update
|
|
283
82
|
|
|
284
83
|
```typescript
|
|
285
|
-
//
|
|
286
|
-
persistentParamsPluginFactory(["mode", "lang", "user_id", "api-key"]);
|
|
287
|
-
|
|
288
|
-
// ❌ Invalid parameter names (TypeError)
|
|
289
|
-
persistentParamsPluginFactory(["mode=dev"]); // contains =
|
|
290
|
-
persistentParamsPluginFactory(["param&other"]); // contains &
|
|
291
|
-
persistentParamsPluginFactory(["query?"]); // contains ?
|
|
292
|
-
persistentParamsPluginFactory(["hash#"]); // contains #
|
|
293
|
-
persistentParamsPluginFactory(["encoded%20"]); // contains %
|
|
294
|
-
persistentParamsPluginFactory(["path/to"]); // contains /
|
|
295
|
-
persistentParamsPluginFactory(["back\\slash"]); // contains \
|
|
296
|
-
persistentParamsPluginFactory(["with space"]); // contains whitespace
|
|
84
|
+
router.navigate("page", { lang: "fr" }); // Updates saved value
|
|
297
85
|
```
|
|
298
86
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
**Why**: These characters have special meaning in URLs and would cause parsing issues or confusion.
|
|
302
|
-
|
|
303
|
-
## Security
|
|
304
|
-
|
|
305
|
-
### Prototype Pollution Protection
|
|
87
|
+
### Remove
|
|
306
88
|
|
|
307
89
|
```typescript
|
|
308
|
-
|
|
309
|
-
malicious.mode = "dev";
|
|
310
|
-
|
|
311
|
-
router.navigate("route", malicious);
|
|
312
|
-
// Result: only mode=dev (inherited properties ignored)
|
|
313
|
-
|
|
314
|
-
// Global prototype not polluted
|
|
315
|
-
({}).isAdmin === undefined; // true
|
|
90
|
+
router.navigate("page", { lang: undefined }); // Removes from persistent params
|
|
316
91
|
```
|
|
317
92
|
|
|
318
|
-
###
|
|
93
|
+
### Priority
|
|
319
94
|
|
|
320
|
-
|
|
321
|
-
router.navigate("route", {
|
|
322
|
-
constructor: { prototype: { polluted: true } },
|
|
323
|
-
});
|
|
324
|
-
// TypeError: Parameter "constructor" must be a primitive value
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
### Safe State Management
|
|
328
|
-
|
|
329
|
-
The plugin safely manages persistent parameters to prevent accidental mutations and ensure consistent behavior across navigation.
|
|
330
|
-
|
|
331
|
-
## Lifecycle
|
|
332
|
-
|
|
333
|
-
### Initialization
|
|
95
|
+
Explicit values override saved ones:
|
|
334
96
|
|
|
335
97
|
```typescript
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
### Double Initialization Protection
|
|
340
|
-
|
|
341
|
-
```typescript
|
|
342
|
-
router.usePlugin(persistentParamsPluginFactory(["mode"]));
|
|
343
|
-
|
|
344
|
-
router.usePlugin(persistentParamsPluginFactory(["mode"]));
|
|
345
|
-
// Error: Plugin already initialized on this router
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
### Teardown
|
|
349
|
-
|
|
350
|
-
Cleanly removes the plugin and restores original router behavior:
|
|
351
|
-
|
|
352
|
-
```typescript
|
|
353
|
-
const unsubscribe = router.usePlugin(persistentParamsPluginFactory(["mode"]));
|
|
354
|
-
|
|
355
|
-
// Work with plugin...
|
|
356
|
-
|
|
357
|
-
unsubscribe();
|
|
358
|
-
// Router methods restored to original behavior
|
|
359
|
-
// Plugin can be reinitialized with new configuration
|
|
98
|
+
// Saved: lang=en
|
|
99
|
+
router.navigate("page", { lang: "de" }); // URL: /page?lang=de
|
|
360
100
|
```
|
|
361
101
|
|
|
362
|
-
|
|
102
|
+
See [Wiki](https://github.com/greydragon888/real-router/wiki/persistent-params-plugin#8-behavior) for edge cases and guarantees.
|
|
363
103
|
|
|
364
|
-
|
|
365
|
-
const unsub1 = router.usePlugin(persistentParamsPluginFactory(["mode"]));
|
|
366
|
-
unsub1();
|
|
367
|
-
|
|
368
|
-
// Now can add with new configuration
|
|
369
|
-
const unsub2 = router.usePlugin(persistentParamsPluginFactory(["theme"]));
|
|
370
|
-
```
|
|
104
|
+
---
|
|
371
105
|
|
|
372
106
|
## Usage Examples
|
|
373
107
|
|
|
374
|
-
### Multilingual
|
|
108
|
+
### Multilingual App
|
|
375
109
|
|
|
376
110
|
```typescript
|
|
377
111
|
router.usePlugin(persistentParamsPluginFactory({ lang: "en" }));
|
|
378
112
|
|
|
379
|
-
// User changes language
|
|
380
113
|
router.navigate("settings", { lang: "fr" });
|
|
381
|
-
|
|
382
|
-
// Language persists across all transitions
|
|
383
|
-
router.navigate("products", { id: "1" }); // ?lang=fr
|
|
114
|
+
router.navigate("products"); // ?lang=fr
|
|
384
115
|
router.navigate("cart"); // ?lang=fr
|
|
385
|
-
router.navigate("checkout"); // ?lang=fr
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
### Development Mode
|
|
389
|
-
|
|
390
|
-
```typescript
|
|
391
|
-
router.usePlugin(persistentParamsPluginFactory(["debug", "apiMock"]));
|
|
392
|
-
|
|
393
|
-
// Developer opens URL with flags
|
|
394
|
-
router.start("/?debug=true&apiMock=local");
|
|
395
|
-
|
|
396
|
-
// Flags persist in all routes
|
|
397
|
-
router.navigate("products"); // ?debug=true&apiMock=local
|
|
398
|
-
router.navigate("cart"); // ?debug=true&apiMock=local
|
|
399
116
|
```
|
|
400
117
|
|
|
401
118
|
### UTM Tracking
|
|
@@ -405,89 +122,40 @@ router.usePlugin(
|
|
|
405
122
|
persistentParamsPluginFactory(["utm_source", "utm_medium", "utm_campaign"]),
|
|
406
123
|
);
|
|
407
124
|
|
|
408
|
-
// User arrives
|
|
409
|
-
router.
|
|
410
|
-
|
|
411
|
-
// UTM tags persist across all transitions
|
|
412
|
-
router.navigate("products"); // includes utm_*
|
|
413
|
-
router.navigate("cart"); // includes utm_*
|
|
414
|
-
router.navigate("checkout"); // includes utm_*
|
|
125
|
+
// User arrives: /?utm_source=google&utm_medium=cpc
|
|
126
|
+
router.navigate("products"); // UTM params preserved
|
|
127
|
+
router.navigate("checkout"); // UTM params preserved
|
|
415
128
|
```
|
|
416
129
|
|
|
417
|
-
|
|
130
|
+
---
|
|
418
131
|
|
|
419
|
-
|
|
420
|
-
router.usePlugin(persistentParamsPluginFactory(["sortBy", "order", "view"]));
|
|
421
|
-
|
|
422
|
-
// User configures display
|
|
423
|
-
router.navigate("products", {
|
|
424
|
-
category: "electronics",
|
|
425
|
-
sortBy: "price",
|
|
426
|
-
order: "asc",
|
|
427
|
-
view: "grid",
|
|
428
|
-
});
|
|
429
|
-
|
|
430
|
-
// Settings persist when changing categories
|
|
431
|
-
router.navigate("products", { category: "books" });
|
|
432
|
-
// URL: /products?category=books&sortBy=price&order=asc&view=grid
|
|
433
|
-
```
|
|
434
|
-
|
|
435
|
-
### Combination with Other Plugins
|
|
132
|
+
## Lifecycle
|
|
436
133
|
|
|
437
134
|
```typescript
|
|
438
|
-
|
|
439
|
-
import { loggerPlugin } from "@real-router/logger-plugin";
|
|
440
|
-
import { persistentParamsPluginFactory } from "@real-router/persistent-params-plugin";
|
|
441
|
-
|
|
442
|
-
router.usePlugin(browserPluginFactory());
|
|
443
|
-
router.usePlugin(loggerPlugin);
|
|
444
|
-
router.usePlugin(persistentParamsPluginFactory(["lang", "theme"]));
|
|
135
|
+
const unsubscribe = router.usePlugin(persistentParamsPluginFactory(["mode"]));
|
|
445
136
|
|
|
446
|
-
//
|
|
137
|
+
// Later: restore original router behavior
|
|
138
|
+
unsubscribe();
|
|
447
139
|
```
|
|
448
140
|
|
|
449
|
-
|
|
141
|
+
**Note:** Double initialization throws an error. Call `unsubscribe()` first.
|
|
450
142
|
|
|
451
|
-
|
|
143
|
+
---
|
|
452
144
|
|
|
453
|
-
|
|
454
|
-
try {
|
|
455
|
-
router.usePlugin(persistentParamsPluginFactory(["mode"]));
|
|
456
|
-
router.usePlugin(persistentParamsPluginFactory(["mode"]));
|
|
457
|
-
} catch (error) {
|
|
458
|
-
// Error: Plugin already initialized on this router
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
try {
|
|
462
|
-
router.navigate("route", { mode: { nested: "value" } });
|
|
463
|
-
} catch (error) {
|
|
464
|
-
// TypeError: Parameter "mode" must be a primitive value
|
|
465
|
-
}
|
|
466
|
-
```
|
|
145
|
+
## Documentation
|
|
467
146
|
|
|
468
|
-
|
|
147
|
+
Full documentation on [Wiki](https://github.com/greydragon888/real-router/wiki/persistent-params-plugin):
|
|
469
148
|
|
|
470
|
-
|
|
149
|
+
- [Configuration Options](https://github.com/greydragon888/real-router/wiki/persistent-params-plugin#3-configuration-options)
|
|
150
|
+
- [Lifecycle Hooks](https://github.com/greydragon888/real-router/wiki/persistent-params-plugin#4-lifecycle-hooks)
|
|
151
|
+
- [Behavior & Edge Cases](https://github.com/greydragon888/real-router/wiki/persistent-params-plugin#8-behavior)
|
|
152
|
+
- [Migration from router5](https://github.com/greydragon888/real-router/wiki/persistent-params-plugin#11-migration-from-router5)
|
|
471
153
|
|
|
472
|
-
|
|
473
|
-
import {
|
|
474
|
-
persistentParamsPluginFactory,
|
|
475
|
-
type PersistentParamsConfig,
|
|
476
|
-
} from "@real-router/persistent-params-plugin";
|
|
477
|
-
|
|
478
|
-
// Configuration types
|
|
479
|
-
const config1: PersistentParamsConfig = ["mode", "lang"];
|
|
480
|
-
const config2: PersistentParamsConfig = { mode: "dev", lang: "en" };
|
|
481
|
-
|
|
482
|
-
// Type inference
|
|
483
|
-
router.usePlugin(persistentParamsPluginFactory(["mode"]));
|
|
484
|
-
router.navigate("route", { mode: "dev" }); // type-safe
|
|
485
|
-
```
|
|
154
|
+
---
|
|
486
155
|
|
|
487
156
|
## Related Packages
|
|
488
157
|
|
|
489
158
|
- [@real-router/core](https://www.npmjs.com/package/@real-router/core) — Core router
|
|
490
|
-
- [@real-router/react](https://www.npmjs.com/package/@real-router/react) — React integration
|
|
491
159
|
- [@real-router/browser-plugin](https://www.npmjs.com/package/@real-router/browser-plugin) — Browser history
|
|
492
160
|
|
|
493
161
|
## License
|