@loozo/angular-router 0.0.0-stage → 0.0.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/.npmignore ADDED
@@ -0,0 +1,3 @@
1
+ # Nested package.json's are only needed for development.
2
+ _core/package.json
3
+ _generated/package.json
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Theophilos Matzavinos
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 CHANGED
@@ -1,3 +1,115 @@
1
- # Temporary Holding Version
1
+ # @loozo/angular-router
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Typed route declarations, codecs, URLs and navigation on top of Angular’s native router. Static generation supplies route configuration, typed destinations and route handles without introducing a second router. Angular owns matching, activation, guards, resolvers, redirects, history and stability.
4
+
5
+ This is an experimental implementation. The reviewed rebuild passed all 126 cases in the approved acceptance copy, plus source review and native consumer/build/browser checks. It is not yet broadly battle-tested. Version `0.0.1` is experimental and MIT-licensed.
6
+
7
+ ```ts
8
+ import {
9
+ defineRoute,
10
+ createUrl,
11
+ numberParam,
12
+ enumParam,
13
+ optionalSearchParam,
14
+ } from "@loozo/angular-router";
15
+
16
+ const product = defineRoute("products/$productId", {
17
+ params: { productId: numberParam },
18
+ search: { tab: optionalSearchParam(enumParam(["details", "reviews"])) },
19
+ fragments: ["summary", "reviews"],
20
+ });
21
+
22
+ createUrl(product, {
23
+ params: { productId: 42 },
24
+ search: { tab: "reviews" },
25
+ fragment: "summary",
26
+ }); // /products/42?tab=reviews#summary
27
+ ```
28
+
29
+ Root runtime exports are exactly `defineRoute`, `createUrl`, `stringParam`, `numberParam`, `booleanParam`, `enumParam`, `optionalSearchParam`, `nullableSearchParam`. Public types are `Route` and `ParamCodec`. `_core` is internal package coupling, not an application metadata/graph API.
30
+
31
+ Paths are decoded authored text. `$id` consumes one logical value (repeated local occurrences reuse that value); terminal `$parts[]` consumes a required readonly array, including `[]`. Parent declarations inherit input ownership through pathless nodes. Catchalls cannot have children. Search keys are globally sorted; fragment names are local, never inherited. Codecs stringify synchronously; no parsing or native callbacks run during declaration/URL creation.
32
+
33
+ Route membership is per physical package instance. Routes and owned containers are shallow-frozen; application codecs, callbacks/providers and opaque values retain identity and are not recursively frozen. `Route<Path, Params, Search, Resolvers = {}>` has readonly optional input/data witnesses. Callback inputs infer effective params/search, except matching guards see only local positional params. Local data unwraps Promise/Observable outputs and excludes RedirectCommand.
34
+
35
+ ## Commands
36
+
37
+ Prerequisites: Node 24.21.0, pnpm 12.9.1, ordinary workspace installation. Run installation from the workspace with `pnpm_config_pm_on_fail=error pnpm_config_verify_deps_before_run=error pnpm install --frozen-lockfile`.
38
+
39
+ From this package directory:
40
+
41
+ ```sh
42
+ pnpm run build # NodeNext tsc + native ng-packagr primary/_core/_generated APF
43
+ pnpm run check # no-fix source formatting/lint checks
44
+ pnpm run typecheck # strict source check, no output
45
+ pnpm run typecheck:consumers # strict NodeNext and ESNext/Bundler against actual APF
46
+ pnpm run test:root # durable public-root runtime regressions; plain Node
47
+ pnpm run test:application /absolute/task-owned/absent-evidence-directory
48
+ pnpm run test:navigation /absolute/task-owned/absent-evidence-directory
49
+ pnpm run test:lifecycle /absolute/task-owned/absent-evidence-directory
50
+ pnpm run test:ssr /absolute/task-owned/absent-evidence-directory
51
+ node tests/packed.mjs /absolute/task-owned/fresh-evidence-directory
52
+ ```
53
+
54
+ Build cleans/emits only package `node/`, then ng-packagr cleans/emits `dist/` and uses package `node_modules/.cache/ng-packagr`; it cannot generate/repair application files. Private Node generation/builders use ordinary NodeNext tsc; manifests/schemas/Node JS are copied as APF assets. Source and packed builder manifests use the same relative paths. Source metadata points to built APF output; ng-packagr rewrites dist metadata to its own paths. Packed verification writes only the supplied fresh evidence directory, packs the actual dist manifest, checks the handwritten TypeScript consumer under NodeNext and ESNext/Bundler, nominal declaration brands, eight-value namespace, plain-Node loading and distinct physical instances. It reuses actual installed dependency bindings; there is no loader/compiler adapter or publication.
55
+
56
+ ## Authored application → native Angular
57
+
58
+ The application installs `routes` from `generated/routes.generated.js` with native `provideRouter`. The companion targets in `consumer/angular.json` generate only exact-name marked artifacts and delegate directly to the official application/dev-server targets. Source candidates are native tsconfig roots intersected with configured scans; analysis never imports/evaluates app modules. Definitions/pages remain application-owned. `_generated` is internal generator coupling, not a supported graph API.
59
+
60
+ From the workspace root, after package build:
61
+
62
+ ```sh
63
+ pnpm run consumer:build # development generation + official Angular build
64
+ pnpm run consumer:check # read-only check:true before official Angular build
65
+ pnpm run consumer:serve # ready watcher → generation → official dev-server
66
+ ```
67
+
68
+ The colocated facade exports parameterless `injectRoute()` and an inert `destination`. Definition getters/reference construction avoid eager ESM binding reads. Normal lazy page imports are extensionless direct import promises; emitted `.js` is used only when native Bundler resolution needs it to preserve the discovered identity.
69
+
70
+ Durable public Architect/filesystem/real-browser development regression (requires `/usr/bin/chromium`):
71
+
72
+ ```sh
73
+ pnpm --filter @loozo/angular-router run test:application /absolute/task-owned/absent-evidence-directory
74
+ ```
75
+
76
+ The evidence-directory argument is required and must not exist. This creates an owned consumer copy, checks concrete facade-factory provenance, literal module-reference preflight, native exact/wildcard ambient helpers, drift priority/nonwrites/byte-identical modes/nanosecond mtimes, and native watch/repair/stop. Its page.js.ts + named-only page.ts collision is built by real Angular and rendered in Chromium.
77
+
78
+ ## Generated selection → native navigation
79
+
80
+ ```ts
81
+ import { injectRoute } from "./route.generated.js";
82
+ import { destination as report } from "../report/route.generated.js";
83
+
84
+ const route = injectRoute(); // parameterless, noncallable; readonly native Resources
85
+ route.link(".", { params: { scopeId: "x" } }); // exact declaration schema
86
+ route.link("./", { params: { scopeId: "x" }, search: { leaf: "required" } }); // canonical winner at this path
87
+ route.link("/reports/$reportId", { params: { reportId: 42 } }); // literal template, not concrete URL
88
+ route.navigate(report, { params: { reportId: 42 } }); // exact exported object declaration
89
+ ```
90
+
91
+ Every origin's absolute and URL-segment-relative selections are computed statically into one shared artifact; colocated facades do not duplicate graph tables. Relative climbs count authored template segments, not directories or parent edges. Unknown/intermediate/nonwinning paths, over-climbs, mixed traversal and query/hash relative suffixes are absent. Catchall origins expose exact-current and absolute/reference targets, never depth-dependent relative navigation. Absolute redirect-source selections serialize their source inputs.
92
+
93
+ Selectors must be single known literals (not widened strings/unions). Values retain the selected target's codecs, required/optional search modifiers and own fragments, with no current-input reuse or third/extras argument. References have a module-local type set identity and authenticate at runtime through weak ownership plus the exact stable generated set object; byte-identical foreign sets and clones are not equivalent. No route expression is parsed against a graph at runtime. Validation/serialization is synchronous before Angular: link calls native parseUrl; navigate calls native navigateByUrl and returns that identical Promise.
94
+
95
+ `test:navigation` uses handwritten strict generated consumers and genuine Architect/Angular/Chromium to check type negatives (including optional prototype-named keys), canonical/exact/reference targets, foreign sets, invalid-call non-entry, native Promise/RouterLink behavior and unrelated facade stability. Like `test:application`, it requires a fresh absent evidence directory.
96
+
97
+ ## Native inputs and lifecycle
98
+
99
+ Exact declarations/complete snapshots share one frozen parsed-input operation; matching candidates share a separate local-position/effective-query operation. All raw cardinalities/types are checked before independent codecs launch. Guards/resolvers enter in the captured native Injector only while subscribed; Angular owns ordering, first values, empty/redirect/error semantics and teardown. Local data projects only own native results among declared string and symbol resolver keys, preserving own `undefined` and opaque values; inherited or missing results are not fabricated. Native rerun policy remains authoritative.
100
+
101
+ Angular 22.1.5 compatibility footnote: Angular’s resolved-data accumulator loses a resolver result named `__proto__`. The handle follows native behavior: it omits the missing value rather than fabricating inherited data. This is an upstream Angular issue, not an added package restriction or an alpha-release blocker. No transport workaround or result cache is added.
102
+
103
+ Each handle owns paired params/search visibility and independent local data, projected into real readonly native Resources. Navigation hides old values; cancel/skip restores the true survivor without reparsing. Commitment bookkeeping is separate from visibility, including reentrant Start8→End7→Cancel8. Relevant handle work holds native PendingTasks, publishes before release, and releases on error/obsolete commitment/destruction. Constructor-time task handoff covers handles created inside native terminal listeners. Promises are not abortable; late failures are observed and cannot publish obsolete output. No URL/data cache, timeout, or second router exists.
104
+
105
+ `test:lifecycle` uses actual Architect/Angular/Chromium and public Router/ApplicationRef/PendingTasks with asynchronous gates, a never-settling obsolete survivor, terminal-listener construction, own string/symbol data, nearest declaring-parent ancestry, injector destruction during task acquisition, same-URL skip reentry, iframe/host Promise guards/resolvers, and synchronous preserved-search failure with a later source rejection. Like the other public tests it requires a fresh absent evidence-directory argument.
106
+
107
+ Full acceptance passed against the reviewed rebuild using the explicitly approved v2 copy. That copy corrects two fixture assumptions: an already-current native redirect resolves `false`, and the SSR route TypeScript program needs Node ambient types. Original inputs and earlier failed results remain preserved separately; this is not a claim that the unchanged original suite passed. The supplied handwritten home consumer remains unchanged.
108
+
109
+ ## Native SSR and hydration proof
110
+
111
+ `consumer/ssr-proof/` is a separate handwritten Angular application. Componentless team inputs, delayed item/score codecs (75 ms), local deterministic catalog resolution, a query/hash-dropping alias, and a resolver-free delayed handle page use genuine generated facades. Shared configuration uses native hydration with no HTTP transfer cache and no blocking initial navigation.
112
+
113
+ `test:ssr` copies that actual application into the required fresh absent evidence directory, runs ordinary Architect production builds and read-only generation checks, and checks strict native TypeScript/Angular templates. Built `AngularNodeAppEngine` + Node HTTP demonstrate native302, matched-position matrix isolation, concurrent request isolation and handle-only stability. Official dev-server + Chromium preserve exact original SSR document/element/text Nodes during hydration, then reuse the same component/DOM for typed alias and query-only SPA navigation. Native production metafile evidence checks browser closure and genuinely lazy page chunks. Servers/browser/Architect runs are stopped in `finally`; raw HTTP HTML/headers, logs, stats and observations remain inspectable.
114
+
115
+ This is a bounded SSR/hydration proof, not cross-browser certification or exhaustive request/fault coverage. The Node entry is a loopback SSR HTTP proof server, not a production static-asset deployment server; use official companion serve for browser demonstration. See `consumer/ssr-proof/README.md`.
package/builders.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "$schema": "./node_modules/@angular-devkit/architect/src/builders-schema.json",
3
+ "builders": {
4
+ "application": {
5
+ "implementation": "./node/src/builders/application.js",
6
+ "schema": "./schemas/application.json",
7
+ "description": "Generate/check authored routes, then build with the official Angular application target."
8
+ },
9
+ "serve": {
10
+ "implementation": "./node/src/builders/serve.js",
11
+ "schema": "./schemas/serve.json",
12
+ "description": "Watch authored routes and delegate to the official Angular dev-server target."
13
+ }
14
+ }
15
+ }