paramour 0.4.0 → 0.5.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 +44 -0
- package/dist/errors.d.ts +4 -3
- package/dist/errors.js +4 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/internal.d.ts +11 -0
- package/dist/internal.js +11 -0
- package/dist/route.d.ts +37 -8
- package/package.json +10 -2
package/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# paramour
|
|
2
|
+
|
|
3
|
+
Type-safe routing companion for the Next.js App Router: validated, typed
|
|
4
|
+
route and search params, type-checked path building, and a predictable,
|
|
5
|
+
human-readable URL wire format. Validation is bring-your-own via
|
|
6
|
+
[Standard Schema](https://github.com/standard-schema/standard-schema) —
|
|
7
|
+
paramour owns serialization (the part validators can't do), your validator
|
|
8
|
+
owns the rules.
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
pnpm add paramour @paramour-js/next
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { defineAppRoute, href, p } from "paramour";
|
|
16
|
+
|
|
17
|
+
export const productRoute = defineAppRoute("/product/[id]", {
|
|
18
|
+
params: { id: p.integer() },
|
|
19
|
+
search: { q: p.string().optional() },
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// typed, validated, explicit: "/product/42?q=paramour"
|
|
23
|
+
href(productRoute, { params: { id: 42 }, search: { q: "paramour" } });
|
|
24
|
+
|
|
25
|
+
// a string into p.integer() fails to compile
|
|
26
|
+
href(productRoute, { params: { id: "42" } });
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Routes are plain imported objects — no central registry, nothing to
|
|
30
|
+
tree-shake around. Codecs are bidirectional wire converters with a
|
|
31
|
+
type-state modifier API (`.optional()`, `.default()`, `.catch()`) where
|
|
32
|
+
illegal chains fail to compile, and every codec serializes by a
|
|
33
|
+
[published, numbered spec](https://paramour.dev/docs/reference/wire-format).
|
|
34
|
+
|
|
35
|
+
## Docs
|
|
36
|
+
|
|
37
|
+
- [Getting started](https://paramour.dev/docs/getting-started)
|
|
38
|
+
- [Core API reference](https://paramour.dev/docs/reference/core)
|
|
39
|
+
- [Wire-format spec & explorer](https://paramour.dev/docs/reference/wire-format)
|
|
40
|
+
- [Migrating from next-typesafe-url](https://paramour.dev/docs/migrate)
|
|
41
|
+
|
|
42
|
+
## License
|
|
43
|
+
|
|
44
|
+
MIT © Jason Paff
|
package/dist/errors.d.ts
CHANGED
|
@@ -57,9 +57,10 @@ export declare function describeType(value: unknown): string;
|
|
|
57
57
|
* Best-effort human-readable message for a foreign (non-paramour) throw:
|
|
58
58
|
* an `Error`'s message, else a {@link showValue}-hardened `String()` — safe
|
|
59
59
|
* even for values whose primitive conversion itself throws (null-prototype
|
|
60
|
-
* objects, `Symbol.toPrimitive` throwers). Public via
|
|
61
|
-
* tooling that catches user-code throws (the devtools panel's edit
|
|
62
|
-
* shares the hardening instead of re-implementing it minus the
|
|
60
|
+
* objects, `Symbol.toPrimitive` throwers). Public via `paramour/internal` so
|
|
61
|
+
* derived tooling that catches user-code throws (the devtools panel's edit
|
|
62
|
+
* preview) shares the hardening instead of re-implementing it minus the
|
|
63
|
+
* guard.
|
|
63
64
|
*/
|
|
64
65
|
export declare function foreignMessage(error: unknown): string;
|
|
65
66
|
/**
|
package/dist/errors.js
CHANGED
|
@@ -110,9 +110,10 @@ export function describeType(value) {
|
|
|
110
110
|
* Best-effort human-readable message for a foreign (non-paramour) throw:
|
|
111
111
|
* an `Error`'s message, else a {@link showValue}-hardened `String()` — safe
|
|
112
112
|
* even for values whose primitive conversion itself throws (null-prototype
|
|
113
|
-
* objects, `Symbol.toPrimitive` throwers). Public via
|
|
114
|
-
* tooling that catches user-code throws (the devtools panel's edit
|
|
115
|
-
* shares the hardening instead of re-implementing it minus the
|
|
113
|
+
* objects, `Symbol.toPrimitive` throwers). Public via `paramour/internal` so
|
|
114
|
+
* derived tooling that catches user-code throws (the devtools panel's edit
|
|
115
|
+
* preview) shares the hardening instead of re-implementing it minus the
|
|
116
|
+
* guard.
|
|
116
117
|
*/
|
|
117
118
|
export function foreignMessage(error) {
|
|
118
119
|
return error instanceof Error ? error.message : showValue(error);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export { type AnyCodec, type Arity, type Codec, type OutputOf, type ParamCodec, type Presence, type PresenceOf, } from "./codec.js";
|
|
2
2
|
export { type CodecDefaultDescription, type CodecDescription, type CodecFormatStyle, describeCodec, describeRoute, formatCodecDescription, type ParamDescription, type RouteDescription, type SearchDescription, } from "./describe.js";
|
|
3
|
-
export {
|
|
3
|
+
export { type Issue, ParamourError, ParamsDecodeError, ParseError, type RouteDecodeError, SearchDecodeError, SearchSourceError, SerializeError, } from "./errors.js";
|
|
4
4
|
export { href, type Href, type HrefArgs, type InferHrefInput, type StaticHrefOptions, } from "./href.js";
|
|
5
5
|
export { p } from "./p.js";
|
|
6
6
|
export { buildPath, decodeParams, type DecodeParamsOptions, encodeParams, encodeStaticParams, type InferStaticParams, type ParamsSource, } from "./path.js";
|
|
7
|
-
export { type AnyAppRoute, type AnyPagesRoute, type AnyRoute, type AppRoute, defineAppRoute, definePagesRoute, type InferRouteParams, type PagesContext, type PagesRoute, type ParamourRegister, type ParamsConfig, type ParamsProps, type RegisteredAppRoutePaths, type RegisteredPagesRoutePaths, type RegisteredStaticAppRoutePaths, type RegisteredStaticPagesRoutePaths, type RegisteredStaticRoutePaths, type Route, type RouteProps, type RouterKind, type SafeResult, type SearchProps, } from "./route.js";
|
|
7
|
+
export { type AnyAppRoute, type AnyPagesRoute, type AnyRoute, type AppRoute, defineAppRoute, definePagesRoute, type InferRouteParams, type PagesContext, type PagesRoute, type ParamourRegister, type ParamsConfig, type ParamsProps, type ParamsPropsInput, type RegisteredAppRoutePaths, type RegisteredPagesRoutePaths, type RegisteredStaticAppRoutePaths, type RegisteredStaticPagesRoutePaths, type RegisteredStaticRoutePaths, type Route, type RouteProps, type RoutePropsInput, type RouterKind, type SafeResult, type SearchProps, type SearchPropsInput, } from "./route.js";
|
|
8
8
|
export { safeDecodeParams, safeDecodeSearch } from "./safe-decode.js";
|
|
9
|
-
export { buildSearchString, decodeSearch, encodeSearch, type InferSearchInput, type InferSearchOutput, isRawSearch,
|
|
9
|
+
export { buildSearchString, decodeSearch, encodeSearch, type InferSearchInput, type InferSearchOutput, isRawSearch, rawSearch, type RawSearch, type SearchConfig, type SearchOutputOf, type SearchSource, searchToString, serializeValue, } from "./search.js";
|
|
10
10
|
export { standardSearchSchema, type StandardSearchSchema, } from "./standard-schema.js";
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export {} from "./codec.js";
|
|
2
2
|
export { describeCodec, describeRoute, formatCodecDescription, } from "./describe.js";
|
|
3
|
-
export {
|
|
3
|
+
export { ParamourError, ParamsDecodeError, ParseError, SearchDecodeError, SearchSourceError, SerializeError, } from "./errors.js";
|
|
4
4
|
export { href, } from "./href.js";
|
|
5
5
|
export { p } from "./p.js";
|
|
6
6
|
export { buildPath, decodeParams, encodeParams, encodeStaticParams, } from "./path.js";
|
|
7
7
|
export { defineAppRoute, definePagesRoute, } from "./route.js";
|
|
8
8
|
export { safeDecodeParams, safeDecodeSearch } from "./safe-decode.js";
|
|
9
|
-
export { buildSearchString, decodeSearch, encodeSearch, isRawSearch,
|
|
9
|
+
export { buildSearchString, decodeSearch, encodeSearch, isRawSearch, rawSearch, searchToString, serializeValue, } from "./search.js";
|
|
10
10
|
export { standardSearchSchema, } from "./standard-schema.js";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `paramour/internal` entry: unstable helpers for derived tooling
|
|
3
|
+
* (devtools, adapters), NOT for app authors and NOT covered by the public
|
|
4
|
+
* API's stability expectations. These live off the main barrel on purpose —
|
|
5
|
+
* the docs' Reference section documents the app-author surface, and these
|
|
6
|
+
* two exist solely so reflection-driven consumers (the devtools panel's
|
|
7
|
+
* catch-attribution probe and edit preview, design-12 DT7) share core's
|
|
8
|
+
* implementation instead of re-deriving it.
|
|
9
|
+
*/
|
|
10
|
+
export { foreignMessage } from "./errors.js";
|
|
11
|
+
export { parseValue } from "./search.js";
|
package/dist/internal.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `paramour/internal` entry: unstable helpers for derived tooling
|
|
3
|
+
* (devtools, adapters), NOT for app authors and NOT covered by the public
|
|
4
|
+
* API's stability expectations. These live off the main barrel on purpose —
|
|
5
|
+
* the docs' Reference section documents the app-author surface, and these
|
|
6
|
+
* two exist solely so reflection-driven consumers (the devtools panel's
|
|
7
|
+
* catch-attribution probe and edit preview, design-12 DT7) share core's
|
|
8
|
+
* implementation instead of re-deriving it.
|
|
9
|
+
*/
|
|
10
|
+
export { foreignMessage } from "./errors.js";
|
|
11
|
+
export { parseValue } from "./search.js";
|
package/dist/route.d.ts
CHANGED
|
@@ -27,20 +27,20 @@ export interface AppRoute<Path extends string, PC extends ParamsConfig<Path>, SC
|
|
|
27
27
|
* FIRST — a params grammar failure means the URL doesn't denote this
|
|
28
28
|
* route at all (morally a 404), so it throws before search is decoded.
|
|
29
29
|
*/
|
|
30
|
-
parse(props:
|
|
30
|
+
parse(props: RoutePropsInput): Promise<{
|
|
31
31
|
params: ParamsOutput<Path, PC>;
|
|
32
32
|
search: SearchOutputOf<SC>;
|
|
33
33
|
}>;
|
|
34
34
|
/** Bare params object (RL6) — layout props are structurally assignable. */
|
|
35
|
-
parseParams(props:
|
|
35
|
+
parseParams(props: ParamsPropsInput): Promise<ParamsOutput<Path, PC>>;
|
|
36
36
|
/** Bare search object (RL6) — the search half alone. */
|
|
37
|
-
parseSearch(props:
|
|
38
|
-
safeParse(props:
|
|
37
|
+
parseSearch(props: SearchPropsInput): Promise<SearchOutputOf<SC>>;
|
|
38
|
+
safeParse(props: RoutePropsInput): Promise<SafeResult<{
|
|
39
39
|
params: ParamsOutput<Path, PC>;
|
|
40
40
|
search: SearchOutputOf<SC>;
|
|
41
41
|
}>>;
|
|
42
|
-
safeParseParams(props:
|
|
43
|
-
safeParseSearch(props:
|
|
42
|
+
safeParseParams(props: ParamsPropsInput): Promise<SafeResult<ParamsOutput<Path, PC>>>;
|
|
43
|
+
safeParseSearch(props: SearchPropsInput): Promise<SafeResult<SearchOutputOf<SC>>>;
|
|
44
44
|
}
|
|
45
45
|
/** Names of `[...name]` catch-all segments in the path literal (RL3). */
|
|
46
46
|
export type CatchAllNames<Path extends string> = Segments<Path> extends infer S extends string ? S extends `[...${infer Name}]` ? NonEmptyName<Name> : never : never;
|
|
@@ -52,7 +52,15 @@ export type CatchAllNames<Path extends string> = Segments<Path> extends infer S
|
|
|
52
52
|
export type ConformParams<Path extends string, PC> = PC & Record<Exclude<keyof PC, PathParamNames<Path>>, never>;
|
|
53
53
|
/** Decoded params object type for a route (RL3); see {@link ParamsOutput}. */
|
|
54
54
|
export type InferRouteParams<R extends AnyRoute> = ParamsOutput<R["path"], R["~params"]>;
|
|
55
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* Accepts promised props and plain objects alike (RL6). This width lives on
|
|
57
|
+
* the parse INPUT surface ({@link RoutePropsInput} and friends), not on the
|
|
58
|
+
* annotation types: every supported Next (peer `>=15`) delivers page props
|
|
59
|
+
* as promises, and Next 15.5's generated `.next/types` page check requires
|
|
60
|
+
* a page's `params` prop to be `Promise<any> | undefined` — a sync arm in
|
|
61
|
+
* {@link RouteProps} fails `next build` there. Hand-built sync props (tests,
|
|
62
|
+
* server code calling `parse` directly) stay legal via the input types.
|
|
63
|
+
*/
|
|
56
64
|
export type MaybePromise<T> = Promise<T> | T;
|
|
57
65
|
/**
|
|
58
66
|
* RL3: an empty name (`[]`, `[...]`, `[[...]]`) is not a token — it falls
|
|
@@ -145,6 +153,14 @@ export type ParamsOutput<Path extends string, PC> = {
|
|
|
145
153
|
* global doesn't exist in fresh clones before `next dev` first runs.
|
|
146
154
|
*/
|
|
147
155
|
export interface ParamsProps {
|
|
156
|
+
readonly params?: Promise<ParamsSource>;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* What `parseParams` ACCEPTS (RL6): {@link ParamsProps} plus plain sync
|
|
160
|
+
* objects — see {@link MaybePromise} for why the annotation type is
|
|
161
|
+
* promise-only while the parse input stays wide.
|
|
162
|
+
*/
|
|
163
|
+
export interface ParamsPropsInput {
|
|
148
164
|
readonly params?: MaybePromise<ParamsSource>;
|
|
149
165
|
}
|
|
150
166
|
/** Every dynamic segment name in the path literal (RL3). */
|
|
@@ -218,9 +234,18 @@ export type RouteConfig<Path extends string, PC extends ParamsConfig<Path>, SC e
|
|
|
218
234
|
readonly params: ConformParams<Path, PC>;
|
|
219
235
|
readonly search?: SC;
|
|
220
236
|
};
|
|
221
|
-
/**
|
|
237
|
+
/**
|
|
238
|
+
* Full page-props contract (RL6): the type a page annotates its props with.
|
|
239
|
+
* Next's `PageProps` is structurally assignable, and both members are
|
|
240
|
+
* promise-only so the annotation survives Next 15.5's generated page check
|
|
241
|
+
* (see {@link MaybePromise}). Deliberately NOT Next's generated `PageProps`
|
|
242
|
+
* global — core stays framework-agnostic.
|
|
243
|
+
*/
|
|
222
244
|
export interface RouteProps extends ParamsProps, SearchProps {
|
|
223
245
|
}
|
|
246
|
+
/** What `parse`/`safeParse` ACCEPT (RL6): {@link RouteProps} plus sync props. */
|
|
247
|
+
export interface RoutePropsInput extends ParamsPropsInput, SearchPropsInput {
|
|
248
|
+
}
|
|
224
249
|
/** Which router a route belongs to (PR3) — the value of the `~router` brand. */
|
|
225
250
|
export type RouterKind = "app" | "pages";
|
|
226
251
|
/**
|
|
@@ -241,6 +266,10 @@ export type SafeResult<T> = {
|
|
|
241
266
|
* shape is the same as the params side's, hence the shared source type.
|
|
242
267
|
*/
|
|
243
268
|
export interface SearchProps {
|
|
269
|
+
readonly searchParams?: Promise<ParamsSource>;
|
|
270
|
+
}
|
|
271
|
+
/** Sync-accepting twin of {@link SearchProps} — see {@link ParamsPropsInput}. */
|
|
272
|
+
export interface SearchPropsInput {
|
|
244
273
|
readonly searchParams?: MaybePromise<ParamsSource>;
|
|
245
274
|
}
|
|
246
275
|
/**
|
package/package.json
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "paramour",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
8
|
"default": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"./internal": {
|
|
11
|
+
"types": "./dist/internal.d.ts",
|
|
12
|
+
"default": "./dist/internal.js"
|
|
9
13
|
}
|
|
10
14
|
},
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=22.13.0"
|
|
17
|
+
},
|
|
11
18
|
"description": "Type-safe routing companion for the Next.js App Router: validated route params and search params, typed path building, and explicit URL serialization.",
|
|
12
19
|
"keywords": [
|
|
13
20
|
"nextjs",
|
|
@@ -26,7 +33,7 @@
|
|
|
26
33
|
"url": "git+https://github.com/JasonPaff/paramour.git",
|
|
27
34
|
"directory": "packages/core"
|
|
28
35
|
},
|
|
29
|
-
"homepage": "https://
|
|
36
|
+
"homepage": "https://paramour.dev",
|
|
30
37
|
"bugs": {
|
|
31
38
|
"url": "https://github.com/JasonPaff/paramour/issues"
|
|
32
39
|
},
|
|
@@ -49,6 +56,7 @@
|
|
|
49
56
|
},
|
|
50
57
|
"scripts": {
|
|
51
58
|
"build": "tsc -p tsconfig.build.json",
|
|
59
|
+
"check:publish": "publint --strict && attw --pack . --profile esm-only",
|
|
52
60
|
"typecheck": "tsc --noEmit"
|
|
53
61
|
}
|
|
54
62
|
}
|