@deot/docs-dever 1.1.5 → 1.1.6

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/README.md CHANGED
@@ -103,7 +103,7 @@ preview 与 production 不提供该入口;`/__docs/*` 在 preview 下返回 40
103
103
  - 原始源码中间件会校验真实路径,拒绝目录穿越和逃逸 workspace 的符号链接。
104
104
  - preview 不启动 Vite、watcher、HMR 或 SSE,不注入开发 runtime,且 `/__docs/*`(含页面保存入口)返回 404。
105
105
  - 根 workspace 构建会跳过隐藏目录、`node_modules`、`coverage`、常见构建缓存目录和当前 outDir。
106
- - 在本仓库预览时会复用统一 DDC 构建,并按 `@deot/docs-client[@version]/dist/index.*` 与 jsDelivr `/+esm`(映射到 `dist/index.js`)改写成本地 Client,本地地址保留 `dist/`;不限制 unpkg、jsDelivr 等 CDN 域名;其他项目保留 HTML 中声明的发布包 URL。
106
+ - 在本仓库预览时会复用统一 DDC 构建,提供本地 launch 与 Client。HTML 的 launch 地址映射到本地适配入口,先调用用户 CDN 钩子,再将动态生成的 Client JS/CSS 地址映射到当前 dist;支持 jsDelivr `/+esm` 和 ESM UNPKG 包根入口。已有 Client `dist/index.*` 地址仍直接改写,本地地址保留 `dist/`。其他项目保留 HTML 中声明的发布包 URL。
107
107
 
108
108
  ## 仓库内验证
109
109
 
