@the-smithy/hearth 0.18.0 → 0.20.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/dist/{chunk-62OMCVBE.js → chunk-V47RFBJE.js} +22 -0
- package/dist/{client-B3n7p9lK.d.ts → client-IImehdSM.d.ts} +16 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +6 -1
- package/dist/next.d.ts +10 -2
- package/dist/next.js +30 -2
- package/llms.md +16 -0
- package/package.json +2 -2
|
@@ -196,6 +196,28 @@ function createCore(options) {
|
|
|
196
196
|
}
|
|
197
197
|
throw err;
|
|
198
198
|
}
|
|
199
|
+
},
|
|
200
|
+
/**
|
|
201
|
+
* Sign up to volunteer at an event that asks for volunteers (its `volunteering` is set). Post `shifts` when
|
|
202
|
+
* `volunteering.pickShifts` isn't "none", and each answer under its field's `name`. Validation problems
|
|
203
|
+
* (including a full shift or closed sign-up) resolve to { ok: false, fieldErrors }; network and auth failures throw.
|
|
204
|
+
*/
|
|
205
|
+
volunteer: async (slug, input, opts = {}) => {
|
|
206
|
+
try {
|
|
207
|
+
const data = await request(`/events/${encodeURIComponent(slug)}/volunteers`, {
|
|
208
|
+
method: "POST",
|
|
209
|
+
body: input,
|
|
210
|
+
headers: opts.ip ? { "X-Forwarded-For": opts.ip } : void 0,
|
|
211
|
+
signal: opts.signal,
|
|
212
|
+
resource: "events.volunteer"
|
|
213
|
+
});
|
|
214
|
+
return { ok: true, ...data };
|
|
215
|
+
} catch (err) {
|
|
216
|
+
if (isHearthError(err) && (err.code === "bad_request" || err.code === "rate_limited" || err.code === "feature_disabled" || err.code === "not_found")) {
|
|
217
|
+
return { ok: false, message: err.message, fieldErrors: err.details ?? {} };
|
|
218
|
+
}
|
|
219
|
+
throw err;
|
|
220
|
+
}
|
|
199
221
|
}
|
|
200
222
|
},
|
|
201
223
|
categories: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Collection, CollectionEntry, HearthEvent, Site, PageSummary, Page, HearthEventDetail, RegistrationInput, RegistrationResult, CategoryGroup, SitemapEntry, Redirect, AnalyticsReport, Fundraiser, FundraiserDetail, DonationInput, DonationCheckout, HearthForm } from '@the-smithy/hearth-schema';
|
|
1
|
+
import { Collection, CollectionEntry, HearthEvent, Site, PageSummary, Page, HearthEventDetail, RegistrationInput, RegistrationResult, VolunteerInput, VolunteerResult, CategoryGroup, SitemapEntry, Redirect, AnalyticsReport, Fundraiser, FundraiserDetail, DonationInput, DonationCheckout, HearthForm } from '@the-smithy/hearth-schema';
|
|
2
2
|
|
|
3
3
|
type HearthErrorCode = "unauthorized" | "not_found" | "bad_request" | "feature_disabled" | "rate_limited" | "server_error" | "network" | "timeout" | "invalid_response";
|
|
4
4
|
/** Any failure talking to Hearth. Messages never contain the API key. */
|
|
@@ -142,6 +142,21 @@ declare function createCore(options: HearthClientOptions): {
|
|
|
142
142
|
message: string;
|
|
143
143
|
fieldErrors: Record<string, string>;
|
|
144
144
|
}>;
|
|
145
|
+
/**
|
|
146
|
+
* Sign up to volunteer at an event that asks for volunteers (its `volunteering` is set). Post `shifts` when
|
|
147
|
+
* `volunteering.pickShifts` isn't "none", and each answer under its field's `name`. Validation problems
|
|
148
|
+
* (including a full shift or closed sign-up) resolve to { ok: false, fieldErrors }; network and auth failures throw.
|
|
149
|
+
*/
|
|
150
|
+
volunteer: (slug: string, input: VolunteerInput, opts?: {
|
|
151
|
+
ip?: string | null;
|
|
152
|
+
signal?: AbortSignal;
|
|
153
|
+
}) => Promise<({
|
|
154
|
+
ok: true;
|
|
155
|
+
} & VolunteerResult) | {
|
|
156
|
+
ok: false;
|
|
157
|
+
message: string;
|
|
158
|
+
fieldErrors: Record<string, string>;
|
|
159
|
+
}>;
|
|
145
160
|
};
|
|
146
161
|
categories: {
|
|
147
162
|
/** The site's category groups, each with its categories. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { H as HearthCore, a as HearthClientOptions } from './client-
|
|
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, h as findRedirect, i as isHearthError, n as normalizeSlug } from './client-
|
|
3
|
-
export { AnalyticsReport, AnalyticsRow, Block, BlockOf, CategoryGroup, CategoryRef, Collection, CollectionEntry, CollectionRef, DonationCheckout, DonationInput, EntryDetails, EventCustomFields, EventRegistration, EventTicket, Fundraiser, FundraiserDetail, HearthEvent, HearthEventDetail, KnownBlock, Page, PageMeta, PageSummary, Redirect, RegistrationInput, RegistrationResult, ResolvedBlock, Site, SiteAnalytics, SiteSettings, SitemapEntry, UnknownBlock, WebhookPayload, videoEmbedUrl } from '@the-smithy/hearth-schema';
|
|
1
|
+
import { H as HearthCore, a as HearthClientOptions } from './client-IImehdSM.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, h as findRedirect, i as isHearthError, n as normalizeSlug } from './client-IImehdSM.js';
|
|
3
|
+
export { AnalyticsReport, AnalyticsRow, Block, BlockOf, CategoryGroup, CategoryRef, Collection, CollectionEntry, CollectionRef, DonationCheckout, DonationInput, EntryDetails, EventCustomFields, EventRegistration, EventTicket, EventVolunteerShift, EventVolunteering, Fundraiser, FundraiserDetail, HearthEvent, HearthEventDetail, ImageRef, KnownBlock, Page, PageMeta, PageSummary, Position, Redirect, RegistrationInput, RegistrationResult, ResolvedBlock, Site, SiteAnalytics, SiteSettings, SitemapEntry, UnknownBlock, VolunteerInput, VolunteerResult, WebhookPayload, directionsUrl, focalPosition, pinned, videoEmbedUrl } from '@the-smithy/hearth-schema';
|
|
4
4
|
|
|
5
5
|
/** A plugin adds resources (and can use the core's `request`) under its own names. */
|
|
6
6
|
type HearthPlugin<T extends object = object> = {
|
package/dist/index.js
CHANGED
|
@@ -5,10 +5,12 @@ import {
|
|
|
5
5
|
findRedirect,
|
|
6
6
|
isHearthError,
|
|
7
7
|
normalizeSlug
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-V47RFBJE.js";
|
|
9
9
|
|
|
10
10
|
// src/index.ts
|
|
11
11
|
import { videoEmbedUrl } from "@the-smithy/hearth-schema";
|
|
12
|
+
import { focalPosition } from "@the-smithy/hearth-schema";
|
|
13
|
+
import { directionsUrl, pinned } from "@the-smithy/hearth-schema";
|
|
12
14
|
function definePlugin(setup) {
|
|
13
15
|
return { setup };
|
|
14
16
|
}
|
|
@@ -27,8 +29,11 @@ export {
|
|
|
27
29
|
HearthError,
|
|
28
30
|
createHearthClient,
|
|
29
31
|
definePlugin,
|
|
32
|
+
directionsUrl,
|
|
30
33
|
findRedirect,
|
|
34
|
+
focalPosition,
|
|
31
35
|
isHearthError,
|
|
32
36
|
normalizeSlug,
|
|
37
|
+
pinned,
|
|
33
38
|
videoEmbedUrl
|
|
34
39
|
};
|
package/dist/next.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { H as HearthCore, b as CollectionPage, E as EventCollectionPage, F as FormResult, c as FormValues } from './client-
|
|
1
|
+
import { H as HearthCore, b as CollectionPage, E as EventCollectionPage, F as FormResult, c as FormValues } from './client-IImehdSM.js';
|
|
2
2
|
import * as _the_smithy_hearth_schema from '@the-smithy/hearth-schema';
|
|
3
3
|
import { Site, PageMeta } from '@the-smithy/hearth-schema';
|
|
4
4
|
import { Metadata, MetadataRoute } from 'next';
|
|
@@ -190,7 +190,7 @@ declare function createHearthNext(client: HearthCore, { tag, revalidate }?: Hear
|
|
|
190
190
|
* A donation form's server action, shaped for `useActionState(action, null)`. Export it from a "use server" file:
|
|
191
191
|
* export const donate = async (prev: FormResult | null, fd: FormData) => donateAction()(prev, fd);
|
|
192
192
|
* Fields: `amount` (dollars, or "custom" with `customAmount`), `fundraiser`, `name`, `email`, `anonymous`,
|
|
193
|
-
* `message
|
|
193
|
+
* `message`, `updates` (a checkbox: "Send me updates about this fundraiser", unticked by default). On success it redirects the donor to the payment page; afterwards they return to `returnPath`.
|
|
194
194
|
*/
|
|
195
195
|
donateAction: ({ returnPath }?: {
|
|
196
196
|
returnPath?: string;
|
|
@@ -204,6 +204,14 @@ declare function createHearthNext(client: HearthCore, { tag, revalidate }?: Hear
|
|
|
204
204
|
registerAction: (slug: string, { returnPath }?: {
|
|
205
205
|
returnPath?: string;
|
|
206
206
|
}) => (_prev: FormResult | null, formData: FormData) => Promise<FormResult>;
|
|
207
|
+
/**
|
|
208
|
+
* A volunteer sign-up form's server action, for `useActionState(action, null)`:
|
|
209
|
+
* export const volunteer = async (slug: string, prev: FormResult | null, fd: FormData) => volunteerAction(slug)(prev, fd);
|
|
210
|
+
* Fields: `name`, `email`, one `shift` per chosen shift id, the honeypot `_gotcha`, and every other field as an
|
|
211
|
+
* answer under its name (a ticked checkbox posts "on"). Resolves to { ok: true, message } with the
|
|
212
|
+
* event's thank-you message.
|
|
213
|
+
*/
|
|
214
|
+
volunteerAction: (slug: string) => (_prev: FormResult | null, formData: FormData) => Promise<FormResult>;
|
|
207
215
|
/** Whether this request is a draft preview (to show a "Preview" banner with an exit link). */
|
|
208
216
|
isPreview: () => Promise<boolean>;
|
|
209
217
|
/**
|
package/dist/next.js
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
findRedirect,
|
|
3
3
|
isHearthError,
|
|
4
4
|
normalizeSlug
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-V47RFBJE.js";
|
|
6
6
|
import {
|
|
7
7
|
parseWebhook,
|
|
8
8
|
tagsForWebhook
|
|
@@ -70,7 +70,7 @@ function createHearthNext(client, { tag = "hearth", revalidate = 3600 } = {}) {
|
|
|
70
70
|
* A donation form's server action, shaped for `useActionState(action, null)`. Export it from a "use server" file:
|
|
71
71
|
* export const donate = async (prev: FormResult | null, fd: FormData) => donateAction()(prev, fd);
|
|
72
72
|
* Fields: `amount` (dollars, or "custom" with `customAmount`), `fundraiser`, `name`, `email`, `anonymous`,
|
|
73
|
-
* `message
|
|
73
|
+
* `message`, `updates` (a checkbox: "Send me updates about this fundraiser", unticked by default). On success it redirects the donor to the payment page; afterwards they return to `returnPath`.
|
|
74
74
|
*/
|
|
75
75
|
donateAction: ({ returnPath = "/donate/thank-you" } = {}) => async (_prev, formData) => {
|
|
76
76
|
const h = await headers();
|
|
@@ -87,6 +87,7 @@ function createHearthNext(client, { tag = "hearth", revalidate = 3600 } = {}) {
|
|
|
87
87
|
name: text("name"),
|
|
88
88
|
email: text("email"),
|
|
89
89
|
anonymous: formData.get("anonymous") === "on" || formData.get("anonymous") === "true",
|
|
90
|
+
updates: formData.get("updates") === "on" || formData.get("updates") === "true",
|
|
90
91
|
message: text("message"),
|
|
91
92
|
returnUrl: `${proto}://${host}${safePath(returnPath)}`
|
|
92
93
|
},
|
|
@@ -128,6 +129,33 @@ function createHearthNext(client, { tag = "hearth", revalidate = 3600 } = {}) {
|
|
|
128
129
|
if (result.status === "pending") redirect(result.checkoutUrl);
|
|
129
130
|
return { ok: true, message: "You're registered. A confirmation is on its way to your email." };
|
|
130
131
|
},
|
|
132
|
+
/**
|
|
133
|
+
* A volunteer sign-up form's server action, for `useActionState(action, null)`:
|
|
134
|
+
* export const volunteer = async (slug: string, prev: FormResult | null, fd: FormData) => volunteerAction(slug)(prev, fd);
|
|
135
|
+
* Fields: `name`, `email`, one `shift` per chosen shift id, the honeypot `_gotcha`, and every other field as an
|
|
136
|
+
* answer under its name (a ticked checkbox posts "on"). Resolves to { ok: true, message } with the
|
|
137
|
+
* event's thank-you message.
|
|
138
|
+
*/
|
|
139
|
+
volunteerAction: (slug) => async (_prev, formData) => {
|
|
140
|
+
const h = await headers();
|
|
141
|
+
const answers = {};
|
|
142
|
+
for (const [key, value] of formData.entries()) {
|
|
143
|
+
if (typeof value !== "string" || key.startsWith("$") || ["name", "email", "shift", "_gotcha"].includes(key)) continue;
|
|
144
|
+
answers[key] = value;
|
|
145
|
+
}
|
|
146
|
+
const result = await client.events.volunteer(
|
|
147
|
+
slug,
|
|
148
|
+
{
|
|
149
|
+
name: String(formData.get("name") ?? "").trim(),
|
|
150
|
+
email: String(formData.get("email") ?? "").trim(),
|
|
151
|
+
shifts: formData.getAll("shift").map(String),
|
|
152
|
+
answers,
|
|
153
|
+
_gotcha: String(formData.get("_gotcha") ?? "") || void 0
|
|
154
|
+
},
|
|
155
|
+
{ ip: clientIp(h) }
|
|
156
|
+
);
|
|
157
|
+
return result.ok ? { ok: true, message: result.message } : { ok: false, message: result.message, fieldErrors: result.fieldErrors };
|
|
158
|
+
},
|
|
131
159
|
/** Whether this request is a draft preview (to show a "Preview" banner with an exit link). */
|
|
132
160
|
isPreview: async () => Boolean(await previewToken()),
|
|
133
161
|
/**
|
package/llms.md
CHANGED
|
@@ -41,6 +41,11 @@ client components: the API key is secret.
|
|
|
41
41
|
- Tickets: `events.register(slug, { ticket, name, email, phone?, teamName?, attendees?, notes?, returnUrl }, { ip? })`:
|
|
42
42
|
`{ ok: true, status: "confirmed" }`, `{ ok: true, status: "pending", checkoutUrl }` or `{ ok: false, message, fieldErrors }`.
|
|
43
43
|
Events with on-site registration have `registration: { open, closesAt, tickets[], fundraiser }`.
|
|
44
|
+
- Volunteers: `events.volunteer(slug, { name, email, shifts?, answers? }, { ip? })`: `{ ok: true, signupId, message }` or
|
|
45
|
+
`{ ok: false, message, fieldErrors }`. Events asking for volunteers have `volunteering: { open, closesAt, intro, fields,
|
|
46
|
+
pickShifts: "none" | "one" | "many", shifts[], submitLabel, successMessage, fundraiser }`.
|
|
47
|
+
The `volunteerSignup` block places that form anywhere: its `data.event` is the Event (no `blocks`, `volunteering` always set);
|
|
48
|
+
without `eventSlug` it stands for the event whose page it's on, and an event page with one leaves out its own form.
|
|
44
49
|
- Giving (sites with the feature): `fundraisers.list({ status?, category?, limit? }): Fundraiser[]`,
|
|
45
50
|
`fundraisers.get(slug): FundraiserDetail | null`, `donations.checkout({ amountCents, fundraiser?, name?, email?,
|
|
46
51
|
anonymous?, message?, returnUrl }, { ip? })`: `{ ok: true, checkoutUrl }` or `{ ok: false, message, fieldErrors }`.
|
|
@@ -53,6 +58,15 @@ client components: the API key is secret.
|
|
|
53
58
|
`openGraph`, `twitter`, `image { url, width, height, alt }`, `jsonLd[]`.
|
|
54
59
|
- Each block is `{ id, type, data }`; fields live on `data`. Narrow by `type`; use `BlockOf<"hero">` for one type.
|
|
55
60
|
- Unknown future types arrive as `UnknownBlock`. Always handle a fallback.
|
|
61
|
+
- Images are `ImageRef = { src, alt, width?, height?, focal?: { x, y } }`. `focal` is the spot to keep in view when the
|
|
62
|
+
image is cropped (percentages across and down, set in Hearth's media library). For an image with `object-fit: cover`,
|
|
63
|
+
set `style={{ objectPosition: focalPosition(image, frameRatio) }}` (`focalPosition` from `@the-smithy/hearth`; the
|
|
64
|
+
frame's width / height centres the spot as far as the crop allows, omit it for frames whose shape changes). Don't
|
|
65
|
+
apply it to uncropped images (`object-contain`, logos).
|
|
66
|
+
- Places (`location`, and each of `locations`' `items`) carry `position?: Position = { lat, lng }`, the map pin set in
|
|
67
|
+
Hearth. Draw maps from it, never by looking addresses up: the template uses MapLibre GL with OpenFreeMap tiles (free,
|
|
68
|
+
no key, no cookies). `pinned(places)` keeps the places with a pin; `directionsUrl(place)` links to directions by
|
|
69
|
+
name and address. Without a pin, show no map.
|
|
56
70
|
|
|
57
71
|
## Next.js (`@the-smithy/hearth/next`)
|
|
58
72
|
- `hearthNext.getPage(slug)`, `getPages()`, `getSite()`, `getEvents(opts)`, `getEvent(slug)`:
|
|
@@ -69,6 +83,8 @@ client components: the API key is secret.
|
|
|
69
83
|
- Tickets: `registerAction(slug)` for a registration form (`ticket`, `name`, `email`, `phone`, `teamName`, `notes`,
|
|
70
84
|
one `attendee` per name); free tickets resolve to `{ ok: true, message }`, paid ones redirect to checkout and return
|
|
71
85
|
to `/registered`.
|
|
86
|
+
- Volunteers: `volunteerAction(slug)` for a sign-up form (`name`, `email`, one `shift` per chosen shift, every other
|
|
87
|
+
field as an answer under its name); resolves to `{ ok: true, message }` with the event's thank-you message.
|
|
72
88
|
- Draft preview: `app/api/preview/route.ts`: `export const GET = hearthNext.previewHandler()` and
|
|
73
89
|
`app/api/preview/exit/route.ts`: `export const GET = hearthNext.exitPreviewHandler()`. While previewing,
|
|
74
90
|
`getPage`, `getEvent` and `getFundraiser` return drafts. Every site renders the SDK's live preview in its root
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@the-smithy/hearth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.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.20.0"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"next": ">=15",
|