@soloworks/smking-next 0.19.0 → 0.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # @soloworks/smking-next
2
2
 
3
+ ## 0.20.1 — 2026-06-03
4
+
5
+ **Chore: removed dead carousel / nav-recent-posts / nav-search block types.**
6
+
7
+ Dropped `NavRecentPostsProps`, `NavSearchIndexEntry`, `NavSearchProps`,
8
+ `CarouselSlideProps`, `CarouselAspectRatio`, and `CarouselProps` from
9
+ `types.ts`. Narrowed the `Block` union to the three active block components
10
+ (`hero`, `article`, `nav-taxonomy-list`). `NavLayout` (layout enum including
11
+ `"carousel"`) is unchanged — that value controls nav rendering style, not a
12
+ separate block type.
13
+
14
+ ## 0.20.0 — 2026-06-02
15
+
16
+ **`<SmkingCms>` now emits the structured-data engine's JSON-LD `@graph` inline.**
17
+
18
+ CMS pages get a full multi-entity `@graph` (BlogPosting / Organization /
19
+ WebSite / BreadcrumbList / FAQPage, `@id`-linked) generated by the smking
20
+ structured-data engine and served via `/api/v1/public/page`. `<SmkingCms>`
21
+ inlines it as `<script type="application/ld+json">` — JSON-LD is valid in
22
+ `<body>`, so no head hoisting needed (unlike `<title>`/`<meta>`, which
23
+ React 19 still hoists for you). The `safeJson` escaper (`</` + U+2028/U+2029)
24
+ is extracted into a shared `lib/safe-json.ts` that `<SmkingAEO>` imports too.
25
+
26
+ No customer code change — `<SmkingCms>` picks up the new `jsonLd` field
27
+ automatically once a page is republished under the engine. Bump your
28
+ constraint to `^0.20`.
29
+
3
30
  ## 0.19.0 — 2026-05-29
4
31
 
5
32
  **CMS base path reported via heartbeat — dashboard "View page" resolves real URLs without per-page visits.**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soloworks/smking-next",
3
- "version": "0.19.0",
3
+ "version": "0.20.1",
4
4
  "description": "AI-native SEO (AEO) for Next.js — auto-inject JSON-LD, FAQ, AI summary, and SEO metadata so AI crawlers (ChatGPT, Perplexity, Google AI) can cite your pages.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/sillyleo/smking/tree/main/packages/smking-next",
@@ -1,5 +1,6 @@
1
1
  import type { DiscoverParams } from "../types";
2
2
  import { getAeoContent } from "../lib/client";
3
+ import { safeJson } from "../lib/safe-json";
3
4
 
4
5
  const SR_ONLY_STYLE: React.CSSProperties = {
5
6
  position: "absolute",
@@ -118,17 +119,3 @@ export async function SmkingAEO(props: SmkingAEOProps) {
118
119
  </>
119
120
  );
120
121
  }
