@absolutejs/absolute 0.20.0-beta.182 → 0.20.0-beta.183
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/CHANGELOG.md +14 -0
- package/changelog.json +21 -0
- package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
- package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
- package/dist/angular/index.js +177 -37
- package/dist/angular/index.js.map +6 -5
- package/dist/angular/server.js +177 -37
- package/dist/angular/server.js.map +6 -5
- package/dist/build.js +22 -8
- package/dist/build.js.map +5 -5
- package/dist/cli/{build-p3qra1nj.js → build-df81wh71.js} +5 -2
- package/dist/cli/{buildReactServerComponents-vc9hh2rd.js → buildReactServerComponents-k6amghrj.js} +1 -1
- package/dist/cli/config/server.js +19 -1
- package/dist/cli/{index-mmm6d3k5.js → index-3dz754hk.js} +2 -2
- package/dist/cli/{index-7zwzyymv.js → index-pq4qqz0r.js} +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/{typecheck-yjme4fv1.js → typecheck-bvm0ndq4.js} +153 -62
- package/dist/dev/serverBootstrap.js +8 -2
- package/dist/index.js +24 -10
- package/dist/index.js.map +5 -5
- package/dist/react/index.js +10 -2
- package/dist/react/index.js.map +3 -3
- package/dist/react/server.js +10 -2
- package/dist/react/server.js.map +3 -3
- package/dist/src/angular/colocatedRouteMatch.d.ts +23 -0
- package/dist/src/cli/scripts/typecheck.d.ts +1 -0
- package/dist/src/cli/scripts/typecheckDiagnostics.d.ts +41 -0
- package/dist/src/dev/hot/analyze.d.ts +1 -1
- package/dist/src/utils/spaRouteManifest.d.ts +1 -0
- package/dist/svelte/index.js +10 -2
- package/dist/svelte/index.js.map +3 -3
- package/dist/svelte/server.js +10 -2
- package/dist/svelte/server.js.map +3 -3
- package/dist/vue/index.js +10 -2
- package/dist/vue/index.js.map +3 -3
- package/dist/vue/server.js +10 -2
- package/dist/vue/server.js.map +3 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,20 @@ This file is generated by `absolute-changelog` from the entries in
|
|
|
6
6
|
`changelog/`. Edit an entry, not this file — and add new ones under
|
|
7
7
|
`changelog/unreleased/`.
|
|
8
8
|
|
|
9
|
+
## 0.20.0-beta.183 — 2026-11-15
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- **Angular pages with colocated routes return 404 for unknown sub-paths**
|
|
14
|
+
An Angular page that exports its own `routes` array and is mounted under a wildcard route (such as `.get('/ng/*', ...)`) never returned 404, even for a path none of its routes match. These pages now return 404 for an unknown sub-path, like the other SPA hosts. On each request the handler takes the path below the mount Elysia matched and checks it against the page's `routes` the way Angular's router does: path segments, `:params`, empty paths, `pathMatch: 'full'`, nested `children`, and `redirectTo` sources. A page navigation or HTMX request gets the not-found page (`not-found.html`) and any other client gets Elysia's JSON 404. That JSON rule now covers the React, Svelte, Vue and Angular SPA hosts' 404s too. A route the server can't resolve counts as a match: `loadChildren` matches anything under its path, and a `matcher` function matches everything. To keep the old behaviour for a page, add a `{ path: '**', component: ... }` route, which matches every path.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- **Dev SSR recovers when you add a missing import, without restarting the dev server**
|
|
19
|
+
In `absolute dev`, saving a React component that renders another component before its import line exists (`<Card />` with no `import { Card }`), then adding the import, left server rendering failing with `Card is not defined` until the dev server restarted. The server updates edited modules in place and keeps every top-level statement whose text did not change; adding an import changes no statement, so it kept the component created by the previous save, which still looked `Card` up as a global. A statement now also counts as changed when a name it uses gets a different binding (a new or removed import, an import from another module, or an import swapped for a local declaration), so the component is re-created with the import. Separately, a second save of a React file that landed before the client rebuild for the first save ran could be skipped on the server, which kept rendering the first save until the next edit; every save now reaches the server.
|
|
20
|
+
- **An error in a .ts file inside svelteDirectory is reported once, not by both the plain checker and svelte-check**
|
|
21
|
+
svelte-check's program includes a configured svelteDirectory whole, so a plain TypeScript error in a .ts file there was printed under both [bun check] (or [tsc]) and [svelte-check]. `absolute typecheck` now reads svelte-check's machine-readable output and drops the errors the plain checker already reported, matching them by file, line, column and code; errors inside .svelte files stay under svelte-check, and svelte-check passes when every error it found was a duplicate. Its remaining errors are printed in the same shape as tsc's: file:line:column, the TS code, the message and the underlined line.
|
|
22
|
+
|
|
9
23
|
## 0.20.0-beta.182 — 2026-11-15
|
|
10
24
|
|
|
11
25
|
### Security
|
package/changelog.json
CHANGED
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
"contract": 1,
|
|
3
3
|
"name": "@absolutejs/absolute",
|
|
4
4
|
"releases": [
|
|
5
|
+
{
|
|
6
|
+
"changes": [
|
|
7
|
+
{
|
|
8
|
+
"detail": "An Angular page that exports its own `routes` array and is mounted under a wildcard route (such as `.get('/ng/*', ...)`) never returned 404, even for a path none of its routes match. These pages now return 404 for an unknown sub-path, like the other SPA hosts. On each request the handler takes the path below the mount Elysia matched and checks it against the page's `routes` the way Angular's router does: path segments, `:params`, empty paths, `pathMatch: 'full'`, nested `children`, and `redirectTo` sources. A page navigation or HTMX request gets the not-found page (`not-found.html`) and any other client gets Elysia's JSON 404. That JSON rule now covers the React, Svelte, Vue and Angular SPA hosts' 404s too. A route the server can't resolve counts as a match: `loadChildren` matches anything under its path, and a `matcher` function matches everything. To keep the old behaviour for a page, add a `{ path: '**', component: ... }` route, which matches every path.",
|
|
9
|
+
"kind": "changed",
|
|
10
|
+
"summary": "Angular pages with colocated routes return 404 for unknown sub-paths"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"detail": "In `absolute dev`, saving a React component that renders another component before its import line exists (`<Card />` with no `import { Card }`), then adding the import, left server rendering failing with `Card is not defined` until the dev server restarted. The server updates edited modules in place and keeps every top-level statement whose text did not change; adding an import changes no statement, so it kept the component created by the previous save, which still looked `Card` up as a global. A statement now also counts as changed when a name it uses gets a different binding (a new or removed import, an import from another module, or an import swapped for a local declaration), so the component is re-created with the import. Separately, a second save of a React file that landed before the client rebuild for the first save ran could be skipped on the server, which kept rendering the first save until the next edit; every save now reaches the server.",
|
|
14
|
+
"kind": "fixed",
|
|
15
|
+
"summary": "Dev SSR recovers when you add a missing import, without restarting the dev server"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"detail": "svelte-check's program includes a configured svelteDirectory whole, so a plain TypeScript error in a .ts file there was printed under both [bun check] (or [tsc]) and [svelte-check]. `absolute typecheck` now reads svelte-check's machine-readable output and drops the errors the plain checker already reported, matching them by file, line, column and code; errors inside .svelte files stay under svelte-check, and svelte-check passes when every error it found was a duplicate. Its remaining errors are printed in the same shape as tsc's: file:line:column, the TS code, the message and the underlined line.",
|
|
19
|
+
"kind": "fixed",
|
|
20
|
+
"summary": "An error in a .ts file inside svelteDirectory is reported once, not by both the plain checker and svelte-check"
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"date": "2026-11-15",
|
|
24
|
+
"version": "0.20.0-beta.183"
|
|
25
|
+
},
|
|
5
26
|
{
|
|
6
27
|
"changes": [
|
|
7
28
|
{
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
// .angular-partial-tmp-
|
|
2
|
+
// .angular-partial-tmp-NwkjSK/src/core/streamingSlotRegistrar.ts
|
|
3
3
|
var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
|
|
4
4
|
var STREAMING_SLOT_WARNING_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotWarningController");
|
|
5
5
|
var STREAMING_SLOT_COLLECTION_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotCollectionController");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
// .angular-partial-tmp-
|
|
2
|
+
// .angular-partial-tmp-NwkjSK/src/core/streamingSlotRegistrar.ts
|
|
3
3
|
var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
|
|
4
4
|
var STREAMING_SLOT_WARNING_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotWarningController");
|
|
5
5
|
var STREAMING_SLOT_COLLECTION_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotCollectionController");
|
|
@@ -46,7 +46,7 @@ var warnMissingStreamingSlotCollector = (primitiveName) => {
|
|
|
46
46
|
getWarningController()?.maybeWarn(primitiveName);
|
|
47
47
|
};
|
|
48
48
|
|
|
49
|
-
// .angular-partial-tmp-
|
|
49
|
+
// .angular-partial-tmp-NwkjSK/src/core/streamingSlotRegistry.ts
|
|
50
50
|
var STREAMING_SLOT_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotAsyncLocalStorage");
|
|
51
51
|
var isObjectRecord2 = (value) => Boolean(value) && typeof value === "object";
|
|
52
52
|
var isAsyncLocalStorage = (value) => isObjectRecord2(value) && ("getStore" in value) && typeof value.getStore === "function" && ("run" in value) && typeof value.run === "function";
|
package/dist/angular/index.js
CHANGED
|
@@ -1437,6 +1437,7 @@ var init_angularDeps = __esm(() => {
|
|
|
1437
1437
|
});
|
|
1438
1438
|
|
|
1439
1439
|
// src/utils/spaRouteManifest.ts
|
|
1440
|
+
import { NotFound } from "elysia";
|
|
1440
1441
|
import { basename as basename2 } from "path";
|
|
1441
1442
|
var SPA_ROUTES_KEY = "__absoluteSpaRoutes", setSpaRouteManifest = (hosts) => {
|
|
1442
1443
|
Reflect.set(globalThis, SPA_ROUTES_KEY, hosts);
|
|
@@ -1501,7 +1502,14 @@ var SPA_ROUTES_KEY = "__absoluteSpaRoutes", setSpaRouteManifest = (hosts) => {
|
|
|
1501
1502
|
}, renderSpaNotFound = async (framework, pageName, request) => {
|
|
1502
1503
|
if (isKnownSpaRoute(framework, pageName, request))
|
|
1503
1504
|
return null;
|
|
1504
|
-
return
|
|
1505
|
+
return renderSpaNotFoundResponse(request);
|
|
1506
|
+
}, renderSpaNotFoundResponse = async (request) => {
|
|
1507
|
+
if (request && !isPageRequest(request)) {
|
|
1508
|
+
return new NotFound().toResponse();
|
|
1509
|
+
}
|
|
1510
|
+
return await renderFirstNotFound({
|
|
1511
|
+
preferHtmx: request?.headers.get("hx-request") === "true"
|
|
1512
|
+
}) ?? new Response("Not found", {
|
|
1505
1513
|
headers: { "Content-Type": "text/plain" },
|
|
1506
1514
|
status: 404
|
|
1507
1515
|
});
|
|
@@ -1558,8 +1566,8 @@ var buildRequestProviders = (deps, request, requestContext, responseInit) => [
|
|
|
1558
1566
|
// src/angular/zoneRuntime.ts
|
|
1559
1567
|
var ZONE_NODE_SPECIFIER = "zone.js/node", MISSING_ZONE_MESSAGE = 'angular.changeDetection is "zone" but zone.js could not be loaded. Install it in your app (bun add zone.js).', isAngularZoneMode = () => globalThis.__absoluteAngularChangeDetection === "zone", setAngularChangeDetection = (mode) => {
|
|
1560
1568
|
globalThis.__absoluteAngularChangeDetection = mode ?? "zoneless";
|
|
1561
|
-
},
|
|
1562
|
-
if (value instanceof NativePromise || !
|
|
1569
|
+
}, isRecord3 = (value) => typeof value === "object" && value !== null, adoptIntoNativePromise = (NativePromise, value) => {
|
|
1570
|
+
if (value instanceof NativePromise || !isRecord3(value))
|
|
1563
1571
|
return value;
|
|
1564
1572
|
const { then } = value;
|
|
1565
1573
|
if (typeof then !== "function")
|
|
@@ -1576,28 +1584,28 @@ var ZONE_NODE_SPECIFIER = "zone.js/node", MISSING_ZONE_MESSAGE = 'angular.change
|
|
|
1576
1584
|
}, wrapRoute = (NativePromise, route) => {
|
|
1577
1585
|
if (typeof route === "function")
|
|
1578
1586
|
return wrapHandler(NativePromise, route);
|
|
1579
|
-
if (!
|
|
1587
|
+
if (!isRecord3(route) || route instanceof Response || route instanceof Blob)
|
|
1580
1588
|
return route;
|
|
1581
1589
|
return Object.fromEntries(Object.entries(route).map(([method, handler]) => [
|
|
1582
1590
|
method,
|
|
1583
1591
|
wrapHandler(NativePromise, handler)
|
|
1584
1592
|
]));
|
|
1585
1593
|
}, wrapServeOptions = (NativePromise, options) => {
|
|
1586
|
-
if (!
|
|
1594
|
+
if (!isRecord3(options))
|
|
1587
1595
|
return options;
|
|
1588
1596
|
const wrapped = { ...options };
|
|
1589
1597
|
if (options.fetch)
|
|
1590
1598
|
wrapped.fetch = wrapHandler(NativePromise, options.fetch);
|
|
1591
1599
|
if (options.error)
|
|
1592
1600
|
wrapped.error = wrapHandler(NativePromise, options.error);
|
|
1593
|
-
if (
|
|
1601
|
+
if (isRecord3(options.routes))
|
|
1594
1602
|
wrapped.routes = Object.fromEntries(Object.entries(options.routes).map(([path, route]) => [
|
|
1595
1603
|
path,
|
|
1596
1604
|
wrapRoute(NativePromise, route)
|
|
1597
1605
|
]));
|
|
1598
1606
|
return wrapped;
|
|
1599
1607
|
}, wrapServerReload = (NativePromise, server) => {
|
|
1600
|
-
if (!
|
|
1608
|
+
if (!isRecord3(server))
|
|
1601
1609
|
return;
|
|
1602
1610
|
const { reload } = server;
|
|
1603
1611
|
if (typeof reload !== "function")
|
|
@@ -3475,15 +3483,15 @@ var init_stylePreprocessor = __esm(() => {
|
|
|
3475
3483
|
});
|
|
3476
3484
|
|
|
3477
3485
|
// src/svelte/router/lazyModule.ts
|
|
3478
|
-
var LAZY_RESOLVED_KEY, LAZY_SOURCE_EXPORT = "__ABSOLUTE_SVELTE_SOURCE__",
|
|
3486
|
+
var LAZY_RESOLVED_KEY, LAZY_SOURCE_EXPORT = "__ABSOLUTE_SVELTE_SOURCE__", isRecord4 = (value) => typeof value === "object" && value !== null, isComponent = (value) => typeof value === "function", toLazyComponent = (value) => {
|
|
3479
3487
|
if (isComponent(value))
|
|
3480
3488
|
return value;
|
|
3481
|
-
if (!
|
|
3489
|
+
if (!isRecord4(value))
|
|
3482
3490
|
return;
|
|
3483
3491
|
const fallback = value.default;
|
|
3484
3492
|
return isComponent(fallback) ? fallback : undefined;
|
|
3485
3493
|
}, readSourceFrom = (value) => {
|
|
3486
|
-
if (!
|
|
3494
|
+
if (!isRecord4(value) && !isComponent(value))
|
|
3487
3495
|
return;
|
|
3488
3496
|
const source = Reflect.get(value, LAZY_SOURCE_EXPORT);
|
|
3489
3497
|
return typeof source === "string" ? source : undefined;
|
|
@@ -3492,7 +3500,7 @@ var LAZY_RESOLVED_KEY, LAZY_SOURCE_EXPORT = "__ABSOLUTE_SVELTE_SOURCE__", isReco
|
|
|
3492
3500
|
const fromValue = readSourceFrom(value);
|
|
3493
3501
|
if (fromValue !== undefined)
|
|
3494
3502
|
return fromValue;
|
|
3495
|
-
if (!
|
|
3503
|
+
if (!isRecord4(value))
|
|
3496
3504
|
return;
|
|
3497
3505
|
return readSourceFrom(value.default);
|
|
3498
3506
|
};
|
|
@@ -3876,14 +3884,14 @@ var defineIslandComponent = (component, options) => ({
|
|
|
3876
3884
|
component,
|
|
3877
3885
|
export: options.export,
|
|
3878
3886
|
source: options.source
|
|
3879
|
-
}), defineIslandRegistry = (registry) => registry,
|
|
3887
|
+
}), defineIslandRegistry = (registry) => registry, isRecord5 = (value) => typeof value === "object" && value !== null, getIslandBuildReference = (component) => {
|
|
3880
3888
|
if (!isIslandComponentDefinition(component))
|
|
3881
3889
|
return null;
|
|
3882
3890
|
return {
|
|
3883
3891
|
export: component.export,
|
|
3884
3892
|
source: component.source
|
|
3885
3893
|
};
|
|
3886
|
-
}, isIslandComponentDefinition = (value) =>
|
|
3894
|
+
}, isIslandComponentDefinition = (value) => isRecord5(value) && ("component" in value) && ("source" in value) && typeof value.source === "string", parseIslandProps = (rawProps) => {
|
|
3887
3895
|
if (!rawProps)
|
|
3888
3896
|
return {};
|
|
3889
3897
|
return JSON.parse(rawProps);
|
|
@@ -3907,7 +3915,7 @@ var init_islandMarkupAttributes = __esm(() => {
|
|
|
3907
3915
|
var islandSequence = 0, resolvedServerComponentCache, resolvedServerBuildComponentCache, syncIslandGeneration3, nextIslandId = () => {
|
|
3908
3916
|
islandSequence += 1;
|
|
3909
3917
|
return `island-${islandSequence}`;
|
|
3910
|
-
},
|
|
3918
|
+
}, isRecord6 = (value) => typeof value === "object" && value !== null, isReactServerIslandComponent = (value) => typeof value === "function", isSvelteServerIslandComponent = (value) => typeof value === "function", isVueServerIslandComponent = (value) => typeof value === "function" || isRecord6(value), isAngularServerIslandComponent = (value) => typeof value === "function", resolveBuildReferencePath = (source, registryPath) => {
|
|
3911
3919
|
if (source.startsWith("file://"))
|
|
3912
3920
|
return new URL(source).pathname;
|
|
3913
3921
|
if (source.startsWith("."))
|
|
@@ -4376,13 +4384,13 @@ var ABSOLUTE_MOBILE_PAGE_MEDIA_TYPE = "application/vnd.absolute.page+json", ABSO
|
|
|
4376
4384
|
}, headerVaryValues, envelopeResponse = (response, status) => new Response(JSON.stringify({
|
|
4377
4385
|
protocol: ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION,
|
|
4378
4386
|
response
|
|
4379
|
-
}), { headers: responseHeaders(), status }),
|
|
4387
|
+
}), { headers: responseHeaders(), status }), isRecord8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), normalizeJsonValue = (value) => {
|
|
4380
4388
|
const serialized = JSON.stringify(value);
|
|
4381
4389
|
if (serialized === undefined) {
|
|
4382
4390
|
throw new TypeError("Mobile page props must be JSON-serializable.");
|
|
4383
4391
|
}
|
|
4384
4392
|
const parsed = JSON.parse(serialized);
|
|
4385
|
-
if (!
|
|
4393
|
+
if (!isRecord8(parsed)) {
|
|
4386
4394
|
throw new TypeError("Mobile page props must serialize to an object.");
|
|
4387
4395
|
}
|
|
4388
4396
|
return parsed;
|
|
@@ -4784,7 +4792,7 @@ var SLOT_ID_PREFIX = "abs-slot-", CLOSING_BODY_TAG = "</body>", CLOSING_HEAD_TAG
|
|
|
4784
4792
|
getStreamingSlotsRuntimeScript()
|
|
4785
4793
|
].filter(Boolean).join(";");
|
|
4786
4794
|
return `<script${createNonceAttr(nonce)}>${escapeScriptContent(runtimeBody)}</script>`;
|
|
4787
|
-
}, toUint8 = (value, encoder) => encoder.encode(value),
|
|
4795
|
+
}, toUint8 = (value, encoder) => encoder.encode(value), isRecord9 = (value) => Boolean(value) && typeof value === "object", isSafeHtmlLike = (value) => isRecord9(value) && typeof value.changingThisBreaksApplicationSecurity === "string", normalizeSafeHtml = (value) => {
|
|
4788
4796
|
if (isSafeHtmlLike(value)) {
|
|
4789
4797
|
return value.changingThisBreaksApplicationSecurity;
|
|
4790
4798
|
}
|
|
@@ -4845,7 +4853,7 @@ var SLOT_ID_PREFIX = "abs-slot-", CLOSING_BODY_TAG = "</body>", CLOSING_HEAD_TAG
|
|
|
4845
4853
|
}, createTimeoutError = (slot, timeoutMs) => {
|
|
4846
4854
|
const error = Object.assign(new Error(`Streaming slot "${slot.id}" timed out after ${timeoutMs}ms`), { __absTimeout: true });
|
|
4847
4855
|
return error;
|
|
4848
|
-
}, isSlotPatchPayloadObject = (value) =>
|
|
4856
|
+
}, isSlotPatchPayloadObject = (value) => isRecord9(value) && ("html" in value), isTimeoutError = (error) => isRecord9(error) && error.__absTimeout === true, toStreamingSlot = (slot, policy) => ({
|
|
4849
4857
|
dynamic: slot.dynamic,
|
|
4850
4858
|
errorHtml: slot.errorHtml === undefined ? policy.errorHtml : slot.errorHtml,
|
|
4851
4859
|
fallbackHtml: normalizeSlotText(slot.fallbackHtml, policy.fallbackHtml),
|
|
@@ -16510,6 +16518,129 @@ var resolveRequestBaseHref = (route, request) => deriveAngularBaseHref(route, re
|
|
|
16510
16518
|
// src/angular/pageHandler.ts
|
|
16511
16519
|
init_spaRouteManifest();
|
|
16512
16520
|
|
|
16521
|
+
// src/angular/colocatedRouteMatch.ts
|
|
16522
|
+
var MAX_ROUTE_DEPTH = 32;
|
|
16523
|
+
var isRecord2 = (value) => typeof value === "object" && value !== null;
|
|
16524
|
+
var PRIMARY_OUTLET = "primary";
|
|
16525
|
+
var routeOutlet = (route) => typeof route.outlet === "string" ? route.outlet : PRIMARY_OUTLET;
|
|
16526
|
+
var matchRoute = (route, segments) => {
|
|
16527
|
+
if (!isRecord2(route))
|
|
16528
|
+
return true;
|
|
16529
|
+
if (routeOutlet(route) !== PRIMARY_OUTLET)
|
|
16530
|
+
return false;
|
|
16531
|
+
if (typeof route.matcher === "function")
|
|
16532
|
+
return true;
|
|
16533
|
+
if (typeof route.path !== "string")
|
|
16534
|
+
return true;
|
|
16535
|
+
const { path } = route;
|
|
16536
|
+
const parts = path.split("/").filter((part) => part !== "");
|
|
16537
|
+
if (parts.includes("**"))
|
|
16538
|
+
return true;
|
|
16539
|
+
const isFull = route.pathMatch === "full";
|
|
16540
|
+
if (parts.length > segments.length)
|
|
16541
|
+
return false;
|
|
16542
|
+
if (isFull && parts.length < segments.length)
|
|
16543
|
+
return false;
|
|
16544
|
+
const consumed = parts.every((part, index) => part.startsWith(":") || part === segments[index]);
|
|
16545
|
+
if (!consumed)
|
|
16546
|
+
return false;
|
|
16547
|
+
const rest = segments.slice(parts.length);
|
|
16548
|
+
if (route.redirectTo !== undefined)
|
|
16549
|
+
return true;
|
|
16550
|
+
if (route.loadChildren !== undefined)
|
|
16551
|
+
return true;
|
|
16552
|
+
if (route.children !== undefined)
|
|
16553
|
+
return { children: route.children, rest };
|
|
16554
|
+
return rest.length === 0;
|
|
16555
|
+
};
|
|
16556
|
+
var matchRoutes = (routes, segments, depth) => {
|
|
16557
|
+
if (!Array.isArray(routes) || depth > MAX_ROUTE_DEPTH)
|
|
16558
|
+
return true;
|
|
16559
|
+
if (segments.length === 0)
|
|
16560
|
+
return true;
|
|
16561
|
+
return routes.some((route) => {
|
|
16562
|
+
const result = matchRoute(route, segments);
|
|
16563
|
+
if (typeof result === "boolean")
|
|
16564
|
+
return result;
|
|
16565
|
+
return matchRoutes(result.children, result.rest, depth + 1);
|
|
16566
|
+
});
|
|
16567
|
+
};
|
|
16568
|
+
var decodeSegment = (segment) => {
|
|
16569
|
+
try {
|
|
16570
|
+
return decodeURIComponent(segment);
|
|
16571
|
+
} catch {
|
|
16572
|
+
return null;
|
|
16573
|
+
}
|
|
16574
|
+
};
|
|
16575
|
+
var toUrlSegments = (path) => {
|
|
16576
|
+
if (path.includes("(") || path.includes(")"))
|
|
16577
|
+
return null;
|
|
16578
|
+
const decoded = path.split("/").map((raw) => raw.split(";")[0] ?? "").filter((segment) => segment !== "").map(decodeSegment);
|
|
16579
|
+
if (decoded.some((segment) => segment === null))
|
|
16580
|
+
return null;
|
|
16581
|
+
return decoded.filter((segment) => segment !== null);
|
|
16582
|
+
};
|
|
16583
|
+
var matchesAngularColocatedRoutes = (routes, path) => {
|
|
16584
|
+
const segments = toUrlSegments(path);
|
|
16585
|
+
if (segments === null)
|
|
16586
|
+
return true;
|
|
16587
|
+
return matchRoutes(routes, segments, 0);
|
|
16588
|
+
};
|
|
16589
|
+
var pathBelowBaseHref = (pathname, baseHref) => {
|
|
16590
|
+
const collapsed = pathname.replace(/\/{2,}/g, "/");
|
|
16591
|
+
const base = baseHref.endsWith("/") ? baseHref : `${baseHref}/`;
|
|
16592
|
+
if (`${collapsed}/` === base)
|
|
16593
|
+
return "";
|
|
16594
|
+
if (!collapsed.startsWith(base))
|
|
16595
|
+
return null;
|
|
16596
|
+
return collapsed.slice(base.length);
|
|
16597
|
+
};
|
|
16598
|
+
var WILDCARD_SUFFIX2 = "/*";
|
|
16599
|
+
var ROOT_WILDCARD = "/*";
|
|
16600
|
+
var MAX_PROVIDER_DEPTH = 8;
|
|
16601
|
+
var providesBaseHref = (provider, depth = 0) => {
|
|
16602
|
+
if (depth > MAX_PROVIDER_DEPTH)
|
|
16603
|
+
return true;
|
|
16604
|
+
if (Array.isArray(provider))
|
|
16605
|
+
return provider.some((entry) => providesBaseHref(entry, depth + 1));
|
|
16606
|
+
if (!isRecord2(provider))
|
|
16607
|
+
return false;
|
|
16608
|
+
const nested = Reflect.get(provider, "\u0275providers");
|
|
16609
|
+
if (Array.isArray(nested))
|
|
16610
|
+
return providesBaseHref(nested, depth + 1);
|
|
16611
|
+
if (!("provide" in provider))
|
|
16612
|
+
return false;
|
|
16613
|
+
return String(provider.provide).includes("appBaseHref");
|
|
16614
|
+
};
|
|
16615
|
+
var isUnmatchedColocatedRoute = ({
|
|
16616
|
+
handlerProviders,
|
|
16617
|
+
pageModule,
|
|
16618
|
+
request,
|
|
16619
|
+
route,
|
|
16620
|
+
runtimeBaseHref
|
|
16621
|
+
}) => {
|
|
16622
|
+
if (!request || !route?.endsWith(WILDCARD_SUFFIX2))
|
|
16623
|
+
return false;
|
|
16624
|
+
const { providers, routes } = pageModule;
|
|
16625
|
+
if (!Array.isArray(routes) || !Array.isArray(providers))
|
|
16626
|
+
return false;
|
|
16627
|
+
if (providesBaseHref(handlerProviders))
|
|
16628
|
+
return false;
|
|
16629
|
+
const baseHref = runtimeBaseHref ?? (route === ROOT_WILDCARD ? "/" : null);
|
|
16630
|
+
if (baseHref === null)
|
|
16631
|
+
return false;
|
|
16632
|
+
let pathname;
|
|
16633
|
+
try {
|
|
16634
|
+
({ pathname } = new URL(request.url));
|
|
16635
|
+
} catch {
|
|
16636
|
+
return false;
|
|
16637
|
+
}
|
|
16638
|
+
const path = pathBelowBaseHref(pathname, baseHref);
|
|
16639
|
+
if (path === null)
|
|
16640
|
+
return false;
|
|
16641
|
+
return !matchesAngularColocatedRoutes(routes, path);
|
|
16642
|
+
};
|
|
16643
|
+
|
|
16513
16644
|
// src/angular/lowerServerIslands.ts
|
|
16514
16645
|
init_renderIslandMarkup();
|
|
16515
16646
|
var ANGULAR_ISLAND_TAG_RE = /<absolute-island\b([^>]*)>[\s\S]*?<\/absolute-island>/gi;
|
|
@@ -16527,7 +16658,7 @@ var islandHydrationModes = [
|
|
|
16527
16658
|
"none"
|
|
16528
16659
|
];
|
|
16529
16660
|
var decodeHtmlAttribute = (value) => value.replaceAll(""", '"').replaceAll(""", '"').replaceAll("'", "'").replaceAll("'", "'").replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
16530
|
-
var
|
|
16661
|
+
var isRecord7 = (value) => typeof value === "object" && value !== null;
|
|
16531
16662
|
var isIslandFramework = (value) => islandFrameworks.some((framework) => framework === value);
|
|
16532
16663
|
var isIslandHydrate = (value) => islandHydrationModes.some((mode) => mode === value);
|
|
16533
16664
|
var parseAttributes = (attributeString) => {
|
|
@@ -16558,7 +16689,7 @@ var parseAngularIslandProps = (attributeString) => {
|
|
|
16558
16689
|
let parsedProps = {};
|
|
16559
16690
|
try {
|
|
16560
16691
|
const candidate = JSON.parse(serializedProps);
|
|
16561
|
-
parsedProps =
|
|
16692
|
+
parsedProps = isRecord7(candidate) ? candidate : {};
|
|
16562
16693
|
} catch {}
|
|
16563
16694
|
return {
|
|
16564
16695
|
component,
|
|
@@ -16927,11 +17058,11 @@ var runWithStreamingSlotWarningScope = (task, metadata) => ensureWarningStorage(
|
|
|
16927
17058
|
|
|
16928
17059
|
// src/angular/pageHandler.ts
|
|
16929
17060
|
init_ssrRender();
|
|
16930
|
-
var
|
|
17061
|
+
var isRecord10 = (value) => typeof value === "object" && value !== null;
|
|
16931
17062
|
var isAngularComponent = (value) => typeof value === "function";
|
|
16932
17063
|
var componentHostsRouterOutlet = (component) => {
|
|
16933
17064
|
const componentDef = Reflect.get(component, "\u0275cmp");
|
|
16934
|
-
if (!
|
|
17065
|
+
if (!isRecord10(componentDef))
|
|
16935
17066
|
return false;
|
|
16936
17067
|
const rawDependencies = componentDef.dependencies;
|
|
16937
17068
|
const dependencies = typeof rawDependencies === "function" ? Reflect.apply(rawDependencies, undefined, []) : rawDependencies;
|
|
@@ -16941,7 +17072,7 @@ var componentHostsRouterOutlet = (component) => {
|
|
|
16941
17072
|
if (dependency === null || typeof dependency !== "object" && typeof dependency !== "function")
|
|
16942
17073
|
return false;
|
|
16943
17074
|
const directiveDef = Reflect.get(dependency, "\u0275dir") ?? dependency;
|
|
16944
|
-
if (!
|
|
17075
|
+
if (!isRecord10(directiveDef))
|
|
16945
17076
|
return false;
|
|
16946
17077
|
const { selectors } = directiveDef;
|
|
16947
17078
|
return Array.isArray(selectors) && JSON.stringify(selectors).includes("router-outlet");
|
|
@@ -16971,7 +17102,7 @@ var ensureAngularCompiler = () => {
|
|
|
16971
17102
|
}
|
|
16972
17103
|
return compilerImportPromise;
|
|
16973
17104
|
};
|
|
16974
|
-
var readAngularPageModule = (value) =>
|
|
17105
|
+
var readAngularPageModule = (value) => isRecord10(value) ? value : null;
|
|
16975
17106
|
var resolveAngularSsrOutDir = (projectRoot = process.cwd(), configuredOutDir = process.env.ABSOLUTE_ANGULAR_SSR_OUTDIR) => configuredOutDir ?? join10(projectRoot, ".absolutejs", "runtime", "angular-ssr");
|
|
16976
17107
|
var createAngularRuntimeCacheBuster = () => `${Date.now().toString(BASE_36_RADIX)}.${Math.random().toString(BASE_36_RADIX).substring(2, RANDOM_ID_END_INDEX)}`;
|
|
16977
17108
|
var existingNodeModulesLinkMatches = async (nodeModulesLink, expectedTarget) => {
|
|
@@ -17089,7 +17220,7 @@ var handleAngularPageRequest = async (input) => {
|
|
|
17089
17220
|
],
|
|
17090
17221
|
runtimes: [String(ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION)]
|
|
17091
17222
|
},
|
|
17092
|
-
props:
|
|
17223
|
+
props: isRecord10(input.requestContext) ? input.requestContext : Object.create(null),
|
|
17093
17224
|
request,
|
|
17094
17225
|
status: input.responseInit?.status,
|
|
17095
17226
|
route: () => {
|
|
@@ -17126,18 +17257,27 @@ var handleAngularPageRequest = async (input) => {
|
|
|
17126
17257
|
});
|
|
17127
17258
|
try {
|
|
17128
17259
|
const handlerCallsite = options?.collectStreamingSlots === true ? undefined : getCurrentRouteRegistrationCallsite() ?? captureStreamingSlotWarningCallsite();
|
|
17260
|
+
const baseDeps = await getAngularDeps();
|
|
17261
|
+
const runtimePagePath = await resolveRuntimeAngularModulePath(resolvedPagePath);
|
|
17262
|
+
const importedPageModule = await import(buildRuntimeModuleSpecifier(runtimePagePath.path, runtimePagePath.cacheBuster));
|
|
17263
|
+
const pageModule = readAngularPageModule(importedPageModule);
|
|
17264
|
+
if (!pageModule) {
|
|
17265
|
+
throw new Error(`Invalid Angular page module: ${resolvedPagePath}`);
|
|
17266
|
+
}
|
|
17267
|
+
const PageComponent = resolvePageComponent(pageModule);
|
|
17268
|
+
if (!isAngularComponent(PageComponent)) {
|
|
17269
|
+
throw new Error(`Angular page module must export an Angular component: ${resolvedPagePath}`);
|
|
17270
|
+
}
|
|
17271
|
+
if (isUnmatchedColocatedRoute({
|
|
17272
|
+
handlerProviders: input.providers,
|
|
17273
|
+
pageModule,
|
|
17274
|
+
request,
|
|
17275
|
+
route: getCurrentAbsoluteRoute(request),
|
|
17276
|
+
runtimeBaseHref
|
|
17277
|
+
})) {
|
|
17278
|
+
return withPageCacheHeaders(await renderSpaNotFoundResponse(request), request);
|
|
17279
|
+
}
|
|
17129
17280
|
const renderPageResponse = async () => {
|
|
17130
|
-
const baseDeps = await getAngularDeps();
|
|
17131
|
-
const runtimePagePath = await resolveRuntimeAngularModulePath(resolvedPagePath);
|
|
17132
|
-
const importedPageModule = await import(buildRuntimeModuleSpecifier(runtimePagePath.path, runtimePagePath.cacheBuster));
|
|
17133
|
-
const pageModule = readAngularPageModule(importedPageModule);
|
|
17134
|
-
if (!pageModule) {
|
|
17135
|
-
throw new Error(`Invalid Angular page module: ${resolvedPagePath}`);
|
|
17136
|
-
}
|
|
17137
|
-
const PageComponent = resolvePageComponent(pageModule);
|
|
17138
|
-
if (!isAngularComponent(PageComponent)) {
|
|
17139
|
-
throw new Error(`Angular page module must export an Angular component: ${resolvedPagePath}`);
|
|
17140
|
-
}
|
|
17141
17281
|
const hasIslands = typeof pageModule.__ABSOLUTE_PAGE_HAS_ISLANDS__ === "boolean" ? pageModule.__ABSOLUTE_PAGE_HAS_ISLANDS__ : false;
|
|
17142
17282
|
const usesLegacyAnimations = pageModule.__ABSOLUTE_PAGE_USES_LEGACY_ANIMATIONS__ === true;
|
|
17143
17283
|
const deps = baseDeps;
|
|
@@ -17709,5 +17849,5 @@ export {
|
|
|
17709
17849
|
withPendingTask
|
|
17710
17850
|
};
|
|
17711
17851
|
|
|
17712
|
-
//# debugId=
|
|
17852
|
+
//# debugId=D3C5CBDE25ADE9C364756E2164756E21
|
|
17713
17853
|
//# sourceMappingURL=index.js.map
|