@the-smithy/hearth 0.0.0-stage → 0.13.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.
@@ -0,0 +1,338 @@
1
+ import { Collection, CollectionEntry, HearthEvent, Site, PageSummary, Page, HearthEventDetail, RegistrationInput, RegistrationResult, CategoryGroup, SitemapEntry, Fundraiser, FundraiserDetail, DonationInput, DonationCheckout, HearthForm } from '@the-smithy/hearth-schema';
2
+
3
+ type HearthErrorCode = "unauthorized" | "not_found" | "bad_request" | "feature_disabled" | "rate_limited" | "server_error" | "network" | "timeout" | "invalid_response";
4
+ /** Any failure talking to Hearth. Messages never contain the API key. */
5
+ declare class HearthError extends Error {
6
+ readonly status: number;
7
+ readonly code: HearthErrorCode;
8
+ readonly details?: unknown;
9
+ constructor(code: HearthErrorCode, message: string, { status, details, cause }?: {
10
+ status?: number;
11
+ details?: unknown;
12
+ cause?: unknown;
13
+ });
14
+ }
15
+ declare const isHearthError: (error: unknown) => error is HearthError;
16
+
17
+ /** One page of a page collection's entries. */
18
+ type CollectionPage = {
19
+ collection: Collection & {
20
+ kind: "pages";
21
+ };
22
+ total: number;
23
+ entries: CollectionEntry[];
24
+ };
25
+ /** An event collection (e.g. Talks) with its upcoming or past events. */
26
+ type EventCollectionPage = {
27
+ collection: Collection & {
28
+ kind: "events";
29
+ };
30
+ events: HearthEvent[];
31
+ };
32
+
33
+ declare const DEFAULT_BASE_URL = "https://hearth.thesmithy.io";
34
+ /** Next.js's extra fetch options (passed through untouched on other runtimes). */
35
+ type NextFetchOptions = {
36
+ revalidate?: number | false;
37
+ tags?: string[];
38
+ };
39
+ type CallOptions = {
40
+ signal?: AbortSignal;
41
+ cache?: RequestCache;
42
+ next?: NextFetchOptions;
43
+ /**
44
+ * A preview token from Hearth (draft preview links). Page and event reads then return saved drafts, and the
45
+ * request is never cached.
46
+ */
47
+ preview?: string;
48
+ };
49
+ /** What a preview token allows (the path to open first, when the preview ends) and `version`: when the site's
50
+ * content, drafts included, last changed. */
51
+ type PreviewSession = {
52
+ path: string;
53
+ expiresAt: string;
54
+ version: string;
55
+ };
56
+ type RequestContext = {
57
+ resource: string;
58
+ method: string;
59
+ path: string;
60
+ attempt: number;
61
+ };
62
+ type HearthHooks = {
63
+ /** Change or replace the request (headers, tracing). The API key is already set. */
64
+ beforeRequest?(request: Request, ctx: RequestContext): Request | void | Promise<Request | void>;
65
+ /** Inspect or replace the response before it's read. */
66
+ afterResponse?(response: Response, ctx: RequestContext): Response | void | Promise<Response | void>;
67
+ onError?(error: HearthError, ctx: RequestContext): void;
68
+ };
69
+ type HearthClientOptions = {
70
+ /** The site's address in Hearth. */
71
+ site: string;
72
+ /** A Delivery API key (hk_…). Server-side only. */
73
+ apiKey: string;
74
+ baseUrl?: string;
75
+ /** Custom transport: tests, proxies, instrumentation. */
76
+ fetch?: typeof fetch;
77
+ /** Per-attempt timeout. Default 10 s. */
78
+ timeoutMs?: number;
79
+ /** Retries for reads on network errors, 429 and 5xx. Default 2. */
80
+ retries?: number;
81
+ /** Check responses against the content schemas: true throws, "warn" logs. Default false. */
82
+ validate?: boolean | "warn";
83
+ hooks?: HearthHooks;
84
+ /** Allow use in a browser (the key would be exposed). Default false. */
85
+ allowBrowser?: boolean;
86
+ };
87
+ type FormValues = Record<string, string | boolean | number | null | undefined> | FormData;
88
+ type FormResult = {
89
+ ok: true;
90
+ message: string;
91
+ } | {
92
+ ok: false;
93
+ message: string;
94
+ fieldErrors: Record<string, string>;
95
+ };
96
+ type RequestOptions = CallOptions & {
97
+ method?: "GET" | "POST";
98
+ body?: unknown;
99
+ headers?: Record<string, string>;
100
+ /** Name for hooks and errors, e.g. "pages.get". */
101
+ resource?: string;
102
+ };
103
+ /** "home", "about/team", ["about", "team"], "/about/" → "about/team"-style slug; empty means "home". */
104
+ declare function normalizeSlug(slug: string | string[] | undefined | null): string;
105
+ declare function createCore(options: HearthClientOptions): {
106
+ /** The site's address in Hearth. */
107
+ siteSlug: string;
108
+ request: <T>(path: string, init?: RequestOptions) => Promise<T>;
109
+ site: {
110
+ get: (o?: CallOptions) => Promise<Site>;
111
+ };
112
+ pages: {
113
+ list: (o?: CallOptions) => Promise<PageSummary[]>;
114
+ get: (slug?: string | string[] | null, o?: CallOptions) => Promise<Page | null>;
115
+ };
116
+ events: {
117
+ /** `category` is "group/category", e.g. "status/featured". */
118
+ list: (opts?: {
119
+ when?: "upcoming" | "past";
120
+ limit?: number;
121
+ collection?: string;
122
+ category?: string;
123
+ }, o?: CallOptions) => Promise<HearthEvent[]>;
124
+ get: (slug: string, o?: CallOptions) => Promise<HearthEventDetail | null>;
125
+ /**
126
+ * Register for an event with on-site registration (sites with Tickets). Free tickets come back confirmed; paid
127
+ * ones come back pending with a `checkoutUrl` to send the buyer to. Validation problems (including sold out or
128
+ * closed) resolve to { ok: false, fieldErrors }; network and auth failures throw.
129
+ */
130
+ register: (slug: string, input: RegistrationInput, opts?: {
131
+ ip?: string | null;
132
+ signal?: AbortSignal;
133
+ }) => Promise<({
134
+ ok: true;
135
+ } & RegistrationResult) | {
136
+ ok: false;
137
+ message: string;
138
+ fieldErrors: Record<string, string>;
139
+ }>;
140
+ };
141
+ categories: {
142
+ /** The site's category groups, each with its categories. */
143
+ list: (o?: CallOptions) => Promise<CategoryGroup[]>;
144
+ };
145
+ collections: {
146
+ /** The site's collections: page groups (a blog) and event types (Talks). */
147
+ list: (o?: CallOptions) => Promise<Collection[]>;
148
+ /**
149
+ * One collection by address ("blog", or nested "resources/case-studies") with its entries, or null.
150
+ * Page collections take limit/offset/tag; event collections take when/limit.
151
+ */
152
+ get: (slug: string, opts?: {
153
+ limit?: number;
154
+ offset?: number;
155
+ tag?: string;
156
+ category?: string;
157
+ when?: "upcoming" | "past";
158
+ }, o?: CallOptions) => Promise<CollectionPage | EventCollectionPage | null>;
159
+ };
160
+ sitemap: (o?: CallOptions) => Promise<SitemapEntry[]>;
161
+ fundraisers: {
162
+ /** Fundraisers with progress (sites with Giving). `category` is "group/category". */
163
+ list: (opts?: {
164
+ status?: "active" | "completed" | "all";
165
+ category?: string;
166
+ limit?: number;
167
+ }, o?: CallOptions) => Promise<Fundraiser[]>;
168
+ get: (slug: string, o?: CallOptions) => Promise<FundraiserDetail | null>;
169
+ };
170
+ donations: {
171
+ /**
172
+ * Start a donation; send the donor to `checkoutUrl`. Validation problems resolve to { ok: false, fieldErrors };
173
+ * network and auth failures throw. Pass the visitor's IP so Hearth can rate-limit per visitor.
174
+ */
175
+ checkout: (input: DonationInput, opts?: {
176
+ ip?: string | null;
177
+ signal?: AbortSignal;
178
+ }) => Promise<({
179
+ ok: true;
180
+ } & DonationCheckout) | {
181
+ ok: false;
182
+ message: string;
183
+ fieldErrors: Record<string, string>;
184
+ }>;
185
+ };
186
+ preview: {
187
+ /** Check a preview token from a Hearth preview link. Throws (unauthorized) if it's expired or for another site. */
188
+ verify: (token: string, o?: Omit<CallOptions, "preview">) => Promise<PreviewSession>;
189
+ };
190
+ customBlocks: {
191
+ /** The site's own block types (Custom blocks in Hearth): each one's key, name and fields, for rendering `custom` blocks. */
192
+ list: (o?: CallOptions) => Promise<{
193
+ key: string;
194
+ name: string;
195
+ description: string;
196
+ fields: ({
197
+ kind: "text";
198
+ name: string;
199
+ label: string;
200
+ hint?: string | undefined;
201
+ optional?: boolean | undefined;
202
+ } | {
203
+ kind: "textarea";
204
+ name: string;
205
+ label: string;
206
+ hint?: string | undefined;
207
+ optional?: boolean | undefined;
208
+ } | {
209
+ kind: "markdown";
210
+ name: string;
211
+ label: string;
212
+ hint?: string | undefined;
213
+ optional?: boolean | undefined;
214
+ } | {
215
+ kind: "url";
216
+ name: string;
217
+ label: string;
218
+ hint?: string | undefined;
219
+ optional?: boolean | undefined;
220
+ } | {
221
+ kind: "image";
222
+ name: string;
223
+ label: string;
224
+ hint?: string | undefined;
225
+ optional?: boolean | undefined;
226
+ } | {
227
+ kind: "link";
228
+ name: string;
229
+ label: string;
230
+ hint?: string | undefined;
231
+ optional?: boolean | undefined;
232
+ } | {
233
+ kind: "number";
234
+ name: string;
235
+ label: string;
236
+ hint?: string | undefined;
237
+ optional?: boolean | undefined;
238
+ } | {
239
+ kind: "boolean";
240
+ name: string;
241
+ label: string;
242
+ hint?: string | undefined;
243
+ optional?: boolean | undefined;
244
+ } | {
245
+ kind: "select";
246
+ options: {
247
+ value: string;
248
+ label: string;
249
+ }[];
250
+ name: string;
251
+ label: string;
252
+ hint?: string | undefined;
253
+ optional?: boolean | undefined;
254
+ } | {
255
+ kind: "list";
256
+ itemLabel: string;
257
+ fields: ({
258
+ kind: "text";
259
+ name: string;
260
+ label: string;
261
+ hint?: string | undefined;
262
+ optional?: boolean | undefined;
263
+ } | {
264
+ kind: "textarea";
265
+ name: string;
266
+ label: string;
267
+ hint?: string | undefined;
268
+ optional?: boolean | undefined;
269
+ } | {
270
+ kind: "markdown";
271
+ name: string;
272
+ label: string;
273
+ hint?: string | undefined;
274
+ optional?: boolean | undefined;
275
+ } | {
276
+ kind: "url";
277
+ name: string;
278
+ label: string;
279
+ hint?: string | undefined;
280
+ optional?: boolean | undefined;
281
+ } | {
282
+ kind: "image";
283
+ name: string;
284
+ label: string;
285
+ hint?: string | undefined;
286
+ optional?: boolean | undefined;
287
+ } | {
288
+ kind: "link";
289
+ name: string;
290
+ label: string;
291
+ hint?: string | undefined;
292
+ optional?: boolean | undefined;
293
+ } | {
294
+ kind: "number";
295
+ name: string;
296
+ label: string;
297
+ hint?: string | undefined;
298
+ optional?: boolean | undefined;
299
+ } | {
300
+ kind: "boolean";
301
+ name: string;
302
+ label: string;
303
+ hint?: string | undefined;
304
+ optional?: boolean | undefined;
305
+ } | {
306
+ kind: "select";
307
+ options: {
308
+ value: string;
309
+ label: string;
310
+ }[];
311
+ name: string;
312
+ label: string;
313
+ hint?: string | undefined;
314
+ optional?: boolean | undefined;
315
+ })[];
316
+ name: string;
317
+ label: string;
318
+ hint?: string | undefined;
319
+ optional?: boolean | undefined;
320
+ })[];
321
+ }[]>;
322
+ };
323
+ forms: {
324
+ /** One of the site's forms, to render anywhere (a footer, a modal); null if there's no form with that key. */
325
+ get: (formKey: string, o?: CallOptions) => Promise<HearthForm | null>;
326
+ /**
327
+ * Store a form submission. Validation problems resolve to { ok: false, fieldErrors };
328
+ * network and auth failures throw. Pass the visitor's IP so Hearth can rate-limit per visitor.
329
+ */
330
+ submit: (formKey: string, values: FormValues, opts?: {
331
+ ip?: string | null;
332
+ signal?: AbortSignal;
333
+ }) => Promise<FormResult>;
334
+ };
335
+ };
336
+ type HearthCore = ReturnType<typeof createCore>;
337
+
338
+ export { type CallOptions as C, DEFAULT_BASE_URL as D, type EventCollectionPage as E, type FormResult as F, type HearthCore as H, type NextFetchOptions as N, type PreviewSession as P, type RequestContext as R, type HearthClientOptions as a, type CollectionPage as b, type FormValues as c, HearthError as d, type HearthErrorCode as e, type HearthHooks as f, type RequestOptions as g, isHearthError as i, normalizeSlug as n };
@@ -0,0 +1,24 @@
1
+ import { H as HearthCore, a as HearthClientOptions } from './client-DCiaDdvu.js';
2
+ export { C as CallOptions, b as CollectionPage, D as DEFAULT_BASE_URL, E as EventCollectionPage, F as FormResult, c as FormValues, d as HearthError, e as HearthErrorCode, f as HearthHooks, N as NextFetchOptions, P as PreviewSession, R as RequestContext, g as RequestOptions, i as isHearthError, n as normalizeSlug } from './client-DCiaDdvu.js';
3
+ export { Block, BlockOf, CategoryGroup, CategoryRef, Collection, CollectionEntry, CollectionRef, DonationCheckout, DonationInput, EntryDetails, EventCustomFields, EventRegistration, EventTicket, Fundraiser, FundraiserDetail, HearthEvent, HearthEventDetail, KnownBlock, Page, PageMeta, PageSummary, RegistrationInput, RegistrationResult, ResolvedBlock, Site, SiteSettings, SitemapEntry, UnknownBlock, WebhookPayload, videoEmbedUrl } from '@the-smithy/hearth-schema';
4
+
5
+ /** A plugin adds resources (and can use the core's `request`) under its own names. */
6
+ type HearthPlugin<T extends object = object> = {
7
+ setup(client: HearthCore): T;
8
+ };
9
+ /** Define a plugin with typed resources, e.g. `definePlugin((c) => ({ products: { list: () => c.request("/products") } }))`. */
10
+ declare function definePlugin<T extends object>(setup: (client: HearthCore) => T): HearthPlugin<T>;
11
+ type UnionToIntersection<U> = (U extends unknown ? (x: U) => void : never) extends (x: infer I) => void ? I : never;
12
+ type PluginResources<P extends readonly HearthPlugin[]> = P extends readonly [] ? unknown : UnionToIntersection<P[number] extends HearthPlugin<infer T> ? T : never>;
13
+ type HearthClient<P extends readonly HearthPlugin[] = []> = HearthCore & PluginResources<P>;
14
+ /**
15
+ * Create a Hearth client for one site. Server-side only: the API key is secret.
16
+ *
17
+ * const hearth = createHearthClient({ site: process.env.HEARTH_SITE!, apiKey: process.env.HEARTH_API_KEY! });
18
+ * const page = await hearth.pages.get("about");
19
+ */
20
+ declare function createHearthClient<const P extends readonly HearthPlugin[] = []>(options: HearthClientOptions & {
21
+ plugins?: P;
22
+ }): HearthClient<P>;
23
+
24
+ export { type HearthClient, HearthClientOptions, type HearthPlugin, createHearthClient, definePlugin };
package/dist/index.js ADDED
@@ -0,0 +1,32 @@
1
+ import {
2
+ DEFAULT_BASE_URL,
3
+ HearthError,
4
+ createCore,
5
+ isHearthError,
6
+ normalizeSlug
7
+ } from "./chunk-ZK7X4FDQ.js";
8
+
9
+ // src/index.ts
10
+ import { videoEmbedUrl } from "@the-smithy/hearth-schema";
11
+ function definePlugin(setup) {
12
+ return { setup };
13
+ }
14
+ function createHearthClient(options) {
15
+ const core = createCore(options);
16
+ const extras = (options.plugins ?? []).map((p) => p.setup(core));
17
+ for (const extra of extras) {
18
+ for (const key of Object.keys(extra)) {
19
+ if (key in core) throw new Error(`Hearth: plugin resource "${key}" would replace a built-in one.`);
20
+ }
21
+ }
22
+ return Object.assign(core, ...extras);
23
+ }
24
+ export {
25
+ DEFAULT_BASE_URL,
26
+ HearthError,
27
+ createHearthClient,
28
+ definePlugin,
29
+ isHearthError,
30
+ normalizeSlug,
31
+ videoEmbedUrl
32
+ };
package/dist/next.d.ts ADDED
@@ -0,0 +1,235 @@
1
+ import { H as HearthCore, b as CollectionPage, E as EventCollectionPage, F as FormResult, c as FormValues } from './client-DCiaDdvu.js';
2
+ import * as _the_smithy_hearth_schema from '@the-smithy/hearth-schema';
3
+ import { PageMeta } from '@the-smithy/hearth-schema';
4
+ import { Metadata, MetadataRoute } from 'next';
5
+
6
+ /** Holds the preview token while Next.js draft mode is on. */
7
+ declare const PREVIEW_COOKIE = "hearth-preview";
8
+ /** Next.js metadata from a page's or event's `meta`. */
9
+ declare function metadataFromMeta(meta: PageMeta): Metadata;
10
+ type HearthNextOptions = {
11
+ /** Base cache tag; every request is tagged with it (default "hearth"). */
12
+ tag?: string;
13
+ /**
14
+ * Longest time (seconds) content stays cached if a publish webhook is missed. Publishing
15
+ * refreshes the cache straight away through the webhook. Default 3600; false caches until then.
16
+ */
17
+ revalidate?: number | false;
18
+ };
19
+ /**
20
+ * Next.js helpers bound to a client: tagged reads (so publish webhooks refresh exactly
21
+ * what changed), metadata, sitemap, the revalidation route, and form submission.
22
+ */
23
+ declare function createHearthNext(client: HearthCore, { tag, revalidate }?: HearthNextOptions): {
24
+ getSite: () => Promise<_the_smithy_hearth_schema.Site>;
25
+ getPages: () => Promise<_the_smithy_hearth_schema.PageSummary[]>;
26
+ getPage: (slug?: string | string[] | null) => Promise<_the_smithy_hearth_schema.Page | null>;
27
+ getEvents: (opts?: {
28
+ when?: "upcoming" | "past";
29
+ limit?: number;
30
+ collection?: string;
31
+ category?: string;
32
+ }) => Promise<_the_smithy_hearth_schema.HearthEvent[]>;
33
+ getCategories: () => Promise<_the_smithy_hearth_schema.CategoryGroup[]>;
34
+ getCustomBlocks: () => Promise<{
35
+ key: string;
36
+ name: string;
37
+ description: string;
38
+ fields: ({
39
+ kind: "text";
40
+ name: string;
41
+ label: string;
42
+ hint?: string | undefined;
43
+ optional?: boolean | undefined;
44
+ } | {
45
+ kind: "textarea";
46
+ name: string;
47
+ label: string;
48
+ hint?: string | undefined;
49
+ optional?: boolean | undefined;
50
+ } | {
51
+ kind: "markdown";
52
+ name: string;
53
+ label: string;
54
+ hint?: string | undefined;
55
+ optional?: boolean | undefined;
56
+ } | {
57
+ kind: "url";
58
+ name: string;
59
+ label: string;
60
+ hint?: string | undefined;
61
+ optional?: boolean | undefined;
62
+ } | {
63
+ kind: "image";
64
+ name: string;
65
+ label: string;
66
+ hint?: string | undefined;
67
+ optional?: boolean | undefined;
68
+ } | {
69
+ kind: "link";
70
+ name: string;
71
+ label: string;
72
+ hint?: string | undefined;
73
+ optional?: boolean | undefined;
74
+ } | {
75
+ kind: "number";
76
+ name: string;
77
+ label: string;
78
+ hint?: string | undefined;
79
+ optional?: boolean | undefined;
80
+ } | {
81
+ kind: "boolean";
82
+ name: string;
83
+ label: string;
84
+ hint?: string | undefined;
85
+ optional?: boolean | undefined;
86
+ } | {
87
+ kind: "select";
88
+ options: {
89
+ value: string;
90
+ label: string;
91
+ }[];
92
+ name: string;
93
+ label: string;
94
+ hint?: string | undefined;
95
+ optional?: boolean | undefined;
96
+ } | {
97
+ kind: "list";
98
+ itemLabel: string;
99
+ fields: ({
100
+ kind: "text";
101
+ name: string;
102
+ label: string;
103
+ hint?: string | undefined;
104
+ optional?: boolean | undefined;
105
+ } | {
106
+ kind: "textarea";
107
+ name: string;
108
+ label: string;
109
+ hint?: string | undefined;
110
+ optional?: boolean | undefined;
111
+ } | {
112
+ kind: "markdown";
113
+ name: string;
114
+ label: string;
115
+ hint?: string | undefined;
116
+ optional?: boolean | undefined;
117
+ } | {
118
+ kind: "url";
119
+ name: string;
120
+ label: string;
121
+ hint?: string | undefined;
122
+ optional?: boolean | undefined;
123
+ } | {
124
+ kind: "image";
125
+ name: string;
126
+ label: string;
127
+ hint?: string | undefined;
128
+ optional?: boolean | undefined;
129
+ } | {
130
+ kind: "link";
131
+ name: string;
132
+ label: string;
133
+ hint?: string | undefined;
134
+ optional?: boolean | undefined;
135
+ } | {
136
+ kind: "number";
137
+ name: string;
138
+ label: string;
139
+ hint?: string | undefined;
140
+ optional?: boolean | undefined;
141
+ } | {
142
+ kind: "boolean";
143
+ name: string;
144
+ label: string;
145
+ hint?: string | undefined;
146
+ optional?: boolean | undefined;
147
+ } | {
148
+ kind: "select";
149
+ options: {
150
+ value: string;
151
+ label: string;
152
+ }[];
153
+ name: string;
154
+ label: string;
155
+ hint?: string | undefined;
156
+ optional?: boolean | undefined;
157
+ })[];
158
+ name: string;
159
+ label: string;
160
+ hint?: string | undefined;
161
+ optional?: boolean | undefined;
162
+ })[];
163
+ }[]>;
164
+ getCollections: () => Promise<_the_smithy_hearth_schema.Collection[]>;
165
+ getCollection: (slug: string, opts?: {
166
+ limit?: number;
167
+ offset?: number;
168
+ tag?: string;
169
+ category?: string;
170
+ when?: "upcoming" | "past";
171
+ }) => Promise<CollectionPage | EventCollectionPage | null>;
172
+ getEvent: (slug: string) => Promise<_the_smithy_hearth_schema.HearthEventDetail | null>;
173
+ /** Fundraisers with progress (sites with Giving). Refreshed after every donation. */
174
+ getFundraisers: (opts?: {
175
+ status?: "active" | "completed" | "all";
176
+ category?: string;
177
+ limit?: number;
178
+ }) => Promise<_the_smithy_hearth_schema.Fundraiser[]>;
179
+ getFundraiser: (slug: string) => Promise<_the_smithy_hearth_schema.FundraiserDetail | null>;
180
+ /**
181
+ * A donation form's server action, shaped for `useActionState(action, null)`. Export it from a "use server" file:
182
+ * export const donate = async (prev: FormResult | null, fd: FormData) => donateAction()(prev, fd);
183
+ * Fields: `amount` (dollars, or "custom" with `customAmount`), `fundraiser`, `name`, `email`, `anonymous`,
184
+ * `message`. On success it redirects the donor to the payment page; afterwards they return to `returnPath`.
185
+ */
186
+ donateAction: ({ returnPath }?: {
187
+ returnPath?: string;
188
+ }) => (_prev: FormResult | null, formData: FormData) => Promise<FormResult>;
189
+ /**
190
+ * An event registration form's server action (sites with Tickets), for `useActionState(action, null)`:
191
+ * export const register = async (slug: string, prev: FormResult | null, fd: FormData) => registerAction(slug)(prev, fd);
192
+ * Fields: `ticket`, `name`, `email`, `phone`, `teamName`, `notes`, and one `attendee` per name. A free ticket
193
+ * resolves to { ok: true, message }; a paid one redirects to the payment page, which returns to `returnPath`.
194
+ */
195
+ registerAction: (slug: string, { returnPath }?: {
196
+ returnPath?: string;
197
+ }) => (_prev: FormResult | null, formData: FormData) => Promise<FormResult>;
198
+ /** Whether this request is a draft preview (to show a "Preview" banner with an exit link). */
199
+ isPreview: () => Promise<boolean>;
200
+ /**
201
+ * GET handler for the site's preview route (app/api/preview/route.ts):
202
+ * export const GET = hearthNext.previewHandler();
203
+ * Hearth's "Preview on the website" button opens it with a token; it checks the token with Hearth, turns on
204
+ * draft mode and opens the page. Page and event reads then return saved drafts until the preview ends.
205
+ * Hearth's side-by-side preview adds `embed=1`, which makes the cookies work inside its editor's frame.
206
+ */
207
+ previewHandler(): (request: Request) => Promise<Response>;
208
+ /** GET handler that ends a preview (app/api/preview/exit/route.ts); `?path=` says where to go next. */
209
+ exitPreviewHandler(): (request: Request) => Promise<never>;
210
+ /** For `generateMetadata`: the page's title, description, canonical, robots and share tags ({} when not found). */
211
+ generatePageMetadata(slug?: string | string[] | null): Promise<Metadata>;
212
+ /** `export default sitemap` from app/sitemap.ts. */
213
+ sitemap(): Promise<MetadataRoute.Sitemap>;
214
+ /**
215
+ * POST handler for the site's revalidation webhook (app/api/revalidate/route.ts):
216
+ * export const POST = hearthNext.revalidateHandler();
217
+ * Verifies the signature with HEARTH_WEBHOOK_SECRET and expires the matching tags.
218
+ */
219
+ revalidateHandler({ secret }?: {
220
+ secret?: string;
221
+ }): (request: Request) => Promise<Response>;
222
+ /**
223
+ * Submit a form from your own server action, forwarding the visitor's IP:
224
+ * "use server";
225
+ * export async function contact(_: unknown, formData: FormData) { return hearthNext.submitForm("contact", formData); }
226
+ */
227
+ submitForm: (formKey: string, values: FormValues) => Promise<FormResult>;
228
+ /**
229
+ * The same, shaped for `useActionState(action, null)`. Export it from a "use server" file:
230
+ * export const contact = async (prev: FormResult | null, fd: FormData) => submitFormAction("contact")(prev, fd);
231
+ */
232
+ submitFormAction: (formKey: string) => (_prev: FormResult | null, formData: FormData) => Promise<FormResult>;
233
+ };
234
+
235
+ export { type HearthNextOptions, PREVIEW_COOKIE, createHearthNext, metadataFromMeta };