@stealthscale/provider-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.
- package/LICENSE +21 -0
- package/README.md +284 -0
- package/dist/cyclonedx/bom.json +1 -0
- package/dist/index.d.ts +489 -0
- package/dist/index.js +689 -0
- package/dist/rolldown-runtime-BBjsoOtd.js +27 -0
- package/package.json +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Stealth Scale B.V.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
# @stealthscale/provider-router
|
|
2
|
+
|
|
3
|
+
`@stealthscale/provider-router` gives you the pieces an application builds a router from. You call
|
|
4
|
+
TanStack Router's own `createRouter`, so all forty-eight of its options remain yours to set.
|
|
5
|
+
|
|
6
|
+
Three things come from here. `routerOptions` states what every router in this design system starts
|
|
7
|
+
from. `compileRoutes` turns route declarations a host read out of a manifest into routes you place
|
|
8
|
+
in your own tree. `namedRoute`, `routeMap`, `routeHref` and `RouteLink` let anything link to
|
|
9
|
+
anything by id.
|
|
10
|
+
|
|
11
|
+
**Use this package when an address is decided at run time.** An application whose routes are all in
|
|
12
|
+
the build should use TanStack Router directly, where the compiler checks every path. This package
|
|
13
|
+
exists for the pages that are not in the build: ones another deployment declares, ones a condition
|
|
14
|
+
decides, ones a host mounts under a path it chooses when it starts.
|
|
15
|
+
|
|
16
|
+
**Link by id, not by path.** A path belongs to whoever composed the application, so a page that
|
|
17
|
+
might be composed differently tomorrow has no path it can write down. An id does not move. That
|
|
18
|
+
holds for a host's own routes as much as for a plugin's, which is why `namedRoute` gives a route
|
|
19
|
+
written in code the same kind of id the compiler gives a declared one.
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pnpm add @stealthscale/provider-router
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The package peers on `@tanstack/react-router` and `react`. It re-exports the library, so you import
|
|
28
|
+
the router from here rather than from two places.
|
|
29
|
+
|
|
30
|
+
## A host that draws routes a manifest declared
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import {
|
|
34
|
+
compileRoutes,
|
|
35
|
+
createAppRootRoute,
|
|
36
|
+
createRoute,
|
|
37
|
+
createRouter,
|
|
38
|
+
namedRoute,
|
|
39
|
+
routeMap,
|
|
40
|
+
routerOptions,
|
|
41
|
+
} from "@stealthscale/provider-router";
|
|
42
|
+
|
|
43
|
+
function buildTree(declarations) {
|
|
44
|
+
const root = createAppRootRoute()();
|
|
45
|
+
const shell = createRoute({ getParentRoute: () => root, path: "/app" });
|
|
46
|
+
const home = createRoute({
|
|
47
|
+
...namedRoute("app.home"),
|
|
48
|
+
getParentRoute: () => shell,
|
|
49
|
+
path: "/home",
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const plugins = compileRoutes(declarations, { evaluate, layouts, parent: shell });
|
|
53
|
+
|
|
54
|
+
return root.addChildren([shell.addChildren([home, ...plugins])]);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const tree = buildTree(await loadManifests());
|
|
58
|
+
const router = createRouter({ ...routerOptions({ routes: routeMap(tree) }), routeTree: tree });
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`compileRoutes` creates routes and never touches the parent you pass it. Build the tree as a
|
|
62
|
+
function of the declarations and call it once per declaration set. Compile every contributor's
|
|
63
|
+
declarations in one call, because two calls under one parent cannot read each other's paths.
|
|
64
|
+
|
|
65
|
+
Use `createAppRootRoute` rather than `createRootRoute`. It types the router context so the route map
|
|
66
|
+
fits, and the alternative reports the mismatch at `createRouter` rather than at the root.
|
|
67
|
+
|
|
68
|
+
**Do not graft into a tree a router has already been built from.** The library caches a processed
|
|
69
|
+
tree on a server, keyed by the tree object and written once per process, so a second router built
|
|
70
|
+
from a mutated tree reads the first one's routes. That failure appears in production and not in
|
|
71
|
+
development.
|
|
72
|
+
|
|
73
|
+
## Naming routes
|
|
74
|
+
|
|
75
|
+
`routeMap` walks the assembled tree and reads the id off every route that carries one. The compiler
|
|
76
|
+
writes that id for a declared route. `namedRoute` writes it for one you wrote yourself. Both kinds
|
|
77
|
+
enter the map the same way, so you pass one value rather than a pair.
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
const settings = createRoute({
|
|
81
|
+
...namedRoute("app.settings"),
|
|
82
|
+
getParentRoute: () => shell,
|
|
83
|
+
path: "/settings",
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The walk refuses two routes carrying one id. Two routes under one id would send a link somewhere
|
|
88
|
+
different without the link itself changing.
|
|
89
|
+
|
|
90
|
+
### A path only one route may serve
|
|
91
|
+
|
|
92
|
+
The same walk refuses two routes serving one path under a shared parent. It counts the routes you
|
|
93
|
+
placed yourself as well as the ones it compiled. A pathless layout consumes no path segment, so
|
|
94
|
+
`/app/_yours/settings` and `/app/settings` are one URL however many layouts stand between.
|
|
95
|
+
|
|
96
|
+
A development build of the library reports that pair as a duplicate route. A production build keeps
|
|
97
|
+
the first and drops the rest without reporting it. The refusal is here as well so that both builds
|
|
98
|
+
fail the same way.
|
|
99
|
+
|
|
100
|
+
## Linking by id
|
|
101
|
+
|
|
102
|
+
Pass the reference the plugin SDK returned, not a string. A reference carries the id and, in its
|
|
103
|
+
type alone, the parameters the route's path names.
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
import { RouteLink, useRouteHref } from "@stealthscale/provider-router";
|
|
107
|
+
|
|
108
|
+
<RouteLink activeProps={{ className: "current" }} params={{ invoice }} to={invoices.one}>
|
|
109
|
+
Open
|
|
110
|
+
</RouteLink>;
|
|
111
|
+
|
|
112
|
+
const href = useRouteHref(invoices.one, { invoice });
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Filling the wrong parameter is a compile error, because the reference's type says which ones the
|
|
116
|
+
path names. A bare id string works too, and gives up that check.
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
<RouteLink params={{ id: "42" }} to={invoices.one} />
|
|
120
|
+
// 'id' does not exist in type '{ invoice: string }'
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`RouteRef` is declared structurally, so a plugin SDK's own reference type satisfies it without this
|
|
124
|
+
package depending on that SDK. Anything carrying an `id` fits.
|
|
125
|
+
|
|
126
|
+
The same resolution serves `navigate` and a `redirect` thrown in a loader, because both take the
|
|
127
|
+
path `routeHref` returns. A hook cannot run inside an event handler, so take the map and resolve
|
|
128
|
+
there.
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
const map = useRouteMap();
|
|
132
|
+
const navigate = useNavigate();
|
|
133
|
+
|
|
134
|
+
const open = (row: Row) => navigate({ to: routeHref(map, invoices.one, { invoice: row.id }) });
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
A resolved path is relative to the route tree, and the library adds your `basepath` when it builds
|
|
138
|
+
the link. A router at `basepath: "/admin"` draws `/admin/app/invoices` for a route compiled at
|
|
139
|
+
`/app/invoices`.
|
|
140
|
+
|
|
141
|
+
Both read the map through the router's own context, so nothing extra is mounted. Both throw rather
|
|
142
|
+
than resolve a path that is wrong: an unknown id, a missing parameter, and a tree no router has
|
|
143
|
+
processed each fail where you wrote them.
|
|
144
|
+
|
|
145
|
+
### The active state needs no configuration
|
|
146
|
+
|
|
147
|
+
`RouteLink` takes everything the library's own `Link` takes, so an active link is marked without you
|
|
148
|
+
configuring anything. On the page it names, the anchor carries `data-status="active"`,
|
|
149
|
+
`aria-current="page"` and a class of `active`.
|
|
150
|
+
|
|
151
|
+
```css
|
|
152
|
+
a[data-status="active"] {
|
|
153
|
+
font-weight: bold;
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Matching is by prefix on a segment boundary. A link to `/app/invoices` stays marked on
|
|
158
|
+
`/app/invoices/42`, which is what a menu wants, and a link to `/` is not marked on `/app/invoices`.
|
|
159
|
+
Pass `activeOptions={{ exact: true }}` to mark only the exact page, and `activeProps={{}}` to drop
|
|
160
|
+
the `active` class the library adds by default.
|
|
161
|
+
|
|
162
|
+
## Reading the route a person is on
|
|
163
|
+
|
|
164
|
+
A named route carries its id in the library's own `staticData`, so a menu, a breadcrumb or a
|
|
165
|
+
telemetry hook reads it off the match rather than holding a second copy of the declaration list.
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
import { declaredOf, useDeclaredRoute, useMatches } from "@stealthscale/provider-router";
|
|
169
|
+
|
|
170
|
+
const here = useDeclaredRoute();
|
|
171
|
+
const trail = useMatches().map((match) => declaredOf(match));
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
`useDeclaredRoute` returns the deepest named route. That is the page a person is looking at, and it
|
|
175
|
+
returns nothing on a page drawn entirely from routes nobody named. Both functions check the shape
|
|
176
|
+
rather than trust it. `staticData` is untyped by design, and a route may carry anything under the
|
|
177
|
+
same name.
|
|
178
|
+
|
|
179
|
+
Each returns a reference to the object the route carries rather than a copy. A navigation that left
|
|
180
|
+
the page alone therefore re-renders nothing that reads them.
|
|
181
|
+
|
|
182
|
+
## Reading a page's own parameters
|
|
183
|
+
|
|
184
|
+
A compiled route is outside the tree the application registered. The library cannot type its
|
|
185
|
+
parameters, and `useParams` returns a loose record. Pass the reference, which carries the types.
|
|
186
|
+
|
|
187
|
+
```tsx
|
|
188
|
+
import { useRouteParams } from "@stealthscale/provider-router";
|
|
189
|
+
|
|
190
|
+
export function Invoice() {
|
|
191
|
+
const { invoice } = useRouteParams(invoices.one);
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
It checks at run time that the page is the route the reference names before it makes the claim, so a
|
|
196
|
+
reference copied from another page throws rather than mistyping what it returns.
|
|
197
|
+
|
|
198
|
+
Search parameters have no equivalent. A reference carries no search type, so read them with
|
|
199
|
+
`useSearch({ strict: false })` and validate at the edge.
|
|
200
|
+
|
|
201
|
+
## A link to a route nobody may reach
|
|
202
|
+
|
|
203
|
+
A condition decides whether a route is routed, not whether it is named. A route whose `when` fails
|
|
204
|
+
is still in the tree and still in the map, so a link to it resolves and then returns a 404.
|
|
205
|
+
|
|
206
|
+
A menu drawn from declarations has to filter them with the same evaluator the compiler was given.
|
|
207
|
+
The foundation does not do it for you, because which entries a person should see is a question about
|
|
208
|
+
your product rather than about routing.
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
const shown = declarations.filter((one) => one.when === undefined || evaluate(one.when));
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Inside a declaration
|
|
215
|
+
|
|
216
|
+
`RouteDeclaration` is the compiled form a plugin SDK produces, not the manifest form. A page is
|
|
217
|
+
either a component or an importer with the export it is published under, because a React component
|
|
218
|
+
is a function and nothing at run time separates one from an importer.
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
{ component: { export: "Invoices", load: () => import("./invoices.js") } }
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
The export name is optional, and the module's default export is used without one. Both go straight
|
|
225
|
+
to the library's `lazyRouteComponent`. The page's chunk loads on the first navigation to it, and a
|
|
226
|
+
chunk the deployment has replaced is reported rather than ignored.
|
|
227
|
+
|
|
228
|
+
`layout` names layouts outermost first. Two declarations naming the same layouts with the same
|
|
229
|
+
options share one pathless parent. Naming a layout a route above already draws is refused, because
|
|
230
|
+
the frame would otherwise be drawn twice.
|
|
231
|
+
|
|
232
|
+
A condition is whatever language your host writes one in, and the `evaluate` you pass reads it. A
|
|
233
|
+
condition that fails makes the route a 404, so a route nobody may reach resolves to nothing. An
|
|
234
|
+
evaluator wanting anything else, such as sending an unauthenticated person to sign in, throws the
|
|
235
|
+
library's `redirect` itself.
|
|
236
|
+
|
|
237
|
+
`compileRoutes` refuses a declaration stating `outlet`. A screen maps to a route and the route
|
|
238
|
+
decides the whole screen, so a page drawn beside another as a pane has no route of its own.
|
|
239
|
+
|
|
240
|
+
Draw a detail beside a list by declaring it as a child, which is what an outlet is for. The parent
|
|
241
|
+
lays out its own content beside `<Outlet />`, and the pane gets a real URL, the back button and
|
|
242
|
+
preloading with it.
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
{ component: List, id: "acme.list", path: "/invoices" }
|
|
246
|
+
{ component: Detail, id: "acme.detail", parent: "acme.list", path: "$invoice" }
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Two `<Outlet />` in one component draw the same child twice. The library matches one route per level
|
|
250
|
+
and `Outlet` takes no name, so there is no second pane to fill.
|
|
251
|
+
|
|
252
|
+
## Testing
|
|
253
|
+
|
|
254
|
+
`@stealthscale/testing-router` mounts a tree and renders the page a path matches, so a specification
|
|
255
|
+
reads a screen rather than driving a router.
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
const { result } = await mountRoute(buildTree(await declarations()), "/app/invoices/42");
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Registering the type
|
|
262
|
+
|
|
263
|
+
The library derives paths, params and search from one declared router type. An application whose
|
|
264
|
+
routes are all in the build declares it and gets a checked `Link`.
|
|
265
|
+
|
|
266
|
+
Put it in a declaration file beside the tree. The statement is type-only and erases to nothing.
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
// src/register.d.ts
|
|
270
|
+
import { type Routed } from "#routes.ts";
|
|
271
|
+
|
|
272
|
+
declare module "@tanstack/react-router" {
|
|
273
|
+
interface Register {
|
|
274
|
+
router: Routed;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
The import keeps the file a module. `declare module` with no import and no export is an ambient
|
|
280
|
+
declaration, which replaces the library's types rather than adding to them.
|
|
281
|
+
|
|
282
|
+
That augmentation names `@tanstack/react-router`, so an application importing everything else from
|
|
283
|
+
this package still names the library in this one file. A route this package compiled is not in the
|
|
284
|
+
registered tree, which is why `RouteLink` and `useRouteParams` exist.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"$schema":"http://cyclonedx.org/schema/bom-1.7.schema.json","bomFormat":"CycloneDX","specVersion":"1.7","version":1,"metadata":{"lifecycles":[{"phase":"build"}],"tools":{"components":[{"type":"application","name":"rolldown","version":"1.2.7"},{"type":"application","name":"vite","version":"8.2.2"},{"type":"library","name":"core","group":"@arethetypeswrong","version":"0.18.5","bom-ref":"pkg:npm/%40arethetypeswrong/core@0.18.5","author":"Andrew Branch","description":"The API behind arethetypeswrong.github.io","hashes":[{"alg":"SHA-512","content":"f72b63cc6c318e6f54cfb23d6af7dbb79be542deae93db914444b3263aabce797a58abc8e9dc184e8faf277534d96aeafe64778aa97f3f386f1e129d2480230d"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40arethetypeswrong/core@0.18.5","externalReferences":[{"url":"https://github.com/arethetypeswrong/arethetypeswrong.github.io.git#packages/core","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=20"}]},{"type":"library","name":"testing-config","group":"@stealthscale","version":"0.4.0","bom-ref":"pkg:npm/%40stealthscale/testing-config@0.4.0","description":"Lists every part of the house contract a config, plugin or library package breaks.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/testing-config@0.4.0","externalReferences":[{"url":"https://github.com/stealth-scale/config/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/config.git#packages/testing-config","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/config/tree/main/packages/testing-config#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-config-react","group":"@stealthscale","version":"0.8.0","bom-ref":"pkg:npm/%40stealthscale/vite-config-react@0.8.0","description":"Adds the JSX transform, the React lint rules, a test document and an MDX compiler to a package that renders.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-config-react@0.8.0","externalReferences":[{"url":"https://github.com/stealth-scale/config/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/config.git#packages/vite-config-react","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/config/tree/main/packages/vite-config-react#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-config-typescript","group":"@stealthscale","version":"0.3.0","bom-ref":"pkg:npm/%40stealthscale/vite-config-typescript@0.3.0","description":"Sets the TypeScript options every stealthscale package compiles with.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-config-typescript@0.3.0","externalReferences":[{"url":"https://github.com/stealth-scale/config/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/config.git#packages/vite-config-typescript","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/config/tree/main/packages/vite-config-typescript#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"vite-config","group":"@stealthscale","version":"0.6.0","bom-ref":"pkg:npm/%40stealthscale/vite-config@0.6.0","description":"Configures a package from five Vite+ tiers and a named layer for every block.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/vite-config@0.6.0","externalReferences":[{"url":"https://github.com/stealth-scale/config/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/config.git#packages/vite-config","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/config/tree/main/packages/vite-config#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}]},{"type":"library","name":"react-router","group":"@tanstack","version":"1.170.34","bom-ref":"pkg:npm/%40tanstack/react-router@1.170.34","author":"Tanner Linsley","description":"Modern and scalable routing for React applications","hashes":[{"alg":"SHA-512","content":"cd8cb548d8c820010c7d4f66aa6079d7bd4f7842ecfe4dd247e53a4310ca4aac8c2f0e00aba47e782e7b49af2207a5fdd6ad68b844b7d2485abb2630c3824c71"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40tanstack/react-router@1.170.34","externalReferences":[{"url":"git+https://github.com/TanStack/router.git#packages/react-router","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://tanstack.com/router","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=20.19"}]},{"type":"library","name":"react","group":"@testing-library","version":"16.3.3","bom-ref":"pkg:npm/%40testing-library/react@16.3.3","author":"Kent C. Dodds <me@kentcdodds.com> (https://kentcdodds.com)","description":"Simple and complete React DOM testing utilities that encourage good testing practices.","hashes":[{"alg":"SHA-512","content":"528d7ddcd8106cf333ea5aeb86d45040570c0ba45efc42cb15b6ee54bdf4583959c65a597fdfe53074c05713d12f0d6ad62bbd389991d5cd812e210d46cb5d06"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40testing-library/react@16.3.3","externalReferences":[{"url":"https://github.com/testing-library/react-testing-library/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"https://github.com/testing-library/react-testing-library","type":"vcs","comment":"as detected from PackageJson property \"repository.url\""},{"url":"https://github.com/testing-library/react-testing-library#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=18"}]},{"type":"library","name":"react-dom","group":"@types","version":"19.3.0","bom-ref":"pkg:npm/%40types/react-dom@19.3.0","description":"TypeScript definitions for react-dom","hashes":[{"alg":"SHA-512","content":"648edb538da66575ca1e7fea34b130d88adb888354ed7e7ebdf81d8b10479023696165e32a07d0fcffaec866f90a338b07d51c9d37a0debca542d5768729b8e1"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40types/react-dom@19.3.0","externalReferences":[{"url":"https://github.com/DefinitelyTyped/DefinitelyTyped.git#types/react-dom","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react-dom","type":"website","comment":"as detected from PackageJson property \"homepage\""}]},{"type":"library","name":"react","group":"@types","version":"19.3.0","bom-ref":"pkg:npm/%40types/react@19.3.0","description":"TypeScript definitions for react","hashes":[{"alg":"SHA-512","content":"374ac50ae1fd628c46f7f9bad65f4c7e924a7e62ce554d1e9bb8a9233e9346049292f45e2c1f6f2fce4607ecabf01b3995eaa9be0f7a252c05e194b5b38be242"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40types/react@19.3.0","externalReferences":[{"url":"https://github.com/DefinitelyTyped/DefinitelyTyped.git#types/react","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react","type":"website","comment":"as detected from PackageJson property \"homepage\""}]},{"type":"library","name":"coverage-v8","group":"@vitest","version":"4.1.11","bom-ref":"pkg:npm/%40vitest/coverage-v8@4.1.11","author":"Anthony Fu <anthonyfu117@hotmail.com>","description":"V8 coverage provider for Vitest","hashes":[{"alg":"SHA-512","content":"f0c5461059c921c7468dc6df2a67aaf33d296471f426556da15647f50feac14a7ac3216710950132bc3d0c26a3fab6b7bd28469a16af8da94c2213cdc5901473"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40vitest/coverage-v8@4.1.11","externalReferences":[{"url":"https://github.com/vitest-dev/vitest/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"git+https://github.com/vitest-dev/vitest.git#packages/coverage-v8","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://vitest.dev/guide/coverage","type":"website","comment":"as detected from PackageJson property \"homepage\""}]},{"type":"library","name":"babel-plugin-react-compiler","version":"1.0.0","bom-ref":"pkg:npm/babel-plugin-react-compiler@1.0.0","description":"Babel plugin for React Compiler.","hashes":[{"alg":"SHA-512","content":"2319bcb457e828a20f61d0822984ecaaff85778209d0342a3321229a8fa9c5438c511f5c54f9704eb16df40beefb771be99a77980ce5fadd4cac6d9fc712acc7"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/babel-plugin-react-compiler@1.0.0","externalReferences":[{"url":"git+https://github.com/facebook/react.git#compiler/packages/babel-plugin-react-compiler","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""}]},{"type":"library","name":"happy-dom","version":"20.14.5","bom-ref":"pkg:npm/happy-dom@20.14.5","author":"David Ortner","description":"Happy DOM is a JavaScript implementation of a web browser without its graphical user interface. It includes many web standards from WHATWG DOM and HTML.","hashes":[{"alg":"SHA-512","content":"c7f47392958ee346d38c8a13df4890b6deb814b2e61ff89171408dd97fff6cbc7b1f789f91d7cf5f2aacae8fce62dab32008622cc300ee69a2391f42dcd38a8d"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/happy-dom@20.14.5","externalReferences":[{"url":"https://github.com/capricorn86/happy-dom","type":"vcs","comment":"as detected from PackageJson property \"repository\""},{"url":"https://github.com/capricorn86/happy-dom","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=20.0.0"}]},{"type":"library","name":"oxc-transform-react","version":"0.149.0","bom-ref":"pkg:npm/oxc-transform-react@0.149.0","author":"Boshen and oxc contributors","description":"Oxc React Compiler Node API","hashes":[{"alg":"SHA-512","content":"69bdddc5c3ed90349f211f6d35dc4752d9a974bd258479ddb010fd214014e41c6d26dc061bff39367473b367f62b0a2e3641e5edc692b3030b41e52fc3714447"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/oxc-transform-react@0.149.0","externalReferences":[{"url":"https://github.com/oxc-project/oxc/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/oxc-project/oxc.git#napi/transform-react","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://oxc.rs","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":"^20.19.0 || >=22.12.0"}]},{"type":"library","name":"react-dom","version":"19.3.0","bom-ref":"pkg:npm/react-dom@19.3.0","description":"React package for working with the DOM.","hashes":[{"alg":"SHA-512","content":"24393c76089fe753a31680c4ef4f8e4fd202c98afeebd1e59a284dc29d7e36c7db9dadede6c22209af59264b43990e3fd5bfeb9f6ea1200476b985c332be6bd1"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/react-dom@19.3.0","externalReferences":[{"url":"https://github.com/react/react/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"https://github.com/react/react.git#packages/react-dom","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://react.dev/","type":"website","comment":"as detected from PackageJson property \"homepage\""}]},{"type":"library","name":"react","version":"19.3.0","bom-ref":"pkg:npm/react@19.3.0","description":"React is a JavaScript library for building user interfaces.","hashes":[{"alg":"SHA-512","content":"13c2d471bb415addb46db9766281dfc7864305dc554df38ab42667f5c0d227897afe7ba8029729201723e3bb76c19a155fc836647b8c1db892860091d53e52a2"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/react@19.3.0","externalReferences":[{"url":"https://github.com/react/react/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"https://github.com/react/react.git#packages/react","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://react.dev/","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=0.10.0"}]},{"type":"library","name":"typescript","version":"7.0.2","bom-ref":"pkg:npm/typescript@7.0.2","author":"Microsoft Corp.","description":"TypeScript is a language for application scale JavaScript development","hashes":[{"alg":"SHA-512","content":"f0561abbdea8dcd28e85b8ca8bfa8dbc6fd6e63873c646dd9b9b23f406d9ff94f9b16aa7de12602df1b1dbbb11299593bf2cc23fc74b4414dfe6d05349155434"}],"licenses":[{"license":{"id":"Apache-2.0"}}],"purl":"pkg:npm/typescript@7.0.2","externalReferences":[{"url":"https://github.com/microsoft/TypeScript/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"https://github.com/microsoft/TypeScript.git","type":"vcs","comment":"as detected from PackageJson property \"repository.url\""},{"url":"https://www.typescriptlang.org/","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=16.20.0"}]},{"type":"library","name":"vitest","version":"4.1.11","bom-ref":"pkg:npm/vitest@4.1.11","author":"Anthony Fu <anthonyfu117@hotmail.com>","description":"Next generation testing framework powered by Vite","hashes":[{"alg":"SHA-512","content":"7e1002acd5d489d21b19206be4595bb8190eed5582d59c8b9740cee025360eb42800fc57f3862cc6cf877864298a2e656565754388016534eee3d985f80e8477"}],"licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/vitest@4.1.11","externalReferences":[{"url":"https://github.com/vitest-dev/vitest/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs.url\""},{"url":"git+https://github.com/vitest-dev/vitest.git#packages/vitest","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://vitest.dev","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":"^20.0.0 || ^22.0.0 || >=24.0.0"}]}]},"component":{"type":"library","name":"provider-router","group":"@stealthscale","version":"0.1.0","bom-ref":"pkg:npm/%40stealthscale/provider-router@0.1.0","description":"Publishes the routes an application navigates by, and the options every router starts from.","licenses":[{"license":{"id":"MIT"}}],"purl":"pkg:npm/%40stealthscale/provider-router@0.1.0","externalReferences":[{"url":"https://github.com/stealth-scale/config/issues","type":"issue-tracker","comment":"as detected from PackageJson property \"bugs\""},{"url":"git+https://github.com/stealth-scale/config.git#foundations/providers/router","type":"vcs","comment":"as detected from PackageJson property \"repository.url\" and \"repository.directory\""},{"url":"https://github.com/stealth-scale/config/tree/main/foundations/providers/router#readme","type":"website","comment":"as detected from PackageJson property \"homepage\""}],"properties":[{"name":"cdx:npm:package:constraint:engine:node","value":">=26.0.0"}],"evidence":{"licenses":[{"license":{"name":"file: LICENSE","text":{"content":"TUlUIExpY2Vuc2UKCkNvcHlyaWdodCAoYykgMjAyNiBTdGVhbHRoIFNjYWxlIEIuVi4KClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHkKb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwKaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cwp0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsCmNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcwpmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsCmNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUgpJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwKRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFCkFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIKTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwKT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUKU09GVFdBUkUuCg==","contentType":"text/plain","encoding":"base64"}}}]}},"supplier":{"name":"Stealth Scale B.V.","url":["https://stealthscale.io"]}},"components":[],"dependencies":[{"ref":"pkg:npm/%40stealthscale/provider-router@0.1.0"}]}
|