@stacksjs/bun-router 0.1.4 → 0.1.6

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.
@@ -5,7 +5,23 @@ import type { BuiltInMiddleware } from '../types';
5
5
  * `../index`, which is the module an application can name in a
6
6
  * `declare module '@stacksjs/bun-router'` augmentation - see the note there.
7
7
  */
8
- export type FromRegistry<TKey extends string, TFallback> = TKey extends keyof RouterTypeRegistry ? (RouterTypeRegistry[TKey] extends TFallback ? RouterTypeRegistry[TKey] : TFallback) : TFallback;
8
+ /**
9
+ * Read a key out of the registry, or fall back.
10
+ *
11
+ * `TKey extends keyof RouterTypeRegistry` is false while the interface is
12
+ * empty, which is what makes every fallback the default.
13
+ *
14
+ * `TShape` is checked separately from `TFallback`, and the distinction is
15
+ * load-bearing. It used to test the declared value against the fallback itself,
16
+ * which sounds like the same thing and is not: the fallback for an action path
17
+ * is the loose pattern `Actions/${string}Action`, and a real application's
18
+ * action list contains names like `'Actions/Dashboard/Library/GetFunctions'`
19
+ * that do not match it. So a correct, complete declaration failed the guard and
20
+ * fell back to the pattern - the feature looked wired up and checked nothing.
21
+ * The guard is meant to catch `actions: number`, so it asks whether the
22
+ * declared value is a string, and nothing more.
23
+ */
24
+ export type FromRegistry<TKey extends string, TShape, TFallback> = TKey extends keyof RouterTypeRegistry ? (RouterTypeRegistry[TKey] extends TShape ? RouterTypeRegistry[TKey] : TFallback) : TFallback;
9
25
  /**
10
26
  * The action paths this application has, or the shape of one when it has not
11
27
  * said.
@@ -14,7 +30,7 @@ export type FromRegistry<TKey extends string, TFallback> = TKey extends keyof Ro
14
30
  * ending in `Action`, or a `Controller@method` reference. It catches a shape
15
31
  * mistake and nothing else, which is why declaring the real set is worth doing.
16
32
  */
17
- export type KnownActionPath = FromRegistry<'actions', `Actions/${string}Action` | `actions/${string}Action` | `${string}Controller@${string}`>;
33
+ export type KnownActionPath = FromRegistry<'actions', string, `Actions/${string}Action` | `actions/${string}Action` | `${string}Controller@${string}`>;
18
34
  /**
19
35
  * The middleware aliases this application registers, or any string.
20
36
  *
@@ -23,7 +39,7 @@ export type KnownActionPath = FromRegistry<'actions', `Actions/${string}Action`
23
39
  * to the group - so the union has to contain both or the group form stops
24
40
  * type-checking the moment anything is declared.
25
41
  */
26
- export type KnownMiddlewareName = FromRegistry<'middleware', string>;
42
+ export type KnownMiddlewareName = FromRegistry<'middleware', string, string>;
27
43
  /**
28
44
  * A middleware reference: an alias, or an alias with parameters.
29
45
  *
@@ -38,7 +54,7 @@ export type KnownMiddlewareName = FromRegistry<'middleware', string>;
38
54
  */
39
55
  export type MiddlewareReference = BuiltInMiddleware | `${BuiltInMiddleware}:${string}` | KnownMiddlewareName | `${KnownMiddlewareName}:${string}`;
40
56
  /** The named routes this application registers, as `name → path`. */
41
- export type KnownRoutes = FromRegistry<'routes', Record<string, string>>;
57
+ export type KnownRoutes = FromRegistry<'routes', Record<string, string>, Record<string, string>>;
42
58
  /** The names of those routes, or any string when none are declared. */
43
59
  export type KnownRouteName = keyof KnownRoutes extends never ? string : Extract<keyof KnownRoutes, string>;
44
60
  /** The path a declared route name resolves to, or any path when it is not declared. */
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Path params, decoded — once.
3
+ *
4
+ * The matchers took the raw path segment, so `/f/{name}` given
5
+ * `/f/caf%C3%A9` handed the handler the literal `caf%C3%A9`, and a space
6
+ * arrived as `%20`. Every consumer had to decode, which means every consumer
7
+ * that forgot had a bug, and the one framework that remembered
8
+ * (`@stacksjs/router`) had to do it in a wrapper.
9
+ *
10
+ * Doing it here rather than in a wrapper is what makes it exactly once. Two
11
+ * layers each calling `decodeURIComponent` turn `%2520` into a space, and a
12
+ * double decode is how a filter that rejects `../` gets walked past.
13
+ *
14
+ * Note for handlers: a decoded param CAN contain `/` (from `%2F`) — that is
15
+ * the point of encoding it — so anything joining a param into a filesystem
16
+ * path still has to sanitise. Decoding makes the value correct, not safe.
17
+ */
18
+ export declare function decodeParam(value: string): string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stacksjs/bun-router",
3
3
  "type": "module",
4
- "version": "0.1.4",
4
+ "version": "0.1.6",
5
5
  "description": "A fast, type-safe router for Bun.",
6
6
  "author": "Chris Breuer <chris@stacksjs.org>",
7
7
  "license": "MIT",