@pylonsync/sdk 0.3.235 → 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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.ts +76 -26
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.3.235",
6
+ "version": "0.3.237",
7
7
  "type": "module",
8
8
  "main": "src/index.ts",
9
9
  "types": "src/index.ts",
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
- "layout.tsx",
715
- "layout.ts",
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: path
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
- return pages.map((p) => ({
766
- path:
767
- "/" +
768
- p.segments
769
- .map((s) => (isParam(s) ? `:${s.slice(1, -1)}` : s))
770
- .join("/"),
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[] {