@ohhwells/bridge 0.1.64-next.176 → 0.1.64

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/dist/styles.css CHANGED
@@ -104,9 +104,6 @@
104
104
  .inset-0 {
105
105
  inset: calc(var(--spacing) * 0);
106
106
  }
107
- .inset-y-0 {
108
- inset-block: calc(var(--spacing) * 0);
109
- }
110
107
  .top-0 {
111
108
  top: calc(var(--spacing) * 0);
112
109
  }
@@ -188,6 +185,12 @@
188
185
  .z-\[2\] {
189
186
  z-index: 2;
190
187
  }
188
+ .z-\[2147483644\] {
189
+ z-index: 2147483644;
190
+ }
191
+ .z-\[2147483645\] {
192
+ z-index: 2147483645;
193
+ }
191
194
  .z-\[2147483646\] {
192
195
  z-index: 2147483646;
193
196
  }
@@ -225,6 +228,9 @@
225
228
  .m-0 {
226
229
  margin: calc(var(--spacing) * 0);
227
230
  }
231
+ .mx-0\.5 {
232
+ margin-inline: calc(var(--spacing) * 0.5);
233
+ }
228
234
  .mx-auto {
229
235
  margin-inline: auto;
230
236
  }
@@ -240,6 +246,9 @@
240
246
  .mb-8 {
241
247
  margin-bottom: calc(var(--spacing) * 8);
242
248
  }
249
+ .ml-0\.5 {
250
+ margin-left: calc(var(--spacing) * 0.5);
251
+ }
243
252
  .box-border {
244
253
  box-sizing: border-box;
245
254
  }
@@ -289,9 +298,6 @@
289
298
  .\!h-full {
290
299
  height: 100% !important;
291
300
  }
292
- .h-2 {
293
- height: calc(var(--spacing) * 2);
294
- }
295
301
  .h-4 {
296
302
  height: calc(var(--spacing) * 4);
297
303
  }
@@ -316,12 +322,18 @@
316
322
  .h-\[3px\] {
317
323
  height: 3px;
318
324
  }
325
+ .h-\[18px\] {
326
+ height: 18px;
327
+ }
319
328
  .h-\[36px\] {
320
329
  height: 36px;
321
330
  }
322
331
  .h-\[70px\] {
323
332
  height: 70px;
324
333
  }
334
+ .h-\[104px\] {
335
+ height: 104px;
336
+ }
325
337
  .h-\[264px\] {
326
338
  height: 264px;
327
339
  }
@@ -391,6 +403,9 @@
391
403
  .w-\[200px\] {
392
404
  width: 200px;
393
405
  }
406
+ .w-\[420px\] {
407
+ width: 420px;
408
+ }
394
409
  .w-\[var\(--radix-popover-trigger-width\)\] {
395
410
  width: var(--radix-popover-trigger-width);
396
411
  }
@@ -425,18 +440,24 @@
425
440
  .min-w-32 {
426
441
  min-width: calc(var(--spacing) * 32);
427
442
  }
443
+ .min-w-\[18px\] {
444
+ min-width: 18px;
445
+ }
428
446
  .min-w-\[64px\] {
429
447
  min-width: 64px;
430
448
  }
431
449
  .min-w-\[80px\] {
432
450
  min-width: 80px;
433
451
  }
452
+ .min-w-\[170px\] {
453
+ min-width: 170px;
454
+ }
455
+ .min-w-\[190px\] {
456
+ min-width: 190px;
457
+ }
434
458
  .flex-1 {
435
459
  flex: 1;
436
460
  }
437
- .shrink {
438
- flex-shrink: 1;
439
- }
440
461
  .shrink-0 {
441
462
  flex-shrink: 0;
442
463
  }
@@ -490,10 +511,8 @@
490
511
  .resize {
491
512
  resize: both;
492
513
  }
