@webnumseoagent/next 0.8.0 → 0.9.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.
package/blog.tsx CHANGED
@@ -23,7 +23,7 @@ const blogfs = () => import("./blog-fs");
23
23
  // .blogfs.json (платформа пишет бренд-цвет владельца в accent + опц. токены оформления сайта).
24
24
  // toc — оглавление статьи: enabled (вкл/выкл), variant (вид), motion (анимация), top (офсет sticky/якоря),
25
25
  // css (маленький scoped-CSS под .sa-toc от Designer-агента — индивидуальный вид/анимация под стиль сайта).
26
- export interface SeoBlogTocTheme { enabled?: boolean; variant?: string; motion?: boolean; top?: string; css?: string }
26
+ export interface SeoBlogTocTheme { enabled?: boolean; variant?: string; motion?: boolean; top?: string; maxh?: string; css?: string }
27
27
  export interface SeoBlogTheme { accent?: string; border?: string; muted?: string; surface?: string; thBg?: string; radius?: string; toc?: SeoBlogTocTheme }
28
28
  export interface SeoBlogSummary { slug: string; title: string; excerpt: string; cover: string | null; date: string | null }
29
29
  export interface SeoBlogPostFull extends SeoBlogSummary { bodyHtml: string; theme?: SeoBlogTheme }
@@ -124,26 +124,34 @@ function safeTocCss(css?: string): string {
124
124
  return css.slice(0, 4000);
125
125
  }
126
126
 
127
- const TOC_CSS = `.sa-article-wrap{max-width:1080px;margin:0 auto;padding:var(--sa-blog-top,clamp(5rem,8vw,7rem)) 1.5rem 3rem}
128
- .sa-article-wrap.has-toc{display:grid;gap:2.5rem;grid-template-columns:1fr}
129
- @media(min-width:1024px){.sa-article-wrap.has-toc{grid-template-columns:250px minmax(0,760px);justify-content:center;align-items:start}}
127
+ const TOC_CSS = `.sa-article-wrap{max-width:1400px;margin:0 auto;padding:var(--sa-blog-top,clamp(5rem,8vw,7rem)) 1.5rem 3rem;container-type:inline-size}
128
+ .sa-article-grid{display:block}
129
+ .sa-article-grid:not(.has-toc){max-width:760px;margin:0 auto}
130
130
  .sa-article{min-width:0;line-height:1.7}
131
- .sa-article-wrap:not(.has-toc) .sa-article{max-width:760px;margin:0 auto}
132
- .sa-toc{order:-1;font-size:.9rem}
133
- @media(min-width:1024px){.sa-toc{position:sticky;top:var(--sa-toc-top,88px);max-height:calc(100vh - 120px);overflow:auto}}
131
+ .sa-toc{font-size:.9rem}
132
+ /* Средняя ширина контента: оглавление слева + статья рядом, блок по центру (формат для узкого контента). */
133
+ @container (min-width:700px){.sa-article-grid.has-toc{display:grid;column-gap:2.5rem;grid-template-columns:250px minmax(0,760px);justify-content:center;align-items:start}
134
+ .sa-toc{position:sticky;top:var(--sa-toc-top,88px)}}
135
+ /* Широкий контент (ZeroMax): статья ПО ЦЕНТРУ вьюпорта, оглавление в левом гуттере, прижато к статье (капнуто ~300px). */
136
+ @container (min-width:1180px){.sa-article-grid.has-toc{grid-template-columns:minmax(0,1fr) minmax(0,760px) minmax(0,1fr);column-gap:0}
137
+ .sa-article-grid.has-toc>.sa-toc{grid-column:1;justify-self:end;width:min(100%,300px);margin-right:2.5rem}
138
+ .sa-article-grid.has-toc>.sa-article{grid-column:2}}
134
139
  .sa-toc>summary{list-style:none;font-weight:700;font-size:.95rem;margin:0 0 .75rem;display:flex;align-items:center;justify-content:space-between;gap:.5rem;color:inherit;cursor:pointer}
135
140
  .sa-toc>summary::-webkit-details-marker{display:none}
