@real-router/angular 0.8.0 → 0.9.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.
Files changed (43) hide show
  1. package/README.md +183 -4
  2. package/dist/README.md +183 -4
  3. package/dist/fesm2022/real-router-angular-ssr.mjs +323 -0
  4. package/dist/fesm2022/real-router-angular-ssr.mjs.map +1 -0
  5. package/dist/fesm2022/real-router-angular.mjs +759 -173
  6. package/dist/fesm2022/real-router-angular.mjs.map +1 -1
  7. package/dist/types/real-router-angular-ssr.d.ts +227 -0
  8. package/dist/types/real-router-angular-ssr.d.ts.map +1 -0
  9. package/dist/types/real-router-angular.d.ts +119 -20
  10. package/dist/types/real-router-angular.d.ts.map +1 -1
  11. package/package.json +18 -11
  12. package/src/components/RouteView.ts +81 -56
  13. package/src/components/RouterErrorBoundary.ts +7 -5
  14. package/src/directives/RealLink.ts +57 -37
  15. package/src/directives/RealLinkActive.ts +34 -25
  16. package/src/dom-utils/link-utils.ts +119 -7
  17. package/src/dom-utils/route-announcer.ts +58 -2
  18. package/src/dom-utils/scroll-restore.ts +160 -12
  19. package/src/functions/injectIsActiveRoute.ts +9 -8
  20. package/src/functions/injectNavigator.ts +4 -0
  21. package/src/functions/injectOrThrow.ts +5 -1
  22. package/src/functions/injectRoute.ts +17 -8
  23. package/src/functions/injectRouteEnter.ts +5 -10
  24. package/src/functions/injectRouteNode.ts +3 -0
  25. package/src/functions/injectRouteUtils.ts +3 -0
  26. package/src/functions/injectRouter.ts +4 -0
  27. package/src/functions/injectRouterTransition.ts +3 -0
  28. package/src/index.ts +14 -3
  29. package/src/internal/buildActiveRouteOptions.ts +20 -0
  30. package/src/internal/install.ts +77 -0
  31. package/src/internal/subscribeSourceToSignal.ts +48 -0
  32. package/src/providers.ts +11 -38
  33. package/src/providersFactory.ts +298 -0
  34. package/src/sourceToSignal.ts +10 -2
  35. package/src/types.ts +6 -1
  36. package/ssr/components/ClientOnly.ts +27 -0
  37. package/ssr/components/HttpStatusCode.ts +106 -0
  38. package/ssr/components/ServerOnly.ts +27 -0
  39. package/ssr/functions/injectDeferred.ts +92 -0
  40. package/ssr/functions/provideHttpStatusSink.ts +43 -0
  41. package/ssr/ng-package.json +6 -0
  42. package/ssr/public_api.ts +35 -0
  43. package/ssr/utils/createHttpStatusSink.ts +61 -0
