@pylonsync/sdk 0.3.236 → 0.3.237
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/package.json +1 -1
- package/src/index.ts +76 -26
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -324,6 +324,15 @@ export interface RouteDefinition {
|
|
|
324
324
|
* as `children`. Only relevant for `mode === "ssr"`.
|
|
325
325
|
*/
|
|
326
326
|
layouts?: string[];
|
|
327
|
+
/**
|
|
328
|
+
* Route kind. Omitted (or `"page"`) is a normal navigable page.
|
|
329
|
+
* `"not-found"` / `"error"` are SSR boundary modules discovered from
|
|
330
|
+
* `app/.../not-found.tsx` and `app/.../error.tsx`. Boundary routes are
|
|
331
|
+
* NOT matched as navigable URLs — the host renders `not-found` for
|
|
332
|
+
* unmatched URLs (HTTP 404) and `error` on render failure (HTTP 500).
|
|
333
|
+
* `path` records the segment prefix the boundary covers (`/` for root).
|
|
334
|
+
*/
|
|
335
|
+
kind?: "page" | "not-found" | "error";
|
|
327
336
|
}
|
|
328
337
|
|
|
329
338
|
export function defineRoute(route: RouteDefinition): RouteDefinition {
|
|
@@ -497,6 +506,8 @@ export interface ManifestRoute {
|
|
|
497
506
|
auth?: string;
|
|
498
507
|
component?: string;
|
|
499
508
|
layouts?: string[];
|
|
509
|
+
/** "not-found" / "error" boundary modules; omitted for normal pages. */
|
|
510
|
+
kind?: "page" | "not-found" | "error";
|
|
500
511
|
}
|
|
501
512
|
|
|
502
513
|
export interface ManifestInputField {
|
|
@@ -637,6 +648,7 @@ export function routesToManifest(routes: RouteDefinition[]): ManifestRoute[] {
|
|
|
637
648
|
if (r.auth) result.auth = r.auth;
|
|
638
649
|
if (r.component) result.component = r.component;
|
|
639
650
|
if (r.layouts && r.layouts.length > 0) result.layouts = r.layouts;
|
|
651
|
+
if (r.kind && r.kind !== "page") result.kind = r.kind;
|
|
640
652
|
return result;
|
|
641
653
|
});
|
|
642
654
|
}
|
|
@@ -701,7 +713,23 @@ export async function discoverAppRoutes(opts?: {
|
|
|
701
713
|
component: string;
|
|
702
714
|
layouts: string[];
|
|
703
715
|
};
|
|
716
|
+
type BoundaryHit = {
|
|
717
|
+
segments: string[];
|
|
718
|
+
component: string;
|
|
719
|
+
layouts: string[];
|
|
720
|
+
kind: "not-found" | "error";
|
|
721
|
+
};
|
|
704
722
|
const pages: PageHit[] = [];
|
|
723
|
+
const boundaries: BoundaryHit[] = [];
|
|
724
|
+
|
|
725
|
+
// Resolve the first existing `<base>.{tsx,ts,jsx,js}` in `dir` and
|
|
726
|
+
// return it as a cwd-relative, extension-less module path (or null).
|
|
727
|
+
const findModule = (dir: string, base: string): string | null => {
|
|
728
|
+
const hit = [`${base}.tsx`, `${base}.ts`, `${base}.jsx`, `${base}.js`]
|
|
729
|
+
.map((n: string) => path.join(dir, n))
|
|
730
|
+
.find((p: string) => fs.existsSync(p));
|
|
731
|
+
return hit ? path.relative(cwd, hit).replace(/\.(tsx?|jsx?)$/, "") : null;
|
|
732
|
+
};
|
|
705
733
|
|
|
706
734
|
function walk(dir: string, segments: string[], layouts: string[]): void {
|
|
707
735
|
let entries: Array<{ name: string; isDirectory(): boolean }>;
|
|
@@ -710,32 +738,38 @@ export async function discoverAppRoutes(opts?: {
|
|
|
710
738
|
} catch {
|
|
711
739
|
return;
|
|
712
740
|
}
|
|
713
|
-
const layoutHere =
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
"layout.jsx",
|
|
717
|
-
"layout.js",
|
|
718
|
-
]
|
|
719
|
-
.map((n) => path.join(dir, n))
|
|
720
|
-
.find((p) => fs.existsSync(p));
|
|
721
|
-
const nextLayouts = layoutHere
|
|
722
|
-
? [
|
|
723
|
-
...layouts,
|
|
724
|
-
path.relative(cwd, layoutHere).replace(/\.(tsx?|jsx?)$/, ""),
|
|
725
|
-
]
|
|
726
|
-
: layouts;
|
|
727
|
-
const pageHere = ["page.tsx", "page.ts", "page.jsx", "page.js"]
|
|
728
|
-
.map((n) => path.join(dir, n))
|
|
729
|
-
.find((p) => fs.existsSync(p));
|
|
741
|
+
const layoutHere = findModule(dir, "layout");
|
|
742
|
+
const nextLayouts = layoutHere ? [...layouts, layoutHere] : layouts;
|
|
743
|
+
const pageHere = findModule(dir, "page");
|
|
730
744
|
if (pageHere) {
|
|
731
745
|
pages.push({
|
|
732
746
|
segments: [...segments],
|
|
733
|
-
component:
|
|
734
|
-
.relative(cwd, pageHere)
|
|
735
|
-
.replace(/\.(tsx?|jsx?)$/, ""),
|
|
747
|
+
component: pageHere,
|
|
736
748
|
layouts: nextLayouts,
|
|
737
749
|
});
|
|
738
750
|
}
|
|
751
|
+
// Boundary modules (not-found.tsx / error.tsx) co-located with a
|
|
752
|
+
// segment. They wrap in the layouts ABOVE them (nextLayouts) so the
|
|
753
|
+
// root not-found renders inside the root shell. The host consults
|
|
754
|
+
// these for unmatched-URL 404s + render-failure 500s.
|
|
755
|
+
const notFoundHere = findModule(dir, "not-found");
|
|
756
|
+
if (notFoundHere) {
|
|
757
|
+
boundaries.push({
|
|
758
|
+
segments: [...segments],
|
|
759
|
+
component: notFoundHere,
|
|
760
|
+
layouts: nextLayouts,
|
|
761
|
+
kind: "not-found",
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
const errorHere = findModule(dir, "error");
|
|
765
|
+
if (errorHere) {
|
|
766
|
+
boundaries.push({
|
|
767
|
+
segments: [...segments],
|
|
768
|
+
component: errorHere,
|
|
769
|
+
layouts: nextLayouts,
|
|
770
|
+
kind: "error",
|
|
771
|
+
});
|
|
772
|
+
}
|
|
739
773
|
for (const e of entries) {
|
|
740
774
|
if (!e.isDirectory()) continue;
|
|
741
775
|
if (e.name.startsWith(".") || e.name === "node_modules") continue;
|
|
@@ -762,16 +796,32 @@ export async function discoverAppRoutes(opts?: {
|
|
|
762
796
|
return a.segments.length - b.segments.length;
|
|
763
797
|
});
|
|
764
798
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
799
|
+
const segmentsToPath = (segments: string[]): string =>
|
|
800
|
+
"/" +
|
|
801
|
+
segments.map((s) => (isParam(s) ? `:${s.slice(1, -1)}` : s)).join("/");
|
|
802
|
+
|
|
803
|
+
const pageRoutes: RouteDefinition[] = pages.map((p) => ({
|
|
804
|
+
path: segmentsToPath(p.segments),
|
|
771
805
|
mode: "ssr" as const,
|
|
772
806
|
component: p.component,
|
|
773
807
|
layouts: p.layouts,
|
|
774
808
|
}));
|
|
809
|
+
|
|
810
|
+
// Boundary routes carry `kind` and the segment-prefix path. The host
|
|
811
|
+
// never matches them as navigable URLs; it picks the longest-prefix
|
|
812
|
+
// not-found for an unmatched URL. Sorted deepest-first so prefix
|
|
813
|
+
// selection is stable.
|
|
814
|
+
const boundaryRoutes: RouteDefinition[] = boundaries
|
|
815
|
+
.sort((a, b) => b.segments.length - a.segments.length)
|
|
816
|
+
.map((b) => ({
|
|
817
|
+
path: segmentsToPath(b.segments),
|
|
818
|
+
mode: "ssr" as const,
|
|
819
|
+
component: b.component,
|
|
820
|
+
layouts: b.layouts,
|
|
821
|
+
kind: b.kind,
|
|
822
|
+
}));
|
|
823
|
+
|
|
824
|
+
return [...pageRoutes, ...boundaryRoutes];
|
|
775
825
|
}
|
|
776
826
|
|
|
777
827
|
export function queriesToManifest(queries: QueryDefinition[]): ManifestQuery[] {
|