136
141
  .sa-toc>summary .sa-toc-chev{transition:transform .2s ease;color:var(--sa-muted,#94a3b8)}
137
142
  .sa-toc[open]>summary .sa-toc-chev{transform:rotate(90deg)}
138
143
  @media(min-width:1024px){.sa-toc>summary{pointer-events:none}.sa-toc>summary .sa-toc-chev{display:none}}
139
- .sa-toc-list{display:flex;flex-direction:column;gap:.1rem}
144
+ .sa-toc-body{position:relative}
145
+ .sa-toc-list{display:flex;flex-direction:column;gap:.1rem;max-height:var(--sa-toc-maxh,300px);overflow-y:auto;overscroll-behavior:contain;scrollbar-width:none;-ms-overflow-style:none}
146
+ .sa-toc-list::-webkit-scrollbar{width:0;height:0;display:none}
140
147
  .sa-toc-list a{display:block;text-decoration:none;color:var(--sa-muted,#64748b);padding:.35rem .6rem;border-radius:var(--sa-radius,8px);line-height:1.4;transition:color .15s ease,background .15s ease,border-color .15s ease}
141
148
  .sa-toc-list a[data-level="3"]{padding-left:1.4rem;font-size:.85em}
142
149
  .sa-toc-list a:hover{color:inherit}
143
150
  .sa-toc-list a.is-active{color:var(--sa-accent,#2563eb)}
144
- .sa-toc[data-sa-toc="minimal"] .sa-toc-list{border-left:2px solid var(--sa-border,#e5e7eb);padding-left:.2rem}
145
- .sa-toc[data-sa-toc="minimal"] .sa-toc-list a{border-left:2px solid transparent;margin-left:-.2rem;border-radius:0}
146
- .sa-toc[data-sa-toc="minimal"] .sa-toc-list a.is-active{border-left-color:var(--sa-accent,#2563eb);font-weight:600}
151
+ .sa-toc[data-sa-toc="minimal"] .sa-toc-body::before{content:"";position:absolute;left:0;top:.2rem;bottom:.2rem;width:2px;background:var(--sa-border,#e5e7eb);z-index:0}
152
+ .sa-toc[data-sa-toc="minimal"] .sa-toc-list a{padding-left:.9rem;border-radius:0;box-shadow:inset 2px 0 0 transparent}
153
+ .sa-toc[data-sa-toc="minimal"] .sa-toc-list a[data-level="3"]{padding-left:1.7rem}
154
+ .sa-toc[data-sa-toc="minimal"] .sa-toc-list a.is-active{box-shadow:inset 2px 0 0 var(--sa-accent,#2563eb)}
147
155
  .sa-toc[data-sa-toc="bordered"]{border:1px solid var(--sa-border,#e5e7eb);border-radius:var(--sa-radius,12px);padding:1rem;background:var(--sa-surface,transparent)}
148
156
  .sa-toc[data-sa-toc="bordered"] .sa-toc-list a.is-active{background:var(--sa-th-bg,color-mix(in srgb,currentColor 8%,transparent))}
149
157
  .sa-toc[data-sa-toc="pill"] .sa-toc-list a.is-active{background:var(--sa-accent,#2563eb);color:#fff}
@@ -231,28 +239,34 @@ export function SeoBlogArticle({ post, locale }: { post: SeoBlogPostFull; locale
231
239
  const variant = toc.variant || "minimal";
232
240
  const motion = toc.motion === false ? "off" : "on";
233
241
  const label = L(TOC_LABEL, locale ?? "", "Contents");
234
- const rootStyle = { ...themeStyle(post.theme), ...(toc.top ? { ["--sa-toc-top"]: toc.top } : {}) } as CSSProperties;
242
+ const rootStyle = { ...themeStyle(post.theme), ...(toc.top ? { ["--sa-toc-top"]: toc.top } : {}), ...(toc.maxh ? { ["--sa-toc-maxh"]: toc.maxh } : {}) } as CSSProperties;
235
243
  return (
236
- <div className={showToc ? "sa-article-wrap has-toc" : "sa-article-wrap"} style={rootStyle}>
244
+ <div className="sa-article-wrap" style={rootStyle}>
237
245
  <style dangerouslySetInnerHTML={{ __html: BODY_CSS + TOC_CSS + (showToc ? safeTocCss(toc.css) : "") }} />
238
- {showToc ? (
239
- <details className="sa-toc" data-sa-toc={variant} data-motion={motion} open>
240
- <summary>{label}<span className="sa-toc-chev" aria-hidden="true">›</span></summary>
241
- <nav className="sa-toc-list" aria-label={label}>
242
- {items.map((it) => (
243
- <a key={it.id} href={`#${it.id}`} data-toc-link={it.id} data-level={it.level}>{it.text}</a>
244
- ))}
245
- </nav>
246
- <SeoBlogTocSpy ids={items.map((it) => it.id)} />
247
- </details>
248
- ) : null}
249
- <article className="sa-article">
250
- {post.cover ? <img src={post.cover} alt={post.title} style={{ width: "100%", aspectRatio: "3 / 2", objectFit: "cover", display: "block", borderRadius: "var(--sa-radius, 12px)", marginBottom: "1.5rem" }} /> : null}
251
- <h1 style={{ fontSize: "2.2rem", lineHeight: 1.2, margin: "0 0 1rem" }}>{post.title}</h1>
252
- {post.date ? <p style={{ color: "var(--sa-muted, #94a3b8)", margin: "0 0 1.5rem" }}>{fmtDate(post.date, locale)}</p> : null}
253
- {/* Тело уже санитайзено при доставке; id-якоря добавлены buildToc при рендере. */}
254
- <div className="seoagent-blog-body" dangerouslySetInnerHTML={{ __html: html }} />
255
- </article>
246
+ {/* Внутренний грид — CSS-контейнер .sa-article-wrap адаптирует его по ШИРИНЕ контента (@container). */}
247
+ <div className={showToc ? "sa-article-grid has-toc" : "sa-article-grid"}>
248
+ {showToc ? (
249
+ <details className="sa-toc" data-sa-toc={variant} data-motion={motion} open>
250
+ <summary>{label}<span className="sa-toc-chev" aria-hidden="true">›</span></summary>
251
+ {/* .sa-toc-body держит общий рельс (::before) вне скролла; скроллится только список. */}
252
+ <div className="sa-toc-body">
253
+ <nav className="sa-toc-list" aria-label={label}>
254
+ {items.map((it) => (
255
+ <a key={it.id} href={`#${it.id}`} data-toc-link={it.id} data-level={it.level}>{it.text}</a>
256
+ ))}
257
+ </nav>
258
+ </div>
259
+ <SeoBlogTocSpy ids={items.map((it) => it.id)} />
260
+ </details>
261
+ ) : null}
262
+ <article className="sa-article">
263
+ {post.cover ? <img src={post.cover} alt={post.title} style={{ width: "100%", aspectRatio: "3 / 2", objectFit: "cover", display: "block", borderRadius: "var(--sa-radius, 12px)", marginBottom: "1.5rem" }} /> : null}
264
+ <h1 style={{ fontSize: "2.2rem", lineHeight: 1.2, margin: "0 0 1rem" }}>{post.title}</h1>
265
+ {post.date ? <p style={{ color: "var(--sa-muted, #94a3b8)", margin: "0 0 1.5rem" }}>{fmtDate(post.date, locale)}</p> : null}
266
+ {/* Тело уже санитайзено при доставке; id-якоря добавлены buildToc при рендере. */}
267
+ <div className="seoagent-blog-body" dangerouslySetInnerHTML={{ __html: html }} />
268
+ </article>
269
+ </div>
256
270
  </div>
257
271
  );
258
272
  }
package/dist/blog-toc.js CHANGED
@@ -20,6 +20,21 @@ function SeoBlogTocSpy({ ids }) {
20
20
  const heads = ids.map((id) => document.getElementById(id)).filter(Boolean);
21
21
  if (!heads.length)
22
22
  return;
23
+ const reduce = typeof matchMedia !== "undefined" && matchMedia("(prefers-reduced-motion: reduce)").matches;
24
+ // Держим активный пункт в видимой (обрезанной) зоне списка: подкручиваем сам скролл-контейнер
25
+ // .sa-toc-list, чтобы при скролле статьи выделенный заголовок не «уезжал» за пределы оглавления.
26
+ const keepInView = (a) => {
27
+ const box = a.closest(".sa-toc-list");
28
+ if (!box || box.scrollHeight <= box.clientHeight)
29
+ return;
30
+ const ar = a.getBoundingClientRect(), br = box.getBoundingClientRect();
31
+ const top = box.scrollTop + (ar.top - br.top);
32
+ const pad = 8;
33
+ if (top < box.scrollTop + pad)
34
+ box.scrollTo({ top: Math.max(0, top - pad), behavior: reduce ? "auto" : "smooth" });
35
+ else if (top + ar.height > box.scrollTop + box.clientHeight - pad)
36
+ box.scrollTo({ top: top + ar.height - box.clientHeight + pad, behavior: reduce ? "auto" : "smooth" });
37
+ };
23
38
  let active = "";
24
39
  const setActive = (id) => {
25
40
  if (id === active)
@@ -33,8 +48,10 @@ function SeoBlogTocSpy({ ids }) {
33
48
  else
34
49
  a.removeAttribute("aria-current");
35
50
  });
51
+ const cur = links.get(id);
52
+ if (cur)
53
+ keepInView(cur);
36
54
  };
37
- const reduce = typeof matchMedia !== "undefined" && matchMedia("(prefers-reduced-motion: reduce)").matches;
38
55
  const onClick = (e) => {
39
56
  const a = e.currentTarget;
40
57
  const id = a.getAttribute("data-toc-link");
package/dist/blog.d.ts CHANGED
@@ -3,6 +3,7 @@ export interface SeoBlogTocTheme {
3
3
  variant?: string;
4
4
  motion?: boolean;
5
5
  top?: string;
6
+ maxh?: string;
6
7
  css?: string;
7
8
  }
8
9
  export interface SeoBlogTheme {
package/dist/blog.js CHANGED
@@ -142,26 +142,34 @@ function safeTocCss(css) {
142
142
  return "";
143
143
  return css.slice(0, 4000);
144
144
  }
145
- const TOC_CSS = `.sa-article-wrap{max-width:1080px;margin:0 auto;padding:var(--sa-blog-top,clamp(5rem,8vw,7rem)) 1.5rem 3rem}
146
- .sa-article-wrap.has-toc{display:grid;gap:2.5rem;grid-template-columns:1fr}
147
- @media(min-width:1024px){.sa-article-wrap.has-toc{grid-template-columns:250px minmax(0,760px);justify-content:center;align-items:start}}
145
+ const TOC_CSS = `.sa-article-wrap{max-width:1400px;margin:0 auto;padding:var(--sa-blog-top,clamp(5rem,8vw,7rem)) 1.5rem 3rem;container-type:inline-size}
146
+ .sa-article-grid{display:block}
147
+ .sa-article-grid:not(.has-toc){max-width:760px;margin:0 auto}
148
148
  .sa-article{min-width:0;line-height:1.7}
149
- .sa-article-wrap:not(.has-toc) .sa-article{max-width:760px;margin:0 auto}
150
- .sa-toc{order:-1;font-size:.9rem}
151
- @media(min-width:1024px){.sa-toc{position:sticky;top:var(--sa-toc-top,88px);max-height:calc(100vh - 120px);overflow:auto}}
149
+ .sa-toc{font-size:.9rem}
150
+ /* Средняя ширина контента: оглавление слева + статья рядом, блок по центру (формат для узкого контента). */
151
+ @container (min-width:700px){.sa-article-grid.has-toc{display:grid;column-gap:2.5rem;grid-template-columns:250px minmax(0,760px);justify-content:center;align-items:start}
152
+ .sa-toc{position:sticky;top:var(--sa-toc-top,88px)}}
153
+ /* Широкий контент (ZeroMax): статья ПО ЦЕНТРУ вьюпорта, оглавление в левом гуттере, прижато к статье (капнуто ~300px). */
154
+ @container (min-width:1180px){.sa-article-grid.has-toc{grid-template-columns:minmax(0,1fr) minmax(0,760px) minmax(0,1fr);column-gap:0}
155
+ .sa-article-grid.has-toc>.sa-toc{grid-column:1;justify-self:end;width:min(100%,300px);margin-right:2.5rem}
156
+ .sa-article-grid.has-toc>.sa-article{grid-column:2}}
152
157
  .sa-toc>summary{list-style:none;font-weight:700;font-size:.95rem;margin:0 0 .75rem;display:flex;align-items:center;justify-content:space-between;gap:.5rem;color:inherit;cursor:pointer}
153
158
  .sa-toc>summary::-webkit-details-marker{display:none}
154
159
  .sa-toc>summary .sa-toc-chev{transition:transform .2s ease;color:var(--sa-muted,#94a3b8)}
155
160
  .sa-toc[open]>summary .sa-toc-chev{transform:rotate(90deg)}
156
161
  @media(min-width:1024px){.sa-toc>summary{pointer-events:none}.sa-toc>summary .sa-toc-chev{display:none}}
157
- .sa-toc-list{display:flex;flex-direction:column;gap:.1rem}
162
+ .sa-toc-body{position:relative}
163
+ .sa-toc-list{display:flex;flex-direction:column;gap:.1rem;max-height:var(--sa-toc-maxh,300px);overflow-y:auto;overscroll-behavior:contain;scrollbar-width:none;-ms-overflow-style:none}
164
+ .sa-toc-list::-webkit-scrollbar{width:0;height:0;display:none}
158
165
  .sa-toc-list a{display:block;text-decoration:none;color:var(--sa-muted,#64748b);padding:.35rem .6rem;border-radius:var(--sa-radius,8px);line-height:1.4;transition:color .15s ease,background .15s ease,border-color .15s ease}
159
166
  .sa-toc-list a[data-level="3"]{padding-left:1.4rem;font-size:.85em}
160
167
  .sa-toc-list a:hover{color:inherit}
161
168
  .sa-toc-list a.is-active{color:var(--sa-accent,#2563eb)}
162
- .sa-toc[data-sa-toc="minimal"] .sa-toc-list{border-left:2px solid var(--sa-border,#e5e7eb);padding-left:.2rem}
163
- .sa-toc[data-sa-toc="minimal"] .sa-toc-list a{border-left:2px solid transparent;margin-left:-.2rem;border-radius:0}
164
- .sa-toc[data-sa-toc="minimal"] .sa-toc-list a.is-active{border-left-color:var(--sa-accent,#2563eb);font-weight:600}
169
+ .sa-toc[data-sa-toc="minimal"] .sa-toc-body::before{content:"";position:absolute;left:0;top:.2rem;bottom:.2rem;width:2px;background:var(--sa-border,#e5e7eb);z-index:0}
170
+ .sa-toc[data-sa-toc="minimal"] .sa-toc-list a{padding-left:.9rem;border-radius:0;box-shadow:inset 2px 0 0 transparent}
171
+ .sa-toc[data-sa-toc="minimal"] .sa-toc-list a[data-level="3"]{padding-left:1.7rem}
172
+ .sa-toc[data-sa-toc="minimal"] .sa-toc-list a.is-active{box-shadow:inset 2px 0 0 var(--sa-accent,#2563eb)}
165
173
  .sa-toc[data-sa-toc="bordered"]{border:1px solid var(--sa-border,#e5e7eb);border-radius:var(--sa-radius,12px);padding:1rem;background:var(--sa-surface,transparent)}
166
174
  .sa-toc[data-sa-toc="bordered"] .sa-toc-list a.is-active{background:var(--sa-th-bg,color-mix(in srgb,currentColor 8%,transparent))}
167
175
  .sa-toc[data-sa-toc="pill"] .sa-toc-list a.is-active{background:var(--sa-accent,#2563eb);color:#fff}
@@ -236,8 +244,8 @@ function SeoBlogArticle({ post, locale }) {
236
244
  const variant = toc.variant || "minimal";
237
245
  const motion = toc.motion === false ? "off" : "on";
238
246
  const label = L(TOC_LABEL, locale ?? "", "Contents");
239
- const rootStyle = { ...themeStyle(post.theme), ...(toc.top ? { ["--sa-toc-top"]: toc.top } : {}) };
240
- return ((0, jsx_runtime_1.jsxs)("div", { className: showToc ? "sa-article-wrap has-toc" : "sa-article-wrap", style: rootStyle, children: [(0, jsx_runtime_1.jsx)("style", { dangerouslySetInnerHTML: { __html: BODY_CSS + TOC_CSS + (showToc ? safeTocCss(toc.css) : "") } }), showToc ? ((0, jsx_runtime_1.jsxs)("details", { className: "sa-toc", "data-sa-toc": variant, "data-motion": motion, open: true, children: [(0, jsx_runtime_1.jsxs)("summary", { children: [label, (0, jsx_runtime_1.jsx)("span", { className: "sa-toc-chev", "aria-hidden": "true", children: "\u203A" })] }), (0, jsx_runtime_1.jsx)("nav", { className: "sa-toc-list", "aria-label": label, children: items.map((it) => ((0, jsx_runtime_1.jsx)("a", { href: `#${it.id}`, "data-toc-link": it.id, "data-level": it.level, children: it.text }, it.id))) }), (0, jsx_runtime_1.jsx)(blog_toc_1.SeoBlogTocSpy, { ids: items.map((it) => it.id) })] })) : null, (0, jsx_runtime_1.jsxs)("article", { className: "sa-article", children: [post.cover ? (0, jsx_runtime_1.jsx)("img", { src: post.cover, alt: post.title, style: { width: "100%", aspectRatio: "3 / 2", objectFit: "cover", display: "block", borderRadius: "var(--sa-radius, 12px)", marginBottom: "1.5rem" } }) : null, (0, jsx_runtime_1.jsx)("h1", { style: { fontSize: "2.2rem", lineHeight: 1.2, margin: "0 0 1rem" }, children: post.title }), post.date ? (0, jsx_runtime_1.jsx)("p", { style: { color: "var(--sa-muted, #94a3b8)", margin: "0 0 1.5rem" }, children: fmtDate(post.date, locale) }) : null, (0, jsx_runtime_1.jsx)("div", { className: "seoagent-blog-body", dangerouslySetInnerHTML: { __html: html } })] })] }));
247
+ const rootStyle = { ...themeStyle(post.theme), ...(toc.top ? { ["--sa-toc-top"]: toc.top } : {}), ...(toc.maxh ? { ["--sa-toc-maxh"]: toc.maxh } : {}) };
248
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "sa-article-wrap", style: rootStyle, children: [(0, jsx_runtime_1.jsx)("style", { dangerouslySetInnerHTML: { __html: BODY_CSS + TOC_CSS + (showToc ? safeTocCss(toc.css) : "") } }), (0, jsx_runtime_1.jsxs)("div", { className: showToc ? "sa-article-grid has-toc" : "sa-article-grid", children: [showToc ? ((0, jsx_runtime_1.jsxs)("details", { className: "sa-toc", "data-sa-toc": variant, "data-motion": motion, open: true, children: [(0, jsx_runtime_1.jsxs)("summary", { children: [label, (0, jsx_runtime_1.jsx)("span", { className: "sa-toc-chev", "aria-hidden": "true", children: "\u203A" })] }), (0, jsx_runtime_1.jsx)("div", { className: "sa-toc-body", children: (0, jsx_runtime_1.jsx)("nav", { className: "sa-toc-list", "aria-label": label, children: items.map((it) => ((0, jsx_runtime_1.jsx)("a", { href: `#${it.id}`, "data-toc-link": it.id, "data-level": it.level, children: it.text }, it.id))) }) }), (0, jsx_runtime_1.jsx)(blog_toc_1.SeoBlogTocSpy, { ids: items.map((it) => it.id) })] })) : null, (0, jsx_runtime_1.jsxs)("article", { className: "sa-article", children: [post.cover ? (0, jsx_runtime_1.jsx)("img", { src: post.cover, alt: post.title, style: { width: "100%", aspectRatio: "3 / 2", objectFit: "cover", display: "block", borderRadius: "var(--sa-radius, 12px)", marginBottom: "1.5rem" } }) : null, (0, jsx_runtime_1.jsx)("h1", { style: { fontSize: "2.2rem", lineHeight: 1.2, margin: "0 0 1rem" }, children: post.title }), post.date ? (0, jsx_runtime_1.jsx)("p", { style: { color: "var(--sa-muted, #94a3b8)", margin: "0 0 1.5rem" }, children: fmtDate(post.date, locale) }) : null, (0, jsx_runtime_1.jsx)("div", { className: "seoagent-blog-body", dangerouslySetInnerHTML: { __html: html } })] })] })] }));
241
249
  }
242
250
  function fmtDate(d, locale) {
243
251
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webnumseoagent/next",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Runtime SEO adapter + installer for Next.js App Router sites (SEO Agent platform)",
5
5
  "main": "dist/client.js",
6
6
  "types": "dist/client.d.ts",