@riverbankcms/sdk 0.78.0 → 0.78.2
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 +45 -43
- package/dist/{PreviewEditorSidebar-RIKFQ72L.mjs → PreviewEditorSidebar-4DXLYX2V.mjs} +29 -21
- package/dist/{PreviewEditorUI-XO7TUWKK.mjs → PreviewEditorUI-CS5P4N3P.mjs} +4 -4
- package/dist/SdkPreviewModeRuntime-IJDHTW4W.mjs +8 -0
- package/dist/_dts/ai/src/contracts/proposals.d.ts +36 -0
- package/dist/_dts/api/src/contentRuntime.d.ts +1 -0
- package/dist/_dts/api/src/endpoints.d.ts +9 -0
- package/dist/_dts/api/src/index.d.ts +3 -3
- package/dist/_dts/api/src/public/types.d.ts +1 -1
- package/dist/_dts/api/src/request.d.ts +3 -11
- package/dist/_dts/api/src/sdkConfig/contracts.d.ts +1 -0
- package/dist/_dts/api/src/sdkContracts.d.ts +7 -1
- package/dist/_dts/api/src/siteManagementEndpoints.d.ts +10 -0
- package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +1 -0
- package/dist/_dts/api/src/siteRuntimeEndpoints.d.ts +15 -19
- package/dist/_dts/api/src/types.d.ts +11 -26
- package/dist/_dts/block-form/src/fields/types.d.ts +6 -0
- package/dist/_dts/block-form/src/widgets/RepeaterField/components/RepeaterList.d.ts +3 -2
- package/dist/_dts/block-form/src/widgets/RepeaterField/components/RepeaterRow.d.ts +6 -3
- package/dist/_dts/block-form/src/widgets/RepeaterField/components/RepeaterRowActions.d.ts +8 -3
- package/dist/_dts/block-form/src/widgets/RepeaterField/hooks/index.d.ts +1 -1
- package/dist/_dts/block-form/src/widgets/RepeaterField/hooks/useLinearRepeaterDnd.d.ts +1 -0
- package/dist/_dts/block-form/src/widgets/RepeaterField/hooks/useRepeaterPointerDragCapability.d.ts +1 -0
- package/dist/_dts/block-form/src/widgets/RepeaterField/hooks/useResolvedItemLabel.d.ts +7 -0
- package/dist/_dts/block-form/src/widgets/RepeaterField/utils/buildSummary.d.ts +1 -0
- package/dist/_dts/block-form/src/widgets/RepeaterField/utils/index.d.ts +3 -1
- package/dist/_dts/block-form/src/widgets/RepeaterField/utils/repeaterDndDomain.d.ts +1 -1
- package/dist/_dts/block-form/src/widgets/RepeaterField/utils/repeaterLabelSource.d.ts +15 -0
- package/dist/_dts/block-form/src/widgets/RepeaterField/utils/repeaterRowActionsDomain.d.ts +50 -0
- package/dist/_dts/blocks/src/system/blocks/appointment-booking.d.ts +591 -0
- package/dist/_dts/blocks/src/system/blocks/blog-listing.d.ts +591 -0
- package/dist/_dts/blocks/src/system/blocks/cart.d.ts +591 -0
- package/dist/_dts/blocks/src/system/blocks/checkout.d.ts +591 -0
- package/dist/_dts/blocks/src/system/blocks/collection.d.ts +591 -0
- package/dist/_dts/blocks/src/system/blocks/faq.d.ts +591 -0
- package/dist/_dts/blocks/src/system/blocks/gifting.d.ts +591 -0
- package/dist/_dts/blocks/src/system/blocks/location-map.d.ts +2 -0
- package/dist/_dts/blocks/src/system/blocks/media-text.d.ts +47 -0
- package/dist/_dts/blocks/src/system/blocks/product-detail.d.ts +591 -0
- package/dist/_dts/blocks/src/system/blocks/product-list.d.ts +591 -0
- package/dist/_dts/blocks/src/system/blocks/shop.d.ts +591 -0
- package/dist/_dts/blocks/src/system/blocks/team-members.d.ts +3 -0
- package/dist/_dts/blocks/src/system/manifest/schema.d.ts +164 -0
- package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.state.d.ts +1 -1
- package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +1 -1
- package/dist/_dts/content-editor/src/index.d.ts +1 -1
- package/dist/_dts/content-editor/src/ui/editorSnapshot.d.ts +2 -2
- package/dist/_dts/content-model/src/content-types/schema.d.ts +14 -0
- package/dist/_dts/content-model/src/templates/bindingTypeCompatibility.d.ts +3 -1
- package/dist/_dts/content-model/src/templates/bindingValidation.d.ts +10 -4
- package/dist/_dts/content-model/src/templates/fieldPaths.d.ts +20 -0
- package/dist/_dts/content-model/src/templates/manifestAdapter.d.ts +5 -2
- package/dist/_dts/core/src/branded.d.ts +108 -85
- package/dist/_dts/core/src/csv-types.d.ts +2 -2
- package/dist/_dts/core/src/editor-state.d.ts +7 -7
- package/dist/_dts/core/src/participants.d.ts +2 -2
- package/dist/_dts/db/src/generated/supabase/database.types.d.ts +11 -0
- package/dist/_dts/editor-blocks/src/blockPayload.d.ts +1 -1
- package/dist/_dts/media-editor/src/MediaEditor.d.ts +3 -1
- package/dist/_dts/media-editor/src/MediaPreview.d.ts +3 -1
- package/dist/_dts/media-editor/src/fieldUi.d.ts +5 -0
- package/dist/_dts/media-editor/src/index.d.ts +1 -1
- package/dist/_dts/sdk/src/cli/commands/push/consts.d.ts +1 -1
- package/dist/_dts/sdk/src/cli/commands/push/metadata.d.ts +2 -0
- package/dist/_dts/sdk/src/cli/commands/push/stale.d.ts +3 -3
- package/dist/_dts/sdk/src/cli/commands/push-execute.d.ts +7 -0
- package/dist/_dts/sdk/src/cli/commands/push.d.ts +2 -0
- package/dist/_dts/sdk/src/cli/content/reader.d.ts +13 -0
- package/dist/_dts/sdk/src/cli/content/writer.d.ts +2 -1
- package/dist/_dts/sdk/src/cli/helpers.d.ts +2 -0
- package/dist/_dts/sdk/src/cli/site-commands/commandKeys.d.ts +6 -6
- package/dist/_dts/sdk/src/cli/site-commands/commandRuntime.d.ts +5 -0
- package/dist/_dts/sdk/src/cli/site-commands/commandSurfaceDispatch.d.ts +4 -0
- package/dist/_dts/sdk/src/cli/site-commands/pageCommands.d.ts +5 -2
- package/dist/_dts/sdk/src/cli/site-commands/pushExecution.d.ts +10 -1
- package/dist/_dts/sdk/src/cli/site-commands/pushExecutionTypes.d.ts +1 -1
- package/dist/_dts/sdk/src/client/management/types.d.ts +6 -0
- package/dist/_dts/sdk/src/client/types.d.ts +2 -2
- package/dist/_dts/sdk/src/config/content-types.d.ts +7 -0
- package/dist/_dts/sdk/src/config/field-definitions.d.ts +2 -0
- package/dist/_dts/sdk/src/version.d.ts +1 -1
- package/dist/_dts/site-commands/src/commands.d.ts +3 -0
- package/dist/{altcha-B5XGSXP5.mjs → altcha-EKUEQ4RP.mjs} +1 -1
- package/dist/{chunk-NIDXI46P.mjs → chunk-4QEGTLK6.mjs} +1 -1
- package/dist/{chunk-TXDES5P2.mjs → chunk-6HYXHRAI.mjs} +5 -5
- package/dist/{chunk-SVMMM2NA.mjs → chunk-CR5HKAGU.mjs} +24 -5
- package/dist/{chunk-OECWLDHN.mjs → chunk-MCRQMPET.mjs} +1030 -588
- package/dist/{chunk-SXOLGNMX.mjs → chunk-OKMBEAXY.mjs} +1 -1
- package/dist/{chunk-XGB3TDIC.mjs → chunk-R7POPVJR.mjs} +2 -8
- package/dist/{chunk-F7RTCZYN.mjs → chunk-RGTOD4AJ.mjs} +20 -14
- package/dist/cli/index.mjs +681 -225
- package/dist/cli/init-docs/content/cli-reference.md +3 -2
- package/dist/cli/init-docs/content/content-management.md +2 -2
- package/dist/cli/init-docs/content/workflow-preview-mode.md +68 -2
- package/dist/client/{accordion-EVDEOUPR.mjs → accordion-PLYNJIIM.mjs} +2 -2
- package/dist/client/analytics.mjs +1 -1
- package/dist/client/{bookingForm-DIHBLC64.mjs → bookingForm-BXAP6AO7.mjs} +55 -48
- package/dist/client/bookings.mjs +62 -55
- package/dist/client/{carousel-FEBQHIWI.mjs → carousel-TRBXDHGF.mjs} +3 -3
- package/dist/client/{cart-7CKSXAE4.mjs → cart-Z7H3HJRS.mjs} +7 -7
- package/dist/client/{checkout-WKYCANLV.mjs → checkout-WAFCUBIX.mjs} +7 -7
- package/dist/client/{chunk-OFMSCGNY.mjs → chunk-75OUS5MT.mjs} +2 -2
- package/dist/client/{chunk-IVNCUVAV.mjs → chunk-AUJ5DBZJ.mjs} +18 -18
- package/dist/client/{chunk-36WJCERQ.mjs → chunk-CE7IBGVW.mjs} +3 -1
- package/dist/client/{chunk-RZDWX7QW.mjs → chunk-CWGTG37I.mjs} +1 -1
- package/dist/client/{chunk-YDSEG6GZ.mjs → chunk-DNRGY432.mjs} +2 -2
- package/dist/client/{chunk-RV6FX7UH.mjs → chunk-FUXW6VW2.mjs} +9 -9
- package/dist/client/{chunk-65F47D7Y.mjs → chunk-JGXPTEI2.mjs} +43 -36
- package/dist/client/{chunk-GUK2FPXQ.mjs → chunk-JRDUHZCT.mjs} +37 -15
- package/dist/client/{chunk-VPPMNXCF.mjs → chunk-UVQEJJTN.mjs} +2 -2
- package/dist/client/{chunk-F7LHOKEH.mjs → chunk-XSV6KW4D.mjs} +1 -1
- package/dist/client/{chunk-PD6NBCEY.mjs → chunk-ZFHRN6W2.mjs} +1 -1
- package/dist/client/{chunk-2SAVKN2M.mjs → chunk-ZI3LLBPZ.mjs} +2 -2
- package/dist/client/client.mjs +249 -160
- package/dist/client/{courseRegistration-5QF2PHKM.mjs → courseRegistration-AHFQHWIJ.mjs} +10 -10
- package/dist/client/{eventCalendar-4ZOSETDU.mjs → eventCalendar-LDXTV5R7.mjs} +9 -9
- package/dist/client/{eventCombined-WQGU7JUX.mjs → eventCombined-A4JGTNJO.mjs} +9 -9
- package/dist/client/{eventDetails-AYWVUJ5Y.mjs → eventDetails-4YXTZ7EG.mjs} +9 -9
- package/dist/client/{eventListing-NT7C6UT5.mjs → eventListing-P72TPFFM.mjs} +9 -9
- package/dist/client/{eventRegistration-OH24F4ZJ.mjs → eventRegistration-LSYJHGMT.mjs} +9 -9
- package/dist/client/{form-7L42SRBB.mjs → form-AOPYOKOW.mjs} +6 -3
- package/dist/client/{headerSection-OZRZNZ52.mjs → headerSection-5TFYDFVQ.mjs} +3 -3
- package/dist/client/hooks.mjs +78 -48
- package/dist/client/{locationMap-ZBXRPQ7C.mjs → locationMap-QSZ3ZVAZ.mjs} +3 -3
- package/dist/client/{newsletterForm-SNAGFF2I.mjs → newsletterForm-KTRHZY52.mjs} +2 -2
- package/dist/client/{productDetail-I46BOFGV.mjs → productDetail-N4E775RG.mjs} +7 -7
- package/dist/client/{productList-BOYHTYI6.mjs → productList-UGUQ2S45.mjs} +7 -7
- package/dist/client/rendering/client.mjs +173 -131
- package/dist/client/rendering/islands.mjs +19 -19
- package/dist/client/rendering.mjs +230 -150
- package/dist/client/{shop-XTXPZTKR.mjs → shop-VHSZEEQ2.mjs} +7 -7
- package/dist/preview-next/before-render.mjs +10 -1
- package/dist/preview-next/client/runtime.mjs +6 -6
- package/dist/preview-next/middleware.mjs +10 -1
- package/dist/preview-next/tailwind-sources.css +1 -0
- package/dist/sdk-runtime-WHPJEF5G.mjs +8 -0
- package/dist/server/components.mjs +101 -54
- package/dist/server/config-template-validation.mjs +221 -15
- package/dist/server/config-validation.mjs +76 -42
- package/dist/server/config.mjs +76 -42
- package/dist/server/data.mjs +77 -47
- package/dist/server/index.mjs +31 -10
- package/dist/server/next.mjs +133 -71
- package/dist/server/page-converter.mjs +60 -40
- package/dist/server/prebuild.mjs +1 -1
- package/dist/server/rendering/server.mjs +107 -60
- package/dist/server/rendering.mjs +111 -61
- package/dist/server/routing.mjs +93 -63
- package/dist/server/server.mjs +102 -57
- package/package.json +1 -1
- package/dist/SdkPreviewModeRuntime-LAGYMPNF.mjs +0 -8
- package/dist/sdk-runtime-ZJLKC6DR.mjs +0 -8
|
@@ -135,6 +135,7 @@ riverbankcms push entries blog-post welcome # Specific entry
|
|
|
135
135
|
riverbankcms push pages # All pages with blocks
|
|
136
136
|
riverbankcms push pages home # Specific page with blocks
|
|
137
137
|
riverbankcms push navigation # Navigation menus
|
|
138
|
+
riverbankcms push settings # Site settings / branding
|
|
138
139
|
riverbankcms push forms # Forms
|
|
139
140
|
riverbankcms push theme # Push content/themes/{activeTheme|current}.json
|
|
140
141
|
riverbankcms push venues # Event venues
|
|
@@ -158,7 +159,7 @@ riverbankcms push --dry-run --json-diff=full
|
|
|
158
159
|
| `--force-update-asset` | Replace CMS media when identifiers conflict (local media sync only) |
|
|
159
160
|
| `--allow-truncated` | Push even if remote content was truncated (may cause incomplete sync) |
|
|
160
161
|
| `--json-diff [mode]` | Output JSON diff: `summary` or `full` |
|
|
161
|
-
| `--with-config` | Also push SDK config after content
|
|
162
|
+
| `--with-config` | Also push SDK schema/config after file content |
|
|
162
163
|
| `--with-theme` | Also push theme when pushing all content |
|
|
163
164
|
| `--sync-media` | Sync media files from local to remote environment |
|
|
164
165
|
| `--overwrite-media` | When using `--sync-media`, overwrite target media on checksum mismatch |
|
|
@@ -248,7 +249,7 @@ For theme and footer pushes, stale resolution updates only the metadata timestam
|
|
|
248
249
|
|
|
249
250
|
- Use `logoIdentifier` / `faviconIdentifier` to manage the site logo and favicon from the repo
|
|
250
251
|
- The identifiers should match files in `content/media/`
|
|
251
|
-
- `riverbankcms push` reuses the normal local-media upload flow before updating site settings
|
|
252
|
+
- `riverbankcms push settings` reuses the normal local-media upload flow before updating site settings, without pushing unrelated content
|
|
252
253
|
- `riverbankcms pull settings` warns and omits a branding field if the current CMS asset cannot be represented by an identifier yet
|
|
253
254
|
- Dashboard branding edits and CLI pushes are last-write-wins on the same settings row, so pull before pushing after dashboard-side changes
|
|
254
255
|
|
|
@@ -193,12 +193,12 @@ Recommended workflow:
|
|
|
193
193
|
|
|
194
194
|
1. Add the branding files to `content/media/`, for example `content/media/positive-play-primary-logo.svg`
|
|
195
195
|
2. Reference those identifiers in `content/settings.json`
|
|
196
|
-
3. Run `riverbankcms push`
|
|
196
|
+
3. Run `riverbankcms push settings`
|
|
197
197
|
4. Run `riverbankcms pull settings` if you want to confirm the CMS state round-trips cleanly
|
|
198
198
|
|
|
199
199
|
Notes:
|
|
200
200
|
|
|
201
|
-
- `riverbankcms push` uploads missing branding files through the normal local-media sync path before updating site settings
|
|
201
|
+
- `riverbankcms push settings` uploads missing branding files through the normal local-media sync path before updating site settings, without pushing unrelated content
|
|
202
202
|
- `riverbankcms pull settings` warns and omits `logoIdentifier` / `faviconIdentifier` if the current CMS branding asset has no media identifier yet
|
|
203
203
|
- Dashboard branding edits and CLI pushes both update the same site settings row, so treat them as last-write-wins and pull before pushing after dashboard-side edits
|
|
204
204
|
|
|
@@ -43,9 +43,17 @@ Create `src/proxy.ts`:
|
|
|
43
43
|
import { handlePreviewTokens } from '@riverbankcms/sdk/preview-next/middleware'
|
|
44
44
|
import { NextResponse, type NextRequest } from 'next/server'
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
import { getCmsConfig } from './lib/env'
|
|
47
|
+
|
|
48
|
+
export async function proxy(request: NextRequest) {
|
|
47
49
|
if (process.env.RIVERBANK_PREVIEW_MODE === 'true') {
|
|
48
|
-
const
|
|
50
|
+
const { dashboardUrl } = getCmsConfig()
|
|
51
|
+
const response = await handlePreviewTokens(request, {
|
|
52
|
+
dashboardUrl: dashboardUrl ?? null,
|
|
53
|
+
onExchangeFailure: (failure) => {
|
|
54
|
+
console.warn('[riverbank] preview token exchange failed', failure)
|
|
55
|
+
},
|
|
56
|
+
})
|
|
49
57
|
if (response) return response
|
|
50
58
|
}
|
|
51
59
|
|
|
@@ -57,6 +65,10 @@ export const config = {
|
|
|
57
65
|
}
|
|
58
66
|
```
|
|
59
67
|
|
|
68
|
+
The example logs preview exchange failures with `console.warn`; replace it with your app logger if you already centralize server-side logging.
|
|
69
|
+
|
|
70
|
+
If you are upgrading an existing generated site, make sure your proxy imports `getCmsConfig`, is declared `async`, and passes `dashboardUrl` into `handlePreviewTokens`. Without the dashboard URL, visits with `preview_code` cannot exchange the short-lived code for preview cookies.
|
|
71
|
+
|
|
60
72
|
## Add Preview Keep-Alive Route
|
|
61
73
|
|
|
62
74
|
Create `src/app/api/preview/keep-alive/route.ts`:
|
|
@@ -127,6 +139,60 @@ export default Page
|
|
|
127
139
|
export { generateMetadata }
|
|
128
140
|
```
|
|
129
141
|
|
|
142
|
+
## Custom Header/Footer Chrome
|
|
143
|
+
|
|
144
|
+
If your site replaces the SDK header or footer, pass that chrome into `PreviewLayoutProvider` only when there is an editable preview session. `RIVERBANK_PREVIEW_MODE=true` makes the route preview-capable, but `getPreviewSession()` tells you whether the current request actually has preview cookies. Regular visitors without preview cookies should keep the normal SDK `Layout`.
|
|
145
|
+
|
|
146
|
+
In `src/app/layout.tsx`:
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
import type { ReactNode } from 'react'
|
|
150
|
+
|
|
151
|
+
import { Layout } from '@riverbankcms/sdk/rendering/server'
|
|
152
|
+
import { PreviewLayoutProvider } from '@riverbankcms/sdk/preview-next/client'
|
|
153
|
+
import { getPreviewSession } from '@riverbankcms/sdk/preview-next/session'
|
|
154
|
+
|
|
155
|
+
import { getRiverbankClient, getSiteId } from '@/lib/riverbank-client'
|
|
156
|
+
|
|
157
|
+
function SiteHeader() {
|
|
158
|
+
return <header>{/* your site header */}</header>
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function SiteFooter() {
|
|
162
|
+
return <footer>{/* your site footer */}</footer>
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export default async function RootLayout({ children }: { children: ReactNode }) {
|
|
166
|
+
const session = await getPreviewSession()
|
|
167
|
+
const hasEditablePreviewSession = Boolean(session?.canEdit && session?.token)
|
|
168
|
+
const headerNode = <SiteHeader />
|
|
169
|
+
const footerNode = <SiteFooter />
|
|
170
|
+
|
|
171
|
+
return (
|
|
172
|
+
<html lang="en">
|
|
173
|
+
<body>
|
|
174
|
+
{hasEditablePreviewSession ? (
|
|
175
|
+
<PreviewLayoutProvider headerNode={headerNode} footerNode={footerNode}>
|
|
176
|
+
{children}
|
|
177
|
+
</PreviewLayoutProvider>
|
|
178
|
+
) : (
|
|
179
|
+
<Layout
|
|
180
|
+
client={getRiverbankClient()}
|
|
181
|
+
siteId={getSiteId()}
|
|
182
|
+
header={() => headerNode}
|
|
183
|
+
footer={() => footerNode}
|
|
184
|
+
>
|
|
185
|
+
{children}
|
|
186
|
+
</Layout>
|
|
187
|
+
)}
|
|
188
|
+
</body>
|
|
189
|
+
</html>
|
|
190
|
+
)
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
If your custom chrome needs CMS navigation data, build the `headerNode` and `footerNode` from the same data used by your normal layout before branching. Calling `getPreviewSession()` in the root layout reads cookies, so the layout becomes dynamic.
|
|
195
|
+
|
|
130
196
|
## Import Preview CSS
|
|
131
197
|
|
|
132
198
|
For Tailwind sites, add this to `src/app/globals.css`:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { defineIslandPropsDecoder } from './chunk-
|
|
2
|
-
import './chunk-
|
|
1
|
+
import { defineIslandPropsDecoder } from './chunk-JGXPTEI2.mjs';
|
|
2
|
+
import './chunk-AUJ5DBZJ.mjs';
|
|
3
3
|
|
|
4
4
|
// src/rendering/islands/enhancers/accordion.ts
|
|
5
5
|
var decode = defineIslandPropsDecoder("accordion");
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { usePolling } from './chunk-
|
|
3
|
-
import { SpinnerNode } from './chunk-
|
|
4
|
-
import { useDiscountCodeUi } from './chunk-
|
|
5
|
-
import { scrollToBlock, buildCheckoutReturnUrls, DiscountCodeDisclosure, formatPrice } from './chunk-
|
|
2
|
+
import { usePolling } from './chunk-DNRGY432.mjs';
|
|
3
|
+
import { SpinnerNode } from './chunk-CE7IBGVW.mjs';
|
|
4
|
+
import { useDiscountCodeUi } from './chunk-ZFHRN6W2.mjs';
|
|
5
|
+
import { scrollToBlock, buildCheckoutReturnUrls, DiscountCodeDisclosure, formatPrice } from './chunk-UVQEJJTN.mjs';
|
|
6
6
|
import { FieldValidationMessage, getFieldValidationControlProps } from './chunk-3DCJ45Z2.mjs';
|
|
7
7
|
import './chunk-3PEDD5KJ.mjs';
|
|
8
8
|
import { isSpamProtectionEnabled, getChallengeUrl, AltchaWidget } from './chunk-YLMKMCSJ.mjs';
|
|
9
9
|
import { BlockApiProvider, useBlockApi, FeedbackMessage } from './chunk-UDNSI5PY.mjs';
|
|
10
10
|
import { mountReactIsland } from './chunk-N7PBWBWQ.mjs';
|
|
11
|
-
import { defineIslandPropsDecoder, resolveBookingSiteId, resolveDefaultBookingServiceId, getBookingRedirectStateFromLocation, deriveBookingFormViewState, logger, getBookingSuccessMessage, resolveAppointmentCheckoutVerificationState, themeButtonClassName, toSelectedCollectionOptionKind, assertNever11, prepareBookingSubmission, formatBookingSubmissionPreparationError, resolveBookingPaymentStep, BOOKING_FORM_DATA_RESERVED_KEYS, clearWorkflowFeedback, reportWorkflowError, reportWorkflowSuccess, okWith2, err2 } from './chunk-
|
|
12
|
-
import { resolveBookingTimeZoneId, DEFAULT_BOOKING_TIME_ZONE,
|
|
11
|
+
import { defineIslandPropsDecoder, resolveBookingSiteId, resolveDefaultBookingServiceId, getBookingRedirectStateFromLocation, deriveBookingFormViewState, logger, getBookingSuccessMessage, resolveAppointmentCheckoutVerificationState, themeButtonClassName, toSelectedCollectionOptionKind, assertNever11, prepareBookingSubmission, formatBookingSubmissionPreparationError, resolveBookingPaymentStep, BOOKING_FORM_DATA_RESERVED_KEYS, clearWorkflowFeedback, reportWorkflowError, reportWorkflowSuccess, okWith2, err2 } from './chunk-JGXPTEI2.mjs';
|
|
12
|
+
import { resolveBookingTimeZoneId, DEFAULT_BOOKING_TIME_ZONE, unsafeAsFormId, unsafeAsAppointmentResourceId, unsafeAsCustomerPassId, unsafeAsAppointmentServiceId, formatLocalScheduleDate, addLocalScheduleDays, parseBookingLocalDate, resolveFlexibleBalanceInitialPaymentCents, resolveFlexibleBalanceDueAt, getBookingInstalmentDepositRefundability, unsafeAsPassId, splitAmountWithRemainderInFirst, addIntervalPreservingMonthAnchor, clampConfiguredAmount, getBookingInstalmentPlanIntervalCount, omitZeroAmountFutureRows, formatBookingInstant } from './chunk-AUJ5DBZJ.mjs';
|
|
13
13
|
import React2, { useRef, useState, useMemo, useReducer, useEffect, useCallback, useLayoutEffect } from 'react';
|
|
14
14
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
15
15
|
|
|
@@ -223,7 +223,7 @@ function useAvailableDates({
|
|
|
223
223
|
const endDate = formatLocalScheduleDate(
|
|
224
224
|
addLocalScheduleDays(parseBookingLocalDate(today), initialDays)
|
|
225
225
|
);
|
|
226
|
-
fetchDates(today, endDate, false);
|
|
226
|
+
void fetchDates(today, endDate, false);
|
|
227
227
|
}, [serviceId, fetchDates, initialDays]);
|
|
228
228
|
useVisibleTabPolling({
|
|
229
229
|
enabled: Boolean(serviceId && loadedRange),
|
|
@@ -243,7 +243,7 @@ function useAvailableDates({
|
|
|
243
243
|
BOOKING_FETCH_CHUNK_DAYS
|
|
244
244
|
)
|
|
245
245
|
);
|
|
246
|
-
fetchDates(start, end, true);
|
|
246
|
+
void fetchDates(start, end, true);
|
|
247
247
|
}, [fetchDates, isLoading]);
|
|
248
248
|
return {
|
|
249
249
|
availableDates,
|
|
@@ -303,7 +303,7 @@ function useAvailableSlots({
|
|
|
303
303
|
setSlots(
|
|
304
304
|
result.slots.map((slot) => ({
|
|
305
305
|
...slot,
|
|
306
|
-
resourceId:
|
|
306
|
+
resourceId: unsafeAsAppointmentResourceId(slot.resourceId)
|
|
307
307
|
}))
|
|
308
308
|
);
|
|
309
309
|
setHasLoaded(true);
|
|
@@ -675,7 +675,7 @@ function formatScheduleDate(isoString, locale) {
|
|
|
675
675
|
}
|
|
676
676
|
|
|
677
677
|
// ../blocks/src/system/runtime/nodes/booking-form.headless.state.ts
|
|
678
|
-
var
|
|
678
|
+
var unsafeAsBookingFieldId = (id) => id;
|
|
679
679
|
function createEmptyBookingValidationErrors() {
|
|
680
680
|
return { formError: null, fieldErrors: {} };
|
|
681
681
|
}
|
|
@@ -745,13 +745,13 @@ function toOptionalBrandedId(value, brand) {
|
|
|
745
745
|
return trimmed ? brand(trimmed) : void 0;
|
|
746
746
|
}
|
|
747
747
|
function toOptionalAppointmentServiceId(value) {
|
|
748
|
-
return toOptionalBrandedId(value,
|
|
748
|
+
return toOptionalBrandedId(value, unsafeAsAppointmentServiceId);
|
|
749
749
|
}
|
|
750
750
|
function toOptionalAppointmentResourceId(value) {
|
|
751
|
-
return toOptionalBrandedId(value,
|
|
751
|
+
return toOptionalBrandedId(value, unsafeAsAppointmentResourceId);
|
|
752
752
|
}
|
|
753
753
|
function toOptionalCustomerPassId(value) {
|
|
754
|
-
return toOptionalBrandedId(value,
|
|
754
|
+
return toOptionalBrandedId(value, unsafeAsCustomerPassId);
|
|
755
755
|
}
|
|
756
756
|
function isBookingFieldValue(value) {
|
|
757
757
|
return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
@@ -905,7 +905,7 @@ function toBookingSlotView(slot) {
|
|
|
905
905
|
key: `${slot.startAt}|${slot.endAt}|${slot.resourceId}`,
|
|
906
906
|
startAt: slot.startAt,
|
|
907
907
|
endAt: slot.endAt,
|
|
908
|
-
resourceId:
|
|
908
|
+
resourceId: unsafeAsAppointmentResourceId(slot.resourceId),
|
|
909
909
|
...slot.resourceName ? { resourceName: slot.resourceName } : {},
|
|
910
910
|
...slot.label ? { label: slot.label } : {}
|
|
911
911
|
};
|
|
@@ -1027,29 +1027,30 @@ function validateBookingField(field, value) {
|
|
|
1027
1027
|
}
|
|
1028
1028
|
if (isBlankFieldValue(value)) return null;
|
|
1029
1029
|
const strValue = typeof value === "string" ? value : String(value);
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
return null;
|
|
1037
|
-
} catch {
|
|
1038
|
-
return "Please enter a valid URL";
|
|
1039
|
-
}
|
|
1040
|
-
case "tel":
|
|
1041
|
-
return /^[+\d\s\-()]+$/.test(strValue) ? null : "Please enter a valid phone number";
|
|
1042
|
-
case "number": {
|
|
1043
|
-
const num = Number(value);
|
|
1044
|
-
if (Number.isNaN(num)) return "Please enter a valid number";
|
|
1045
|
-
if (field.min !== void 0 && num < field.min) {
|
|
1046
|
-
return `Value must be at least ${field.min}`;
|
|
1047
|
-
}
|
|
1048
|
-
if (field.max !== void 0 && num > field.max) {
|
|
1049
|
-
return `Value must be at most ${field.max}`;
|
|
1050
|
-
}
|
|
1030
|
+
if (field.type === "email") {
|
|
1031
|
+
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(strValue) ? null : "Please enter a valid email address";
|
|
1032
|
+
}
|
|
1033
|
+
if (field.type === "url") {
|
|
1034
|
+
try {
|
|
1035
|
+
new URL(strValue);
|
|
1051
1036
|
return null;
|
|
1037
|
+
} catch {
|
|
1038
|
+
return "Please enter a valid URL";
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
if (field.type === "tel") {
|
|
1042
|
+
return /^[+\d\s\-()]+$/.test(strValue) ? null : "Please enter a valid phone number";
|
|
1043
|
+
}
|
|
1044
|
+
if (field.type === "number") {
|
|
1045
|
+
const num = Number(value);
|
|
1046
|
+
if (Number.isNaN(num)) return "Please enter a valid number";
|
|
1047
|
+
if (field.min !== void 0 && num < field.min) {
|
|
1048
|
+
return `Value must be at least ${field.min}`;
|
|
1049
|
+
}
|
|
1050
|
+
if (field.max !== void 0 && num > field.max) {
|
|
1051
|
+
return `Value must be at most ${field.max}`;
|
|
1052
1052
|
}
|
|
1053
|
+
return null;
|
|
1053
1054
|
}
|
|
1054
1055
|
if (typeof value === "string") {
|
|
1055
1056
|
if (field.minLength && value.length < field.minLength) {
|
|
@@ -1148,7 +1149,7 @@ function buildBookingAvailabilityQuery(input) {
|
|
|
1148
1149
|
}
|
|
1149
1150
|
function deriveBookingFieldViews(input) {
|
|
1150
1151
|
return (input.form?.schema?.fields ?? []).map((field) => {
|
|
1151
|
-
const fieldId =
|
|
1152
|
+
const fieldId = unsafeAsBookingFieldId(field.id);
|
|
1152
1153
|
const inputId = `${input.idPrefix}-${fieldId}`;
|
|
1153
1154
|
const helpTextId = field.helpText ? `${inputId}-help` : null;
|
|
1154
1155
|
const fieldValue = input.values[field.id] ?? null;
|
|
@@ -1305,8 +1306,8 @@ function resolveAppointmentPackagesModel(input) {
|
|
|
1305
1306
|
function toHeadlessEligibleAppointmentPackage(appointmentPackage) {
|
|
1306
1307
|
return {
|
|
1307
1308
|
...appointmentPackage,
|
|
1308
|
-
customerPassId:
|
|
1309
|
-
passId:
|
|
1309
|
+
customerPassId: unsafeAsCustomerPassId(appointmentPackage.customerPassId),
|
|
1310
|
+
passId: unsafeAsPassId(appointmentPackage.passId)
|
|
1310
1311
|
};
|
|
1311
1312
|
}
|
|
1312
1313
|
function resolveHeadlessBookingStatus(input) {
|
|
@@ -1366,7 +1367,7 @@ function omitRecordKey(record, key) {
|
|
|
1366
1367
|
// ../blocks/src/system/runtime/hooks/useHeadlessBookingFlow.ts
|
|
1367
1368
|
function useHeadlessBookingFlow(options) {
|
|
1368
1369
|
const viewerTimeZone = options.viewerTimeZone ?? getRuntimeTimeZone();
|
|
1369
|
-
const formKey =
|
|
1370
|
+
const formKey = unsafeAsFormId(options.formId);
|
|
1370
1371
|
const defaultServiceId = toOptionalAppointmentServiceId(
|
|
1371
1372
|
options.initialServiceId ?? resolveDefaultBookingServiceId(options.form, options.services) ?? void 0
|
|
1372
1373
|
);
|
|
@@ -1532,7 +1533,7 @@ function useHeadlessBookingFlow(options) {
|
|
|
1532
1533
|
setResourcesState({
|
|
1533
1534
|
tag: "loaded",
|
|
1534
1535
|
value: (result.options ?? []).map((option) => ({
|
|
1535
|
-
id:
|
|
1536
|
+
id: unsafeAsAppointmentResourceId(option.id),
|
|
1536
1537
|
label: option.label
|
|
1537
1538
|
}))
|
|
1538
1539
|
});
|
|
@@ -1748,11 +1749,11 @@ function useHeadlessBookingFlow(options) {
|
|
|
1748
1749
|
() => ({
|
|
1749
1750
|
selectService: (serviceId) => dispatch({
|
|
1750
1751
|
type: "service-selected",
|
|
1751
|
-
serviceId:
|
|
1752
|
+
serviceId: unsafeAsAppointmentServiceId(serviceId)
|
|
1752
1753
|
}),
|
|
1753
1754
|
selectResource: (resourceId) => dispatch({
|
|
1754
1755
|
type: "resource-selected",
|
|
1755
|
-
resourceId: resourceId ?
|
|
1756
|
+
resourceId: resourceId ? unsafeAsAppointmentResourceId(resourceId) : null
|
|
1756
1757
|
}),
|
|
1757
1758
|
selectDate: (date) => dispatch({ type: "date-selected", date }),
|
|
1758
1759
|
selectSlot: (slot) => dispatch({
|
|
@@ -1761,14 +1762,14 @@ function useHeadlessBookingFlow(options) {
|
|
|
1761
1762
|
}),
|
|
1762
1763
|
updateField: (fieldId, value) => dispatch({
|
|
1763
1764
|
type: "field-updated",
|
|
1764
|
-
fieldId:
|
|
1765
|
+
fieldId: unsafeAsBookingFieldId(fieldId),
|
|
1765
1766
|
value
|
|
1766
1767
|
}),
|
|
1767
|
-
markFieldTouched: (fieldId) => dispatch({ type: "field-touched", fieldId:
|
|
1768
|
+
markFieldTouched: (fieldId) => dispatch({ type: "field-touched", fieldId: unsafeAsBookingFieldId(fieldId) }),
|
|
1768
1769
|
selectPaymentOption: (kind) => dispatch({ type: "payment-option-selected", kind }),
|
|
1769
1770
|
selectAppointmentPackage: (packageId) => dispatch({
|
|
1770
1771
|
type: "appointment-package-selected",
|
|
1771
|
-
packageId: packageId ?
|
|
1772
|
+
packageId: packageId ? unsafeAsCustomerPassId(packageId) : null
|
|
1772
1773
|
}),
|
|
1773
1774
|
setDiscountCode: (code) => {
|
|
1774
1775
|
dispatch({ type: "discount-code-changed", code });
|
|
@@ -2603,7 +2604,7 @@ function DefaultFieldInput({
|
|
|
2603
2604
|
] }, option.value)) });
|
|
2604
2605
|
case "checkbox":
|
|
2605
2606
|
if (field.field.options && field.field.options.length > 1) {
|
|
2606
|
-
const checkedValues =
|
|
2607
|
+
const checkedValues = toStringArray(value);
|
|
2607
2608
|
return /* @__PURE__ */ jsx("div", { className: "rb-space-y-2", children: field.field.options.map((option) => /* @__PURE__ */ jsxs("label", { className: "rb-flex rb-items-center rb-gap-2 rb-cursor-pointer", children: [
|
|
2608
2609
|
/* @__PURE__ */ jsx(
|
|
2609
2610
|
"input",
|
|
@@ -2698,7 +2699,10 @@ function DefaultFieldInput({
|
|
|
2698
2699
|
className: "form-input"
|
|
2699
2700
|
}
|
|
2700
2701
|
);
|
|
2701
|
-
|
|
2702
|
+
case "text":
|
|
2703
|
+
case "email":
|
|
2704
|
+
case "tel":
|
|
2705
|
+
case "url":
|
|
2702
2706
|
return /* @__PURE__ */ jsx(
|
|
2703
2707
|
"input",
|
|
2704
2708
|
{
|
|
@@ -2715,6 +2719,9 @@ function DefaultFieldInput({
|
|
|
2715
2719
|
);
|
|
2716
2720
|
}
|
|
2717
2721
|
}
|
|
2722
|
+
function toStringArray(value) {
|
|
2723
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
2724
|
+
}
|
|
2718
2725
|
function DefaultBookingDiscount({
|
|
2719
2726
|
booking
|
|
2720
2727
|
}) {
|
|
@@ -2806,7 +2813,7 @@ function collapseHeadlessSlotsForDisplay(input) {
|
|
|
2806
2813
|
visibleSlots.push({
|
|
2807
2814
|
startAt: slot.startAt,
|
|
2808
2815
|
endAt: slot.endAt,
|
|
2809
|
-
resourceId:
|
|
2816
|
+
resourceId: unsafeAsAppointmentResourceId(slot.resourceId)
|
|
2810
2817
|
});
|
|
2811
2818
|
}
|
|
2812
2819
|
return visibleSlots;
|