493
- .appearance-none {
494
- -webkit-appearance: none;
495
- -moz-appearance: none;
496
- appearance: none;
514
+ .grid-cols-3 {
515
+ grid-template-columns: repeat(3, minmax(0, 1fr));
497
516
  }
498
517
  .flex-col {
499
518
  flex-direction: column;
@@ -572,9 +591,6 @@
572
591
  .overflow-x-auto {
573
592
  overflow-x: auto;
574
593
  }
575
- .rounded {
576
- border-radius: var(--radius);
577
- }
578
594
  .rounded-2xl {
579
595
  border-radius: var(--radius-2xl);
580
596
  }
@@ -715,6 +731,14 @@
715
731
  background-color: color-mix(in oklab, var(--color-muted) 40%, transparent);
716
732
  }
717
733
  }
734
+ .bg-muted\/70 {
735
+ background-color: var(--color-muted);
736
+ }
737
+ @supports (color: color-mix(in lab, red, red)) {
738
+ .bg-muted\/70 {
739
+ background-color: color-mix(in oklab, var(--color-muted) 70%, transparent);
740
+ }
741
+ }
718
742
  .bg-popover {
719
743
  background-color: var(--color-popover);
720
744
  }
@@ -724,6 +748,14 @@
724
748
  .bg-primary-50 {
725
749
  background-color: var(--color-primary-50);
726
750
  }
751
+ .bg-primary\/10 {
752
+ background-color: var(--color-primary);
753
+ }
754
+ @supports (color: color-mix(in lab, red, red)) {
755
+ .bg-primary\/10 {
756
+ background-color: color-mix(in oklab, var(--color-primary) 10%, transparent);
757
+ }
758
+ }
727
759
  .bg-secondary {
728
760
  background-color: var(--color-secondary);
729
761
  }
@@ -752,6 +784,9 @@
752
784
  .p-3 {
753
785
  padding: calc(var(--spacing) * 3);
754
786
  }
787
+ .p-4 {
788
+ padding: calc(var(--spacing) * 4);
789
+ }
755
790
  .p-5 {
756
791
  padding: calc(var(--spacing) * 5);
757
792
  }
@@ -904,6 +939,15 @@
904
939
  font-size: var(--text-body);
905
940
  line-height: var(--tw-leading, var(--text-body--line-height));
906
941
  }
942
+ .text-\[11px\] {
943
+ font-size: 11px;
944
+ }
945
+ .text-\[13px\] {
946
+ font-size: 13px;
947
+ }
948
+ .text-\[15px\] {
949
+ font-size: 15px;
950
+ }
907
951
  .leading-4 {
908
952
  --tw-leading: calc(var(--spacing) * 4);
909
953
  line-height: calc(var(--spacing) * 4);
@@ -999,6 +1043,9 @@
999
1043
  .text-popover-foreground {
1000
1044
  color: var(--color-popover-foreground);
1001
1045
  }
1046
+ .text-primary {
1047
+ color: var(--color-primary);
1048
+ }
1002
1049
  .text-primary-foreground {
1003
1050
  color: var(--color-primary-foreground);
1004
1051
  }
@@ -1014,8 +1061,8 @@
1014
1061
  .text-white {
1015
1062
  color: var(--color-white);
1016
1063
  }
1017
- .uppercase {
1018
- text-transform: uppercase;
1064
+ .capitalize {
1065
+ text-transform: capitalize;
1019
1066
  }
1020
1067
  .italic {
1021
1068
  font-style: italic;
@@ -1155,9 +1202,6 @@
1155
1202
  -moz-user-select: none;
1156
1203
  user-select: none;
1157
1204
  }
1158
- .\[ow\:scheduling\] {
1159
- ow: scheduling;
1160
- }
1161
1205
  .placeholder\:text-muted-foreground::-moz-placeholder {
1162
1206
  color: var(--color-muted-foreground);
1163
1207
  }
@@ -1233,6 +1277,11 @@
1233
1277
  --tw-content: "";
1234
1278
  content: var(--tw-content);
1235
1279
  }
1280
+ @media (hover: hover) {
1281
+ .hover\:border-primary:hover {
1282
+ border-color: var(--color-primary);
1283
+ }
1284
+ }
1236
1285
  @media (hover: hover) {
1237
1286
  .hover\:bg-accent:hover {
1238
1287
  background-color: var(--color-accent);
@@ -1278,6 +1327,16 @@
1278
1327
  }
1279
1328
  }
1280
1329
  }
