@aiquants/markdown 1.18.0 → 2.0.0

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.
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const L=require("cheerio"),w=require("./simple-logger-DZxBpX7v.cjs"),q=require("unist-util-visit"),$=require("node:fs/promises"),h=require("node:path"),j=require("url-join"),J=require("node:child_process"),M=require("node:fs"),W=require("node:module"),K=require("node:net"),z=require("node:url"),G=require("@connectrpc/connect"),V=require("@connectrpc/connect-node"),m=require("@bufbuild/protobuf");var N=typeof document<"u"?document.currentScript:null;function x(t){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t){for(const r in t)if(r!=="default"){const l=Object.getOwnPropertyDescriptor(t,r);Object.defineProperty(e,r,l.get?l:{enumerable:!0,get:()=>t[r]})}}return e.default=t,Object.freeze(e)}const Z=x(L),_=x(h),C=x(K),F=async t=>{try{const e=new AbortController,r=setTimeout(()=>e.abort(),1e4),l=await fetch(t,{signal:e.signal});if(clearTimeout(r),!l.ok)return null;const s=await l.text(),o={url:t},a=L.load(s),n=a("title").text().trim();o.title=n;const c=a("meta");for(const i of c){const u=i.attribs.property;u==="og:site_name"&&(o.site_name=i.attribs.content||void 0),u==="og:title"&&(o.title=i.attribs.content||n),u==="og:description"&&(o.description=i.attribs.content||void 0),u==="og:image"&&(o.image=i.attribs.content||void 0),u==="og:type"&&(o.type=i.attribs.content||void 0),i.attribs.name==="description"&&(o.description=i.attribs.content||void 0)}return o}catch(e){return w.Logger.error("Error fetching site metadata:",e),null}},T=new Map,H=(t,e)=>e.fetchAll?!0:e.urlPatterns&&e.urlPatterns.length>0?e.urlPatterns.some(r=>r.test(t)):/^https?:\/\//.test(t)&&!t.includes("localhost")&&!t.includes("127.0.0.1"),X=(t={})=>{const{enableCache:e=!0}=t;return async r=>{const l=[];q.visit(r,"block-link",o=>{H(o.url,t)&&l.push(o)});const s=l.map(async o=>{const a=o.url;if(e&&T.has(a)){const n=T.get(a);n&&(o.data=o.data||{},o.data.siteMetadata=n);return}try{const n=await F(a);n?(o.data=o.data||{},o.data.siteMetadata=n,e&&T.set(a,n)):e&&T.set(a,null)}catch(n){w.Logger.warn(`Failed to fetch metadata for ${a}:`,n),e&&T.set(a,null)}});await Promise.all(s)}},Y=/<!--\s+@import\s+"(.+?)"\s+-->/;function Q(t){return async e=>{const{markdownFilePath:r}=t,l=h.dirname(r),s=[];if(q.visit(e,"html",(a,n,c)=>{if(!c||typeof n!="number")return;const i=a.value.match(Y);if(!i)return;const u=i[1],d=h.resolve(l,u);Array.isArray(c.children)&&s.push({parent:c,index:n,absolutePath:d})}),s.length===0)return;const o=await Promise.all(s.map(async({absolutePath:a})=>{try{const n=await $.readFile(a,"utf-8");return this.parse(n)}catch(n){return n&&n.code==="ENOENT"?w.Logger.warn(`[remark-import-directive] Import file not found: ${a}`):w.Logger.error(`[remark-import-directive] Error processing import: ${a}`,n),null}}));for(let a=s.length-1;a>=0;a--){const{parent:n,index:c}=s[a],i=o[a];i?.children&&Array.isArray(i.children)&&n.children.splice(c,1,...i.children)}}}const O=/^[a-z][a-z0-9+.-]*:/,R=async(t,e,r,l,s=!1)=>{if(!t)return"";if(O.test(t)){const u=t.substring(0,t.indexOf(":")).toLowerCase();if(["http","https","mailto","tel","file"].includes(u))return t}if(t.startsWith("#")||t.startsWith("/"))return t;const o=decodeURIComponent(t),a=h.dirname(r),n=h.normalize(h.join(a,o)),c=h.resolve(l,n);if(!c.startsWith(l)||n.startsWith(".."))return w.Logger.error(`Security Alert: Attempt to access file outside project root: ${c}`),"";if(s)try{await $.access(c)}catch{return w.Logger.warn(`File not found: ${c}`),""}const i=n.replace(/\\/g,"/");return e?j("/assets/",i):`?filePath=${encodeURIComponent(i)}`};function ee(t){return async e=>{if(!(t?.markdownFilePath&&t?.workspaceRoot)){w.Logger.warn("remark-resolve-uri-async: markdownFilePath and workspaceRoot are required. Skipping URI resolution.");return}const r=[],l=[];q.visit(e,["image","link","html"],a=>{if(a.type==="html")l.push(a);else{const n=a;n.url&&r.push({node:n,isImage:n.type==="image"})}});const s=r.map(async({node:a,isImage:n})=>{const c=await R(a.url,n,t.markdownFilePath,t.workspaceRoot,t.validateExistence);a.url=c}),o=l.map(async a=>{const n=Z.load(a.value,null,!1);let c=!1;const i=n("img").toArray();for(const d of i){const f=n(d).attr("src");if(f){const p=await R(f,!0,t.markdownFilePath,t.workspaceRoot,t.validateExistence);p!==f&&(n(d).attr("src",p),c=!0)}}const u=n("a").toArray();for(const d of u){const f=n(d).attr("href");if(f){const p=await R(f,!1,t.markdownFilePath,t.workspaceRoot,t.validateExistence);p!==f&&(n(d).attr("href",p),c=!0)}}if(c){const d=n.html();d&&(a.value=d)}});await Promise.all([...s,...o])}}class g extends m.Message{markdownText="";filePath="";workspaceRoot="";validateExistence=!1;enableSubscript;enableSuperscript;enableMark;enableTableMerge;enableEmbeds;enableZennDirectives;constructor(e){super(),m.proto3.util.initPartial(e,this)}static runtime=m.proto3;static typeName="markdown.v1.ConvertRequest";static fields=m.proto3.util.newFieldList(()=>[{no:1,name:"markdown_text",kind:"scalar",T:9},{no:2,name:"file_path",kind:"scalar",T:9},{no:3,name:"workspace_root",kind:"scalar",T:9},{no:4,name:"validate_existence",kind:"scalar",T:8},{no:5,name:"enable_subscript",kind:"scalar",T:8,opt:!0},{no:6,name:"enable_superscript",kind:"scalar",T:8,opt:!0},{no:7,name:"enable_mark",kind:"scalar",T:8,opt:!0},{no:8,name:"enable_table_merge",kind:"scalar",T:8,opt:!0},{no:9,name:"enable_embeds",kind:"scalar",T:8,opt:!0},{no:10,name:"enable_zenn_directives",kind:"scalar",T:8,opt:!0}]);static fromBinary(e,r){return new g().fromBinary(e,r)}static fromJson(e,r){return new g().fromJson(e,r)}static fromJsonString(e,r){return new g().fromJsonString(e,r)}static equals(e,r){return m.proto3.util.equals(g,e,r)}}class y extends m.Message{htmlContent="";headings=[];constructor(e){super(),m.proto3.util.initPartial(e,this)}static runtime=m.proto3;static typeName="markdown.v1.ConvertResponse";static fields=m.proto3.util.newFieldList(()=>[{no:1,name:"html_content",kind:"scalar",T:9},{no:2,name:"headings",kind:"message",T:b,repeated:!0}]);static fromBinary(e,r){return new y().fromBinary(e,r)}static fromJson(e,r){return new y().fromJson(e,r)}static fromJsonString(e,r){return new y().fromJsonString(e,r)}static equals(e,r){return m.proto3.util.equals(y,e,r)}}class b extends m.Message{text="";depth=0;id="";constructor(e){super(),m.proto3.util.initPartial(e,this)}static runtime=m.proto3;static typeName="markdown.v1.Heading";static fields=m.proto3.util.newFieldList(()=>[{no:1,name:"text",kind:"scalar",T:9},{no:2,name:"depth",kind:"scalar",T:5},{no:3,name:"id",kind:"scalar",T:9}]);static fromBinary(e,r){return new b().fromBinary(e,r)}static fromJson(e,r){return new b().fromJson(e,r)}static fromJsonString(e,r){return new b().fromJsonString(e,r)}static equals(e,r){return m.proto3.util.equals(b,e,r)}}const te={typeName:"markdown.v1.MarkdownService",methods:{convert:{name:"Convert",I:g,O:y,kind:m.MethodKind.Unary}}},k=process.env.MARKDOWN_SOCKET_PATH||"/tmp/markdown.sock",re=V.createConnectTransport({baseUrl:"http://localhost",httpVersion:"2",nodeOptions:{createConnection:()=>C.connect(k)}}),ne=G.createClient(te,re),E=()=>{try{return _.dirname(z.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:N&&N.tagName.toUpperCase()==="SCRIPT"&&N.src||new URL("index.server.cjs",document.baseURI).href))}catch{return __dirname}},B=()=>`@aiquants/markdown-${process.platform}-${process.arch}`,I=()=>process.platform==="win32"?"bin/markdown-api.exe":"bin/markdown-api",ae=()=>{const t=process.env.MARKDOWN_API_BINARY;if(t&&M.existsSync(t))return t;try{const r=W.createRequire(_.join(E(),"index.js")).resolve(`${B()}/${I()}`);if(M.existsSync(r))return r}catch{}const e=_.join(E(),"..","..","go","markdown-api","dist",_.basename(I()));return M.existsSync(e)?e:void 0},oe=()=>[`markdown-api binary not found for ${process.platform}-${process.arch}.`,`Expected the optional dependency ${B()} to be installed.`,"If your platform is unsupported, build the service yourself","(https://github.com/fehde-k/aiquants/tree/main/packages/go/markdown-api)","and point MARKDOWN_API_BINARY at it."].join(" "),D=()=>new Promise(t=>{const e=C.connect(k);e.on("connect",()=>{e.destroy(),t(!0)}),e.on("error",()=>t(!1))}),U=async t=>{const e=Date.now();for(;Date.now()-e<t;){if(await D())return!0;await new Promise(r=>setTimeout(r,100))}return!1};let S=null,P=null;const se=2e3,ie=()=>{const t=Number(process.env.MARKDOWN_API_STARTUP_TIMEOUT_MS);return Number.isFinite(t)&&t>0?t:1e4};let A=null;const ce=async()=>{if(await D())return!0;if(P)return P;P=(async()=>{const e=ae();if(!e)return await U(se)?!0:(A=oe(),!1);A=null;try{M.existsSync(k)&&M.unlinkSync(k)}catch{}try{S=J.spawn(e,[],{stdio:"ignore"});const r=()=>{if(S){try{S.kill("SIGTERM")}catch{}S=null}};return process.once("exit",r),await U(ie())?!0:(console.error("markdown-api Go server did not become ready on socket:",k),r(),process.removeListener("exit",r),!1)}catch(r){return console.error("Failed to spawn markdown-api Go server:",r),S=null,!1}})();const t=await P;return t||(P=null),t},le=async(t,e,r,l,s=!0)=>{if(!await ce()){const v=A?` ${A}`:"";throw new Error(`markdown service is not reachable on ${k}.${v}`)}let o=!0,a,n,c,i,u,d;typeof s=="boolean"?o=s:s&&typeof s=="object"&&(o=s.validateExistence??!0,a=s.enableSubscript,n=s.enableSuperscript,c=s.enableMark,i=s.enableTableMerge,u=s.enableEmbeds,d=s.enableZennDirectives);const f={};l&&(f.Authorization=`Bearer ${l}`);const p=await ne.convert({markdownText:t,filePath:e,workspaceRoot:r,validateExistence:o,enableSubscript:a,enableSuperscript:n,enableMark:c,enableTableMerge:i,enableEmbeds:u,enableZennDirectives:d},{headers:f});return{htmlContent:p.htmlContent,headings:p.headings.map(v=>({text:v.text,depth:v.depth,id:v.id}))}};exports.fetchSiteMetadata=F;exports.parseMarkdown=le;exports.remarkBlockLinkMetadata=X;exports.remarkImportDirective=Q;exports.remarkResolveUriAsync=ee;exports.transformUriAsync=R;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const D=require("cheerio"),A=require("./simple-logger-DZxBpX7v.cjs"),I=require("unist-util-visit"),J=require("node:child_process"),g=require("node:fs"),j=require("node:module"),U=require("node:net"),E=require("node:path"),F=require("node:url"),K=require("@connectrpc/connect"),G=require("@connectrpc/connect-node"),a=require("@bufbuild/protobuf");var _=typeof document<"u"?document.currentScript:null;function B(r){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const t in r)if(t!=="default"){const c=Object.getOwnPropertyDescriptor(r,t);Object.defineProperty(e,t,c.get?c:{enumerable:!0,get:()=>r[t]})}}return e.default=r,Object.freeze(e)}const x=B(U),S=B(E),C=async r=>{try{const e=new AbortController,t=setTimeout(()=>e.abort(),1e4),c=await fetch(r,{signal:e.signal});if(clearTimeout(t),!c.ok)return null;const o=await c.text(),n={url:r},i=D.load(o),s=i("title").text().trim();n.title=s;const k=i("meta");for(const l of k){const u=l.attribs.property;u==="og:site_name"&&(n.site_name=l.attribs.content||void 0),u==="og:title"&&(n.title=l.attribs.content||s),u==="og:description"&&(n.description=l.attribs.content||void 0),u==="og:image"&&(n.image=l.attribs.content||void 0),u==="og:type"&&(n.type=l.attribs.content||void 0),l.attribs.name==="description"&&(n.description=l.attribs.content||void 0)}return n}catch(e){return A.Logger.error("Error fetching site metadata:",e),null}},h=new Map,W=(r,e)=>e.fetchAll?!0:e.urlPatterns&&e.urlPatterns.length>0?e.urlPatterns.some(t=>t.test(r)):/^https?:\/\//.test(r)&&!r.includes("localhost")&&!r.includes("127.0.0.1"),z=(r={})=>{const{enableCache:e=!0}=r;return async t=>{const c=[];I.visit(t,"block-link",n=>{W(n.url,r)&&c.push(n)});const o=c.map(async n=>{const i=n.url;if(e&&h.has(i)){const s=h.get(i);s&&(n.data=n.data||{},n.data.siteMetadata=s);return}try{const s=await C(i);s?(n.data=n.data||{},n.data.siteMetadata=s,e&&h.set(i,s)):e&&h.set(i,null)}catch(s){A.Logger.warn(`Failed to fetch metadata for ${i}:`,s),e&&h.set(i,null)}});await Promise.all(o)}};class d extends a.Message{markdownText="";filePath="";workspaceRoot="";validateExistence=!1;enableSubscript;enableSuperscript;enableMark;enableTableMerge;enableEmbeds;enableZennDirectives;constructor(e){super(),a.proto3.util.initPartial(e,this)}static runtime=a.proto3;static typeName="markdown.v1.ConvertRequest";static fields=a.proto3.util.newFieldList(()=>[{no:1,name:"markdown_text",kind:"scalar",T:9},{no:2,name:"file_path",kind:"scalar",T:9},{no:3,name:"workspace_root",kind:"scalar",T:9},{no:4,name:"validate_existence",kind:"scalar",T:8},{no:5,name:"enable_subscript",kind:"scalar",T:8,opt:!0},{no:6,name:"enable_superscript",kind:"scalar",T:8,opt:!0},{no:7,name:"enable_mark",kind:"scalar",T:8,opt:!0},{no:8,name:"enable_table_merge",kind:"scalar",T:8,opt:!0},{no:9,name:"enable_embeds",kind:"scalar",T:8,opt:!0},{no:10,name:"enable_zenn_directives",kind:"scalar",T:8,opt:!0}]);static fromBinary(e,t){return new d().fromBinary(e,t)}static fromJson(e,t){return new d().fromJson(e,t)}static fromJsonString(e,t){return new d().fromJsonString(e,t)}static equals(e,t){return a.proto3.util.equals(d,e,t)}}class m extends a.Message{htmlContent="";headings=[];constructor(e){super(),a.proto3.util.initPartial(e,this)}static runtime=a.proto3;static typeName="markdown.v1.ConvertResponse";static fields=a.proto3.util.newFieldList(()=>[{no:1,name:"html_content",kind:"scalar",T:9},{no:2,name:"headings",kind:"message",T:p,repeated:!0}]);static fromBinary(e,t){return new m().fromBinary(e,t)}static fromJson(e,t){return new m().fromJson(e,t)}static fromJsonString(e,t){return new m().fromJsonString(e,t)}static equals(e,t){return a.proto3.util.equals(m,e,t)}}class p extends a.Message{text="";depth=0;id="";constructor(e){super(),a.proto3.util.initPartial(e,this)}static runtime=a.proto3;static typeName="markdown.v1.Heading";static fields=a.proto3.util.newFieldList(()=>[{no:1,name:"text",kind:"scalar",T:9},{no:2,name:"depth",kind:"scalar",T:5},{no:3,name:"id",kind:"scalar",T:9}]);static fromBinary(e,t){return new p().fromBinary(e,t)}static fromJson(e,t){return new p().fromJson(e,t)}static fromJsonString(e,t){return new p().fromJsonString(e,t)}static equals(e,t){return a.proto3.util.equals(p,e,t)}}const V={typeName:"markdown.v1.MarkdownService",methods:{convert:{name:"Convert",I:d,O:m,kind:a.MethodKind.Unary}}},f=process.env.MARKDOWN_SOCKET_PATH||"/tmp/markdown.sock",Z=G.createConnectTransport({baseUrl:"http://localhost",httpVersion:"2",nodeOptions:{createConnection:()=>x.connect(f)}}),Y=K.createClient(V,Z),q=()=>{try{return S.dirname(F.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:_&&_.tagName.toUpperCase()==="SCRIPT"&&_.src||new URL("index.server.cjs",document.baseURI).href))}catch{return __dirname}},L=()=>`@aiquants/markdown-${process.platform}-${process.arch}`,N=()=>process.platform==="win32"?"bin/markdown-api.exe":"bin/markdown-api",X=()=>{const r=process.env.MARKDOWN_API_BINARY;if(r&&g.existsSync(r))return r;try{const t=j.createRequire(S.join(q(),"index.js")).resolve(`${L()}/${N()}`);if(g.existsSync(t))return t}catch{}const e=S.join(q(),"..","..","go","markdown-api","dist",S.basename(N()));return g.existsSync(e)?e:void 0},H=()=>[`markdown-api binary not found for ${process.platform}-${process.arch}.`,`Expected the optional dependency ${L()} to be installed.`,"If your platform is unsupported, build the service yourself","(https://github.com/fehde-k/aiquants/tree/main/packages/go/markdown-api)","and point MARKDOWN_API_BINARY at it."].join(" "),$=()=>new Promise(r=>{const e=x.connect(f);e.on("connect",()=>{e.destroy(),r(!0)}),e.on("error",()=>r(!1))}),R=async r=>{const e=Date.now();for(;Date.now()-e<r;){if(await $())return!0;await new Promise(t=>setTimeout(t,100))}return!1};let w=null,y=null;const Q=2e3,O=()=>{const r=Number(process.env.MARKDOWN_API_STARTUP_TIMEOUT_MS);return Number.isFinite(r)&&r>0?r:1e4};let T=null;const ee=async()=>{if(await $())return!0;if(y)return y;y=(async()=>{const e=X();if(!e)return await R(Q)?!0:(T=H(),!1);T=null;try{g.existsSync(f)&&g.unlinkSync(f)}catch{}try{w=J.spawn(e,[],{stdio:"ignore"});const t=()=>{if(w){try{w.kill("SIGTERM")}catch{}w=null}};return process.once("exit",t),await R(O())?!0:(console.error("markdown-api Go server did not become ready on socket:",f),t(),process.removeListener("exit",t),!1)}catch(t){return console.error("Failed to spawn markdown-api Go server:",t),w=null,!1}})();const r=await y;return r||(y=null),r},te=async(r,e,t,c,o=!0)=>{if(!await ee()){const b=T?` ${T}`:"";throw new Error(`markdown service is not reachable on ${f}.${b}`)}let n=!0,i,s,k,l,u,M;typeof o=="boolean"?n=o:o&&typeof o=="object"&&(n=o.validateExistence??!0,i=o.enableSubscript,s=o.enableSuperscript,k=o.enableMark,l=o.enableTableMerge,u=o.enableEmbeds,M=o.enableZennDirectives);const v={};c&&(v.Authorization=`Bearer ${c}`);const P=await Y.convert({markdownText:r,filePath:e,workspaceRoot:t,validateExistence:n,enableSubscript:i,enableSuperscript:s,enableMark:k,enableTableMerge:l,enableEmbeds:u,enableZennDirectives:M},{headers:v});return{htmlContent:P.htmlContent,headings:P.headings.map(b=>({text:b.text,depth:b.depth,id:b.id}))}};exports.fetchSiteMetadata=C;exports.parseMarkdown=te;exports.remarkBlockLinkMetadata=z;
2
2
  //# sourceMappingURL=index.server.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.server.cjs","sources":["../src/plugins/fetchSiteMetadata.ts","../src/plugins/remark-block-link-metadata.ts","../src/plugins/remark-import-directive.async.server.ts","../src/plugins/transformUri.async.server.ts","../src/plugins/remark-resolve-uri.async.ts","../src/gen/markdown/v1/markdown_pb.ts","../src/gen/markdown/v1/markdown_connect.ts","../src/remarkProcessor.server.ts"],"sourcesContent":["/**\n * This module provides functionality to fetch site metadata from a given URL.\n * 指定された URL からサイトのメタデータを取得する機能を提供します。\n */\nimport { load } from \"cheerio\"\nimport { Logger } from \"../utils/simple-logger\"\n\n/**\n * Represents the metadata of a website.\n * Web サイトのメタデータを表します。\n */\nexport type SiteMetadata = {\n /** The URL of the website. Web サイトの URL。 */\n url: string\n /** The name of the site. サイト名。 */\n site_name?: string\n /** The title of the page. ページのタイトル。 */\n title?: string\n /** A description of the page. ページの説明。 */\n description?: string\n /** The URL of an image representing the page. ページを表す画像の URL。 */\n image?: string\n /** The type of the page (e.g., website, article). ページの種類 (例: website, article)。 */\n type?: string\n}\n\n/**\n * Fetches site metadata from the given URL.\n * 指定された URL からサイトのメタデータを取得します。\n *\n * @param url The URL to fetch metadata from. メタデータを取得する URL。\n * @returns A Promise that resolves to the site metadata, or null if fetching fails.\n * サイトのメタデータに解決される Promise、または取得に失敗した場合は null。\n */\nexport const fetchSiteMetadata = async (url: string): Promise<SiteMetadata | null> => {\n try {\n // 指定された URL に HTTP GET リクエストを送信\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), 10000)\n const response = await fetch(url, { signal: controller.signal })\n clearTimeout(timeoutId)\n\n // レスポンスが成功しなかった場合 (例: 404 Not Found) は null を返す\n if (!response.ok) {\n return null\n }\n\n // レスポンスボディをテキストとして取得\n const html = await response.text()\n // メタデータオブジェクトを初期化\n const metadata: SiteMetadata = { url }\n // HTML をパースして Cheerio オブジェクトを生成\n const $ = load(html)\n\n // <title> タグからタイトルを取得\n const title = $(\"title\").text().trim()\n metadata.title = title\n\n // <meta> タグをすべて取得\n const metaTags = $(\"meta\")\n\n // 各 <meta> タグを処理\n for (const meta of metaTags) {\n const property = meta.attribs.property\n\n // Open Graph (OGP) タグの処理\n if (property === \"og:site_name\") {\n metadata.site_name = meta.attribs.content || undefined\n }\n if (property === \"og:title\") {\n metadata.title = meta.attribs.content || title\n }\n if (property === \"og:description\") {\n metadata.description = meta.attribs.content || undefined\n }\n if (property === \"og:image\") {\n metadata.image = meta.attribs.content || undefined\n }\n if (property === \"og:type\") {\n metadata.type = meta.attribs.content || undefined\n }\n\n // name 属性を持つ <meta> タグの処理 (主に description)\n const metaName = meta.attribs.name\n\n if (metaName === \"description\") {\n metadata.description = meta.attribs.content || undefined\n }\n }\n\n // 取得したメタデータを返す\n return metadata\n } catch (error) {\n Logger.error(\"Error fetching site metadata:\", error)\n // エラーが発生した場合は null を返す\n return null\n }\n}\n","/**\n * @fileoverview Remark plugin to enrich block-link nodes with site metadata.\n * block-linkノードにサイトメタデータを付加するための Remark プラグイン。\n */\nimport type { Link, Root } from \"mdast\"\nimport type { Plugin } from \"unified\"\nimport { visit } from \"unist-util-visit\"\nimport { Logger } from \"../utils/simple-logger\"\nimport { fetchSiteMetadata, type SiteMetadata } from \"./fetchSiteMetadata.ts\"\n\n/**\n * Extended block-link node with site metadata.\n * サイトメタデータが付加されたブロックリンクノード。\n */\nexport interface EnrichedBlockLink extends Omit<Link, \"type\"> {\n type: \"block-link\"\n data?: {\n siteMetadata?: SiteMetadata\n }\n}\n\ndeclare module \"mdast\" {\n interface LinkData {\n siteMetadata?: SiteMetadata\n }\n}\n\n/**\n * Options for the remark-block-link-metadata plugin.\n * remark-block-link-metadata プラグインのオプション。\n */\ninterface BlockLinkMetadataOptions {\n /** Whether to fetch metadata for all block-links. 全てのブロックリンクでメタデータを取得するかどうか。 */\n fetchAll?: boolean\n /** Patterns of URLs to fetch metadata for. メタデータを取得する URL のパターン。 */\n urlPatterns?: RegExp[]\n /** Whether to enable caching of fetched metadata. 取得したメタデータのキャッシュを有効にするかどうか。 */\n enableCache?: boolean\n}\n\n// Simple in-memory cache for metadata\nconst metadataCache = new Map<string, SiteMetadata | null>()\n\n/**\n * Determines if a URL should have its metadata fetched.\n * URL のメタデータを取得すべきかどうかを判定します。\n *\n * @param url The URL to check. チェックする URL。\n * @param options Plugin options. プラグインオプション。\n * @returns Whether metadata should be fetched. メタデータを取得すべきかどうか。\n */\nconst shouldFetchMetadata = (url: string, options: BlockLinkMetadataOptions): boolean => {\n if (options.fetchAll) {\n return true\n }\n\n if (options.urlPatterns && options.urlPatterns.length > 0) {\n return options.urlPatterns.some((pattern: RegExp) => pattern.test(url))\n }\n\n // デフォルトでは、HTTP/HTTPS の外部リンクのみ対象\n return /^https?:\\/\\//.test(url) && !url.includes(\"localhost\") && !url.includes(\"127.0.0.1\")\n}\n\n/**\n * Remark plugin to enrich block-link nodes with site metadata.\n * block-linkノードにサイトメタデータを付加する Remark プラグイン。\n *\n * @param options Plugin options. プラグインオプション。\n * @returns The plugin function. プラグイン関数。\n */\nexport const remarkBlockLinkMetadata: Plugin<[BlockLinkMetadataOptions?], Root> = (options = {}) => {\n const { enableCache = true } = options\n\n return async (tree: Root) => {\n const linkNodes: EnrichedBlockLink[] = []\n\n // block-link ノードを収集\n visit(tree, \"block-link\", (node) => {\n if (shouldFetchMetadata(node.url, options)) {\n linkNodes.push(node as EnrichedBlockLink)\n }\n })\n\n // 各block-linkのメタデータを並行取得\n const metadataPromises = linkNodes.map(async (link) => {\n const url = link.url\n\n // キャッシュから取得を試行\n if (enableCache && metadataCache.has(url)) {\n const cachedMetadata = metadataCache.get(url)\n if (cachedMetadata) {\n link.data = link.data || {}\n link.data.siteMetadata = cachedMetadata\n }\n return\n }\n\n try {\n // サイトメタデータを取得\n const metadata = await fetchSiteMetadata(url)\n\n if (metadata) {\n // block-linkノードにメタデータを付加\n link.data = link.data || {}\n link.data.siteMetadata = metadata\n\n // キャッシュに保存\n if (enableCache) {\n metadataCache.set(url, metadata)\n }\n } else if (enableCache) {\n // 失敗した場合もキャッシュして、同じ URL への再リクエストを防ぐ\n metadataCache.set(url, null)\n }\n } catch (error) {\n Logger.warn(`Failed to fetch metadata for ${url}:`, error)\n if (enableCache) {\n metadataCache.set(url, null)\n }\n }\n })\n\n // 全てのメタデータ取得を待機\n await Promise.all(metadataPromises)\n }\n}\n","/**\n * @file This file defines a remark plugin to handle `@import` directives in Markdown.\n * @brief このファイルは、Markdown 内の `@import` ディレクティブを処理するための remark プラグインを定義します。\n */\nimport fs from \"node:fs/promises\"\nimport path from \"node:path\"\nimport type { Root } from \"mdast\"\nimport type { Processor } from \"unified\"\nimport { visit } from \"unist-util-visit\"\nimport { Logger } from \"../utils/simple-logger\"\n\ntype ParentNodeWithChildren = {\n children: unknown[]\n}\n\nconst importRegex = /<!--\\s+@import\\s+\"(.+?)\"\\s+-->/\n\n/**\n * A remark plugin to support `@import` directives in Markdown.\n * This allows importing content from other Markdown files.\n * Markdown の `@import` ディレクティブをサポートする remark プラグイン。\n * これにより、他の Markdown ファイルからコンテンツをインポート可能。\n *\n * @param this The remark processor instance. / remark プロセッサーのインスタンス。\n * @param options Options for the plugin. / プラグインのオプション。\n * @param options.markdownFilePath The path to the Markdown file being processed. / 処理対象の Markdown ファイルへのパス。\n */\nexport function remarkImportDirective(this: Processor, options: { markdownFilePath: string }) {\n return async (tree: Root): Promise<void> => {\n const { markdownFilePath } = options\n const parentDir = path.dirname(markdownFilePath)\n\n // すべてのインポートディレクティブを収集\n const imports: { parent: ParentNodeWithChildren; index: number; absolutePath: string }[] = []\n visit(tree, \"html\", (node, index, parent) => {\n if (!parent || typeof index !== \"number\") {\n return\n }\n\n const match = node.value.match(importRegex)\n if (!match) {\n return\n }\n\n const importPath = match[1]\n const absolutePath = path.resolve(parentDir, importPath)\n if (Array.isArray((parent as { children?: unknown[] }).children)) {\n imports.push({ parent: parent as ParentNodeWithChildren, index, absolutePath })\n }\n })\n\n if (imports.length === 0) {\n return\n }\n\n // すべてのファイルを読み込み、解析\n const parsedTrees = await Promise.all(\n imports.map(async ({ absolutePath }) => {\n try {\n const fileContent = await fs.readFile(absolutePath, \"utf-8\")\n return this.parse(fileContent) as Root\n } catch (error) {\n if (error && (error as NodeJS.ErrnoException).code === \"ENOENT\") {\n Logger.warn(`[remark-import-directive] Import file not found: ${absolutePath}`)\n } else {\n Logger.error(`[remark-import-directive] Error processing import: ${absolutePath}`, error)\n }\n return null // エラー時は null を返却\n }\n }),\n )\n\n // ツリー内のノードを後方から置換\n for (let i = imports.length - 1; i >= 0; i--) {\n const { parent, index } = imports[i]\n const newTree = parsedTrees[i]\n\n if (newTree?.children && Array.isArray(newTree.children)) {\n parent.children.splice(index, 1, ...newTree.children)\n }\n }\n }\n}\n","/**\n * @file Async version of transformUri for file existence validation.\n * @brief ファイル存在確認を含む transformUri の非同期版。\n */\nimport fs from \"node:fs/promises\"\nimport path from \"node:path\"\nimport urlJoin from \"url-join\"\nimport { Logger } from \"../utils/simple-logger\"\n\n// RFC 3986 URI scheme regex\nconst URI_SCHEME_REGEX = /^[a-z][a-z0-9+.-]*:/\n\n/**\n * Async version of transformUri that validates file existence.\n * ファイル存在確認を行う transformUri の非同期版。\n *\n * @param uri The URI to transform. / 変換対象の URI。\n * @param isImage Whether this is an image URI. / 画像 URI かどうか。\n * @param markdownFilePath Path to the markdown file. / Markdown ファイルのパス。\n * @param workspaceRoot Workspace root directory. / ワークスペースのルートディレクトリ。\n * @param validateExistence Whether to validate file existence. / ファイル存在確認を行うかどうか。\n * @returns Promise resolving to the transformed URI. / 変換された URI を返す Promise。\n */\nexport const transformUriAsync = async (uri: string, isImage: boolean, markdownFilePath: string, workspaceRoot: string, validateExistence = false): Promise<string> => {\n if (!uri) {\n return \"\"\n }\n\n // 1. 絶対URL (http, https, mailto, tel) はそのまま返す\n if (URI_SCHEME_REGEX.test(uri)) {\n const protocol = uri.substring(0, uri.indexOf(\":\")).toLowerCase()\n if ([\"http\", \"https\", \"mailto\", \"tel\", \"file\"].includes(protocol)) {\n return uri\n }\n }\n\n // 2. アンカーリンク (#fragment) はそのまま返す\n if (uri.startsWith(\"#\")) {\n return uri\n }\n\n // 3. ルート相対パス (/) はそのまま返す\n if (uri.startsWith(\"/\")) {\n return uri\n }\n\n // 4. 相対パスをプロジェクトルートからのパスとして解決する\n const decodedUri = decodeURIComponent(uri)\n const markdownDir = path.dirname(markdownFilePath)\n const projectRelativePath = path.normalize(path.join(markdownDir, decodedUri))\n\n // セキュリティチェック\n const absolutePath = path.resolve(workspaceRoot, projectRelativePath)\n if (!absolutePath.startsWith(workspaceRoot) || projectRelativePath.startsWith(\"..\")) {\n Logger.error(`Security Alert: Attempt to access file outside project root: ${absolutePath}`)\n return \"\"\n }\n\n // ファイル存在確認(オプション)\n if (validateExistence) {\n try {\n await fs.access(absolutePath)\n } catch {\n Logger.warn(`File not found: ${absolutePath}`)\n return \"\"\n }\n }\n\n const pathForEncoding = projectRelativePath.replace(/\\\\/g, \"/\")\n\n if (isImage) {\n return urlJoin(\"/assets/\", pathForEncoding)\n }\n return `?filePath=${encodeURIComponent(pathForEncoding)}`\n}\n","/**\n * @file Async version of remark-resolve-uri plugin.\n * @brief URI 解決プラグインの非同期版。\n */\nimport * as cheerio from \"cheerio\"\nimport type { Html, Image, Link, Root } from \"mdast\"\nimport { visit } from \"unist-util-visit\"\nimport { Logger } from \"../utils/simple-logger\"\nimport { transformUriAsync } from \"./transformUri.async.server\"\n\ninterface Options {\n markdownFilePath: string\n workspaceRoot: string\n validateExistence?: boolean\n}\n\n/**\n * An async remark plugin to resolve image and link URIs with optional file validation.\n * ファイル検証オプション付きで画像とリンクの URI を解決する非同期 remark プラグイン。\n */\nexport function remarkResolveUriAsync(options: Options) {\n return async (tree: Root): Promise<void> => {\n if (!(options?.markdownFilePath && options?.workspaceRoot)) {\n Logger.warn(\"remark-resolve-uri-async: markdownFilePath and workspaceRoot are required. Skipping URI resolution.\")\n return\n }\n\n // すべての画像とリンクノードを収集\n const uriNodes: Array<{ node: Image | Link; isImage: boolean }> = []\n const htmlNodes: Array<Html> = []\n\n visit(tree, [\"image\", \"link\", \"html\"], (node) => {\n if (node.type === \"html\") {\n htmlNodes.push(node as Html)\n } else {\n const targetNode = node as Image | Link\n if (targetNode.url) {\n uriNodes.push({ node: targetNode, isImage: targetNode.type === \"image\" })\n }\n }\n })\n\n // 並列でURI変換を実行 (標準Markdownノード)\n const transformPromises = uriNodes.map(async ({ node, isImage }) => {\n const transformedUri = await transformUriAsync(node.url, isImage, options.markdownFilePath, options.workspaceRoot, options.validateExistence)\n node.url = transformedUri\n })\n\n // 並列でURI変換を実行 (HTMLノード内の属性)\n const htmlTransformPromises = htmlNodes.map(async (node) => {\n // HTMLフラグメントとしてロード (isDocument=false)\n const $ = cheerio.load(node.value, null, false)\n let modified = false\n\n // imgタグのsrc属性を変換\n const imgTags = $(\"img\").toArray()\n for (const img of imgTags) {\n const src = $(img).attr(\"src\")\n if (src) {\n const transformed = await transformUriAsync(src, true, options.markdownFilePath, options.workspaceRoot, options.validateExistence)\n if (transformed !== src) {\n $(img).attr(\"src\", transformed)\n modified = true\n }\n }\n }\n\n // aタグのhref属性を変換\n const aTags = $(\"a\").toArray()\n for (const a of aTags) {\n const href = $(a).attr(\"href\")\n if (href) {\n const transformed = await transformUriAsync(href, false, options.markdownFilePath, options.workspaceRoot, options.validateExistence)\n if (transformed !== href) {\n $(a).attr(\"href\", transformed)\n modified = true\n }\n }\n }\n\n if (modified) {\n // 変更があれば node.value を更新\n // html() はエンコードされた実体を返す可能性があるが、HTMLノードとしては許容される\n const newHtml = $.html()\n if (newHtml) {\n node.value = newHtml\n }\n }\n })\n\n await Promise.all([...transformPromises, ...htmlTransformPromises])\n }\n}\n","// @generated by protoc-gen-es v1.10.1 with parameter \"target=ts\"\n// @generated from file markdown/v1/markdown.proto (package markdown.v1, syntax proto3)\n/* eslint-disable */\n// @ts-nocheck\n\nimport type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from \"@bufbuild/protobuf\"\nimport { Message, proto3 } from \"@bufbuild/protobuf\"\n\n/**\n * @generated from message markdown.v1.ConvertRequest\n */\nexport class ConvertRequest extends Message<ConvertRequest> {\n /**\n * @generated from field: string markdown_text = 1;\n */\n markdownText = \"\"\n\n /**\n * Path of the document being converted. Canonical form is a fully qualified\n * URI: `file:///abs/path.md` (or a bare absolute path) for local documents,\n * `gcs://` / `gdrive://` URIs for cloud documents. A workspace-relative path\n * (bare or with a stray `file://` prefix) is also accepted and is anchored to\n * `workspace_root` server-side. Relative paths are NEVER resolved against the\n * server process's working directory. INVALID_ARGUMENT is returned when the\n * path is empty, when `workspace_root` is not absolute for a local document,\n * or when a relative path cannot be anchored strictly inside `workspace_root`\n * (e.g. `.` or `..` escapes).\n *\n * @generated from field: string file_path = 2;\n */\n filePath = \"\"\n\n /**\n * Absolute path of the workspace root. Required for local (file scheme)\n * documents: it anchors relative `file_path` values, bounds the local file://\n * sandbox, and derives the workspace-relative `/assets/` URLs emitted for\n * local images. Ignored for cloud documents.\n *\n * @generated from field: string workspace_root = 3;\n */\n workspaceRoot = \"\"\n\n /**\n * Enables existence validation for locally resolvable image and doc-link\n * targets. When true, a missing local image loses its src and gains\n * `data-asset-exists=\"false\"` plus `data-asset-src` (the workspace-relative\n * target, emitted only when it is inside `workspace_root`), and local doc\n * links gain `data-doc-exists`. When false, no existence markers are emitted\n * and no existence probes run. Cloud-scheme (gcs/gdrive) image targets are\n * rewritten to signed/proxy URLs without existence validation in either mode.\n *\n * @generated from field: bool validate_existence = 4;\n */\n validateExistence = false\n\n /**\n * @generated from field: optional bool enable_subscript = 5;\n */\n enableSubscript?: boolean\n\n /**\n * @generated from field: optional bool enable_superscript = 6;\n */\n enableSuperscript?: boolean\n\n /**\n * @generated from field: optional bool enable_mark = 7;\n */\n enableMark?: boolean\n\n /**\n * @generated from field: optional bool enable_table_merge = 8;\n */\n enableTableMerge?: boolean\n\n /**\n * @generated from field: optional bool enable_embeds = 9;\n */\n enableEmbeds?: boolean\n\n /**\n * @generated from field: optional bool enable_zenn_directives = 10;\n */\n enableZennDirectives?: boolean\n\n constructor(data?: PartialMessage<ConvertRequest>) {\n super()\n proto3.util.initPartial(data, this)\n }\n\n static readonly runtime: typeof proto3 = proto3\n static readonly typeName = \"markdown.v1.ConvertRequest\"\n static readonly fields: FieldList = proto3.util.newFieldList(() => [\n { no: 1, name: \"markdown_text\", kind: \"scalar\", T: 9 /* ScalarType.STRING */ },\n { no: 2, name: \"file_path\", kind: \"scalar\", T: 9 /* ScalarType.STRING */ },\n { no: 3, name: \"workspace_root\", kind: \"scalar\", T: 9 /* ScalarType.STRING */ },\n { no: 4, name: \"validate_existence\", kind: \"scalar\", T: 8 /* ScalarType.BOOL */ },\n { no: 5, name: \"enable_subscript\", kind: \"scalar\", T: 8 /* ScalarType.BOOL */, opt: true },\n { no: 6, name: \"enable_superscript\", kind: \"scalar\", T: 8 /* ScalarType.BOOL */, opt: true },\n { no: 7, name: \"enable_mark\", kind: \"scalar\", T: 8 /* ScalarType.BOOL */, opt: true },\n { no: 8, name: \"enable_table_merge\", kind: \"scalar\", T: 8 /* ScalarType.BOOL */, opt: true },\n { no: 9, name: \"enable_embeds\", kind: \"scalar\", T: 8 /* ScalarType.BOOL */, opt: true },\n { no: 10, name: \"enable_zenn_directives\", kind: \"scalar\", T: 8 /* ScalarType.BOOL */, opt: true },\n ])\n\n static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): ConvertRequest {\n return new ConvertRequest().fromBinary(bytes, options)\n }\n\n static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): ConvertRequest {\n return new ConvertRequest().fromJson(jsonValue, options)\n }\n\n static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): ConvertRequest {\n return new ConvertRequest().fromJsonString(jsonString, options)\n }\n\n static equals(a: ConvertRequest | PlainMessage<ConvertRequest> | undefined, b: ConvertRequest | PlainMessage<ConvertRequest> | undefined): boolean {\n return proto3.util.equals(ConvertRequest, a, b)\n }\n}\n\n/**\n * @generated from message markdown.v1.ConvertResponse\n */\nexport class ConvertResponse extends Message<ConvertResponse> {\n /**\n * @generated from field: string html_content = 1;\n */\n htmlContent = \"\"\n\n /**\n * @generated from field: repeated markdown.v1.Heading headings = 2;\n */\n headings: Heading[] = []\n\n constructor(data?: PartialMessage<ConvertResponse>) {\n super()\n proto3.util.initPartial(data, this)\n }\n\n static readonly runtime: typeof proto3 = proto3\n static readonly typeName = \"markdown.v1.ConvertResponse\"\n static readonly fields: FieldList = proto3.util.newFieldList(() => [\n { no: 1, name: \"html_content\", kind: \"scalar\", T: 9 /* ScalarType.STRING */ },\n { no: 2, name: \"headings\", kind: \"message\", T: Heading, repeated: true },\n ])\n\n static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): ConvertResponse {\n return new ConvertResponse().fromBinary(bytes, options)\n }\n\n static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): ConvertResponse {\n return new ConvertResponse().fromJson(jsonValue, options)\n }\n\n static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): ConvertResponse {\n return new ConvertResponse().fromJsonString(jsonString, options)\n }\n\n static equals(a: ConvertResponse | PlainMessage<ConvertResponse> | undefined, b: ConvertResponse | PlainMessage<ConvertResponse> | undefined): boolean {\n return proto3.util.equals(ConvertResponse, a, b)\n }\n}\n\n/**\n * @generated from message markdown.v1.Heading\n */\nexport class Heading extends Message<Heading> {\n /**\n * @generated from field: string text = 1;\n */\n text = \"\"\n\n /**\n * @generated from field: int32 depth = 2;\n */\n depth = 0\n\n /**\n * @generated from field: string id = 3;\n */\n id = \"\"\n\n constructor(data?: PartialMessage<Heading>) {\n super()\n proto3.util.initPartial(data, this)\n }\n\n static readonly runtime: typeof proto3 = proto3\n static readonly typeName = \"markdown.v1.Heading\"\n static readonly fields: FieldList = proto3.util.newFieldList(() => [\n { no: 1, name: \"text\", kind: \"scalar\", T: 9 /* ScalarType.STRING */ },\n { no: 2, name: \"depth\", kind: \"scalar\", T: 5 /* ScalarType.INT32 */ },\n { no: 3, name: \"id\", kind: \"scalar\", T: 9 /* ScalarType.STRING */ },\n ])\n\n static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Heading {\n return new Heading().fromBinary(bytes, options)\n }\n\n static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): Heading {\n return new Heading().fromJson(jsonValue, options)\n }\n\n static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): Heading {\n return new Heading().fromJsonString(jsonString, options)\n }\n\n static equals(a: Heading | PlainMessage<Heading> | undefined, b: Heading | PlainMessage<Heading> | undefined): boolean {\n return proto3.util.equals(Heading, a, b)\n }\n}\n","// @generated by protoc-gen-connect-es v1.7.0 with parameter \"target=ts\"\n// @generated from file markdown/v1/markdown.proto (package markdown.v1, syntax proto3)\n/* eslint-disable */\n// @ts-nocheck\n\nimport { MethodKind } from \"@bufbuild/protobuf\"\nimport { ConvertRequest, ConvertResponse } from \"./markdown_pb.js\"\n\n/**\n * @generated from service markdown.v1.MarkdownService\n */\nexport const MarkdownService = {\n typeName: \"markdown.v1.MarkdownService\",\n methods: {\n /**\n * @generated from rpc markdown.v1.MarkdownService.Convert\n */\n convert: {\n name: \"Convert\",\n I: ConvertRequest,\n O: ConvertResponse,\n kind: MethodKind.Unary,\n },\n },\n} as const\n","import { spawn } from \"node:child_process\"\nimport { existsSync, unlinkSync } from \"node:fs\"\nimport { createRequire } from \"node:module\"\nimport * as net from \"node:net\"\nimport * as path from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\nimport { createClient } from \"@connectrpc/connect\"\nimport { createConnectTransport } from \"@connectrpc/connect-node\"\nimport { MarkdownService } from \"./gen/markdown/v1/markdown_connect.ts\"\n\nconst SOCKET_PATH = process.env.MARKDOWN_SOCKET_PATH || \"/tmp/markdown.sock\"\n\nconst transport = createConnectTransport({\n baseUrl: \"http://localhost\",\n httpVersion: \"2\",\n nodeOptions: {\n createConnection: () => {\n return net.connect(SOCKET_PATH)\n },\n } as unknown as Record<string, unknown>,\n})\n\nconst client = createClient(MarkdownService, transport)\n\nexport interface ParseResult {\n htmlContent: string\n headings: Array<{\n text: string\n depth: number\n id: string\n }>\n}\n\nexport interface ParseOptions {\n validateExistence?: boolean\n enableSubscript?: boolean\n enableSuperscript?: boolean\n enableMark?: boolean\n enableTableMerge?: boolean\n enableEmbeds?: boolean\n enableZennDirectives?: boolean\n}\n\n/**\n * Returns the directory of this module in a way that works for both ESM and CJS output.\n * ESM / CJS どちらのビルド出力でも動作する形で本モジュールのディレクトリを返す処理。\n *\n * @returns Absolute directory path / 絶対ディレクトリパス\n */\nconst getDirname = (): string => {\n try {\n return path.dirname(fileURLToPath(import.meta.url))\n } catch {\n return __dirname\n }\n}\n\n/** プラットフォームパッケージ名 (@aiquants/markdown-linux-x64 等) */\nconst platformPackageName = (): string => `@aiquants/markdown-${process.platform}-${process.arch}`\n\n/** プラットフォームパッケージ内のバイナリ相対パス (Windows のみ .exe) */\nconst platformBinarySubpath = (): string => (process.platform === \"win32\" ? \"bin/markdown-api.exe\" : \"bin/markdown-api\")\n\n/**\n * Locates the `markdown-api` binary for the running platform.\n * 実行中プラットフォーム向けの `markdown-api` バイナリを探索する処理。\n *\n * 探索順:\n * 1. `MARKDOWN_API_BINARY` 環境変数 (自前ビルドの差し込み口)\n * 2. プラットフォームパッケージ (通常の配布経路。Node の解決機構に委ねるため\n * パス組み立てのヒューリスティックが不要)\n * 3. モノレポ開発時に `pnpm run build:go` がビルドする `packages/go/markdown-api/dist/`\n *\n * 候補 3 はモノレポ内の消費アプリからは機能しない。workspace 依存が injected\n * (ハードリンクコピー) で解決されるため、`.pnpm/` 配下のコピーから相対で辿れない。\n * サービスを自前起動する統合テストは `MARKDOWN_API_BINARY` を明示すること。\n *\n * 実行権限は付与しない。バイナリはプラットフォームパッケージの `bin` フィールド経由で\n * 配られ、パッケージマネージャが 0755 を保証する。\n *\n * @returns Absolute binary path, or undefined when unavailable / バイナリの絶対パス。見つからない場合は undefined\n */\nexport const resolveBinaryPath = (): string | undefined => {\n const fromEnvironment = process.env.MARKDOWN_API_BINARY\n if (fromEnvironment && existsSync(fromEnvironment)) {\n return fromEnvironment\n }\n\n try {\n // createRequire の基点はビルド形式に依存しない getDirname() から作る\n // (CJS 出力で import.meta.url がどう変換されても影響を受けない)\n const resolved = createRequire(path.join(getDirname(), \"index.js\")).resolve(`${platformPackageName()}/${platformBinarySubpath()}`)\n if (existsSync(resolved)) {\n return resolved\n }\n } catch {\n // プラットフォームパッケージ未インストール (モノレポ開発時は常にこの経路)\n }\n\n const monorepoBinary = path.join(getDirname(), \"..\", \"..\", \"go\", \"markdown-api\", \"dist\", path.basename(platformBinarySubpath()))\n return existsSync(monorepoBinary) ? monorepoBinary : undefined\n}\n\n/**\n * Builds a diagnosable message for a missing binary.\n * バイナリが見つからない場合の原因診断メッセージを組み立てる処理。\n *\n * 「見つからない」だけでは利用者が次に何をすべきか分からないため、期待した\n * プラットフォームパッケージ名と自前ビルドの差し込み口まで示す。\n *\n * @returns Human-readable diagnostic message / 人間が読める診断メッセージ\n */\nconst describeMissingBinary = (): string =>\n [\n `markdown-api binary not found for ${process.platform}-${process.arch}.`,\n `Expected the optional dependency ${platformPackageName()} to be installed.`,\n \"If your platform is unsupported, build the service yourself\",\n \"(https://github.com/fehde-k/aiquants/tree/main/packages/go/markdown-api)\",\n \"and point MARKDOWN_API_BINARY at it.\",\n ].join(\" \")\n\nconst canConnect = (): Promise<boolean> =>\n new Promise((resolve) => {\n const socket = net.connect(SOCKET_PATH)\n socket.on(\"connect\", () => {\n socket.destroy()\n resolve(true)\n })\n socket.on(\"error\", () => resolve(false))\n })\n\nconst waitForServer = async (timeoutMs: number): Promise<boolean> => {\n const start = Date.now()\n while (Date.now() - start < timeoutMs) {\n if (await canConnect()) return true\n await new Promise((r) => setTimeout(r, 100))\n }\n return false\n}\n\nlet spawnedServer: ReturnType<typeof spawn> | null = null\nlet startPromise: Promise<boolean> | null = null\n\n/**\n * Grace period for a server started outside this process, in milliseconds.\n * 本プロセス外で起動されたサーバを待つ猶予時間 (ミリ秒)。\n *\n * コンテナ環境ではプロセスマネージャ (supervisor 等) が `markdown-api` を別プログラムとして\n * 起動するため、パッケージ内にバイナリは存在しない。その構成で Node 側が先に温まると\n * ソケット未 bind の瞬間に当たりうるので、自前起動を諦める前に短時間だけ待つ。\n * Go 側の bind はミリ秒で完了するため、これで十分。\n */\nconst EXTERNAL_SERVER_GRACE_MS = 2000\n\n/**\n * Time budget for a freshly spawned server to start listening, in milliseconds.\n * 新規起動したサーバが待ち受け開始するまでの猶予時間 (ミリ秒)。\n *\n * 低速な CI コンテナでは既定の 10 秒でも足りないことがあるため環境変数で調整できる。\n * 不正値 (数値でない / 0 以下) は既定へ戻す (設定ミスで永久に待たないようにする)。\n *\n * @returns Timeout in milliseconds / ミリ秒単位のタイムアウト\n */\nconst startupTimeoutMs = (): number => {\n const configured = Number(process.env.MARKDOWN_API_STARTUP_TIMEOUT_MS)\n return Number.isFinite(configured) && configured > 0 ? configured : 10000\n}\n\n/** 自動起動をバイナリ不在で諦めた理由。到達不能エラーへ添えて診断可能にする */\nlet missingBinaryReason: string | null = null\n\nconst ensureServerRunning = async (): Promise<boolean> => {\n if (await canConnect()) return true\n\n if (startPromise) return startPromise\n\n startPromise = (async () => {\n const binPath = resolveBinaryPath()\n if (!binPath) {\n // 外部管理サーバの起動待ちに賭ける。ここで即諦めると、プロセスマネージャ管理型の\n // 構成 (バイナリを同梱しない) で起動直後のリクエストが理由なく失敗する\n if (await waitForServer(EXTERNAL_SERVER_GRACE_MS)) return true\n missingBinaryReason = describeMissingBinary()\n return false\n }\n // バイナリが見つかった以降は不在が理由ではない。古い理由を残すと誤診を招く\n missingBinaryReason = null\n\n // Clean up stale socket file if it exists\n try {\n if (existsSync(SOCKET_PATH)) {\n unlinkSync(SOCKET_PATH)\n }\n } catch {\n // ignore\n }\n\n try {\n spawnedServer = spawn(binPath, [], { stdio: \"ignore\" })\n\n const cleanup = () => {\n if (spawnedServer) {\n try {\n spawnedServer.kill(\"SIGTERM\")\n } catch {\n // 既に終了しているケースは無視する\n }\n spawnedServer = null\n }\n }\n\n // once で登録し、失敗時は明示的に解除する。on のままだと起動失敗を\n // 繰り返すたびにリスナーが蓄積し、MaxListeners 警告とメモリリークを招く\n process.once(\"exit\", cleanup)\n\n const ready = await waitForServer(startupTimeoutMs())\n if (!ready) {\n console.error(\"markdown-api Go server did not become ready on socket:\", SOCKET_PATH)\n cleanup()\n process.removeListener(\"exit\", cleanup)\n return false\n }\n return true\n } catch (err) {\n console.error(\"Failed to spawn markdown-api Go server:\", err)\n spawnedServer = null\n return false\n }\n })()\n\n const success = await startPromise\n if (!success) {\n startPromise = null\n }\n return success\n}\n\n/**\n * Converts markdown text to HTML via the Go markdown-api server over ConnectRPC/UDS.\n * ConnectRPC/UDS 経由で Go markdown-api サーバへ委譲し、Markdown を HTML へ変換する処理。\n *\n * Path contract (パス契約):\n * - `markdownFilePath` の正準形はスキーム付き完全 URI (ローカルは `file:///abs/path.md`、\n * クラウドは `gcs://` / `gdrive://`)。素の絶対パスも同義に扱われる。\n * - ワークスペース相対パスも受理され、サーバ側で `workspaceRoot` にアンカーされる。\n * 相対パスがサーバプロセスの CWD 基準で解釈されることは決してない。\n * - ローカルドキュメントでは `workspaceRoot` が絶対パスであることが必須 (file://\n * サンドボックスの境界かつ `/assets/` 相対 URL の基点)。空・相対の `workspaceRoot`、\n * 空の `markdownFilePath`、アンカー後にルート外へ逃げる相対パスはいずれも\n * INVALID_ARGUMENT で拒否される (Fail Fast)。\n *\n * `validateExistenceOrOptions` が true (既定) のとき、解決先が存在しない画像は src を\n * 失い data-asset-exists=\"false\" を持ち、解決先が `workspaceRoot` の内側にある場合に\n * 限り data-asset-src (解決先の相対パス) も付く (ワークスペース外のパス構造は開示\n * しない)。ローカルドキュメントリンクには data-doc-exists が付く。false のとき\n * 存在検証は一切行われない。\n */\nexport const parseMarkdown = async (markdownText: string, markdownFilePath: string, workspaceRoot: string, userOAuthToken?: string, validateExistenceOrOptions: boolean | ParseOptions = true): Promise<ParseResult> => {\n // Automatically ensure the backend Go server is running\n if (!(await ensureServerRunning())) {\n // 到達できないまま RPC へ進むと、利用者には原因不明の ENOENT だけが届く。\n // 自動起動がバイナリ不在で諦めた場合は、必要なパッケージ名まで含めて伝える\n const detail = missingBinaryReason ? ` ${missingBinaryReason}` : \"\"\n throw new Error(`markdown service is not reachable on ${SOCKET_PATH}.${detail}`)\n }\n\n let validateExistence = true\n let enableSubscript: boolean | undefined\n let enableSuperscript: boolean | undefined\n let enableMark: boolean | undefined\n let enableTableMerge: boolean | undefined\n let enableEmbeds: boolean | undefined\n let enableZennDirectives: boolean | undefined\n\n if (typeof validateExistenceOrOptions === \"boolean\") {\n validateExistence = validateExistenceOrOptions\n } else if (validateExistenceOrOptions && typeof validateExistenceOrOptions === \"object\") {\n validateExistence = validateExistenceOrOptions.validateExistence ?? true\n enableSubscript = validateExistenceOrOptions.enableSubscript\n enableSuperscript = validateExistenceOrOptions.enableSuperscript\n enableMark = validateExistenceOrOptions.enableMark\n enableTableMerge = validateExistenceOrOptions.enableTableMerge\n enableEmbeds = validateExistenceOrOptions.enableEmbeds\n enableZennDirectives = validateExistenceOrOptions.enableZennDirectives\n }\n\n const headers: Record<string, string> = {}\n if (userOAuthToken) {\n headers.Authorization = `Bearer ${userOAuthToken}`\n }\n\n const response = await client.convert(\n {\n markdownText,\n filePath: markdownFilePath,\n workspaceRoot,\n validateExistence,\n enableSubscript,\n enableSuperscript,\n enableMark,\n enableTableMerge,\n enableEmbeds,\n enableZennDirectives,\n },\n { headers },\n )\n\n return {\n htmlContent: response.htmlContent,\n headings: response.headings.map((h) => ({\n text: h.text,\n depth: h.depth,\n id: h.id,\n })),\n }\n}\n"],"names":["fetchSiteMetadata","url","controller","timeoutId","response","html","metadata","$","load","title","metaTags","meta","property","error","Logger","metadataCache","shouldFetchMetadata","options","pattern","remarkBlockLinkMetadata","enableCache","tree","linkNodes","visit","node","metadataPromises","link","cachedMetadata","importRegex","remarkImportDirective","markdownFilePath","parentDir","path","imports","index","parent","match","importPath","absolutePath","parsedTrees","fileContent","fs","i","newTree","URI_SCHEME_REGEX","transformUriAsync","uri","isImage","workspaceRoot","validateExistence","protocol","decodedUri","markdownDir","projectRelativePath","pathForEncoding","urlJoin","remarkResolveUriAsync","uriNodes","htmlNodes","targetNode","transformPromises","transformedUri","htmlTransformPromises","cheerio","modified","imgTags","img","src","transformed","aTags","a","href","newHtml","ConvertRequest","Message","data","proto3","bytes","jsonValue","jsonString","b","ConvertResponse","Heading","MarkdownService","MethodKind","SOCKET_PATH","transport","createConnectTransport","net","client","createClient","getDirname","fileURLToPath","_documentCurrentScript","platformPackageName","platformBinarySubpath","resolveBinaryPath","fromEnvironment","existsSync","resolved","createRequire","monorepoBinary","describeMissingBinary","canConnect","resolve","socket","waitForServer","timeoutMs","start","spawnedServer","startPromise","EXTERNAL_SERVER_GRACE_MS","startupTimeoutMs","configured","missingBinaryReason","ensureServerRunning","binPath","unlinkSync","spawn","cleanup","err","success","parseMarkdown","markdownText","userOAuthToken","validateExistenceOrOptions","detail","enableSubscript","enableSuperscript","enableMark","enableTableMerge","enableEmbeds","enableZennDirectives","headers","h"],"mappings":"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"}
