@the-smithy/hearth 0.24.1 → 0.26.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/README.md +5 -0
- package/dist/next.d.ts +7 -2
- package/dist/next.js +6 -5
- package/dist/testing.js +2 -1
- package/llms.md +7 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -52,6 +52,11 @@ curl -H "Authorization: Bearer $HEARTH_API_KEY" https://hearth.thesmithy.io/admi
|
|
|
52
52
|
|
|
53
53
|
Keep `hearth-api.md` out of git, and the key out of chat: the agent only needs it in `.env.local`.
|
|
54
54
|
|
|
55
|
+
## Hosting
|
|
56
|
+
|
|
57
|
+
Netlify and Vercel both work with no host-specific code. Sites made from the starter have a guide to each in
|
|
58
|
+
`HOSTING.md`, and `llms.md` has the short version.
|
|
59
|
+
|
|
55
60
|
## Documentation
|
|
56
61
|
|
|
57
62
|
Once you have developer access, the full documentation (every method, Next.js helpers, rendering blocks,
|
package/dist/next.d.ts
CHANGED
|
@@ -5,6 +5,11 @@ import { Metadata, MetadataRoute } from 'next';
|
|
|
5
5
|
|
|
6
6
|
/** Holds the preview token while Next.js draft mode is on. */
|
|
7
7
|
declare const PREVIEW_COOKIE = "hearth-preview";
|
|
8
|
+
/**
|
|
9
|
+
* The visitor's IP. Netlify's own header only counts on Netlify, whose functions always have SITE_ID: anywhere else a
|
|
10
|
+
* visitor could send it themselves to get round the rate limits. Vercel overwrites x-forwarded-for, so it's safe there.
|
|
11
|
+
*/
|
|
12
|
+
declare const clientIp: (h: Headers) => string | null;
|
|
8
13
|
/**
|
|
9
14
|
* Whether this deploy is a preview or branch deploy (Netlify's CONTEXT, Vercel's VERCEL_ENV), which search engines
|
|
10
15
|
* shouldn't index: only the production deploy is the real site.
|
|
@@ -254,7 +259,7 @@ declare function createHearthNext(client: HearthCore, { tag, revalidate }?: Hear
|
|
|
254
259
|
sitemap(): Promise<MetadataRoute.Sitemap>;
|
|
255
260
|
/**
|
|
256
261
|
* Hearth's sitemap plus pages the site's own code serves (an events calendar, a donate page), skipping any
|
|
257
|
-
* Hearth already lists:
|
|
262
|
+
* Hearth already lists and any that a page in Hearth at that address hides from search engines:
|
|
258
263
|
* export default hearthNext.sitemapWith(["/events", "/fundraisers"]);
|
|
259
264
|
*/
|
|
260
265
|
sitemapWith(paths: string[]): () => Promise<MetadataRoute.Sitemap>;
|
|
@@ -285,4 +290,4 @@ declare function createHearthNext(client: HearthCore, { tag, revalidate }?: Hear
|
|
|
285
290
|
submitFormAction: (formKey: string) => (_prev: FormResult | null, formData: FormData) => Promise<FormResult>;
|
|
286
291
|
};
|
|
287
292
|
|
|
288
|
-
export { type HearthNextOptions, PREVIEW_COOKIE, createHearthNext, isNonProductionDeploy, metadataFromMeta, siteBaseUrl, siteLang };
|
|
293
|
+
export { type HearthNextOptions, PREVIEW_COOKIE, clientIp, createHearthNext, isNonProductionDeploy, metadataFromMeta, siteBaseUrl, siteLang };
|
package/dist/next.js
CHANGED
|
@@ -18,7 +18,7 @@ async function previewToken() {
|
|
|
18
18
|
if (!(await draftMode()).isEnabled) return void 0;
|
|
19
19
|
return (await cookies()).get(PREVIEW_COOKIE)?.value;
|
|
20
20
|
}
|
|
21
|
-
var clientIp = (h) => h.get("x-nf-client-connection-ip") ?? h.get("x-forwarded-for")?.split(",")[0]?.trim() ?? h.get("x-real-ip");
|
|
21
|
+
var clientIp = (h) => (process.env.SITE_ID ? h.get("x-nf-client-connection-ip") : null) ?? h.get("x-forwarded-for")?.split(",")[0]?.trim() ?? h.get("x-real-ip");
|
|
22
22
|
var safePath = (path) => path && path.startsWith("/") && !path.startsWith("//") ? path : "/";
|
|
23
23
|
var isNonProductionDeploy = () => {
|
|
24
24
|
const netlify = process.env.CONTEXT;
|
|
@@ -276,15 +276,15 @@ function createHearthNext(client, { tag = "hearth", revalidate = 3600 } = {}) {
|
|
|
276
276
|
},
|
|
277
277
|
/**
|
|
278
278
|
* Hearth's sitemap plus pages the site's own code serves (an events calendar, a donate page), skipping any
|
|
279
|
-
* Hearth already lists:
|
|
279
|
+
* Hearth already lists and any that a page in Hearth at that address hides from search engines:
|
|
280
280
|
* export default hearthNext.sitemapWith(["/events", "/fundraisers"]);
|
|
281
281
|
*/
|
|
282
282
|
sitemapWith(paths) {
|
|
283
283
|
return async () => {
|
|
284
|
-
const [entries, site] = await Promise.all([client.sitemap(tags(`${tag}:pages`, `${tag}:events`)), client.site.get(tags(`${tag}:site`))]);
|
|
284
|
+
const [entries, site, pages] = await Promise.all([client.sitemap(tags(`${tag}:pages`, `${tag}:events`)), client.site.get(tags(`${tag}:site`)), client.pages.list(tags(`${tag}:pages`))]);
|
|
285
285
|
const base = siteBaseUrl(site) ?? "";
|
|
286
|
-
const
|
|
287
|
-
const extra = site.settings.seo.noIndex ? [] : paths.filter((p) => !
|
|
286
|
+
const skip = /* @__PURE__ */ new Set([...entries.map((e) => e.path), ...pages.filter((p) => p.noIndex).map((p) => p.path)]);
|
|
287
|
+
const extra = site.settings.seo.noIndex ? [] : paths.filter((p) => !skip.has(p)).map((p) => ({ url: `${base}${p}`, priority: 0.6 }));
|
|
288
288
|
return [...entries.map((e) => ({ url: e.url, ...e.lastModified ? { lastModified: e.lastModified } : {}, priority: e.priority })), ...extra];
|
|
289
289
|
};
|
|
290
290
|
},
|
|
@@ -332,6 +332,7 @@ function createHearthNext(client, { tag = "hearth", revalidate = 3600 } = {}) {
|
|
|
332
332
|
}
|
|
333
333
|
export {
|
|
334
334
|
PREVIEW_COOKIE,
|
|
335
|
+
clientIp,
|
|
335
336
|
createHearthNext,
|
|
336
337
|
isNonProductionDeploy,
|
|
337
338
|
metadataFromMeta,
|
package/dist/testing.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/testing.ts
|
|
2
|
+
import { isUnlistedPage } from "@the-smithy/hearth-schema";
|
|
2
3
|
var json = (body, status = 200) => new Response(JSON.stringify(body), { status, headers: { "Content-Type": "application/json" } });
|
|
3
4
|
var notFound = () => json({ error: { code: "not_found", message: "Not found" } }, 404);
|
|
4
5
|
function createMockHearth(data = {}) {
|
|
@@ -30,7 +31,7 @@ function createMockHearth(data = {}) {
|
|
|
30
31
|
return result.ok ? json({ data: { message: result.message } }, 201) : json({ error: { code: "bad_request", message: result.message, details: result.fieldErrors } }, 400);
|
|
31
32
|
}
|
|
32
33
|
if (rest === "") return json({ data: { slug, name: slug, domain: null, features: [], settings: {}, ...data.site } });
|
|
33
|
-
if (rest === "/pages") return json({ data: (data.pages ?? []).map(({ slug: slug2, path, title, seo, publishedAt }) => ({ slug: slug2, path, title, seo, noIndex:
|
|
34
|
+
if (rest === "/pages") return json({ data: (data.pages ?? []).map(({ slug: slug2, path, title, seo, publishedAt }) => ({ slug: slug2, path, title, seo, noIndex: Boolean(seo?.noIndex) || isUnlistedPage(slug2), publishedAt })) });
|
|
34
35
|
if (rest.startsWith("/pages/")) {
|
|
35
36
|
const pool = req.headers.get("x-hearth-preview") ? [...data.draftPages ?? [], ...data.pages ?? []] : data.pages ?? [];
|
|
36
37
|
const page = pool.find((p) => p.slug === decodeURIComponent(rest.slice(7)));
|
package/llms.md
CHANGED
|
@@ -6,7 +6,7 @@ client components: the API key is secret.
|
|
|
6
6
|
## Setup
|
|
7
7
|
- Sites made with `pnpm create @the-smithy/hearth-site` already have all of this, and every block, page and form,
|
|
8
8
|
in `src/hearth/` (the client is `@/hearth/client`). Don't rebuild them: style the site in `src/theme/` (tokens,
|
|
9
|
-
and Tailwind classes per slot; `src/hearth/theme/defaults.ts` lists the slots) and read the site's `
|
|
9
|
+
and Tailwind classes per slot; `src/hearth/theme/defaults.ts` lists the slots) and read the site's `AGENTS.md`.
|
|
10
10
|
`pnpm hearth:update` brings in new releases. The rest of this section is for other Next.js apps.
|
|
11
11
|
- `pnpm add @the-smithy/hearth` (public on npm; no registry config or token needed). It's useless without a
|
|
12
12
|
Hearth site's API key. The full guide is in Hearth under API docs (Markdown download).
|
|
@@ -62,6 +62,7 @@ client components: the API key is secret.
|
|
|
62
62
|
- `PageMeta`: `fullTitle`, `title`, `description`, `canonical`, `robots { index, follow }`,
|
|
63
63
|
`openGraph`, `twitter`, `image { url, width, height, alt }`, `jsonLd[]`.
|
|
64
64
|
- Each block is `{ id, type, data }`; fields live on `data`. Narrow by `type`; use `BlockOf<"hero">` for one type.
|
|
65
|
+
- Any block may have `anchor` (beside `type`): make it the `id` of its outermost element, so `/#anchor` links reach it.
|
|
65
66
|
- Unknown future types arrive as `UnknownBlock`. Always handle a fallback.
|
|
66
67
|
- Images are `ImageRef = { src, alt, width?, height?, focal?: { x, y } }`. `focal` is the spot to keep in view when the
|
|
67
68
|
image is cropped (percentages across and down, set in Hearth's media library). For an image with `object-fit: cover`,
|
|
@@ -113,6 +114,11 @@ client components: the API key is secret.
|
|
|
113
114
|
how-to guides (a "guides" collection) read inside The Smithy's products. Same blocks and structure everywhere;
|
|
114
115
|
each product passes its own class names (`GuideTheme`) and Markdown renderer. No CSS ships with it.
|
|
115
116
|
|
|
117
|
+
## Hosting
|
|
118
|
+
Netlify and Vercel both work with no host-specific code. Set `HEARTH_SITE` and `HEARTH_API_KEY` at the host before the
|
|
119
|
+
first build, since it reads Hearth. Point the publish webhook at `https://<primary domain>/api/revalidate` and set
|
|
120
|
+
`HEARTH_WEBHOOK_SECRET`, then deploy again. Sites from the starter have the full guide in `HOSTING.md`.
|
|
121
|
+
|
|
116
122
|
## Other entry points
|
|
117
123
|
- `@the-smithy/hearth/webhooks`: `verifyWebhook(raw, header, secret)`, `parseWebhook(request, secret)`,
|
|
118
124
|
`tagsForWebhook(payload)`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@the-smithy/hearth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "Typed client for the Hearth Delivery API: content, SEO, forms and publish webhooks.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"llms.md"
|
|
50
50
|
],
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@the-smithy/hearth-schema": "^0.
|
|
52
|
+
"@the-smithy/hearth-schema": "^0.26.0"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"next": ">=15",
|