1330
+ @media (hover: hover) {
1331
+ .hover\:bg-muted\/70:hover {
1332
+ background-color: var(--color-muted);
1333
+ }
1334
+ @supports (color: color-mix(in lab, red, red)) {
1335
+ .hover\:bg-muted\/70:hover {
1336
+ background-color: color-mix(in oklab, var(--color-muted) 70%, transparent);
1337
+ }
1338
+ }
1339
+ }
1281
1340
  @media (hover: hover) {
1282
1341
  .hover\:bg-muted\/80:hover {
1283
1342
  background-color: var(--color-muted);
@@ -1293,6 +1352,16 @@
1293
1352
  background-color: var(--color-primary);
1294
1353
  }
1295
1354
  }
1355
+ @media (hover: hover) {
1356
+ .hover\:bg-primary\/5:hover {
1357
+ background-color: var(--color-primary);
1358
+ }
1359
+ @supports (color: color-mix(in lab, red, red)) {
1360
+ .hover\:bg-primary\/5:hover {
1361
+ background-color: color-mix(in oklab, var(--color-primary) 5%, transparent);
1362
+ }
1363
+ }
1364
+ }
1296
1365
  @media (hover: hover) {
1297
1366
  .hover\:bg-secondary\/80:hover {
1298
1367
  background-color: var(--color-secondary);
@@ -1552,44 +1621,6 @@
1552
1621
  .\[\&_svg\:not\(\[class\*\=absolute\]\)\]\:relative svg:not([class*=absolute]) {
1553
1622
  position: relative;
1554
1623
  }
1555
- .\[\&\:\:-moz-range-thumb\]\:size-5::-moz-range-thumb {
1556
- width: calc(var(--spacing) * 5);
1557
- height: calc(var(--spacing) * 5);
1558
- }
1559
- .\[\&\:\:-moz-range-thumb\]\:rounded-full::-moz-range-thumb {
1560
- border-radius: calc(infinity * 1px);
1561
- }
1562
- .\[\&\:\:-moz-range-thumb\]\:border-2::-moz-range-thumb {
1563
- border-style: var(--tw-border-style);
1564
- border-width: 2px;
1565
- }
1566
- .\[\&\:\:-moz-range-thumb\]\:border-primary::-moz-range-thumb {
1567
- border-color: var(--color-primary);
1568
- }
1569
- .\[\&\:\:-moz-range-thumb\]\:bg-background::-moz-range-thumb {
1570
- background-color: var(--color-background);
1571
- }
1572
- .\[\&\:\:-webkit-slider-thumb\]\:size-5::-webkit-slider-thumb {
1573
- width: calc(var(--spacing) * 5);
1574
- height: calc(var(--spacing) * 5);
1575
- }
1576
- .\[\&\:\:-webkit-slider-thumb\]\:appearance-none::-webkit-slider-thumb {
1577
- -webkit-appearance: none;
1578
- appearance: none;
1579
- }
1580
- .\[\&\:\:-webkit-slider-thumb\]\:rounded-full::-webkit-slider-thumb {
1581
- border-radius: calc(infinity * 1px);
1582
- }
1583
- .\[\&\:\:-webkit-slider-thumb\]\:border-2::-webkit-slider-thumb {
1584
- border-style: var(--tw-border-style);
1585
- border-width: 2px;
1586
- }
1587
- .\[\&\:\:-webkit-slider-thumb\]\:border-primary::-webkit-slider-thumb {
1588
- border-color: var(--color-primary);
1589
- }
1590
- .\[\&\:\:-webkit-slider-thumb\]\:bg-background::-webkit-slider-thumb {
1591
- background-color: var(--color-background);
1592
- }
1593
1624
  .\[\&\>svg\:first-child\]\:absolute > svg:first-child {
1594
1625
  position: absolute;
1595
1626
  }
@@ -1855,6 +1886,15 @@ html[data-ohw-section-picking] [data-ohw-state-toggle] {
1855
1886
  appearance: none;
1856
1887
  }
1857
1888
  }
1889
+ [data-ohw-field-required]::after {
1890
+ content: " *";
1891
+ }
1892
+ [data-ohw-form-success],
1893
+ [data-ohw-form-success-text] {
1894
+ max-width: 100%;
1895
+ overflow-wrap: anywhere;
1896
+ word-break: break-word;
1897
+ }
1858
1898
  @property --tw-translate-x {
1859
1899
  syntax: "*";
1860
1900
  inherits: false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ohhwells/bridge",
3
- "version": "0.1.64-next.176",
3
+ "version": "0.1.64",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -12,11 +12,6 @@
12
12
  "import": "./dist/index.js",
13
13
  "require": "./dist/index.cjs"
14
14
  },
15
- "./pages": {
16
- "types": "./dist/pages.d.ts",
17
- "import": "./dist/pages.js",
18
- "require": "./dist/pages.cjs"
19
- },
20
15
  "./styles": "./dist/styles.css"
21
16
  },
