@publish.os/nextjs 0.0.1-alpha.90 → 0.0.1-alpha.91
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/compiler-assets/nextjs/defaults/group/layout.tsx +1 -5
- package/compiler-assets/nextjs/defaults/group/page.tsx +31 -22
- package/compiler-assets/nextjs/defaults/project/next.config.mjs +19 -10
- package/compiler-assets/nextjs/defaults/project/tsconfig.json.template +10 -0
- package/compiler-assets/nextjs/defaults/root/css/components/code-block.css +18 -0
- package/compiler-assets/nextjs/shims/document.tsx +38 -0
- package/compiler-assets/nextjs/shims/generated-leaf-page.tsx +2 -0
- package/compiler-assets/nextjs/shims/global-layout.tsx +8 -42
- package/compiler-assets/nextjs/shims/global-not-found.tsx +69 -0
- package/compiler-assets/nextjs/shims/markdown-route.ts +2 -0
- package/compiler-assets/nextjs/shims/metadata-icons.tsx +39 -0
- package/compiler-assets/nextjs/shims/not-found-content.tsx +53 -0
- package/compiler-assets/nextjs/shims/not-found-navigation.tsx +60 -0
- package/compiler-assets/nextjs/shims/proxy.ts +126 -60
- package/compiler-assets/nextjs/shims/site-fenced-code-block.tsx +2 -6
- package/compiler-assets/nextjs/shims/site-mdx-components.tsx +28 -16
- package/compiler-assets/nextjs/shims/site-mdx.tsx +6 -1
- package/dist/{build-operation-2JAYBSKF.js → build-operation-5QMLXF7N.js} +29 -23
- package/dist/{button-c3WGnxIj.d.ts → button-BdCScEKi.d.ts} +3 -3
- package/dist/capture-local-source-WGGDIUU2.js +258 -0
- package/dist/chunk-22RSSUNV.js +13 -0
- package/dist/{chunk-WKTEO6RS.js → chunk-4BC2L2KA.js} +46 -12
- package/dist/{chunk-WDY4IK6Z.js → chunk-5J3YUNRY.js} +3 -10
- package/dist/chunk-5KAD7W53.js +248 -0
- package/dist/{chunk-DWA3ZRGW.js → chunk-6C65KV7O.js} +2 -2
- package/dist/{chunk-GGKFQ3MA.js → chunk-6D2E6UMD.js} +144 -70
- package/dist/{chunk-7OGTPSKI.js → chunk-7NY22B5U.js} +8 -3
- package/dist/chunk-EFO6AWXN.js +19 -0
- package/dist/{chunk-726GV2NF.js → chunk-F3AGNDF4.js} +100 -67
- package/dist/chunk-GBPLER5H.js +426 -0
- package/dist/chunk-IL4RJOKI.js +186 -0
- package/dist/{chunk-DLDFHU7Y.js → chunk-NNBJZPFM.js} +4 -2
- package/dist/{chunk-VO2I7MTM.js → chunk-ORIUWJBQ.js} +8 -6
- package/dist/{chunk-H6XILMZX.js → chunk-OXOFRXEI.js} +1806 -831
- package/dist/chunk-UYGCOWRF.js +1709 -0
- package/dist/{chunk-YLTOLYWM.js → chunk-WL75GQ5M.js} +6 -18
- package/dist/compiler.d.ts +15 -2
- package/dist/compiler.js +90 -21
- package/dist/components/blocks/agent-actions.d.ts +81 -0
- package/dist/components/blocks/agent-actions.js +594 -0
- package/dist/components/blocks/toc.d.ts +43 -0
- package/dist/components/blocks/toc.js +136 -0
- package/dist/components/ui/button.d.ts +5 -0
- package/dist/components/ui/button.js +94 -0
- package/dist/compose-CVBJRAF6.js +16 -0
- package/dist/config/createNextConfig.js +17 -3
- package/dist/{dev-operation-TZDVJCN7.js → dev-operation-OSHHWRWK.js} +121 -81
- package/dist/{framework-selection-X4U6Y6QC.js → framework-selection-ZVO323PK.js} +3 -2
- package/dist/ide-support-CU6Z5PVR.js +16 -0
- package/dist/index.d.ts +40 -1
- package/dist/jsx-dev-runtime.d.ts +6 -0
- package/dist/jsx-dev-runtime.js +100 -0
- package/dist/jsx-runtime.d.ts +7 -0
- package/dist/jsx-runtime.js +97 -0
- package/dist/kernel/components/blocks/AgentActions.d.ts +35 -6
- package/dist/kernel/components/blocks/AgentActions.js +383 -142
- package/dist/kernel/components/blocks/agent-actions.d.ts +5 -0
- package/dist/kernel/components/blocks/agent-actions.js +594 -0
- package/dist/kernel/components/blocks/animated-icon-swap.js +1 -1
- package/dist/kernel/components/blocks/color-palette.js +4 -4
- package/dist/kernel/components/blocks/logo-block.js +1 -1
- package/dist/kernel/components/blocks/nav-breadcrumb.js +2 -2
- package/dist/kernel/components/blocks/navbar.js +17 -17
- package/dist/kernel/components/blocks/navigation-progress.js +2 -2
- package/dist/kernel/components/blocks/next-prev.js +1 -1
- package/dist/kernel/components/blocks/page-list.js +2 -2
- package/dist/kernel/components/blocks/search.d.ts +1 -1
- package/dist/kernel/components/blocks/search.js +16 -17
- package/dist/kernel/components/blocks/sidebar-node.js +1 -1
- package/dist/kernel/components/blocks/sidebar.js +7 -4
- package/dist/kernel/components/blocks/theme-toggle.d.ts +1 -1
- package/dist/kernel/components/blocks/theme-toggle.js +5 -5
- package/dist/kernel/components/blocks/toc-client.d.ts +40 -0
- package/dist/kernel/components/blocks/toc-client.js +495 -0
- package/dist/kernel/components/blocks/toc.d.ts +19 -1
- package/dist/kernel/components/blocks/toc.js +121 -179
- package/dist/kernel/components/mdx/components/blockquote.js +1 -1
- package/dist/kernel/components/mdx/components/callout.js +1 -1
- package/dist/kernel/components/mdx/components/code-block.js +2 -2
- package/dist/kernel/components/mdx/components/copy-code-button.js +5 -4
- package/dist/kernel/components/mdx/components/figure-caption.d.ts +1 -1
- package/dist/kernel/components/mdx/components/figure-caption.js +3 -2
- package/dist/kernel/components/mdx/components/figure.d.ts +6 -2
- package/dist/kernel/components/mdx/components/figure.js +23 -13
- package/dist/kernel/components/mdx/components/footnotes.js +1 -1
- package/dist/kernel/components/mdx/components/heading-copy-link.js +1 -1
- package/dist/kernel/components/mdx/components/heading.js +6 -3
- package/dist/kernel/components/mdx/components/hr.js +2 -2
- package/dist/kernel/components/mdx/components/image-zoom.js +1 -1
- package/dist/kernel/components/mdx/components/image.d.ts +1 -1
- package/dist/kernel/components/mdx/components/image.js +21 -16
- package/dist/kernel/components/mdx/components/inline-code.js +1 -1
- package/dist/kernel/components/mdx/components/kbd.js +2 -2
- package/dist/kernel/components/mdx/components/link.d.ts +3 -3
- package/dist/kernel/components/mdx/components/link.js +2 -2
- package/dist/kernel/components/mdx/components/paragraph.js +1 -1
- package/dist/kernel/components/mdx/components/strikethrough.js +1 -1
- package/dist/kernel/components/mdx/components/table.js +2 -2
- package/dist/kernel/components/mdx/components/task-list.js +1 -1
- package/dist/kernel/components/mdx/components/video-player.d.ts +6 -2
- package/dist/kernel/components/mdx/components/video-player.js +6 -2
- package/dist/kernel/components/mdx/components/video.d.ts +5 -3
- package/dist/kernel/components/mdx/components/video.js +7 -5
- package/dist/kernel/components/mdx/error-boundary.d.ts +1 -1
- package/dist/kernel/components/mdx/error-boundary.js +2 -2
- package/dist/kernel/components/mdx/error-fallback.js +1 -1
- package/dist/kernel/components/mdx/mdx.d.ts +20 -10
- package/dist/kernel/components/mdx/mdx.js +231 -34
- package/dist/kernel/components/mdx/rehype-heading-ids.d.ts +1 -0
- package/dist/kernel/components/mdx/rehype-heading-ids.js +5 -3
- package/dist/kernel/components/mdx/types.d.ts +1 -1
- package/dist/kernel/components/next-image.d.ts +12 -0
- package/dist/kernel/components/next-image.js +61 -0
- package/dist/kernel/components/ui/accordion.js +1 -1
- package/dist/kernel/components/ui/breadcrumb-trail.d.ts +2 -2
- package/dist/kernel/components/ui/breadcrumb-trail.js +2 -2
- package/dist/kernel/components/ui/breadcrumb.d.ts +1 -1
- package/dist/kernel/components/ui/breadcrumb.js +4 -4
- package/dist/kernel/components/ui/button-group.d.ts +1 -1
- package/dist/kernel/components/ui/button-group.js +3 -3
- package/dist/kernel/components/ui/button.d.ts +56 -4
- package/dist/kernel/components/ui/button.js +43 -39
- package/dist/kernel/components/ui/card.js +1 -1
- package/dist/kernel/components/ui/dialog.js +1 -1
- package/dist/kernel/components/ui/drawer.js +1 -1
- package/dist/kernel/components/ui/input.d.ts +2 -2
- package/dist/kernel/components/ui/input.js +1 -1
- package/dist/kernel/components/ui/kbd.d.ts +1 -1
- package/dist/kernel/components/ui/kbd.js +1 -1
- package/dist/kernel/components/ui/link.d.ts +8 -2
- package/dist/kernel/components/ui/link.js +2 -2
- package/dist/kernel/components/ui/menu.js +1 -1
- package/dist/kernel/components/ui/mod-key.js +2 -2
- package/dist/kernel/components/ui/navigation-menu.js +1 -1
- package/dist/kernel/components/ui/popover.js +1 -1
- package/dist/kernel/components/ui/progress.js +1 -1
- package/dist/kernel/components/ui/scroll-area.d.ts +8 -8
- package/dist/kernel/components/ui/scroll-area.js +1 -1
- package/dist/kernel/components/ui/select.js +1 -1
- package/dist/kernel/components/ui/separator.js +1 -1
- package/dist/kernel/components/ui/table.js +1 -1
- package/dist/kernel/components/ui/tabs.js +1 -1
- package/dist/kernel/components/ui/tag.js +1 -1
- package/dist/kernel/components/ui/text.d.ts +1 -1
- package/dist/kernel/components/ui/text.js +1 -1
- package/dist/kernel/components/ui/toast.js +1 -1
- package/dist/kernel/components/ui/tooltip.js +1 -1
- package/dist/kernel/defaults.registry.d.ts +2 -15
- package/dist/kernel/defaults.registry.js +2 -17
- package/dist/kernel/routes/agent/markdown.d.ts +3 -0
- package/dist/kernel/routes/agent/markdown.js +219 -48
- package/dist/kernel/routes/layouts/group.d.ts +1 -1
- package/dist/kernel/routes/layouts/group.js +5 -7
- package/dist/kernel/routes/metadata/feed.d.ts +1 -1
- package/dist/kernel/routes/metadata/feed.js +109 -83
- package/dist/kernel/routes/metadata/llms.d.ts +11 -3
- package/dist/kernel/routes/metadata/llms.js +154 -57
- package/dist/kernel/routes/metadata/og-image.js +1 -1
- package/dist/kernel/routes/metadata/robots.d.ts +1 -1
- package/dist/kernel/routes/metadata/sitemap.d.ts +22 -3
- package/dist/kernel/routes/metadata/sitemap.js +183 -43
- package/dist/kernel/routes/not-found.d.ts +34 -0
- package/dist/kernel/routes/not-found.js +213 -0
- package/dist/kernel/routes/pages/group.d.ts +2 -2
- package/dist/kernel/routes/pages/group.js +1 -1
- package/dist/kernel/routes/pages/leaf.d.ts +30 -3
- package/dist/kernel/routes/pages/leaf.js +5 -4
- package/dist/kernel/routes/pages/root.d.ts +2 -2
- package/dist/kernel/routes/pages/root.js +1 -1
- package/dist/keyboard-shortcuts.js +1 -1
- package/dist/route-metadata-og-image-BeKKFHg7.d.ts +58 -0
- package/dist/search.js +7 -9
- package/dist/theme-scope.js +1 -1
- package/dist/{types-BzkZty3r.d.ts → types-J2w_puPF.d.ts} +1 -20
- package/dist/types-sM2g9nW0.d.ts +12 -0
- package/dist/types.d.ts +1 -0
- package/dist/utils/heading-ids.js +30 -11
- package/dist/utils/toc-selection.d.ts +7 -0
- package/dist/utils/toc-selection.js +14 -0
- package/dist/validate-local-source-SV44DBQT.js +16 -0
- package/dist/validate-publish-os-source-NZJF3TB2.js +14 -0
- package/init/seed/minimal/publish.os/assets/blog/hello-world.svg +13 -0
- package/init/seed/minimal/publish.os/assets/favicon.dark.svg +13 -0
- package/init/seed/minimal/publish.os/assets/favicon.svg +13 -0
- package/init/seed/minimal/publish.os/blog/content/hello-world.mdx +48 -0
- package/init/seed/minimal/publish.os/blog/content/series-a.mdx +11 -0
- package/init/seed/minimal/publish.os/blog/index.tsx +82 -0
- package/init/seed/minimal/publish.os/blog/layout.tsx +13 -0
- package/init/seed/minimal/publish.os/blog/page.tsx +76 -0
- package/init/seed/minimal/publish.os/components/blog/copy-link.tsx +64 -0
- package/init/seed/minimal/publish.os/docs/content/get-started.mdx +2 -3
- package/init/seed/minimal/publish.os/docs/content/groups.mdx +5 -6
- package/init/seed/minimal/publish.os/publish.os.config.json +6 -2
- package/init/seed/minimal/publish.os/theme.css +3 -3
- package/init/seed/minimal/seed.json +11 -4
- package/init/seed/scratch/publish.os/docs/content/get-started.mdx +1 -1
- package/init/seed/scratch/publish.os/publish.os.config.json +1 -1
- package/package.json +45 -20
- package/release/app/phosphor/package.json +3 -3
- package/release/app/phosphor/pnpm-lock.yaml.template +88 -75
- package/release/compiler/package.json +5 -3
- package/release/compiler/pnpm-lock.yaml.template +118 -74
- package/release/release.json +6 -6
- package/dist/button-CtzUJB8u.d.ts +0 -11
- package/dist/chunk-535TM4A5.js +0 -1455
- package/dist/chunk-B2V22WRT.js +0 -297
- package/dist/chunk-NECL5IBJ.js +0 -318
- package/dist/chunk-SVYGXXYR.js +0 -36
- package/dist/chunk-UF6ATARM.js +0 -1100
- package/dist/compose-NN23UJGC.js +0 -13
- package/dist/ide-support-ZNW7ODFY.js +0 -15
- package/dist/kernel/components/blocks/design-system-preview.d.ts +0 -61
- package/dist/kernel/components/blocks/design-system-preview.js +0 -667
- package/dist/kernel/components/blocks/link-playground.d.ts +0 -5
- package/dist/kernel/components/blocks/link-playground.js +0 -744
- package/dist/kernel/components/blocks/navigation-progress-playground.d.ts +0 -5
- package/dist/kernel/components/blocks/navigation-progress-playground.js +0 -629
- package/dist/kernel/components/ui/theme-toggle.d.ts +0 -24
- package/dist/kernel/components/ui/theme-toggle.js +0 -53
- package/dist/validate-local-source-XRL2Y7XE.js +0 -14
- package/dist/validate-publish-os-source-DAPZ4QGE.js +0 -12
- package/init/seed/minimal/publish.os/assets/favicon/favicon.dark.png +0 -0
- package/init/seed/minimal/publish.os/assets/favicon/favicon.png +0 -0
|
@@ -1,52 +1,70 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertFrameworkArchiveIdentity,
|
|
3
|
+
assertFrameworkSelection,
|
|
4
|
+
readCheckoutTypeScriptConfig
|
|
5
|
+
} from "./chunk-NNBJZPFM.js";
|
|
1
6
|
import {
|
|
2
7
|
ROOT_CONTENT_GROUP_KEY,
|
|
8
|
+
admitThemeImageResource,
|
|
3
9
|
assertSourceDependency,
|
|
4
|
-
cssImports,
|
|
5
|
-
decodeCssPath,
|
|
6
10
|
faviconsAndLogosManifestModule,
|
|
7
11
|
groupedMdxExports,
|
|
8
12
|
mdxComponentExportName,
|
|
13
|
+
mdxIconPackage,
|
|
14
|
+
mediaAssetBudgets,
|
|
9
15
|
mediaManifestModule,
|
|
10
16
|
namedValueExports,
|
|
17
|
+
nextjs_runtime_surface_default,
|
|
11
18
|
normalizeUrlPath,
|
|
19
|
+
readMdxIconImports,
|
|
12
20
|
replacedMdxSourceFiles,
|
|
13
|
-
|
|
21
|
+
supportedRuntimeComponentAliases,
|
|
14
22
|
writeMediaOutputs
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import {
|
|
17
|
-
assertFrameworkArchiveIdentity,
|
|
18
|
-
assertFrameworkSelection,
|
|
19
|
-
readCheckoutTypeScriptConfig
|
|
20
|
-
} from "./chunk-DLDFHU7Y.js";
|
|
23
|
+
} from "./chunk-UYGCOWRF.js";
|
|
21
24
|
import {
|
|
22
|
-
ASSET_PREFIX,
|
|
23
25
|
FRAMEWORK_PREFIX,
|
|
24
26
|
FRAMEWORK_PROXY_MATCHER,
|
|
25
27
|
IMAGE_OPTIMIZER_PATH,
|
|
28
|
+
INTERNAL_PREFIX,
|
|
26
29
|
NEXT_IMAGE_OPTIMIZER_PATH,
|
|
27
30
|
OG_SERVICE_PREFIX,
|
|
28
|
-
PUBLIC_ASSET_DIRECTORY,
|
|
29
31
|
PUBLIC_FONT_DIRECTORY,
|
|
30
|
-
|
|
32
|
+
PUBLIC_INTERNAL_DIRECTORY,
|
|
33
|
+
PUBLIC_SEARCH_DIRECTORY,
|
|
34
|
+
SOURCE_ASSET_PREFIX,
|
|
35
|
+
isFrameworkNamespacePath
|
|
36
|
+
} from "./chunk-EFO6AWXN.js";
|
|
37
|
+
import {
|
|
38
|
+
cssImports,
|
|
39
|
+
decodeCssPath,
|
|
40
|
+
ignoredMediaDocumentWarning,
|
|
41
|
+
ignoredMediaPathWarning,
|
|
42
|
+
isHiddenMediaPath,
|
|
43
|
+
mediaFileTooLarge,
|
|
44
|
+
readBoundedMediaFile,
|
|
45
|
+
themeResourceByteLimit
|
|
46
|
+
} from "./chunk-5KAD7W53.js";
|
|
47
|
+
import {
|
|
31
48
|
isApprovedPublishOsPath,
|
|
32
49
|
isDescendant,
|
|
33
50
|
isExcludedSourcePath,
|
|
34
|
-
isFrameworkNamespacePath,
|
|
35
51
|
isReservedFrameworkPath,
|
|
36
52
|
isSameOrDescendant
|
|
37
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-WL75GQ5M.js";
|
|
38
54
|
import {
|
|
39
|
-
AppError,
|
|
40
55
|
readInstalledFramework,
|
|
41
56
|
readInstalledFrameworkLocation
|
|
42
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-5J3YUNRY.js";
|
|
58
|
+
import {
|
|
59
|
+
AppError
|
|
60
|
+
} from "./chunk-22RSSUNV.js";
|
|
43
61
|
|
|
44
62
|
// src/lib/compiler/nextjs/compose.ts
|
|
45
63
|
import { createHash as createHash4 } from "crypto";
|
|
46
64
|
import { existsSync } from "fs";
|
|
47
65
|
import {
|
|
48
66
|
cp,
|
|
49
|
-
lstat as
|
|
67
|
+
lstat as lstat3,
|
|
50
68
|
mkdir as mkdir6,
|
|
51
69
|
mkdtemp as mkdtemp2,
|
|
52
70
|
readdir as readdir3,
|
|
@@ -69,6 +87,84 @@ import {
|
|
|
69
87
|
import { googleFontsMetadata as googleFontsMetadata2 } from "next/dist/compiled/@next/font/dist/google/google-fonts-metadata.js";
|
|
70
88
|
import ts3 from "typescript";
|
|
71
89
|
|
|
90
|
+
// src/lib/assets/map-source-asset-css.ts
|
|
91
|
+
import postcss from "postcss";
|
|
92
|
+
import valueParser from "postcss-value-parser";
|
|
93
|
+
|
|
94
|
+
// src/lib/assets/map-source-asset-url.ts
|
|
95
|
+
var SOURCE_ASSET_PATH = "/assets/";
|
|
96
|
+
function hasUnsafeControlCharacters(value) {
|
|
97
|
+
for (let character of value) {
|
|
98
|
+
let code = character.codePointAt(0) ?? 0;
|
|
99
|
+
if (code <= 31 || code >= 127 && code <= 159) return !0;
|
|
100
|
+
}
|
|
101
|
+
return !1;
|
|
102
|
+
}
|
|
103
|
+
function assertSafeAssetPath(path) {
|
|
104
|
+
if (path.includes("\\") || hasUnsafeControlCharacters(path))
|
|
105
|
+
throw new TypeError("Local asset URLs must use safe path segments.");
|
|
106
|
+
for (let segment of path.split("/")) {
|
|
107
|
+
if (!segment)
|
|
108
|
+
throw new TypeError("Local asset URLs must use safe path segments.");
|
|
109
|
+
let decoded;
|
|
110
|
+
try {
|
|
111
|
+
decoded = decodeURIComponent(segment);
|
|
112
|
+
} catch {
|
|
113
|
+
throw new TypeError("Local asset URLs must use valid URL encoding.");
|
|
114
|
+
}
|
|
115
|
+
if (decoded === "." || decoded === ".." || decoded.includes("/") || decoded.includes("\\") || hasUnsafeControlCharacters(decoded))
|
|
116
|
+
throw new TypeError("Local asset URLs must use safe path segments.");
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function mapSourceAssetUrl(value) {
|
|
120
|
+
if (typeof value != "string" || !value.startsWith(SOURCE_ASSET_PATH))
|
|
121
|
+
return value;
|
|
122
|
+
let suffixIndex = value.search(/[?#]/u), pathname = suffixIndex < 0 ? value : value.slice(0, suffixIndex), suffix = suffixIndex < 0 ? "" : value.slice(suffixIndex), path = pathname.slice(SOURCE_ASSET_PATH.length);
|
|
123
|
+
return assertSafeAssetPath(path), `${SOURCE_ASSET_PREFIX}/${path}${suffix}`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// src/lib/assets/map-source-asset-css.ts
|
|
127
|
+
var IMAGE_SET_FUNCTIONS = /* @__PURE__ */ new Set(["image-set", "-webkit-image-set"]);
|
|
128
|
+
function mapCssUrls(value) {
|
|
129
|
+
let parsed = valueParser(value);
|
|
130
|
+
return parsed.walk((node) => {
|
|
131
|
+
if (node.type !== "function") return;
|
|
132
|
+
let name = node.value.toLowerCase();
|
|
133
|
+
if (name === "url") {
|
|
134
|
+
let url = node.nodes.find(
|
|
135
|
+
(part) => part.type === "word" || part.type === "string"
|
|
136
|
+
);
|
|
137
|
+
if (url) {
|
|
138
|
+
let mapped = mapSourceAssetUrl(url.value.trim());
|
|
139
|
+
typeof mapped == "string" && (url.value = mapped);
|
|
140
|
+
}
|
|
141
|
+
return !1;
|
|
142
|
+
}
|
|
143
|
+
if (IMAGE_SET_FUNCTIONS.has(name))
|
|
144
|
+
for (let candidate of node.nodes) {
|
|
145
|
+
if (candidate.type !== "string") continue;
|
|
146
|
+
let mapped = mapSourceAssetUrl(candidate.value.trim());
|
|
147
|
+
typeof mapped == "string" && (candidate.value = mapped);
|
|
148
|
+
}
|
|
149
|
+
}), parsed.toString();
|
|
150
|
+
}
|
|
151
|
+
function mapSourceAssetCss(css, sourcePath) {
|
|
152
|
+
let root = postcss.parse(css, { from: sourcePath });
|
|
153
|
+
return root.walkDecls((declaration) => {
|
|
154
|
+
declaration.value = mapCssUrls(declaration.value);
|
|
155
|
+
}), root.walkAtRules((atRule) => {
|
|
156
|
+
if (atRule.name.toLowerCase() !== "import") return;
|
|
157
|
+
let parsed = valueParser(atRule.params), source = parsed.nodes.find(
|
|
158
|
+
(node) => node.type === "word" || node.type === "string"
|
|
159
|
+
);
|
|
160
|
+
if (source) {
|
|
161
|
+
let mapped = mapSourceAssetUrl(source.value);
|
|
162
|
+
typeof mapped == "string" && (source.value = mapped);
|
|
163
|
+
}
|
|
164
|
+
atRule.params = mapCssUrls(parsed.toString());
|
|
165
|
+
}), root.toString();
|
|
166
|
+
}
|
|
167
|
+
|
|
72
168
|
// src/lib/compiler/deployment/deployment-evidence.ts
|
|
73
169
|
import { mkdir, writeFile } from "fs/promises";
|
|
74
170
|
import { join } from "path";
|
|
@@ -713,6 +809,58 @@ function tabHandler(node, context) {
|
|
|
713
809
|
] : children;
|
|
714
810
|
}
|
|
715
811
|
|
|
812
|
+
// src/lib/compiler/markdown/handlers/html.ts
|
|
813
|
+
function inlineHtmlHandler(node, context) {
|
|
814
|
+
handlerDiagnostic(node, context);
|
|
815
|
+
let children = context.transformChildrenAsPhrasing(node, context);
|
|
816
|
+
switch (normalizeComponentName(node.name)) {
|
|
817
|
+
case "strong":
|
|
818
|
+
case "b":
|
|
819
|
+
return [{ type: "strong", children }];
|
|
820
|
+
case "em":
|
|
821
|
+
case "i":
|
|
822
|
+
return [{ type: "emphasis", children }];
|
|
823
|
+
case "code":
|
|
824
|
+
return [{ type: "inlineCode", value: extractText(children) }];
|
|
825
|
+
case "br":
|
|
826
|
+
return [{ type: "break" }];
|
|
827
|
+
default:
|
|
828
|
+
return children;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
function blockquoteHtmlHandler(node, context) {
|
|
832
|
+
return handlerDiagnostic(node, context), [
|
|
833
|
+
{
|
|
834
|
+
type: "blockquote",
|
|
835
|
+
children: node.type === "mdxJsxTextElement" ? paragraphBlock(context.transformChildrenAsPhrasing(node, context)) : context.transformChildrenAsBlocks(node, context)
|
|
836
|
+
}
|
|
837
|
+
];
|
|
838
|
+
}
|
|
839
|
+
function paragraphHtmlHandler(node, context) {
|
|
840
|
+
return handlerDiagnostic(node, context), paragraphBlock(context.transformChildrenAsPhrasing(node, context));
|
|
841
|
+
}
|
|
842
|
+
function preformattedText(node, context) {
|
|
843
|
+
if (node.type === "mdxTextExpression" || node.type === "mdxFlowExpression") {
|
|
844
|
+
let statement = node.data?.estree?.body?.[0], expression = statement?.type === "ExpressionStatement" ? statement.expression : void 0;
|
|
845
|
+
return expression?.type === "Literal" && typeof expression.value == "string" ? expression.value : expression?.type === "TemplateLiteral" && expression.expressions?.length === 0 ? expression.quasis?.[0]?.value.cooked ?? "" : (addDiagnostic(context, {
|
|
846
|
+
code: "mdx-expression-dropped",
|
|
847
|
+
message: "Dropped non-literal MDX expression from preformatted Markdown output."
|
|
848
|
+
}), "");
|
|
849
|
+
}
|
|
850
|
+
return typeof node.value == "string" ? node.value : (node.children ?? []).map((child, index) => (index > 0 && child.type === "paragraph" ? `
|
|
851
|
+
|
|
852
|
+
` : "") + preformattedText(child, context)).join("");
|
|
853
|
+
}
|
|
854
|
+
function preHtmlHandler(node, context) {
|
|
855
|
+
handlerDiagnostic(node, context);
|
|
856
|
+
let code = node.children?.find((child) => child.name === "code");
|
|
857
|
+
return [
|
|
858
|
+
{ type: "code", lang: code ? firstAttribute(code, ["className", "class"], context)?.match(
|
|
859
|
+
/(?:^|\s)language-([^\s]+)/
|
|
860
|
+
)?.[1] : void 0, value: preformattedText(node, context) }
|
|
861
|
+
];
|
|
862
|
+
}
|
|
863
|
+
|
|
716
864
|
// src/lib/compiler/markdown/handlers/inline.ts
|
|
717
865
|
function iconHandler(node, context) {
|
|
718
866
|
handlerDiagnostic(node, context);
|
|
@@ -764,18 +912,33 @@ function imageHandler(node, context, kind) {
|
|
|
764
912
|
let caption = firstAttribute(node, ["caption"], context), image = {
|
|
765
913
|
type: "image",
|
|
766
914
|
url: context.resolveMediaUrl(src),
|
|
767
|
-
alt:
|
|
915
|
+
alt: getAttribute(node, "alt", context) ?? firstAttribute(node, ["title", "aria-label"], context) ?? "",
|
|
768
916
|
title: firstAttribute(node, ["title"], context)
|
|
769
917
|
};
|
|
770
|
-
return kind === "inline" ? [image] : [
|
|
918
|
+
return kind === "inline" ? [image, ...caption ? [text(` ${caption}`)] : []] : [
|
|
771
919
|
...paragraphBlock([image]),
|
|
772
|
-
...caption ? paragraphBlock([
|
|
920
|
+
...caption ? paragraphBlock([text(caption)]) : []
|
|
773
921
|
];
|
|
774
922
|
}
|
|
775
923
|
function figureCaptionHandler(node, context) {
|
|
924
|
+
return handlerDiagnostic(node, context), node.type === "mdxJsxTextElement" ? paragraphBlock(context.transformChildrenAsPhrasing(node, context)) : context.transformChildrenAsBlocks(node, context);
|
|
925
|
+
}
|
|
926
|
+
function isCaption(node) {
|
|
927
|
+
return ["figcaption", "figurecaption", "figure.caption"].includes(
|
|
928
|
+
normalizeComponentName(node.name)
|
|
929
|
+
);
|
|
930
|
+
}
|
|
931
|
+
function hasDirectCaption(node) {
|
|
932
|
+
return (node.children ?? []).some(
|
|
933
|
+
(child) => isCaption(child) || (child.type === "paragraph" || child.type.startsWith("mdxJsx") && child.name === null) && hasDirectCaption(child)
|
|
934
|
+
);
|
|
935
|
+
}
|
|
936
|
+
function figureHandler(node, context) {
|
|
776
937
|
handlerDiagnostic(node, context);
|
|
777
|
-
let children =
|
|
778
|
-
|
|
938
|
+
let children = context.transformChildrenAsBlocks(node, context);
|
|
939
|
+
if (hasDirectCaption(node)) return children;
|
|
940
|
+
let caption = firstAttribute(node, ["caption"], context);
|
|
941
|
+
return [...children, ...caption ? paragraphBlock([text(caption)]) : []];
|
|
779
942
|
}
|
|
780
943
|
function videoHandler(node, context, kind) {
|
|
781
944
|
let src = firstAttribute(node, ["src", "url", "href"], context);
|
|
@@ -785,8 +948,11 @@ function videoHandler(node, context, kind) {
|
|
|
785
948
|
type: "link",
|
|
786
949
|
url: context.resolveMediaUrl(src),
|
|
787
950
|
children: [text(label)]
|
|
788
|
-
}, children = [text("Video: "), link];
|
|
789
|
-
return kind === "inline" ? children
|
|
951
|
+
}, children = [text("Video: "), link], caption = firstAttribute(node, ["caption"], context);
|
|
952
|
+
return kind === "inline" ? [...children, ...caption ? [text(` ${caption}`)] : []] : [
|
|
953
|
+
...paragraphBlock(children),
|
|
954
|
+
...caption ? paragraphBlock([text(caption)]) : []
|
|
955
|
+
];
|
|
790
956
|
}
|
|
791
957
|
|
|
792
958
|
// src/lib/compiler/markdown/handlers/passthrough.ts
|
|
@@ -814,9 +980,29 @@ var defaultHandlers = [
|
|
|
814
980
|
transform: calloutHandler
|
|
815
981
|
},
|
|
816
982
|
{
|
|
817
|
-
componentNames: ["codeblock"
|
|
983
|
+
componentNames: ["codeblock"],
|
|
818
984
|
transform: codeBlockHandler
|
|
819
985
|
},
|
|
986
|
+
{
|
|
987
|
+
componentNames: ["strong", "b", "em", "i", "code", "span", "br"],
|
|
988
|
+
transform: inlineHtmlHandler
|
|
989
|
+
},
|
|
990
|
+
{
|
|
991
|
+
componentNames: ["pre"],
|
|
992
|
+
transform: preHtmlHandler
|
|
993
|
+
},
|
|
994
|
+
{
|
|
995
|
+
componentNames: ["blockquote"],
|
|
996
|
+
transform: blockquoteHtmlHandler
|
|
997
|
+
},
|
|
998
|
+
{
|
|
999
|
+
componentNames: ["p"],
|
|
1000
|
+
transform: paragraphHtmlHandler
|
|
1001
|
+
},
|
|
1002
|
+
{
|
|
1003
|
+
componentNames: ["div"],
|
|
1004
|
+
transform: passthroughBlockHandler
|
|
1005
|
+
},
|
|
820
1006
|
{
|
|
821
1007
|
componentNames: [
|
|
822
1008
|
"codetab",
|
|
@@ -830,10 +1016,10 @@ var defaultHandlers = [
|
|
|
830
1016
|
},
|
|
831
1017
|
{
|
|
832
1018
|
componentNames: ["figure"],
|
|
833
|
-
transform:
|
|
1019
|
+
transform: figureHandler
|
|
834
1020
|
},
|
|
835
1021
|
{
|
|
836
|
-
componentNames: ["figcaption", "figurecaption"],
|
|
1022
|
+
componentNames: ["figcaption", "figurecaption", "figure.caption"],
|
|
837
1023
|
transform: figureCaptionHandler
|
|
838
1024
|
},
|
|
839
1025
|
{
|
|
@@ -898,6 +1084,12 @@ function transformChildrenAsPhrasing(node, context) {
|
|
|
898
1084
|
);
|
|
899
1085
|
}
|
|
900
1086
|
function transformMdxElement(node, context, kind) {
|
|
1087
|
+
if (node.name === null)
|
|
1088
|
+
return kind === "block" ? transformChildrenAsBlocks(node, context) : transformChildrenAsPhrasing(node, context);
|
|
1089
|
+
if (node.name && context.importedIcons.has(node.name)) {
|
|
1090
|
+
let label = firstAttribute(node, ["aria-hidden"], context) === "true" ? "" : firstAttribute(node, ["aria-label", "title"], context), children2 = label ? [{ type: "text", value: label }] : [];
|
|
1091
|
+
return kind === "block" ? paragraphBlock(children2) : children2;
|
|
1092
|
+
}
|
|
901
1093
|
let componentName = normalizeComponentName(node.name), handler = handlersByName.get(componentName);
|
|
902
1094
|
if (handler) {
|
|
903
1095
|
let result = handler.transform(node, context, kind);
|
|
@@ -957,9 +1149,18 @@ function transformInlineNode(node, context) {
|
|
|
957
1149
|
case "link":
|
|
958
1150
|
return [{
|
|
959
1151
|
...node,
|
|
1152
|
+
url: context.resolveMediaUrl(node.url),
|
|
960
1153
|
children: transformChildrenAsPhrasing(node, context)
|
|
961
1154
|
}];
|
|
962
1155
|
case "image":
|
|
1156
|
+
return [
|
|
1157
|
+
{
|
|
1158
|
+
...node,
|
|
1159
|
+
url: context.resolveMediaUrl(node.url)
|
|
1160
|
+
}
|
|
1161
|
+
];
|
|
1162
|
+
case "linkReference":
|
|
1163
|
+
case "imageReference":
|
|
963
1164
|
return [node];
|
|
964
1165
|
case "html":
|
|
965
1166
|
return [node];
|
|
@@ -987,6 +1188,20 @@ function transformTableRow(node, context) {
|
|
|
987
1188
|
)
|
|
988
1189
|
};
|
|
989
1190
|
}
|
|
1191
|
+
function isFigureBlock(node) {
|
|
1192
|
+
if (node.type !== "mdxJsxTextElement" && node.type !== "mdxJsxFlowElement")
|
|
1193
|
+
return !1;
|
|
1194
|
+
if (node.name === null) return (node.children ?? []).some(isFigureBlock);
|
|
1195
|
+
let name = normalizeComponentName(node.name);
|
|
1196
|
+
return [
|
|
1197
|
+
"figure",
|
|
1198
|
+
"figcaption",
|
|
1199
|
+
"figurecaption",
|
|
1200
|
+
"figure.caption",
|
|
1201
|
+
"pre",
|
|
1202
|
+
"blockquote"
|
|
1203
|
+
].includes(name) || ["image", "img", "video", "videoiframe", "iframe"].includes(name) && (node.attributes ?? []).some((attribute) => attribute.name === "caption");
|
|
1204
|
+
}
|
|
990
1205
|
function transformBlockNode(node, context) {
|
|
991
1206
|
if (node.type === "mdxjsEsm")
|
|
992
1207
|
return addDiagnostic(context, {
|
|
@@ -1002,6 +1217,20 @@ function transformBlockNode(node, context) {
|
|
|
1002
1217
|
return transformMdxElement(node, context, "block");
|
|
1003
1218
|
switch (node.type) {
|
|
1004
1219
|
case "paragraph": {
|
|
1220
|
+
if ((node.children ?? []).some(isFigureBlock)) {
|
|
1221
|
+
let blocks = [], pending = [], flushPhrasing = () => {
|
|
1222
|
+
let children = transformChildrenAsPhrasing(
|
|
1223
|
+
{ type: "paragraph", children: pending },
|
|
1224
|
+
context
|
|
1225
|
+
);
|
|
1226
|
+
children.some(
|
|
1227
|
+
(child) => child.type !== "text" || child.value.trim()
|
|
1228
|
+
) && blocks.push(...paragraphBlock(children)), pending = [];
|
|
1229
|
+
};
|
|
1230
|
+
for (let child of node.children ?? [])
|
|
1231
|
+
isFigureBlock(child) ? (flushPhrasing(), blocks.push(...transformBlockNode(child, context))) : pending.push(child);
|
|
1232
|
+
return flushPhrasing(), blocks;
|
|
1233
|
+
}
|
|
1005
1234
|
let paragraphNode = paragraph(
|
|
1006
1235
|
transformChildrenAsPhrasing(node, context)
|
|
1007
1236
|
);
|
|
@@ -1047,18 +1276,25 @@ function transformBlockNode(node, context) {
|
|
|
1047
1276
|
case "thematicBreak":
|
|
1048
1277
|
case "html":
|
|
1049
1278
|
case "yaml":
|
|
1050
|
-
case "definition":
|
|
1051
1279
|
case "footnoteDefinition":
|
|
1052
1280
|
return [node];
|
|
1281
|
+
case "definition":
|
|
1282
|
+
return [
|
|
1283
|
+
{
|
|
1284
|
+
...node,
|
|
1285
|
+
url: context.resolveMediaUrl(node.url)
|
|
1286
|
+
}
|
|
1287
|
+
];
|
|
1053
1288
|
default:
|
|
1054
1289
|
return [];
|
|
1055
1290
|
}
|
|
1056
1291
|
}
|
|
1057
1292
|
function convertMdxToMarkdown(options) {
|
|
1058
|
-
let
|
|
1293
|
+
let context = {
|
|
1294
|
+
importedIcons: /* @__PURE__ */ new Set(),
|
|
1059
1295
|
collectDiagnostics: options.collectDiagnostics ?? !0,
|
|
1060
1296
|
diagnostics: [],
|
|
1061
|
-
resolveMediaUrl,
|
|
1297
|
+
resolveMediaUrl: (url) => String(mapSourceAssetUrl(url)),
|
|
1062
1298
|
transformChildrenAsBlocks,
|
|
1063
1299
|
transformChildrenAsPhrasing,
|
|
1064
1300
|
unknownComponentMode: options.unknownComponentMode ?? "children"
|
|
@@ -1069,6 +1305,13 @@ function convertMdxToMarkdown(options) {
|
|
|
1069
1305
|
markdown: stripTopLevelImports(options.source),
|
|
1070
1306
|
text: ""
|
|
1071
1307
|
};
|
|
1308
|
+
for (let node of parsed.children)
|
|
1309
|
+
if (node.type === "mdxjsEsm") {
|
|
1310
|
+
for (let statement of node.data?.estree?.body ?? [])
|
|
1311
|
+
if (!(statement.type !== "ImportDeclaration" || statement.source.value !== mdxIconPackage))
|
|
1312
|
+
for (let specifier of statement.specifiers)
|
|
1313
|
+
specifier.type === "ImportSpecifier" && context.importedIcons.add(specifier.local.name);
|
|
1314
|
+
}
|
|
1072
1315
|
let transformed = {
|
|
1073
1316
|
type: "root",
|
|
1074
1317
|
children: parsed.children.flatMap(
|
|
@@ -1082,6 +1325,20 @@ function convertMdxToMarkdown(options) {
|
|
|
1082
1325
|
};
|
|
1083
1326
|
}
|
|
1084
1327
|
|
|
1328
|
+
// src/lib/compiler/markdown/page-artifact-conversions.ts
|
|
1329
|
+
function convertPublishedPageBodies(manifest) {
|
|
1330
|
+
return new Map(
|
|
1331
|
+
manifest.pages.filter((page) => page.status === "published").map((page) => [
|
|
1332
|
+
page.path,
|
|
1333
|
+
convertMdxToMarkdown({
|
|
1334
|
+
collectDiagnostics: !1,
|
|
1335
|
+
source: page.body,
|
|
1336
|
+
unknownComponentMode: "children"
|
|
1337
|
+
})
|
|
1338
|
+
])
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1085
1342
|
// src/lib/compiler/nextjs/checkout-runtime.ts
|
|
1086
1343
|
import {
|
|
1087
1344
|
mkdir as mkdir3,
|
|
@@ -1096,8 +1353,11 @@ import { basename, dirname as dirname2, join as join4, relative } from "path";
|
|
|
1096
1353
|
import ts from "typescript";
|
|
1097
1354
|
|
|
1098
1355
|
// src/lib/compiler/nextjs/framework-next-config.ts
|
|
1099
|
-
function renderFrameworkNextConfig(template) {
|
|
1100
|
-
return template.replaceAll("
|
|
1356
|
+
function renderFrameworkNextConfig(template, componentAliases = {}) {
|
|
1357
|
+
return template.replaceAll("__PUBLISHOS_INTERNAL_PREFIX__", INTERNAL_PREFIX).replaceAll("__PUBLISHOS_SOURCE_ASSET_PREFIX__", SOURCE_ASSET_PREFIX).replaceAll("__PUBLISHOS_IMAGE_PATH__", IMAGE_OPTIMIZER_PATH).replaceAll("__PUBLISHOS_NEXT_IMAGE_PATH__", NEXT_IMAGE_OPTIMIZER_PATH).replaceAll(
|
|
1358
|
+
"__PUBLISHOS_COMPONENT_ALIASES__",
|
|
1359
|
+
JSON.stringify(componentAliases)
|
|
1360
|
+
);
|
|
1101
1361
|
}
|
|
1102
1362
|
|
|
1103
1363
|
// src/lib/compiler/nextjs/checkout-runtime.ts
|
|
@@ -1235,6 +1495,7 @@ export default {
|
|
|
1235
1495
|
...base.turbopack,
|
|
1236
1496
|
root,
|
|
1237
1497
|
resolveAlias: {
|
|
1498
|
+
...base.turbopack?.resolveAlias,
|
|
1238
1499
|
...aliases,
|
|
1239
1500
|
"@app/*": "./app/*",
|
|
1240
1501
|
"@source/*": "./source/*",
|
|
@@ -1276,7 +1537,7 @@ function googleFontOutput({
|
|
|
1276
1537
|
() => `font-family: '${family}';`
|
|
1277
1538
|
);
|
|
1278
1539
|
for (let file of assets.files)
|
|
1279
|
-
css = css.split(file.url).join(`${
|
|
1540
|
+
css = css.split(file.url).join(`${INTERNAL_PREFIX}/fonts/${file.sha256}.${file.format}`);
|
|
1280
1541
|
let metrics = font.adjustFontFallback ? getFallbackFontOverrideMetrics(font.family) : void 0;
|
|
1281
1542
|
metrics && (css += `
|
|
1282
1543
|
@font-face { font-family: '${family} Fallback'; src: local('${metrics.fallbackFont}'); ascent-override: ${metrics.ascentOverride}; descent-override: ${metrics.descentOverride}; line-gap-override: ${metrics.lineGapOverride}; size-adjust: ${metrics.sizeAdjust}; }
|
|
@@ -1298,7 +1559,7 @@ function googleFontOutput({
|
|
|
1298
1559
|
else if (font.preload && subset && font.subsets.includes(subset)) {
|
|
1299
1560
|
let url = match[2]?.trim().replace(/^["']|["']$/g, ""), file = assets.files.find((entry) => entry.url === url);
|
|
1300
1561
|
file && preloads.add(
|
|
1301
|
-
` preload("${
|
|
1562
|
+
` preload("${INTERNAL_PREFIX}/fonts/${file.sha256}.${file.format}", { as: "font", type: "font/${file.format}", crossOrigin: "anonymous" });`
|
|
1302
1563
|
);
|
|
1303
1564
|
}
|
|
1304
1565
|
return {
|
|
@@ -1315,6 +1576,183 @@ export const ${exportName}: { className: string; variable: string; style: { font
|
|
|
1315
1576
|
};
|
|
1316
1577
|
}
|
|
1317
1578
|
|
|
1579
|
+
// src/lib/compiler/nextjs/mdx-icon-components.ts
|
|
1580
|
+
function mdxIconComponentsModule(pages) {
|
|
1581
|
+
let names = /* @__PURE__ */ new Map(), entries = [];
|
|
1582
|
+
for (let page of pages) {
|
|
1583
|
+
let bindings = readMdxIconImports(page.body);
|
|
1584
|
+
if (bindings.length === 0) continue;
|
|
1585
|
+
let properties = bindings.map(({ imported, local }) => {
|
|
1586
|
+
let identifier = names.get(imported);
|
|
1587
|
+
return identifier || (identifier = `ImportedIcon${names.size}`, names.set(imported, identifier)), `[${JSON.stringify(local)}]: ${identifier}`;
|
|
1588
|
+
});
|
|
1589
|
+
entries.push(`${JSON.stringify(page.path)}: { ${properties.join(", ")} }`);
|
|
1590
|
+
}
|
|
1591
|
+
return [
|
|
1592
|
+
'import type { MDXComponents } from "@publish.os/nextjs/mdx/mdx";',
|
|
1593
|
+
...names.size ? [
|
|
1594
|
+
`import { ${[...names].map(([name, identifier]) => `${name} as ${identifier}`).join(", ")} } from ${JSON.stringify(mdxIconPackage)};`
|
|
1595
|
+
] : [],
|
|
1596
|
+
`export const importedMdxComponents: Record<string, MDXComponents> = {
|
|
1597
|
+
${entries.join(`,
|
|
1598
|
+
`)}
|
|
1599
|
+
};
|
|
1600
|
+
`
|
|
1601
|
+
].join(`
|
|
1602
|
+
`);
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
// src/lib/runtime/metadata/canonical-url.ts
|
|
1606
|
+
function canonicalUrl(manifest, path, group) {
|
|
1607
|
+
let origin = (group && manifest.groups[group]?.origin) ?? manifest.site.origin;
|
|
1608
|
+
if (!origin) return path;
|
|
1609
|
+
try {
|
|
1610
|
+
return new URL(path, `${origin}/`).toString();
|
|
1611
|
+
} catch {
|
|
1612
|
+
return path;
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
function navigationUrl(manifest, path, group) {
|
|
1616
|
+
let origin = manifest.groups[group]?.origin ?? manifest.site.origin;
|
|
1617
|
+
return !origin || origin === manifest.site.origin ? path : canonicalUrl(manifest, path, group);
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
// src/route-not-found.ts
|
|
1621
|
+
var UNSAFE_PATH_CHARACTERS = /[\p{Cc}\p{Cs}\u200b-\u200f\u2028-\u202f\u2060-\u206f\ufeff]/u;
|
|
1622
|
+
var DEFAULT_MARKDOWN = serializeNotFoundMarkdown({
|
|
1623
|
+
recommendations: [],
|
|
1624
|
+
indexes: []
|
|
1625
|
+
});
|
|
1626
|
+
function publicRecoveryHref(href) {
|
|
1627
|
+
if (href.includes("\\") || UNSAFE_PATH_CHARACTERS.test(href))
|
|
1628
|
+
return;
|
|
1629
|
+
let relative5 = href.startsWith("/") && !href.startsWith("//");
|
|
1630
|
+
try {
|
|
1631
|
+
let url = new URL(
|
|
1632
|
+
href,
|
|
1633
|
+
relative5 ? "https://publishos.invalid" : void 0
|
|
1634
|
+
);
|
|
1635
|
+
return !["http:", "https:"].includes(url.protocol) || url.username || url.password ? void 0 : relative5 ? `${url.pathname}${url.search}${url.hash}` : url.href;
|
|
1636
|
+
} catch {
|
|
1637
|
+
return;
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
function markdownText(value) {
|
|
1641
|
+
return value.replace(/\s+/gu, " ").replace(/[\p{Cc}\p{Cs}]/gu, "").trim().replace(/[\\`*_[\]{}<>|~]/gu, "\\$&");
|
|
1642
|
+
}
|
|
1643
|
+
function markdownLink(link) {
|
|
1644
|
+
let title = markdownText(link.title), href = publicRecoveryHref(link.href)?.replace(
|
|
1645
|
+
/[()`<>]/gu,
|
|
1646
|
+
(character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`
|
|
1647
|
+
);
|
|
1648
|
+
if (!title || !href) return;
|
|
1649
|
+
let description = link.description ? markdownText(link.description) : void 0;
|
|
1650
|
+
return `- [${title}](${href})${description ? `: ${description}` : ""}`;
|
|
1651
|
+
}
|
|
1652
|
+
function serializeNotFoundMarkdown({
|
|
1653
|
+
recommendations,
|
|
1654
|
+
indexes
|
|
1655
|
+
}) {
|
|
1656
|
+
let sections = [
|
|
1657
|
+
{ title: "Recommendations", links: recommendations },
|
|
1658
|
+
{ title: "For crawlers and agents", links: indexes }
|
|
1659
|
+
], lines = [
|
|
1660
|
+
"# 404 \u2014 Not Found",
|
|
1661
|
+
"",
|
|
1662
|
+
"This page does not exist. Please check the URL and try again.",
|
|
1663
|
+
""
|
|
1664
|
+
];
|
|
1665
|
+
for (let section of sections) {
|
|
1666
|
+
let links = section.links.map(markdownLink).filter((link) => link !== void 0);
|
|
1667
|
+
links.length && lines.push(`## ${section.title}`, "", ...links, "");
|
|
1668
|
+
}
|
|
1669
|
+
return lines.join(`
|
|
1670
|
+
`);
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
// src/lib/compiler/nextjs/not-found-plan.ts
|
|
1674
|
+
var belongsToPath = (path, base) => base === "/" || path === base || path.startsWith(`${base}/`), outputDirectory = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
1675
|
+
function orderedPagePaths(tree) {
|
|
1676
|
+
return tree.flatMap(
|
|
1677
|
+
(node) => node.type === "page" ? [node.path] : "children" in node ? orderedPagePaths(node.children) : []
|
|
1678
|
+
);
|
|
1679
|
+
}
|
|
1680
|
+
function createNotFoundScopes({
|
|
1681
|
+
manifest,
|
|
1682
|
+
outputs,
|
|
1683
|
+
rootOwnedGroups,
|
|
1684
|
+
markdownPaths = /* @__PURE__ */ new Set()
|
|
1685
|
+
}) {
|
|
1686
|
+
return [
|
|
1687
|
+
void 0,
|
|
1688
|
+
...Object.values(manifest.groups).filter(
|
|
1689
|
+
(group) => group.key !== ROOT_CONTENT_GROUP_KEY
|
|
1690
|
+
)
|
|
1691
|
+
].map((group) => {
|
|
1692
|
+
let path = group?.path ?? "/", origin = group?.origin ?? manifest.site.origin, rootOwned = !group || (rootOwnedGroups ? rootOwnedGroups.has(group.key) : origin === manifest.site.origin), groupKeys = new Set(group?.ancestry ?? []);
|
|
1693
|
+
group && groupKeys.add(group.key);
|
|
1694
|
+
let url = (route, key = group?.key) => canonicalUrl(manifest, route, key), recommendations = [];
|
|
1695
|
+
group && recommendations.push({
|
|
1696
|
+
title: `Back to ${group.title}`,
|
|
1697
|
+
href: url(group.path)
|
|
1698
|
+
});
|
|
1699
|
+
let visible = manifest.pages.filter(
|
|
1700
|
+
(page) => page.status === "published" && page.meta.hidden !== !0 && (manifest.groups[page.group]?.origin ?? manifest.site.origin) === origin && belongsToPath(page.path, path) && (!group || page.group === group.key || manifest.groups[page.group]?.ancestry?.includes(group.key))
|
|
1701
|
+
), byPath = new Map(visible.map((page) => [page.path, page])), first = orderedPagePaths(group?.tree ?? manifest.tree).map((entry) => byPath.get(entry)).find(Boolean) ?? visible[0];
|
|
1702
|
+
first && first.path !== path && recommendations.push({
|
|
1703
|
+
title: first.title,
|
|
1704
|
+
href: url(first.path, first.group)
|
|
1705
|
+
}), rootOwned && !recommendations.some((link) => link.href === url("/")) && recommendations.push({ title: "Go home", href: url("/") });
|
|
1706
|
+
let available = outputs.filter((output) => {
|
|
1707
|
+
let scopeGroup = output.scopeGroup ?? output.group;
|
|
1708
|
+
return (output.group && manifest.groups[output.group]?.origin || manifest.site.origin) !== origin || !output.group && !rootOwned || scopeGroup && group && output.scope !== "site" && !groupKeys.has(scopeGroup) || scopeGroup && !group && output.scope !== "site" || output.scope === "self" && scopeGroup !== group?.key ? !1 : belongsToPath(path, outputDirectory(output.path));
|
|
1709
|
+
}), choose = (kind) => available.filter((output) => output.kind === kind).sort(
|
|
1710
|
+
(a, b) => +!!a.group - +!!b.group || +(b.sitemaps !== void 0) - +(a.sitemaps !== void 0) || (manifest.groups[b.group ?? ""]?.path.length ?? 0) - (manifest.groups[a.group ?? ""]?.path.length ?? 0)
|
|
1711
|
+
)[0], sitemap = choose("sitemap") ?? choose("sitemap-md"), llms = choose("llms"), full = choose("llms-full"), nearestLlms = available.filter((output) => output.kind === "llms").sort(
|
|
1712
|
+
(a, b) => outputDirectory(b.path).length - outputDirectory(a.path).length || (manifest.groups[b.group ?? ""]?.path.length ?? 0) - (manifest.groups[a.group ?? ""]?.path.length ?? 0)
|
|
1713
|
+
)[0], indexes = [
|
|
1714
|
+
sitemap && {
|
|
1715
|
+
title: sitemap.kind === "sitemap-md" ? "Markdown sitemap" : "Sitemap",
|
|
1716
|
+
href: url(sitemap.path, sitemap.group),
|
|
1717
|
+
kind: sitemap.kind
|
|
1718
|
+
},
|
|
1719
|
+
llms && {
|
|
1720
|
+
title: "llms.txt",
|
|
1721
|
+
href: url(llms.path, llms.group),
|
|
1722
|
+
kind: "llms"
|
|
1723
|
+
},
|
|
1724
|
+
full && {
|
|
1725
|
+
title: "llms-full.txt",
|
|
1726
|
+
href: url(full.path, full.group),
|
|
1727
|
+
kind: "llms-full"
|
|
1728
|
+
}
|
|
1729
|
+
].filter(
|
|
1730
|
+
(link) => !!link
|
|
1731
|
+
), agentLink = (link) => {
|
|
1732
|
+
let page = visible.find(
|
|
1733
|
+
(candidate) => url(candidate.path, candidate.group) === link.href
|
|
1734
|
+
), markdownPath = page ? `${page.path}.md` : void 0;
|
|
1735
|
+
return markdownPath && markdownPaths.has(markdownPath) ? { ...link, href: url(markdownPath, page?.group) } : link;
|
|
1736
|
+
}, markdown = serializeNotFoundMarkdown({
|
|
1737
|
+
recommendations: recommendations.map(agentLink),
|
|
1738
|
+
indexes
|
|
1739
|
+
});
|
|
1740
|
+
return {
|
|
1741
|
+
id: group ? `g-${Buffer.from(group.key).toString("base64url")}` : "root",
|
|
1742
|
+
path,
|
|
1743
|
+
...group ? { group: group.key } : {},
|
|
1744
|
+
...origin ? { origin } : {},
|
|
1745
|
+
htmlPath: "/_not-found",
|
|
1746
|
+
recommendations,
|
|
1747
|
+
indexes,
|
|
1748
|
+
...nearestLlms ? { describedBy: url(nearestLlms.path, nearestLlms.group) } : {},
|
|
1749
|
+
markdown
|
|
1750
|
+
};
|
|
1751
|
+
}).sort(
|
|
1752
|
+
(a, b) => b.path.length - a.path.length || +!!b.group - +!!a.group
|
|
1753
|
+
);
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1318
1756
|
// src/lib/compiler/nextjs/route-layout-planner.ts
|
|
1319
1757
|
import { stat as stat2 } from "fs/promises";
|
|
1320
1758
|
import { resolve } from "path";
|
|
@@ -1442,11 +1880,12 @@ function fontReadErrorDetails(error) {
|
|
|
1442
1880
|
async function validateVariableFontFile({
|
|
1443
1881
|
configuredPath,
|
|
1444
1882
|
sourcePath,
|
|
1445
|
-
weight
|
|
1883
|
+
weight,
|
|
1884
|
+
contents
|
|
1446
1885
|
}) {
|
|
1447
1886
|
let font;
|
|
1448
1887
|
try {
|
|
1449
|
-
font = await fontkit.open(sourcePath);
|
|
1888
|
+
font = contents ? fontkit.create(contents) : await fontkit.open(sourcePath);
|
|
1450
1889
|
} catch (error) {
|
|
1451
1890
|
let details = fontReadErrorDetails(error);
|
|
1452
1891
|
throw details.reasonCode === "ENOENT" ? new AppError({
|
|
@@ -1762,7 +2201,7 @@ async function normalizedLogoDataUri(options) {
|
|
|
1762
2201
|
};
|
|
1763
2202
|
}
|
|
1764
2203
|
async function logoDataUri(options) {
|
|
1765
|
-
let output = options.
|
|
2204
|
+
let output = options.media.outputs.find(
|
|
1766
2205
|
(candidate) => candidate.outputPath === options.entry.outputPath
|
|
1767
2206
|
);
|
|
1768
2207
|
if (output) {
|
|
@@ -1788,7 +2227,7 @@ async function resolveOgLogo(options) {
|
|
|
1788
2227
|
if (!selected || !options.faviconsAndLogos) return;
|
|
1789
2228
|
let logoData = await logoDataUri({
|
|
1790
2229
|
entry: selected.entry,
|
|
1791
|
-
|
|
2230
|
+
media: options.media
|
|
1792
2231
|
});
|
|
1793
2232
|
return {
|
|
1794
2233
|
dataUri: logoData?.dataUri,
|
|
@@ -1871,8 +2310,7 @@ async function resolveOgFonts({
|
|
|
1871
2310
|
path: file.path,
|
|
1872
2311
|
sourceFile: "publish.os.config.json"
|
|
1873
2312
|
});
|
|
1874
|
-
let data =
|
|
1875
|
-
});
|
|
2313
|
+
let data = file.data;
|
|
1876
2314
|
if (!data || data.byteLength > MAX_OG_FONT_BYTES)
|
|
1877
2315
|
return;
|
|
1878
2316
|
let probe = fontProbe(data);
|
|
@@ -1911,9 +2349,6 @@ function fontProbe(data) {
|
|
|
1911
2349
|
return;
|
|
1912
2350
|
}
|
|
1913
2351
|
}
|
|
1914
|
-
function isRemoteImageAllowed(url, sources) {
|
|
1915
|
-
return sources.some((source) => source.protocol !== "https" || url.protocol !== "https:" || source.hostname !== url.hostname ? !1 : source.pathname ? url.pathname.startsWith(source.pathname) : !0);
|
|
1916
|
-
}
|
|
1917
2352
|
function imageSource(image) {
|
|
1918
2353
|
if (image)
|
|
1919
2354
|
return typeof image == "string" ? { src: image } : image;
|
|
@@ -1947,10 +2382,10 @@ function resolveExplicitImage(options) {
|
|
|
1947
2382
|
details: { image: source.src, routePath: options.routePath }
|
|
1948
2383
|
});
|
|
1949
2384
|
}
|
|
1950
|
-
if (
|
|
2385
|
+
if (url.protocol !== "https:")
|
|
1951
2386
|
throw new AppError({
|
|
1952
2387
|
code: "FRAMEWORK_OG_REMOTE_IMAGE_REJECTED",
|
|
1953
|
-
message: `Remote OG image "${source.src}" for route "${options.routePath}"
|
|
2388
|
+
message: `Remote OG image "${source.src}" for route "${options.routePath}" must use HTTPS`,
|
|
1954
2389
|
details: { image: source.src, routePath: options.routePath }
|
|
1955
2390
|
});
|
|
1956
2391
|
return { source: "remote", url: source.src, alt: source.alt };
|
|
@@ -2154,6 +2589,7 @@ async function buildOgManifest(options) {
|
|
|
2154
2589
|
},
|
|
2155
2590
|
logo: await resolveOgLogo({
|
|
2156
2591
|
faviconsAndLogos: options.faviconsAndLogos,
|
|
2592
|
+
media: options.media,
|
|
2157
2593
|
theme: colors.theme
|
|
2158
2594
|
})
|
|
2159
2595
|
}, groupGeneratedDefaults = Object.fromEntries(
|
|
@@ -2168,6 +2604,7 @@ async function buildOgManifest(options) {
|
|
|
2168
2604
|
...group?.origin ? { siteUrl: group.origin } : {},
|
|
2169
2605
|
logo: await resolveOgLogo({
|
|
2170
2606
|
faviconsAndLogos: options.faviconsAndLogos,
|
|
2607
|
+
media: options.media,
|
|
2171
2608
|
theme: routeColors.theme
|
|
2172
2609
|
})
|
|
2173
2610
|
}
|
|
@@ -2625,24 +3062,7 @@ async function materializeAppInstallation({
|
|
|
2625
3062
|
// src/lib/compiler/search/search-index.ts
|
|
2626
3063
|
import { mkdir as mkdir5, writeFile as writeFile5 } from "fs/promises";
|
|
2627
3064
|
import { dirname as dirname4, resolve as resolve3 } from "path";
|
|
2628
|
-
|
|
2629
|
-
// src/lib/runtime/metadata/canonical-url.ts
|
|
2630
|
-
function canonicalUrl(manifest, path, group) {
|
|
2631
|
-
let origin = (group && manifest.groups[group]?.origin) ?? manifest.site.origin;
|
|
2632
|
-
if (!origin) return path;
|
|
2633
|
-
try {
|
|
2634
|
-
return new URL(path, `${origin}/`).toString();
|
|
2635
|
-
} catch {
|
|
2636
|
-
return path;
|
|
2637
|
-
}
|
|
2638
|
-
}
|
|
2639
|
-
function navigationUrl(manifest, path, group) {
|
|
2640
|
-
let origin = manifest.groups[group]?.origin ?? manifest.site.origin;
|
|
2641
|
-
return !origin || origin === manifest.site.origin ? path : canonicalUrl(manifest, path, group);
|
|
2642
|
-
}
|
|
2643
|
-
|
|
2644
|
-
// src/lib/compiler/search/search-index.ts
|
|
2645
|
-
var SEARCH_BUNDLE_DIR = PUBLIC_PAGEFIND_DIRECTORY, SEARCH_INDEX_SCRIPT_PATH = "scripts/build-search-index.mjs", SEARCH_RECORDS_PATH = ".meta/search-records.json", SEARCH_STATUS_FILE = "publishos-search-status.json", SEARCH_INDEX_STATUS_MESSAGE = "Building search index...";
|
|
3065
|
+
var SEARCH_BUNDLE_DIR = PUBLIC_SEARCH_DIRECTORY, SEARCH_INDEX_SCRIPT_PATH = "scripts/build-search-index.mjs", SEARCH_RECORDS_PATH = ".meta/search-records.json", SEARCH_STATUS_FILE = "publishos-search-status.json", SEARCH_INDEX_STATUS_MESSAGE = "Building search index...";
|
|
2646
3066
|
function stringifyMetaValue(value) {
|
|
2647
3067
|
if (typeof value == "string" && value.trim()) return value;
|
|
2648
3068
|
if (typeof value == "number" || typeof value == "boolean")
|
|
@@ -2651,17 +3071,13 @@ function stringifyMetaValue(value) {
|
|
|
2651
3071
|
function pageAuthors(page) {
|
|
2652
3072
|
return page.authors.flatMap((author) => typeof author.name == "string" && author.name.trim() ? [author.name] : []);
|
|
2653
3073
|
}
|
|
2654
|
-
function pageContent(page) {
|
|
3074
|
+
function pageContent(page, conversions) {
|
|
2655
3075
|
return [
|
|
2656
3076
|
page.title,
|
|
2657
3077
|
page.description,
|
|
2658
3078
|
page.tags.join(" "),
|
|
2659
3079
|
pageAuthors(page).join(" "),
|
|
2660
|
-
|
|
2661
|
-
collectDiagnostics: !1,
|
|
2662
|
-
source: page.body,
|
|
2663
|
-
unknownComponentMode: "children"
|
|
2664
|
-
}).text
|
|
3080
|
+
conversions.get(page.path)?.text ?? ""
|
|
2665
3081
|
].filter(Boolean).join(`
|
|
2666
3082
|
|
|
2667
3083
|
`);
|
|
@@ -2689,9 +3105,9 @@ function pageMeta({
|
|
|
2689
3105
|
function pagesToIndex(manifest) {
|
|
2690
3106
|
return manifest.pages.filter((page) => page.status === "published").sort((a, b) => a.path.localeCompare(b.path));
|
|
2691
3107
|
}
|
|
2692
|
-
function createSearchRecords(manifest) {
|
|
3108
|
+
function createSearchRecords(manifest, conversions) {
|
|
2693
3109
|
return pagesToIndex(manifest).map((page) => ({
|
|
2694
|
-
content: pageContent(page),
|
|
3110
|
+
content: pageContent(page, conversions),
|
|
2695
3111
|
filters: {
|
|
2696
3112
|
author: pageAuthors(page),
|
|
2697
3113
|
group: [page.group],
|
|
@@ -2708,11 +3124,12 @@ function createSearchRecords(manifest) {
|
|
|
2708
3124
|
}));
|
|
2709
3125
|
}
|
|
2710
3126
|
async function writeSearchRecordsArtifact({
|
|
3127
|
+
conversions,
|
|
2711
3128
|
manifest,
|
|
2712
3129
|
outputDir
|
|
2713
3130
|
}) {
|
|
2714
3131
|
let artifact = {
|
|
2715
|
-
records: createSearchRecords(manifest)
|
|
3132
|
+
records: createSearchRecords(manifest, conversions)
|
|
2716
3133
|
}, filePath = resolve3(outputDir, SEARCH_RECORDS_PATH);
|
|
2717
3134
|
await mkdir5(dirname4(filePath), { recursive: !0 }), await writeFile5(filePath, `${JSON.stringify(artifact, null, 2)}
|
|
2718
3135
|
`, "utf-8");
|
|
@@ -2840,272 +3257,23 @@ try {
|
|
|
2840
3257
|
`;
|
|
2841
3258
|
}
|
|
2842
3259
|
|
|
2843
|
-
// src/lib/compiler/theme/
|
|
2844
|
-
import {
|
|
2845
|
-
import { dirname as dirname5,
|
|
2846
|
-
import
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
"popover",
|
|
2853
|
-
"select",
|
|
2854
|
-
"toast",
|
|
2855
|
-
"tooltip"
|
|
2856
|
-
], SOURCE_EXTENSIONS = [".js", ".jsx", ".md", ".mdx", ".mjs", ".ts", ".tsx"], IMPORT_PATTERN = /(?:\bfrom\s*|\bimport\s*\(\s*|\bimport\s*)["']([^"']+)["']/g;
|
|
2857
|
-
function sourceImports(content, path) {
|
|
2858
|
-
if ([".md", ".mdx"].includes(extname(path)))
|
|
2859
|
-
return {
|
|
2860
|
-
dynamic: !1,
|
|
2861
|
-
specifiers: [...content.matchAll(IMPORT_PATTERN)].flatMap(
|
|
2862
|
-
(match) => match[1] ? [match[1]] : []
|
|
2863
|
-
)
|
|
2864
|
-
};
|
|
2865
|
-
let source = ts2.createSourceFile(
|
|
2866
|
-
path,
|
|
2867
|
-
content,
|
|
2868
|
-
ts2.ScriptTarget.Latest,
|
|
2869
|
-
!1,
|
|
2870
|
-
ts2.ScriptKind.TSX
|
|
2871
|
-
), specifiers = [], dynamic = !1, visit = (node) => {
|
|
2872
|
-
if ((ts2.isImportDeclaration(node) || ts2.isExportDeclaration(node)) && node.moduleSpecifier && ts2.isStringLiteral(node.moduleSpecifier))
|
|
2873
|
-
specifiers.push(node.moduleSpecifier.text);
|
|
2874
|
-
else if (ts2.isCallExpression(node) && node.expression.kind === ts2.SyntaxKind.ImportKeyword) {
|
|
2875
|
-
let argument = node.arguments[0];
|
|
2876
|
-
argument && ts2.isStringLiteral(argument) ? specifiers.push(argument.text) : dynamic = !0;
|
|
2877
|
-
}
|
|
2878
|
-
ts2.forEachChild(node, visit);
|
|
2879
|
-
};
|
|
2880
|
-
return visit(source), { dynamic, specifiers };
|
|
2881
|
-
}
|
|
2882
|
-
function portable(path) {
|
|
2883
|
-
return path.split(sep).join("/");
|
|
2884
|
-
}
|
|
2885
|
-
async function fileExists2(path) {
|
|
2886
|
-
return stat3(path).then((entry) => entry.isFile()).catch(() => !1);
|
|
2887
|
-
}
|
|
2888
|
-
async function sourceFiles(dir, prefix = "") {
|
|
2889
|
-
let entries = await readdir2(dir, { withFileTypes: !0 }).catch(() => []), files = [];
|
|
2890
|
-
for (let entry of entries) {
|
|
2891
|
-
let relativePath = prefix ? `${prefix}/${entry.name}` : entry.name, path = resolve4(dir, entry.name);
|
|
2892
|
-
if (entry.isDirectory()) {
|
|
2893
|
-
if (relativePath === "components") continue;
|
|
2894
|
-
files.push(...await sourceFiles(path, relativePath));
|
|
2895
|
-
} else SOURCE_EXTENSIONS.includes(extname(entry.name)) && files.push(relativePath);
|
|
2896
|
-
}
|
|
2897
|
-
return files;
|
|
3260
|
+
// src/lib/compiler/theme/compile-theme-css.ts
|
|
3261
|
+
import { lstat as lstat2, stat as stat3 } from "fs/promises";
|
|
3262
|
+
import { dirname as dirname5, relative as relative2, resolve as resolve4, sep } from "path";
|
|
3263
|
+
import postcss2 from "postcss";
|
|
3264
|
+
import selectorParser from "postcss-selector-parser";
|
|
3265
|
+
import valueParser2 from "postcss-value-parser";
|
|
3266
|
+
var GROUP_CONDITIONAL_AT_RULES = /* @__PURE__ */ new Set(["container", "media", "supports"]), IMAGE_SET_FUNCTIONS2 = /* @__PURE__ */ new Set(["image-set", "-webkit-image-set"]);
|
|
3267
|
+
function fail(code, message, details) {
|
|
3268
|
+
throw new AppError({ code, message, details });
|
|
2898
3269
|
}
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
for (
|
|
2902
|
-
if (
|
|
2903
|
-
|
|
2904
|
-
let indexPath = resolve4(path, `index${extension}`);
|
|
2905
|
-
if (await fileExists2(indexPath)) return indexPath;
|
|
3270
|
+
function hasRuleAncestor(rule) {
|
|
3271
|
+
let parent = rule.parent;
|
|
3272
|
+
for (; parent; ) {
|
|
3273
|
+
if (parent.type === "rule") return !0;
|
|
3274
|
+
parent = parent.parent;
|
|
2906
3275
|
}
|
|
2907
|
-
|
|
2908
|
-
function resolveApplicationFile(application, path) {
|
|
2909
|
-
let candidates = [
|
|
2910
|
-
path,
|
|
2911
|
-
...SOURCE_EXTENSIONS.map((extension) => `${path}${extension}`),
|
|
2912
|
-
...SOURCE_EXTENSIONS.map((extension) => resolve4(path, `index${extension}`))
|
|
2913
|
-
];
|
|
2914
|
-
for (let candidate of candidates) {
|
|
2915
|
-
let file = application.get(candidate);
|
|
2916
|
-
if (file) return [candidate, file];
|
|
2917
|
-
}
|
|
2918
|
-
}
|
|
2919
|
-
function runtimeSubpath(specifier) {
|
|
2920
|
-
let prefix = "@publish.os/nextjs";
|
|
2921
|
-
if (specifier === prefix) return "index.js";
|
|
2922
|
-
if (!specifier.startsWith(`${prefix}/`)) return;
|
|
2923
|
-
let subpath = specifier.slice(prefix.length + 1);
|
|
2924
|
-
return subpath === "mdx" ? "kernel/components/mdx/mdx.js" : subpath.startsWith("mdx/") ? `kernel/components/mdx/${subpath.slice(4)}.js` : `${subpath}.js`;
|
|
2925
|
-
}
|
|
2926
|
-
function familyForPath(path) {
|
|
2927
|
-
let normalized = portable(path);
|
|
2928
|
-
return componentFamilies.find(
|
|
2929
|
-
(family) => new RegExp(`/components/ui/${family}\\.[cm]?[jt]sx?$`).test(normalized)
|
|
2930
|
-
);
|
|
2931
|
-
}
|
|
2932
|
-
async function publicTokensForFamily({
|
|
2933
|
-
family,
|
|
2934
|
-
runtimeDistDir
|
|
2935
|
-
}) {
|
|
2936
|
-
let path = resolve4(
|
|
2937
|
-
runtimeDistDir,
|
|
2938
|
-
"../compiler-assets/nextjs/defaults/root/css/components",
|
|
2939
|
-
`${family}.css`
|
|
2940
|
-
), css = await readFile4(path, "utf8").catch(() => "");
|
|
2941
|
-
return [
|
|
2942
|
-
...new Set(
|
|
2943
|
-
[...css.matchAll(new RegExp(`(--${family}-[a-z0-9-]+)\\s*:`, "g"))].map((match) => match[1]).filter((token) => !!token)
|
|
2944
|
-
)
|
|
2945
|
-
].sort();
|
|
2946
|
-
}
|
|
2947
|
-
async function createComponentManifest({
|
|
2948
|
-
applicationFiles,
|
|
2949
|
-
runtimeDistDir,
|
|
2950
|
-
sourceDir,
|
|
2951
|
-
editableCheckout = !1
|
|
2952
|
-
}) {
|
|
2953
|
-
let application = new Map(
|
|
2954
|
-
applicationFiles.map((file) => [
|
|
2955
|
-
resolve4(dirname5(sourceDir), file.path),
|
|
2956
|
-
file
|
|
2957
|
-
])
|
|
2958
|
-
), queue = [], visited = /* @__PURE__ */ new Set(), sources = /* @__PURE__ */ new Set(), sourceByKey = /* @__PURE__ */ new Map(), importsByKey = /* @__PURE__ */ new Map(), families = /* @__PURE__ */ new Set(), familyKeys = /* @__PURE__ */ new Map(), fallbackReasons = /* @__PURE__ */ new Set(), connect = (from, to) => {
|
|
2959
|
-
if (!to) return;
|
|
2960
|
-
let imports = importsByKey.get(from) ?? /* @__PURE__ */ new Set();
|
|
2961
|
-
imports.add(to), importsByKey.set(from, imports);
|
|
2962
|
-
};
|
|
2963
|
-
if (editableCheckout)
|
|
2964
|
-
for (let source of [
|
|
2965
|
-
"../app",
|
|
2966
|
-
"../source",
|
|
2967
|
-
"../node_modules/@publish.os/nextjs/src",
|
|
2968
|
-
"../node_modules/@publish.os/nextjs/compiler-assets/nextjs/defaults"
|
|
2969
|
-
])
|
|
2970
|
-
sources.add(source);
|
|
2971
|
-
for (let path of editableCheckout ? [] : await sourceFiles(sourceDir))
|
|
2972
|
-
queue.push({ kind: "local", path: resolve4(sourceDir, path) });
|
|
2973
|
-
for (let file of editableCheckout ? [] : applicationFiles)
|
|
2974
|
-
queue.push({
|
|
2975
|
-
content: file.content,
|
|
2976
|
-
key: resolve4(dirname5(sourceDir), file.path),
|
|
2977
|
-
kind: "application",
|
|
2978
|
-
path: file.path
|
|
2979
|
-
});
|
|
2980
|
-
let enqueueRuntime = async (specifier) => {
|
|
2981
|
-
let subpath = runtimeSubpath(specifier);
|
|
2982
|
-
if (!subpath) return;
|
|
2983
|
-
let path = resolve4(runtimeDistDir, subpath);
|
|
2984
|
-
if (!await fileExists2(path)) {
|
|
2985
|
-
fallbackReasons.add(`Missing runtime source for ${specifier}`);
|
|
2986
|
-
return;
|
|
2987
|
-
}
|
|
2988
|
-
return queue.push({ kind: "runtime", path }), path;
|
|
2989
|
-
};
|
|
2990
|
-
for (; queue.length > 0; ) {
|
|
2991
|
-
let entry = queue.shift();
|
|
2992
|
-
if (!entry) continue;
|
|
2993
|
-
let key = entry.kind === "application" ? entry.key : entry.path;
|
|
2994
|
-
if (visited.has(key)) continue;
|
|
2995
|
-
visited.add(key);
|
|
2996
|
-
let content = entry.kind === "application" ? entry.content : await readFile4(entry.path, "utf8"), imports = sourceImports(content, key);
|
|
2997
|
-
imports.dynamic && fallbackReasons.add(`Dynamic import in ${key}`);
|
|
2998
|
-
let source = entry.kind === "runtime" ? `../node_modules/@publish.os/nextjs/dist/${portable(relative2(runtimeDistDir, entry.path))}` : entry.kind === "application" ? `../${portable(entry.path)}` : `../source/${portable(relative2(sourceDir, entry.path))}`;
|
|
2999
|
-
sources.add(source), sourceByKey.set(key, source);
|
|
3000
|
-
let family = familyForPath(key);
|
|
3001
|
-
if (family) {
|
|
3002
|
-
families.add(family);
|
|
3003
|
-
let keys = familyKeys.get(family) ?? /* @__PURE__ */ new Set();
|
|
3004
|
-
keys.add(key), familyKeys.set(family, keys);
|
|
3005
|
-
}
|
|
3006
|
-
for (let specifier of imports.specifiers) {
|
|
3007
|
-
if (specifier.endsWith(".css")) continue;
|
|
3008
|
-
if (specifier.startsWith("@publish.os/nextjs")) {
|
|
3009
|
-
connect(key, await enqueueRuntime(specifier));
|
|
3010
|
-
continue;
|
|
3011
|
-
}
|
|
3012
|
-
if (specifier.startsWith("@components/")) {
|
|
3013
|
-
let componentPath = specifier.slice(12), local = await resolveSourceFile(
|
|
3014
|
-
resolve4(sourceDir, "components", componentPath)
|
|
3015
|
-
);
|
|
3016
|
-
local ? (connect(key, local), queue.push({ kind: "local", path: local })) : connect(
|
|
3017
|
-
key,
|
|
3018
|
-
await enqueueRuntime(
|
|
3019
|
-
`@publish.os/nextjs/kernel/components/${componentPath}`
|
|
3020
|
-
)
|
|
3021
|
-
);
|
|
3022
|
-
continue;
|
|
3023
|
-
}
|
|
3024
|
-
if (specifier.startsWith("@source/")) {
|
|
3025
|
-
let local = await resolveSourceFile(
|
|
3026
|
-
resolve4(sourceDir, specifier.slice(8))
|
|
3027
|
-
);
|
|
3028
|
-
local ? (connect(key, local), queue.push({ kind: "local", path: local })) : fallbackReasons.add(`Missing source import ${specifier} in ${key}`);
|
|
3029
|
-
continue;
|
|
3030
|
-
}
|
|
3031
|
-
if (!specifier.startsWith(".")) continue;
|
|
3032
|
-
let base = entry.kind === "application" ? dirname5(entry.key) : dirname5(entry.path), unresolvedTarget = resolve4(base, specifier), planned = resolveApplicationFile(application, unresolvedTarget);
|
|
3033
|
-
if (planned) {
|
|
3034
|
-
connect(key, planned[0]), queue.push({
|
|
3035
|
-
content: planned[1].content,
|
|
3036
|
-
key: planned[0],
|
|
3037
|
-
kind: "application",
|
|
3038
|
-
path: planned[1].path
|
|
3039
|
-
});
|
|
3040
|
-
continue;
|
|
3041
|
-
}
|
|
3042
|
-
let target = await resolveSourceFile(unresolvedTarget);
|
|
3043
|
-
target ? (connect(key, target), queue.push({
|
|
3044
|
-
kind: target.startsWith(runtimeDistDir) ? "runtime" : "local",
|
|
3045
|
-
path: target
|
|
3046
|
-
})) : fallbackReasons.add(`Missing relative import ${specifier} in ${key}`);
|
|
3047
|
-
}
|
|
3048
|
-
}
|
|
3049
|
-
let fallback = fallbackReasons.size > 0, activeFamilies = fallback || editableCheckout ? [...componentFamilies] : [...families].sort();
|
|
3050
|
-
fallback && sources.add("../node_modules/@publish.os/nextjs/dist/**/*.js");
|
|
3051
|
-
let componentEntries = await Promise.all(
|
|
3052
|
-
activeFamilies.map(async (family) => {
|
|
3053
|
-
let familySources = /* @__PURE__ */ new Set();
|
|
3054
|
-
if (editableCheckout)
|
|
3055
|
-
for (let source of sources) familySources.add(source);
|
|
3056
|
-
let pending = [...familyKeys.get(family) ?? []], traced = /* @__PURE__ */ new Set();
|
|
3057
|
-
for (; pending.length > 0; ) {
|
|
3058
|
-
let key = pending.pop();
|
|
3059
|
-
if (!key || traced.has(key)) continue;
|
|
3060
|
-
traced.add(key);
|
|
3061
|
-
let source = sourceByKey.get(key);
|
|
3062
|
-
source && familySources.add(source), pending.push(...importsByKey.get(key) ?? []);
|
|
3063
|
-
}
|
|
3064
|
-
return fallback && familySources.add("../node_modules/@publish.os/nextjs/dist/**/*.js"), [
|
|
3065
|
-
family,
|
|
3066
|
-
{
|
|
3067
|
-
optionalCss: `./css/components/${family}.css`,
|
|
3068
|
-
publicTokenPrefix: `--${family}-`,
|
|
3069
|
-
publicTokens: await publicTokensForFamily({
|
|
3070
|
-
family,
|
|
3071
|
-
runtimeDistDir
|
|
3072
|
-
}),
|
|
3073
|
-
source: `@publish.os/nextjs/kernel/components/ui/${family}`,
|
|
3074
|
-
sources: [...familySources].sort()
|
|
3075
|
-
}
|
|
3076
|
-
];
|
|
3077
|
-
})
|
|
3078
|
-
);
|
|
3079
|
-
return {
|
|
3080
|
-
components: Object.fromEntries(componentEntries),
|
|
3081
|
-
fallback,
|
|
3082
|
-
fallbackReasons: [...fallbackReasons].sort(),
|
|
3083
|
-
families: activeFamilies,
|
|
3084
|
-
sources: [...sources].sort()
|
|
3085
|
-
};
|
|
3086
|
-
}
|
|
3087
|
-
|
|
3088
|
-
// src/lib/compiler/theme/create-theme-build-plan.ts
|
|
3089
|
-
import { readFile as readFile5, stat as stat5 } from "fs/promises";
|
|
3090
|
-
import { dirname as dirname7, resolve as resolve6 } from "path";
|
|
3091
|
-
|
|
3092
|
-
// src/lib/compiler/theme/compile-theme-css.ts
|
|
3093
|
-
import { stat as stat4 } from "fs/promises";
|
|
3094
|
-
import { dirname as dirname6, relative as relative3, resolve as resolve5, sep as sep2 } from "path";
|
|
3095
|
-
import postcss from "postcss";
|
|
3096
|
-
import selectorParser from "postcss-selector-parser";
|
|
3097
|
-
import valueParser from "postcss-value-parser";
|
|
3098
|
-
var GROUP_CONDITIONAL_AT_RULES = /* @__PURE__ */ new Set(["container", "media", "supports"]), IMAGE_SET_FUNCTIONS = /* @__PURE__ */ new Set(["image-set", "-webkit-image-set"]);
|
|
3099
|
-
function fail(code, message, details) {
|
|
3100
|
-
throw new AppError({ code, message, details });
|
|
3101
|
-
}
|
|
3102
|
-
function hasRuleAncestor(rule) {
|
|
3103
|
-
let parent = rule.parent;
|
|
3104
|
-
for (; parent; ) {
|
|
3105
|
-
if (parent.type === "rule") return !0;
|
|
3106
|
-
parent = parent.parent;
|
|
3107
|
-
}
|
|
3108
|
-
return !1;
|
|
3276
|
+
return !1;
|
|
3109
3277
|
}
|
|
3110
3278
|
function rejectGlobalSelector(selector, sourcePath) {
|
|
3111
3279
|
let globalElement;
|
|
@@ -3133,7 +3301,7 @@ function scopeGroupThemeCss({
|
|
|
3133
3301
|
scopeSelectors,
|
|
3134
3302
|
sourcePath
|
|
3135
3303
|
}) {
|
|
3136
|
-
let root =
|
|
3304
|
+
let root = postcss2.parse(css, { from: sourcePath });
|
|
3137
3305
|
return root.walkAtRules((atRule) => {
|
|
3138
3306
|
GROUP_CONDITIONAL_AT_RULES.has(atRule.name.toLowerCase()) || fail(
|
|
3139
3307
|
"FRAMEWORK_GROUP_THEME_GLOBAL_AT_RULE",
|
|
@@ -3163,14 +3331,146 @@ function urlKind(value) {
|
|
|
3163
3331
|
let trimmed = value.trim();
|
|
3164
3332
|
return trimmed.startsWith("#") ? "fragment" : trimmed.startsWith("//") || /^[a-z][a-z0-9+.-]*:/i.test(trimmed) ? "unsafe" : trimmed.startsWith("/") ? "root" : "relative";
|
|
3165
3333
|
}
|
|
3166
|
-
async function
|
|
3167
|
-
return
|
|
3334
|
+
async function fileExists2(path) {
|
|
3335
|
+
return stat3(path).then((entry) => entry.isFile()).catch(() => !1);
|
|
3168
3336
|
}
|
|
3169
3337
|
function portablePath(path) {
|
|
3170
|
-
return path.split(
|
|
3338
|
+
return path.split(sep).join("/");
|
|
3339
|
+
}
|
|
3340
|
+
var FONT_EXTENSIONS = /* @__PURE__ */ new Set(["woff", "woff2", "ttf", "otf"]);
|
|
3341
|
+
function validFontResource(contents, extension) {
|
|
3342
|
+
if (extension === "woff" || extension === "woff2") {
|
|
3343
|
+
let signature2 = extension === "woff" ? "wOFF" : "wOF2", headerBytes = extension === "woff" ? 44 : 48;
|
|
3344
|
+
return contents.length >= headerBytes && contents.toString("ascii", 0, 4) === signature2 && contents.readUInt32BE(8) === contents.length && contents.readUInt16BE(12) > 0;
|
|
3345
|
+
}
|
|
3346
|
+
if (contents.length < 12) return !1;
|
|
3347
|
+
let signature = contents.toString("ascii", 0, 4), truetype = contents.readUInt32BE(0) === 65536;
|
|
3348
|
+
if (extension === "ttf" && signature !== "true" && !truetype || extension === "otf" && signature !== "OTTO" && !truetype) return !1;
|
|
3349
|
+
let tables = contents.readUInt16BE(4);
|
|
3350
|
+
if (tables === 0 || tables > 4096 || 12 + tables * 16 > contents.length)
|
|
3351
|
+
return !1;
|
|
3352
|
+
for (let index = 0; index < tables; index += 1) {
|
|
3353
|
+
let table = 12 + index * 16, offset = contents.readUInt32BE(table + 8), length = contents.readUInt32BE(table + 12);
|
|
3354
|
+
if (offset > contents.length || length > contents.length - offset)
|
|
3355
|
+
return !1;
|
|
3356
|
+
}
|
|
3357
|
+
return !0;
|
|
3358
|
+
}
|
|
3359
|
+
function createThemeResourceAdmission({
|
|
3360
|
+
media,
|
|
3361
|
+
publishOsDir
|
|
3362
|
+
}) {
|
|
3363
|
+
let limits = mediaAssetBudgets(), baseBytes = media?.manifest.totals.bytes ?? 0, baseCount = media?.manifest.totals.count ?? 0, admitted = /* @__PURE__ */ new Map(), mediaPaths = /* @__PURE__ */ new Map();
|
|
3364
|
+
for (let entry of Object.values(media?.manifest.assets ?? {})) {
|
|
3365
|
+
let sourcePrefix = "publish.os/";
|
|
3366
|
+
entry.sourcePath.startsWith(sourcePrefix) && mediaPaths.set(
|
|
3367
|
+
resolve4(publishOsDir, entry.sourcePath.slice(sourcePrefix.length)),
|
|
3368
|
+
entry.outputPath
|
|
3369
|
+
);
|
|
3370
|
+
}
|
|
3371
|
+
let additionalBytes = 0;
|
|
3372
|
+
return {
|
|
3373
|
+
assets: admitted,
|
|
3374
|
+
async admit({
|
|
3375
|
+
filePath,
|
|
3376
|
+
relativePath,
|
|
3377
|
+
sourcePath
|
|
3378
|
+
}) {
|
|
3379
|
+
let existingMediaPath = mediaPaths.get(sourcePath);
|
|
3380
|
+
if (existingMediaPath)
|
|
3381
|
+
return { urlPath: `/${existingMediaPath.replace(/^\/+/, "")}` };
|
|
3382
|
+
let existing = admitted.get(sourcePath);
|
|
3383
|
+
if (existing)
|
|
3384
|
+
return {
|
|
3385
|
+
asset: existing,
|
|
3386
|
+
urlPath: themeResourceUrlPath(existing.outputPath)
|
|
3387
|
+
};
|
|
3388
|
+
let limit = themeResourceByteLimit(relativePath);
|
|
3389
|
+
if (limit === void 0)
|
|
3390
|
+
throw new AppError({
|
|
3391
|
+
code: "FRAMEWORK_MEDIA_TYPE_REJECTED",
|
|
3392
|
+
message: `${relativePath} is not an allowed theme resource type`,
|
|
3393
|
+
details: { path: relativePath }
|
|
3394
|
+
});
|
|
3395
|
+
let entry = await lstat2(sourcePath);
|
|
3396
|
+
if (!entry.isFile() || entry.isSymbolicLink())
|
|
3397
|
+
throw new AppError({
|
|
3398
|
+
code: "FRAMEWORK_SOURCE_DEPENDENCY_NOT_FILE",
|
|
3399
|
+
message: "A theme resource must be a regular file.",
|
|
3400
|
+
details: { file: filePath, target: relativePath }
|
|
3401
|
+
});
|
|
3402
|
+
if (entry.size > limit)
|
|
3403
|
+
throw mediaFileTooLarge({
|
|
3404
|
+
relativePath,
|
|
3405
|
+
bytes: entry.size,
|
|
3406
|
+
limit
|
|
3407
|
+
});
|
|
3408
|
+
let remainingBytes = limits.maxTotalBytes - baseBytes - additionalBytes, reservedTotalBytes = baseBytes + additionalBytes + entry.size;
|
|
3409
|
+
if (reservedTotalBytes > limits.maxTotalBytes)
|
|
3410
|
+
throw new AppError({
|
|
3411
|
+
code: "FRAMEWORK_MEDIA_TOTAL_TOO_LARGE",
|
|
3412
|
+
message: `Theme resources and publish.os/assets total ${reservedTotalBytes} bytes, exceeding the limit of ${limits.maxTotalBytes}`,
|
|
3413
|
+
details: { bytes: reservedTotalBytes, limit: limits.maxTotalBytes }
|
|
3414
|
+
});
|
|
3415
|
+
let totalCount = baseCount + admitted.size + 1;
|
|
3416
|
+
if (totalCount > limits.maxFileCount)
|
|
3417
|
+
throw new AppError({
|
|
3418
|
+
code: "FRAMEWORK_MEDIA_FILE_COUNT_EXCEEDED",
|
|
3419
|
+
message: `Theme resources and publish.os/assets contain more than ${limits.maxFileCount} files, exceeding the limit of ${limits.maxFileCount}`,
|
|
3420
|
+
details: { count: totalCount, limit: limits.maxFileCount }
|
|
3421
|
+
});
|
|
3422
|
+
let contents = await readBoundedMediaFile({
|
|
3423
|
+
path: sourcePath,
|
|
3424
|
+
relativePath,
|
|
3425
|
+
limit: Math.min(limit, remainingBytes),
|
|
3426
|
+
expectedIdentity: { dev: entry.dev, ino: entry.ino }
|
|
3427
|
+
});
|
|
3428
|
+
if (contents.byteLength > limit)
|
|
3429
|
+
throw mediaFileTooLarge({
|
|
3430
|
+
relativePath,
|
|
3431
|
+
bytes: contents.byteLength,
|
|
3432
|
+
limit
|
|
3433
|
+
});
|
|
3434
|
+
if (contents.byteLength > remainingBytes) {
|
|
3435
|
+
let totalBytes = baseBytes + additionalBytes + contents.byteLength;
|
|
3436
|
+
throw new AppError({
|
|
3437
|
+
code: "FRAMEWORK_MEDIA_TOTAL_TOO_LARGE",
|
|
3438
|
+
message: `Theme resources and publish.os/assets total ${totalBytes} bytes, exceeding the limit of ${limits.maxTotalBytes}`,
|
|
3439
|
+
details: { bytes: totalBytes, limit: limits.maxTotalBytes }
|
|
3440
|
+
});
|
|
3441
|
+
}
|
|
3442
|
+
let extension = relativePath.split(".").at(-1)?.toLowerCase() ?? "", admittedContents;
|
|
3443
|
+
if (FONT_EXTENSIONS.has(extension)) {
|
|
3444
|
+
if (!validFontResource(contents, extension))
|
|
3445
|
+
throw new AppError({
|
|
3446
|
+
code: "FRAMEWORK_THEME_FONT_INVALID",
|
|
3447
|
+
message: `${relativePath} is not a valid ${extension.toUpperCase()} font`,
|
|
3448
|
+
details: { path: relativePath }
|
|
3449
|
+
});
|
|
3450
|
+
admittedContents = contents;
|
|
3451
|
+
} else
|
|
3452
|
+
admittedContents = (await admitThemeImageResource({ contents, relativePath })).contents;
|
|
3453
|
+
let admittedTotalBytes = baseBytes + additionalBytes + admittedContents.byteLength;
|
|
3454
|
+
if (admittedTotalBytes > limits.maxTotalBytes)
|
|
3455
|
+
throw new AppError({
|
|
3456
|
+
code: "FRAMEWORK_MEDIA_TOTAL_TOO_LARGE",
|
|
3457
|
+
message: `Theme resources and publish.os/assets total ${admittedTotalBytes} bytes, exceeding the limit of ${limits.maxTotalBytes}`,
|
|
3458
|
+
details: { bytes: admittedTotalBytes, limit: limits.maxTotalBytes }
|
|
3459
|
+
});
|
|
3460
|
+
let projectPath = portablePath(relative2(publishOsDir, sourcePath)), asset = {
|
|
3461
|
+
contents: admittedContents,
|
|
3462
|
+
outputPath: `${PUBLIC_INTERNAL_DIRECTORY}/themes/${projectPath}`,
|
|
3463
|
+
sourcePath
|
|
3464
|
+
};
|
|
3465
|
+
return admitted.set(sourcePath, asset), additionalBytes += admittedContents.byteLength, {
|
|
3466
|
+
asset,
|
|
3467
|
+
urlPath: themeResourceUrlPath(asset.outputPath)
|
|
3468
|
+
};
|
|
3469
|
+
}
|
|
3470
|
+
};
|
|
3171
3471
|
}
|
|
3172
3472
|
function cssUrlReferences(value) {
|
|
3173
|
-
let parsed =
|
|
3473
|
+
let parsed = valueParser2(value), references = [];
|
|
3174
3474
|
return parsed.walk((node) => {
|
|
3175
3475
|
if (node.type !== "function") return;
|
|
3176
3476
|
let functionName = node.value.toLowerCase();
|
|
@@ -3184,10 +3484,10 @@ function cssUrlReferences(value) {
|
|
|
3184
3484
|
valueNode.value = nextValue;
|
|
3185
3485
|
}
|
|
3186
3486
|
} : {},
|
|
3187
|
-
value: valueNode?.value ??
|
|
3487
|
+
value: valueNode?.value ?? valueParser2.stringify(node.nodes).trim()
|
|
3188
3488
|
}), !1;
|
|
3189
3489
|
}
|
|
3190
|
-
if (
|
|
3490
|
+
if (IMAGE_SET_FUNCTIONS2.has(functionName))
|
|
3191
3491
|
for (let child of node.nodes)
|
|
3192
3492
|
child.type === "string" && references.push({
|
|
3193
3493
|
set: (nextValue) => {
|
|
@@ -3204,18 +3504,23 @@ function pathAndSuffix(url) {
|
|
|
3204
3504
|
suffix: url.slice(suffixIndex)
|
|
3205
3505
|
};
|
|
3206
3506
|
}
|
|
3507
|
+
function themeResourceUrlPath(outputPath) {
|
|
3508
|
+
return `/${outputPath.replace(/^\/+/, "").split("/").map((segment) => encodeURIComponent(segment)).join("/")}`;
|
|
3509
|
+
}
|
|
3207
3510
|
async function rewriteThemeCssUrls({
|
|
3208
3511
|
css,
|
|
3209
3512
|
filePath,
|
|
3210
3513
|
publishOsDir,
|
|
3514
|
+
media,
|
|
3515
|
+
resourceAdmission,
|
|
3211
3516
|
scopeRoot
|
|
3212
3517
|
}) {
|
|
3213
|
-
let root =
|
|
3518
|
+
let admission = resourceAdmission ?? createThemeResourceAdmission({ media, publishOsDir }), root = postcss2.parse(css, { from: filePath }), assets = /* @__PURE__ */ new Map(), warnings = /* @__PURE__ */ new Map(), declarations = [];
|
|
3214
3519
|
root.walkDecls((declaration) => {
|
|
3215
3520
|
declarations.push(declaration);
|
|
3216
3521
|
});
|
|
3217
3522
|
for (let declaration of declarations) {
|
|
3218
|
-
let { parsed, references } = cssUrlReferences(declaration.value);
|
|
3523
|
+
let { parsed, references } = cssUrlReferences(declaration.value), declarationAssets = /* @__PURE__ */ new Map(), preparedReferences = [], ignoredDeclaration = !1;
|
|
3219
3524
|
for (let reference of references) {
|
|
3220
3525
|
let url = decodeCssPath(reference.value);
|
|
3221
3526
|
reference.set || fail(
|
|
@@ -3227,33 +3532,313 @@ async function rewriteThemeCssUrls({
|
|
|
3227
3532
|
if (kind === "unsafe" && fail(
|
|
3228
3533
|
"FRAMEWORK_THEME_URL_REJECTED",
|
|
3229
3534
|
"Theme CSS contains an unsafe URL.",
|
|
3230
|
-
{
|
|
3231
|
-
source: filePath,
|
|
3232
|
-
url
|
|
3233
|
-
}
|
|
3535
|
+
{ source: filePath, url }
|
|
3234
3536
|
), kind !== "relative") continue;
|
|
3235
|
-
let { path, suffix } = pathAndSuffix(url), sourcePath =
|
|
3537
|
+
let { path, suffix } = pathAndSuffix(url), sourcePath = resolve4(dirname5(filePath), path);
|
|
3236
3538
|
isSameOrDescendant(scopeRoot, sourcePath) || fail(
|
|
3237
3539
|
"FRAMEWORK_THEME_URL_ESCAPE",
|
|
3238
3540
|
"Theme CSS assets cannot escape their theme scope.",
|
|
3239
3541
|
{ source: filePath, url }
|
|
3240
|
-
)
|
|
3542
|
+
);
|
|
3543
|
+
let projectPath = portablePath(relative2(publishOsDir, sourcePath));
|
|
3544
|
+
await fileExists2(sourcePath) || fail(
|
|
3241
3545
|
"FRAMEWORK_THEME_ASSET_MISSING",
|
|
3242
3546
|
"A theme CSS asset does not exist.",
|
|
3243
|
-
{
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3547
|
+
{ source: filePath, url }
|
|
3548
|
+
), await assertSourceDependency({
|
|
3549
|
+
publishOsDir,
|
|
3550
|
+
path: sourcePath,
|
|
3551
|
+
sourceFile: filePath
|
|
3552
|
+
});
|
|
3553
|
+
let ignoredDocument = ignoredMediaDocumentWarning(projectPath);
|
|
3554
|
+
if (ignoredDocument) {
|
|
3555
|
+
warnings.set(projectPath, { ...ignoredDocument, level: "warning" }), ignoredDeclaration = !0;
|
|
3556
|
+
continue;
|
|
3557
|
+
}
|
|
3558
|
+
if (isHiddenMediaPath(projectPath)) {
|
|
3559
|
+
warnings.set(projectPath, {
|
|
3560
|
+
...ignoredMediaPathWarning(projectPath),
|
|
3561
|
+
level: "warning"
|
|
3562
|
+
}), ignoredDeclaration = !0;
|
|
3563
|
+
continue;
|
|
3564
|
+
}
|
|
3565
|
+
preparedReferences.push({
|
|
3566
|
+
set: reference.set,
|
|
3567
|
+
suffix,
|
|
3568
|
+
sourcePath,
|
|
3569
|
+
projectPath
|
|
3570
|
+
});
|
|
3571
|
+
}
|
|
3572
|
+
if (ignoredDeclaration) {
|
|
3573
|
+
declaration.remove();
|
|
3574
|
+
continue;
|
|
3575
|
+
}
|
|
3576
|
+
for (let { set, suffix, sourcePath, projectPath } of preparedReferences) {
|
|
3577
|
+
let admitted = await admission.admit({
|
|
3578
|
+
filePath,
|
|
3579
|
+
relativePath: projectPath,
|
|
3580
|
+
sourcePath
|
|
3581
|
+
});
|
|
3582
|
+
admitted.asset && declarationAssets.set(sourcePath, admitted.asset), set(`${admitted.urlPath}${suffix}`);
|
|
3583
|
+
}
|
|
3584
|
+
for (let [path, asset] of declarationAssets) assets.set(path, asset);
|
|
3585
|
+
declaration.value = parsed.toString();
|
|
3586
|
+
}
|
|
3587
|
+
return {
|
|
3588
|
+
assets: [...assets.values()],
|
|
3589
|
+
css: root.toString(),
|
|
3590
|
+
warnings: [...warnings.values()]
|
|
3591
|
+
};
|
|
3592
|
+
}
|
|
3593
|
+
|
|
3594
|
+
// src/lib/compiler/theme/component-manifest.ts
|
|
3595
|
+
import { readdir as readdir2, readFile as readFile4, stat as stat4 } from "fs/promises";
|
|
3596
|
+
import { dirname as dirname6, extname, relative as relative3, resolve as resolve5, sep as sep2 } from "path";
|
|
3597
|
+
import ts2 from "typescript";
|
|
3598
|
+
var componentFamilies = [
|
|
3599
|
+
"dialog",
|
|
3600
|
+
"drawer",
|
|
3601
|
+
"menu",
|
|
3602
|
+
"navigation-menu",
|
|
3603
|
+
"popover",
|
|
3604
|
+
"select",
|
|
3605
|
+
"toast",
|
|
3606
|
+
"tooltip"
|
|
3607
|
+
], SOURCE_EXTENSIONS = [".js", ".jsx", ".md", ".mdx", ".mjs", ".ts", ".tsx"], IMPORT_PATTERN = /(?:\bfrom\s*|\bimport\s*\(\s*|\bimport\s*)["']([^"']+)["']/g;
|
|
3608
|
+
function sourceImports(content, path) {
|
|
3609
|
+
if ([".md", ".mdx"].includes(extname(path)))
|
|
3610
|
+
return {
|
|
3611
|
+
dynamic: !1,
|
|
3612
|
+
specifiers: [...content.matchAll(IMPORT_PATTERN)].flatMap(
|
|
3613
|
+
(match) => match[1] ? [match[1]] : []
|
|
3614
|
+
)
|
|
3615
|
+
};
|
|
3616
|
+
let source = ts2.createSourceFile(
|
|
3617
|
+
path,
|
|
3618
|
+
content,
|
|
3619
|
+
ts2.ScriptTarget.Latest,
|
|
3620
|
+
!1,
|
|
3621
|
+
ts2.ScriptKind.TSX
|
|
3622
|
+
), specifiers = [], dynamic = !1, visit = (node) => {
|
|
3623
|
+
if ((ts2.isImportDeclaration(node) || ts2.isExportDeclaration(node)) && node.moduleSpecifier && ts2.isStringLiteral(node.moduleSpecifier))
|
|
3624
|
+
specifiers.push(node.moduleSpecifier.text);
|
|
3625
|
+
else if (ts2.isCallExpression(node) && node.expression.kind === ts2.SyntaxKind.ImportKeyword) {
|
|
3626
|
+
let argument = node.arguments[0];
|
|
3627
|
+
argument && ts2.isStringLiteral(argument) ? specifiers.push(argument.text) : dynamic = !0;
|
|
3628
|
+
}
|
|
3629
|
+
ts2.forEachChild(node, visit);
|
|
3630
|
+
};
|
|
3631
|
+
return visit(source), { dynamic, specifiers };
|
|
3632
|
+
}
|
|
3633
|
+
function portable(path) {
|
|
3634
|
+
return path.split(sep2).join("/");
|
|
3635
|
+
}
|
|
3636
|
+
async function fileExists3(path) {
|
|
3637
|
+
return stat4(path).then((entry) => entry.isFile()).catch(() => !1);
|
|
3638
|
+
}
|
|
3639
|
+
async function sourceFiles(dir, prefix = "") {
|
|
3640
|
+
let entries = await readdir2(dir, { withFileTypes: !0 }).catch(() => []), files = [];
|
|
3641
|
+
for (let entry of entries) {
|
|
3642
|
+
let relativePath = prefix ? `${prefix}/${entry.name}` : entry.name, path = resolve5(dir, entry.name);
|
|
3643
|
+
if (entry.isDirectory()) {
|
|
3644
|
+
if (relativePath === "components") continue;
|
|
3645
|
+
files.push(...await sourceFiles(path, relativePath));
|
|
3646
|
+
} else SOURCE_EXTENSIONS.includes(extname(entry.name)) && files.push(relativePath);
|
|
3647
|
+
}
|
|
3648
|
+
return files;
|
|
3649
|
+
}
|
|
3650
|
+
async function resolveSourceFile(path) {
|
|
3651
|
+
if (await fileExists3(path)) return path;
|
|
3652
|
+
for (let extension of SOURCE_EXTENSIONS)
|
|
3653
|
+
if (await fileExists3(`${path}${extension}`)) return `${path}${extension}`;
|
|
3654
|
+
for (let extension of SOURCE_EXTENSIONS) {
|
|
3655
|
+
let indexPath = resolve5(path, `index${extension}`);
|
|
3656
|
+
if (await fileExists3(indexPath)) return indexPath;
|
|
3657
|
+
}
|
|
3658
|
+
}
|
|
3659
|
+
function resolveApplicationFile(application, path) {
|
|
3660
|
+
let candidates = [
|
|
3661
|
+
path,
|
|
3662
|
+
...SOURCE_EXTENSIONS.map((extension) => `${path}${extension}`),
|
|
3663
|
+
...SOURCE_EXTENSIONS.map((extension) => resolve5(path, `index${extension}`))
|
|
3664
|
+
];
|
|
3665
|
+
for (let candidate of candidates) {
|
|
3666
|
+
let file = application.get(candidate);
|
|
3667
|
+
if (file) return [candidate, file];
|
|
3668
|
+
}
|
|
3669
|
+
}
|
|
3670
|
+
function runtimeSubpath(specifier) {
|
|
3671
|
+
let prefix = "@publish.os/nextjs";
|
|
3672
|
+
if (specifier === prefix) return "index.js";
|
|
3673
|
+
if (!specifier.startsWith(`${prefix}/`)) return;
|
|
3674
|
+
let requestedSubpath = specifier.slice(prefix.length + 1), subpath = nextjs_runtime_surface_default.entryAliases[requestedSubpath] ?? requestedSubpath;
|
|
3675
|
+
return subpath === "mdx" ? "kernel/components/mdx/mdx.js" : subpath.startsWith("mdx/") ? `kernel/components/mdx/${subpath.slice(4)}.js` : `${subpath}.js`;
|
|
3676
|
+
}
|
|
3677
|
+
function familyForPath(path) {
|
|
3678
|
+
let normalized = portable(path);
|
|
3679
|
+
return componentFamilies.find(
|
|
3680
|
+
(family) => new RegExp(`/components/ui/${family}\\.[cm]?[jt]sx?$`).test(normalized)
|
|
3681
|
+
);
|
|
3682
|
+
}
|
|
3683
|
+
async function publicTokensForFamily({
|
|
3684
|
+
family,
|
|
3685
|
+
runtimeDistDir
|
|
3686
|
+
}) {
|
|
3687
|
+
let path = resolve5(
|
|
3688
|
+
runtimeDistDir,
|
|
3689
|
+
"../compiler-assets/nextjs/defaults/root/css/components",
|
|
3690
|
+
`${family}.css`
|
|
3691
|
+
), css = await readFile4(path, "utf8").catch(() => "");
|
|
3692
|
+
return [
|
|
3693
|
+
...new Set(
|
|
3694
|
+
[...css.matchAll(new RegExp(`(--${family}-[a-z0-9-]+)\\s*:`, "g"))].map((match) => match[1]).filter((token) => !!token)
|
|
3695
|
+
)
|
|
3696
|
+
].sort();
|
|
3697
|
+
}
|
|
3698
|
+
async function createComponentManifest({
|
|
3699
|
+
applicationFiles,
|
|
3700
|
+
runtimeDistDir,
|
|
3701
|
+
sourceDir,
|
|
3702
|
+
editableCheckout = !1
|
|
3703
|
+
}) {
|
|
3704
|
+
let application = new Map(
|
|
3705
|
+
applicationFiles.map((file) => [
|
|
3706
|
+
resolve5(dirname6(sourceDir), file.path),
|
|
3707
|
+
file
|
|
3708
|
+
])
|
|
3709
|
+
), queue = [], visited = /* @__PURE__ */ new Set(), sources = /* @__PURE__ */ new Set(), sourceByKey = /* @__PURE__ */ new Map(), importsByKey = /* @__PURE__ */ new Map(), families = /* @__PURE__ */ new Set(), familyKeys = /* @__PURE__ */ new Map(), fallbackReasons = /* @__PURE__ */ new Set(), connect = (from, to) => {
|
|
3710
|
+
if (!to) return;
|
|
3711
|
+
let imports = importsByKey.get(from) ?? /* @__PURE__ */ new Set();
|
|
3712
|
+
imports.add(to), importsByKey.set(from, imports);
|
|
3713
|
+
};
|
|
3714
|
+
if (editableCheckout)
|
|
3715
|
+
for (let source of [
|
|
3716
|
+
"../app",
|
|
3717
|
+
"../source",
|
|
3718
|
+
"../node_modules/@publish.os/nextjs/src",
|
|
3719
|
+
"../node_modules/@publish.os/nextjs/compiler-assets/nextjs/defaults"
|
|
3720
|
+
])
|
|
3721
|
+
sources.add(source);
|
|
3722
|
+
for (let path of editableCheckout ? [] : await sourceFiles(sourceDir))
|
|
3723
|
+
queue.push({ kind: "local", path: resolve5(sourceDir, path) });
|
|
3724
|
+
for (let file of editableCheckout ? [] : applicationFiles)
|
|
3725
|
+
queue.push({
|
|
3726
|
+
content: file.content,
|
|
3727
|
+
key: resolve5(dirname6(sourceDir), file.path),
|
|
3728
|
+
kind: "application",
|
|
3729
|
+
path: file.path
|
|
3730
|
+
});
|
|
3731
|
+
let enqueueRuntime = async (specifier) => {
|
|
3732
|
+
let subpath = runtimeSubpath(specifier);
|
|
3733
|
+
if (!subpath) return;
|
|
3734
|
+
let path = resolve5(runtimeDistDir, subpath);
|
|
3735
|
+
if (!await fileExists3(path)) {
|
|
3736
|
+
fallbackReasons.add(`Missing runtime source for ${specifier}`);
|
|
3737
|
+
return;
|
|
3738
|
+
}
|
|
3739
|
+
return queue.push({ kind: "runtime", path }), path;
|
|
3740
|
+
};
|
|
3741
|
+
for (; queue.length > 0; ) {
|
|
3742
|
+
let entry = queue.shift();
|
|
3743
|
+
if (!entry) continue;
|
|
3744
|
+
let key = entry.kind === "application" ? entry.key : entry.path;
|
|
3745
|
+
if (visited.has(key)) continue;
|
|
3746
|
+
visited.add(key);
|
|
3747
|
+
let content = entry.kind === "application" ? entry.content : await readFile4(entry.path, "utf8"), imports = sourceImports(content, key);
|
|
3748
|
+
imports.dynamic && fallbackReasons.add(`Dynamic import in ${key}`);
|
|
3749
|
+
let source = entry.kind === "runtime" ? `../node_modules/@publish.os/nextjs/dist/${portable(relative3(runtimeDistDir, entry.path))}` : entry.kind === "application" ? `../${portable(entry.path)}` : `../source/${portable(relative3(sourceDir, entry.path))}`;
|
|
3750
|
+
sources.add(source), sourceByKey.set(key, source);
|
|
3751
|
+
let family = familyForPath(key);
|
|
3752
|
+
if (family) {
|
|
3753
|
+
families.add(family);
|
|
3754
|
+
let keys = familyKeys.get(family) ?? /* @__PURE__ */ new Set();
|
|
3755
|
+
keys.add(key), familyKeys.set(family, keys);
|
|
3756
|
+
}
|
|
3757
|
+
for (let specifier of imports.specifiers) {
|
|
3758
|
+
if (specifier.endsWith(".css")) continue;
|
|
3759
|
+
if (specifier.startsWith("@publish.os/nextjs")) {
|
|
3760
|
+
connect(key, await enqueueRuntime(specifier));
|
|
3761
|
+
continue;
|
|
3762
|
+
}
|
|
3763
|
+
if (specifier.startsWith("@components/")) {
|
|
3764
|
+
let componentPath = specifier.slice(12), local = await resolveSourceFile(
|
|
3765
|
+
resolve5(sourceDir, "components", componentPath)
|
|
3766
|
+
);
|
|
3767
|
+
local ? (connect(key, local), queue.push({ kind: "local", path: local })) : connect(
|
|
3768
|
+
key,
|
|
3769
|
+
await enqueueRuntime(
|
|
3770
|
+
`@publish.os/nextjs/kernel/components/${componentPath}`
|
|
3771
|
+
)
|
|
3772
|
+
);
|
|
3773
|
+
continue;
|
|
3774
|
+
}
|
|
3775
|
+
if (specifier.startsWith("@source/")) {
|
|
3776
|
+
let local = await resolveSourceFile(
|
|
3777
|
+
resolve5(sourceDir, specifier.slice(8))
|
|
3778
|
+
);
|
|
3779
|
+
local ? (connect(key, local), queue.push({ kind: "local", path: local })) : fallbackReasons.add(`Missing source import ${specifier} in ${key}`);
|
|
3780
|
+
continue;
|
|
3781
|
+
}
|
|
3782
|
+
if (!specifier.startsWith(".")) continue;
|
|
3783
|
+
let base = entry.kind === "application" ? dirname6(entry.key) : dirname6(entry.path), unresolvedTarget = resolve5(base, specifier), planned = resolveApplicationFile(application, unresolvedTarget);
|
|
3784
|
+
if (planned) {
|
|
3785
|
+
connect(key, planned[0]), queue.push({
|
|
3786
|
+
content: planned[1].content,
|
|
3787
|
+
key: planned[0],
|
|
3788
|
+
kind: "application",
|
|
3789
|
+
path: planned[1].path
|
|
3790
|
+
});
|
|
3791
|
+
continue;
|
|
3792
|
+
}
|
|
3793
|
+
let target = await resolveSourceFile(unresolvedTarget);
|
|
3794
|
+
target ? (connect(key, target), queue.push({
|
|
3795
|
+
kind: target.startsWith(runtimeDistDir) ? "runtime" : "local",
|
|
3796
|
+
path: target
|
|
3797
|
+
})) : fallbackReasons.add(`Missing relative import ${specifier} in ${key}`);
|
|
3250
3798
|
}
|
|
3251
|
-
declaration.value = parsed.toString();
|
|
3252
3799
|
}
|
|
3253
|
-
|
|
3800
|
+
let fallback = fallbackReasons.size > 0, activeFamilies = fallback || editableCheckout ? [...componentFamilies] : [...families].sort();
|
|
3801
|
+
fallback && sources.add("../node_modules/@publish.os/nextjs/dist/**/*.js");
|
|
3802
|
+
let componentEntries = await Promise.all(
|
|
3803
|
+
activeFamilies.map(async (family) => {
|
|
3804
|
+
let familySources = /* @__PURE__ */ new Set();
|
|
3805
|
+
if (editableCheckout)
|
|
3806
|
+
for (let source of sources) familySources.add(source);
|
|
3807
|
+
let pending = [...familyKeys.get(family) ?? []], traced = /* @__PURE__ */ new Set();
|
|
3808
|
+
for (; pending.length > 0; ) {
|
|
3809
|
+
let key = pending.pop();
|
|
3810
|
+
if (!key || traced.has(key)) continue;
|
|
3811
|
+
traced.add(key);
|
|
3812
|
+
let source = sourceByKey.get(key);
|
|
3813
|
+
source && familySources.add(source), pending.push(...importsByKey.get(key) ?? []);
|
|
3814
|
+
}
|
|
3815
|
+
return fallback && familySources.add("../node_modules/@publish.os/nextjs/dist/**/*.js"), [
|
|
3816
|
+
family,
|
|
3817
|
+
{
|
|
3818
|
+
optionalCss: `./css/components/${family}.css`,
|
|
3819
|
+
publicTokenPrefix: `--${family}-`,
|
|
3820
|
+
publicTokens: await publicTokensForFamily({
|
|
3821
|
+
family,
|
|
3822
|
+
runtimeDistDir
|
|
3823
|
+
}),
|
|
3824
|
+
source: `@publish.os/nextjs/kernel/components/ui/${family}`,
|
|
3825
|
+
sources: [...familySources].sort()
|
|
3826
|
+
}
|
|
3827
|
+
];
|
|
3828
|
+
})
|
|
3829
|
+
);
|
|
3830
|
+
return {
|
|
3831
|
+
components: Object.fromEntries(componentEntries),
|
|
3832
|
+
fallback,
|
|
3833
|
+
fallbackReasons: [...fallbackReasons].sort(),
|
|
3834
|
+
families: activeFamilies,
|
|
3835
|
+
sources: [...sources].sort()
|
|
3836
|
+
};
|
|
3254
3837
|
}
|
|
3255
3838
|
|
|
3256
3839
|
// src/lib/compiler/theme/create-theme-build-plan.ts
|
|
3840
|
+
import { readFile as readFile5, stat as stat5 } from "fs/promises";
|
|
3841
|
+
import { dirname as dirname7, resolve as resolve6 } from "path";
|
|
3257
3842
|
var GROUP_KEY_PATTERN = /^[a-z0-9/-]+$/, installedFramework = readInstalledFrameworkLocation(), THEME_DEFAULTS_PATH = resolve6(
|
|
3258
3843
|
installedFramework.packageRoot,
|
|
3259
3844
|
"compiler-assets/nextjs/shims/theme-defaults.css"
|
|
@@ -3288,6 +3873,8 @@ async function inlineLocalCssImports({
|
|
|
3288
3873
|
rootDir,
|
|
3289
3874
|
publishOsDir,
|
|
3290
3875
|
assets,
|
|
3876
|
+
resourceAdmission,
|
|
3877
|
+
onWarning,
|
|
3291
3878
|
seen = /* @__PURE__ */ new Set()
|
|
3292
3879
|
}) {
|
|
3293
3880
|
seen.has(filePath) && fail2("FRAMEWORK_THEME_IMPORT_CYCLE", "Theme CSS imports contain a cycle.", {
|
|
@@ -3301,9 +3888,16 @@ async function inlineLocalCssImports({
|
|
|
3301
3888
|
css: await readFile5(filePath, "utf-8"),
|
|
3302
3889
|
filePath,
|
|
3303
3890
|
publishOsDir,
|
|
3891
|
+
resourceAdmission,
|
|
3304
3892
|
scopeRoot: rootDir
|
|
3305
3893
|
});
|
|
3306
3894
|
for (let asset of rewritten.assets) assets.set(asset.sourcePath, asset);
|
|
3895
|
+
for (let warning of rewritten.warnings)
|
|
3896
|
+
onWarning?.({
|
|
3897
|
+
code: warning.code,
|
|
3898
|
+
message: warning.message,
|
|
3899
|
+
...typeof warning.details?.file == "string" ? { file: warning.details.file } : {}
|
|
3900
|
+
});
|
|
3307
3901
|
assertNoThemeModeCssVariables(rewritten.css, filePath);
|
|
3308
3902
|
let imports = cssImports({ css: rewritten.css }).map((statement) => {
|
|
3309
3903
|
statement.path.startsWith(".") || fail2(
|
|
@@ -3317,26 +3911,27 @@ async function inlineLocalCssImports({
|
|
|
3317
3911
|
"Theme CSS imports cannot escape their publish.os scope.",
|
|
3318
3912
|
{ importPath: statement.path, source: filePath }
|
|
3319
3913
|
), { ...statement, path };
|
|
3320
|
-
}), importedCss =
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3914
|
+
}), importedCss = [];
|
|
3915
|
+
for (let statement of imports) {
|
|
3916
|
+
let body = await inlineLocalCssImports({
|
|
3917
|
+
filePath: statement.path,
|
|
3918
|
+
rootDir,
|
|
3919
|
+
publishOsDir,
|
|
3920
|
+
assets,
|
|
3921
|
+
resourceAdmission,
|
|
3922
|
+
onWarning,
|
|
3923
|
+
seen: new Set(seen)
|
|
3924
|
+
});
|
|
3925
|
+
statement.media && (body = `@media ${statement.media} {
|
|
3330
3926
|
${body}
|
|
3331
3927
|
}`), statement.supports && (body = `@supports ${/^[^():]+:/.test(
|
|
3332
|
-
|
|
3333
|
-
|
|
3928
|
+
statement.supports.replace(/\/\*[\s\S]*?\*\//g, " ")
|
|
3929
|
+
) ? `(${statement.supports})` : statement.supports} {
|
|
3334
3930
|
${body}
|
|
3335
3931
|
}`), statement.layer !== void 0 && (body = `@layer${statement.layer === !0 ? "" : ` ${statement.layer}`} {
|
|
3336
3932
|
${body}
|
|
3337
|
-
}`), body;
|
|
3338
|
-
|
|
3339
|
-
);
|
|
3933
|
+
}`), importedCss.push(body);
|
|
3934
|
+
}
|
|
3340
3935
|
return imports.reduceRight(
|
|
3341
3936
|
(body, statement, index) => `${body.slice(0, statement.start)}${importedCss[index] ?? ""}${body.slice(statement.end)}`,
|
|
3342
3937
|
rewritten.css
|
|
@@ -3423,7 +4018,10 @@ function ogInput({
|
|
|
3423
4018
|
}
|
|
3424
4019
|
async function createThemeBuildPlan({
|
|
3425
4020
|
config,
|
|
3426
|
-
publishOsDir
|
|
4021
|
+
publishOsDir,
|
|
4022
|
+
media,
|
|
4023
|
+
resourceAdmission: suppliedResourceAdmission,
|
|
4024
|
+
onWarning
|
|
3427
4025
|
}) {
|
|
3428
4026
|
let sources = /* @__PURE__ */ new Map(), rootSource = await themeSource({
|
|
3429
4027
|
folderPath: publishOsDir,
|
|
@@ -3439,41 +4037,46 @@ async function createThemeBuildPlan({
|
|
|
3439
4037
|
source && sources.set(group.key, source);
|
|
3440
4038
|
})
|
|
3441
4039
|
);
|
|
3442
|
-
let assets = /* @__PURE__ */ new Map(),
|
|
4040
|
+
let assets = /* @__PURE__ */ new Map(), resourceAdmission = suppliedResourceAdmission ?? createThemeResourceAdmission({ media, publishOsDir }), warnedFiles = /* @__PURE__ */ new Set(), warn = (warning) => {
|
|
4041
|
+
warning.file && warnedFiles.has(warning.file) || (warning.file && warnedFiles.add(warning.file), onWarning?.(warning));
|
|
4042
|
+
}, defaultsTemplate = await readFile5(THEME_DEFAULTS_PATH, "utf-8"), rootCss = rootSource ? await inlineLocalCssImports({
|
|
3443
4043
|
filePath: rootSource.filePath,
|
|
3444
4044
|
rootDir: publishOsDir,
|
|
3445
4045
|
publishOsDir,
|
|
3446
|
-
assets
|
|
4046
|
+
assets,
|
|
4047
|
+
resourceAdmission,
|
|
4048
|
+
onWarning: warn
|
|
3447
4049
|
}) : "", groups = {};
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
if (!source || group.key === ROOT_CONTENT_GROUP_KEY) {
|
|
3452
|
-
groups[group.key] = {
|
|
3453
|
-
css: "",
|
|
3454
|
-
hasCss: !1,
|
|
3455
|
-
selector: selectors.join(`,
|
|
3456
|
-
`)
|
|
3457
|
-
};
|
|
3458
|
-
return;
|
|
3459
|
-
}
|
|
3460
|
-
let authoredCss = await inlineLocalCssImports({
|
|
3461
|
-
filePath: source.filePath,
|
|
3462
|
-
rootDir: group.folderPath,
|
|
3463
|
-
publishOsDir,
|
|
3464
|
-
assets
|
|
3465
|
-
});
|
|
4050
|
+
for (let group of Object.values(config.groups)) {
|
|
4051
|
+
let source = sources.get(group.key), selectors = groupSelectors(config, group);
|
|
4052
|
+
if (!source || group.key === ROOT_CONTENT_GROUP_KEY) {
|
|
3466
4053
|
groups[group.key] = {
|
|
3467
|
-
css:
|
|
4054
|
+
css: "",
|
|
4055
|
+
hasCss: !1,
|
|
4056
|
+
selector: selectors.join(`,
|
|
4057
|
+
`)
|
|
4058
|
+
};
|
|
4059
|
+
continue;
|
|
4060
|
+
}
|
|
4061
|
+
let authoredCss = await inlineLocalCssImports({
|
|
4062
|
+
filePath: source.filePath,
|
|
4063
|
+
rootDir: group.folderPath,
|
|
4064
|
+
publishOsDir,
|
|
4065
|
+
assets,
|
|
4066
|
+
resourceAdmission,
|
|
4067
|
+
onWarning: warn
|
|
4068
|
+
});
|
|
4069
|
+
groups[group.key] = {
|
|
4070
|
+
css: `/* ${group.key} */
|
|
3468
4071
|
${derivedThemeCss(defaultsTemplate, selectors.join(`,
|
|
3469
4072
|
`))}${scopeGroupThemeCss({ css: authoredCss, scopeSelectors: selectors, sourcePath: source.relativePath })}
|
|
3470
4073
|
`,
|
|
3471
|
-
|
|
3472
|
-
|
|
4074
|
+
hasCss: !0,
|
|
4075
|
+
selector: selectors.join(`,
|
|
3473
4076
|
`)
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
4077
|
+
};
|
|
4078
|
+
}
|
|
4079
|
+
return {
|
|
3477
4080
|
assets: [...assets.values()].sort(
|
|
3478
4081
|
(left, right) => left.sourcePath.localeCompare(right.sourcePath)
|
|
3479
4082
|
),
|
|
@@ -3486,6 +4089,206 @@ ${derivedThemeCss(defaultsTemplate, selectors.join(`,
|
|
|
3486
4089
|
};
|
|
3487
4090
|
}
|
|
3488
4091
|
|
|
4092
|
+
// src/lib/runtime/metadata/discovery-content.ts
|
|
4093
|
+
function discoveryOrigin(manifest, group) {
|
|
4094
|
+
return (group ? manifest.groups[group]?.origin : void 0) ?? manifest.site.origin;
|
|
4095
|
+
}
|
|
4096
|
+
function pathWithin(path, basePath) {
|
|
4097
|
+
return basePath === "/" || path === basePath || path.startsWith(`${basePath}/`);
|
|
4098
|
+
}
|
|
4099
|
+
function discoveryPages({
|
|
4100
|
+
manifest,
|
|
4101
|
+
group,
|
|
4102
|
+
scope,
|
|
4103
|
+
limit
|
|
4104
|
+
}) {
|
|
4105
|
+
let origin = discoveryOrigin(manifest, group), basePath = group ? manifest.groups[group]?.path ?? "/" : "/", pages = manifest.pages.filter((page) => page.status !== "published" || discoveryOrigin(manifest, page.group) !== origin ? !1 : !group || scope === "site" ? !0 : pathWithin(page.path, basePath) ? page.group === group || scope !== "self" && page.group.startsWith(`${group}/`) : !1);
|
|
4106
|
+
return limit ? pages.slice(0, limit) : pages;
|
|
4107
|
+
}
|
|
4108
|
+
function groupDiscoveryPages({
|
|
4109
|
+
manifest,
|
|
4110
|
+
pages
|
|
4111
|
+
}) {
|
|
4112
|
+
let sections = /* @__PURE__ */ new Map();
|
|
4113
|
+
for (let page of pages) {
|
|
4114
|
+
let group = manifest.groups[page.group], key = group ? page.group : "", section = sections.get(key);
|
|
4115
|
+
section || (section = {
|
|
4116
|
+
...group ? { group: page.group } : {},
|
|
4117
|
+
title: group ? group.key === "__root" ? manifest.site.name : group.title : "Pages",
|
|
4118
|
+
pages: []
|
|
4119
|
+
}, sections.set(key, section)), section.pages.push(page);
|
|
4120
|
+
}
|
|
4121
|
+
return [...sections.values()].sort(
|
|
4122
|
+
(a, b) => (manifest.groups[a.group ?? ""]?.path ?? "/").localeCompare(
|
|
4123
|
+
manifest.groups[b.group ?? ""]?.path ?? "/"
|
|
4124
|
+
) || a.title.localeCompare(b.title)
|
|
4125
|
+
);
|
|
4126
|
+
}
|
|
4127
|
+
|
|
4128
|
+
// src/lib/runtime/metadata/feed-serialization.ts
|
|
4129
|
+
function xmlEscape(value) {
|
|
4130
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
4131
|
+
}
|
|
4132
|
+
function latestDate(pages) {
|
|
4133
|
+
let timestamp = Math.max(
|
|
4134
|
+
0,
|
|
4135
|
+
...pages.map((page) => {
|
|
4136
|
+
let date = page.publishedAt ?? page.updatedAt;
|
|
4137
|
+
if (!date) return -1 / 0;
|
|
4138
|
+
let parsed = Date.parse(date);
|
|
4139
|
+
return Number.isNaN(parsed) ? -1 / 0 : parsed;
|
|
4140
|
+
})
|
|
4141
|
+
);
|
|
4142
|
+
return new Date(timestamp).toISOString();
|
|
4143
|
+
}
|
|
4144
|
+
function serializeRssFeed(input) {
|
|
4145
|
+
let description = input.description ?? input.title, items = input.pages.map((page) => {
|
|
4146
|
+
let publishedAt = page.publishedAt, pubDate = publishedAt ? `
|
|
4147
|
+
<pubDate>${xmlEscape(new Date(publishedAt).toUTCString())}</pubDate>` : "", itemDescription = page.description ? `
|
|
4148
|
+
<description>${xmlEscape(page.description)}</description>` : "";
|
|
4149
|
+
return ` <item>
|
|
4150
|
+
<title>${xmlEscape(page.title)}</title>
|
|
4151
|
+
<link>${xmlEscape(page.url)}</link>
|
|
4152
|
+
<guid>${xmlEscape(page.url)}</guid>${pubDate}${itemDescription}
|
|
4153
|
+
</item>`;
|
|
4154
|
+
}).join(`
|
|
4155
|
+
`);
|
|
4156
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
4157
|
+
<rss version="2.0">
|
|
4158
|
+
<channel>
|
|
4159
|
+
<title>${xmlEscape(input.title)}</title>
|
|
4160
|
+
<link>${xmlEscape(input.homeUrl)}</link>
|
|
4161
|
+
<description>${xmlEscape(description)}</description>
|
|
4162
|
+
${items}
|
|
4163
|
+
</channel>
|
|
4164
|
+
</rss>
|
|
4165
|
+
`;
|
|
4166
|
+
}
|
|
4167
|
+
function serializeAtomFeed(input) {
|
|
4168
|
+
let entries = input.pages.map((page) => {
|
|
4169
|
+
let date = page.publishedAt ?? page.updatedAt, updated = date ? new Date(date).toISOString() : latestDate([]), summary = page.description ? `
|
|
4170
|
+
<summary>${xmlEscape(page.description)}</summary>` : "";
|
|
4171
|
+
return ` <entry>
|
|
4172
|
+
<title>${xmlEscape(page.title)}</title>
|
|
4173
|
+
<id>${xmlEscape(page.url)}</id>
|
|
4174
|
+
<link href="${xmlEscape(page.url)}" />
|
|
4175
|
+
<updated>${xmlEscape(updated)}</updated>${summary}
|
|
4176
|
+
</entry>`;
|
|
4177
|
+
}).join(`
|
|
4178
|
+
`);
|
|
4179
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
4180
|
+
<feed xmlns="http://www.w3.org/2005/Atom">
|
|
4181
|
+
<title>${xmlEscape(input.title)}</title>
|
|
4182
|
+
<id>${xmlEscape(input.homeUrl)}</id>
|
|
4183
|
+
<updated>${xmlEscape(latestDate(input.pages))}</updated>
|
|
4184
|
+
${entries}
|
|
4185
|
+
</feed>
|
|
4186
|
+
`;
|
|
4187
|
+
}
|
|
4188
|
+
function serializeJsonFeed(input) {
|
|
4189
|
+
return `${JSON.stringify(
|
|
4190
|
+
{
|
|
4191
|
+
version: "https://jsonfeed.org/version/1.1",
|
|
4192
|
+
title: input.title,
|
|
4193
|
+
description: input.description,
|
|
4194
|
+
home_page_url: input.homeUrl,
|
|
4195
|
+
items: input.pages.map((page) => ({
|
|
4196
|
+
id: page.url,
|
|
4197
|
+
url: page.url,
|
|
4198
|
+
title: page.title,
|
|
4199
|
+
summary: page.description,
|
|
4200
|
+
content_text: page.body,
|
|
4201
|
+
date_published: page.publishedAt,
|
|
4202
|
+
date_modified: page.updatedAt,
|
|
4203
|
+
tags: page.tags
|
|
4204
|
+
}))
|
|
4205
|
+
},
|
|
4206
|
+
null,
|
|
4207
|
+
2
|
|
4208
|
+
)}
|
|
4209
|
+
`;
|
|
4210
|
+
}
|
|
4211
|
+
|
|
4212
|
+
// src/lib/runtime/metadata/llms-serialization.ts
|
|
4213
|
+
function inlineText(value) {
|
|
4214
|
+
return value.replace(/[\r\n]+/g, " ").replace(/([\\`*_[\]<>])/g, "\\$1");
|
|
4215
|
+
}
|
|
4216
|
+
function markdownLink2(link) {
|
|
4217
|
+
let url = link.url.replace(
|
|
4218
|
+
/[\s()<>]/g,
|
|
4219
|
+
(value) => value === "(" ? "%28" : value === ")" ? "%29" : encodeURIComponent(value)
|
|
4220
|
+
);
|
|
4221
|
+
return `[${inlineText(link.title)}](${url})`;
|
|
4222
|
+
}
|
|
4223
|
+
function serializeLlmsIndex(input) {
|
|
4224
|
+
let body = (input.sections ?? [
|
|
4225
|
+
{ title: "Pages", pages: input.pages ?? [] }
|
|
4226
|
+
]).map((section) => {
|
|
4227
|
+
let lines = [
|
|
4228
|
+
...(section.links ?? []).map((link) => `- ${markdownLink2(link)}`),
|
|
4229
|
+
...section.pages.map((page) => {
|
|
4230
|
+
let description = input.includeDescriptions && page.description ? `: ${inlineText(page.description)}` : "", alternate = page.alternate ? ` (${markdownLink2(page.alternate)})` : "";
|
|
4231
|
+
return `- ${markdownLink2(page)}${alternate}${description}`;
|
|
4232
|
+
})
|
|
4233
|
+
];
|
|
4234
|
+
return `## ${inlineText(section.title)}
|
|
4235
|
+
|
|
4236
|
+
${lines.join(`
|
|
4237
|
+
`)}`;
|
|
4238
|
+
}).join(`
|
|
4239
|
+
|
|
4240
|
+
`), linkLines = (input.links ?? []).map(
|
|
4241
|
+
(link) => `- ${markdownLink2(link)}`
|
|
4242
|
+
), linkSection = linkLines.length ? `
|
|
4243
|
+
|
|
4244
|
+
## Group LLM indexes
|
|
4245
|
+
|
|
4246
|
+
${linkLines.join(`
|
|
4247
|
+
`)}` : "", otherGroupLines = (input.otherGroupLinks ?? []).map(
|
|
4248
|
+
(link) => `- ${markdownLink2(link)}`
|
|
4249
|
+
), otherGroupSection = otherGroupLines.length ? `
|
|
4250
|
+
|
|
4251
|
+
## Other content groups
|
|
4252
|
+
|
|
4253
|
+
${otherGroupLines.join(`
|
|
4254
|
+
`)}` : "";
|
|
4255
|
+
return `# ${inlineText(input.title)}
|
|
4256
|
+
|
|
4257
|
+
> ${inlineText(input.summary)}
|
|
4258
|
+
|
|
4259
|
+
${body}${linkSection}${otherGroupSection}
|
|
4260
|
+
`;
|
|
4261
|
+
}
|
|
4262
|
+
function serializeLlmsFull(input) {
|
|
4263
|
+
let encoder = new TextEncoder(), byteLength = (value) => encoder.encode(value).byteLength, references = [
|
|
4264
|
+
input.indexUrl ? `> LLMS index: ${input.indexUrl}` : void 0,
|
|
4265
|
+
input.sitemapUrl ? `> Sitemap: ${input.sitemapUrl}` : void 0
|
|
4266
|
+
].filter(Boolean).join(`
|
|
4267
|
+
`), header = `# ${input.title} Full Content
|
|
4268
|
+
|
|
4269
|
+
${references ? `${references}
|
|
4270
|
+
|
|
4271
|
+
` : ""}`, sections = [], totalBytes = byteLength(header), included = 0, truncated = !1;
|
|
4272
|
+
for (let artifact of [...input.artifacts].sort(
|
|
4273
|
+
(a, b) => a.markdownPath.localeCompare(b.markdownPath)
|
|
4274
|
+
)) {
|
|
4275
|
+
let section = `---
|
|
4276
|
+
|
|
4277
|
+
${artifact.body.trim()}
|
|
4278
|
+
|
|
4279
|
+
`, sectionBytes = byteLength(section);
|
|
4280
|
+
if (totalBytes + sectionBytes > input.maxBytes) {
|
|
4281
|
+
truncated = !0;
|
|
4282
|
+
break;
|
|
4283
|
+
}
|
|
4284
|
+
sections.push(section), totalBytes += sectionBytes, included += 1;
|
|
4285
|
+
}
|
|
4286
|
+
let footer = truncated ? `
|
|
4287
|
+
> Truncated at ${included} of ${input.totalCount ?? input.artifacts.length} Markdown pages to stay under ${input.maxBytes} bytes.
|
|
4288
|
+
` : "";
|
|
4289
|
+
return `${header}${sections.join("")}${footer}`;
|
|
4290
|
+
}
|
|
4291
|
+
|
|
3489
4292
|
// src/lib/compiler/nextjs/compose.ts
|
|
3490
4293
|
var BANNER = `// AUTO-GENERATED by the PublishOS framework - do not edit.
|
|
3491
4294
|
`, MARKDOWN_ARTIFACT_SHARD_MAX_BYTES = 256e3, MARKDOWN_ARTIFACT_SHARD_MAX_PAGES = 250, DEFAULT_LLMS_FULL_MAX_BYTES = 1e6;
|
|
@@ -3510,31 +4313,29 @@ function assertComposeOutputDirSafe(options) {
|
|
|
3510
4313
|
function childRouteDir(routeDir, child) {
|
|
3511
4314
|
return routeDir ? `${routeDir}/${child}` : child;
|
|
3512
4315
|
}
|
|
3513
|
-
var installedFramework2 = readInstalledFrameworkLocation(), KERNEL_DIR = resolve7(installedFramework2.packageRoot, "compiler-assets"), NEXTJS_KERNEL_DIR = resolve7(KERNEL_DIR, "nextjs"), DEFAULTS_DIR = resolve7(NEXTJS_KERNEL_DIR, "defaults"), SHIMS_DIR = resolve7(NEXTJS_KERNEL_DIR, "shims"), RUNTIME_DIST_DIR = resolve7(installedFramework2.packageRoot, "dist")
|
|
3514
|
-
"design-system-page.tsx",
|
|
3515
|
-
"design-system-progress-page.tsx",
|
|
3516
|
-
"design-system-links-page.tsx"
|
|
3517
|
-
];
|
|
3518
|
-
async function hasDirectDesignSystemRoute() {
|
|
3519
|
-
let files = await Promise.all(
|
|
3520
|
-
DIRECT_DESIGN_SYSTEM_SHIMS.map(async (file) => ({
|
|
3521
|
-
file,
|
|
3522
|
-
present: await fileExists5(resolve7(DIRECT_SHIMS_DIR, file))
|
|
3523
|
-
}))
|
|
3524
|
-
);
|
|
3525
|
-
if (!files.some(({ present }) => present)) return !1;
|
|
3526
|
-
let missing = files.filter(({ present }) => !present).map(({ file }) => file);
|
|
3527
|
-
if (missing.length > 0)
|
|
3528
|
-
throw new AppError({
|
|
3529
|
-
code: "FRAMEWORK_RELEASE_INVALID",
|
|
3530
|
-
message: "The local design-system route assets are incomplete.",
|
|
3531
|
-
details: { missing }
|
|
3532
|
-
});
|
|
3533
|
-
return !0;
|
|
3534
|
-
}
|
|
4316
|
+
var installedFramework2 = readInstalledFrameworkLocation(), KERNEL_DIR = resolve7(installedFramework2.packageRoot, "compiler-assets"), NEXTJS_KERNEL_DIR = resolve7(KERNEL_DIR, "nextjs"), DEFAULTS_DIR = resolve7(NEXTJS_KERNEL_DIR, "defaults"), SHIMS_DIR = resolve7(NEXTJS_KERNEL_DIR, "shims"), RUNTIME_DIST_DIR = resolve7(installedFramework2.packageRoot, "dist");
|
|
3535
4317
|
async function fileExists5(path) {
|
|
3536
4318
|
return await stat6(path).then((entry) => entry.isFile()).catch(() => !1);
|
|
3537
4319
|
}
|
|
4320
|
+
async function componentResolveAliases({
|
|
4321
|
+
outputDir,
|
|
4322
|
+
sourceDir
|
|
4323
|
+
}) {
|
|
4324
|
+
let extensions = [".tsx", ".ts", ".jsx", ".js", ".mjs", ".cjs"], aliases = {};
|
|
4325
|
+
for (let alias of supportedRuntimeComponentAliases()) {
|
|
4326
|
+
let componentPath = alias.slice(12), base = resolve7(sourceDir, "components", componentPath), candidates = [
|
|
4327
|
+
...extensions.map((extension) => `${base}${extension}`),
|
|
4328
|
+
...extensions.map((extension) => resolve7(base, `index${extension}`))
|
|
4329
|
+
], authored;
|
|
4330
|
+
for (let candidate of candidates)
|
|
4331
|
+
if (await fileExists5(candidate)) {
|
|
4332
|
+
authored = candidate;
|
|
4333
|
+
break;
|
|
4334
|
+
}
|
|
4335
|
+
aliases[alias] = authored ? `./${relative4(outputDir, authored).replaceAll("\\", "/")}` : `@publish.os/nextjs/kernel/components/${componentPath}`;
|
|
4336
|
+
}
|
|
4337
|
+
return aliases;
|
|
4338
|
+
}
|
|
3538
4339
|
async function readKernelFile(path) {
|
|
3539
4340
|
return await readFile6(resolve7(KERNEL_DIR, path), "utf-8");
|
|
3540
4341
|
}
|
|
@@ -3572,6 +4373,13 @@ async function walkPublishOsSourceFiles(dir) {
|
|
|
3572
4373
|
skipDirectory: isExcludedSourcePath
|
|
3573
4374
|
})).filter((path) => !isExcludedSourcePath(path));
|
|
3574
4375
|
}
|
|
4376
|
+
async function mapLocalAssetUrlsInCss(outputDir) {
|
|
4377
|
+
for (let path of await walkFiles(outputDir)) {
|
|
4378
|
+
if (!path.endsWith(".css")) continue;
|
|
4379
|
+
let absolutePath = resolve7(outputDir, path), css = await readFile6(absolutePath, "utf-8"), mapped = mapSourceAssetCss(css, absolutePath);
|
|
4380
|
+
mapped !== css && await writeText(absolutePath, mapped);
|
|
4381
|
+
}
|
|
4382
|
+
}
|
|
3575
4383
|
function createIdeSourceArtifacts(options) {
|
|
3576
4384
|
return {
|
|
3577
4385
|
mediaModule: mediaManifestModule(options.mediaManifest)
|
|
@@ -3658,117 +4466,30 @@ function defaultSourceGlobalsEntrypoint() {
|
|
|
3658
4466
|
'@import "./css/layout.css";',
|
|
3659
4467
|
'@import "./css/zindex.css";',
|
|
3660
4468
|
'@import "./css/typography.css";',
|
|
3661
|
-
'@import "./css/animation.css";',
|
|
3662
|
-
'@import "./css/media.css";',
|
|
3663
|
-
'@import "./theme-base.generated.css";',
|
|
3664
|
-
'@import "./theme-defaults.generated.css";',
|
|
3665
|
-
'@import "./components.generated.css";',
|
|
3666
|
-
'@import "./theme.css";',
|
|
3667
|
-
'@import "./publishos.css";'
|
|
3668
|
-
|
|
3669
|
-
`
|
|
3670
|
-
`;
|
|
3671
|
-
}
|
|
3672
|
-
function componentDefaultsCss(manifest) {
|
|
3673
|
-
return `${manifest.families.map((family) => `@import "./css/components/${family}.css";`).join(`
|
|
3674
|
-
`)}
|
|
3675
|
-
`;
|
|
3676
|
-
}
|
|
3677
|
-
async function appGlobalsCss(manifest) {
|
|
3678
|
-
return (await readKernelFile("nextjs/defaults/app/globals.css")).replace(
|
|
3679
|
-
"/* PUBLISHOS_TAILWIND_SOURCES */",
|
|
3680
|
-
manifest.sources.map((source) => `@source "${source}";`).join(`
|
|
3681
|
-
`)
|
|
3682
|
-
);
|
|
3683
|
-
}
|
|
3684
|
-
async function designSystemPreviewModule(publishOsDir) {
|
|
3685
|
-
let hasButton = await fileExists5(
|
|
3686
|
-
resolve7(publishOsDir, "components", "ui", "button.tsx")
|
|
3687
|
-
), hasMdxLink = await fileExists5(
|
|
3688
|
-
resolve7(publishOsDir, "components", "mdx", "link.tsx")
|
|
3689
|
-
), hasNavbar = await fileExists5(
|
|
3690
|
-
resolve7(publishOsDir, "components", "blocks", "navbar.tsx")
|
|
3691
|
-
), imports = [
|
|
3692
|
-
'import { DesignSystemPreview } from "@components/blocks/design-system-preview";',
|
|
3693
|
-
'import type { DesignSystemPreviewFixture } from "@components/blocks/design-system-preview";',
|
|
3694
|
-
'import { Tabs, TabsList, TabsPanel, TabsTab } from "@components/ui/tabs";'
|
|
3695
|
-
];
|
|
3696
|
-
hasButton && imports.push('import { Button } from "@components/ui/button";'), hasMdxLink && imports.push('import { Link as MdxLink } from "@components/mdx/link";'), hasNavbar && (imports.push('import { Navbar } from "@components/blocks/navbar";'), imports.push(
|
|
3697
|
-
'import type { SiteData, TreeNode } from "@publish.os/nextjs/types";'
|
|
3698
|
-
));
|
|
3699
|
-
let declarations = [], uiFixtures = hasButton ? `[
|
|
3700
|
-
{
|
|
3701
|
-
name: "Button",
|
|
3702
|
-
children: (
|
|
3703
|
-
<div className="flex flex-col items-center gap-3">
|
|
3704
|
-
<Button>Solid</Button>
|
|
3705
|
-
<Button variant="soft">Soft</Button>
|
|
3706
|
-
<Button disabled>Disabled</Button>
|
|
3707
|
-
</div>
|
|
3708
|
-
),
|
|
3709
|
-
},
|
|
3710
|
-
]` : "[]", mdxFixtures = hasMdxLink ? `[
|
|
3711
|
-
{
|
|
3712
|
-
name: "Link",
|
|
3713
|
-
children: (
|
|
3714
|
-
<div className="flex flex-col items-center gap-2 text-sm">
|
|
3715
|
-
<MdxLink href="/ds">Internal link</MdxLink>
|
|
3716
|
-
<MdxLink href="#">Example link</MdxLink>
|
|
3717
|
-
</div>
|
|
3718
|
-
),
|
|
3719
|
-
},
|
|
3720
|
-
]` : "[]";
|
|
3721
|
-
hasNavbar && declarations.push(`const previewSite: SiteData = {
|
|
3722
|
-
name: "publishOS Preview",
|
|
3723
|
-
};
|
|
3724
|
-
|
|
3725
|
-
const previewTree: TreeNode[] = [
|
|
3726
|
-
{
|
|
3727
|
-
type: "section",
|
|
3728
|
-
id: "docs",
|
|
3729
|
-
title: "Docs",
|
|
3730
|
-
path: "/docs",
|
|
3731
|
-
children: [],
|
|
3732
|
-
},
|
|
3733
|
-
{
|
|
3734
|
-
type: "section",
|
|
3735
|
-
id: "blog",
|
|
3736
|
-
title: "Blog",
|
|
3737
|
-
path: "/blog",
|
|
3738
|
-
children: [],
|
|
3739
|
-
},
|
|
3740
|
-
];`);
|
|
3741
|
-
let blockFixtures = hasNavbar ? `[
|
|
3742
|
-
{
|
|
3743
|
-
name: "Navbar",
|
|
3744
|
-
children: (
|
|
3745
|
-
<Navbar site={previewSite} tree={previewTree} />
|
|
3746
|
-
),
|
|
3747
|
-
},
|
|
3748
|
-
]` : "[]";
|
|
3749
|
-
return `${imports.join(`
|
|
3750
|
-
`)}
|
|
3751
|
-
|
|
3752
|
-
${declarations.join(`
|
|
3753
|
-
|
|
4469
|
+
'@import "./css/animation.css";',
|
|
4470
|
+
'@import "./css/media.css";',
|
|
4471
|
+
'@import "./theme-base.generated.css";',
|
|
4472
|
+
'@import "./theme-defaults.generated.css";',
|
|
4473
|
+
'@import "./components.generated.css";',
|
|
4474
|
+
'@import "./theme.css";',
|
|
4475
|
+
'@import "./publishos.css";',
|
|
4476
|
+
'@import "./css/components/code-block.css";'
|
|
4477
|
+
].join(`
|
|
3754
4478
|
`)}
|
|
3755
|
-
|
|
3756
|
-
const uiFixtures: DesignSystemPreviewFixture[] = ${uiFixtures};
|
|
3757
|
-
const mdxFixtures: DesignSystemPreviewFixture[] = ${mdxFixtures};
|
|
3758
|
-
const blockFixtures: DesignSystemPreviewFixture[] = ${blockFixtures};
|
|
3759
|
-
|
|
3760
|
-
export default function GeneratedDesignSystemPreview() {
|
|
3761
|
-
return (
|
|
3762
|
-
<DesignSystemPreview
|
|
3763
|
-
blocks={blockFixtures}
|
|
3764
|
-
mdx={mdxFixtures}
|
|
3765
|
-
tabComponents={{ Tabs, TabsList, TabsPanel, TabsTab }}
|
|
3766
|
-
ui={uiFixtures}
|
|
3767
|
-
/>
|
|
3768
|
-
);
|
|
4479
|
+
`;
|
|
3769
4480
|
}
|
|
4481
|
+
function componentDefaultsCss(manifest) {
|
|
4482
|
+
return `${manifest.families.map((family) => `@import "./css/components/${family}.css";`).join(`
|
|
4483
|
+
`)}
|
|
3770
4484
|
`;
|
|
3771
4485
|
}
|
|
4486
|
+
async function appGlobalsCss(manifest) {
|
|
4487
|
+
return (await readKernelFile("nextjs/defaults/app/globals.css")).replace(
|
|
4488
|
+
"/* PUBLISHOS_TAILWIND_SOURCES */",
|
|
4489
|
+
manifest.sources.map((source) => `@source "${source}";`).join(`
|
|
4490
|
+
`)
|
|
4491
|
+
);
|
|
4492
|
+
}
|
|
3772
4493
|
async function mdxSourceComponentsModule(publishOsDir) {
|
|
3773
4494
|
let mdxDir = resolve7(publishOsDir, "components", "mdx"), files = (await readdir3(mdxDir).catch(() => [])).filter((file) => file.endsWith(".tsx")).sort(), imports = [
|
|
3774
4495
|
'import type { MDXComponents } from "@publish.os/nextjs/mdx/mdx";'
|
|
@@ -4204,12 +4925,21 @@ function ogFontRoleInput(font) {
|
|
|
4204
4925
|
subsets: font.subsets,
|
|
4205
4926
|
weight: font.weight,
|
|
4206
4927
|
...font.localFiles ? {
|
|
4207
|
-
files: font.localFiles.map((file) =>
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4928
|
+
files: font.localFiles.map((file) => {
|
|
4929
|
+
if (!file.admittedContents)
|
|
4930
|
+
throw new AppError({
|
|
4931
|
+
code: "FRAMEWORK_FONT_ASSET_UNAVAILABLE",
|
|
4932
|
+
message: `The local font file was not admitted: ${file.configuredPath}`,
|
|
4933
|
+
details: { path: file.configuredPath }
|
|
4934
|
+
});
|
|
4935
|
+
return {
|
|
4936
|
+
configuredPath: file.configuredPath,
|
|
4937
|
+
data: file.admittedContents,
|
|
4938
|
+
path: file.sourcePath,
|
|
4939
|
+
style: file.style,
|
|
4940
|
+
weight: file.declaredWeight
|
|
4941
|
+
};
|
|
4942
|
+
})
|
|
4213
4943
|
} : {}
|
|
4214
4944
|
};
|
|
4215
4945
|
}
|
|
@@ -4263,7 +4993,8 @@ async function validateLocalVariableFonts({
|
|
|
4263
4993
|
isVariableFontWeight(weight) && (file.weight = await validateVariableFontFile({
|
|
4264
4994
|
configuredPath: file.configuredPath,
|
|
4265
4995
|
sourcePath: file.sourcePath,
|
|
4266
|
-
weight
|
|
4996
|
+
weight,
|
|
4997
|
+
contents: file.admittedContents
|
|
4267
4998
|
}));
|
|
4268
4999
|
})
|
|
4269
5000
|
), localFiles.length === 1 && isVariableFontWeight(font.weight) && (font.weight = localFiles[0]?.weight), localFiles.length === 1 && (font.style = localFiles[0]?.style ?? font.style);
|
|
@@ -4274,19 +5005,51 @@ async function fontBuildPlan({
|
|
|
4274
5005
|
config,
|
|
4275
5006
|
publishOsDir,
|
|
4276
5007
|
prepareAssets,
|
|
4277
|
-
themeGroups
|
|
5008
|
+
themeGroups,
|
|
5009
|
+
resourceAdmission
|
|
4278
5010
|
}) {
|
|
4279
5011
|
let rootFonts = resolvedRootFonts(config, publishOsDir), fontsByIdentity = /* @__PURE__ */ new Map(), register = (font) => {
|
|
4280
5012
|
fontsByIdentity.has(font.identity) || fontsByIdentity.set(font.identity, font);
|
|
4281
5013
|
};
|
|
4282
5014
|
for (let font of Object.values(rootFonts)) register(font);
|
|
4283
|
-
let groups = {};
|
|
5015
|
+
let groupOverridesByKey = /* @__PURE__ */ new Map(), groups = {};
|
|
4284
5016
|
for (let group of Object.values(config.groups)) {
|
|
4285
5017
|
if (!hasFontOverrides(group)) continue;
|
|
4286
5018
|
let overrides = groupFontOverrides(group, publishOsDir);
|
|
5019
|
+
groupOverridesByKey.set(group.key, overrides);
|
|
4287
5020
|
for (let font of Object.values(overrides))
|
|
4288
5021
|
font && register(font);
|
|
4289
5022
|
}
|
|
5023
|
+
let admittedFonts = /* @__PURE__ */ new Map(), allFontInstances = [
|
|
5024
|
+
...Object.values(rootFonts),
|
|
5025
|
+
...[...groupOverridesByKey.values()].flatMap(
|
|
5026
|
+
(overrides) => Object.values(overrides).filter(
|
|
5027
|
+
(font) => !!font
|
|
5028
|
+
)
|
|
5029
|
+
)
|
|
5030
|
+
];
|
|
5031
|
+
for (let font of allFontInstances)
|
|
5032
|
+
for (let file of font.localFiles ?? []) {
|
|
5033
|
+
let sourcePath = resolve7(
|
|
5034
|
+
publishOsDir,
|
|
5035
|
+
localFontSourcePath(file.configuredPath)
|
|
5036
|
+
), admitted = admittedFonts.get(sourcePath);
|
|
5037
|
+
if (!admitted) {
|
|
5038
|
+
let result = await resourceAdmission.admit({
|
|
5039
|
+
filePath: file.configuredPath,
|
|
5040
|
+
relativePath: relative4(publishOsDir, sourcePath),
|
|
5041
|
+
sourcePath
|
|
5042
|
+
});
|
|
5043
|
+
if (!result.asset)
|
|
5044
|
+
throw new AppError({
|
|
5045
|
+
code: "FRAMEWORK_FONT_ASSET_UNAVAILABLE",
|
|
5046
|
+
message: `The local font file could not be admitted: ${file.configuredPath}`,
|
|
5047
|
+
details: { path: file.configuredPath }
|
|
5048
|
+
});
|
|
5049
|
+
admitted = result.asset.contents, admittedFonts.set(sourcePath, admitted);
|
|
5050
|
+
}
|
|
5051
|
+
file.admittedContents = admitted;
|
|
5052
|
+
}
|
|
4290
5053
|
await validateLocalVariableFonts({
|
|
4291
5054
|
fonts: fontsByIdentity.values(),
|
|
4292
5055
|
publishOsDir
|
|
@@ -4321,7 +5084,7 @@ async function fontBuildPlan({
|
|
|
4321
5084
|
message: `Theme scope is missing for group "${group.key}"`,
|
|
4322
5085
|
details: { group: group.key }
|
|
4323
5086
|
});
|
|
4324
|
-
let overrides =
|
|
5087
|
+
let overrides = groupOverridesByKey.get(group.key) ?? {}, overrideFonts = Object.values(overrides).filter(
|
|
4325
5088
|
Boolean
|
|
4326
5089
|
), imports = Array.from(new Set(overrideFonts.map(importFor))), classNameExport = `${camelCase(group.key)}FontClassName`, module = `${BANNER}${imports.join(`
|
|
4327
5090
|
`)}
|
|
@@ -4367,9 +5130,8 @@ ${declaredFontRoles(group.fonts).map(
|
|
|
4367
5130
|
Object.values(config.groups).filter((group) => hasConfiguredOgRole(group)).map((group) => {
|
|
4368
5131
|
let resolved = { main: rootFonts.main, mono: rootFonts.mono };
|
|
4369
5132
|
for (let key of group.ancestry) {
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
let overrides = groupFontOverrides(ancestor, publishOsDir);
|
|
5133
|
+
if (!config.groups[key]) continue;
|
|
5134
|
+
let overrides = groupOverridesByKey.get(key) ?? {};
|
|
4373
5135
|
overrides.main && (resolved.main = overrides.main), overrides.mono && (resolved.mono = overrides.mono);
|
|
4374
5136
|
}
|
|
4375
5137
|
return [
|
|
@@ -4426,7 +5188,7 @@ ${declaredFontRoles(group.fonts).map(
|
|
|
4426
5188
|
assets: [...fontsByIdentity.values()].flatMap(
|
|
4427
5189
|
(font) => (font.localFiles ?? []).map((file) => ({
|
|
4428
5190
|
dest: file.generatedPath,
|
|
4429
|
-
|
|
5191
|
+
data: file.admittedContents
|
|
4430
5192
|
}))
|
|
4431
5193
|
),
|
|
4432
5194
|
root: {
|
|
@@ -4471,7 +5233,7 @@ ${Object.entries(rootFonts).sort(([left], [right]) => left.localeCompare(right))
|
|
|
4471
5233
|
...ogFontManifest ? { og: ogFontManifest } : {}
|
|
4472
5234
|
};
|
|
4473
5235
|
}
|
|
4474
|
-
async function overlaySource(publishOsDir, sourceDir, config, fonts, theme) {
|
|
5236
|
+
async function overlaySource(publishOsDir, sourceDir, config, fonts, theme, pages) {
|
|
4475
5237
|
let defaultsUsed = [], sourceOverrides = [], sourceConfigPath = resolve7(publishOsDir, "publish.os.config.json");
|
|
4476
5238
|
await fileExists5(sourceConfigPath) && (await copyText(
|
|
4477
5239
|
sourceConfigPath,
|
|
@@ -4502,6 +5264,9 @@ async function overlaySource(publishOsDir, sourceDir, config, fonts, theme) {
|
|
|
4502
5264
|
resolve7(sourceDir, "_internal", "mdx-source-components.generated.ts"),
|
|
4503
5265
|
await mdxSourceComponentsModule(publishOsDir)
|
|
4504
5266
|
), defaultsUsed.push("_internal/mdx-source-components.generated.ts"), await writeText(
|
|
5267
|
+
resolve7(sourceDir, "_internal", "mdx-icon-components.generated.ts"),
|
|
5268
|
+
mdxIconComponentsModule(pages)
|
|
5269
|
+
), defaultsUsed.push("_internal/mdx-icon-components.generated.ts"), await writeText(
|
|
4505
5270
|
resolve7(sourceDir, "_internal", "mdx-components.generated.tsx"),
|
|
4506
5271
|
BANNER + await renderShim("site-mdx-components.tsx", {})
|
|
4507
5272
|
), defaultsUsed.push("_internal/mdx-components.generated.tsx"), await writeText(
|
|
@@ -4525,29 +5290,19 @@ async function overlaySource(publishOsDir, sourceDir, config, fonts, theme) {
|
|
|
4525
5290
|
for (let module of fonts.modules)
|
|
4526
5291
|
await writeText(resolve7(dirname8(sourceDir), module.path), module.content), defaultsUsed.push(module.path.replace(/^source\//, ""));
|
|
4527
5292
|
for (let asset of fonts.assets) {
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
path: asset.src,
|
|
4531
|
-
sourceFile: "publish.os.config.json"
|
|
4532
|
-
}), !await fileExists5(asset.src))
|
|
4533
|
-
throw new AppError({
|
|
4534
|
-
code: "FRAMEWORK_FONT_CONFIG_INVALID",
|
|
4535
|
-
message: `Local font file does not exist: ${asset.src}`,
|
|
4536
|
-
details: { path: asset.src }
|
|
4537
|
-
});
|
|
4538
|
-
await copyTreeIfExists(asset.src, resolve7(dirname8(sourceDir), asset.dest)), defaultsUsed.push(asset.dest.replace(/^source\//, ""));
|
|
5293
|
+
let destination = resolve7(dirname8(sourceDir), asset.dest);
|
|
5294
|
+
await mkdir6(dirname8(destination), { recursive: !0 }), await writeFile6(destination, asset.data), defaultsUsed.push(asset.dest.replace(/^source\//, ""));
|
|
4539
5295
|
}
|
|
4540
5296
|
for (let asset of fonts.downloadedAssets) {
|
|
4541
5297
|
let destination = resolve7(dirname8(sourceDir), asset.dest);
|
|
4542
5298
|
await mkdir6(dirname8(destination), { recursive: !0 }), await writeFile6(destination, asset.data);
|
|
4543
5299
|
}
|
|
4544
|
-
for (let asset of theme.assets)
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
resolve7(dirname8(sourceDir), "public", asset.outputPath)
|
|
4548
|
-
), sourceOverrides.push(
|
|
5300
|
+
for (let asset of theme.assets) {
|
|
5301
|
+
let destination = resolve7(dirname8(sourceDir), "public", asset.outputPath);
|
|
5302
|
+
await mkdir6(dirname8(destination), { recursive: !0 }), await writeFile6(destination, asset.contents), sourceOverrides.push(
|
|
4549
5303
|
relative4(publishOsDir, asset.sourcePath).split("\\").join("/")
|
|
4550
5304
|
);
|
|
5305
|
+
}
|
|
4551
5306
|
for (let file of ["layout.tsx", "index.tsx", "page.tsx"]) {
|
|
4552
5307
|
let projectPath = resolve7(publishOsDir, file), dest = resolve7(sourceDir, file);
|
|
4553
5308
|
await fileExists5(projectPath) ? (await copyTreeIfExists(projectPath, dest), sourceOverrides.push(file)) : (await copyTreeIfExists(resolve7(DEFAULTS_DIR, "root", file), dest), defaultsUsed.push(file));
|
|
@@ -4604,10 +5359,6 @@ export default function InheritedGroupLayout({ children }: LayoutProps) { return
|
|
|
4604
5359
|
resolve7(publishOsDir, "components"),
|
|
4605
5360
|
resolve7(sourceDir, "components"),
|
|
4606
5361
|
publishOsDir
|
|
4607
|
-
), await copyTreeIfExists(
|
|
4608
|
-
resolve7(publishOsDir, "public"),
|
|
4609
|
-
resolve7(dirname8(sourceDir), "public"),
|
|
4610
|
-
publishOsDir
|
|
4611
5362
|
), { defaultsUsed, sourceOverrides };
|
|
4612
5363
|
}
|
|
4613
5364
|
function manifestModule(manifest) {
|
|
@@ -4681,6 +5432,20 @@ function outputRoutePath(outputPath) {
|
|
|
4681
5432
|
function outputPathWithinGroup(path, groupPath) {
|
|
4682
5433
|
return groupPath === "/" || path === groupPath || path.startsWith(`${groupPath}/`);
|
|
4683
5434
|
}
|
|
5435
|
+
function outputDirectory2(path) {
|
|
5436
|
+
return path.slice(0, path.lastIndexOf("/") + 1) || "/";
|
|
5437
|
+
}
|
|
5438
|
+
function discoveryPlanCovers({
|
|
5439
|
+
manifest,
|
|
5440
|
+
plan,
|
|
5441
|
+
group,
|
|
5442
|
+
path
|
|
5443
|
+
}) {
|
|
5444
|
+
if (effectiveOrigin(manifest, plan.group) !== effectiveOrigin(manifest, group))
|
|
5445
|
+
return !1;
|
|
5446
|
+
let scopeGroup = plan.scopeGroup ?? plan.group;
|
|
5447
|
+
return scopeGroup ? outputPathWithinGroup(path, manifest.groups[scopeGroup]?.path ?? "/") ? plan.scope === "site" ? !0 : group === scopeGroup || plan.scope !== "self" && group.startsWith(`${scopeGroup}/`) : !1 : !0;
|
|
5448
|
+
}
|
|
4684
5449
|
function outputFactory(kind) {
|
|
4685
5450
|
return kind === "atom" ? { factory: "createAtomFeedRoute", routeModule: "feed" } : kind === "json-feed" ? { factory: "createJsonFeedRoute", routeModule: "feed" } : kind === "rss" ? { factory: "createRssFeedRoute", routeModule: "feed" } : kind === "llms" ? { factory: "createLlmsTxtRoute", routeModule: "llms" } : kind === "llms-full" ? { factory: "createLlmsFullTxtRoute", routeModule: "llms" } : kind === "sitemap-md" ? { factory: "createSitemapMarkdownRoute", routeModule: "sitemap" } : { factory: "createSitemapXmlRoute", routeModule: "sitemap" };
|
|
4686
5451
|
}
|
|
@@ -4701,13 +5466,13 @@ export const GET = createPrecomputedFeedRoute(agentTextOutputs[${JSON.stringify(
|
|
|
4701
5466
|
export const HEAD = GET;
|
|
4702
5467
|
`;
|
|
4703
5468
|
let options = {};
|
|
4704
|
-
plan.scope && (options.scope = plan.scope), plan.group && (options.group = plan.group), plan.limit && (options.limit = plan.limit), plan.status && (options.status = plan.status), plan.includeDescriptions && (options.includeDescriptions = plan.includeDescriptions), plan.links
|
|
5469
|
+
plan.scope && (options.scope = plan.scope), plan.group && (options.group = plan.group), plan.kind === "sitemap-md" && plan.scopeGroup && (options.group = plan.scopeGroup), plan.limit && (options.limit = plan.limit), plan.status && (options.status = plan.status), plan.includeDescriptions && (options.includeDescriptions = plan.includeDescriptions), plan.links && (options.links = plan.links), plan.otherGroupLinks && (options.otherGroupLinks = plan.otherGroupLinks), plan.kind === "sitemap" && (options.path = plan.path, plan.sitemaps && (options.sitemaps = plan.sitemaps), plan.exclude?.length && (options.exclude = plan.exclude)), plan.markdownAlternates === !1 && (options.markdownAlternates = !1);
|
|
4705
5470
|
let args = Object.keys(options).length > 0 ? `manifest, ${JSON.stringify(options, null, 2)}` : "manifest";
|
|
4706
5471
|
return plan.kind === "sitemap-md" ? `import manifest from "@manifest";
|
|
4707
5472
|
import { markdownArtifactManifest } from "@source/.publishos/markdown-index.generated";
|
|
4708
5473
|
import { ${factory} } from "@publish.os/nextjs/kernel/routes/metadata/${routeModule}";
|
|
4709
5474
|
|
|
4710
|
-
export const GET = ${factory}(manifest, markdownArtifactManifest);
|
|
5475
|
+
export const GET = ${factory}(manifest, markdownArtifactManifest, ${JSON.stringify(options, null, 2)});
|
|
4711
5476
|
` : `import manifest from "@manifest";
|
|
4712
5477
|
import { ${factory} } from "@publish.os/nextjs/kernel/routes/metadata/${routeModule}";
|
|
4713
5478
|
|
|
@@ -4740,36 +5505,51 @@ function outputHome(manifest, plan) {
|
|
|
4740
5505
|
function llmsSummary(manifest, title) {
|
|
4741
5506
|
return manifest.site.description ? `> ${manifest.site.description}` : `> Agent-readable index for ${title}.`;
|
|
4742
5507
|
}
|
|
4743
|
-
function llmsTextBody(manifest, plan) {
|
|
4744
|
-
let home = outputHome(manifest, plan), pages =
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
5508
|
+
function llmsTextBody(manifest, plan, markdownPaths) {
|
|
5509
|
+
let home = outputHome(manifest, plan), pages = discoveryPages({
|
|
5510
|
+
manifest,
|
|
5511
|
+
...plan,
|
|
5512
|
+
group: plan.scopeGroup ?? plan.group
|
|
5513
|
+
}), sections = groupDiscoveryPages({ manifest, pages });
|
|
5514
|
+
for (let link of plan.links ?? []) {
|
|
5515
|
+
let group = link.group ? manifest.groups[link.group] : void 0;
|
|
5516
|
+
group && !sections.some((section) => section.group === group.key) && sections.push({ group: group.key, title: group.title, pages: [] });
|
|
5517
|
+
}
|
|
5518
|
+
return serializeLlmsIndex({
|
|
5519
|
+
title: home.title,
|
|
5520
|
+
summary: llmsSummary(manifest, home.title).replace(/^> /, ""),
|
|
5521
|
+
sections: sections.sort(
|
|
5522
|
+
(a, b) => (manifest.groups[a.group ?? ""]?.path ?? "/").localeCompare(
|
|
5523
|
+
manifest.groups[b.group ?? ""]?.path ?? "/"
|
|
5524
|
+
)
|
|
5525
|
+
).map((section) => ({
|
|
5526
|
+
title: section.title,
|
|
5527
|
+
pages: section.pages.map((page) => ({
|
|
5528
|
+
title: page.title,
|
|
5529
|
+
url: canonicalUrl(
|
|
5530
|
+
manifest,
|
|
5531
|
+
markdownPaths.get(page.path) ?? page.path,
|
|
5532
|
+
page.group
|
|
5533
|
+
),
|
|
5534
|
+
description: page.description
|
|
5535
|
+
})),
|
|
5536
|
+
links: plan.links?.filter((link) => link.group === section.group).map((link) => ({
|
|
5537
|
+
title: `${link.title} index`,
|
|
5538
|
+
url: canonicalUrl(manifest, link.path, link.group)
|
|
5539
|
+
}))
|
|
5540
|
+
})),
|
|
5541
|
+
includeDescriptions: plan.includeDescriptions,
|
|
5542
|
+
otherGroupLinks: plan.otherGroupLinks?.map((link) => ({
|
|
5543
|
+
title: link.title,
|
|
5544
|
+
url: canonicalUrl(manifest, link.path, link.group)
|
|
5545
|
+
}))
|
|
5546
|
+
});
|
|
4764
5547
|
}
|
|
4765
5548
|
function feedContentType(kind) {
|
|
4766
5549
|
if (kind === "rss") return "application/rss+xml; charset=utf-8";
|
|
4767
5550
|
if (kind === "atom") return "application/atom+xml; charset=utf-8";
|
|
4768
5551
|
if (kind === "json-feed") return "application/feed+json; charset=utf-8";
|
|
4769
5552
|
}
|
|
4770
|
-
function xmlEscape(value) {
|
|
4771
|
-
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
4772
|
-
}
|
|
4773
5553
|
function pageTimestamp(page) {
|
|
4774
5554
|
let value = page.publishedAt ?? page.updatedAt;
|
|
4775
5555
|
if (!value) return -1 / 0;
|
|
@@ -4783,126 +5563,72 @@ function feedPages(manifest, plan) {
|
|
|
4783
5563
|
let statuses = outputStatuses(plan), pages = manifest.pages.filter((page) => statuses.has(page.status)).filter((page) => pageInOutputScope(page, plan, manifest)).sort((a, b) => pageTimestamp(b) - pageTimestamp(a));
|
|
4784
5564
|
return plan.limit ? pages.slice(0, plan.limit) : pages;
|
|
4785
5565
|
}
|
|
4786
|
-
function
|
|
4787
|
-
return page.publishedAt ?? page.updatedAt;
|
|
4788
|
-
}
|
|
4789
|
-
function latestFeedDate(pages) {
|
|
4790
|
-
let timestamp = Math.max(0, ...pages.map((page) => pageTimestamp(page)));
|
|
4791
|
-
return new Date(timestamp).toISOString();
|
|
4792
|
-
}
|
|
4793
|
-
function rssFeedBody(manifest, plan) {
|
|
4794
|
-
let home = outputHome(manifest, plan), title = home.title, description = manifest.site.description ?? title, pages = feedPages(manifest, plan), homeUrl = canonicalUrl(manifest, home.path, home.group), items = pages.map((page) => {
|
|
4795
|
-
let pageUrl = canonicalUrl(manifest, page.path, page.group), pubDate = page.publishedAt ? `
|
|
4796
|
-
<pubDate>${xmlEscape(new Date(page.publishedAt).toUTCString())}</pubDate>` : "", description2 = page.description ? `
|
|
4797
|
-
<description>${xmlEscape(page.description)}</description>` : "";
|
|
4798
|
-
return ` <item>
|
|
4799
|
-
<title>${xmlEscape(page.title)}</title>
|
|
4800
|
-
<link>${xmlEscape(pageUrl)}</link>
|
|
4801
|
-
<guid>${xmlEscape(pageUrl)}</guid>${pubDate}${description2}
|
|
4802
|
-
</item>`;
|
|
4803
|
-
}).join(`
|
|
4804
|
-
`);
|
|
4805
|
-
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
4806
|
-
<rss version="2.0">
|
|
4807
|
-
<channel>
|
|
4808
|
-
<title>${xmlEscape(title)}</title>
|
|
4809
|
-
<link>${xmlEscape(homeUrl)}</link>
|
|
4810
|
-
<description>${xmlEscape(description)}</description>
|
|
4811
|
-
${items}
|
|
4812
|
-
</channel>
|
|
4813
|
-
</rss>
|
|
4814
|
-
`;
|
|
4815
|
-
}
|
|
4816
|
-
function atomFeedBody(manifest, plan) {
|
|
4817
|
-
let home = outputHome(manifest, plan), title = home.title, pages = feedPages(manifest, plan), homeUrl = canonicalUrl(manifest, home.path, home.group), entries = pages.map((page) => {
|
|
4818
|
-
let date = pageDate(page), updated = date ? new Date(date).toISOString() : latestFeedDate([]), pageUrl = canonicalUrl(manifest, page.path, page.group), summary = page.description ? `
|
|
4819
|
-
<summary>${xmlEscape(page.description)}</summary>` : "";
|
|
4820
|
-
return ` <entry>
|
|
4821
|
-
<title>${xmlEscape(page.title)}</title>
|
|
4822
|
-
<id>${xmlEscape(pageUrl)}</id>
|
|
4823
|
-
<link href="${xmlEscape(pageUrl)}" />
|
|
4824
|
-
<updated>${xmlEscape(updated)}</updated>${summary}
|
|
4825
|
-
</entry>`;
|
|
4826
|
-
}).join(`
|
|
4827
|
-
`);
|
|
4828
|
-
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
4829
|
-
<feed xmlns="http://www.w3.org/2005/Atom">
|
|
4830
|
-
<title>${xmlEscape(title)}</title>
|
|
4831
|
-
<id>${xmlEscape(homeUrl)}</id>
|
|
4832
|
-
<updated>${xmlEscape(latestFeedDate(pages))}</updated>
|
|
4833
|
-
${entries}
|
|
4834
|
-
</feed>
|
|
4835
|
-
`;
|
|
4836
|
-
}
|
|
4837
|
-
function jsonFeedBody(manifest, plan) {
|
|
5566
|
+
function generatedFeedInput(manifest, plan) {
|
|
4838
5567
|
let home = outputHome(manifest, plan), pages = feedPages(manifest, plan);
|
|
4839
|
-
return
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
tags: page.tags
|
|
4854
|
-
}))
|
|
4855
|
-
},
|
|
4856
|
-
null,
|
|
4857
|
-
2
|
|
4858
|
-
)}
|
|
4859
|
-
`;
|
|
5568
|
+
return {
|
|
5569
|
+
title: home.title,
|
|
5570
|
+
description: manifest.site.description,
|
|
5571
|
+
homeUrl: canonicalUrl(manifest, home.path, home.group),
|
|
5572
|
+
pages: pages.map((page) => ({
|
|
5573
|
+
url: canonicalUrl(manifest, page.path, page.group),
|
|
5574
|
+
title: page.title,
|
|
5575
|
+
publishedAt: page.publishedAt,
|
|
5576
|
+
updatedAt: page.updatedAt,
|
|
5577
|
+
description: page.description,
|
|
5578
|
+
body: page.body,
|
|
5579
|
+
tags: page.tags
|
|
5580
|
+
}))
|
|
5581
|
+
};
|
|
4860
5582
|
}
|
|
4861
5583
|
function feedBody(manifest, plan) {
|
|
4862
|
-
if (plan.kind === "rss")
|
|
4863
|
-
|
|
4864
|
-
if (plan.kind === "
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
(
|
|
4880
|
-
)
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
sections.push(section), totalBytes += sectionBytes, included += 1;
|
|
4891
|
-
}
|
|
4892
|
-
let footer = truncated ? `
|
|
4893
|
-
> Truncated at ${included} of ${visibleArtifacts.length} Markdown pages to stay under ${DEFAULT_LLMS_FULL_MAX_BYTES} bytes.
|
|
4894
|
-
` : "";
|
|
4895
|
-
return `${header}${sections.join("")}${footer}`;
|
|
5584
|
+
if (plan.kind === "rss")
|
|
5585
|
+
return serializeRssFeed(generatedFeedInput(manifest, plan));
|
|
5586
|
+
if (plan.kind === "atom")
|
|
5587
|
+
return serializeAtomFeed(generatedFeedInput(manifest, plan));
|
|
5588
|
+
if (plan.kind === "json-feed")
|
|
5589
|
+
return serializeJsonFeed(generatedFeedInput(manifest, plan));
|
|
5590
|
+
}
|
|
5591
|
+
function llmsFullTextBody(manifest, plan, outputPlans, artifacts) {
|
|
5592
|
+
let home = outputHome(manifest, plan), pages = new Set(
|
|
5593
|
+
discoveryPages({
|
|
5594
|
+
manifest,
|
|
5595
|
+
...plan,
|
|
5596
|
+
group: plan.scopeGroup ?? plan.group
|
|
5597
|
+
}).map((page) => page.path)
|
|
5598
|
+
), visibleArtifacts = artifacts.filter(
|
|
5599
|
+
(artifact) => pages.has(artifact.htmlPath)
|
|
5600
|
+
), index = outputPlans.find(
|
|
5601
|
+
(candidate) => candidate.kind === "llms" && candidate.group === plan.group
|
|
5602
|
+
), sitemap = outputPlans.find(
|
|
5603
|
+
(candidate) => candidate.kind === "sitemap-md" && candidate.group === plan.group
|
|
5604
|
+
);
|
|
5605
|
+
return serializeLlmsFull({
|
|
5606
|
+
title: home.title,
|
|
5607
|
+
indexUrl: index ? canonicalUrl(manifest, index.path, index.group) : void 0,
|
|
5608
|
+
sitemapUrl: sitemap ? canonicalUrl(manifest, sitemap.path, sitemap.group) : void 0,
|
|
5609
|
+
artifacts: visibleArtifacts,
|
|
5610
|
+
maxBytes: DEFAULT_LLMS_FULL_MAX_BYTES
|
|
5611
|
+
});
|
|
4896
5612
|
}
|
|
4897
|
-
function agentTextOutputsModule(manifest, outputPlans, artifacts = []) {
|
|
4898
|
-
let
|
|
5613
|
+
function agentTextOutputsModule(manifest, outputPlans, artifacts = [], availableMarkdownPaths) {
|
|
5614
|
+
let markdownPaths = new Map(
|
|
5615
|
+
artifacts.filter(
|
|
5616
|
+
(artifact) => !availableMarkdownPaths || availableMarkdownPaths.has(artifact.markdownPath)
|
|
5617
|
+
).map((artifact) => [artifact.htmlPath, artifact.markdownPath])
|
|
5618
|
+
), sitemap = outputPlans.find(
|
|
5619
|
+
(output) => output.kind === "sitemap" && output.sitemaps !== void 0 && !output.group
|
|
5620
|
+
) ?? outputPlans.find((output) => output.kind === "sitemap" && !output.group), robotsSitemaps = outputPlans.filter(
|
|
5621
|
+
(output) => output.kind === "sitemap" && effectiveOrigin(manifest, output.group) === manifest.site.origin && (output === sitemap || !sitemap || (sitemap.sitemaps ? !sitemap.sitemaps.some(
|
|
5622
|
+
(entry) => entry.path === output.path && entry.group === output.group
|
|
5623
|
+
) : !output.path.startsWith(outputDirectory2(sitemap.path))))
|
|
5624
|
+
), outputs = Object.fromEntries(
|
|
4899
5625
|
outputPlans.filter(
|
|
4900
5626
|
(plan) => plan.kind === "robots" || plan.kind === "llms" || plan.kind === "llms-full" || plan.kind === "rss" || plan.kind === "atom" || plan.kind === "json-feed"
|
|
4901
5627
|
).map((plan) => {
|
|
4902
5628
|
let body = plan.kind === "robots" ? `User-agent: *
|
|
4903
5629
|
Allow: /
|
|
4904
|
-
|
|
4905
|
-
` : plan.kind === "llms-full" ? llmsFullTextBody(manifest, artifacts) : feedBody(manifest, plan) ?? llmsTextBody(manifest, plan);
|
|
5630
|
+
${robotsSitemaps.map((output) => `Sitemap: ${canonicalUrl(manifest, output.path, output.group)}
|
|
5631
|
+
`).join("")}` : plan.kind === "llms-full" ? llmsFullTextBody(manifest, plan, outputPlans, artifacts) : feedBody(manifest, plan) ?? llmsTextBody(manifest, plan, markdownPaths);
|
|
4906
5632
|
return [
|
|
4907
5633
|
plan.path,
|
|
4908
5634
|
{
|
|
@@ -4917,7 +5643,7 @@ Sitemap: ${canonicalUrl(manifest, outputPlans.find((output) => output.kind === "
|
|
|
4917
5643
|
return `export const agentTextOutputs = ${JSON.stringify(outputs, null, 2)} as const;
|
|
4918
5644
|
`;
|
|
4919
5645
|
}
|
|
4920
|
-
function agentRouteConfig(config, outputPlans, manifest, additionalPublicPaths) {
|
|
5646
|
+
function agentRouteConfig(config, outputPlans, manifest, additionalPublicPaths, notFoundScopes, markdownPaths) {
|
|
4921
5647
|
return {
|
|
4922
5648
|
agentDetection: config.agent?.agentDetection ?? !0,
|
|
4923
5649
|
blockInternalMarkdownRoute: config.agent?.blockInternalMarkdownRoute ?? !0,
|
|
@@ -4927,6 +5653,9 @@ function agentRouteConfig(config, outputPlans, manifest, additionalPublicPaths)
|
|
|
4927
5653
|
markdownAccept: config.agent?.markdownAccept ?? !0,
|
|
4928
5654
|
markdownRoutes: config.agent?.markdownRoutes ?? !0,
|
|
4929
5655
|
plainTextAccept: config.agent?.plainTextAccept ?? !0,
|
|
5656
|
+
notFoundScopes,
|
|
5657
|
+
markdownPaths,
|
|
5658
|
+
outputPaths: outputPlans.map((output) => output.path),
|
|
4930
5659
|
publicPaths: [
|
|
4931
5660
|
.../* @__PURE__ */ new Set([
|
|
4932
5661
|
"/",
|
|
@@ -4938,9 +5667,16 @@ function agentRouteConfig(config, outputPlans, manifest, additionalPublicPaths)
|
|
|
4938
5667
|
].sort()
|
|
4939
5668
|
};
|
|
4940
5669
|
}
|
|
4941
|
-
function agentRouteConfigModule(config, outputPlans, manifest, additionalPublicPaths) {
|
|
5670
|
+
function agentRouteConfigModule(config, outputPlans, manifest, additionalPublicPaths, notFoundScopes, markdownPaths) {
|
|
4942
5671
|
return `export const agentRouteConfig = ${JSON.stringify(
|
|
4943
|
-
agentRouteConfig(
|
|
5672
|
+
agentRouteConfig(
|
|
5673
|
+
config,
|
|
5674
|
+
outputPlans,
|
|
5675
|
+
manifest,
|
|
5676
|
+
additionalPublicPaths,
|
|
5677
|
+
notFoundScopes,
|
|
5678
|
+
markdownPaths
|
|
5679
|
+
),
|
|
4944
5680
|
null,
|
|
4945
5681
|
2
|
|
4946
5682
|
)} as const;
|
|
@@ -4956,10 +5692,23 @@ function groupBreadcrumbs(manifest, groupKey, title) {
|
|
|
4956
5692
|
let group = manifest.groups[groupKey], seenKeys = /* @__PURE__ */ new Set(), groups = [...group?.ancestry ?? [], groupKey].filter((key) => seenKeys.has(key) ? !1 : (seenKeys.add(key), !0)).map((key) => manifest.groups[key]?.title).filter((value) => !!value), seenLabels = /* @__PURE__ */ new Set();
|
|
4957
5693
|
return [...groups, title].filter((label) => seenLabels.has(label) ? !1 : (seenLabels.add(label), !0)).join(" > ");
|
|
4958
5694
|
}
|
|
4959
|
-
function
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
5695
|
+
function pageDiscoveryPlan({
|
|
5696
|
+
manifest,
|
|
5697
|
+
outputPlans,
|
|
5698
|
+
page,
|
|
5699
|
+
rootOwnedGroups,
|
|
5700
|
+
kinds
|
|
5701
|
+
}) {
|
|
5702
|
+
return outputPlans.filter(
|
|
5703
|
+
(plan) => kinds.includes(plan.kind) && (plan.group || rootOwnedGroups.has(page.group)) && discoveryPlanCovers({
|
|
5704
|
+
manifest,
|
|
5705
|
+
plan,
|
|
5706
|
+
group: page.group,
|
|
5707
|
+
path: page.path
|
|
5708
|
+
}) && page.path.startsWith(outputDirectory2(plan.path))
|
|
5709
|
+
).sort(
|
|
5710
|
+
(a, b) => outputDirectory2(b.path).length - outputDirectory2(a.path).length || kinds.indexOf(a.kind) - kinds.indexOf(b.kind) || +(b.sitemaps !== void 0) - +(a.sitemaps !== void 0)
|
|
5711
|
+
)[0];
|
|
4963
5712
|
}
|
|
4964
5713
|
function markdownLinkForPage(manifest, page) {
|
|
4965
5714
|
return `[${page.title}](${canonicalUrl(
|
|
@@ -5086,7 +5835,10 @@ function markdownArtifactEnrichment(options) {
|
|
|
5086
5835
|
let { next, previous } = adjacentMarkdownPages({
|
|
5087
5836
|
context: options.context,
|
|
5088
5837
|
page: options.page
|
|
5089
|
-
}), group = options.manifest.groups[options.page.group],
|
|
5838
|
+
}), group = options.manifest.groups[options.page.group], llms = pageDiscoveryPlan({ ...options, kinds: ["llms"] }), sitemap = pageDiscoveryPlan({
|
|
5839
|
+
...options,
|
|
5840
|
+
kinds: ["sitemap-md", "sitemap"]
|
|
5841
|
+
}), related = relatedMarkdownPages({
|
|
5090
5842
|
context: options.context,
|
|
5091
5843
|
page: options.page
|
|
5092
5844
|
}), continueItems = [
|
|
@@ -5097,9 +5849,8 @@ function markdownArtifactEnrichment(options) {
|
|
|
5097
5849
|
return `${markdownLinkForPage(options.manifest, page)}${description}`;
|
|
5098
5850
|
}), sectionItems = [
|
|
5099
5851
|
group?.path ? `[${group.title} home](${canonicalUrl(options.manifest, group.path, options.page.group)})` : void 0,
|
|
5100
|
-
|
|
5101
|
-
`[
|
|
5102
|
-
`[Sitemap](${canonicalUrl(options.manifest, "/sitemap.md")})`
|
|
5852
|
+
llms ? `[LLMS index](${canonicalUrl(options.manifest, llms.path, llms.group)})` : void 0,
|
|
5853
|
+
sitemap ? `[Sitemap](${canonicalUrl(options.manifest, sitemap.path, sitemap.group)})` : void 0
|
|
5103
5854
|
].filter((item) => !!item);
|
|
5104
5855
|
return [
|
|
5105
5856
|
markdownListSection("Continue reading", continueItems),
|
|
@@ -5108,7 +5859,10 @@ function markdownArtifactEnrichment(options) {
|
|
|
5108
5859
|
].filter((section) => !!section);
|
|
5109
5860
|
}
|
|
5110
5861
|
function markdownArtifactBody(options) {
|
|
5111
|
-
let markdownPath = markdownRoutePathForPage(options.page.path), group = options.manifest.groups[options.page.group],
|
|
5862
|
+
let markdownPath = markdownRoutePathForPage(options.page.path), group = options.manifest.groups[options.page.group], llms = pageDiscoveryPlan({ ...options, kinds: ["llms"] }), sitemap = pageDiscoveryPlan({
|
|
5863
|
+
...options,
|
|
5864
|
+
kinds: ["sitemap-md", "sitemap"]
|
|
5865
|
+
}), frontmatter = [
|
|
5112
5866
|
"---",
|
|
5113
5867
|
`title: ${yamlString(options.page.title)}`,
|
|
5114
5868
|
options.page.description ? `description: ${yamlString(options.page.description)}` : void 0,
|
|
@@ -5122,19 +5876,14 @@ function markdownArtifactBody(options) {
|
|
|
5122
5876
|
options.page.group,
|
|
5123
5877
|
options.page.title
|
|
5124
5878
|
)}`,
|
|
5125
|
-
`> Sitemap: ${canonicalUrl(options.manifest,
|
|
5126
|
-
`> LLMS index: ${canonicalUrl(options.manifest,
|
|
5127
|
-
|
|
5128
|
-
].filter(Boolean), body = convertMdxToMarkdown({
|
|
5129
|
-
collectDiagnostics: !1,
|
|
5130
|
-
mediaAssets: options.mediaManifest.assets,
|
|
5131
|
-
source: options.page.body,
|
|
5132
|
-
unknownComponentMode: "children"
|
|
5133
|
-
}).markdown.trim(), enrichment = markdownArtifactEnrichment({
|
|
5879
|
+
sitemap ? `> Sitemap: ${canonicalUrl(options.manifest, sitemap.path, sitemap.group)}` : void 0,
|
|
5880
|
+
llms ? `> LLMS index: ${canonicalUrl(options.manifest, llms.path, llms.group)}` : void 0
|
|
5881
|
+
].filter(Boolean), body = options.conversions.get(options.page.path)?.markdown.trim() ?? "", enrichment = markdownArtifactEnrichment({
|
|
5134
5882
|
manifest: options.manifest,
|
|
5135
5883
|
outputPlans: options.outputPlans,
|
|
5136
5884
|
page: options.page,
|
|
5137
|
-
context: options.enrichmentContext
|
|
5885
|
+
context: options.enrichmentContext,
|
|
5886
|
+
rootOwnedGroups: options.rootOwnedGroups
|
|
5138
5887
|
});
|
|
5139
5888
|
return [
|
|
5140
5889
|
frontmatter.join(`
|
|
@@ -5149,15 +5898,16 @@ function markdownArtifactBody(options) {
|
|
|
5149
5898
|
|
|
5150
5899
|
`);
|
|
5151
5900
|
}
|
|
5152
|
-
function markdownArtifacts(manifest, outputPlans,
|
|
5901
|
+
function markdownArtifacts(manifest, outputPlans, conversions, rootOwnedGroups) {
|
|
5153
5902
|
let enrichmentContext = createMarkdownEnrichmentContext(manifest);
|
|
5154
5903
|
return enrichmentContext.publishedPages.map((page) => {
|
|
5155
5904
|
let body = markdownArtifactBody({
|
|
5156
5905
|
manifest,
|
|
5157
|
-
mediaManifest,
|
|
5158
5906
|
outputPlans,
|
|
5159
5907
|
page,
|
|
5160
|
-
|
|
5908
|
+
conversions,
|
|
5909
|
+
enrichmentContext,
|
|
5910
|
+
rootOwnedGroups
|
|
5161
5911
|
}), markdownPath = markdownRoutePathForPage(page.path);
|
|
5162
5912
|
return {
|
|
5163
5913
|
bodyHash: markdownContentHash(body),
|
|
@@ -5431,12 +6181,8 @@ function outputLimit(defaults, declaration) {
|
|
|
5431
6181
|
return declaration.limit ?? defaults?.limit;
|
|
5432
6182
|
}
|
|
5433
6183
|
function planGeneratedOutputs(config, manifest) {
|
|
5434
|
-
let plans = /* @__PURE__ */ new Map(), add = (plan
|
|
5435
|
-
let normalizedPath = normalizeOutputPath(plan.path);
|
|
5436
|
-
if (options.replaceKind)
|
|
5437
|
-
for (let [existingPath, existing2] of plans)
|
|
5438
|
-
!existing2.group && existing2.kind === plan.kind && plans.delete(existingPath);
|
|
5439
|
-
let origin = effectiveOrigin(manifest, plan.group), key = JSON.stringify([origin, normalizedPath]), existing = plans.get(key);
|
|
6184
|
+
let plans = /* @__PURE__ */ new Map(), add = (plan) => {
|
|
6185
|
+
let normalizedPath = normalizeOutputPath(plan.path), origin = effectiveOrigin(manifest, plan.group), key = JSON.stringify([origin, normalizedPath]), existing = plans.get(key);
|
|
5440
6186
|
if (existing)
|
|
5441
6187
|
throw new AppError({
|
|
5442
6188
|
code: "FRAMEWORK_OUTPUT_PATH_COLLISION",
|
|
@@ -5448,32 +6194,45 @@ function planGeneratedOutputs(config, manifest) {
|
|
|
5448
6194
|
kind: plan.kind
|
|
5449
6195
|
}
|
|
5450
6196
|
});
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
6197
|
+
let normalized = { ...plan, path: normalizedPath };
|
|
6198
|
+
return plans.set(key, normalized), normalized;
|
|
6199
|
+
}, rootDefaults = resolveOutputDefaults(config), rootMountedGroup = Object.values(config.groups).find(
|
|
6200
|
+
(group) => group.key !== ROOT_CONTENT_GROUP_KEY && group.path === "/" && effectiveOrigin(manifest, group.key) === manifest.site.origin
|
|
6201
|
+
), rootMountedOutputs = rootMountedGroup?.outputs, rootLlmsDefaults = resolveOutputDefaults(config, rootMountedGroup).llms, rootScopeGroup = rootMountedGroup?.key ?? ROOT_CONTENT_GROUP_KEY, rootOutputs = {
|
|
6202
|
+
...config.outputs ?? {},
|
|
6203
|
+
robots: config.outputs?.robots ?? rootMountedOutputs?.robots,
|
|
6204
|
+
sitemap: config.outputs?.sitemap ?? rootMountedOutputs?.sitemap,
|
|
6205
|
+
sitemapMarkdown: config.outputs?.sitemapMarkdown ?? rootMountedOutputs?.sitemapMarkdown,
|
|
6206
|
+
llms: config.outputs?.llms ?? rootMountedOutputs?.llms,
|
|
6207
|
+
llmsFull: config.outputs?.llmsFull ?? rootMountedOutputs?.llmsFull
|
|
6208
|
+
};
|
|
6209
|
+
if (rootOutputs.robots !== !1 && add({ kind: "robots", path: rootOutputs.robots?.path ?? "/robots.txt" }), rootOutputs.sitemap !== !1 && add({
|
|
6210
|
+
kind: "sitemap",
|
|
6211
|
+
path: rootOutputs.sitemap?.path ?? "/sitemap.xml",
|
|
6212
|
+
...rootOutputs.sitemap?.mode === "urls" ? {} : { sitemaps: [] }
|
|
6213
|
+
}), rootOutputs.sitemapMarkdown !== !1 && add({
|
|
6214
|
+
kind: "sitemap-md",
|
|
6215
|
+
path: rootOutputs.sitemapMarkdown?.path ?? "/sitemap.md",
|
|
6216
|
+
scopeGroup: rootScopeGroup,
|
|
6217
|
+
scope: rootOutputs.sitemapMarkdown?.scope ?? (config.outputs?.sitemapMarkdown === void 0 && rootMountedOutputs?.sitemapMarkdown ? "group" : "site")
|
|
6218
|
+
}), rootOutputs.llms !== !1 && add({
|
|
5454
6219
|
kind: "llms",
|
|
5455
|
-
path: "/llms.txt",
|
|
5456
|
-
|
|
5457
|
-
|
|
6220
|
+
path: rootOutputs.llms?.path ?? "/llms.txt",
|
|
6221
|
+
scopeGroup: rootScopeGroup,
|
|
6222
|
+
scope: outputScope(
|
|
6223
|
+
rootLlmsDefaults,
|
|
6224
|
+
rootOutputs.llms ?? {},
|
|
6225
|
+
config.outputs?.llms === void 0 && rootMountedOutputs?.llms ? "group" : "site"
|
|
6226
|
+
),
|
|
6227
|
+
limit: outputLimit(rootLlmsDefaults, rootOutputs.llms ?? {}),
|
|
5458
6228
|
includeDescriptions: rootLlmsDefaults?.includeDescriptions
|
|
5459
|
-
}),
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
{ replaceKind: !0 }
|
|
5467
|
-
), rootOutputs.llms && add(
|
|
5468
|
-
{
|
|
5469
|
-
kind: "llms",
|
|
5470
|
-
path: rootOutputs.llms.path,
|
|
5471
|
-
scope: outputScope(rootLlmsDefaults, rootOutputs.llms, "site"),
|
|
5472
|
-
limit: outputLimit(rootLlmsDefaults, rootOutputs.llms),
|
|
5473
|
-
includeDescriptions: rootLlmsDefaults?.includeDescriptions
|
|
5474
|
-
},
|
|
5475
|
-
{ replaceKind: !0 }
|
|
5476
|
-
), rootOutputs.feeds?.rss) {
|
|
6229
|
+
}), rootOutputs.llmsFull !== !1 && add({
|
|
6230
|
+
kind: "llms-full",
|
|
6231
|
+
path: rootOutputs.llmsFull?.path ?? "/llms-full.txt",
|
|
6232
|
+
scopeGroup: rootScopeGroup,
|
|
6233
|
+
scope: rootOutputs.llmsFull?.scope ?? (config.outputs?.llmsFull === void 0 && rootMountedOutputs?.llmsFull ? "group" : "site"),
|
|
6234
|
+
limit: rootOutputs.llmsFull?.limit
|
|
6235
|
+
}), rootOutputs.feeds?.rss) {
|
|
5477
6236
|
let defaults = feedDefaults(rootDefaults, "rss");
|
|
5478
6237
|
add({
|
|
5479
6238
|
kind: "rss",
|
|
@@ -5504,23 +6263,56 @@ function planGeneratedOutputs(config, manifest) {
|
|
|
5504
6263
|
});
|
|
5505
6264
|
}
|
|
5506
6265
|
for (let group of Object.values(config.groups)) {
|
|
5507
|
-
let defaults = resolveOutputDefaults(config, group);
|
|
5508
|
-
if (group.outputs?.sitemap &&
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
6266
|
+
let defaults = resolveOutputDefaults(config, group), nested = group.key !== ROOT_CONTENT_GROUP_KEY && group.path !== "/";
|
|
6267
|
+
if (group.key !== rootMountedGroup?.key && (group.outputs?.sitemap || nested && group.outputs?.sitemap !== !1)) {
|
|
6268
|
+
if (group.outputs?.sitemap && group.outputs.sitemap.mode === "index")
|
|
6269
|
+
throw new AppError({
|
|
6270
|
+
code: "FRAMEWORK_OUTPUT_PATH_INVALID",
|
|
6271
|
+
message: `Group "${group.key}" cannot declare a sitemap index.`,
|
|
6272
|
+
fix: 'Use mode "urls" for a group sitemap, or configure the index in root outputs.sitemap.',
|
|
6273
|
+
details: {
|
|
6274
|
+
group: group.key,
|
|
6275
|
+
propertyPath: `groups.${group.key}.outputs.sitemap.mode`
|
|
6276
|
+
}
|
|
6277
|
+
});
|
|
6278
|
+
add({
|
|
6279
|
+
kind: "sitemap",
|
|
6280
|
+
path: joinOutputPath(
|
|
6281
|
+
group.path,
|
|
6282
|
+
group.outputs?.sitemap ? group.outputs.sitemap.path ?? "sitemap.xml" : "sitemap.xml"
|
|
6283
|
+
),
|
|
6284
|
+
group: group.key
|
|
6285
|
+
});
|
|
6286
|
+
}
|
|
6287
|
+
if (group.key !== rootMountedGroup?.key && (group.outputs?.llms || nested && group.outputs?.llms !== !1)) {
|
|
5513
6288
|
let llmsDefaults = defaults.llms;
|
|
5514
6289
|
add({
|
|
5515
6290
|
kind: "llms",
|
|
5516
|
-
path: joinOutputPath(
|
|
6291
|
+
path: joinOutputPath(
|
|
6292
|
+
group.path,
|
|
6293
|
+
group.outputs?.llms ? group.outputs.llms.path : "llms.txt"
|
|
6294
|
+
),
|
|
5517
6295
|
group: group.key,
|
|
5518
|
-
scope: outputScope(llmsDefaults, group.outputs
|
|
5519
|
-
limit: outputLimit(llmsDefaults, group.outputs
|
|
6296
|
+
scope: outputScope(llmsDefaults, group.outputs?.llms || {}, "group"),
|
|
6297
|
+
limit: outputLimit(llmsDefaults, group.outputs?.llms || {}),
|
|
5520
6298
|
includeDescriptions: llmsDefaults?.includeDescriptions
|
|
5521
6299
|
});
|
|
5522
6300
|
}
|
|
5523
|
-
if (group.outputs?.
|
|
6301
|
+
if (group.key !== rootMountedGroup?.key && (group.outputs?.sitemapMarkdown || nested && group.outputs?.sitemapMarkdown !== !1) && add({
|
|
6302
|
+
kind: "sitemap-md",
|
|
6303
|
+
path: joinOutputPath(
|
|
6304
|
+
group.path,
|
|
6305
|
+
group.outputs?.sitemapMarkdown ? group.outputs.sitemapMarkdown.path : "sitemap.md"
|
|
6306
|
+
),
|
|
6307
|
+
group: group.key,
|
|
6308
|
+
scope: group.outputs?.sitemapMarkdown ? group.outputs.sitemapMarkdown.scope ?? "group" : "group"
|
|
6309
|
+
}), group.key !== rootMountedGroup?.key && group.outputs?.llmsFull && add({
|
|
6310
|
+
kind: "llms-full",
|
|
6311
|
+
path: joinOutputPath(group.path, group.outputs.llmsFull.path),
|
|
6312
|
+
group: group.key,
|
|
6313
|
+
scope: group.outputs.llmsFull.scope ?? "group",
|
|
6314
|
+
limit: group.outputs.llmsFull.limit
|
|
6315
|
+
}), group.outputs?.feeds?.rss) {
|
|
5524
6316
|
let feedOptions = feedDefaults(defaults, "rss");
|
|
5525
6317
|
add({
|
|
5526
6318
|
kind: "rss",
|
|
@@ -5554,19 +6346,98 @@ function planGeneratedOutputs(config, manifest) {
|
|
|
5554
6346
|
});
|
|
5555
6347
|
}
|
|
5556
6348
|
}
|
|
6349
|
+
let xmlLeaves = [...plans.values()].filter(
|
|
6350
|
+
(plan) => plan.kind === "sitemap" && plan.group
|
|
6351
|
+
), rootSitemap = [...plans.values()].find(
|
|
6352
|
+
(plan) => plan.kind === "sitemap" && !plan.group
|
|
6353
|
+
);
|
|
6354
|
+
if (rootSitemap?.sitemaps) {
|
|
6355
|
+
let directory = outputDirectory2(rootSitemap.path), leaves = xmlLeaves.filter(
|
|
6356
|
+
(plan) => effectiveOrigin(manifest, plan.group) === manifest.site.origin && plan.path.startsWith(directory)
|
|
6357
|
+
);
|
|
6358
|
+
if ([
|
|
6359
|
+
"/",
|
|
6360
|
+
...Object.values(manifest.groups).filter(
|
|
6361
|
+
(group) => effectiveOrigin(manifest, group.key) === manifest.site.origin
|
|
6362
|
+
).map((group) => group.path),
|
|
6363
|
+
...manifest.pages.filter(
|
|
6364
|
+
(page) => page.status === "published" && effectiveOrigin(manifest, page.group) === manifest.site.origin
|
|
6365
|
+
).map((page) => page.path)
|
|
6366
|
+
].some(
|
|
6367
|
+
(path) => path.startsWith(directory) && !leaves.some((leaf) => path.startsWith(outputDirectory2(leaf.path)))
|
|
6368
|
+
)) {
|
|
6369
|
+
let rootLeaf = add({
|
|
6370
|
+
kind: "sitemap",
|
|
6371
|
+
path: `${rootSitemap.path.replace(/\.[^/.]+$/, "")}-pages.xml`
|
|
6372
|
+
});
|
|
6373
|
+
leaves.push(rootLeaf);
|
|
6374
|
+
}
|
|
6375
|
+
if (rootSitemap.sitemaps = leaves.map(({ path, group }) => ({
|
|
6376
|
+
path,
|
|
6377
|
+
...group ? { group } : {}
|
|
6378
|
+
})), !rootSitemap.sitemaps.length)
|
|
6379
|
+
throw new AppError({
|
|
6380
|
+
code: "FRAMEWORK_OUTPUT_PATH_INVALID",
|
|
6381
|
+
message: `Sitemap index "${rootSitemap.path}" has no generated sitemap files within its directory.`,
|
|
6382
|
+
fix: "Put the root sitemap index at the origin root, or use a directory that contains an enabled group sitemap.",
|
|
6383
|
+
details: { path: rootSitemap.path, directory }
|
|
6384
|
+
});
|
|
6385
|
+
xmlLeaves.push(...leaves.filter((leaf) => !leaf.group));
|
|
6386
|
+
}
|
|
6387
|
+
for (let leaf of xmlLeaves) {
|
|
6388
|
+
let directory = outputDirectory2(leaf.path);
|
|
6389
|
+
leaf.exclude = xmlLeaves.filter(
|
|
6390
|
+
(candidate) => candidate !== leaf && effectiveOrigin(manifest, candidate.group) === effectiveOrigin(manifest, leaf.group) && outputDirectory2(candidate.path).startsWith(directory) && outputDirectory2(candidate.path).length > directory.length
|
|
6391
|
+
).map(({ path, group }) => ({ path, ...group ? { group } : {} }));
|
|
6392
|
+
}
|
|
5557
6393
|
let groupLlmsPlans = [...plans.values()].filter(
|
|
5558
|
-
(plan) => plan.kind === "llms" && plan.group
|
|
6394
|
+
(plan) => plan.kind === "llms" && plan.group
|
|
5559
6395
|
);
|
|
5560
6396
|
for (let plan of plans.values())
|
|
5561
|
-
plan.kind
|
|
6397
|
+
plan.kind === "llms" ? (plan.links = groupLlmsPlans.filter(
|
|
6398
|
+
(candidate) => candidate !== plan && discoveryPlanCovers({
|
|
6399
|
+
manifest,
|
|
6400
|
+
plan,
|
|
6401
|
+
group: candidate.group ?? "",
|
|
6402
|
+
path: manifest.groups[candidate.group ?? ""]?.path ?? "/"
|
|
6403
|
+
})
|
|
6404
|
+
).map((llmsPlan) => ({
|
|
5562
6405
|
title: config.groups[llmsPlan.group ?? ""]?.title ?? llmsPlan.group ?? "Group",
|
|
5563
6406
|
path: llmsPlan.path,
|
|
5564
6407
|
group: llmsPlan.group
|
|
5565
|
-
}))
|
|
6408
|
+
})), plan.group && (plan.otherGroupLinks = groupLlmsPlans.filter(
|
|
6409
|
+
(candidate) => candidate !== plan && candidate.group !== plan.group && effectiveOrigin(manifest, candidate.group) === effectiveOrigin(manifest, plan.group) && !discoveryPlanCovers({
|
|
6410
|
+
manifest,
|
|
6411
|
+
plan,
|
|
6412
|
+
group: candidate.group ?? "",
|
|
6413
|
+
path: manifest.groups[candidate.group ?? ""]?.path ?? "/"
|
|
6414
|
+
})
|
|
6415
|
+
).map((candidate) => ({
|
|
6416
|
+
title: `${config.groups[candidate.group ?? ""]?.title ?? candidate.group ?? "Group"} llms.txt`,
|
|
6417
|
+
path: candidate.path,
|
|
6418
|
+
group: candidate.group
|
|
6419
|
+
})))) : plan.kind === "sitemap-md" && (plan.markdownAlternates = config.agent?.enabled !== !1 && config.agent?.markdownRoutes !== !1, plan.links = [...plans.values()].filter(
|
|
6420
|
+
(candidate) => (candidate.kind === "llms" || candidate.kind === "llms-full" || candidate.kind === "sitemap" && (plan.group ? candidate.group === plan.group : candidate === rootSitemap)) && candidate.group === plan.group
|
|
6421
|
+
).map((candidate) => ({
|
|
6422
|
+
title: candidate.kind === "llms" ? "LLMS index" : candidate.kind === "llms-full" ? "Full LLMS index" : "XML sitemap",
|
|
6423
|
+
path: candidate.path,
|
|
6424
|
+
...candidate.group ? { group: candidate.group } : {}
|
|
6425
|
+
})), plan.group && (plan.otherGroupLinks = [...plans.values()].filter(
|
|
6426
|
+
(candidate) => (candidate.kind === "sitemap-md" || candidate.kind === "sitemap" || candidate.kind === "llms") && candidate.group && candidate.group !== plan.group && effectiveOrigin(manifest, candidate.group) === effectiveOrigin(manifest, plan.group) && !discoveryPlanCovers({
|
|
6427
|
+
manifest,
|
|
6428
|
+
plan,
|
|
6429
|
+
group: candidate.group,
|
|
6430
|
+
path: manifest.groups[candidate.group]?.path ?? "/"
|
|
6431
|
+
})
|
|
6432
|
+
).map((candidate) => ({
|
|
6433
|
+
title: `${config.groups[candidate.group ?? ""]?.title ?? candidate.group ?? "Group"} ${candidate.kind === "sitemap-md" ? "sitemap.md" : candidate.kind === "sitemap" ? "XML sitemap" : "llms.txt"}`,
|
|
6434
|
+
path: candidate.path,
|
|
6435
|
+
group: candidate.group
|
|
6436
|
+
}))));
|
|
5566
6437
|
return [...plans.values()].sort((a, b) => a.path.localeCompare(b.path));
|
|
5567
6438
|
}
|
|
5568
6439
|
function validateGeneratedOutputPaths(config, manifest, plans, mediaManifest) {
|
|
5569
|
-
let outputKey = (origin, path) => JSON.stringify([origin,
|
|
6440
|
+
let outputKey = (origin, path) => JSON.stringify([origin, path]), reserved = /* @__PURE__ */ new Map(), reserve = (origin, path, value) => {
|
|
5570
6441
|
let key = outputKey(origin, path);
|
|
5571
6442
|
reserved.has(key) || reserved.set(key, value);
|
|
5572
6443
|
};
|
|
@@ -5588,10 +6459,7 @@ function validateGeneratedOutputPaths(config, manifest, plans, mediaManifest) {
|
|
|
5588
6459
|
]);
|
|
5589
6460
|
for (let asset of Object.values(mediaManifest?.assets ?? {}))
|
|
5590
6461
|
for (let origin of origins)
|
|
5591
|
-
reserve(origin, asset.
|
|
5592
|
-
kind: "media",
|
|
5593
|
-
owner: asset.sourcePath
|
|
5594
|
-
}), reserve(origin, asset.outputPath, {
|
|
6462
|
+
reserve(origin, asset.outputPath, {
|
|
5595
6463
|
kind: "media",
|
|
5596
6464
|
owner: asset.sourcePath
|
|
5597
6465
|
});
|
|
@@ -5634,7 +6502,7 @@ function validateGeneratedOutputPaths(config, manifest, plans, mediaManifest) {
|
|
|
5634
6502
|
outputRoutes.set(routePath, { path: plan.path, origin });
|
|
5635
6503
|
}
|
|
5636
6504
|
}
|
|
5637
|
-
async function appFilePlans(config, manifest, fonts, groupThemes,
|
|
6505
|
+
async function appFilePlans(config, manifest, fonts, groupThemes, privateFiles = [], notFoundScopes = []) {
|
|
5638
6506
|
let hasRootMountedGroup = Object.values(config.groups).some(
|
|
5639
6507
|
(group) => group.key !== ROOT_CONTENT_GROUP_KEY && group.path === "/"
|
|
5640
6508
|
), plans = [
|
|
@@ -5652,6 +6520,25 @@ async function appFilePlans(config, manifest, fonts, groupThemes, options) {
|
|
|
5652
6520
|
path: "app/providers.tsx",
|
|
5653
6521
|
content: BANNER + await readFile6(resolve7(SHIMS_DIR, "providers.tsx"), "utf-8")
|
|
5654
6522
|
},
|
|
6523
|
+
{
|
|
6524
|
+
path: "app/document.tsx",
|
|
6525
|
+
content: BANNER + await readFile6(resolve7(SHIMS_DIR, "document.tsx"), "utf8")
|
|
6526
|
+
},
|
|
6527
|
+
{
|
|
6528
|
+
path: "app/metadata-icons.tsx",
|
|
6529
|
+
content: BANNER + await readFile6(resolve7(SHIMS_DIR, "metadata-icons.tsx"), "utf8")
|
|
6530
|
+
},
|
|
6531
|
+
{
|
|
6532
|
+
path: "app/not-found-content.tsx",
|
|
6533
|
+
content: BANNER + await readFile6(resolve7(SHIMS_DIR, "not-found-content.tsx"), "utf8")
|
|
6534
|
+
},
|
|
6535
|
+
{
|
|
6536
|
+
path: "app/not-found-navigation.tsx",
|
|
6537
|
+
content: BANNER + await readFile6(
|
|
6538
|
+
resolve7(SHIMS_DIR, "not-found-navigation.tsx"),
|
|
6539
|
+
"utf8"
|
|
6540
|
+
)
|
|
6541
|
+
},
|
|
5655
6542
|
{
|
|
5656
6543
|
path: "proxy.ts",
|
|
5657
6544
|
content: BANNER + (await readFile6(resolve7(SHIMS_DIR, "proxy.ts"), "utf-8")).replaceAll(
|
|
@@ -5669,7 +6556,39 @@ async function appFilePlans(config, manifest, fonts, groupThemes, options) {
|
|
|
5669
6556
|
"utf-8"
|
|
5670
6557
|
)
|
|
5671
6558
|
}
|
|
5672
|
-
],
|
|
6559
|
+
], notFoundLayoutImports = [], notFoundLayouts = [];
|
|
6560
|
+
for (let [index, scope] of notFoundScopes.entries()) {
|
|
6561
|
+
if (!scope.group) continue;
|
|
6562
|
+
let groupChain = await resolveLayoutChain(config, scope.group, {
|
|
6563
|
+
themedGroups: groupThemes
|
|
6564
|
+
}), modulePath = `not-found-layout-${index}`;
|
|
6565
|
+
notFoundLayoutImports.push(
|
|
6566
|
+
`import NotFoundLayout${index} from "@app/${modulePath}";`
|
|
6567
|
+
), notFoundLayouts.push(
|
|
6568
|
+
`${JSON.stringify(scope.id)}: NotFoundLayout${index},`
|
|
6569
|
+
), plans.push({
|
|
6570
|
+
path: `app/${modulePath}.tsx`,
|
|
6571
|
+
content: BANNER + await generatedGroupLayoutModule(
|
|
6572
|
+
config,
|
|
6573
|
+
scope.group,
|
|
6574
|
+
groupChain,
|
|
6575
|
+
groupThemes,
|
|
6576
|
+
fonts
|
|
6577
|
+
)
|
|
6578
|
+
});
|
|
6579
|
+
}
|
|
6580
|
+
plans.push({
|
|
6581
|
+
path: "app/global-not-found.tsx",
|
|
6582
|
+
content: BANNER + await renderShim("global-not-found.tsx", {
|
|
6583
|
+
__PUBLISHOS_NOT_FOUND_LAYOUT_IMPORTS__: notFoundLayoutImports.join(`
|
|
6584
|
+
`),
|
|
6585
|
+
__PUBLISHOS_NOT_FOUND_LAYOUTS__: `{
|
|
6586
|
+
${notFoundLayouts.join(`
|
|
6587
|
+
`)}
|
|
6588
|
+
}`
|
|
6589
|
+
})
|
|
6590
|
+
});
|
|
6591
|
+
let outputPlans = planGeneratedOutputs(config, manifest);
|
|
5673
6592
|
validateGeneratedOutputPaths(config, manifest, outputPlans);
|
|
5674
6593
|
for (let output of outputPlans)
|
|
5675
6594
|
plans.push({
|
|
@@ -5682,25 +6601,7 @@ async function appFilePlans(config, manifest, fonts, groupThemes, options) {
|
|
|
5682
6601
|
}), plans.push({
|
|
5683
6602
|
path: `app/${FRAMEWORK_PREFIX.slice(1)}/api/og/[key]/route.ts`,
|
|
5684
6603
|
content: BANNER + await readFile6(resolve7(SHIMS_DIR, "og-image-route.ts"), "utf-8")
|
|
5685
|
-
})
|
|
5686
|
-
path: "app/ds/page.tsx",
|
|
5687
|
-
content: BANNER + await readFile6(
|
|
5688
|
-
resolve7(DIRECT_SHIMS_DIR, "design-system-page.tsx"),
|
|
5689
|
-
"utf-8"
|
|
5690
|
-
)
|
|
5691
|
-
}), plans.push({
|
|
5692
|
-
path: "app/ds/progress/page.tsx",
|
|
5693
|
-
content: BANNER + await readFile6(
|
|
5694
|
-
resolve7(DIRECT_SHIMS_DIR, "design-system-progress-page.tsx"),
|
|
5695
|
-
"utf-8"
|
|
5696
|
-
)
|
|
5697
|
-
}), plans.push({
|
|
5698
|
-
path: "app/ds/links/page.tsx",
|
|
5699
|
-
content: BANNER + await readFile6(
|
|
5700
|
-
resolve7(DIRECT_SHIMS_DIR, "design-system-links-page.tsx"),
|
|
5701
|
-
"utf-8"
|
|
5702
|
-
)
|
|
5703
|
-
}));
|
|
6604
|
+
});
|
|
5704
6605
|
for (let [groupKey, group] of Object.entries(config.groups)) {
|
|
5705
6606
|
let routeDir = routeDirForGroup(config, group), groupChain = await resolveLayoutChain(config, groupKey, {
|
|
5706
6607
|
themedGroups: groupThemes
|
|
@@ -5748,7 +6649,14 @@ async function appFilePlans(config, manifest, fonts, groupThemes, options) {
|
|
|
5748
6649
|
})
|
|
5749
6650
|
}));
|
|
5750
6651
|
}
|
|
5751
|
-
|
|
6652
|
+
let occupied = new Set(plans.map((plan) => plan.path)), collision = privateFiles.find((file) => occupied.has(file.path));
|
|
6653
|
+
if (collision)
|
|
6654
|
+
throw new AppError({
|
|
6655
|
+
code: "FRAMEWORK_PRIVATE_COMPOSITION_CONFLICT",
|
|
6656
|
+
message: "A private app file conflicts with a generated framework route.",
|
|
6657
|
+
details: { path: collision.path }
|
|
6658
|
+
});
|
|
6659
|
+
return [...plans, ...privateFiles];
|
|
5752
6660
|
}
|
|
5753
6661
|
function withPublicNavigationTargets(nodes, manifest) {
|
|
5754
6662
|
return nodes.map((node) => node.type === "page" ? {
|
|
@@ -5765,8 +6673,13 @@ async function writeComposedApplication(options) {
|
|
|
5765
6673
|
let preparedSource = options.preparedSource, config = preparedSource.config, manifest = withAttribution(preparedSource.manifest, {
|
|
5766
6674
|
config,
|
|
5767
6675
|
projectSlug: options.projectSlug
|
|
5768
|
-
}), connectedOrigin = options.hostedSite ? normalizeHostedSiteUrl(options.hostedSite.url) : void 0
|
|
5769
|
-
|
|
6676
|
+
}), connectedOrigin = options.hostedSite ? normalizeHostedSiteUrl(options.hostedSite.url) : void 0, rootOwnedGroups = new Set(
|
|
6677
|
+
Object.keys(manifest.groups).filter((key) => {
|
|
6678
|
+
let publicOrigin = config.groups[key]?.origin ?? config.origin ?? connectedOrigin;
|
|
6679
|
+
return !connectedOrigin || !publicOrigin || publicOrigin === connectedOrigin;
|
|
6680
|
+
})
|
|
6681
|
+
);
|
|
6682
|
+
options.hostedSite && (manifest.site.name = config.site?.name?.trim() || normalizeHostedSiteName(options.hostedSite.name)), manifest.site.origin = options.previewUrl ?? connectedOrigin ?? config.origin;
|
|
5770
6683
|
for (let [groupKey, group] of Object.entries(manifest.groups))
|
|
5771
6684
|
group.origin = options.previewUrl ? options.previewUrl : options.hostedSite ? config.groups[groupKey]?.origin ?? (groupKey === ROOT_CONTENT_GROUP_KEY ? void 0 : config.origin) ?? connectedOrigin : void 0;
|
|
5772
6685
|
manifest.tree = withPublicNavigationTargets(manifest.tree, manifest);
|
|
@@ -5781,19 +6694,33 @@ async function writeComposedApplication(options) {
|
|
|
5781
6694
|
},
|
|
5782
6695
|
signal: options.signal,
|
|
5783
6696
|
onDownloadStart: options.onAssetDownloadStart
|
|
6697
|
+
}), warnedMediaFiles = new Set(
|
|
6698
|
+
media.warnings.flatMap(
|
|
6699
|
+
(warning) => typeof warning.details?.file == "string" ? [warning.details.file] : []
|
|
6700
|
+
)
|
|
6701
|
+
), resourceAdmission = createThemeResourceAdmission({
|
|
6702
|
+
media,
|
|
6703
|
+
publishOsDir: options.publishOsDir
|
|
5784
6704
|
}), theme = await createThemeBuildPlan({
|
|
5785
6705
|
config,
|
|
5786
|
-
|
|
6706
|
+
media,
|
|
6707
|
+
publishOsDir: options.publishOsDir,
|
|
6708
|
+
resourceAdmission,
|
|
6709
|
+
onWarning: (warning) => {
|
|
6710
|
+
warning.file && warnedMediaFiles.has(warning.file) || (warning.file && warnedMediaFiles.add(warning.file), options.onWarning?.(warning));
|
|
6711
|
+
}
|
|
5787
6712
|
}), fonts = await fontBuildPlan({
|
|
5788
6713
|
config,
|
|
5789
6714
|
publishOsDir: options.publishOsDir,
|
|
5790
6715
|
prepareAssets,
|
|
5791
|
-
themeGroups: theme.groups
|
|
6716
|
+
themeGroups: theme.groups,
|
|
6717
|
+
resourceAdmission
|
|
5792
6718
|
}), og = await buildOgManifest({
|
|
5793
6719
|
faviconsAndLogos,
|
|
5794
6720
|
fonts: fonts.og,
|
|
5795
6721
|
prepareFonts: prepareAssets,
|
|
5796
6722
|
manifest,
|
|
6723
|
+
media,
|
|
5797
6724
|
mediaManifest: media.manifest,
|
|
5798
6725
|
publishOsDir: options.publishOsDir,
|
|
5799
6726
|
themes: theme.og,
|
|
@@ -5801,19 +6728,26 @@ async function writeComposedApplication(options) {
|
|
|
5801
6728
|
code: "FRAMEWORK_OG_COLOR_FALLBACK",
|
|
5802
6729
|
message
|
|
5803
6730
|
})
|
|
5804
|
-
}), sourceDir = resolve7(options.outputDir, "source"),
|
|
6731
|
+
}), sourceDir = resolve7(options.outputDir, "source"), outputPlans = planGeneratedOutputs(config, manifest);
|
|
5805
6732
|
validateGeneratedOutputPaths(config, manifest, outputPlans, media.manifest);
|
|
5806
6733
|
let { defaultsUsed, sourceOverrides } = await overlaySource(
|
|
5807
6734
|
options.publishOsDir,
|
|
5808
6735
|
sourceDir,
|
|
5809
6736
|
config,
|
|
5810
6737
|
fonts,
|
|
5811
|
-
theme
|
|
6738
|
+
theme,
|
|
6739
|
+
manifest.pages
|
|
5812
6740
|
);
|
|
5813
|
-
|
|
5814
|
-
resolve7(sourceDir,
|
|
5815
|
-
|
|
5816
|
-
|
|
6741
|
+
for (let file of options.privateComposition?.sourceFiles ?? []) {
|
|
6742
|
+
if (await fileExists5(resolve7(sourceDir, file.path)))
|
|
6743
|
+
throw new AppError({
|
|
6744
|
+
code: "FRAMEWORK_PRIVATE_COMPOSITION_CONFLICT",
|
|
6745
|
+
message: "A private source file conflicts with an existing source file.",
|
|
6746
|
+
details: { path: file.path }
|
|
6747
|
+
});
|
|
6748
|
+
await writeText(resolve7(sourceDir, file.path), BANNER + file.content);
|
|
6749
|
+
}
|
|
6750
|
+
await writeText(
|
|
5817
6751
|
resolve7(sourceDir, ".publishos", "media-manifest.generated.ts"),
|
|
5818
6752
|
mediaManifestModule(media.manifest)
|
|
5819
6753
|
), await writeText(
|
|
@@ -5834,23 +6768,38 @@ async function writeComposedApplication(options) {
|
|
|
5834
6768
|
resolve7(options.outputDir, ".meta", "og-manifest.json"),
|
|
5835
6769
|
`${JSON.stringify(ogManifestMetadata(og), null, 2)}
|
|
5836
6770
|
`
|
|
5837
|
-
)
|
|
6771
|
+
);
|
|
6772
|
+
let pageArtifactConversions = convertPublishedPageBodies(manifest), markdownRouteArtifacts = markdownArtifacts(
|
|
6773
|
+
manifest,
|
|
6774
|
+
outputPlans,
|
|
6775
|
+
pageArtifactConversions,
|
|
6776
|
+
rootOwnedGroups
|
|
6777
|
+
), markdownPaths = config.agent?.enabled === !1 || config.agent?.markdownRoutes === !1 ? /* @__PURE__ */ new Set() : new Set(
|
|
6778
|
+
markdownRouteArtifacts.map((artifact) => artifact.markdownPath)
|
|
6779
|
+
), notFoundScopes = createNotFoundScopes({
|
|
6780
|
+
manifest,
|
|
6781
|
+
outputs: outputPlans,
|
|
6782
|
+
rootOwnedGroups,
|
|
6783
|
+
markdownPaths
|
|
6784
|
+
});
|
|
6785
|
+
await writeText(
|
|
5838
6786
|
resolve7(sourceDir, ".publishos", "agent-route-config.generated.ts"),
|
|
5839
6787
|
agentRouteConfigModule(
|
|
5840
6788
|
config,
|
|
5841
6789
|
outputPlans,
|
|
5842
6790
|
manifest,
|
|
5843
|
-
|
|
6791
|
+
options.privateComposition?.publicPaths ?? [],
|
|
6792
|
+
notFoundScopes,
|
|
6793
|
+
markdownRouteArtifacts.map((artifact) => artifact.htmlPath)
|
|
5844
6794
|
)
|
|
5845
|
-
)
|
|
5846
|
-
let markdownRouteArtifacts = markdownArtifacts(
|
|
5847
|
-
manifest,
|
|
5848
|
-
outputPlans,
|
|
5849
|
-
media.manifest
|
|
5850
|
-
);
|
|
5851
|
-
await writeText(
|
|
6795
|
+
), await writeText(
|
|
5852
6796
|
resolve7(sourceDir, ".publishos", "agent-text.generated.ts"),
|
|
5853
|
-
agentTextOutputsModule(
|
|
6797
|
+
agentTextOutputsModule(
|
|
6798
|
+
manifest,
|
|
6799
|
+
outputPlans,
|
|
6800
|
+
markdownRouteArtifacts,
|
|
6801
|
+
markdownPaths
|
|
6802
|
+
)
|
|
5854
6803
|
);
|
|
5855
6804
|
let markdownRouteArtifactShards = createMarkdownArtifactShards(
|
|
5856
6805
|
markdownRouteArtifacts
|
|
@@ -5875,13 +6824,18 @@ async function writeComposedApplication(options) {
|
|
|
5875
6824
|
2
|
|
5876
6825
|
)}
|
|
5877
6826
|
`
|
|
5878
|
-
), await writeMediaOutputs({ media, outputDir: options.outputDir })
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
6827
|
+
), await writeMediaOutputs({ media, outputDir: options.outputDir });
|
|
6828
|
+
let appPlans = await appFilePlans(
|
|
6829
|
+
config,
|
|
6830
|
+
manifest,
|
|
6831
|
+
fonts,
|
|
6832
|
+
theme.groups,
|
|
6833
|
+
(options.privateComposition?.appFiles ?? []).map((file) => ({
|
|
6834
|
+
...file,
|
|
6835
|
+
content: BANNER + file.content
|
|
6836
|
+
})),
|
|
6837
|
+
notFoundScopes
|
|
6838
|
+
), componentManifest = await createComponentManifest({
|
|
5885
6839
|
applicationFiles: appPlans,
|
|
5886
6840
|
runtimeDistDir: RUNTIME_DIST_DIR,
|
|
5887
6841
|
sourceDir,
|
|
@@ -5903,13 +6857,20 @@ async function writeComposedApplication(options) {
|
|
|
5903
6857
|
});
|
|
5904
6858
|
for (let plan of appPlans)
|
|
5905
6859
|
await writeText(join6(options.outputDir, plan.path), plan.content);
|
|
6860
|
+
await mapLocalAssetUrlsInCss(options.outputDir);
|
|
5906
6861
|
let projectDir = resolve7(DEFAULTS_DIR, "project"), nextConfigTemplate = await readFile6(
|
|
5907
6862
|
resolve7(projectDir, "next.config.mjs"),
|
|
5908
6863
|
"utf-8"
|
|
5909
6864
|
);
|
|
5910
6865
|
await writeText(
|
|
5911
6866
|
resolve7(options.outputDir, "next.config.mjs"),
|
|
5912
|
-
renderFrameworkNextConfig(
|
|
6867
|
+
renderFrameworkNextConfig(
|
|
6868
|
+
nextConfigTemplate,
|
|
6869
|
+
await componentResolveAliases({
|
|
6870
|
+
outputDir: options.outputDir,
|
|
6871
|
+
sourceDir
|
|
6872
|
+
})
|
|
6873
|
+
)
|
|
5913
6874
|
), await copyText(
|
|
5914
6875
|
resolve7(projectDir, "tsconfig.json.template"),
|
|
5915
6876
|
resolve7(options.outputDir, "tsconfig.json")
|
|
@@ -5928,6 +6889,7 @@ async function writeComposedApplication(options) {
|
|
|
5928
6889
|
resolve7(options.outputDir, "manifest.generated.ts"),
|
|
5929
6890
|
manifestModule(manifest)
|
|
5930
6891
|
), await writeSearchRecordsArtifact({
|
|
6892
|
+
conversions: pageArtifactConversions,
|
|
5931
6893
|
outputDir: options.outputDir,
|
|
5932
6894
|
manifest
|
|
5933
6895
|
}), await writeText(
|
|
@@ -6002,7 +6964,7 @@ function normalizeHostedSiteUrl(value) {
|
|
|
6002
6964
|
}
|
|
6003
6965
|
async function physicalOutputPath(path) {
|
|
6004
6966
|
try {
|
|
6005
|
-
if ((await
|
|
6967
|
+
if ((await lstat3(path)).isSymbolicLink())
|
|
6006
6968
|
throw new AppError({
|
|
6007
6969
|
code: "FRAMEWORK_OUTPUT_SYMLINK",
|
|
6008
6970
|
message: "The composition output must not be a symbolic link."
|
|
@@ -6047,7 +7009,7 @@ function localPreviewOrigin(request, hosted) {
|
|
|
6047
7009
|
return value.origin;
|
|
6048
7010
|
}
|
|
6049
7011
|
async function removeTemporaryFontCache(staging) {
|
|
6050
|
-
let temporaryCache = join6(staging, ".font-assets"), cache = await
|
|
7012
|
+
let temporaryCache = join6(staging, ".font-assets"), cache = await lstat3(temporaryCache).catch(
|
|
6051
7013
|
(error) => {
|
|
6052
7014
|
if (error.code !== "ENOENT") throw error;
|
|
6053
7015
|
}
|
|
@@ -6085,7 +7047,21 @@ async function cleanupCompositionStage(staging, onProgress) {
|
|
|
6085
7047
|
}
|
|
6086
7048
|
}
|
|
6087
7049
|
async function composeFrameworkSource(options) {
|
|
6088
|
-
let { request, source, signal, onProgress } = options, outputDir = request.paths.output, archive = request.context?.archive;
|
|
7050
|
+
let { request, source, signal, onProgress } = options, outputDir = request.paths.output, archive = request.context?.archive, privateComposition = request.context?.privateComposition;
|
|
7051
|
+
if (privateComposition) {
|
|
7052
|
+
let validPath = (path, prefix) => path.startsWith(prefix) && !path.includes("\\") && !path.split("/").some((part) => part === "" || part === "." || part === "..");
|
|
7053
|
+
if (!["dev", "compose"].includes(request.operation) || request.context?.framework?.kind !== "checkout" || !privateComposition.appFiles.every(
|
|
7054
|
+
(file) => validPath(file.path, "app/")
|
|
7055
|
+
) || !privateComposition.sourceFiles.every(
|
|
7056
|
+
(file) => validPath(file.path, "_internal/")
|
|
7057
|
+
) || !privateComposition.publicPaths.every(
|
|
7058
|
+
(path) => path.startsWith("/") && !path.includes("..")
|
|
7059
|
+
))
|
|
7060
|
+
throw new AppError({
|
|
7061
|
+
code: "FRAMEWORK_PRIVATE_COMPOSITION_INVALID",
|
|
7062
|
+
message: "Private app files are allowed only for local checkout Dev and must use safe app and source paths."
|
|
7063
|
+
});
|
|
7064
|
+
}
|
|
6089
7065
|
if (!outputDir || !isAbsolute2(outputDir) || !archive && request.context?.framework?.kind !== "checkout")
|
|
6090
7066
|
throw new AppError({
|
|
6091
7067
|
code: "FRAMEWORK_COMPOSE_INPUT_INVALID",
|
|
@@ -6124,6 +7100,7 @@ async function composeFrameworkSource(options) {
|
|
|
6124
7100
|
try {
|
|
6125
7101
|
onProgress?.("Composing source"), await writeComposedApplication({
|
|
6126
7102
|
checkoutRoot: request.context?.framework?.kind === "checkout" ? installedFramework2.packageRoot : void 0,
|
|
7103
|
+
privateComposition,
|
|
6127
7104
|
publishOsDir: request.paths.source,
|
|
6128
7105
|
outputDir: staging,
|
|
6129
7106
|
preparedSource: source,
|
|
@@ -6147,8 +7124,6 @@ async function composeFrameworkSource(options) {
|
|
|
6147
7124
|
}
|
|
6148
7125
|
|
|
6149
7126
|
export {
|
|
6150
|
-
prepareAppInstallation,
|
|
6151
|
-
materializeAppInstallation,
|
|
6152
7127
|
createIdeSourceArtifacts,
|
|
6153
7128
|
composeFrameworkSource
|
|
6154
7129
|
};
|