1
+ {"version":3,"file":"index.server.cjs","sources":["../src/plugins/fetchSiteMetadata.ts","../src/plugins/remark-block-link-metadata.ts","../src/gen/markdown/v1/markdown_pb.ts","../src/gen/markdown/v1/markdown_connect.ts","../src/remarkProcessor.server.ts"],"sourcesContent":["/**\n * This module provides functionality to fetch site metadata from a given URL.\n * 指定された URL からサイトのメタデータを取得する機能を提供します。\n */\nimport { load } from \"cheerio\"\nimport { Logger } from \"../utils/simple-logger\"\n\n/**\n * Represents the metadata of a website.\n * Web サイトのメタデータを表します。\n */\nexport type SiteMetadata = {\n /** The URL of the website. Web サイトの URL。 */\n url: string\n /** The name of the site. サイト名。 */\n site_name?: string\n /** The title of the page. ページのタイトル。 */\n title?: string\n /** A description of the page. ページの説明。 */\n description?: string\n /** The URL of an image representing the page. ページを表す画像の URL。 */\n image?: string\n /** The type of the page (e.g., website, article). ページの種類 (例: website, article)。 */\n type?: string\n}\n\n/**\n * Fetches site metadata from the given URL.\n * 指定された URL からサイトのメタデータを取得します。\n *\n * @param url The URL to fetch metadata from. メタデータを取得する URL。\n * @returns A Promise that resolves to the site metadata, or null if fetching fails.\n * サイトのメタデータに解決される Promise、または取得に失敗した場合は null。\n */\nexport const fetchSiteMetadata = async (url: string): Promise<SiteMetadata | null> => {\n try {\n // 指定された URL に HTTP GET リクエストを送信\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), 10000)\n const response = await fetch(url, { signal: controller.signal })\n clearTimeout(timeoutId)\n\n // レスポンスが成功しなかった場合 (例: 404 Not Found) は null を返す\n if (!response.ok) {\n return null\n }\n\n // レスポンスボディをテキストとして取得\n const html = await response.text()\n // メタデータオブジェクトを初期化\n const metadata: SiteMetadata = { url }\n // HTML をパースして Cheerio オブジェクトを生成\n const $ = load(html)\n\n // <title> タグからタイトルを取得\n const title = $(\"title\").text().trim()\n metadata.title = title\n\n // <meta> タグをすべて取得\n const metaTags = $(\"meta\")\n\n // 各 <meta> タグを処理\n for (const meta of metaTags) {\n const property = meta.attribs.property\n\n // Open Graph (OGP) タグの処理\n if (property === \"og:site_name\") {\n metadata.site_name = meta.attribs.content || undefined\n }\n if (property === \"og:title\") {\n metadata.title = meta.attribs.content || title\n }\n if (property === \"og:description\") {\n metadata.description = meta.attribs.content || undefined\n }\n if (property === \"og:image\") {\n metadata.image = meta.attribs.content || undefined\n }\n if (property === \"og:type\") {\n metadata.type = meta.attribs.content || undefined\n }\n\n // name 属性を持つ <meta> タグの処理 (主に description)\n const metaName = meta.attribs.name\n\n if (metaName === \"description\") {\n metadata.description = meta.attribs.content || undefined\n }\n }\n\n // 取得したメタデータを返す\n return metadata\n } catch (error) {\n Logger.error(\"Error fetching site metadata:\", error)\n // エラーが発生した場合は null を返す\n return null\n }\n}\n","/**\n * @fileoverview Remark plugin to enrich block-link nodes with site metadata.\n * block-linkノードにサイトメタデータを付加するための Remark プラグイン。\n */\nimport type { Link, Root } from \"mdast\"\nimport type { Plugin } from \"unified\"\nimport { visit } from \"unist-util-visit\"\nimport { Logger } from \"../utils/simple-logger\"\nimport { fetchSiteMetadata, type SiteMetadata } from \"./fetchSiteMetadata.ts\"\n\n/**\n * Extended block-link node with site metadata.\n * サイトメタデータが付加されたブロックリンクノード。\n */\nexport interface EnrichedBlockLink extends Omit<Link, \"type\"> {\n type: \"block-link\"\n data?: {\n siteMetadata?: SiteMetadata\n }\n}\n\ndeclare module \"mdast\" {\n interface LinkData {\n siteMetadata?: SiteMetadata\n }\n}\n\n/**\n * Options for the remark-block-link-metadata plugin.\n * remark-block-link-metadata プラグインのオプション。\n */\ninterface BlockLinkMetadataOptions {\n /** Whether to fetch metadata for all block-links. 全てのブロックリンクでメタデータを取得するかどうか。 */\n fetchAll?: boolean\n /** Patterns of URLs to fetch metadata for. メタデータを取得する URL のパターン。 */\n urlPatterns?: RegExp[]\n /** Whether to enable caching of fetched metadata. 取得したメタデータのキャッシュを有効にするかどうか。 */\n enableCache?: boolean\n}\n\n// Simple in-memory cache for metadata\nconst metadataCache = new Map<string, SiteMetadata | null>()\n\n/**\n * Determines if a URL should have its metadata fetched.\n * URL のメタデータを取得すべきかどうかを判定します。\n *\n * @param url The URL to check. チェックする URL。\n * @param options Plugin options. プラグインオプション。\n * @returns Whether metadata should be fetched. メタデータを取得すべきかどうか。\n */\nconst shouldFetchMetadata = (url: string, options: BlockLinkMetadataOptions): boolean => {\n if (options.fetchAll) {\n return true\n }\n\n if (options.urlPatterns && options.urlPatterns.length > 0) {\n return options.urlPatterns.some((pattern: RegExp) => pattern.test(url))\n }\n\n // デフォルトでは、HTTP/HTTPS の外部リンクのみ対象\n return /^https?:\\/\\//.test(url) && !url.includes(\"localhost\") && !url.includes(\"127.0.0.1\")\n}\n\n/**\n * Remark plugin to enrich block-link nodes with site metadata.\n * block-linkノードにサイトメタデータを付加する Remark プラグイン。\n *\n * @param options Plugin options. プラグインオプション。\n * @returns The plugin function. プラグイン関数。\n */\nexport const remarkBlockLinkMetadata: Plugin<[BlockLinkMetadataOptions?], Root> = (options = {}) => {\n const { enableCache = true } = options\n\n return async (tree: Root) => {\n const linkNodes: EnrichedBlockLink[] = []\n\n // block-link ノードを収集\n visit(tree, \"block-link\", (node) => {\n if (shouldFetchMetadata(node.url, options)) {\n linkNodes.push(node as EnrichedBlockLink)\n }\n })\n\n // 各block-linkのメタデータを並行取得\n const metadataPromises = linkNodes.map(async (link) => {\n const url = link.url\n\n // キャッシュから取得を試行\n if (enableCache && metadataCache.has(url)) {\n const cachedMetadata = metadataCache.get(url)\n if (cachedMetadata) {\n link.data = link.data || {}\n link.data.siteMetadata = cachedMetadata\n }\n return\n }\n\n try {\n // サイトメタデータを取得\n const metadata = await fetchSiteMetadata(url)\n\n if (metadata) {\n // block-linkノードにメタデータを付加\n link.data = link.data || {}\n link.data.siteMetadata = metadata\n\n // キャッシュに保存\n if (enableCache) {\n metadataCache.set(url, metadata)\n }\n } else if (enableCache) {\n // 失敗した場合もキャッシュして、同じ URL への再リクエストを防ぐ\n metadataCache.set(url, null)\n }\n } catch (error) {\n Logger.warn(`Failed to fetch metadata for ${url}:`, error)\n if (enableCache) {\n metadataCache.set(url, null)\n }\n }\n })\n\n // 全てのメタデータ取得を待機\n await Promise.all(metadataPromises)\n }\n}\n","// @generated by protoc-gen-es v1.10.1 with parameter \"target=ts\"\n// @generated from file markdown/v1/markdown.proto (package markdown.v1, syntax proto3)\n/* eslint-disable */\n// @ts-nocheck\n\nimport type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from \"@bufbuild/protobuf\"\nimport { Message, proto3 } from \"@bufbuild/protobuf\"\n\n/**\n * @generated from message markdown.v1.ConvertRequest\n */\nexport class ConvertRequest extends Message<ConvertRequest> {\n /**\n * @generated from field: string markdown_text = 1;\n */\n markdownText = \"\"\n\n /**\n * Path of the document being converted. Canonical form is a fully qualified\n * URI: `file:///abs/path.md` (or a bare absolute path) for local documents,\n * `gcs://` / `gdrive://` URIs for cloud documents. A workspace-relative path\n * (bare or with a stray `file://` prefix) is also accepted and is anchored to\n * `workspace_root` server-side. Relative paths are NEVER resolved against the\n * server process's working directory. INVALID_ARGUMENT is returned when the\n * path is empty, when `workspace_root` is not absolute for a local document,\n * or when a relative path cannot be anchored strictly inside `workspace_root`\n * (e.g. `.` or `..` escapes).\n *\n * @generated from field: string file_path = 2;\n */\n filePath = \"\"\n\n /**\n * Absolute path of the workspace root. Required for local (file scheme)\n * documents: it anchors relative `file_path` values, bounds the local file://\n * sandbox, and derives the workspace-relative `/assets/` URLs emitted for\n * local images. Ignored for cloud documents.\n *\n * @generated from field: string workspace_root = 3;\n */\n workspaceRoot = \"\"\n\n /**\n * Enables existence validation for locally resolvable image and doc-link\n * targets. When true, a missing local image loses its src and gains\n * `data-asset-exists=\"false\"` plus `data-asset-src` (the workspace-relative\n * target, emitted only when it is inside `workspace_root`), and local doc\n * links gain `data-doc-exists`. When false, no existence markers are emitted\n * and no existence probes run. Cloud-scheme (gcs/gdrive) image targets are\n * rewritten to signed/proxy URLs without existence validation in either mode.\n *\n * @generated from field: bool validate_existence = 4;\n */\n validateExistence = false\n\n /**\n * @generated from field: optional bool enable_subscript = 5;\n */\n enableSubscript?: boolean\n\n /**\n * @generated from field: optional bool enable_superscript = 6;\n */\n enableSuperscript?: boolean\n\n /**\n * @generated from field: optional bool enable_mark = 7;\n */\n enableMark?: boolean\n\n /**\n * @generated from field: optional bool enable_table_merge = 8;\n */\n enableTableMerge?: boolean\n\n /**\n * @generated from field: optional bool enable_embeds = 9;\n */\n enableEmbeds?: boolean\n\n /**\n * @generated from field: optional bool enable_zenn_directives = 10;\n */\n enableZennDirectives?: boolean\n\n constructor(data?: PartialMessage<ConvertRequest>) {\n super()\n proto3.util.initPartial(data, this)\n }\n\n static readonly runtime: typeof proto3 = proto3\n static readonly typeName = \"markdown.v1.ConvertRequest\"\n static readonly fields: FieldList = proto3.util.newFieldList(() => [\n { no: 1, name: \"markdown_text\", kind: \"scalar\", T: 9 /* ScalarType.STRING */ },\n { no: 2, name: \"file_path\", kind: \"scalar\", T: 9 /* ScalarType.STRING */ },\n { no: 3, name: \"workspace_root\", kind: \"scalar\", T: 9 /* ScalarType.STRING */ },\n { no: 4, name: \"validate_existence\", kind: \"scalar\", T: 8 /* ScalarType.BOOL */ },\n { no: 5, name: \"enable_subscript\", kind: \"scalar\", T: 8 /* ScalarType.BOOL */, opt: true },\n { no: 6, name: \"enable_superscript\", kind: \"scalar\", T: 8 /* ScalarType.BOOL */, opt: true },\n { no: 7, name: \"enable_mark\", kind: \"scalar\", T: 8 /* ScalarType.BOOL */, opt: true },\n { no: 8, name: \"enable_table_merge\", kind: \"scalar\", T: 8 /* ScalarType.BOOL */, opt: true },\n { no: 9, name: \"enable_embeds\", kind: \"scalar\", T: 8 /* ScalarType.BOOL */, opt: true },\n { no: 10, name: \"enable_zenn_directives\", kind: \"scalar\", T: 8 /* ScalarType.BOOL */, opt: true },\n ])\n\n static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): ConvertRequest {\n return new ConvertRequest().fromBinary(bytes, options)\n }\n\n static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): ConvertRequest {\n return new ConvertRequest().fromJson(jsonValue, options)\n }\n\n static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): ConvertRequest {\n return new ConvertRequest().fromJsonString(jsonString, options)\n }\n\n static equals(a: ConvertRequest | PlainMessage<ConvertRequest> | undefined, b: ConvertRequest | PlainMessage<ConvertRequest> | undefined): boolean {\n return proto3.util.equals(ConvertRequest, a, b)\n }\n}\n\n/**\n * @generated from message markdown.v1.ConvertResponse\n */\nexport class ConvertResponse extends Message<ConvertResponse> {\n /**\n * @generated from field: string html_content = 1;\n */\n htmlContent = \"\"\n\n /**\n * @generated from field: repeated markdown.v1.Heading headings = 2;\n */\n headings: Heading[] = []\n\n constructor(data?: PartialMessage<ConvertResponse>) {\n super()\n proto3.util.initPartial(data, this)\n }\n\n static readonly runtime: typeof proto3 = proto3\n static readonly typeName = \"markdown.v1.ConvertResponse\"\n static readonly fields: FieldList = proto3.util.newFieldList(() => [\n { no: 1, name: \"html_content\", kind: \"scalar\", T: 9 /* ScalarType.STRING */ },\n { no: 2, name: \"headings\", kind: \"message\", T: Heading, repeated: true },\n ])\n\n static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): ConvertResponse {\n return new ConvertResponse().fromBinary(bytes, options)\n }\n\n static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): ConvertResponse {\n return new ConvertResponse().fromJson(jsonValue, options)\n }\n\n static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): ConvertResponse {\n return new ConvertResponse().fromJsonString(jsonString, options)\n }\n\n static equals(a: ConvertResponse | PlainMessage<ConvertResponse> | undefined, b: ConvertResponse | PlainMessage<ConvertResponse> | undefined): boolean {\n return proto3.util.equals(ConvertResponse, a, b)\n }\n}\n\n/**\n * @generated from message markdown.v1.Heading\n */\nexport class Heading extends Message<Heading> {\n /**\n * @generated from field: string text = 1;\n */\n text = \"\"\n\n /**\n * @generated from field: int32 depth = 2;\n */\n depth = 0\n\n /**\n * @generated from field: string id = 3;\n */\n id = \"\"\n\n constructor(data?: PartialMessage<Heading>) {\n super()\n proto3.util.initPartial(data, this)\n }\n\n static readonly runtime: typeof proto3 = proto3\n static readonly typeName = \"markdown.v1.Heading\"\n static readonly fields: FieldList = proto3.util.newFieldList(() => [\n { no: 1, name: \"text\", kind: \"scalar\", T: 9 /* ScalarType.STRING */ },\n { no: 2, name: \"depth\", kind: \"scalar\", T: 5 /* ScalarType.INT32 */ },\n { no: 3, name: \"id\", kind: \"scalar\", T: 9 /* ScalarType.STRING */ },\n ])\n\n static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Heading {\n return new Heading().fromBinary(bytes, options)\n }\n\n static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): Heading {\n return new Heading().fromJson(jsonValue, options)\n }\n\n static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): Heading {\n return new Heading().fromJsonString(jsonString, options)\n }\n\n static equals(a: Heading | PlainMessage<Heading> | undefined, b: Heading | PlainMessage<Heading> | undefined): boolean {\n return proto3.util.equals(Heading, a, b)\n }\n}\n","// @generated by protoc-gen-connect-es v1.7.0 with parameter \"target=ts\"\n// @generated from file markdown/v1/markdown.proto (package markdown.v1, syntax proto3)\n/* eslint-disable */\n// @ts-nocheck\n\nimport { MethodKind } from \"@bufbuild/protobuf\"\nimport { ConvertRequest, ConvertResponse } from \"./markdown_pb.js\"\n\n/**\n * @generated from service markdown.v1.MarkdownService\n */\nexport const MarkdownService = {\n typeName: \"markdown.v1.MarkdownService\",\n methods: {\n /**\n * @generated from rpc markdown.v1.MarkdownService.Convert\n */\n convert: {\n name: \"Convert\",\n I: ConvertRequest,\n O: ConvertResponse,\n kind: MethodKind.Unary,\n },\n },\n} as const\n","import { spawn } from \"node:child_process\"\nimport { existsSync, unlinkSync } from \"node:fs\"\nimport { createRequire } from \"node:module\"\nimport * as net from \"node:net\"\nimport * as path from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\nimport { createClient } from \"@connectrpc/connect\"\nimport { createConnectTransport } from \"@connectrpc/connect-node\"\nimport { MarkdownService } from \"./gen/markdown/v1/markdown_connect.ts\"\n\nconst SOCKET_PATH = process.env.MARKDOWN_SOCKET_PATH || \"/tmp/markdown.sock\"\n\nconst transport = createConnectTransport({\n baseUrl: \"http://localhost\",\n httpVersion: \"2\",\n nodeOptions: {\n createConnection: () => {\n return net.connect(SOCKET_PATH)\n },\n } as unknown as Record<string, unknown>,\n})\n\nconst client = createClient(MarkdownService, transport)\n\nexport interface ParseResult {\n htmlContent: string\n headings: Array<{\n text: string\n depth: number\n id: string\n }>\n}\n\nexport interface ParseOptions {\n validateExistence?: boolean\n enableSubscript?: boolean\n enableSuperscript?: boolean\n enableMark?: boolean\n enableTableMerge?: boolean\n enableEmbeds?: boolean\n enableZennDirectives?: boolean\n}\n\n/**\n * Returns the directory of this module in a way that works for both ESM and CJS output.\n * ESM / CJS どちらのビルド出力でも動作する形で本モジュールのディレクトリを返す処理。\n *\n * @returns Absolute directory path / 絶対ディレクトリパス\n */\nconst getDirname = (): string => {\n try {\n return path.dirname(fileURLToPath(import.meta.url))\n } catch {\n return __dirname\n }\n}\n\n/** プラットフォームパッケージ名 (@aiquants/markdown-linux-x64 等) */\nconst platformPackageName = (): string => `@aiquants/markdown-${process.platform}-${process.arch}`\n\n/** プラットフォームパッケージ内のバイナリ相対パス (Windows のみ .exe) */\nconst platformBinarySubpath = (): string => (process.platform === \"win32\" ? \"bin/markdown-api.exe\" : \"bin/markdown-api\")\n\n/**\n * Locates the `markdown-api` binary for the running platform.\n * 実行中プラットフォーム向けの `markdown-api` バイナリを探索する処理。\n *\n * 探索順:\n * 1. `MARKDOWN_API_BINARY` 環境変数 (自前ビルドの差し込み口)\n * 2. プラットフォームパッケージ (通常の配布経路。Node の解決機構に委ねるため\n * パス組み立てのヒューリスティックが不要)\n * 3. モノレポ開発時に `pnpm run build:go` がビルドする `packages/go/markdown-api/dist/`\n *\n * 候補 3 はモノレポ内の消費アプリからは機能しない。workspace 依存が injected\n * (ハードリンクコピー) で解決されるため、`.pnpm/` 配下のコピーから相対で辿れない。\n * サービスを自前起動する統合テストは `MARKDOWN_API_BINARY` を明示すること。\n *\n * 実行権限は付与しない。バイナリはプラットフォームパッケージの `bin` フィールド経由で\n * 配られ、パッケージマネージャが 0755 を保証する。\n *\n * @returns Absolute binary path, or undefined when unavailable / バイナリの絶対パス。見つからない場合は undefined\n */\nexport const resolveBinaryPath = (): string | undefined => {\n const fromEnvironment = process.env.MARKDOWN_API_BINARY\n if (fromEnvironment && existsSync(fromEnvironment)) {\n return fromEnvironment\n }\n\n try {\n // createRequire の基点はビルド形式に依存しない getDirname() から作る\n // (CJS 出力で import.meta.url がどう変換されても影響を受けない)\n const resolved = createRequire(path.join(getDirname(), \"index.js\")).resolve(`${platformPackageName()}/${platformBinarySubpath()}`)\n if (existsSync(resolved)) {\n return resolved\n }\n } catch {\n // プラットフォームパッケージ未インストール (モノレポ開発時は常にこの経路)\n }\n\n const monorepoBinary = path.join(getDirname(), \"..\", \"..\", \"go\", \"markdown-api\", \"dist\", path.basename(platformBinarySubpath()))\n return existsSync(monorepoBinary) ? monorepoBinary : undefined\n}\n\n/**\n * Builds a diagnosable message for a missing binary.\n * バイナリが見つからない場合の原因診断メッセージを組み立てる処理。\n *\n * 「見つからない」だけでは利用者が次に何をすべきか分からないため、期待した\n * プラットフォームパッケージ名と自前ビルドの差し込み口まで示す。\n *\n * @returns Human-readable diagnostic message / 人間が読める診断メッセージ\n */\nconst describeMissingBinary = (): string =>\n [\n `markdown-api binary not found for ${process.platform}-${process.arch}.`,\n `Expected the optional dependency ${platformPackageName()} to be installed.`,\n \"If your platform is unsupported, build the service yourself\",\n \"(https://github.com/fehde-k/aiquants/tree/main/packages/go/markdown-api)\",\n \"and point MARKDOWN_API_BINARY at it.\",\n ].join(\" \")\n\nconst canConnect = (): Promise<boolean> =>\n new Promise((resolve) => {\n const socket = net.connect(SOCKET_PATH)\n socket.on(\"connect\", () => {\n socket.destroy()\n resolve(true)\n })\n socket.on(\"error\", () => resolve(false))\n })\n\nconst waitForServer = async (timeoutMs: number): Promise<boolean> => {\n const start = Date.now()\n while (Date.now() - start < timeoutMs) {\n if (await canConnect()) return true\n await new Promise((r) => setTimeout(r, 100))\n }\n return false\n}\n\nlet spawnedServer: ReturnType<typeof spawn> | null = null\nlet startPromise: Promise<boolean> | null = null\n\n/**\n * Grace period for a server started outside this process, in milliseconds.\n * 本プロセス外で起動されたサーバを待つ猶予時間 (ミリ秒)。\n *\n * コンテナ環境ではプロセスマネージャ (supervisor 等) が `markdown-api` を別プログラムとして\n * 起動するため、パッケージ内にバイナリは存在しない。その構成で Node 側が先に温まると\n * ソケット未 bind の瞬間に当たりうるので、自前起動を諦める前に短時間だけ待つ。\n * Go 側の bind はミリ秒で完了するため、これで十分。\n */\nconst EXTERNAL_SERVER_GRACE_MS = 2000\n\n/**\n * Time budget for a freshly spawned server to start listening, in milliseconds.\n * 新規起動したサーバが待ち受け開始するまでの猶予時間 (ミリ秒)。\n *\n * 低速な CI コンテナでは既定の 10 秒でも足りないことがあるため環境変数で調整できる。\n * 不正値 (数値でない / 0 以下) は既定へ戻す (設定ミスで永久に待たないようにする)。\n *\n * @returns Timeout in milliseconds / ミリ秒単位のタイムアウト\n */\nconst startupTimeoutMs = (): number => {\n const configured = Number(process.env.MARKDOWN_API_STARTUP_TIMEOUT_MS)\n return Number.isFinite(configured) && configured > 0 ? configured : 10000\n}\n\n/** 自動起動をバイナリ不在で諦めた理由。到達不能エラーへ添えて診断可能にする */\nlet missingBinaryReason: string | null = null\n\nconst ensureServerRunning = async (): Promise<boolean> => {\n if (await canConnect()) return true\n\n if (startPromise) return startPromise\n\n startPromise = (async () => {\n const binPath = resolveBinaryPath()\n if (!binPath) {\n // 外部管理サーバの起動待ちに賭ける。ここで即諦めると、プロセスマネージャ管理型の\n // 構成 (バイナリを同梱しない) で起動直後のリクエストが理由なく失敗する\n if (await waitForServer(EXTERNAL_SERVER_GRACE_MS)) return true\n missingBinaryReason = describeMissingBinary()\n return false\n }\n // バイナリが見つかった以降は不在が理由ではない。古い理由を残すと誤診を招く\n missingBinaryReason = null\n\n // Clean up stale socket file if it exists\n try {\n if (existsSync(SOCKET_PATH)) {\n unlinkSync(SOCKET_PATH)\n }\n } catch {\n // ignore\n }\n\n try {\n spawnedServer = spawn(binPath, [], { stdio: \"ignore\" })\n\n const cleanup = () => {\n if (spawnedServer) {\n try {\n spawnedServer.kill(\"SIGTERM\")\n } catch {\n // 既に終了しているケースは無視する\n }\n spawnedServer = null\n }\n }\n\n // once で登録し、失敗時は明示的に解除する。on のままだと起動失敗を\n // 繰り返すたびにリスナーが蓄積し、MaxListeners 警告とメモリリークを招く\n process.once(\"exit\", cleanup)\n\n const ready = await waitForServer(startupTimeoutMs())\n if (!ready) {\n console.error(\"markdown-api Go server did not become ready on socket:\", SOCKET_PATH)\n cleanup()\n process.removeListener(\"exit\", cleanup)\n return false\n }\n return true\n } catch (err) {\n console.error(\"Failed to spawn markdown-api Go server:\", err)\n spawnedServer = null\n return false\n }\n })()\n\n const success = await startPromise\n if (!success) {\n startPromise = null\n }\n return success\n}\n\n/**\n * Converts markdown text to HTML via the Go markdown-api server over ConnectRPC/UDS.\n * ConnectRPC/UDS 経由で Go markdown-api サーバへ委譲し、Markdown を HTML へ変換する処理。\n *\n * Path contract (パス契約):\n * - `markdownFilePath` の正準形はスキーム付き完全 URI (ローカルは `file:///abs/path.md`、\n * クラウドは `gcs://` / `gdrive://`)。素の絶対パスも同義に扱われる。\n * - ワークスペース相対パスも受理され、サーバ側で `workspaceRoot` にアンカーされる。\n * 相対パスがサーバプロセスの CWD 基準で解釈されることは決してない。\n * - ローカルドキュメントでは `workspaceRoot` が絶対パスであることが必須 (file://\n * サンドボックスの境界かつ `/assets/` 相対 URL の基点)。空・相対の `workspaceRoot`、\n * 空の `markdownFilePath`、アンカー後にルート外へ逃げる相対パスはいずれも\n * INVALID_ARGUMENT で拒否される (Fail Fast)。\n *\n * `validateExistenceOrOptions` が true (既定) のとき、解決先が存在しない画像は src を\n * 失い data-asset-exists=\"false\" を持ち、解決先が `workspaceRoot` の内側にある場合に\n * 限り data-asset-src (解決先の相対パス) も付く (ワークスペース外のパス構造は開示\n * しない)。ローカルドキュメントリンクには data-doc-exists が付く。false のとき\n * 存在検証は一切行われない。\n */\nexport const parseMarkdown = async (markdownText: string, markdownFilePath: string, workspaceRoot: string, userOAuthToken?: string, validateExistenceOrOptions: boolean | ParseOptions = true): Promise<ParseResult> => {\n // Automatically ensure the backend Go server is running\n if (!(await ensureServerRunning())) {\n // 到達できないまま RPC へ進むと、利用者には原因不明の ENOENT だけが届く。\n // 自動起動がバイナリ不在で諦めた場合は、必要なパッケージ名まで含めて伝える\n const detail = missingBinaryReason ? ` ${missingBinaryReason}` : \"\"\n throw new Error(`markdown service is not reachable on ${SOCKET_PATH}.${detail}`)\n }\n\n let validateExistence = true\n let enableSubscript: boolean | undefined\n let enableSuperscript: boolean | undefined\n let enableMark: boolean | undefined\n let enableTableMerge: boolean | undefined\n let enableEmbeds: boolean | undefined\n let enableZennDirectives: boolean | undefined\n\n if (typeof validateExistenceOrOptions === \"boolean\") {\n validateExistence = validateExistenceOrOptions\n } else if (validateExistenceOrOptions && typeof validateExistenceOrOptions === \"object\") {\n validateExistence = validateExistenceOrOptions.validateExistence ?? true\n enableSubscript = validateExistenceOrOptions.enableSubscript\n enableSuperscript = validateExistenceOrOptions.enableSuperscript\n enableMark = validateExistenceOrOptions.enableMark\n enableTableMerge = validateExistenceOrOptions.enableTableMerge\n enableEmbeds = validateExistenceOrOptions.enableEmbeds\n enableZennDirectives = validateExistenceOrOptions.enableZennDirectives\n }\n\n const headers: Record<string, string> = {}\n if (userOAuthToken) {\n headers.Authorization = `Bearer ${userOAuthToken}`\n }\n\n const response = await client.convert(\n {\n markdownText,\n filePath: markdownFilePath,\n workspaceRoot,\n validateExistence,\n enableSubscript,\n enableSuperscript,\n enableMark,\n enableTableMerge,\n enableEmbeds,\n enableZennDirectives,\n },\n { headers },\n )\n\n return {\n htmlContent: response.htmlContent,\n headings: response.headings.map((h) => ({\n text: h.text,\n depth: h.depth,\n id: h.id,\n })),\n }\n}\n"],"names":["fetchSiteMetadata","url","controller","timeoutId","response","html","metadata","$","load","title","metaTags","meta","property","error","Logger","metadataCache","shouldFetchMetadata","options","pattern","remarkBlockLinkMetadata","enableCache","tree","linkNodes","visit","node","metadataPromises","link","cachedMetadata","ConvertRequest","Message","data","proto3","bytes","jsonValue","jsonString","a","b","ConvertResponse","Heading","MarkdownService","MethodKind","SOCKET_PATH","transport","createConnectTransport","net","client","createClient","getDirname","path","fileURLToPath","_documentCurrentScript","platformPackageName","platformBinarySubpath","resolveBinaryPath","fromEnvironment","existsSync","resolved","createRequire","monorepoBinary","describeMissingBinary","canConnect","resolve","socket","waitForServer","timeoutMs","start","r","spawnedServer","startPromise","EXTERNAL_SERVER_GRACE_MS","startupTimeoutMs","configured","missingBinaryReason","ensureServerRunning","binPath","unlinkSync","spawn","cleanup","err","success","parseMarkdown","markdownText","markdownFilePath","workspaceRoot","userOAuthToken","validateExistenceOrOptions","detail","validateExistence","enableSubscript","enableSuperscript","enableMark","enableTableMerge","enableEmbeds","enableZennDirectives","headers","h"],"mappings":"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"}
@@ -1,11 +1,17 @@
1
1
  /**
2
2
  * @module
3
3
  * Server side exports for the @aiquants/markdown package.
4
+ *
5
+ * Resolving a relative reference (`![](images/x.png)`, `<!-- @import "rel" -->`) is not done here.
6
+ * The rule deciding what a base URI is belongs to the storage backend — Drive reads a bare
7
+ * twenty-character segment as an identifier and a dotted one as a path — so resolution is performed by
8
+ * the markdown service through `storage-api`, and `parseMarkdown` returns references already resolved.
9
+ * 相対参照 (`![](images/x.png)` や `<!-- @import "rel" -->`) の解決はここでは行わない。基準 URI が
10
+ * 何であるかを決める規則はストレージのバックエンドの持ち物であり (Drive は裸の 20 文字の区画を
11
+ * 識別子として読み、点を含むものをパスとして読む)、解決は markdown サービスが `storage-api` を
12
+ * 通して行う。`parseMarkdown` が返す参照は既に解決済みである。
4
13
  */
5
14
  export { fetchSiteMetadata, type SiteMetadata } from './plugins/fetchSiteMetadata.ts';
6
15
  export { remarkBlockLinkMetadata } from './plugins/remark-block-link-metadata.ts';
7
- export { remarkImportDirective } from './plugins/remark-import-directive.async.server.ts';
8
- export { remarkResolveUriAsync } from './plugins/remark-resolve-uri.async.ts';
9
- export { transformUriAsync } from './plugins/transformUri.async.server.ts';
10
16
  export { type ParseOptions, type ParseResult, parseMarkdown } from './remarkProcessor.server.ts';
11
17
  //# sourceMappingURL=index.server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.server.d.ts","sourceRoot":"","sources":["../src/index.server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,iBAAiB,EAAE,KAAK,YAAY,EAAE,MAAM,gCAAgC,CAAA;AACrF,OAAO,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAA;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,mDAAmD,CAAA;AACzF,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAA;AAC7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAA;AAE1E,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA"}
1
+ {"version":3,"file":"index.server.d.ts","sourceRoot":"","sources":["../src/index.server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,iBAAiB,EAAE,KAAK,YAAY,EAAE,MAAM,gCAAgC,CAAA;AACrF,OAAO,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAA;AAEjF,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA"}