121
-
122
- /**
123
- * Escape JSON for safe `<script>` embedding. Covers the three values
124
- * that can break out:
125
- * - `</` (any `</script>`-like sequence)
126
- * - U+2028 / U+2029 (treated as line terminators inside a JS string
127
- * literal, which would corrupt the embedded JSON)
128
- */
129
- function safeJson(value: Record<string, unknown>): string {
130
- return JSON.stringify(value)
131
- .replace(/<\//g, "<\\/")
132
- .replace(/\u2028/g, "\\u2028")
133
- .replace(/\u2029/g, "\\u2029");
134
- }
@@ -1,4 +1,5 @@
1
1
  import { getCmsPage } from "../lib/cms-client";
2
+ import { safeJson } from "../lib/safe-json";
2
3
  import type { CmsParams } from "../types";
3
4
 
4
5
  /**
@@ -72,6 +73,17 @@ export async function SmkingCms(props: CmsParams) {
72
73
  <link rel="canonical" href={seo.canonicalUrl} data-smking="cms" />
73
74
  )}
74
75
 
76
+ {/* Engine-precomputed @graph. JSON-LD is valid in <body>, so no
77
+ head hoisting needed (unlike title/meta above). */}
78
+ {data.page.jsonLd && (
79
+ <script
80
+ type="application/ld+json"
81
+ data-smking="cms"
82
+ // eslint-disable-next-line react/no-danger -- escaped via safeJson; engine output is schema-bounded
83
+ dangerouslySetInnerHTML={{ __html: safeJson(data.page.jsonLd) }}
84
+ />
85
+ )}
86
+
75
87
  {/* Raw passthrough — bodyHtml is SaaS-emitted Plate output (Tailwind
76
88
  utility + slate-* hooks + data-slate-* attrs all intact). No
77
89
  article shell, no canonical CSS injection: what the dashboard
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Escape an object for safe `<script type="application/ld+json">`
3
+ * embedding. Covers the sequences that can break out of / corrupt the
4
+ * script:
5
+ * - `</` (any `</script>`-like sequence)
6
+ * - U+2028 / U+2029 (JS string-literal line terminators)
7
+ *
8
+ * The U+2028 / U+2029 patterns are built via `new RegExp("\\u2028", ...)`
9
+ * (escaped-backslash strings) so this source file stays pure ASCII — no
10
+ * invisible line-separator characters to corrupt on edit.
11
+ *
12
+ * Shared by `<SmkingAEO>` and `<SmkingCms>`. Engine output is
13
+ * schema-bounded, but this guard is mandatory defence-in-depth — never
14
+ * inline JSON-LD without it.
15
+ */
16
+ export function safeJson(value: Record<string, unknown>): string {
17
+ return JSON.stringify(value)
18
+ .replace(/<\//g, "<\\/")
19
+ .replace(new RegExp("\\u2028", "g"), "\\u2028")
20
+ .replace(new RegExp("\\u2029", "g"), "\\u2029");
21
+ }
package/src/types.ts CHANGED
@@ -102,13 +102,6 @@ export interface NavSnapshotEntry {
102
102
  contentType: "article" | "landing" | "listing" | null;
103
103
  }
104
104
 
105
- export interface NavRecentPostsProps extends ModuleHeader {
106
- limit: number;
107
- layout: NavLayout;
108
- contentType?: "article" | "all";
109
- /** Publish-time materialized — never fetched live. */
110
- snapshot?: NavSnapshotEntry[];
111
- }
112
105
  export interface NavTaxonomyListProps extends ModuleHeader {
113
106
  /** category-by-path: slug prefix; tag: taxonomies.slug */
114
107
  source: "category-by-path" | "tag";
@@ -119,56 +112,10 @@ export interface NavTaxonomyListProps extends ModuleHeader {
119
112
  snapshot?: NavSnapshotEntry[];
120
113
  }
121
114
 
122
- /**
123
- * Search index entry. Customer SDK does client-side fuzzy filter
124
- * against this list; clicking a result navigates to the slug.
125
- */
126
- export interface NavSearchIndexEntry {
127
- slug: string;
128
- title: string | null;
129
- excerpt: string | null;
130
- }
131
-
132
- export interface NavSearchProps {
133
- placeholder: string;
134
- contentType?: "article" | "all";
135
- /** Publish-time materialized full-site search index. */
136
- index?: NavSearchIndexEntry[];
137
- }
138
-
139
- export interface CarouselSlideProps {
140
- imageUrl: string;
141
- caption: string;
142
- }
143
-
144
- export type CarouselAspectRatio =
145
- | "16:9"
146
- | "4:3"
147
- | "1:1"
148
- | "3:4"
149
- | "9:16";
150
-
151
- export interface CarouselProps {
152
- slides: CarouselSlideProps[];
153
- /** Fixed aspect ratio for all slides — image fills via `object-fit: cover`. Default `16:9`. */
154
- aspectRatio?: CarouselAspectRatio;
155
- }
156
-
157
115
  export type Block =
158
116
  | { component: "hero"; id: string; props: HeroProps }
159
117
  | { component: "article"; id: string; props: ArticleProps }
160
- | { component: "carousel"; id: string; props: CarouselProps }
161
- | {
162
- component: "nav-recent-posts";
163
- id: string;
164
- props: NavRecentPostsProps;
165
- }
166
- | {
167
- component: "nav-taxonomy-list";
168
- id: string;
169
- props: NavTaxonomyListProps;
170
- }
171
- | { component: "nav-search"; id: string; props: NavSearchProps };
118
+ | { component: "nav-taxonomy-list"; id: string; props: NavTaxonomyListProps };
172
119
 
173
120
  /**
174
121
  * A single published CMS page returned by the smking public API
@@ -191,6 +138,12 @@ export interface CmsPage {
191
138
  excerpt?: string | null;
192
139
  featuredImageUrl?: string | null;
193
140
  publishedAt: string | null;
141
+ /**
142
+ * v0.M1+ engine-precomputed schema.org @graph. `<SmkingCms>` inlines it
143
+ * as `<script type="application/ld+json">`. Null until the page is
144
+ * republished under the structured-data engine.
145
+ */
146
+ jsonLd?: Record<string, unknown> | null;
194
147
  }
195
148
 
196
149
  /**