@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 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"}]}