package/dist/index.cjs CHANGED
@@ -518,7 +518,7 @@ var createRuntimePlugin = (options, resolvedWorkspace) => ({
518
518
  name: "docs-runtime",
519
519
  transformIndexHtml: options.build || options.preview ? void 0 : {
520
520
  order: "pre",
521
- handler() {
521
+ handler(html = "") {
522
522
  const workspace = (resolvedWorkspace || resolveDocsWorkspace(process.cwd(), options.workspace)).urlBase;
523
523
  const localClientEntry = node_path.resolve(process.cwd(), "packages/client/src/index.ts");
524
524
  const runtime = JSON.stringify({
@@ -526,7 +526,7 @@ var createRuntimePlugin = (options, resolvedWorkspace) => ({
526
526
  workspace,
527
527
  events: "/__docs/events"
528
528
  }).replace(/</g, "\\u003c");
529
- const styles = node_fs.existsSync(localClientEntry) ? [] : [
529
+ const styles = node_fs.existsSync(localClientEntry) || html.includes("@deot/docs-launch") ? [] : [
530
530
  "https://cdn.jsdelivr.net/npm/@deot/docs-client/dist/index.style.css",
531
531
  "https://cdn.jsdelivr.net/npm/@deot/docs-renderer/dist/index.style.css",
532
532
  "https://cdn.jsdelivr.net/npm/@deot/docs-markdown/dist/index.style.css",
@@ -831,7 +831,10 @@ var plugins_default = (options = {}, resolvedWorkspace) => (0, vite.defineConfig
831
831
  //#endregion
832
832
  //#region packages/dever/src/preview.ts
833
833
  var CLIENT_PREFIX = "/@deot/docs-client/";
834
+ var LAUNCH_PREFIX = "/@deot/docs-launch/";
835
+ var LAUNCH_ASSET_PATTERN = /https?:\/\/[^/"'\s<>]+(?:\/[^/"'\s<>?#]+)*\/@deot\/docs-launch(?:@[^/"'\s<>?#]+)?(?:\/\+esm|\/dist\/index\.js)?(?=["'\s<>?#]|$)/gu;
834
836
  var CLIENT_ENTRY = "dist/index.js";
837
+ var UNPKG_CLIENT_ENTRY_PATTERN = /https?:\/\/esm\.unpkg\.com\/@deot\/docs-client(?:@[^/"'\x60\s<>?#]+)?(?=["'\x60\s<>?#]|$)/gu;
835
838
  var CLIENT_ASSET_PATTERN = new RegExp([
836
839
  String.raw`(?:https?:)?//[^/"'\x60\s<>]+`,
837
840
  String.raw`(?:/[^/"'\x60\s<>?#]+)*/@deot/docs-client`,
@@ -933,9 +936,40 @@ var ensureLocalClientDist = async (cwd) => {
933
936
  if (!node_fs.existsSync(output)) throw new Error(`Local client build did not create: ${output}`);
934
937
  return localClient.clientDist;
935
938
  };
936
- var rewriteLocalClient = (html, clientDist) => clientDist ? Buffer.from(html.toString("utf8").replace(CLIENT_ASSET_PATTERN, (_url, asset, suffix) => `${CLIENT_PREFIX}${asset === "/+esm" ? CLIENT_ENTRY : asset.slice(1)}${suffix}`)) : html;
939
+ var rewriteLocalClient = (html, clientDist) => clientDist ? Buffer.from(html.toString("utf8").replace(CLIENT_ASSET_PATTERN, (_url, asset, suffix) => `${CLIENT_PREFIX}${asset === "/+esm" ? CLIENT_ENTRY : asset.slice(1)}${suffix}`).replace(UNPKG_CLIENT_ENTRY_PATTERN, `${CLIENT_PREFIX}${CLIENT_ENTRY}`)) : html;
940
+ var ensureLocalLaunchDist = async (cwd) => {
941
+ const source = node_path.resolve(cwd, "packages/launch/src");
942
+ if (!node_fs.existsSync(source)) return void 0;
943
+ const dist = node_path.resolve(cwd, "packages/launch/dist");
944
+ const output = node_path.join(dist, "index.js");
945
+ const inputTime = Math.max(...[
946
+ source,
947
+ node_path.resolve(cwd, "packages/launch/package.json"),
948
+ node_path.resolve(cwd, "z.build.config.ts")
949
+ ].map(getLatestModification));
950
+ if (getLatestModification(output) < inputTime) await _deot_dev_shared.Shell.spawn("npm", [
951
+ "run",
952
+ "build",
953
+ "--",
954
+ "--package-name",
955
+ "launch"
956
+ ], { cwd });
957
+ if (!node_fs.existsSync(output)) throw new Error(`Local launch build did not create: ${output}`);
958
+ return dist;
959
+ };
960
+ var localLaunchEntry = [
961
+ "const config = window.$docs ||= {};",
962
+ "const custom = config.resolve?.cdn;",
963
+ `const pattern = new RegExp(${JSON.stringify(CLIENT_ASSET_PATTERN.source)}, 'gu');`,
964
+ `const unpkg = new RegExp(${JSON.stringify(UNPKG_CLIENT_ENTRY_PATTERN.source)}, 'gu');`,
965
+ "config.resolve = {...config.resolve, cdn(context) {",
966
+ "const url = custom?.(context) || context.url;",
967
+ `return url.replace(pattern, (_url, asset, suffix) => ${JSON.stringify(CLIENT_PREFIX)} + (asset === '/+esm' ? ${JSON.stringify(CLIENT_ENTRY)} : asset.slice(1)) + suffix).replace(unpkg, ${JSON.stringify(CLIENT_PREFIX + CLIENT_ENTRY)});`,
968
+ "}};",
969
+ `import('${LAUNCH_PREFIX}dist/index.js');`
970
+ ].join("\n");
937
971
  var createEtag = (content) => `W/"${(0, node_crypto.createHash)("sha1").update(content).digest("hex")}"`;
938
- var sendFile = (req, res, filename, root, clientDist) => {
972
+ var sendFile = (req, res, filename, root, clientDist, launchDist) => {
939
973
  if (!node_fs.existsSync(filename) || !node_fs.statSync(filename).isFile()) return false;
940
974
  const realRoot = node_fs.realpathSync(root);
941
975
  const realFilename = node_fs.realpathSync(filename);
@@ -947,7 +981,8 @@ var sendFile = (req, res, filename, root, clientDist) => {
947
981
  const stat = node_fs.statSync(realFilename);
948
982
  const extension = node_path.extname(realFilename).toLowerCase();
949
983
  const rawContent = node_fs.readFileSync(realFilename);
950
- const content = extension === ".html" ? rewriteLocalClient(rawContent, clientDist) : rawContent;
984
+ let content = extension === ".html" ? rewriteLocalClient(rawContent, clientDist) : rawContent;
985
+ if (extension === ".html" && launchDist) content = Buffer.from(content.toString("utf8").replace(LAUNCH_ASSET_PATTERN, `${LAUNCH_PREFIX}+esm`));
951
986
  const etag = createEtag(content);
952
987
  const lastModified = stat.mtime.toUTCString();
953
988
  res.setHeader("Cache-Control", "no-cache");
@@ -976,6 +1011,7 @@ var sendFile = (req, res, filename, root, clientDist) => {
976
1011
  var createPreviewRequestHandler = (options) => {
977
1012
  const workspace = node_path.resolve(options.workspace);
978
1013
  const clientDist = options.clientDist && node_path.resolve(options.clientDist);
1014
+ const launchDist = options.launchDist && node_path.resolve(options.launchDist);
979
1015
  return (req, res) => {
980
1016
  try {
981
1017
  if (req.method !== "GET" && req.method !== "HEAD") {
@@ -985,6 +1021,12 @@ var createPreviewRequestHandler = (options) => {
985
1021
  return;
986
1022
  }
987
1023
  const pathname = decodeRequestPath(req.url || "/");
1024
+ if (launchDist && pathname === `${LAUNCH_PREFIX}+esm`) {
1025
+ res.setHeader("Content-Type", "text/javascript; charset=utf-8");
1026
+ res.setHeader("Cache-Control", "no-cache");
1027
+ res.end(req.method === "HEAD" ? void 0 : localLaunchEntry);
1028
+ return;
1029
+ }
988
1030
  const isPreviewPage = /^\/__docs\/(?:preview|raw-editor|markdown-editor)$/.test(pathname) && String(req.headers.accept || "").includes("text/html");
989
1031
  if (pathname.startsWith("/__docs/") && !isPreviewPage) {
990
1032
  res.statusCode = 404;
@@ -998,6 +1040,10 @@ var createPreviewRequestHandler = (options) => {
998
1040
  const rest = pathname.slice(19);
999
1041
  relative = rest === "+esm" ? "index.js" : rest.replace(/^dist\//u, "");
1000
1042
  }
1043
+ if (launchDist && pathname.startsWith(LAUNCH_PREFIX)) {
1044
+ root = launchDist;
1045
+ relative = pathname.slice(19).replace(/^dist\//u, "");
1046
+ }
1001
1047
  let filename = node_path.resolve(root, relative || "index.html");
1002
1048
  if (!isInside(root, filename)) {
1003
1049
  res.statusCode = 403;
@@ -1005,9 +1051,9 @@ var createPreviewRequestHandler = (options) => {
1005
1051
  return;
1006
1052
  }
1007
1053
  if (node_fs.existsSync(filename) && node_fs.statSync(filename).isDirectory()) filename = node_path.join(filename, "index.html");
1008
- if (sendFile(req, res, filename, root, clientDist)) return;
1054
+ if (sendFile(req, res, filename, root, clientDist, launchDist)) return;
1009
1055
  if (String(req.headers.accept || "").includes("text/html")) {
1010
- if (sendFile(req, res, node_path.join(workspace, "index.html"), workspace, clientDist)) return;
1056
+ if (sendFile(req, res, node_path.join(workspace, "index.html"), workspace, clientDist, launchDist)) return;
1011
1057
  }
1012
1058
  res.statusCode = 404;
1013
1059
  res.end("Not Found");
@@ -1037,9 +1083,11 @@ var startPreviewServer = async (options) => {
1037
1083
  const cwd = process.cwd();
1038
1084
  const workspace = resolveDocsWorkspace(cwd, options.workspace);
1039
1085
  const clientDist = await ensureLocalClientDist(cwd);
1086
+ const launchDist = await ensureLocalLaunchDist(cwd);
1040
1087
  const server = node_http.createServer(createPreviewRequestHandler({
1041
1088
  workspace: workspace.root,
1042
- clientDist
1089
+ clientDist,
1090
+ launchDist
1043
1091
  }));
1044
1092
  const port = Number(options.port ?? 4173);
1045
1093
  const host = String(options.host || "0.0.0.0");
package/dist/index.js CHANGED
@@ -489,7 +489,7 @@ var createRuntimePlugin = (options, resolvedWorkspace) => ({
489
489
  name: "docs-runtime",
490
490
  transformIndexHtml: options.build || options.preview ? void 0 : {
491
491
  order: "pre",
492
- handler() {
492
+ handler(html = "") {
493
493
  const workspace = (resolvedWorkspace || resolveDocsWorkspace(process.cwd(), options.workspace)).urlBase;
494
494
  const localClientEntry = path.resolve(process.cwd(), "packages/client/src/index.ts");
495
495
  const runtime = JSON.stringify({
@@ -497,7 +497,7 @@ var createRuntimePlugin = (options, resolvedWorkspace) => ({
497
497
  workspace,
498
498
  events: "/__docs/events"
499
499
  }).replace(/</g, "\\u003c");
500
- const styles = fs$1.existsSync(localClientEntry) ? [] : [
500
+ const styles = fs$1.existsSync(localClientEntry) || html.includes("@deot/docs-launch") ? [] : [
501
501
  "https://cdn.jsdelivr.net/npm/@deot/docs-client/dist/index.style.css",
502
502
  "https://cdn.jsdelivr.net/npm/@deot/docs-renderer/dist/index.style.css",
503
503
  "https://cdn.jsdelivr.net/npm/@deot/docs-markdown/dist/index.style.css",
@@ -802,7 +802,10 @@ var plugins_default = (options = {}, resolvedWorkspace) => defineConfig({ plugin
802
802
  //#endregion
803
803
  //#region packages/dever/src/preview.ts
804
804
  var CLIENT_PREFIX = "/@deot/docs-client/";
805
+ var LAUNCH_PREFIX = "/@deot/docs-launch/";
806
+ var LAUNCH_ASSET_PATTERN = /https?:\/\/[^/"'\s<>]+(?:\/[^/"'\s<>?#]+)*\/@deot\/docs-launch(?:@[^/"'\s<>?#]+)?(?:\/\+esm|\/dist\/index\.js)?(?=["'\s<>?#]|$)/gu;
805
807
  var CLIENT_ENTRY = "dist/index.js";
808
+ var UNPKG_CLIENT_ENTRY_PATTERN = /https?:\/\/esm\.unpkg\.com\/@deot\/docs-client(?:@[^/"'\x60\s<>?#]+)?(?=["'\x60\s<>?#]|$)/gu;
806
809
  var CLIENT_ASSET_PATTERN = new RegExp([
807
810
  String.raw`(?:https?:)?//[^/"'\x60\s<>]+`,
808
811
  String.raw`(?:/[^/"'\x60\s<>?#]+)*/@deot/docs-client`,
@@ -904,9 +907,40 @@ var ensureLocalClientDist = async (cwd) => {
904
907
  if (!fs$1.existsSync(output)) throw new Error(`Local client build did not create: ${output}`);
905
908
  return localClient.clientDist;
906
909
  };
907
- var rewriteLocalClient = (html, clientDist) => clientDist ? Buffer.from(html.toString("utf8").replace(CLIENT_ASSET_PATTERN, (_url, asset, suffix) => `${CLIENT_PREFIX}${asset === "/+esm" ? CLIENT_ENTRY : asset.slice(1)}${suffix}`)) : html;
910
+ var rewriteLocalClient = (html, clientDist) => clientDist ? Buffer.from(html.toString("utf8").replace(CLIENT_ASSET_PATTERN, (_url, asset, suffix) => `${CLIENT_PREFIX}${asset === "/+esm" ? CLIENT_ENTRY : asset.slice(1)}${suffix}`).replace(UNPKG_CLIENT_ENTRY_PATTERN, `${CLIENT_PREFIX}${CLIENT_ENTRY}`)) : html;
911
+ var ensureLocalLaunchDist = async (cwd) => {
912
+ const source = path.resolve(cwd, "packages/launch/src");
913
+ if (!fs$1.existsSync(source)) return void 0;
914
+ const dist = path.resolve(cwd, "packages/launch/dist");
915
+ const output = path.join(dist, "index.js");
916
+ const inputTime = Math.max(...[
917
+ source,
918
+ path.resolve(cwd, "packages/launch/package.json"),
919
+ path.resolve(cwd, "z.build.config.ts")
920
+ ].map(getLatestModification));
921
+ if (getLatestModification(output) < inputTime) await Shell.spawn("npm", [
922
+ "run",
923
+ "build",
924
+ "--",
925
+ "--package-name",
926
+ "launch"
927
+ ], { cwd });
928
+ if (!fs$1.existsSync(output)) throw new Error(`Local launch build did not create: ${output}`);
929
+ return dist;
930
+ };
931
+ var localLaunchEntry = [
932
+ "const config = window.$docs ||= {};",
933
+ "const custom = config.resolve?.cdn;",
934
+ `const pattern = new RegExp(${JSON.stringify(CLIENT_ASSET_PATTERN.source)}, 'gu');`,
935
+ `const unpkg = new RegExp(${JSON.stringify(UNPKG_CLIENT_ENTRY_PATTERN.source)}, 'gu');`,
936
+ "config.resolve = {...config.resolve, cdn(context) {",
937
+ "const url = custom?.(context) || context.url;",
938
+ `return url.replace(pattern, (_url, asset, suffix) => ${JSON.stringify(CLIENT_PREFIX)} + (asset === '/+esm' ? ${JSON.stringify(CLIENT_ENTRY)} : asset.slice(1)) + suffix).replace(unpkg, ${JSON.stringify(CLIENT_PREFIX + CLIENT_ENTRY)});`,
939
+ "}};",
940
+ `import('${LAUNCH_PREFIX}dist/index.js');`
941
+ ].join("\n");
908
942
  var createEtag = (content) => `W/"${createHash("sha1").update(content).digest("hex")}"`;
909
- var sendFile = (req, res, filename, root, clientDist) => {
943
+ var sendFile = (req, res, filename, root, clientDist, launchDist) => {
910
944
  if (!fs$1.existsSync(filename) || !fs$1.statSync(filename).isFile()) return false;
911
945
  const realRoot = fs$1.realpathSync(root);
912
946
  const realFilename = fs$1.realpathSync(filename);
@@ -918,7 +952,8 @@ var sendFile = (req, res, filename, root, clientDist) => {
918
952
  const stat = fs$1.statSync(realFilename);
919
953
  const extension = path.extname(realFilename).toLowerCase();
920
954
  const rawContent = fs$1.readFileSync(realFilename);
921
- const content = extension === ".html" ? rewriteLocalClient(rawContent, clientDist) : rawContent;
955
+ let content = extension === ".html" ? rewriteLocalClient(rawContent, clientDist) : rawContent;
956
+ if (extension === ".html" && launchDist) content = Buffer.from(content.toString("utf8").replace(LAUNCH_ASSET_PATTERN, `${LAUNCH_PREFIX}+esm`));
922
957
  const etag = createEtag(content);
923
958
  const lastModified = stat.mtime.toUTCString();
924
959
  res.setHeader("Cache-Control", "no-cache");
@@ -947,6 +982,7 @@ var sendFile = (req, res, filename, root, clientDist) => {
947
982
  var createPreviewRequestHandler = (options) => {
948
983
  const workspace = path.resolve(options.workspace);
949
984
  const clientDist = options.clientDist && path.resolve(options.clientDist);
985
+ const launchDist = options.launchDist && path.resolve(options.launchDist);
950
986
  return (req, res) => {
951
987
  try {
952
988
  if (req.method !== "GET" && req.method !== "HEAD") {
@@ -956,6 +992,12 @@ var createPreviewRequestHandler = (options) => {
956
992
  return;
957
993
  }
958
994
  const pathname = decodeRequestPath(req.url || "/");
995
+ if (launchDist && pathname === `${LAUNCH_PREFIX}+esm`) {
996
+ res.setHeader("Content-Type", "text/javascript; charset=utf-8");
997
+ res.setHeader("Cache-Control", "no-cache");
998
+ res.end(req.method === "HEAD" ? void 0 : localLaunchEntry);
999
+ return;
1000
+ }
959
1001
  const isPreviewPage = /^\/__docs\/(?:preview|raw-editor|markdown-editor)$/.test(pathname) && String(req.headers.accept || "").includes("text/html");
960
1002
  if (pathname.startsWith("/__docs/") && !isPreviewPage) {
961
1003
  res.statusCode = 404;
@@ -969,6 +1011,10 @@ var createPreviewRequestHandler = (options) => {
969
1011
  const rest = pathname.slice(19);
970
1012
  relative = rest === "+esm" ? "index.js" : rest.replace(/^dist\//u, "");
971
1013
  }
1014
+ if (launchDist && pathname.startsWith(LAUNCH_PREFIX)) {
1015
+ root = launchDist;
1016
+ relative = pathname.slice(19).replace(/^dist\//u, "");
1017
+ }
972
1018
  let filename = path.resolve(root, relative || "index.html");
973
1019
  if (!isInside(root, filename)) {
974
1020
  res.statusCode = 403;
@@ -976,9 +1022,9 @@ var createPreviewRequestHandler = (options) => {
976
1022
  return;
977
1023
  }
978
1024
  if (fs$1.existsSync(filename) && fs$1.statSync(filename).isDirectory()) filename = path.join(filename, "index.html");
979
- if (sendFile(req, res, filename, root, clientDist)) return;
1025
+ if (sendFile(req, res, filename, root, clientDist, launchDist)) return;
980
1026
  if (String(req.headers.accept || "").includes("text/html")) {
981
- if (sendFile(req, res, path.join(workspace, "index.html"), workspace, clientDist)) return;
1027
+ if (sendFile(req, res, path.join(workspace, "index.html"), workspace, clientDist, launchDist)) return;
982
1028
  }
983
1029
  res.statusCode = 404;
984
1030
  res.end("Not Found");
@@ -1008,9 +1054,11 @@ var startPreviewServer = async (options) => {
1008
1054
  const cwd = process.cwd();
1009
1055
  const workspace = resolveDocsWorkspace(cwd, options.workspace);
1010
1056
  const clientDist = await ensureLocalClientDist(cwd);
1057
+ const launchDist = await ensureLocalLaunchDist(cwd);
1011
1058
  const server = http.createServer(createPreviewRequestHandler({
1012
1059
  workspace: workspace.root,
1013
- clientDist
1060
+ clientDist,
1061
+ launchDist
1014
1062
  }));
1015
1063
  const port = Number(options.port ?? 4173);
1016
1064
  const host = String(options.host || "0.0.0.0");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deot/docs-dever",
3
- "version": "1.1.5",
3
+ "version": "1.1.6",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",