@@ -0,0 +1,227 @@
1
+ import * as i0 from '@angular/core';
2
+ import { TemplateRef, OnInit, Signal, InjectionToken, EnvironmentProviders } from '@angular/core';
3
+
4
+ declare class ClientOnly {
5
+ readonly fallback: i0.InputSignal<TemplateRef<unknown> | undefined>;
6
+ readonly mounted: i0.WritableSignal<boolean>;
7
+ constructor();
8
+ static ɵfac: i0.ɵɵFactoryDeclaration<ClientOnly, never>;
9
+ static ɵcmp: i0.ɵɵComponentDeclaration<ClientOnly, "client-only", never, { "fallback": { "alias": "fallback"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
10
+ }
11
+
12
+ declare class ServerOnly {
13
+ readonly fallback: i0.InputSignal<TemplateRef<unknown> | undefined>;
14
+ readonly mounted: i0.WritableSignal<boolean>;
15
+ constructor();
16
+ static ɵfac: i0.ɵɵFactoryDeclaration<ServerOnly, never>;
17
+ static ɵcmp: i0.ɵɵComponentDeclaration<ServerOnly, "server-only", never, { "fallback": { "alias": "fallback"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
18
+ }
19
+
20
+ /**
21
+ * Render-time HTTP status declaration. Mount inside a route component
22
+ * (typical use case: a glob `*` route's NotFound page) when the status is
23
+ * decided by the rendered tree rather than a loader.
24
+ *
25
+ * Writes `code` to the optionally injected `HTTP_STATUS_SINK` in `ngOnInit`
26
+ * (after the input binding has fired) and renders nothing. Without a provider
27
+ * registered (the standard client-side case) the component is a silent no-op
28
+ * — same component tree hydrates without touching the DOM or warning about
29
+ * mismatches.
30
+ *
31
+ * Loader-driven errors (`LoaderNotFound` → 404, `LoaderRedirect` → 30x) keep
32
+ * working as before; this component covers render-time decisions only.
33
+ *
34
+ * Last write wins when several `<http-status-code />` instances mount in the
35
+ * same render pass — sink reflects the last component whose `ngOnInit` ran.
36
+ *
37
+ * ```ts
38
+ * // entry-server.ts
39
+ * import { bootstrapApplication } from "@angular/platform-browser";
40
+ * import {
41
+ * createHttpStatusSink,
42
+ * provideHttpStatusSink,
43
+ * } from "@real-router/angular/ssr";
44
+ *
45
+ * const sink = createHttpStatusSink();
46
+ * await bootstrapApplication(AppRoot, {
47
+ * providers: [
48
+ * provideRealRouterFactory({ ... }),
49
+ * provideHttpStatusSink(sink),
50
+ * ],
51
+ * });
52
+ * response.status(sink.code ?? 200).send(html);
53
+ * ```
54
+ *
55
+ * ```html
56
+ * <!-- inside not-found.component.ts template -->
57
+ * <http-status-code [code]="404" />
58
+ * ```
59
+ *
60
+ * **Per-request wiring with `AngularNodeAppEngine`:** the sink must be
61
+ * passed via the second arg of `handle(req, requestContext)` — Angular
62
+ * surfaces it through the `REQUEST_CONTEXT` token. Attaching to `req`
63
+ * directly does NOT work: `AngularNodeAppEngine.handle` constructs a fresh
64
+ * Web `Request` from the Express `IncomingMessage` and discards every
65
+ * custom property. See the `ssr/` example's `app.config.ts` factory for
66
+ * the canonical pattern (`inject(REQUEST_CONTEXT, { optional: true })`
67
+ * → `(ctx as { httpStatusSink? } | null)?.httpStatusSink`).
68
+ *
69
+ * **`@angular/ssr` streaming + `@defer` blocks:** `@defer` blocks hydrate
70
+ * lazily on the client; their server-side rendering is fully synchronous,
71
+ * so `<http-status-code />` inside or outside a `@defer` writes to the
72
+ * sink before `AngularNodeAppEngine.handle` resolves. No streaming
73
+ * ordering concern in Angular's current SSR model.
74
+ *
75
+ * **JIT vs AOT:** the `code` input is declared as `input<number>()` (not
76
+ * `input.required<number>()`) because `input.required` trips `NG0950` in
77
+ * JIT/TestBed even after `componentRef.setInput(...)`. `ngOnInit` skips
78
+ * the write when `code()` is `undefined`. AOT (production build) binds
79
+ * the value normally and the skip never fires.
80
+ *
81
+ * **Valid `code` range:** Node's `res.end()` throws `Invalid status code`
82
+ * on `NaN`, `0`, negative values, or values `> 999` — this surfaces as a
83
+ * 5xx / dropped connection, not silent corruption. Pass a real HTTP status
84
+ * integer (commonly 4xx/5xx; 100-999 is what Node accepts).
85
+ */
86
+ declare class HttpStatusCode implements OnInit {
87
+ /**
88
+ * HTTP status to apply to the response. Common values: 404, 410, 451, 503.
89
+ *
90
+ * Declared as optional so the signal is safe to read in `ngOnInit` under
91
+ * both AOT (template binding fires before init hooks) and JIT/TestBed
92
+ * (`componentRef.setInput("code", N)` writes the value before the first
93
+ * change detection). `input.required` would trip `NG0950` in the JIT path
94
+ * because the required-flag is asserted independently of the runtime
95
+ * value. Consumers should always pass a value — `undefined` makes
96
+ * `ngOnInit` skip the sink write rather than throw.
97
+ */
98
+ readonly code: i0.InputSignal<number | undefined>;
99
+ private readonly sink;
100
+ ngOnInit(): void;
101
+ static ɵfac: i0.ɵɵFactoryDeclaration<HttpStatusCode, never>;
102
+ static ɵcmp: i0.ɵɵComponentDeclaration<HttpStatusCode, "http-status-code", never, { "code": { "alias": "code"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
103
+ }
104
+
105
+ /**
106
+ * Read a deferred promise published by `defer({ deferred: { <key>: Promise } })`
107
+ * inside an SSR data loader. Returns an Angular `Signal<T | undefined>` that
108
+ * tracks the active route — re-keying picks up the new state's deferred map.
109
+ *
110
+ * The signal starts `undefined` and updates to the resolved value once the
111
+ * promise settles. Use with native Angular control flow:
112
+ *
113
+ * ```ts
114
+ * @Component({
115
+ * template: `
116
+ * @if (reviews()) {
117
+ * <ul>
118
+ * @for (r of reviews(); track r.id) {
119
+ * <li>{{ r.author }}</li>
120
+ * }
121
+ * </ul>
122
+ * } @else {
123
+ * <p>Loading reviews…</p>
124
+ * }
125
+ * `,
126
+ * })
127
+ * export class Reviews {
128
+ * readonly reviews = injectDeferred<Review[]>("reviews");
129
+ * }
130
+ * ```
131
+ *
132
+ * **Asymmetric Angular** (see `.claude/SSR_FEATURE_GAPS_RU.md` §8): Angular
133
+ * does not ship `<Await>` / `<Streamed>` adapter components — Angular has no
134
+ * direct analogue to React's `use(promise)` or Svelte's `{#await}`. Use
135
+ * `@if (signal()) { … } @else { … }` or the `async` pipe with
136
+ * `from(deferredPromise)` instead.
137
+ */
138
+ declare function injectDeferred<T = unknown>(key: string): Signal<T | undefined>;
139
+
140
+ /**
141
+ * Render-scoped HTTP status sink. Created per request on the server and
142
+ * provided via `provideHttpStatusSink(sink)` (or directly through
143
+ * `{ provide: HTTP_STATUS_SINK, useValue: sink }`). Read after the SSR pass
144
+ * (`renderApplication` / `AngularNodeAppEngine` rendering) to apply the value
145
+ * to the HTTP response.
146
+ *
147
+ * Last write wins: if the rendered tree mounts more than one
148
+ * `<http-status-code [code]="N" />`, the value reflects the last component
149
+ * that ran during the render pass.
150
+ *
151
+ * No-op on the client — `<http-status-code />` injects `HTTP_STATUS_SINK`
152
+ * with `{ optional: true }` and skips the write when no provider is
153
+ * registered, so the same component tree can be hydrated without changing
154
+ * behaviour.
155
+ *
156
+ * Constraints:
157
+ * - **Per-request only.** Don't share a sink across requests; the rendered
158
+ * tree mutates `code` in place. Module-level singletons leak status
159
+ * between concurrent requests.
160
+ * - **Don't `Object.freeze` the sink.** The component writes to `.code`;
161
+ * freezing makes the assignment throw under ESM strict mode.
162
+ * - **Pass through `REQUEST_CONTEXT`, not via `req` properties.** Wire the
163
+ * sink with `angularApp.handle(req, { httpStatusSink })` and read it back
164
+ * in the `HTTP_STATUS_SINK` factory via `inject(REQUEST_CONTEXT)`.
165
+ * `AngularNodeAppEngine` builds a fresh Web `Request` from the
166
+ * `IncomingMessage` and discards every custom property, so attaching to
167
+ * `req` directly silently no-ops.
168
+ */
169
+ interface HttpStatusSink {
170
+ code: number | undefined;
171
+ }
172
+ declare function createHttpStatusSink(): HttpStatusSink;
173
+ /**
174
+ * DI token for the request-scoped HTTP status sink. Application-side wiring:
175
+ *
176
+ * ```ts
177
+ * import { bootstrapApplication } from "@angular/platform-browser";
178
+ * import { provideHttpStatusSink, createHttpStatusSink } from "@real-router/angular/ssr";
179
+ *
180
+ * const sink = createHttpStatusSink();
181
+ *
182
+ * await bootstrapApplication(AppRoot, {
183
+ * providers: [
184
+ * provideRealRouterFactory({ ... }),
185
+ * provideHttpStatusSink(sink),
186
+ * ],
187
+ * });
188
+ *
189
+ * response.status(sink.code ?? 200).send(html);
190
+ * ```
191
+ */
192
+ declare const HTTP_STATUS_SINK: InjectionToken<HttpStatusSink>;
193
+
194
+ /**
195
+ * Environment providers for a request-scoped `HttpStatusSink`. Pair with
196
+ * `createHttpStatusSink()` and read `sink.code` after the SSR render pass
197
+ * completes.
198
+ *
199
+ * Application bootstrap:
200
+ *
201
+ * ```ts
202
+ * const sink = createHttpStatusSink();
203
+ *
204
+ * await bootstrapApplication(AppRoot, {
205
+ * providers: [
206
+ * provideRealRouterFactory({ ... }),
207
+ * provideHttpStatusSink(sink),
208
+ * ],
209
+ * });
210
+ *
211
+ * response.status(sink.code ?? 200).send(html);
212
+ * ```
213
+ *
214
+ * Equivalent to:
215
+ *
216
+ * ```ts
217
+ * { provide: HTTP_STATUS_SINK, useValue: sink }
218
+ * ```
219
+ *
220
+ * Use the explicit `useValue` form when you need to compose with other
221
+ * application providers in a single `providers: [...]` block.
222
+ */
223
+ declare function provideHttpStatusSink(sink: HttpStatusSink): EnvironmentProviders;
224
+
225
+ export { ClientOnly, HTTP_STATUS_SINK, HttpStatusCode, ServerOnly, createHttpStatusSink, injectDeferred, provideHttpStatusSink };
226
+ export type { HttpStatusSink };
227
+ //# sourceMappingURL=real-router-angular-ssr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"real-router-angular-ssr.d.ts","sources":["../../ssr/components/ClientOnly.ts","../../ssr/components/ServerOnly.ts","../../ssr/components/HttpStatusCode.ts","../../ssr/functions/injectDeferred.ts","../../ssr/utils/createHttpStatusSink.ts","../../ssr/functions/provideHttpStatusSink.ts"],"mappings":";;;AAKA,cAWa,UAAU;uBACJA,EAAA,CAAA,WAAA,CAAA,WAAA;sBAEDA,EAAA,CAAA,cAAA;;yCAHL,UAAU;2CAAV,UAAU;AAUtB;;ACrBD,cAWa,UAAU;uBACJA,EAAA,CAAA,WAAA,CAAA,WAAA;sBAEDA,EAAA,CAAA,cAAA;;yCAHL,UAAU;2CAAV,UAAU;AAUtB;;ACpBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiEG;AACH,cAIa,cAAe,YAAW,MAAM;AAC3C;;;;;;;;;;AAUG;mBACUA,EAAA,CAAA,WAAA;AAIb;AAEA;yCAlBW,cAAc;2CAAd,cAAc;AA6B1B;;ACzFD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCG;AACH,iBAAgB,cAAc,4BAE3B,MAAM;;ACjDT;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BG;UACc,cAAc;AAC7B;AACD;AAED,iBAAgB,oBAAoB,IAAI,cAAc;AAItD;;;;;;;;;;;;;;;;;;AAkBG;AACH,cAAa,gBAAgB,EAAA,cAAA,CAAA,cAAA;;ACnD7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BG;AACH,iBAAgB,qBAAqB,OAC7B,cAAc,GACnB,oBAAoB;;;;","names":["_angular_core"]}
@@ -1,7 +1,7 @@
1
1
  import * as _real_router_types from '@real-router/types';
2
2
  import * as _angular_core from '@angular/core';
3
- import { Signal, InjectionToken, EnvironmentProviders, TemplateRef, OnInit } from '@angular/core';
4
- import { Params, Navigator, Router, State, RouterError, NavigationOptions } from '@real-router/core';
3
+ import { Signal, InjectionToken, EnvironmentProviders, TemplateRef } from '@angular/core';
4
+ import { RouterError, Params, Navigator, Router, DefaultDependencies, PluginFactory, State, NavigationOptions } from '@real-router/core';
5
5
  export { Navigator } from '@real-router/core';
6
6
  import { RouteSnapshot, RouterSource, RouterTransitionSnapshot } from '@real-router/sources';
7
7
  export { RouteSnapshot, RouterErrorSnapshot, RouterTransitionSnapshot } from '@real-router/sources';
@@ -39,6 +39,10 @@ interface RouteSignals<P extends Params = Params> {
39
39
  readonly routeState: Signal<RouteSnapshot<P>>;
40
40
  readonly navigator: Navigator;
41
41
  }
42
+ interface ErrorContext {
43
+ $implicit: RouterError;
44
+ resetError: () => void;
45
+ }
42
46
 
43
47
  declare const ROUTER: InjectionToken<Router<object>>;
44
48
  declare const NAVIGATOR: InjectionToken<Navigator>;
@@ -49,6 +53,102 @@ interface RealRouterOptions {
49
53
  }
50
54
  declare function provideRealRouter(router: Router, options?: RealRouterOptions): EnvironmentProviders;
51
55
 
56
+ /**
57
+ * Factory function for deriving per-request dependencies from an SSR `Request`.
58
+ *
59
+ * - **Server:** receives the real `Request` exposed via Angular's `REQUEST` token.
60
+ * - **SSG:** receives a mocked `Request` injected via `platformProviders`.
61
+ * - **Client:** receives `null` — derive deps from `document.cookie` etc.
62
+ *
63
+ * The returned object becomes the second argument to
64
+ * `cloneRouter(baseRouter, deps)`. Returning `undefined` clones the router with
65
+ * no extra deps (cloneRouter accepts the optional 2nd argument).
66
+ */
67
+ type RequestDepsFactory<TDeps extends DefaultDependencies = DefaultDependencies> = (request: Request | null) => TDeps | undefined;
68
+ /**
69
+ * Function form for conditional plugins (different sets server vs client).
70
+ *
71
+ * Use this when the plugin set must differ — typically because some plugins
72
+ * (e.g. `browser-plugin`, `navigation-plugin`, `hash-plugin`) touch
73
+ * `window.history` / `window.location` and cannot run on the server.
74
+ */
75
+ type RequestPluginsFactory<TDeps extends DefaultDependencies = DefaultDependencies> = (request: Request | null) => readonly PluginFactory<TDeps>[];
76
+ interface RealRouterFactoryOptions<TDeps extends DefaultDependencies = DefaultDependencies> {
77
+ /**
78
+ * Base router instance — created once at app bootstrap (typically inside
79
+ * `app.config.ts` module scope). Each request clones this router via
80
+ * `cloneRouter(baseRouter, deps?.(request))`, producing an isolated
81
+ * router with its own state, plugins, and subscriptions.
82
+ *
83
+ * **Important:** the `baseRouter` MUST NOT be started ahead of time —
84
+ * `provideAppInitializer` is responsible for calling `router.start(url)`
85
+ * inside the per-request DI scope.
86
+ */
87
+ baseRouter: Router<TDeps>;
88
+ /**
89
+ * Plugins applied to every per-request router clone.
90
+ *
91
+ * **Static form** — same plugins on both sides:
92
+ * ```ts
93
+ * plugins: [ssrDataPluginFactory(loaders)]
94
+ * ```
95
+ *
96
+ * **Function form** — conditional client vs server (recommended when any
97
+ * browser-only plugin is involved):
98
+ * ```ts
99
+ * plugins: (request) => request
100
+ * ? [ssrDataPluginFactory(loaders)]
101
+ * : [browserPluginFactory(), ssrDataPluginFactory(loaders)],
102
+ * ```
103
+ *
104
+ * Function form is required if the plugin list contains
105
+ * `browser-plugin`, `navigation-plugin`, or `hash-plugin` — those plugins
106
+ * read `window.history` / `window.location` and crash on the server.
107
+ */
108
+ plugins?: readonly PluginFactory<TDeps>[] | RequestPluginsFactory<TDeps>;
109
+ /**
110
+ * Derive request-scoped deps (e.g. `currentUser` from cookies). The result
111
+ * is passed to `cloneRouter(baseRouter, deps)` and merged with any deps
112
+ * already registered on the base router.
113
+ *
114
+ * Receives `request: Request | null`:
115
+ * - non-null on server (real `Request` from `@angular/ssr` runtime)
116
+ * - non-null on SSG (mocked `Request` via `platformProviders`)
117
+ * - null on client (derive deps externally — e.g. parse `document.cookie`)
118
+ */
119
+ deps?: RequestDepsFactory<TDeps>;
120
+ /** Optional scroll restoration — same semantics as `provideRealRouter`. */
121
+ scrollRestoration?: ScrollRestorationOptions;
122
+ /** Optional view transitions — same semantics as `provideRealRouter`. */
123
+ viewTransitions?: boolean;
124
+ }
125
+ /**
126
+ * `provideRealRouterFactory` — environment providers for SSR / SSG scenarios.
127
+ *
128
+ * Unlike `provideRealRouter(router)` (single instance via `useValue`), this
129
+ * factory uses `useFactory` to produce a per-request router clone:
130
+ *
131
+ * 1. Reads Angular's `REQUEST` token (`{ optional: true }`).
132
+ * 2. Calls `cloneRouter(baseRouter, deps?.(request))` to create a request-scoped clone.
133
+ * 3. Applies plugins (`plugins` array or `plugins(request)` factory).
134
+ * 4. Registers `provideAppInitializer` that calls `await router.start(url)`.
135
+ * 5. Schedules `router.dispose()` via `DestroyRef.onDestroy` — the request
136
+ * Injector is destroyed after the response is sent, releasing all
137
+ * subscriptions and plugins.
138
+ *
139
+ * Use cases:
140
+ * - Angular SSR with `@angular/ssr` (`outputMode: "server"`).
141
+ * - SSG build-time render via `renderApplication` + `platformProviders` `REQUEST` mock.
142
+ * - Multi-tenant request-scoped routing.
143
+ *
144
+ * Existing single-instance scenarios (SPA, SSG client after hydration) continue
145
+ * to use `provideRealRouter(router)` — both APIs ship in parallel.
146
+ *
147
+ * @param options - Factory configuration — see `RealRouterFactoryOptions`.
148
+ * @returns `EnvironmentProviders` to spread into `ApplicationConfig.providers`.
149
+ */
150
+ declare function provideRealRouterFactory<TDeps extends DefaultDependencies = DefaultDependencies>(options: RealRouterFactoryOptions<TDeps>): EnvironmentProviders;
151
+
52
152
  /** Must be called within an injection context (constructor, field initializer, runInInjectionContext). */
53
153
  declare function sourceToSignal<T>(source: RouterSource<T>): Signal<T>;
54
154
 
@@ -56,11 +156,12 @@ declare function injectRouter(): Router;
56
156
 
57
157
  declare function injectNavigator(): Navigator;
58
158
 
59
- declare function injectRoute<P extends Params = Params>(): Omit<RouteSignals<P>, "routeState"> & {
159
+ type NonNullRouteSignals<P extends Params> = Omit<RouteSignals<P>, "routeState"> & {
60
160
  readonly routeState: Signal<Omit<RouteSnapshot<P>, "route"> & {
61
161
  route: State<P>;
62
162
  }>;
63
163
  };
164
+ declare function injectRoute<P extends Params = Params>(): NonNullRouteSignals<P>;
64
165
 
65
166
  declare function injectRouteNode(nodeName: string): RouteSignals;
66
167
 
@@ -252,25 +353,22 @@ declare class RouteSelf {
252
353
  static ɵdir: _angular_core.ɵɵDirectiveDeclaration<RouteSelf, "ng-template[routeSelf]", never, {}, {}, never, never, true, never>;
253
354
  }
254
355
 
255
- declare class RouteView implements OnInit {
356
+ declare class RouteView {
256
357
  readonly nodeName: _angular_core.InputSignal<string>;
257
358
  readonly matches: _angular_core.Signal<readonly RouteMatch[]>;
258
359
  readonly selfs: _angular_core.Signal<readonly RouteSelf[]>;
259
360
  readonly notFounds: _angular_core.Signal<readonly RouteNotFound[]>;
260
361
  readonly activeTemplate: _angular_core.Signal<TemplateRef<unknown> | null>;
261
- private readonly matchEntries;
262
362
  private readonly router;
263
- private readonly destroyRef;
264
363
  private readonly routeState;
265
- ngOnInit(): void;
364
+ private readonly matchEntries;
365
+ private readonly matchedTemplate;
366
+ private readonly fallbackTemplate;
367
+ constructor();
266
368
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<RouteView, never>;
267
369
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<RouteView, "route-view", never, { "nodeName": { "alias": "routeNode"; "required": false; "isSignal": true; }; }, {}, ["matches", "selfs", "notFounds"], never, true, never>;
268
370
  }
269
371
 
270
- interface ErrorContext {
271
- $implicit: RouterError;
272
- resetError: () => void;
273
- }
274
372
  declare class RouterErrorBoundary {
275
373
  readonly errorTemplate: _angular_core.InputSignal<TemplateRef<ErrorContext> | undefined>;
276
374
  readonly onError: _angular_core.OutputEmitterRef<{
@@ -293,7 +391,7 @@ declare class NavigationAnnouncer {
293
391
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<NavigationAnnouncer, "navigation-announcer", never, {}, {}, never, never, true, never>;
294
392
  }
295
393
 
296
- declare class RealLink implements OnInit {
394
+ declare class RealLink {
297
395
  readonly routeName: _angular_core.InputSignal<string>;
298
396
  readonly routeParams: _angular_core.InputSignal<Params>;
299
397
  readonly routeOptions: _angular_core.InputSignal<NavigationOptions>;
@@ -308,35 +406,36 @@ declare class RealLink implements OnInit {
308
406
  */
309
407
  readonly hash: _angular_core.InputSignal<string | undefined>;
310
408
  private readonly router;
311
- private readonly destroyRef;
312
409
  private readonly anchor;
313
410
  private readonly isActive;
314
411
  private readonly href;
315
412
  private prevActiveClass;
316
- ngOnInit(): void;
413
+ private prevHref;
414
+ private prevActive;
415
+ constructor();
317
416
  onClick(event: MouseEvent): void;
318
- private updateDom;
417
+ private updateHref;
418
+ private updateActiveClass;
319
419
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<RealLink, never>;
320
420
  static ɵdir: _angular_core.ɵɵDirectiveDeclaration<RealLink, "a[realLink]", never, { "routeName": { "alias": "routeName"; "required": false; "isSignal": true; }; "routeParams": { "alias": "routeParams"; "required": false; "isSignal": true; }; "routeOptions": { "alias": "routeOptions"; "required": false; "isSignal": true; }; "activeClassName": { "alias": "activeClassName"; "required": false; "isSignal": true; }; "activeStrict": { "alias": "activeStrict"; "required": false; "isSignal": true; }; "ignoreQueryParams": { "alias": "ignoreQueryParams"; "required": false; "isSignal": true; }; "hash": { "alias": "hash"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
321
421
  }
322
422
 
323
- declare class RealLinkActive implements OnInit {
423
+ declare class RealLinkActive {
324
424
  readonly realLinkActive: _angular_core.InputSignal<string>;
325
425
  readonly routeName: _angular_core.InputSignal<string>;
326
426
  readonly routeParams: _angular_core.InputSignal<Params>;
327
427
  readonly activeStrict: _angular_core.InputSignal<boolean>;
328
428
  readonly ignoreQueryParams: _angular_core.InputSignal<boolean>;
329
429
  private readonly router;
330
- private readonly destroyRef;
331
430
  private readonly element;
332
431
  private readonly isActive;
432
+ private prevActive;
333
433
  constructor();
334
- ngOnInit(): void;
335
434
  private updateClass;
336
435
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<RealLinkActive, never>;
337
436
  static ɵdir: _angular_core.ɵɵDirectiveDeclaration<RealLinkActive, "[realLinkActive]", never, { "realLinkActive": { "alias": "realLinkActive"; "required": false; "isSignal": true; }; "routeName": { "alias": "routeName"; "required": false; "isSignal": true; }; "routeParams": { "alias": "routeParams"; "required": false; "isSignal": true; }; "activeStrict": { "alias": "activeStrict"; "required": false; "isSignal": true; }; "ignoreQueryParams": { "alias": "ignoreQueryParams"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
338
437
  }
339
438
 
340
- export { NAVIGATOR, NavigationAnnouncer, ROUTE, ROUTER, RealLink, RealLinkActive, RouteMatch, RouteNotFound, RouteSelf, RouteView, RouterErrorBoundary, injectIsActiveRoute, injectNavigator, injectRoute, injectRouteEnter, injectRouteExit, injectRouteNode, injectRouteUtils, injectRouter, injectRouterTransition, provideRealRouter, sourceToSignal };
341
- export type { ErrorContext, RouteEnterContext, RouteEnterHandler, RouteExitContext, RouteExitHandler, RouteSignals, UseRouteEnterOptions, UseRouteExitOptions };
439
+ export { NAVIGATOR, NavigationAnnouncer, ROUTE, ROUTER, RealLink, RealLinkActive, RouteMatch, RouteNotFound, RouteSelf, RouteView, RouterErrorBoundary, injectIsActiveRoute, injectNavigator, injectRoute, injectRouteEnter, injectRouteExit, injectRouteNode, injectRouteUtils, injectRouter, injectRouterTransition, provideRealRouter, provideRealRouterFactory, sourceToSignal };
440
+ export type { ErrorContext, RealRouterFactoryOptions, RealRouterOptions, RequestDepsFactory, RequestPluginsFactory, RouteEnterContext, RouteEnterHandler, RouteExitContext, RouteExitHandler, RouteSignals, UseRouteEnterOptions, UseRouteExitOptions };
342
441
  //# sourceMappingURL=real-router-angular.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"real-router-angular.d.ts","sources":["../../src/dom-utils/scroll-restore.ts","../../src/types.ts","../../src/providers.ts","../../src/sourceToSignal.ts","../../src/functions/injectRouter.ts","../../src/functions/injectNavigator.ts","../../src/functions/injectRoute.ts","../../src/functions/injectRouteNode.ts","../../src/functions/injectRouteUtils.ts","../../src/functions/injectRouterTransition.ts","../../src/functions/injectIsActiveRoute.ts","../../src/functions/injectRouteExit.ts","../../src/functions/injectRouteEnter.ts","../../src/directives/RouteMatch.ts","../../src/directives/RouteNotFound.ts","../../src/directives/RouteSelf.ts","../../src/components/RouteView.ts","../../src/components/RouterErrorBoundary.ts","../../src/components/NavigationAnnouncer.ts","../../src/directives/RealLink.ts","../../src/directives/RealLinkActive.ts"],"mappings":"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","names":[]}
1
+ {"version":3,"file":"real-router-angular.d.ts","sources":["../../src/dom-utils/scroll-restore.ts","../../src/types.ts","../../src/providers.ts","../../src/providersFactory.ts","../../src/sourceToSignal.ts","../../src/functions/injectRouter.ts","../../src/functions/injectNavigator.ts","../../src/functions/injectRoute.ts","../../src/functions/injectRouteNode.ts","../../src/functions/injectRouteUtils.ts","../../src/functions/injectRouterTransition.ts","../../src/functions/injectIsActiveRoute.ts","../../src/functions/injectRouteExit.ts","../../src/functions/injectRouteEnter.ts","../../src/directives/RouteMatch.ts","../../src/directives/RouteNotFound.ts","../../src/directives/RouteSelf.ts","../../src/components/RouteView.ts","../../src/components/RouterErrorBoundary.ts","../../src/components/NavigationAnnouncer.ts","../../src/directives/RealLink.ts","../../src/directives/RealLinkActive.ts"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@real-router/angular",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "type": "commonjs",
5
5
  "description": "Angular 21 integration for Real-Router",
6
6
  "exports": {
@@ -8,11 +8,17 @@
8
8
  "@real-router/internal-source": "./src/index.ts",
9
9
  "types": "./dist/types/real-router-angular.d.ts",
10
10
  "default": "./dist/fesm2022/real-router-angular.mjs"
11
+ },
12
+ "./ssr": {
13
+ "@real-router/internal-source": "./ssr/public_api.ts",
14
+ "types": "./dist/types/real-router-angular-ssr.d.ts",
15
+ "default": "./dist/fesm2022/real-router-angular-ssr.mjs"
11
16
  }
12
17
  },
13
18
  "files": [
14
19
  "dist",
15
- "src"
20
+ "src",
21
+ "ssr"
16
22
  ],
17
23
  "homepage": "https://github.com/greydragon888/real-router",
18
24
  "repository": {
@@ -35,19 +41,19 @@
35
41
  "license": "MIT",
36
42
  "sideEffects": false,
37
43
  "dependencies": {
38
- "@real-router/core": "^0.51.0",
44
+ "@real-router/core": "^0.53.0",
39
45
  "@real-router/route-utils": "^0.2.2",
40
- "@real-router/sources": "^0.8.0"
46
+ "@real-router/sources": "^0.8.2"
41
47
  },
42
48
  "devDependencies": {
43
49
  "@analogjs/vitest-angular": "2.4.7",
44
- "@angular/common": "21.2.8",
45
- "@angular/compiler": "21.2.8",
46
- "@angular/compiler-cli": "21.2.8",
47
- "@angular/core": "21.2.8",
48
- "@angular/platform-browser": "21.2.8",
50
+ "@angular/common": "21.2.9",
51
+ "@angular/compiler": "21.2.9",
52
+ "@angular/compiler-cli": "21.2.9",
53
+ "@angular/core": "21.2.9",
54
+ "@angular/platform-browser": "21.2.9",
49
55
  "ng-packagr": "21.2.2",
50
- "typescript": "6.0.2"
56
+ "typescript": "6.0.3"
51
57
  },
52
58
  "peerDependencies": {
53
59
  "@angular/common": ">=21.0.0",
@@ -55,9 +61,10 @@
55
61
  },
56
62
  "scripts": {
57
63
  "test": "vitest",
64
+ "test:properties": "vitest run --config vitest.config.properties.mts",
58
65
  "test:stress": "vitest -c vitest.config.stress.mts",
59
66
  "type-check": "tsc --noEmit",
60
- "lint": "eslint --cache src/ tests/ --fix --max-warnings 0",
67
+ "lint": "eslint --cache src/ ssr/ tests/ --fix --max-warnings 0",
61
68
  "prebundle": "node scripts/sync-dom-utils.mjs",
62
69
  "bundle": "ng-packagr -p ng-package.json -c tsconfig.lib.json"
63
70
  }