22
17
  "files": [
package/dist/pages.cjs DELETED
@@ -1,141 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/pages.ts
21
- var pages_exports = {};
22
- __export(pages_exports, {
23
- DELETED_PAGE_PREFIX: () => DELETED_PAGE_PREFIX,
24
- fetchSitePages: () => fetchSitePages,
25
- renderCatchAllPage: () => renderCatchAllPage,
26
- resolvePageRewrite: () => resolvePageRewrite,
27
- resolveSitePage: () => resolveSitePage,
28
- resolveSubdomain: () => resolveSubdomain,
29
- sitePagesMiddleware: () => sitePagesMiddleware,
30
- sitePagesMiddlewareConfig: () => sitePagesMiddlewareConfig
31
- });
32
- module.exports = __toCommonJS(pages_exports);
33
-
34
- // src/lib/site-pages.ts
35
- var DELETED_PAGE_PREFIX = "/__ohw-deleted";
36
- function resolveSubdomain(hostnameOverride) {
37
- if (hostnameOverride) {
38
- const parts = hostnameOverride.split(".");
39
- if (parts.length >= 3 && parts[0] !== "www") return parts[0];
40
- }
41
- const siteUrl = process.env.NEXT_PUBLIC_SITE_URL;
42
- if (!siteUrl) return "";
43
- try {
44
- const parts = new URL(siteUrl).hostname.split(".");
45
- if (parts.length >= 3 && parts[0] !== "www") return parts[0];
46
- } catch {
47
- }
48
- return "";
49
- }
50
- async function fetchSitePages(subdomainOverride) {
51
- const subdomain = subdomainOverride || resolveSubdomain();
52
- const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL;
53
- if (!subdomain || !apiUrl) return [];
54
- try {
55
- const res = await fetch(`${apiUrl}/api/public/sites/${subdomain}/pages`, {
56
- cache: "no-store"
57
- });
58
- if (!res.ok) return [];
59
- const { pages } = await res.json();
60
- return pages;
61
- } catch {
62
- return [];
63
- }
64
- }
65
- function resolvePageRewrite(pathname, pages) {
66
- const current = pages.find((page) => page.path === pathname);
67
- if (current) {
68
- if (current.is_deleted) return { path: `${DELETED_PAGE_PREFIX}${pathname}` };
69
- if (current.is_physical && current.original_path && current.original_path !== current.path) {
70
- return { path: current.original_path };
71
- }
72
- return null;
73
- }
74
- const oldUrlOfRenamed = pages.find(
75
- (page) => page.is_physical && page.original_path === pathname && page.path !== pathname
76
- );
77
- if (oldUrlOfRenamed) return { path: `${DELETED_PAGE_PREFIX}${pathname}` };
78
- return null;
79
- }
80
- async function resolveSitePage(segments, subdomainOverride) {
81
- if (`/${segments[0]}` === DELETED_PAGE_PREFIX) return { kind: "not-found" };
82
- const path = `/${segments.join("/")}`;
83
- const pages = await fetchSitePages(subdomainOverride);
84
- const page = pages.find((entry) => entry.path === path && !entry.is_deleted);
85
- if (!page) return { kind: "not-found" };
86
- if (page.duplicated_from) {
87
- const sourceSegment = page.duplicated_from === "/" ? "" : page.duplicated_from.replace(/^\//, "");
88
- return { kind: "duplicate", sourceSegment, page };
89
- }
90
- return { kind: "blank", page };
91
- }
92
-
93
- // src/lib/site-pages-middleware.ts
94
- var import_server = require("next/server");
95
- async function sitePagesMiddleware(request) {
96
- const { pathname } = request.nextUrl;
97
- if (pathname.startsWith("/_next") || pathname.startsWith("/api") || /\.[a-zA-Z0-9]+$/.test(pathname)) {
98
- return import_server.NextResponse.next();
99
- }
100
- const subdomain = request.nextUrl.searchParams.get("subdomain") || resolveSubdomain(request.nextUrl.hostname);
101
- const pages = await fetchSitePages(subdomain || void 0);
102
- if (pages.length === 0) return import_server.NextResponse.next();
103
- const decision = resolvePageRewrite(pathname, pages);
104
- if (!decision) return import_server.NextResponse.next();
105
- return import_server.NextResponse.rewrite(new URL(decision.path, request.url));
106
- }
107
- var sitePagesMiddlewareConfig = {
108
- matcher: ["/((?!_next|api).*)"]
109
- };
110
-
111
- // src/lib/site-pages-render.ts
112
- var import_headers = require("next/headers");
113
- var import_navigation = require("next/navigation");
114
- var import_react = require("react");
115
- async function renderCatchAllPage(segments, subdomainOverride, handlers) {
116
- const host = (await (0, import_headers.headers)()).get("host") ?? void 0;
117
- const subdomain = subdomainOverride || resolveSubdomain(host) || void 0;
118
- const result = await resolveSitePage(segments, subdomain);
119
- if (result.kind === "not-found") (0, import_navigation.notFound)();
120
- if (result.kind === "duplicate") {
121
- try {
122
- const sourceModule = await handlers.renderDuplicate(result.sourceSegment);
123
- return (0, import_react.createElement)(sourceModule.default);
124
- } catch {
125
- (0, import_navigation.notFound)();
126
- }
127
- }
128
- return handlers.renderBlank(result.page);
129
- }
130
- // Annotate the CommonJS export names for ESM import in node:
131
- 0 && (module.exports = {
132
- DELETED_PAGE_PREFIX,
133
- fetchSitePages,
134
- renderCatchAllPage,
135
- resolvePageRewrite,
136
- resolveSitePage,
137
- resolveSubdomain,
138
- sitePagesMiddleware,
139
- sitePagesMiddlewareConfig
140
- });
141
- //# sourceMappingURL=pages.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/pages.ts","../src/lib/site-pages.ts","../src/lib/site-pages-middleware.ts","../src/lib/site-pages-render.ts"],"sourcesContent":["// Server-safe entry point (no 'use client' banner) — for middleware/Edge runtime and\n// Server Components. Keep this file free of React component exports; UI goes in the\n// default `@ohhwells/bridge` entry (src/index.ts).\nexport {\n DELETED_PAGE_PREFIX,\n resolveSubdomain,\n fetchSitePages,\n resolvePageRewrite,\n resolveSitePage,\n} from './lib/site-pages'\nexport type { SitePage, PageRewriteDecision, SitePageResolution } from './lib/site-pages'\nexport { sitePagesMiddleware, sitePagesMiddlewareConfig } from './lib/site-pages-middleware'\nexport { renderCatchAllPage } from './lib/site-pages-render'\nexport type { CatchAllPageHandlers } from './lib/site-pages-render'\n","// Shared page-CRUD infra (OHH-670): fetching a site's page list and deciding how the\n// catch-all route / middleware should handle deleted, renamed, and duplicated pages.\n// Server-safe (no React/browser APIs) so it can run in middleware (Edge runtime) and\n// Server Components — kept out of the main client-bundled entry point, see `../pages.ts`.\n\n// Prefix used to route deleted-physical-page requests into the catch-all `[...page]`\n// route, which has no file of its own at that segment and calls notFound() for it.\nexport const DELETED_PAGE_PREFIX = '/__ohw-deleted'\n\nexport type SitePage = {\n id: string\n path: string\n title: string\n is_physical: boolean\n original_path: string | null\n duplicated_from: string | null\n is_deleted: boolean\n}\n\n// Mirrors OhhwellsBridge's client-side resolveSubdomain: prefer the real request hostname\n// (window.location isn't available on the server, so callers pass the Host header/nextUrl\n// hostname instead) and only fall back to the NEXT_PUBLIC_SITE_URL env var when no hostname\n// is known — the only case that's true in local dev, where the host is just localhost.\nexport function resolveSubdomain(hostnameOverride?: string): string {\n if (hostnameOverride) {\n const parts = hostnameOverride.split('.')\n if (parts.length >= 3 && parts[0] !== 'www') return parts[0]\n }\n\n const siteUrl = process.env.NEXT_PUBLIC_SITE_URL\n if (!siteUrl) return ''\n try {\n const parts = new URL(siteUrl).hostname.split('.')\n if (parts.length >= 3 && parts[0] !== 'www') return parts[0]\n } catch {\n // ignore malformed env value\n }\n return ''\n}\n\n// `subdomainOverride` is the `?subdomain=` query param the canvas editor's iframe appends\n// (see `editUrl` in fo-class-experience). It's required locally: NEXT_PUBLIC_SITE_URL is\n// `http://localhost:3000` in dev, which resolveSubdomain() can't parse a subdomain from.\nexport async function fetchSitePages(subdomainOverride?: string): Promise<SitePage[]> {\n const subdomain = subdomainOverride || resolveSubdomain()\n const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL\n if (!subdomain || !apiUrl) return []\n\n try {\n // no-store, not a timed revalidate: middleware uses this list to decide whether a\n // path is deleted/renamed, and `next start`'s persistent Data Cache would otherwise\n // keep routing a just-deleted page's URL to its live content for longer than expected.\n const res = await fetch(`${apiUrl}/api/public/sites/${subdomain}/pages`, {\n cache: 'no-store',\n })\n if (!res.ok) return []\n const { pages } = (await res.json()) as { pages: SitePage[] }\n return pages\n } catch {\n return []\n }\n}\n\nexport type PageRewriteDecision = { path: string } | null\n\n// Middleware decision logic: given the current pathname and the site's page list, decide\n// whether to rewrite to the deleted-page placeholder or to a renamed physical page's real\n// file location. Callers still own the `_next`/`api`/static-file early-return and the actual\n// `NextResponse.rewrite` call, since those are Next.js-specific.\nexport function resolvePageRewrite(pathname: string, pages: SitePage[]): PageRewriteDecision {\n const current = pages.find((page) => page.path === pathname)\n\n if (current) {\n if (current.is_deleted) return { path: `${DELETED_PAGE_PREFIX}${pathname}` }\n // Renamed physical page: the file still lives at original_path, so rewrite there\n // internally while the browser keeps showing the new canonical path.\n if (current.is_physical && current.original_path && current.original_path !== current.path) {\n return { path: current.original_path }\n }\n return null\n }\n\n // Old URL of a renamed physical page — no redirect, it just no longer resolves to\n // anything (whether or not the page has since also been deleted).\n const oldUrlOfRenamed = pages.find(\n (page) => page.is_physical && page.original_path === pathname && page.path !== pathname,\n )\n if (oldUrlOfRenamed) return { path: `${DELETED_PAGE_PREFIX}${pathname}` }\n\n return null\n}\n\nexport type SitePageResolution =\n | { kind: 'not-found' }\n | { kind: 'duplicate'; sourceSegment: string; page: SitePage }\n | { kind: 'blank'; page: SitePage }\n\n// Catch-all route lookup: given the route's path segments, resolve which page (if any) this\n// request maps to. Callers still own the dynamic `import()` for `kind: 'duplicate'` — that\n// needs a literal relative path per app for webpack's static context analysis to work, so it\n// can't live in this shared package (see the comment at the call site).\nexport async function resolveSitePage(segments: string[], subdomainOverride?: string): Promise<SitePageResolution> {\n if (`/${segments[0]}` === DELETED_PAGE_PREFIX) return { kind: 'not-found' }\n\n const path = `/${segments.join('/')}`\n const pages = await fetchSitePages(subdomainOverride)\n const page = pages.find((entry) => entry.path === path && !entry.is_deleted)\n if (!page) return { kind: 'not-found' }\n\n if (page.duplicated_from) {\n const sourceSegment = page.duplicated_from === '/' ? '' : page.duplicated_from.replace(/^\\//, '')\n return { kind: 'duplicate', sourceSegment, page }\n }\n\n return { kind: 'blank', page }\n}\n","import { NextRequest, NextResponse } from 'next/server'\nimport { fetchSitePages, resolvePageRewrite, resolveSubdomain } from './site-pages'\n\n// Drop-in Next.js middleware for the OHH-670 page-CRUD system: rewrites deleted/renamed\n// pages to the right place before the catch-all route (see `resolveSitePage`) ever runs.\n// Apps that need extra middleware logic of their own can still compose `fetchSitePages`/\n// `resolvePageRewrite` directly instead of using this wrapper.\nexport async function sitePagesMiddleware(request: NextRequest): Promise<NextResponse> {\n const { pathname } = request.nextUrl\n\n if (pathname.startsWith('/_next') || pathname.startsWith('/api') || /\\.[a-zA-Z0-9]+$/.test(pathname)) {\n return NextResponse.next()\n }\n\n // `?subdomain=` is the canvas editor iframe's override (its own origin isn't the site's\n // real domain). Every other request — every real visitor — hits the site's actual\n // `*.ohhwells.site`/custom domain, so the request's own hostname is the source of truth\n // there; without this fallback the middleware silently no-ops on every production request.\n const subdomain =\n request.nextUrl.searchParams.get('subdomain') || resolveSubdomain(request.nextUrl.hostname)\n const pages = await fetchSitePages(subdomain || undefined)\n if (pages.length === 0) return NextResponse.next()\n\n const decision = resolvePageRewrite(pathname, pages)\n if (!decision) return NextResponse.next()\n return NextResponse.rewrite(new URL(decision.path, request.url))\n}\n\n// Mirrors the `_next`/`api` early-return above so apps that re-export this directly as\n// their middleware `config` don't invoke the function needlessly on asset requests.\nexport const sitePagesMiddlewareConfig = {\n matcher: ['/((?!_next|api).*)'],\n}\n","import { headers } from 'next/headers'\nimport { notFound } from 'next/navigation'\nimport { createElement, type ComponentType, type ReactElement } from 'react'\nimport { resolveSitePage, resolveSubdomain, type SitePage } from './site-pages'\n\nexport interface CatchAllPageHandlers {\n // Called for a page that's a duplicate of another. Must contain the actual `import(...)`\n // call itself (relative, not the `@` alias) — webpack can only build a static context\n // module (bundling every matching src/app/*/page.tsx) when the prefix is a real relative\n // path, so this one expression has to stay in the calling app's own file, resolved against\n // its own src/app tree, not this shared package's. Everything else about turning the\n // resolved module into a rendered element lives here instead.\n renderDuplicate: (sourceSegment: string) => Promise<{ default: ComponentType }>\n // Called for a page with no section content of its own yet.\n renderBlank: (page: SitePage) => ReactElement\n}\n\n// Full catch-all route resolution for the OHH-670 page-CRUD system: looks the page up,\n// calls `notFound()` for anything unresolved, and delegates to the two things every\n// consuming app still owns (the duplicate-source import and its blank-page chrome).\nexport async function renderCatchAllPage(\n segments: string[],\n subdomainOverride: string | undefined,\n handlers: CatchAllPageHandlers,\n): Promise<ReactElement> {\n // `subdomainOverride` is the canvas editor iframe's `?subdomain=` query param — its own\n // origin isn't the site's real domain. Every real visitor hits the site's actual\n // `*.ohhwells.site`/custom domain, so fall back to the request's own Host header there,\n // mirroring `sitePagesMiddleware`'s hostname fallback.\n const host = (await headers()).get('host') ?? undefined\n const subdomain = subdomainOverride || resolveSubdomain(host) || undefined\n const result = await resolveSitePage(segments, subdomain)\n\n if (result.kind === 'not-found') notFound()\n\n if (result.kind === 'duplicate') {\n try {\n const sourceModule = await handlers.renderDuplicate(result.sourceSegment)\n return createElement(sourceModule.default)\n } catch {\n notFound()\n }\n }\n\n return handlers.renderBlank(result.page)\n}\n"],"mappings":"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","names":[]}
package/dist/pages.d.cts DELETED
@@ -1,45 +0,0 @@
1
- import { NextRequest, NextResponse } from 'next/server';
2
- import { ComponentType, ReactElement } from 'react';
3
-
4
- declare const DELETED_PAGE_PREFIX = "/__ohw-deleted";
5
- type SitePage = {
6
- id: string;
7
- path: string;
8
- title: string;
9
- is_physical: boolean;
10
- original_path: string | null;
11
- duplicated_from: string | null;
12
- is_deleted: boolean;
13
- };
14
- declare function resolveSubdomain(hostnameOverride?: string): string;
15
- declare function fetchSitePages(subdomainOverride?: string): Promise<SitePage[]>;
16
- type PageRewriteDecision = {
17
- path: string;
18
- } | null;
19
- declare function resolvePageRewrite(pathname: string, pages: SitePage[]): PageRewriteDecision;
20
- type SitePageResolution = {
21
- kind: 'not-found';
22
- } | {
23
- kind: 'duplicate';
24
- sourceSegment: string;
25
- page: SitePage;
26
- } | {
27
- kind: 'blank';
28
- page: SitePage;
29
- };
30
- declare function resolveSitePage(segments: string[], subdomainOverride?: string): Promise<SitePageResolution>;
31
-
32
- declare function sitePagesMiddleware(request: NextRequest): Promise<NextResponse>;
33
- declare const sitePagesMiddlewareConfig: {
34
- matcher: string[];
35
- };
36
-
37
- interface CatchAllPageHandlers {
38
- renderDuplicate: (sourceSegment: string) => Promise<{
39
- default: ComponentType;
40
- }>;
41
- renderBlank: (page: SitePage) => ReactElement;
42
- }
43
- declare function renderCatchAllPage(segments: string[], subdomainOverride: string | undefined, handlers: CatchAllPageHandlers): Promise<ReactElement>;
44
-
45
- export { type CatchAllPageHandlers, DELETED_PAGE_PREFIX, type PageRewriteDecision, type SitePage, type SitePageResolution, fetchSitePages, renderCatchAllPage, resolvePageRewrite, resolveSitePage, resolveSubdomain, sitePagesMiddleware, sitePagesMiddlewareConfig };
package/dist/pages.d.ts DELETED
@@ -1,45 +0,0 @@
1
- import { NextRequest, NextResponse } from 'next/server';
2
- import { ComponentType, ReactElement } from 'react';
3
-
4
- declare const DELETED_PAGE_PREFIX = "/__ohw-deleted";
5
- type SitePage = {
6
- id: string;
7
- path: string;
8
- title: string;
9
- is_physical: boolean;
10
- original_path: string | null;
11
- duplicated_from: string | null;
12
- is_deleted: boolean;
13
- };
14
- declare function resolveSubdomain(hostnameOverride?: string): string;
15
- declare function fetchSitePages(subdomainOverride?: string): Promise<SitePage[]>;
16
- type PageRewriteDecision = {
17
- path: string;
18
- } | null;
19
- declare function resolvePageRewrite(pathname: string, pages: SitePage[]): PageRewriteDecision;
20
- type SitePageResolution = {
21
- kind: 'not-found';
22
- } | {
23
- kind: 'duplicate';
24
- sourceSegment: string;
25
- page: SitePage;
26
- } | {
27
- kind: 'blank';
28
- page: SitePage;
29
- };
30
- declare function resolveSitePage(segments: string[], subdomainOverride?: string): Promise<SitePageResolution>;
31
-
32
- declare function sitePagesMiddleware(request: NextRequest): Promise<NextResponse>;
33
- declare const sitePagesMiddlewareConfig: {
34
- matcher: string[];
35
- };
36
-
37
- interface CatchAllPageHandlers {
38
- renderDuplicate: (sourceSegment: string) => Promise<{
39
- default: ComponentType;
40
- }>;
41
- renderBlank: (page: SitePage) => ReactElement;
42
- }
43
- declare function renderCatchAllPage(segments: string[], subdomainOverride: string | undefined, handlers: CatchAllPageHandlers): Promise<ReactElement>;
44
-
45
- export { type CatchAllPageHandlers, DELETED_PAGE_PREFIX, type PageRewriteDecision, type SitePage, type SitePageResolution, fetchSitePages, renderCatchAllPage, resolvePageRewrite, resolveSitePage, resolveSubdomain, sitePagesMiddleware, sitePagesMiddlewareConfig };