@websolutespa/bom-next 3.0.0 → 3.0.2
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 +1 -1
- package/dist/_virtual/_rolldown/runtime.js +24 -0
- package/dist/client/client.d.ts +9 -0
- package/dist/client/client.d.ts.map +1 -0
- package/dist/client/client.js +18 -0
- package/dist/client/client.js.map +1 -0
- package/dist/client/extra.d.ts +17 -0
- package/dist/client/extra.d.ts.map +1 -0
- package/dist/client/extra.js +13 -0
- package/dist/client/extra.js.map +1 -0
- package/dist/client/label.d.ts +15 -0
- package/dist/client/label.d.ts.map +1 -0
- package/dist/client/label.js +20 -0
- package/dist/client/label.js.map +1 -0
- package/dist/client/layout.d.ts +18 -0
- package/dist/client/layout.d.ts.map +1 -0
- package/dist/client/layout.js +13 -0
- package/dist/client/layout.js.map +1 -0
- package/dist/client/local.collection.d.ts +32 -0
- package/dist/client/local.collection.d.ts.map +1 -0
- package/dist/client/local.collection.js +49 -0
- package/dist/client/local.collection.js.map +1 -0
- package/dist/client/metadata.d.ts +43 -0
- package/dist/client/metadata.d.ts.map +1 -0
- package/dist/client/metadata.js +146 -0
- package/dist/client/metadata.js.map +1 -0
- package/dist/client/page.d.ts +404 -0
- package/dist/client/page.d.ts.map +1 -0
- package/dist/client/page.js +13 -0
- package/dist/client/page.js.map +1 -0
- package/dist/client/useApi.d.ts +21 -0
- package/dist/client/useApi.d.ts.map +1 -0
- package/dist/client/useApi.js +65 -0
- package/dist/client/useApi.js.map +1 -0
- package/dist/client/useCollectionApi.d.ts +21 -0
- package/dist/client/useCollectionApi.d.ts.map +1 -0
- package/dist/client/useCollectionApi.js +65 -0
- package/dist/client/useCollectionApi.js.map +1 -0
- package/dist/client/useExtra.d.ts +9 -0
- package/dist/client/useExtra.d.ts.map +1 -0
- package/dist/client/useExtra.js +13 -0
- package/dist/client/useExtra.js.map +1 -0
- package/dist/client/useHttp.d.ts +15 -0
- package/dist/client/useHttp.d.ts.map +1 -0
- package/dist/client/useHttp.js +70 -0
- package/dist/client/useHttp.js.map +1 -0
- package/dist/client/useLabel.d.ts +9 -0
- package/dist/client/useLabel.d.ts.map +1 -0
- package/dist/client/useLabel.js +13 -0
- package/dist/client/useLabel.js.map +1 -0
- package/dist/client/useLayout.d.ts +9 -0
- package/dist/client/useLayout.d.ts.map +1 -0
- package/dist/client/useLayout.js +13 -0
- package/dist/client/useLayout.js.map +1 -0
- package/dist/client/useLink.d.ts +7 -0
- package/dist/client/useLink.d.ts.map +1 -0
- package/dist/client/useLink.js +15 -0
- package/dist/client/useLink.js.map +1 -0
- package/dist/client/useMetaData.d.ts +9 -0
- package/dist/client/useMetaData.d.ts.map +1 -0
- package/dist/client/useMetaData.js +13 -0
- package/dist/client/useMetaData.js.map +1 -0
- package/dist/client/usePage.d.ts +394 -0
- package/dist/client/usePage.d.ts.map +1 -0
- package/dist/client/usePage.js +13 -0
- package/dist/client/usePage.js.map +1 -0
- package/dist/client/useUser.d.ts +9 -0
- package/dist/client/useUser.d.ts.map +1 -0
- package/dist/client/useUser.js +13 -0
- package/dist/client/useUser.js.map +1 -0
- package/dist/client/user.d.ts +20 -0
- package/dist/client/user.d.ts.map +1 -0
- package/dist/client/user.js +33 -0
- package/dist/client/user.js.map +1 -0
- package/dist/exports/client.d.ts +20 -0
- package/dist/exports/client.js +19 -5734
- package/dist/exports/instrumentation.d.ts +2 -0
- package/dist/exports/instrumentation.js +1 -24
- package/dist/exports/proxy.d.ts +5 -0
- package/dist/exports/proxy.js +4 -253
- package/dist/exports/server.d.ts +19 -0
- package/dist/exports/server.js +18 -1973
- package/dist/index.d.ts +18 -0
- package/dist/index.js +10 -200
- package/dist/instrumentation/client.d.ts +8 -0
- package/dist/instrumentation/client.d.ts.map +1 -0
- package/dist/instrumentation/client.js +15 -0
- package/dist/instrumentation/client.js.map +1 -0
- package/dist/instrumentation/sentry/capture.requestError.js +10 -0
- package/dist/instrumentation/sentry/capture.requestError.js.map +1 -0
- package/dist/instrumentation/sentry/capture.routerTransitionStart.js +7 -0
- package/dist/instrumentation/sentry/capture.routerTransitionStart.js.map +1 -0
- package/dist/{exports/instrumentation-DBO6QH4d.d.ts → instrumentation/server.d.ts} +2 -2
- package/dist/instrumentation/server.d.ts.map +1 -0
- package/dist/instrumentation/server.js +19 -0
- package/dist/instrumentation/server.js.map +1 -0
- package/dist/{types-BatUTdbZ.d.ts → instrumentation/types.d.ts} +2 -2
- package/dist/instrumentation/types.d.ts.map +1 -0
- package/dist/lib/breadcrumb.d.ts +15 -0
- package/dist/lib/breadcrumb.d.ts.map +1 -0
- package/dist/lib/breadcrumb.js +20 -0
- package/dist/lib/breadcrumb.js.map +1 -0
- package/dist/lib/const.d.ts +9 -0
- package/dist/lib/const.d.ts.map +1 -0
- package/dist/lib/const.js +9 -0
- package/dist/lib/const.js.map +1 -0
- package/dist/lib/http.d.ts +36 -0
- package/dist/lib/http.d.ts.map +1 -0
- package/dist/{http-_2M-UFRx.js → lib/http.js} +2 -2
- package/dist/lib/http.js.map +1 -0
- package/dist/lib/label.d.ts +16 -0
- package/dist/lib/label.d.ts.map +1 -0
- package/dist/lib/label.js +33 -0
- package/dist/lib/label.js.map +1 -0
- package/dist/lib/layout.defaults.d.ts +9 -0
- package/dist/lib/layout.defaults.d.ts.map +1 -0
- package/dist/lib/layout.defaults.js +161 -0
- package/dist/lib/layout.defaults.js.map +1 -0
- package/dist/lib/link.d.ts +9 -0
- package/dist/lib/link.d.ts.map +1 -0
- package/dist/lib/link.js +16 -0
- package/dist/lib/link.js.map +1 -0
- package/dist/lib/meta-data.d.ts +56 -0
- package/dist/lib/meta-data.d.ts.map +1 -0
- package/dist/lib/open-graph.d.ts +143 -0
- package/dist/lib/open-graph.d.ts.map +1 -0
- package/dist/lib/pagination.d.ts +27 -0
- package/dist/lib/pagination.d.ts.map +1 -0
- package/dist/lib/pagination.js +39 -0
- package/dist/lib/pagination.js.map +1 -0
- package/dist/lib/route.d.ts +17 -0
- package/dist/lib/route.d.ts.map +1 -0
- package/dist/{route-DzFwERQP.js → lib/route.js} +2 -2
- package/dist/lib/route.js.map +1 -0
- package/dist/lib/store.d.ts +27 -0
- package/dist/lib/store.d.ts.map +1 -0
- package/dist/{store-CJzqrHsl.js → lib/store.js} +2 -25
- package/dist/lib/store.js.map +1 -0
- package/dist/lib/structured-data.d.ts +9 -0
- package/dist/lib/structured-data.d.ts.map +1 -0
- package/dist/lib/twitter-card.d.ts +43 -0
- package/dist/lib/twitter-card.d.ts.map +1 -0
- package/dist/lib/utils.d.ts +13 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +35 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/mock.d.ts +127 -0
- package/dist/mock.d.ts.map +1 -0
- package/dist/node_modules/@selderee/plugin-htmlparser2/lib/hp2-builder.js +75 -0
- package/dist/node_modules/@selderee/plugin-htmlparser2/lib/hp2-builder.js.map +1 -0
- package/dist/node_modules/deepmerge/dist/cjs.js +86 -0
- package/dist/node_modules/deepmerge/dist/cjs.js.map +1 -0
- package/dist/node_modules/dom-serializer/lib/esm/foreignNames.js +105 -0
- package/dist/node_modules/dom-serializer/lib/esm/foreignNames.js.map +1 -0
- package/dist/node_modules/dom-serializer/lib/esm/index.js +146 -0
- package/dist/node_modules/dom-serializer/lib/esm/index.js.map +1 -0
- package/dist/node_modules/domelementtype/lib/esm/index.js +53 -0
- package/dist/node_modules/domelementtype/lib/esm/index.js.map +1 -0
- package/dist/node_modules/domhandler/lib/esm/index.js +130 -0
- package/dist/node_modules/domhandler/lib/esm/index.js.map +1 -0
- package/dist/node_modules/domhandler/lib/esm/node.js +307 -0
- package/dist/node_modules/domhandler/lib/esm/node.js.map +1 -0
- package/dist/node_modules/entities/lib/esm/decode.js +363 -0
- package/dist/node_modules/entities/lib/esm/decode.js.map +1 -0
- package/dist/node_modules/entities/lib/esm/decode_codepoint.js +59 -0
- package/dist/node_modules/entities/lib/esm/decode_codepoint.js.map +1 -0
- package/dist/node_modules/entities/lib/esm/escape.js +85 -0
- package/dist/node_modules/entities/lib/esm/escape.js.map +1 -0
- package/dist/node_modules/entities/lib/esm/generated/decode-data-html.js +6 -0
- package/dist/node_modules/entities/lib/esm/generated/decode-data-html.js.map +1 -0
- package/dist/node_modules/entities/lib/esm/generated/decode-data-xml.js +6 -0
- package/dist/node_modules/entities/lib/esm/generated/decode-data-xml.js.map +1 -0
- package/dist/node_modules/html-to-text/lib/html-to-text.js +1816 -0
- package/dist/node_modules/html-to-text/lib/html-to-text.js.map +1 -0
- package/dist/node_modules/html-to-text/node_modules/htmlparser2/lib/esm/Parser.js +435 -0
- package/dist/node_modules/html-to-text/node_modules/htmlparser2/lib/esm/Parser.js.map +1 -0
- package/dist/node_modules/html-to-text/node_modules/htmlparser2/lib/esm/Tokenizer.js +736 -0
- package/dist/node_modules/html-to-text/node_modules/htmlparser2/lib/esm/Tokenizer.js.map +1 -0
- package/dist/node_modules/html-to-text/node_modules/htmlparser2/lib/esm/index.js +19 -0
- package/dist/node_modules/html-to-text/node_modules/htmlparser2/lib/esm/index.js.map +1 -0
- package/dist/node_modules/leac/lib/leac.js +101 -0
- package/dist/node_modules/leac/lib/leac.js.map +1 -0
- package/dist/node_modules/parseley/lib/parseley.js +310 -0
- package/dist/node_modules/parseley/lib/parseley.js.map +1 -0
- package/dist/node_modules/peberminta/lib/core.js +149 -0
- package/dist/node_modules/peberminta/lib/core.js.map +1 -0
- package/dist/node_modules/selderee/lib/selderee.js +319 -0
- package/dist/node_modules/selderee/lib/selderee.js.map +1 -0
- package/dist/proxy/protected-route.d.ts +9 -0
- package/dist/proxy/protected-route.d.ts.map +1 -0
- package/dist/proxy/protected-route.js +40 -0
- package/dist/proxy/protected-route.js.map +1 -0
- package/dist/proxy/proxy.d.ts +31 -0
- package/dist/proxy/proxy.d.ts.map +1 -0
- package/dist/proxy/proxy.js +49 -0
- package/dist/proxy/proxy.js.map +1 -0
- package/dist/proxy/route-auto-detection.d.ts +12 -0
- package/dist/proxy/route-auto-detection.d.ts.map +1 -0
- package/dist/proxy/route-auto-detection.js +82 -0
- package/dist/proxy/route-auto-detection.js.map +1 -0
- package/dist/proxy/route-proxy.d.ts +36 -0
- package/dist/proxy/route-proxy.d.ts.map +1 -0
- package/dist/proxy/route-proxy.js +103 -0
- package/dist/proxy/route-proxy.js.map +1 -0
- package/dist/server/context.d.ts +30 -0
- package/dist/server/context.d.ts.map +1 -0
- package/dist/server/context.js +106 -0
- package/dist/server/context.js.map +1 -0
- package/dist/server/handlers/auth.handler.d.ts +10 -0
- package/dist/server/handlers/auth.handler.d.ts.map +1 -0
- package/dist/server/handlers/auth.handler.js +29 -0
- package/dist/server/handlers/auth.handler.js.map +1 -0
- package/dist/server/handlers/captions.handler.d.ts +10 -0
- package/dist/server/handlers/captions.handler.d.ts.map +1 -0
- package/dist/server/handlers/captions.handler.js +33 -0
- package/dist/server/handlers/captions.handler.js.map +1 -0
- package/dist/server/handlers/collection.handler.d.ts +36 -0
- package/dist/server/handlers/collection.handler.d.ts.map +1 -0
- package/dist/server/handlers/collection.handler.js +166 -0
- package/dist/server/handlers/collection.handler.js.map +1 -0
- package/dist/server/handlers/error-response.js +24 -0
- package/dist/server/handlers/error-response.js.map +1 -0
- package/dist/server/handlers/index.handler.d.ts +9 -0
- package/dist/server/handlers/index.handler.d.ts.map +1 -0
- package/dist/server/handlers/index.handler.js +145 -0
- package/dist/server/handlers/index.handler.js.map +1 -0
- package/dist/server/handlers/preview.handler.d.ts +9 -0
- package/dist/server/handlers/preview.handler.d.ts.map +1 -0
- package/dist/server/handlers/preview.handler.js +15 -0
- package/dist/server/handlers/preview.handler.js.map +1 -0
- package/dist/server/handlers/registry.handler.d.ts +16 -0
- package/dist/server/handlers/registry.handler.d.ts.map +1 -0
- package/dist/server/handlers/registry.handler.js +260 -0
- package/dist/server/handlers/registry.handler.js.map +1 -0
- package/dist/server/handlers/route.handler.d.ts +20 -0
- package/dist/server/handlers/route.handler.d.ts.map +1 -0
- package/dist/server/handlers/route.handler.js +122 -0
- package/dist/server/handlers/route.handler.js.map +1 -0
- package/dist/server/handlers/sitemap.handler.d.ts +30 -0
- package/dist/server/handlers/sitemap.handler.d.ts.map +1 -0
- package/dist/server/handlers/sitemap.handler.js +338 -0
- package/dist/server/handlers/sitemap.handler.js.map +1 -0
- package/dist/server/handlers/static-params.handler.d.ts +24 -0
- package/dist/server/handlers/static-params.handler.d.ts.map +1 -0
- package/dist/server/handlers/static-params.handler.js +56 -0
- package/dist/server/handlers/static-params.handler.js.map +1 -0
- package/dist/server/handlers/vars.handler.d.ts +10 -0
- package/dist/server/handlers/vars.handler.d.ts.map +1 -0
- package/dist/server/handlers/vars.handler.js +159 -0
- package/dist/server/handlers/vars.handler.js.map +1 -0
- package/dist/server/layout.js +88 -0
- package/dist/server/layout.js.map +1 -0
- package/dist/server/lazy.d.ts +11 -0
- package/dist/server/lazy.d.ts.map +1 -0
- package/dist/server/lazy.js +33 -0
- package/dist/server/lazy.js.map +1 -0
- package/dist/server/local-api.d.ts +9 -0
- package/dist/server/local-api.d.ts.map +1 -0
- package/dist/server/local-api.js +60 -0
- package/dist/server/local-api.js.map +1 -0
- package/dist/server/metadata.d.ts +21 -0
- package/dist/server/metadata.d.ts.map +1 -0
- package/dist/server/metadata.js +20 -0
- package/dist/server/metadata.js.map +1 -0
- package/dist/server/mixer-payload.d.ts +63 -0
- package/dist/server/mixer-payload.d.ts.map +1 -0
- package/dist/server/mixer.d.ts +214 -0
- package/dist/server/mixer.d.ts.map +1 -0
- package/dist/server/mixer.js +355 -0
- package/dist/server/mixer.js.map +1 -0
- package/dist/server/page.d.ts +22 -0
- package/dist/server/page.d.ts.map +1 -0
- package/dist/server/page.js +57 -0
- package/dist/server/page.js.map +1 -0
- package/dist/server/utils.d.ts +12 -0
- package/dist/server/utils.d.ts.map +1 -0
- package/dist/{utils-YwteTbk7.js → server/utils.js} +3 -3
- package/dist/server/utils.js.map +1 -0
- package/dist/server/utmz.d.ts +9 -0
- package/dist/server/utmz.d.ts.map +1 -0
- package/dist/server/utmz.js +14 -0
- package/dist/server/utmz.js.map +1 -0
- package/dist/types.d.ts +136 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/index.ts +0 -1
- package/dist/exports/client-xcFJNcG7.d.ts +0 -979
- package/dist/exports/client-xcFJNcG7.d.ts.map +0 -1
- package/dist/exports/client.js.map +0 -1
- package/dist/exports/instrumentation-DBO6QH4d.d.ts.map +0 -1
- package/dist/exports/instrumentation.js.map +0 -1
- package/dist/exports/proxy-Cv7QFVci.d.ts +0 -71
- package/dist/exports/proxy-Cv7QFVci.d.ts.map +0 -1
- package/dist/exports/proxy.js.map +0 -1
- package/dist/exports/server-BHObJHJ6.d.ts +0 -402
- package/dist/exports/server-BHObJHJ6.d.ts.map +0 -1
- package/dist/exports/server.js.map +0 -1
- package/dist/http-_2M-UFRx.js.map +0 -1
- package/dist/index-CdYcvudT.d.ts +0 -4
- package/dist/index-CtfAJ0y7.d.ts +0 -499
- package/dist/index-CtfAJ0y7.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/route-DzFwERQP.js.map +0 -1
- package/dist/store-CJzqrHsl.js.map +0 -1
- package/dist/types-BatUTdbZ.d.ts.map +0 -1
- package/dist/types-D29_snYY.d.ts +0 -191
- package/dist/types-D29_snYY.d.ts.map +0 -1
- package/dist/utils-Ca7xh5mm.js +0 -78
- package/dist/utils-Ca7xh5mm.js.map +0 -1
- package/dist/utils-YwteTbk7.js.map +0 -1
- /package/dist/{config.client-B8As5DY0.js → instrumentation/sentry/config.client.js} +0 -0
- /package/dist/{config.edge-B8As5DY0.js → instrumentation/sentry/config.edge.js} +0 -0
- /package/dist/{config.server-B8As5DY0.js → instrumentation/sentry/config.server.js} +0 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { readFile, readdir, stat } from "node:fs/promises";
|
|
2
|
+
import { basename, dirname, extname, join, relative, resolve } from "node:path";
|
|
3
|
+
//#region src/server/handlers/registry.handler.ts
|
|
4
|
+
const REGISTRY_SCHEMA = "https://ui.shadcn.com/schema/registry.json";
|
|
5
|
+
const REGISTRY_ITEM_SCHEMA = "https://ui.shadcn.com/schema/registry-item.json";
|
|
6
|
+
const SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
7
|
+
".css",
|
|
8
|
+
".json",
|
|
9
|
+
".ts",
|
|
10
|
+
".tsx"
|
|
11
|
+
]);
|
|
12
|
+
const PUBLISHED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
13
|
+
"components",
|
|
14
|
+
"examples",
|
|
15
|
+
"hooks",
|
|
16
|
+
"lazy",
|
|
17
|
+
"lib",
|
|
18
|
+
"sections",
|
|
19
|
+
"theme"
|
|
20
|
+
]);
|
|
21
|
+
const SHADCN_COMPONENTS = /* @__PURE__ */ new Set([
|
|
22
|
+
"accordion",
|
|
23
|
+
"alert-dialog",
|
|
24
|
+
"alert",
|
|
25
|
+
"aspect-ratio",
|
|
26
|
+
"avatar",
|
|
27
|
+
"badge",
|
|
28
|
+
"breadcrumb",
|
|
29
|
+
"calendar",
|
|
30
|
+
"card",
|
|
31
|
+
"carousel",
|
|
32
|
+
"chart",
|
|
33
|
+
"checkbox",
|
|
34
|
+
"collapsible",
|
|
35
|
+
"combobox",
|
|
36
|
+
"command",
|
|
37
|
+
"context-menu",
|
|
38
|
+
"dialog",
|
|
39
|
+
"drawer",
|
|
40
|
+
"dropdown-menu",
|
|
41
|
+
"form",
|
|
42
|
+
"hover-card",
|
|
43
|
+
"input",
|
|
44
|
+
"input-otp",
|
|
45
|
+
"label",
|
|
46
|
+
"menubar",
|
|
47
|
+
"navigation-menu",
|
|
48
|
+
"pagination",
|
|
49
|
+
"popover",
|
|
50
|
+
"progress",
|
|
51
|
+
"radio-group",
|
|
52
|
+
"resizable",
|
|
53
|
+
"scroll-area",
|
|
54
|
+
"select",
|
|
55
|
+
"separator",
|
|
56
|
+
"sheet",
|
|
57
|
+
"sidebar",
|
|
58
|
+
"skeleton",
|
|
59
|
+
"slider",
|
|
60
|
+
"sonner",
|
|
61
|
+
"switch",
|
|
62
|
+
"table",
|
|
63
|
+
"tabs",
|
|
64
|
+
"textarea",
|
|
65
|
+
"toast",
|
|
66
|
+
"toggle",
|
|
67
|
+
"toggle-group",
|
|
68
|
+
"tooltip"
|
|
69
|
+
]);
|
|
70
|
+
function toKebabCase(value) {
|
|
71
|
+
return value.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[._\s]+/g, "-").toLowerCase();
|
|
72
|
+
}
|
|
73
|
+
function titleFromName(name) {
|
|
74
|
+
return name.replace(/(^|[-_])(\w)/g, (_, __, character) => character.toUpperCase());
|
|
75
|
+
}
|
|
76
|
+
function packageName(specifier) {
|
|
77
|
+
return specifier.startsWith("@") ? specifier.split("/").slice(0, 2).join("/") : specifier.split("/")[0];
|
|
78
|
+
}
|
|
79
|
+
function getOrigin(request) {
|
|
80
|
+
return process.env.NEXT_PUBLIC_URL?.replace(/\/$/, "") || request.nextUrl.origin;
|
|
81
|
+
}
|
|
82
|
+
async function directoryExists(directory) {
|
|
83
|
+
try {
|
|
84
|
+
return (await stat(directory)).isDirectory();
|
|
85
|
+
} catch {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async function getUiSourceDirectory() {
|
|
90
|
+
if (process.env.UI_REGISTRY_SOURCE_DIR) {
|
|
91
|
+
const configuredPath = resolve(process.env.UI_REGISTRY_SOURCE_DIR);
|
|
92
|
+
if (await directoryExists(configuredPath)) return configuredPath;
|
|
93
|
+
throw new Error(`UI_REGISTRY_SOURCE_DIR does not exist: ${configuredPath}`);
|
|
94
|
+
}
|
|
95
|
+
let currentDirectory = process.cwd();
|
|
96
|
+
while (dirname(currentDirectory) !== currentDirectory) {
|
|
97
|
+
const candidate = join(currentDirectory, "packages", "ui", "src");
|
|
98
|
+
if (await directoryExists(candidate)) return candidate;
|
|
99
|
+
currentDirectory = dirname(currentDirectory);
|
|
100
|
+
}
|
|
101
|
+
throw new Error("Unable to find packages/ui/src. Set UI_REGISTRY_SOURCE_DIR to its absolute path.");
|
|
102
|
+
}
|
|
103
|
+
async function getSourceFiles(directory, sourceDirectory = directory) {
|
|
104
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
105
|
+
return (await Promise.all(entries.map(async (entry) => {
|
|
106
|
+
const absolutePath = join(directory, entry.name);
|
|
107
|
+
if (entry.isDirectory()) return getSourceFiles(absolutePath, sourceDirectory);
|
|
108
|
+
if (!SOURCE_EXTENSIONS.has(extname(entry.name)) || entry.name.endsWith(".d.ts") || /\.(test|spec)\.[^.]+$/.test(entry.name)) return [];
|
|
109
|
+
return [{
|
|
110
|
+
absolutePath,
|
|
111
|
+
relativePath: entry.name
|
|
112
|
+
}];
|
|
113
|
+
}))).flat().map((file) => ({
|
|
114
|
+
...file,
|
|
115
|
+
relativePath: relative(sourceDirectory, file.absolutePath).replaceAll("\\", "/")
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
function getImportSpecifiers(source) {
|
|
119
|
+
return [...source.matchAll(/(?:import|export)\s+(?:type\s+)?(?:[\s\S]*?\s+from\s+)?['"]([^'"]+)['"]/g)].map((match) => match[1]);
|
|
120
|
+
}
|
|
121
|
+
function resolveSourceImport(sourceDirectory, sourceFile, specifier, sourceFiles) {
|
|
122
|
+
let candidate;
|
|
123
|
+
if (specifier.startsWith("@app/ui/")) candidate = specifier.slice(8);
|
|
124
|
+
if (specifier.startsWith(".")) candidate = relative(sourceDirectory, resolve(dirname(sourceFile), specifier)).replaceAll("\\", "/");
|
|
125
|
+
if (!candidate) return void 0;
|
|
126
|
+
const normalizedCandidate = candidate.replace(/^\.\//, "");
|
|
127
|
+
return sourceFiles.get(normalizedCandidate) || sourceFiles.get(`${normalizedCandidate}.ts`) || sourceFiles.get(`${normalizedCandidate}.tsx`) || sourceFiles.get(`${normalizedCandidate}/index.ts`) || sourceFiles.get(`${normalizedCandidate}/index.tsx`);
|
|
128
|
+
}
|
|
129
|
+
function rewriteUiImports(source, sourceFile, sourceDirectory, sourceFiles) {
|
|
130
|
+
return source.replace(/(['"])(@app\/ui\/[^'"]+|\.\.?\/[^'"]+)\1/g, (match, quote, specifier) => {
|
|
131
|
+
const importedFile = resolveSourceImport(sourceDirectory, sourceFile.absolutePath, specifier, sourceFiles);
|
|
132
|
+
return importedFile ? `${quote}${getImportPath(importedFile.relativePath)}${quote}` : match;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
function getImportPath(relativePath) {
|
|
136
|
+
const extensionlessPath = relativePath.replace(/\.(tsx?|mts|cts)$/, "");
|
|
137
|
+
if (extensionlessPath.startsWith("components/")) return `@/components/ui/${extensionlessPath.slice(11)}`;
|
|
138
|
+
if (extensionlessPath.startsWith("hooks/")) return `@/hooks/${extensionlessPath.slice(6)}`;
|
|
139
|
+
if (extensionlessPath.startsWith("lib/")) return `@/lib/${extensionlessPath.slice(4)}`;
|
|
140
|
+
return `@/components/${extensionlessPath}`;
|
|
141
|
+
}
|
|
142
|
+
function getTargetPath(relativePath) {
|
|
143
|
+
if (relativePath.startsWith("components/")) return `@ui/${relativePath.slice(11)}`;
|
|
144
|
+
if (relativePath.startsWith("hooks/")) return `@hooks/${relativePath.slice(6)}`;
|
|
145
|
+
if (relativePath.startsWith("lib/")) return `@lib/${relativePath.slice(4)}`;
|
|
146
|
+
return `@components/${relativePath}`;
|
|
147
|
+
}
|
|
148
|
+
function getRegistryFileType(relativePath) {
|
|
149
|
+
if (relativePath.startsWith("components/")) return "registry:ui";
|
|
150
|
+
if (relativePath.startsWith("hooks/")) return "registry:hook";
|
|
151
|
+
if (relativePath.startsWith("theme/")) return "registry:style";
|
|
152
|
+
if (extname(relativePath) === ".json") return "registry:file";
|
|
153
|
+
return "registry:lib";
|
|
154
|
+
}
|
|
155
|
+
function isPublishedFile(file) {
|
|
156
|
+
const [directory] = file.relativePath.split("/");
|
|
157
|
+
return PUBLISHED_DIRECTORIES.has(directory) && !/(^|\/)index\.[^.]+$/.test(file.relativePath);
|
|
158
|
+
}
|
|
159
|
+
function getRegistryItemName(file) {
|
|
160
|
+
const [directory, ...path] = file.relativePath.split("/");
|
|
161
|
+
const name = toKebabCase(path.join("/").replace(extname(file.relativePath), "").replaceAll("/", "-"));
|
|
162
|
+
return directory === "components" ? name : `${directory}-${name}`;
|
|
163
|
+
}
|
|
164
|
+
async function createRegistryCatalog(sourceDirectory, origin) {
|
|
165
|
+
const files = (await getSourceFiles(sourceDirectory)).filter((file) => PUBLISHED_DIRECTORIES.has(file.relativePath.split("/")[0]));
|
|
166
|
+
const filesByRelativePath = new Map(files.map((file) => [file.relativePath, file]));
|
|
167
|
+
const entries = new Map(files.filter(isPublishedFile).map((file) => [getRegistryItemName(file), file]));
|
|
168
|
+
const entryNamesByPath = new Map([...entries].map(([name, file]) => [file.relativePath, name]));
|
|
169
|
+
const includedItems = new Set([...entries].filter(([name, file]) => !file.relativePath.startsWith("components/") || name === "button" || !SHADCN_COMPONENTS.has(name)).map(([name]) => name));
|
|
170
|
+
async function getItem(name) {
|
|
171
|
+
const entry = entries.get(name);
|
|
172
|
+
if (!entry || !includedItems.has(name)) return void 0;
|
|
173
|
+
const filesToInclude = /* @__PURE__ */ new Map();
|
|
174
|
+
const externalDependencies = /* @__PURE__ */ new Set();
|
|
175
|
+
const registryDependencies = /* @__PURE__ */ new Set();
|
|
176
|
+
const pendingFiles = [entry];
|
|
177
|
+
while (pendingFiles.length) {
|
|
178
|
+
const file = pendingFiles.pop();
|
|
179
|
+
if (filesToInclude.has(file.relativePath)) continue;
|
|
180
|
+
filesToInclude.set(file.relativePath, file);
|
|
181
|
+
const source = await readFile(file.absolutePath, "utf8");
|
|
182
|
+
for (const specifier of getImportSpecifiers(source)) {
|
|
183
|
+
const localFile = resolveSourceImport(sourceDirectory, file.absolutePath, specifier, filesByRelativePath);
|
|
184
|
+
const dependencyName = localFile && entryNamesByPath.get(localFile.relativePath);
|
|
185
|
+
if (localFile?.relativePath.startsWith("components/")) {
|
|
186
|
+
const componentName = toKebabCase(basename(localFile.relativePath, extname(localFile.relativePath)));
|
|
187
|
+
if (dependencyName !== name) registryDependencies.add(includedItems.has(componentName) ? `${origin}/r/${componentName}.json` : componentName);
|
|
188
|
+
} else if (localFile && dependencyName && dependencyName !== name && includedItems.has(dependencyName)) registryDependencies.add(`${origin}/r/${dependencyName}.json`);
|
|
189
|
+
else if (localFile) pendingFiles.push(localFile);
|
|
190
|
+
else if (!specifier.startsWith(".") && !specifier.startsWith("@app/ui/") && !specifier.startsWith("node:") && specifier !== "react" && specifier !== "react-dom") externalDependencies.add(packageName(specifier));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const registryFiles = await Promise.all([...filesToInclude.values()].sort((left, right) => left.relativePath.localeCompare(right.relativePath)).map(async (file) => ({
|
|
194
|
+
path: file.relativePath,
|
|
195
|
+
content: rewriteUiImports(await readFile(file.absolutePath, "utf8"), file, sourceDirectory, filesByRelativePath),
|
|
196
|
+
type: getRegistryFileType(file.relativePath),
|
|
197
|
+
target: getTargetPath(file.relativePath)
|
|
198
|
+
})));
|
|
199
|
+
return {
|
|
200
|
+
$schema: REGISTRY_ITEM_SCHEMA,
|
|
201
|
+
name,
|
|
202
|
+
type: "registry:ui",
|
|
203
|
+
title: titleFromName(name),
|
|
204
|
+
...externalDependencies.size && { dependencies: [...externalDependencies].sort() },
|
|
205
|
+
...registryDependencies.size && { registryDependencies: [...registryDependencies].sort() },
|
|
206
|
+
files: registryFiles
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
async function getCatalogItem(name) {
|
|
210
|
+
const item = await getItem(name);
|
|
211
|
+
if (!item) return void 0;
|
|
212
|
+
return {
|
|
213
|
+
...item,
|
|
214
|
+
files: item.files.map((file) => ({
|
|
215
|
+
path: file.path,
|
|
216
|
+
type: file.type,
|
|
217
|
+
target: file.target
|
|
218
|
+
}))
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
items: includedItems,
|
|
223
|
+
getCatalogItem,
|
|
224
|
+
getItem
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
function jsonResponse(body, status = 200) {
|
|
228
|
+
return Response.json(body, {
|
|
229
|
+
status,
|
|
230
|
+
headers: {
|
|
231
|
+
"X-Frame-Options": "SAMEORIGIN",
|
|
232
|
+
"X-Robots-Tag": "noindex, follow"
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
function getRegistry() {
|
|
237
|
+
return async function(request) {
|
|
238
|
+
const catalog = await createRegistryCatalog(await getUiSourceDirectory(), getOrigin(request));
|
|
239
|
+
const items = (await Promise.all([...catalog.items].sort().map((name) => catalog.getCatalogItem(name)))).filter(Boolean);
|
|
240
|
+
return jsonResponse({
|
|
241
|
+
$schema: REGISTRY_SCHEMA,
|
|
242
|
+
name: "bom-ui",
|
|
243
|
+
homepage: getOrigin(request),
|
|
244
|
+
items
|
|
245
|
+
});
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function getRegistryItem() {
|
|
249
|
+
return async function(request, { params: getParams }) {
|
|
250
|
+
const { slug } = await getParams;
|
|
251
|
+
const name = slug.at(-1)?.replace(/\.json$/, "");
|
|
252
|
+
if (!name) return jsonResponse({ error: "Registry item name is required." }, 404);
|
|
253
|
+
const item = await (await createRegistryCatalog(await getUiSourceDirectory(), getOrigin(request))).getItem(name);
|
|
254
|
+
return item ? jsonResponse(item) : jsonResponse({ error: `Registry item not found: ${name}` }, 404);
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
//#endregion
|
|
258
|
+
export { getRegistry, getRegistryItem };
|
|
259
|
+
|
|
260
|
+
//# sourceMappingURL=registry.handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.handler.js","names":[],"sources":["../../../src/server/handlers/registry.handler.ts"],"sourcesContent":["import { NextRequest } from 'next/server';\r\nimport { readdir, readFile, stat } from 'node:fs/promises';\r\nimport { basename, dirname, extname, join, relative, resolve } from 'node:path';\r\n\r\nconst REGISTRY_SCHEMA = 'https://ui.shadcn.com/schema/registry.json';\r\nconst REGISTRY_ITEM_SCHEMA = 'https://ui.shadcn.com/schema/registry-item.json';\r\nconst SOURCE_EXTENSIONS = new Set(['.css', '.json', '.ts', '.tsx']);\r\nconst PUBLISHED_DIRECTORIES = new Set(['components', 'examples', 'hooks', 'lazy', 'lib', 'sections', 'theme']);\r\nconst SHADCN_COMPONENTS = new Set([\r\n 'accordion', 'alert-dialog', 'alert', 'aspect-ratio', 'avatar', 'badge', 'breadcrumb', 'calendar', 'card',\r\n 'carousel', 'chart', 'checkbox', 'collapsible', 'combobox', 'command', 'context-menu', 'dialog', 'drawer',\r\n 'dropdown-menu', 'form', 'hover-card', 'input', 'input-otp', 'label', 'menubar', 'navigation-menu',\r\n 'pagination', 'popover', 'progress', 'radio-group', 'resizable', 'scroll-area', 'select', 'separator', 'sheet',\r\n 'sidebar', 'skeleton', 'slider', 'sonner', 'switch', 'table', 'tabs', 'textarea', 'toast', 'toggle',\r\n 'toggle-group', 'tooltip',\r\n]);\r\n\r\ntype RegistryFile = {\r\n path: string;\r\n content: string;\r\n type: 'registry:ui' | 'registry:lib' | 'registry:hook' | 'registry:style' | 'registry:file';\r\n target: string;\r\n};\r\n\r\ntype RegistryCatalogFile = Omit<RegistryFile, 'content'>;\r\n\r\ntype RegistryItem = {\r\n $schema: typeof REGISTRY_ITEM_SCHEMA;\r\n name: string;\r\n type: 'registry:ui';\r\n title: string;\r\n dependencies?: string[];\r\n registryDependencies?: string[];\r\n files: RegistryFile[];\r\n};\r\n\r\ntype RegistryCatalogItem = Omit<RegistryItem, 'files'> & {\r\n files: RegistryCatalogFile[];\r\n};\r\n\r\ntype SourceFile = { absolutePath: string; relativePath: string };\r\n\r\nfunction toKebabCase(value: string) {\r\n return value.replace(/([a-z0-9])([A-Z])/g, '$1-$2').replace(/[._\\s]+/g, '-').toLowerCase();\r\n}\r\n\r\nfunction titleFromName(name: string) {\r\n return name.replace(/(^|[-_])(\\w)/g, (_, __, character: string) => character.toUpperCase());\r\n}\r\n\r\nfunction packageName(specifier: string) {\r\n return specifier.startsWith('@') ? specifier.split('/').slice(0, 2).join('/') : specifier.split('/')[0];\r\n}\r\n\r\nfunction getOrigin(request: NextRequest) {\r\n return process.env.NEXT_PUBLIC_URL?.replace(/\\/$/, '') || request.nextUrl.origin;\r\n}\r\n\r\nasync function directoryExists(directory: string) {\r\n try {\r\n return (await stat(directory)).isDirectory();\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nasync function getUiSourceDirectory() {\r\n if (process.env.UI_REGISTRY_SOURCE_DIR) {\r\n const configuredPath = resolve(process.env.UI_REGISTRY_SOURCE_DIR);\r\n if (await directoryExists(configuredPath)) return configuredPath;\r\n throw new Error(`UI_REGISTRY_SOURCE_DIR does not exist: ${configuredPath}`);\r\n }\r\n\r\n let currentDirectory = process.cwd();\r\n while (dirname(currentDirectory) !== currentDirectory) {\r\n const candidate = join(currentDirectory, 'packages', 'ui', 'src');\r\n if (await directoryExists(candidate)) return candidate;\r\n currentDirectory = dirname(currentDirectory);\r\n }\r\n throw new Error('Unable to find packages/ui/src. Set UI_REGISTRY_SOURCE_DIR to its absolute path.');\r\n}\r\n\r\nasync function getSourceFiles(directory: string, sourceDirectory = directory): Promise<SourceFile[]> {\r\n const entries = await readdir(directory, { withFileTypes: true });\r\n const files = await Promise.all(entries.map(async entry => {\r\n const absolutePath = join(directory, entry.name);\r\n if (entry.isDirectory()) return getSourceFiles(absolutePath, sourceDirectory);\r\n if (!SOURCE_EXTENSIONS.has(extname(entry.name)) || entry.name.endsWith('.d.ts') || /\\.(test|spec)\\.[^.]+$/.test(entry.name)) return [];\r\n return [{ absolutePath, relativePath: entry.name }];\r\n }));\r\n\r\n return files.flat().map(file => ({\r\n ...file,\r\n relativePath: relative(sourceDirectory, file.absolutePath).replaceAll('\\\\', '/'),\r\n }));\r\n}\r\n\r\nfunction getImportSpecifiers(source: string) {\r\n return [...source.matchAll(/(?:import|export)\\s+(?:type\\s+)?(?:[\\s\\S]*?\\s+from\\s+)?['\"]([^'\"]+)['\"]/g)]\r\n .map(match => match[1]);\r\n}\r\n\r\nfunction resolveSourceImport(sourceDirectory: string, sourceFile: string, specifier: string, sourceFiles: Map<string, SourceFile>) {\r\n let candidate: string | undefined;\r\n if (specifier.startsWith('@app/ui/')) candidate = specifier.slice('@app/ui/'.length);\r\n if (specifier.startsWith('.')) candidate = relative(sourceDirectory, resolve(dirname(sourceFile), specifier)).replaceAll('\\\\', '/');\r\n if (!candidate) return undefined;\r\n\r\n const normalizedCandidate = candidate.replace(/^\\.\\//, '');\r\n return sourceFiles.get(normalizedCandidate) ||\r\n sourceFiles.get(`${normalizedCandidate}.ts`) || sourceFiles.get(`${normalizedCandidate}.tsx`) ||\r\n sourceFiles.get(`${normalizedCandidate}/index.ts`) || sourceFiles.get(`${normalizedCandidate}/index.tsx`);\r\n}\r\n\r\nfunction rewriteUiImports(source: string, sourceFile: SourceFile, sourceDirectory: string, sourceFiles: Map<string, SourceFile>) {\r\n return source.replace(/(['\"])(@app\\/ui\\/[^'\"]+|\\.\\.?\\/[^'\"]+)\\1/g, (match, quote: string, specifier: string) => {\r\n const importedFile = resolveSourceImport(sourceDirectory, sourceFile.absolutePath, specifier, sourceFiles);\r\n return importedFile ? `${quote}${getImportPath(importedFile.relativePath)}${quote}` : match;\r\n });\r\n}\r\n\r\nfunction getImportPath(relativePath: string) {\r\n const extensionlessPath = relativePath.replace(/\\.(tsx?|mts|cts)$/, '');\r\n if (extensionlessPath.startsWith('components/')) return `@/components/ui/${extensionlessPath.slice('components/'.length)}`;\r\n if (extensionlessPath.startsWith('hooks/')) return `@/hooks/${extensionlessPath.slice('hooks/'.length)}`;\r\n if (extensionlessPath.startsWith('lib/')) return `@/lib/${extensionlessPath.slice('lib/'.length)}`;\r\n return `@/components/${extensionlessPath}`;\r\n}\r\n\r\nfunction getTargetPath(relativePath: string) {\r\n if (relativePath.startsWith('components/')) return `@ui/${relativePath.slice('components/'.length)}`;\r\n if (relativePath.startsWith('hooks/')) return `@hooks/${relativePath.slice('hooks/'.length)}`;\r\n if (relativePath.startsWith('lib/')) return `@lib/${relativePath.slice('lib/'.length)}`;\r\n return `@components/${relativePath}`;\r\n}\r\n\r\nfunction getRegistryFileType(relativePath: string): RegistryFile['type'] {\r\n if (relativePath.startsWith('components/')) return 'registry:ui';\r\n if (relativePath.startsWith('hooks/')) return 'registry:hook';\r\n if (relativePath.startsWith('theme/')) return 'registry:style';\r\n if (extname(relativePath) === '.json') return 'registry:file';\r\n return 'registry:lib';\r\n}\r\n\r\nfunction isPublishedFile(file: SourceFile) {\r\n const [directory] = file.relativePath.split('/');\r\n return PUBLISHED_DIRECTORIES.has(directory) && !/(^|\\/)index\\.[^.]+$/.test(file.relativePath);\r\n}\r\n\r\nfunction getRegistryItemName(file: SourceFile) {\r\n const [directory, ...path] = file.relativePath.split('/');\r\n const filename = path.join('/').replace(extname(file.relativePath), '');\r\n const name = toKebabCase(filename.replaceAll('/', '-'));\r\n return directory === 'components' ? name : `${directory}-${name}`;\r\n}\r\n\r\nasync function createRegistryCatalog(sourceDirectory: string, origin: string) {\r\n const files = (await getSourceFiles(sourceDirectory)).filter(file => PUBLISHED_DIRECTORIES.has(file.relativePath.split('/')[0]));\r\n const filesByRelativePath = new Map(files.map(file => [file.relativePath, file]));\r\n const entries = new Map(files.filter(isPublishedFile).map(file => [getRegistryItemName(file), file]));\r\n const entryNamesByPath = new Map([...entries].map(([name, file]) => [file.relativePath, name]));\r\n const includedItems = new Set([...entries].filter(([name, file]) =>\r\n !file.relativePath.startsWith('components/') || name === 'button' || !SHADCN_COMPONENTS.has(name)\r\n ).map(([name]) => name));\r\n\r\n async function getItem(name: string): Promise<RegistryItem | undefined> {\r\n const entry = entries.get(name);\r\n if (!entry || !includedItems.has(name)) return undefined;\r\n\r\n const filesToInclude = new Map<string, SourceFile>();\r\n const externalDependencies = new Set<string>();\r\n const registryDependencies = new Set<string>();\r\n const pendingFiles = [entry];\r\n\r\n while (pendingFiles.length) {\r\n const file = pendingFiles.pop()!;\r\n if (filesToInclude.has(file.relativePath)) continue;\r\n filesToInclude.set(file.relativePath, file);\r\n const source = await readFile(file.absolutePath, 'utf8');\r\n\r\n for (const specifier of getImportSpecifiers(source)) {\r\n const localFile = resolveSourceImport(sourceDirectory, file.absolutePath, specifier, filesByRelativePath);\r\n const dependencyName = localFile && entryNamesByPath.get(localFile.relativePath);\r\n if (localFile?.relativePath.startsWith('components/')) {\r\n const componentName = toKebabCase(basename(localFile.relativePath, extname(localFile.relativePath)));\r\n if (dependencyName !== name) {\r\n registryDependencies.add(includedItems.has(componentName) ? `${origin}/r/${componentName}.json` : componentName);\r\n }\r\n } else if (localFile && dependencyName && dependencyName !== name && includedItems.has(dependencyName)) {\r\n registryDependencies.add(`${origin}/r/${dependencyName}.json`);\r\n } else if (localFile) {\r\n pendingFiles.push(localFile);\r\n } else if (!specifier.startsWith('.') && !specifier.startsWith('@app/ui/') && !specifier.startsWith('node:') && specifier !== 'react' && specifier !== 'react-dom') {\r\n externalDependencies.add(packageName(specifier));\r\n }\r\n }\r\n }\r\n\r\n const registryFiles = await Promise.all([...filesToInclude.values()].sort((left, right) => left.relativePath.localeCompare(right.relativePath)).map(async file => ({\r\n path: file.relativePath,\r\n content: rewriteUiImports(await readFile(file.absolutePath, 'utf8'), file, sourceDirectory, filesByRelativePath),\r\n type: getRegistryFileType(file.relativePath),\r\n target: getTargetPath(file.relativePath),\r\n })));\r\n\r\n return {\r\n $schema: REGISTRY_ITEM_SCHEMA,\r\n name,\r\n type: 'registry:ui',\r\n title: titleFromName(name),\r\n ...(externalDependencies.size && { dependencies: [...externalDependencies].sort() }),\r\n ...(registryDependencies.size && { registryDependencies: [...registryDependencies].sort() }),\r\n files: registryFiles,\r\n };\r\n }\r\n\r\n async function getCatalogItem(name: string): Promise<RegistryCatalogItem | undefined> {\r\n const item = await getItem(name);\r\n if (!item) return undefined;\r\n return {\r\n ...item,\r\n files: item.files.map(file => ({\r\n path: file.path,\r\n type: file.type,\r\n target: file.target,\r\n })),\r\n };\r\n }\r\n\r\n return { items: includedItems, getCatalogItem, getItem };\r\n}\r\n\r\nfunction jsonResponse(body: unknown, status = 200) {\r\n return Response.json(body, {\r\n status,\r\n headers: { 'X-Frame-Options': 'SAMEORIGIN', 'X-Robots-Tag': 'noindex, follow' },\r\n });\r\n}\r\n\r\nexport function getRegistry() {\r\n return async function (request: NextRequest) {\r\n const sourceDirectory = await getUiSourceDirectory();\r\n const catalog = await createRegistryCatalog(sourceDirectory, getOrigin(request));\r\n const items = (await Promise.all([...catalog.items].sort().map(name => catalog.getCatalogItem(name)))).filter(Boolean);\r\n return jsonResponse({ $schema: REGISTRY_SCHEMA, name: 'bom-ui', homepage: getOrigin(request), items });\r\n };\r\n}\r\n\r\nexport function getRegistryItem() {\r\n return async function (request: NextRequest, { params: getParams }: { params: Promise<{ slug: string[] }> }) {\r\n const { slug } = await getParams;\r\n const name = slug.at(-1)?.replace(/\\.json$/, '');\r\n if (!name) return jsonResponse({ error: 'Registry item name is required.' }, 404);\r\n\r\n const sourceDirectory = await getUiSourceDirectory();\r\n const item = await (await createRegistryCatalog(sourceDirectory, getOrigin(request))).getItem(name);\r\n return item ? jsonResponse(item) : jsonResponse({ error: `Registry item not found: ${name}` }, 404);\r\n };\r\n}\r\n"],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { NextRequest } from "next/server";
|
|
2
|
+
import { SanitizedConfig } from "payload";
|
|
3
|
+
|
|
4
|
+
//#region src/server/handlers/route.handler.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Creates the internal `/-route` GET handler used by middleware to resolve CMS
|
|
8
|
+
* paths, route schemas, and redirects before a page is rendered.
|
|
9
|
+
*
|
|
10
|
+
* One Payload request is created per incoming API request so authentication and
|
|
11
|
+
* query context are shared by every route operation. The route service then
|
|
12
|
+
* reuses its snapshot cache, which avoids rebuilding the complete route graph
|
|
13
|
+
* for repeated market, locale, and access contexts.
|
|
14
|
+
*/
|
|
15
|
+
declare function getRouteHandler(config: Promise<SanitizedConfig>): (request: NextRequest) => Promise<Response>;
|
|
16
|
+
//# sourceMappingURL=route.handler.d.ts.map
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
19
|
+
export { getRouteHandler };
|
|
20
|
+
//# sourceMappingURL=route.handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route.handler.d.ts","names":[],"sources":["../../../src/server/handlers/route.handler.ts"],"mappings":";;;;;;;AAkBA;AAA+B;AAAiB;AAAR;AACN;AAAW;AAAA;AAAA,iBAD7B,eAAA,CAC6B,MAAA,EADL,OACK,CADG,eACH,CAAA,CAAA,EAAA,CAAA,OAAA,EAAX,WAAW,EAAA,GAAA,OAAA,CAAA,QAAA,CAAA"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { guest } from "../../lib/const.js";
|
|
2
|
+
import { sanitizeHref, sanitizeRedirectFrom, sanitizeRedirectTo, sanitizeRedirectUrl } from "../../lib/utils.js";
|
|
3
|
+
import { getHandlerErrorResponse } from "./error-response.js";
|
|
4
|
+
import { qsDeserialize } from "@websolutespa/bom-core";
|
|
5
|
+
import { getRouteSnapshot, getRoutes, sortCollection, whereCollection } from "@websolutespa/payload-plugin-bowl";
|
|
6
|
+
import { createPayloadRequest, getPayload } from "payload";
|
|
7
|
+
import { ResponseNotFound, ResponseSuccess } from "@websolutespa/payload-utils/server";
|
|
8
|
+
//#region src/server/handlers/route.handler.ts
|
|
9
|
+
/**
|
|
10
|
+
* Creates the internal `/-route` GET handler used by middleware to resolve CMS
|
|
11
|
+
* paths, route schemas, and redirects before a page is rendered.
|
|
12
|
+
*
|
|
13
|
+
* One Payload request is created per incoming API request so authentication and
|
|
14
|
+
* query context are shared by every route operation. The route service then
|
|
15
|
+
* reuses its snapshot cache, which avoids rebuilding the complete route graph
|
|
16
|
+
* for repeated market, locale, and access contexts.
|
|
17
|
+
*/
|
|
18
|
+
function getRouteHandler(config) {
|
|
19
|
+
return async function(request) {
|
|
20
|
+
try {
|
|
21
|
+
const searchParams = request.nextUrl.searchParams;
|
|
22
|
+
const pathname = searchParams.get("pathname") || void 0;
|
|
23
|
+
const href = searchParams.get("href") || void 0;
|
|
24
|
+
const hrefBeforeRedirect = searchParams.get("hrefBeforeRedirect") || void 0;
|
|
25
|
+
const schema = searchParams.get("schema") || void 0;
|
|
26
|
+
const market = searchParams.get("market") || void 0;
|
|
27
|
+
const locale = searchParams.get("locale") || void 0;
|
|
28
|
+
const payload = await getPayload({ config });
|
|
29
|
+
const req = await createPayloadRequest({
|
|
30
|
+
config,
|
|
31
|
+
request
|
|
32
|
+
});
|
|
33
|
+
req.payload = payload;
|
|
34
|
+
req.user = guest;
|
|
35
|
+
if (schema && market && locale) {
|
|
36
|
+
req.query = {
|
|
37
|
+
locale,
|
|
38
|
+
market
|
|
39
|
+
};
|
|
40
|
+
const route = (await getRouteSnapshot(req)).getSchema(schema, market, locale);
|
|
41
|
+
return route ? ResponseSuccess({ route }) : ResponseNotFound();
|
|
42
|
+
}
|
|
43
|
+
if (pathname && href) {
|
|
44
|
+
const resolution = (await getRouteSnapshot(req)).resolve(pathname);
|
|
45
|
+
const route = resolution.route;
|
|
46
|
+
if (route !== void 0) return ResponseSuccess({
|
|
47
|
+
parent: resolution.parent,
|
|
48
|
+
route: {
|
|
49
|
+
...route,
|
|
50
|
+
...resolution.splat ? { splat: resolution.splat } : {}
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
else {
|
|
54
|
+
const url = new URL(href);
|
|
55
|
+
const urlBeforeRedirect = hrefBeforeRedirect ? new URL(hrefBeforeRedirect) : null;
|
|
56
|
+
const sanitizedHref = sanitizeHref(url, urlBeforeRedirect);
|
|
57
|
+
const { payload } = req;
|
|
58
|
+
const payloadResponse = await payload.find({
|
|
59
|
+
collection: "redirect",
|
|
60
|
+
where: { isActive: { equals: true } },
|
|
61
|
+
sort: "order",
|
|
62
|
+
depth: 0,
|
|
63
|
+
limit: 1e4,
|
|
64
|
+
pagination: false,
|
|
65
|
+
req,
|
|
66
|
+
overrideAccess: true
|
|
67
|
+
});
|
|
68
|
+
let redirects = payloadResponse.docs ? payloadResponse.docs : [];
|
|
69
|
+
redirects = redirects.map((x) => ({
|
|
70
|
+
...x,
|
|
71
|
+
from: sanitizeRedirectFrom(x.from, url, urlBeforeRedirect),
|
|
72
|
+
to: sanitizeRedirectTo(x.to)
|
|
73
|
+
}));
|
|
74
|
+
const exactMatchResolver = (redirect) => {
|
|
75
|
+
const status = parseInt(redirect.status) || 307;
|
|
76
|
+
if (status < 400) {
|
|
77
|
+
const redirectUrl = sanitizeRedirectUrl(redirect.to, url);
|
|
78
|
+
return Response.json({ redirectUrl }, { status });
|
|
79
|
+
} else return Response.json("gone", { status });
|
|
80
|
+
};
|
|
81
|
+
const exactMatchRedirect = redirects.find((x) => x.from === sanitizedHref);
|
|
82
|
+
if (exactMatchRedirect !== void 0) return exactMatchResolver(exactMatchRedirect);
|
|
83
|
+
const patternMatchResolver = (redirect) => {
|
|
84
|
+
const status = parseInt(redirect.status) || 307;
|
|
85
|
+
if (status < 400) {
|
|
86
|
+
const regexp = new RegExp(redirect.from);
|
|
87
|
+
let i = 0;
|
|
88
|
+
let redirectUrl = redirect.to.replace(/\*/g, (...rest) => {
|
|
89
|
+
return `$${++i}`;
|
|
90
|
+
});
|
|
91
|
+
redirectUrl = sanitizedHref.replace(regexp, redirectUrl);
|
|
92
|
+
return Response.json({ redirectUrl }, { status });
|
|
93
|
+
} else return Response.json("gone", { status });
|
|
94
|
+
};
|
|
95
|
+
redirects.forEach((x) => {
|
|
96
|
+
let expression = x.from;
|
|
97
|
+
expression = expression.replace(/\*(?!\))/g, "(.*)");
|
|
98
|
+
expression = `^${expression.replace(/(^\^)|(\$$)/g, "")}$`;
|
|
99
|
+
x.from = expression;
|
|
100
|
+
});
|
|
101
|
+
const firstMatch = redirects.find((x) => sanitizedHref.match(x.from));
|
|
102
|
+
if (firstMatch) return patternMatchResolver(firstMatch);
|
|
103
|
+
return ResponseSuccess({ parent: resolution.parent });
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
const query = qsDeserialize(decodeURIComponent(searchParams.toString()));
|
|
107
|
+
req.query = query;
|
|
108
|
+
const routes = await getRoutes(req);
|
|
109
|
+
let items = await whereCollection(routes, query.where);
|
|
110
|
+
items = await sortCollection(items, query.sort);
|
|
111
|
+
return ResponseSuccess(items);
|
|
112
|
+
}
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.error("routeGetHandler.error", error);
|
|
115
|
+
return getHandlerErrorResponse(error);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
//#endregion
|
|
120
|
+
export { getRouteHandler };
|
|
121
|
+
|
|
122
|
+
//# sourceMappingURL=route.handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route.handler.js","names":["getPayload_"],"sources":["../../../src/server/handlers/route.handler.ts"],"sourcesContent":["import { IRedirect, IRoute, qsDeserialize } from '@websolutespa/bom-core';\r\nimport { getRoutes, getRouteSnapshot, sortCollection, whereCollection } from '@websolutespa/payload-plugin-bowl';\r\nimport { ResponseNotFound, ResponseSuccess } from '@websolutespa/payload-utils/server';\r\nimport { NextRequest } from 'next/server';\r\nimport { createPayloadRequest, getPayload as getPayload_, PayloadRequest, SanitizedConfig } from 'payload';\r\nimport { guest } from '../../lib/const';\r\nimport { sanitizeHref, sanitizeRedirectFrom, sanitizeRedirectTo, sanitizeRedirectUrl } from '../../lib/utils';\r\nimport { getHandlerErrorResponse } from './error-response';\r\n\r\n/**\r\n * Creates the internal `/-route` GET handler used by middleware to resolve CMS\r\n * paths, route schemas, and redirects before a page is rendered.\r\n *\r\n * One Payload request is created per incoming API request so authentication and\r\n * query context are shared by every route operation. The route service then\r\n * reuses its snapshot cache, which avoids rebuilding the complete route graph\r\n * for repeated market, locale, and access contexts.\r\n */\r\nexport function getRouteHandler(config: Promise<SanitizedConfig>) {\r\n return async function (request: NextRequest) {\r\n try {\r\n const searchParams = request.nextUrl.searchParams;\r\n const pathname = searchParams.get('pathname') || undefined;\r\n const href = searchParams.get('href') || undefined;\r\n const hrefBeforeRedirect = searchParams.get('hrefBeforeRedirect') || undefined;\r\n const schema = searchParams.get('schema') || undefined;\r\n const market = searchParams.get('market') || undefined;\r\n const locale = searchParams.get('locale') || undefined;\r\n const payload = await getPayload_({ config });\r\n const req: PayloadRequest = await createPayloadRequest({\r\n config,\r\n request,\r\n });\r\n req.payload = payload;\r\n req.user = guest as never;\r\n if (schema && market && locale) {\r\n // Schema lookups are used by middleware such as login protection. They\r\n // resolve directly from the snapshot instead of enumerating routes.\r\n req.query = { locale, market };\r\n const route = (await getRouteSnapshot(req)).getSchema(schema, market, locale);\r\n return route ? ResponseSuccess({ route }) : ResponseNotFound();\r\n }\r\n // console.log('routes.length', routes.length);\r\n if (pathname && href) {\r\n // Resolve the public path first. A successful result bypasses the\r\n // redirect collection query, the costliest branch for normal traffic.\r\n const resolution = (await getRouteSnapshot(req)).resolve(pathname);\r\n /*\r\n console.log('pathname', pathname);\r\n console.log('href', href);\r\n console.log('hrefBeforeRedirect', hrefBeforeRedirect);\r\n */\r\n const route = resolution.route;\r\n // console.log('route', route, 'pathname', pathname);\r\n if (route !== undefined) {\r\n return ResponseSuccess({\r\n parent: resolution.parent,\r\n route: {\r\n ...route,\r\n ...(resolution.splat ? { splat: resolution.splat } : {}),\r\n },\r\n });\r\n } else {\r\n const url = new URL(href);\r\n const urlBeforeRedirect = hrefBeforeRedirect ? new URL(hrefBeforeRedirect) : null;\r\n const sanitizedHref = sanitizeHref(url, urlBeforeRedirect);\r\n // Query only active redirects and request depth 0 because matching\r\n // needs scalar fields only; this minimizes Payload serialization.\r\n const { payload } = req;\r\n const payloadResponse = await payload.find({\r\n collection: 'redirect',\r\n where: {\r\n isActive: {\r\n equals: true,\r\n },\r\n },\r\n sort: 'order',\r\n depth: 0,\r\n limit: 10000,\r\n pagination: false,\r\n req,\r\n overrideAccess: true,\r\n });\r\n let redirects = (payloadResponse.docs ? payloadResponse.docs : []) as unknown as IRedirect[];\r\n redirects = redirects.map(x => ({\r\n ...x,\r\n from: sanitizeRedirectFrom(x.from, url, urlBeforeRedirect),\r\n to: sanitizeRedirectTo(x.to),\r\n }));\r\n // redirects.sort((a, b) => a.order - b.order);\r\n // exact match redirect resolver\r\n const exactMatchResolver = (redirect: IRedirect) => {\r\n const status: number = parseInt(redirect.status) || 307;\r\n if (status < 400) {\r\n const redirectUrl = sanitizeRedirectUrl(redirect.to, url);\r\n // console.log('>>>>>>>>>> findRoute exactMatchResolver', status, redirectUrl, redirect.to);\r\n return Response.json({ redirectUrl }, { status });\r\n } else {\r\n return Response.json('gone', { status });\r\n }\r\n };\r\n // check exact match redirects\r\n const exactMatchRedirect = redirects.find(x => x.from === sanitizedHref);\r\n if (exactMatchRedirect !== undefined) {\r\n // Exact matching avoids compiling patterns for the common case.\r\n return exactMatchResolver(exactMatchRedirect);\r\n }\r\n // pattern match redirect resolver\r\n const patternMatchResolver = (redirect: IRedirect) => {\r\n const status: number = parseInt(redirect.status) || 307;\r\n if (status < 400) {\r\n const regexp = new RegExp(redirect.from);\r\n let i = 0;\r\n let redirectUrl = (redirect.to as string).replace(/\\*/g, (...rest) => {\r\n return `$${++i}`;\r\n });\r\n redirectUrl = sanitizedHref.replace(regexp, redirectUrl);\r\n // console.log('>>>>>>>>>> findRoute patternMatchResolver', status, redirectUrl, redirect.to);\r\n return Response.json({ redirectUrl }, { status });\r\n } else {\r\n return Response.json('gone', { status });\r\n }\r\n };\r\n // check redirects by pattern\r\n redirects.forEach(x => {\r\n let expression = x.from;\r\n // wrapping catchall in (.*)\r\n expression = expression.replace(/\\*(?!\\))/g, '(.*)');\r\n // wrapping expression in ^...$\r\n expression = `^${expression.replace(/(^\\^)|(\\$$)/g, '')}$`;\r\n x.from = expression;\r\n });\r\n // check if a regex pattern redirect does match\r\n const firstMatch = redirects.find(x => sanitizedHref.match(x.from));\r\n // console.log('>>>>>>>>>> findRoute firstMatch', firstMatch);\r\n if (firstMatch) {\r\n return patternMatchResolver(firstMatch);\r\n }\r\n // console.error('not found', collection);\r\n // Preserve the nearest parent so middleware can render a localized\r\n // 404 without a second snapshot lookup.\r\n return ResponseSuccess({ parent: resolution.parent });\r\n }\r\n } else {\r\n // The collection branch serves management/list callers. Apply in-memory\r\n // filtering after the cached route graph is built, avoiding duplicate\r\n // collection queries for each filter or sort combination.\r\n const query = qsDeserialize(decodeURIComponent(searchParams.toString()));\r\n req.query = query;\r\n const routes = await getRoutes(req);\r\n let items = await whereCollection<IRoute>(routes, query.where);\r\n items = await sortCollection(items, query.sort);\r\n return ResponseSuccess(items);\r\n // return ResponseBadRequest();\r\n }\r\n } catch (error: unknown) {\r\n console.error('routeGetHandler.error', error);\r\n return getHandlerErrorResponse(error);\r\n }\r\n };\r\n}\r\n"],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { NextRequest } from "next/server";
|
|
2
|
+
import { SanitizedConfig } from "payload";
|
|
3
|
+
|
|
4
|
+
//#region src/server/handlers/sitemap.handler.d.ts
|
|
5
|
+
type ISiteMap = {
|
|
6
|
+
id: string;
|
|
7
|
+
updatedAt?: string | Date;
|
|
8
|
+
};
|
|
9
|
+
declare function getSiteMapIndex(config: Promise<SanitizedConfig>): (request: NextRequest) => Promise<Response>;
|
|
10
|
+
declare function getSiteMapXML(config: Promise<SanitizedConfig>): (request: NextRequest, {
|
|
11
|
+
params: getParams
|
|
12
|
+
}: {
|
|
13
|
+
params: Promise<{
|
|
14
|
+
market?: string;
|
|
15
|
+
locale?: string;
|
|
16
|
+
}>;
|
|
17
|
+
}) => Promise<Response>;
|
|
18
|
+
declare function getSiteMapXSL(config: Promise<SanitizedConfig>): (request: NextRequest, {
|
|
19
|
+
params: getParams
|
|
20
|
+
}: {
|
|
21
|
+
params: Promise<{
|
|
22
|
+
market?: string;
|
|
23
|
+
locale?: string;
|
|
24
|
+
}>;
|
|
25
|
+
}) => Promise<Response>;
|
|
26
|
+
//# sourceMappingURL=sitemap.handler.d.ts.map
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
export { ISiteMap, getSiteMapIndex, getSiteMapXML, getSiteMapXSL };
|
|
30
|
+
//# sourceMappingURL=sitemap.handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sitemap.handler.d.ts","names":[],"sources":["../../../src/server/handlers/sitemap.handler.ts"],"mappings":";;;;KAQY,QAAA;;EAAA,SAAA,CAAA,EAAQ,MAAA,GAEG,IAAA;AAGvB,CAAA;AAA+B,iBAAf,eAAA,CAAe,MAAA,EAAS,OAAT,CAAiB,eAAjB,CAAA,CAAA,EAAA,CAAA,OAAA,EACG,WADH,EAAA,GACc,OADd,CACc,QADd,CAAA;AAAiB,iBA2ChC,aAAA,CA3CgC,MAAA,EA2CV,OA3CU,CA2CF,eA3CE,CAAA,CAAA,EAAA,CAAA,OAAA,EA4Cd,WA5Cc,EAAA;EAAA,MAAA,EA4CD;AA3CF,CADG,EAAA;EAAR,MAAA,EA+C5B,OA/C4B,CAAA;IACN,MAAA,CAAA,EAAA,MAAA;IAAW,MAAA,CAAA,EAAA,MAAA;EAAA,CAAA,CAAA;AAAA,CAAA,EAAA,GA+C1C,OA/C0C,CA+C1C,QA/C0C,CAAA;AA0C7B,iBAuDA,aAAA,CAvDa,MAAA,EAuDS,OAvDT,CAuDiB,eAvDjB,CAAA,CAAA,EAAA,CAAA,OAAA,EAwDK,WAxDL,EAAA;EAAA,MAAA,EAwDkB;AAvDA,CADlB,EAAA;EAAA,MAAA,EA2DjB,OA3DiB,CAAA;IAAiB,MAAA,CAAA,EAAA,MAAA;IAAR,MAAA,CAAA,EAAA,MAAA;EACJ,CAAA,CAAA;AAAa,CAAA,EAAA,GA2D5C,OA3D4C,CA2D5C,QA3D4C,CAAA;AAGnC"}
|