@riverbankcms/sdk 0.1.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.
Files changed (157) hide show
  1. package/README.md +1892 -0
  2. package/dist/cli/index.js +327 -0
  3. package/dist/cli/index.js.map +1 -0
  4. package/dist/client/analytics.d.mts +103 -0
  5. package/dist/client/analytics.d.ts +103 -0
  6. package/dist/client/analytics.js +197 -0
  7. package/dist/client/analytics.js.map +1 -0
  8. package/dist/client/analytics.mjs +169 -0
  9. package/dist/client/analytics.mjs.map +1 -0
  10. package/dist/client/bookings.d.mts +89 -0
  11. package/dist/client/bookings.d.ts +89 -0
  12. package/dist/client/bookings.js +34 -0
  13. package/dist/client/bookings.js.map +1 -0
  14. package/dist/client/bookings.mjs +11 -0
  15. package/dist/client/bookings.mjs.map +1 -0
  16. package/dist/client/client.d.mts +195 -0
  17. package/dist/client/client.d.ts +195 -0
  18. package/dist/client/client.js +606 -0
  19. package/dist/client/client.js.map +1 -0
  20. package/dist/client/client.mjs +572 -0
  21. package/dist/client/client.mjs.map +1 -0
  22. package/dist/client/hooks.d.mts +71 -0
  23. package/dist/client/hooks.d.ts +71 -0
  24. package/dist/client/hooks.js +264 -0
  25. package/dist/client/hooks.js.map +1 -0
  26. package/dist/client/hooks.mjs +235 -0
  27. package/dist/client/hooks.mjs.map +1 -0
  28. package/dist/client/rendering/client.d.mts +1 -0
  29. package/dist/client/rendering/client.d.ts +1 -0
  30. package/dist/client/rendering/client.js +33 -0
  31. package/dist/client/rendering/client.js.map +1 -0
  32. package/dist/client/rendering/client.mjs +8 -0
  33. package/dist/client/rendering/client.mjs.map +1 -0
  34. package/dist/client/usePage-BvKAa3Zw.d.mts +366 -0
  35. package/dist/client/usePage-BvKAa3Zw.d.ts +366 -0
  36. package/dist/server/chunk-2RW5HAQQ.mjs +86 -0
  37. package/dist/server/chunk-2RW5HAQQ.mjs.map +1 -0
  38. package/dist/server/chunk-3KKZVGH4.mjs +179 -0
  39. package/dist/server/chunk-3KKZVGH4.mjs.map +1 -0
  40. package/dist/server/chunk-4Z3GPTCS.js +179 -0
  41. package/dist/server/chunk-4Z3GPTCS.js.map +1 -0
  42. package/dist/server/chunk-4Z5FBFRL.mjs +211 -0
  43. package/dist/server/chunk-4Z5FBFRL.mjs.map +1 -0
  44. package/dist/server/chunk-ADREPXFU.js +86 -0
  45. package/dist/server/chunk-ADREPXFU.js.map +1 -0
  46. package/dist/server/chunk-F472SMKX.js +140 -0
  47. package/dist/server/chunk-F472SMKX.js.map +1 -0
  48. package/dist/server/chunk-GWBMJPLH.mjs +57 -0
  49. package/dist/server/chunk-GWBMJPLH.mjs.map +1 -0
  50. package/dist/server/chunk-JB4LIEFS.js +85 -0
  51. package/dist/server/chunk-JB4LIEFS.js.map +1 -0
  52. package/dist/server/chunk-PEAXKTDU.mjs +140 -0
  53. package/dist/server/chunk-PEAXKTDU.mjs.map +1 -0
  54. package/dist/server/chunk-QQ6U4QX6.js +120 -0
  55. package/dist/server/chunk-QQ6U4QX6.js.map +1 -0
  56. package/dist/server/chunk-R5YGLRUG.mjs +122 -0
  57. package/dist/server/chunk-R5YGLRUG.mjs.map +1 -0
  58. package/dist/server/chunk-SW7LE4M3.js +211 -0
  59. package/dist/server/chunk-SW7LE4M3.js.map +1 -0
  60. package/dist/server/chunk-W3K7LVPS.mjs +120 -0
  61. package/dist/server/chunk-W3K7LVPS.mjs.map +1 -0
  62. package/dist/server/chunk-WKG57P2H.mjs +85 -0
  63. package/dist/server/chunk-WKG57P2H.mjs.map +1 -0
  64. package/dist/server/chunk-YHEZMVTS.js +122 -0
  65. package/dist/server/chunk-YHEZMVTS.js.map +1 -0
  66. package/dist/server/chunk-YXDDFG3N.js +57 -0
  67. package/dist/server/chunk-YXDDFG3N.js.map +1 -0
  68. package/dist/server/components.d.mts +49 -0
  69. package/dist/server/components.d.ts +49 -0
  70. package/dist/server/components.js +22 -0
  71. package/dist/server/components.js.map +1 -0
  72. package/dist/server/components.mjs +22 -0
  73. package/dist/server/components.mjs.map +1 -0
  74. package/dist/server/config-validation.d.mts +300 -0
  75. package/dist/server/config-validation.d.ts +300 -0
  76. package/dist/server/config-validation.js +50 -0
  77. package/dist/server/config-validation.js.map +1 -0
  78. package/dist/server/config-validation.mjs +50 -0
  79. package/dist/server/config-validation.mjs.map +1 -0
  80. package/dist/server/config.d.mts +38 -0
  81. package/dist/server/config.d.ts +38 -0
  82. package/dist/server/config.js +44 -0
  83. package/dist/server/config.js.map +1 -0
  84. package/dist/server/config.mjs +44 -0
  85. package/dist/server/config.mjs.map +1 -0
  86. package/dist/server/data.d.mts +108 -0
  87. package/dist/server/data.d.ts +108 -0
  88. package/dist/server/data.js +15 -0
  89. package/dist/server/data.js.map +1 -0
  90. package/dist/server/data.mjs +15 -0
  91. package/dist/server/data.mjs.map +1 -0
  92. package/dist/server/index-B0yI_V6Z.d.mts +18 -0
  93. package/dist/server/index-C6M0Wfjq.d.ts +18 -0
  94. package/dist/server/index.d.mts +5 -0
  95. package/dist/server/index.d.ts +5 -0
  96. package/dist/server/index.js +12 -0
  97. package/dist/server/index.js.map +1 -0
  98. package/dist/server/index.mjs +12 -0
  99. package/dist/server/index.mjs.map +1 -0
  100. package/dist/server/loadContent-CJcbYF3J.d.ts +152 -0
  101. package/dist/server/loadContent-zhlL4YSE.d.mts +152 -0
  102. package/dist/server/loadPage-BYmVMk0V.d.ts +216 -0
  103. package/dist/server/loadPage-CCf15nt8.d.mts +216 -0
  104. package/dist/server/loadPage-DVH3DW6E.js +9 -0
  105. package/dist/server/loadPage-DVH3DW6E.js.map +1 -0
  106. package/dist/server/loadPage-PHQZ6XQZ.mjs +9 -0
  107. package/dist/server/loadPage-PHQZ6XQZ.mjs.map +1 -0
  108. package/dist/server/metadata.d.mts +135 -0
  109. package/dist/server/metadata.d.ts +135 -0
  110. package/dist/server/metadata.js +68 -0
  111. package/dist/server/metadata.js.map +1 -0
  112. package/dist/server/metadata.mjs +68 -0
  113. package/dist/server/metadata.mjs.map +1 -0
  114. package/dist/server/rendering/server.d.mts +83 -0
  115. package/dist/server/rendering/server.d.ts +83 -0
  116. package/dist/server/rendering/server.js +14 -0
  117. package/dist/server/rendering/server.js.map +1 -0
  118. package/dist/server/rendering/server.mjs +14 -0
  119. package/dist/server/rendering/server.mjs.map +1 -0
  120. package/dist/server/rendering.d.mts +12 -0
  121. package/dist/server/rendering.d.ts +12 -0
  122. package/dist/server/rendering.js +40 -0
  123. package/dist/server/rendering.js.map +1 -0
  124. package/dist/server/rendering.mjs +40 -0
  125. package/dist/server/rendering.mjs.map +1 -0
  126. package/dist/server/routing.d.mts +115 -0
  127. package/dist/server/routing.d.ts +115 -0
  128. package/dist/server/routing.js +57 -0
  129. package/dist/server/routing.js.map +1 -0
  130. package/dist/server/routing.mjs +57 -0
  131. package/dist/server/routing.mjs.map +1 -0
  132. package/dist/server/server.d.mts +9 -0
  133. package/dist/server/server.d.ts +9 -0
  134. package/dist/server/server.js +21 -0
  135. package/dist/server/server.js.map +1 -0
  136. package/dist/server/server.mjs +21 -0
  137. package/dist/server/server.mjs.map +1 -0
  138. package/dist/server/theme-bridge.d.mts +232 -0
  139. package/dist/server/theme-bridge.d.ts +232 -0
  140. package/dist/server/theme-bridge.js +231 -0
  141. package/dist/server/theme-bridge.js.map +1 -0
  142. package/dist/server/theme-bridge.mjs +231 -0
  143. package/dist/server/theme-bridge.mjs.map +1 -0
  144. package/dist/server/theme.d.mts +40 -0
  145. package/dist/server/theme.d.ts +40 -0
  146. package/dist/server/theme.js +17 -0
  147. package/dist/server/theme.js.map +1 -0
  148. package/dist/server/theme.mjs +17 -0
  149. package/dist/server/theme.mjs.map +1 -0
  150. package/dist/server/types-BCeqWtI2.d.mts +333 -0
  151. package/dist/server/types-BCeqWtI2.d.ts +333 -0
  152. package/dist/server/types-Bbo01M7P.d.mts +76 -0
  153. package/dist/server/types-Bbo01M7P.d.ts +76 -0
  154. package/dist/server/types-C6gmRHLe.d.mts +150 -0
  155. package/dist/server/types-C6gmRHLe.d.ts +150 -0
  156. package/package.json +147 -0
  157. package/src/styles/index.css +10 -0
@@ -0,0 +1,197 @@
1
+ "use client";
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/analytics/index.ts
22
+ var analytics_exports = {};
23
+ __export(analytics_exports, {
24
+ AnalyticsBootstrap: () => AnalyticsBootstrap,
25
+ useAnalytics: () => useAnalytics
26
+ });
27
+ module.exports = __toCommonJS(analytics_exports);
28
+
29
+ // src/analytics/AnalyticsBootstrap.tsx
30
+ var import_react = require("react");
31
+ function AnalyticsBootstrap(config) {
32
+ useAnalytics(config);
33
+ return null;
34
+ }
35
+ function useAnalytics(config) {
36
+ const siteId = config?.siteId ?? null;
37
+ const siteSlug = config?.siteSlug ?? "";
38
+ const endpoint = config?.endpoint ?? "/api/analytics/collect";
39
+ const sessionCookieName = config?.sessionCookieName ?? "builder_analytics_session";
40
+ const disabled = config?.disabled ?? false;
41
+ const activeConfig = (0, import_react.useMemo)(() => {
42
+ if (!siteId || disabled) {
43
+ return null;
44
+ }
45
+ return { siteId, siteSlug, endpoint, sessionCookieName };
46
+ }, [disabled, endpoint, sessionCookieName, siteId, siteSlug]);
47
+ const stateRef = (0, import_react.useRef)({
48
+ client: null,
49
+ queue: []
50
+ });
51
+ const configRef = (0, import_react.useRef)(null);
52
+ configRef.current = activeConfig;
53
+ const enqueue = (0, import_react.useCallback)((action) => {
54
+ if (!configRef.current) return;
55
+ const state = stateRef.current;
56
+ if (state.client) {
57
+ action(state.client);
58
+ return;
59
+ }
60
+ state.queue.push(action);
61
+ }, []);
62
+ (0, import_react.useEffect)(() => {
63
+ const state = stateRef.current;
64
+ if (!activeConfig) {
65
+ if (state.client) {
66
+ state.client.destroy();
67
+ state.client = null;
68
+ }
69
+ state.queue = [];
70
+ return;
71
+ }
72
+ const configSnapshot = activeConfig;
73
+ let disposed = false;
74
+ async function start() {
75
+ try {
76
+ const client = createMinimalAnalyticsClient({
77
+ siteId: configSnapshot.siteId,
78
+ siteSlug: configSnapshot.siteSlug,
79
+ endpoint: configSnapshot.endpoint,
80
+ sessionCookieName: configSnapshot.sessionCookieName
81
+ });
82
+ if (disposed) return;
83
+ state.client = client;
84
+ if (state.queue.length > 0) {
85
+ const pending = state.queue.splice(0);
86
+ for (const action of pending) action(client);
87
+ }
88
+ await client.track({
89
+ eventType: "page_view",
90
+ metadata: { path: window.location.pathname }
91
+ });
92
+ } catch (error) {
93
+ console.warn("[analytics] Failed to initialize client", error);
94
+ }
95
+ }
96
+ start();
97
+ return () => {
98
+ disposed = true;
99
+ if (state.client) {
100
+ state.client.destroy();
101
+ state.client = null;
102
+ }
103
+ state.queue = [];
104
+ };
105
+ }, [activeConfig]);
106
+ const trackEvent = (0, import_react.useCallback)(
107
+ (event) => {
108
+ enqueue((client) => void client.track(event));
109
+ },
110
+ [enqueue]
111
+ );
112
+ const trackCtaClick = (0, import_react.useCallback)(
113
+ (metadata) => {
114
+ enqueue((client) => void client.trackCtaClick(metadata));
115
+ },
116
+ [enqueue]
117
+ );
118
+ const trackFormSubmit = (0, import_react.useCallback)(
119
+ (metadata) => {
120
+ enqueue((client) => void client.trackFormSubmit(metadata));
121
+ },
122
+ [enqueue]
123
+ );
124
+ return (0, import_react.useMemo)(
125
+ () => ({ trackEvent, trackCtaClick, trackFormSubmit }),
126
+ [trackEvent, trackCtaClick, trackFormSubmit]
127
+ );
128
+ }
129
+ function createMinimalAnalyticsClient(config) {
130
+ let sessionId = null;
131
+ const cookies = document.cookie.split(";");
132
+ for (const cookie of cookies) {
133
+ const [name, value] = cookie.trim().split("=");
134
+ if (name === config.sessionCookieName) {
135
+ sessionId = value;
136
+ break;
137
+ }
138
+ }
139
+ if (!sessionId) {
140
+ sessionId = generateSessionId();
141
+ const expires = new Date(Date.now() + 30 * 24 * 60 * 60 * 1e3);
142
+ document.cookie = `${config.sessionCookieName}=${sessionId}; expires=${expires.toUTCString()}; path=/; SameSite=Lax`;
143
+ }
144
+ const track = async (event) => {
145
+ try {
146
+ await fetch(config.endpoint, {
147
+ method: "POST",
148
+ headers: {
149
+ "Content-Type": "application/json"
150
+ },
151
+ body: JSON.stringify({
152
+ siteId: config.siteId,
153
+ siteSlug: config.siteSlug,
154
+ sessionId,
155
+ eventType: event.eventType,
156
+ metadata: {
157
+ ...event.metadata,
158
+ userAgent: navigator.userAgent,
159
+ referrer: document.referrer,
160
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
161
+ }
162
+ })
163
+ });
164
+ } catch (error) {
165
+ console.warn("[analytics] Failed to track event", error);
166
+ }
167
+ };
168
+ const trackCtaClick = async (metadata) => {
169
+ await track({
170
+ eventType: "cta_click",
171
+ metadata
172
+ });
173
+ };
174
+ const trackFormSubmit = async (metadata) => {
175
+ await track({
176
+ eventType: "form_submit",
177
+ metadata
178
+ });
179
+ };
180
+ const destroy = () => {
181
+ };
182
+ return {
183
+ track,
184
+ trackCtaClick,
185
+ trackFormSubmit,
186
+ destroy
187
+ };
188
+ }
189
+ function generateSessionId() {
190
+ return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;
191
+ }
192
+ // Annotate the CommonJS export names for ESM import in node:
193
+ 0 && (module.exports = {
194
+ AnalyticsBootstrap,
195
+ useAnalytics
196
+ });
197
+ //# sourceMappingURL=analytics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/analytics/index.ts","../../src/analytics/AnalyticsBootstrap.tsx"],"sourcesContent":["/**\n * Analytics utilities for tracking user behavior\n *\n * Lightweight analytics helpers for tracking page views, CTA clicks,\n * form submissions, and custom events.\n */\n\nexport { AnalyticsBootstrap, useAnalytics } from './AnalyticsBootstrap';\nexport type {\n AnalyticsConfig,\n AnalyticsClient,\n AnalyticsHelpers,\n TrackEventInput,\n} from './AnalyticsBootstrap';\n","/**\n * Analytics Bootstrap Component\n *\n * Client component that initializes analytics tracking for a Builder site.\n * Auto-tracks page views and provides helpers for tracking custom events.\n */\n\n'use client';\n\nimport { useCallback, useEffect, useMemo, useRef } from 'react';\n\nexport type AnalyticsConfig = {\n /**\n * Site ID for analytics tracking\n */\n siteId: string;\n\n /**\n * Site slug for analytics tracking\n */\n siteSlug: string;\n\n /**\n * Analytics endpoint URL\n * @default '/api/analytics/collect'\n */\n endpoint?: string;\n\n /**\n * Custom session cookie name\n * @default 'builder_analytics_session'\n */\n sessionCookieName?: string;\n\n /**\n * Disable analytics tracking\n * @default false\n */\n disabled?: boolean;\n};\n\nexport type AnalyticsClient = {\n track: (event: TrackEventInput) => Promise<void>;\n trackCtaClick: (metadata?: Record<string, unknown>) => Promise<void>;\n trackFormSubmit: (metadata?: Record<string, unknown>) => Promise<void>;\n destroy: () => void;\n};\n\nexport type TrackEventInput = {\n eventType: string;\n metadata?: Record<string, unknown>;\n};\n\n/**\n * Analytics helpers returned by useAnalytics hook\n */\nexport type AnalyticsHelpers = {\n trackEvent: (event: TrackEventInput) => void;\n trackCtaClick: (metadata?: Record<string, unknown>) => void;\n trackFormSubmit: (metadata?: Record<string, unknown>) => void;\n};\n\n/**\n * Analytics Bootstrap component\n *\n * Place this component in your layout to enable analytics tracking.\n *\n * @example\n * ```tsx\n * import { AnalyticsBootstrap } from '@riverbankcms/sdk/analytics';\n *\n * export default function Layout({ children }) {\n * return (\n * <html>\n * <body>\n * {children}\n * <AnalyticsBootstrap\n * siteId=\"your-site-id\"\n * siteSlug=\"your-site-slug\"\n * />\n * </body>\n * </html>\n * );\n * }\n * ```\n */\nexport function AnalyticsBootstrap(config: AnalyticsConfig) {\n useAnalytics(config);\n\n // Component renders nothing, analytics runs in background\n return null;\n}\n\n/**\n * Hook for tracking analytics events\n *\n * @param config - Analytics configuration. Pass null to disable analytics.\n * @returns Analytics helpers for tracking events\n *\n * @example\n * ```tsx\n * 'use client';\n *\n * import { useAnalytics } from '@riverbankcms/sdk/analytics';\n *\n * export function MyComponent() {\n * const analytics = useAnalytics({\n * siteId: 'your-site-id',\n * siteSlug: 'your-site-slug',\n * });\n *\n * const handleClick = () => {\n * analytics.trackCtaClick({ buttonLabel: 'Sign Up' });\n * };\n *\n * return <button onClick={handleClick}>Sign Up</button>;\n * }\n * ```\n */\nexport function useAnalytics(config: AnalyticsConfig | null): AnalyticsHelpers {\n const siteId = config?.siteId ?? null;\n const siteSlug = config?.siteSlug ?? '';\n const endpoint = config?.endpoint ?? '/api/analytics/collect';\n const sessionCookieName = config?.sessionCookieName ?? 'builder_analytics_session';\n const disabled = config?.disabled ?? false;\n\n const activeConfig = useMemo(() => {\n if (!siteId || disabled) {\n return null;\n }\n return { siteId, siteSlug, endpoint, sessionCookieName };\n }, [disabled, endpoint, sessionCookieName, siteId, siteSlug]);\n\n const stateRef = useRef<{\n client: AnalyticsClient | null;\n queue: Array<(client: AnalyticsClient) => void>;\n }>({\n client: null,\n queue: [],\n });\n\n const configRef = useRef<typeof activeConfig>(null);\n configRef.current = activeConfig;\n\n const enqueue = useCallback((action: (client: AnalyticsClient) => void) => {\n if (!configRef.current) return;\n const state = stateRef.current;\n if (state.client) {\n action(state.client);\n return;\n }\n state.queue.push(action);\n }, []);\n\n useEffect(() => {\n const state = stateRef.current;\n\n if (!activeConfig) {\n if (state.client) {\n state.client.destroy();\n state.client = null;\n }\n state.queue = [];\n return;\n }\n\n const configSnapshot = activeConfig;\n let disposed = false;\n\n async function start() {\n try {\n // Create minimal analytics client\n const client = createMinimalAnalyticsClient({\n siteId: configSnapshot.siteId,\n siteSlug: configSnapshot.siteSlug,\n endpoint: configSnapshot.endpoint,\n sessionCookieName: configSnapshot.sessionCookieName,\n });\n\n if (disposed) return;\n\n state.client = client;\n\n // Flush queued events\n if (state.queue.length > 0) {\n const pending = state.queue.splice(0);\n for (const action of pending) action(client);\n }\n\n // Auto-track initial page view\n await client.track({\n eventType: 'page_view',\n metadata: { path: window.location.pathname },\n });\n } catch (error) {\n console.warn('[analytics] Failed to initialize client', error);\n }\n }\n\n start();\n\n return () => {\n disposed = true;\n if (state.client) {\n state.client.destroy();\n state.client = null;\n }\n state.queue = [];\n };\n }, [activeConfig]);\n\n const trackEvent = useCallback(\n (event: TrackEventInput) => {\n enqueue((client) => void client.track(event));\n },\n [enqueue]\n );\n\n const trackCtaClick = useCallback(\n (metadata?: Record<string, unknown>) => {\n enqueue((client) => void client.trackCtaClick(metadata));\n },\n [enqueue]\n );\n\n const trackFormSubmit = useCallback(\n (metadata?: Record<string, unknown>) => {\n enqueue((client) => void client.trackFormSubmit(metadata));\n },\n [enqueue]\n );\n\n return useMemo(\n () => ({ trackEvent, trackCtaClick, trackFormSubmit }),\n [trackEvent, trackCtaClick, trackFormSubmit]\n );\n}\n\n/**\n * Create a minimal analytics client\n *\n * This is a lightweight implementation for tracking basic events.\n * For full analytics features, use @riverbankcms/analytics package.\n */\nfunction createMinimalAnalyticsClient(config: {\n siteId: string;\n siteSlug: string;\n endpoint: string;\n sessionCookieName: string;\n}): AnalyticsClient {\n let sessionId: string | null = null;\n\n // Try to read existing session from cookie\n const cookies = document.cookie.split(';');\n for (const cookie of cookies) {\n const [name, value] = cookie.trim().split('=');\n if (name === config.sessionCookieName) {\n sessionId = value;\n break;\n }\n }\n\n // Generate new session if needed\n if (!sessionId) {\n sessionId = generateSessionId();\n // Set cookie for 30 days\n const expires = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);\n document.cookie = `${config.sessionCookieName}=${sessionId}; expires=${expires.toUTCString()}; path=/; SameSite=Lax`;\n }\n\n const track = async (event: TrackEventInput) => {\n try {\n await fetch(config.endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n siteId: config.siteId,\n siteSlug: config.siteSlug,\n sessionId,\n eventType: event.eventType,\n metadata: {\n ...event.metadata,\n userAgent: navigator.userAgent,\n referrer: document.referrer,\n timestamp: new Date().toISOString(),\n },\n }),\n });\n } catch (error) {\n console.warn('[analytics] Failed to track event', error);\n }\n };\n\n const trackCtaClick = async (metadata?: Record<string, unknown>) => {\n await track({\n eventType: 'cta_click',\n metadata,\n });\n };\n\n const trackFormSubmit = async (metadata?: Record<string, unknown>) => {\n await track({\n eventType: 'form_submit',\n metadata,\n });\n };\n\n const destroy = () => {\n // Cleanup if needed\n };\n\n return {\n track,\n trackCtaClick,\n trackFormSubmit,\n destroy,\n };\n}\n\n/**\n * Generate a random session ID\n */\nfunction generateSessionId(): string {\n return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACSA,mBAAwD;AA6EjD,SAAS,mBAAmB,QAAyB;AAC1D,eAAa,MAAM;AAGnB,SAAO;AACT;AA4BO,SAAS,aAAa,QAAkD;AAC7E,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,oBAAoB,QAAQ,qBAAqB;AACvD,QAAM,WAAW,QAAQ,YAAY;AAErC,QAAM,mBAAe,sBAAQ,MAAM;AACjC,QAAI,CAAC,UAAU,UAAU;AACvB,aAAO;AAAA,IACT;AACA,WAAO,EAAE,QAAQ,UAAU,UAAU,kBAAkB;AAAA,EACzD,GAAG,CAAC,UAAU,UAAU,mBAAmB,QAAQ,QAAQ,CAAC;AAE5D,QAAM,eAAW,qBAGd;AAAA,IACD,QAAQ;AAAA,IACR,OAAO,CAAC;AAAA,EACV,CAAC;AAED,QAAM,gBAAY,qBAA4B,IAAI;AAClD,YAAU,UAAU;AAEpB,QAAM,cAAU,0BAAY,CAAC,WAA8C;AACzE,QAAI,CAAC,UAAU,QAAS;AACxB,UAAM,QAAQ,SAAS;AACvB,QAAI,MAAM,QAAQ;AAChB,aAAO,MAAM,MAAM;AACnB;AAAA,IACF;AACA,UAAM,MAAM,KAAK,MAAM;AAAA,EACzB,GAAG,CAAC,CAAC;AAEL,8BAAU,MAAM;AACd,UAAM,QAAQ,SAAS;AAEvB,QAAI,CAAC,cAAc;AACjB,UAAI,MAAM,QAAQ;AAChB,cAAM,OAAO,QAAQ;AACrB,cAAM,SAAS;AAAA,MACjB;AACA,YAAM,QAAQ,CAAC;AACf;AAAA,IACF;AAEA,UAAM,iBAAiB;AACvB,QAAI,WAAW;AAEf,mBAAe,QAAQ;AACrB,UAAI;AAEF,cAAM,SAAS,6BAA6B;AAAA,UAC1C,QAAQ,eAAe;AAAA,UACvB,UAAU,eAAe;AAAA,UACzB,UAAU,eAAe;AAAA,UACzB,mBAAmB,eAAe;AAAA,QACpC,CAAC;AAED,YAAI,SAAU;AAEd,cAAM,SAAS;AAGf,YAAI,MAAM,MAAM,SAAS,GAAG;AAC1B,gBAAM,UAAU,MAAM,MAAM,OAAO,CAAC;AACpC,qBAAW,UAAU,QAAS,QAAO,MAAM;AAAA,QAC7C;AAGA,cAAM,OAAO,MAAM;AAAA,UACjB,WAAW;AAAA,UACX,UAAU,EAAE,MAAM,OAAO,SAAS,SAAS;AAAA,QAC7C,CAAC;AAAA,MACH,SAAS,OAAO;AACd,gBAAQ,KAAK,2CAA2C,KAAK;AAAA,MAC/D;AAAA,IACF;AAEA,UAAM;AAEN,WAAO,MAAM;AACX,iBAAW;AACX,UAAI,MAAM,QAAQ;AAChB,cAAM,OAAO,QAAQ;AACrB,cAAM,SAAS;AAAA,MACjB;AACA,YAAM,QAAQ,CAAC;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,YAAY,CAAC;AAEjB,QAAM,iBAAa;AAAA,IACjB,CAAC,UAA2B;AAC1B,cAAQ,CAAC,WAAW,KAAK,OAAO,MAAM,KAAK,CAAC;AAAA,IAC9C;AAAA,IACA,CAAC,OAAO;AAAA,EACV;AAEA,QAAM,oBAAgB;AAAA,IACpB,CAAC,aAAuC;AACtC,cAAQ,CAAC,WAAW,KAAK,OAAO,cAAc,QAAQ,CAAC;AAAA,IACzD;AAAA,IACA,CAAC,OAAO;AAAA,EACV;AAEA,QAAM,sBAAkB;AAAA,IACtB,CAAC,aAAuC;AACtC,cAAQ,CAAC,WAAW,KAAK,OAAO,gBAAgB,QAAQ,CAAC;AAAA,IAC3D;AAAA,IACA,CAAC,OAAO;AAAA,EACV;AAEA,aAAO;AAAA,IACL,OAAO,EAAE,YAAY,eAAe,gBAAgB;AAAA,IACpD,CAAC,YAAY,eAAe,eAAe;AAAA,EAC7C;AACF;AAQA,SAAS,6BAA6B,QAKlB;AAClB,MAAI,YAA2B;AAG/B,QAAM,UAAU,SAAS,OAAO,MAAM,GAAG;AACzC,aAAW,UAAU,SAAS;AAC5B,UAAM,CAAC,MAAM,KAAK,IAAI,OAAO,KAAK,EAAE,MAAM,GAAG;AAC7C,QAAI,SAAS,OAAO,mBAAmB;AACrC,kBAAY;AACZ;AAAA,IACF;AAAA,EACF;AAGA,MAAI,CAAC,WAAW;AACd,gBAAY,kBAAkB;AAE9B,UAAM,UAAU,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,KAAK,GAAI;AAC9D,aAAS,SAAS,GAAG,OAAO,iBAAiB,IAAI,SAAS,aAAa,QAAQ,YAAY,CAAC;AAAA,EAC9F;AAEA,QAAM,QAAQ,OAAO,UAA2B;AAC9C,QAAI;AACF,YAAM,MAAM,OAAO,UAAU;AAAA,QAC3B,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB,QAAQ,OAAO;AAAA,UACf,UAAU,OAAO;AAAA,UACjB;AAAA,UACA,WAAW,MAAM;AAAA,UACjB,UAAU;AAAA,YACR,GAAG,MAAM;AAAA,YACT,WAAW,UAAU;AAAA,YACrB,UAAU,SAAS;AAAA,YACnB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,UACpC;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAAA,IACH,SAAS,OAAO;AACd,cAAQ,KAAK,qCAAqC,KAAK;AAAA,IACzD;AAAA,EACF;AAEA,QAAM,gBAAgB,OAAO,aAAuC;AAClE,UAAM,MAAM;AAAA,MACV,WAAW;AAAA,MACX;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,kBAAkB,OAAO,aAAuC;AACpE,UAAM,MAAM;AAAA,MACV,WAAW;AAAA,MACX;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,UAAU,MAAM;AAAA,EAEtB;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAKA,SAAS,oBAA4B;AACnC,SAAO,GAAG,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,EAAE,CAAC;AACrE;","names":[]}
@@ -0,0 +1,169 @@
1
+ "use client";
2
+ // src/analytics/AnalyticsBootstrap.tsx
3
+ import { useCallback, useEffect, useMemo, useRef } from "react";
4
+ function AnalyticsBootstrap(config) {
5
+ useAnalytics(config);
6
+ return null;
7
+ }
8
+ function useAnalytics(config) {
9
+ const siteId = config?.siteId ?? null;
10
+ const siteSlug = config?.siteSlug ?? "";
11
+ const endpoint = config?.endpoint ?? "/api/analytics/collect";
12
+ const sessionCookieName = config?.sessionCookieName ?? "builder_analytics_session";
13
+ const disabled = config?.disabled ?? false;
14
+ const activeConfig = useMemo(() => {
15
+ if (!siteId || disabled) {
16
+ return null;
17
+ }
18
+ return { siteId, siteSlug, endpoint, sessionCookieName };
19
+ }, [disabled, endpoint, sessionCookieName, siteId, siteSlug]);
20
+ const stateRef = useRef({
21
+ client: null,
22
+ queue: []
23
+ });
24
+ const configRef = useRef(null);
25
+ configRef.current = activeConfig;
26
+ const enqueue = useCallback((action) => {
27
+ if (!configRef.current) return;
28
+ const state = stateRef.current;
29
+ if (state.client) {
30
+ action(state.client);
31
+ return;
32
+ }
33
+ state.queue.push(action);
34
+ }, []);
35
+ useEffect(() => {
36
+ const state = stateRef.current;
37
+ if (!activeConfig) {
38
+ if (state.client) {
39
+ state.client.destroy();
40
+ state.client = null;
41
+ }
42
+ state.queue = [];
43
+ return;
44
+ }
45
+ const configSnapshot = activeConfig;
46
+ let disposed = false;
47
+ async function start() {
48
+ try {
49
+ const client = createMinimalAnalyticsClient({
50
+ siteId: configSnapshot.siteId,
51
+ siteSlug: configSnapshot.siteSlug,
52
+ endpoint: configSnapshot.endpoint,
53
+ sessionCookieName: configSnapshot.sessionCookieName
54
+ });
55
+ if (disposed) return;
56
+ state.client = client;
57
+ if (state.queue.length > 0) {
58
+ const pending = state.queue.splice(0);
59
+ for (const action of pending) action(client);
60
+ }
61
+ await client.track({
62
+ eventType: "page_view",
63
+ metadata: { path: window.location.pathname }
64
+ });
65
+ } catch (error) {
66
+ console.warn("[analytics] Failed to initialize client", error);
67
+ }
68
+ }
69
+ start();
70
+ return () => {
71
+ disposed = true;
72
+ if (state.client) {
73
+ state.client.destroy();
74
+ state.client = null;
75
+ }
76
+ state.queue = [];
77
+ };
78
+ }, [activeConfig]);
79
+ const trackEvent = useCallback(
80
+ (event) => {
81
+ enqueue((client) => void client.track(event));
82
+ },
83
+ [enqueue]
84
+ );
85
+ const trackCtaClick = useCallback(
86
+ (metadata) => {
87
+ enqueue((client) => void client.trackCtaClick(metadata));
88
+ },
89
+ [enqueue]
90
+ );
91
+ const trackFormSubmit = useCallback(
92
+ (metadata) => {
93
+ enqueue((client) => void client.trackFormSubmit(metadata));
94
+ },
95
+ [enqueue]
96
+ );
97
+ return useMemo(
98
+ () => ({ trackEvent, trackCtaClick, trackFormSubmit }),
99
+ [trackEvent, trackCtaClick, trackFormSubmit]
100
+ );
101
+ }
102
+ function createMinimalAnalyticsClient(config) {
103
+ let sessionId = null;
104
+ const cookies = document.cookie.split(";");
105
+ for (const cookie of cookies) {
106
+ const [name, value] = cookie.trim().split("=");
107
+ if (name === config.sessionCookieName) {
108
+ sessionId = value;
109
+ break;
110
+ }
111
+ }
112
+ if (!sessionId) {
113
+ sessionId = generateSessionId();
114
+ const expires = new Date(Date.now() + 30 * 24 * 60 * 60 * 1e3);
115
+ document.cookie = `${config.sessionCookieName}=${sessionId}; expires=${expires.toUTCString()}; path=/; SameSite=Lax`;
116
+ }
117
+ const track = async (event) => {
118
+ try {
119
+ await fetch(config.endpoint, {
120
+ method: "POST",
121
+ headers: {
122
+ "Content-Type": "application/json"
123
+ },
124
+ body: JSON.stringify({
125
+ siteId: config.siteId,
126
+ siteSlug: config.siteSlug,
127
+ sessionId,
128
+ eventType: event.eventType,
129
+ metadata: {
130
+ ...event.metadata,
131
+ userAgent: navigator.userAgent,
132
+ referrer: document.referrer,
133
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
134
+ }
135
+ })
136
+ });
137
+ } catch (error) {
138
+ console.warn("[analytics] Failed to track event", error);
139
+ }
140
+ };
141
+ const trackCtaClick = async (metadata) => {
142
+ await track({
143
+ eventType: "cta_click",
144
+ metadata
145
+ });
146
+ };
147
+ const trackFormSubmit = async (metadata) => {
148
+ await track({
149
+ eventType: "form_submit",
150
+ metadata
151
+ });
152
+ };
153
+ const destroy = () => {
154
+ };
155
+ return {
156
+ track,
157
+ trackCtaClick,
158
+ trackFormSubmit,
159
+ destroy
160
+ };
161
+ }
162
+ function generateSessionId() {
163
+ return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;
164
+ }
165
+ export {
166
+ AnalyticsBootstrap,
167
+ useAnalytics
168
+ };
169
+ //# sourceMappingURL=analytics.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/analytics/AnalyticsBootstrap.tsx"],"sourcesContent":["/**\n * Analytics Bootstrap Component\n *\n * Client component that initializes analytics tracking for a Builder site.\n * Auto-tracks page views and provides helpers for tracking custom events.\n */\n\n'use client';\n\nimport { useCallback, useEffect, useMemo, useRef } from 'react';\n\nexport type AnalyticsConfig = {\n /**\n * Site ID for analytics tracking\n */\n siteId: string;\n\n /**\n * Site slug for analytics tracking\n */\n siteSlug: string;\n\n /**\n * Analytics endpoint URL\n * @default '/api/analytics/collect'\n */\n endpoint?: string;\n\n /**\n * Custom session cookie name\n * @default 'builder_analytics_session'\n */\n sessionCookieName?: string;\n\n /**\n * Disable analytics tracking\n * @default false\n */\n disabled?: boolean;\n};\n\nexport type AnalyticsClient = {\n track: (event: TrackEventInput) => Promise<void>;\n trackCtaClick: (metadata?: Record<string, unknown>) => Promise<void>;\n trackFormSubmit: (metadata?: Record<string, unknown>) => Promise<void>;\n destroy: () => void;\n};\n\nexport type TrackEventInput = {\n eventType: string;\n metadata?: Record<string, unknown>;\n};\n\n/**\n * Analytics helpers returned by useAnalytics hook\n */\nexport type AnalyticsHelpers = {\n trackEvent: (event: TrackEventInput) => void;\n trackCtaClick: (metadata?: Record<string, unknown>) => void;\n trackFormSubmit: (metadata?: Record<string, unknown>) => void;\n};\n\n/**\n * Analytics Bootstrap component\n *\n * Place this component in your layout to enable analytics tracking.\n *\n * @example\n * ```tsx\n * import { AnalyticsBootstrap } from '@riverbankcms/sdk/analytics';\n *\n * export default function Layout({ children }) {\n * return (\n * <html>\n * <body>\n * {children}\n * <AnalyticsBootstrap\n * siteId=\"your-site-id\"\n * siteSlug=\"your-site-slug\"\n * />\n * </body>\n * </html>\n * );\n * }\n * ```\n */\nexport function AnalyticsBootstrap(config: AnalyticsConfig) {\n useAnalytics(config);\n\n // Component renders nothing, analytics runs in background\n return null;\n}\n\n/**\n * Hook for tracking analytics events\n *\n * @param config - Analytics configuration. Pass null to disable analytics.\n * @returns Analytics helpers for tracking events\n *\n * @example\n * ```tsx\n * 'use client';\n *\n * import { useAnalytics } from '@riverbankcms/sdk/analytics';\n *\n * export function MyComponent() {\n * const analytics = useAnalytics({\n * siteId: 'your-site-id',\n * siteSlug: 'your-site-slug',\n * });\n *\n * const handleClick = () => {\n * analytics.trackCtaClick({ buttonLabel: 'Sign Up' });\n * };\n *\n * return <button onClick={handleClick}>Sign Up</button>;\n * }\n * ```\n */\nexport function useAnalytics(config: AnalyticsConfig | null): AnalyticsHelpers {\n const siteId = config?.siteId ?? null;\n const siteSlug = config?.siteSlug ?? '';\n const endpoint = config?.endpoint ?? '/api/analytics/collect';\n const sessionCookieName = config?.sessionCookieName ?? 'builder_analytics_session';\n const disabled = config?.disabled ?? false;\n\n const activeConfig = useMemo(() => {\n if (!siteId || disabled) {\n return null;\n }\n return { siteId, siteSlug, endpoint, sessionCookieName };\n }, [disabled, endpoint, sessionCookieName, siteId, siteSlug]);\n\n const stateRef = useRef<{\n client: AnalyticsClient | null;\n queue: Array<(client: AnalyticsClient) => void>;\n }>({\n client: null,\n queue: [],\n });\n\n const configRef = useRef<typeof activeConfig>(null);\n configRef.current = activeConfig;\n\n const enqueue = useCallback((action: (client: AnalyticsClient) => void) => {\n if (!configRef.current) return;\n const state = stateRef.current;\n if (state.client) {\n action(state.client);\n return;\n }\n state.queue.push(action);\n }, []);\n\n useEffect(() => {\n const state = stateRef.current;\n\n if (!activeConfig) {\n if (state.client) {\n state.client.destroy();\n state.client = null;\n }\n state.queue = [];\n return;\n }\n\n const configSnapshot = activeConfig;\n let disposed = false;\n\n async function start() {\n try {\n // Create minimal analytics client\n const client = createMinimalAnalyticsClient({\n siteId: configSnapshot.siteId,\n siteSlug: configSnapshot.siteSlug,\n endpoint: configSnapshot.endpoint,\n sessionCookieName: configSnapshot.sessionCookieName,\n });\n\n if (disposed) return;\n\n state.client = client;\n\n // Flush queued events\n if (state.queue.length > 0) {\n const pending = state.queue.splice(0);\n for (const action of pending) action(client);\n }\n\n // Auto-track initial page view\n await client.track({\n eventType: 'page_view',\n metadata: { path: window.location.pathname },\n });\n } catch (error) {\n console.warn('[analytics] Failed to initialize client', error);\n }\n }\n\n start();\n\n return () => {\n disposed = true;\n if (state.client) {\n state.client.destroy();\n state.client = null;\n }\n state.queue = [];\n };\n }, [activeConfig]);\n\n const trackEvent = useCallback(\n (event: TrackEventInput) => {\n enqueue((client) => void client.track(event));\n },\n [enqueue]\n );\n\n const trackCtaClick = useCallback(\n (metadata?: Record<string, unknown>) => {\n enqueue((client) => void client.trackCtaClick(metadata));\n },\n [enqueue]\n );\n\n const trackFormSubmit = useCallback(\n (metadata?: Record<string, unknown>) => {\n enqueue((client) => void client.trackFormSubmit(metadata));\n },\n [enqueue]\n );\n\n return useMemo(\n () => ({ trackEvent, trackCtaClick, trackFormSubmit }),\n [trackEvent, trackCtaClick, trackFormSubmit]\n );\n}\n\n/**\n * Create a minimal analytics client\n *\n * This is a lightweight implementation for tracking basic events.\n * For full analytics features, use @riverbankcms/analytics package.\n */\nfunction createMinimalAnalyticsClient(config: {\n siteId: string;\n siteSlug: string;\n endpoint: string;\n sessionCookieName: string;\n}): AnalyticsClient {\n let sessionId: string | null = null;\n\n // Try to read existing session from cookie\n const cookies = document.cookie.split(';');\n for (const cookie of cookies) {\n const [name, value] = cookie.trim().split('=');\n if (name === config.sessionCookieName) {\n sessionId = value;\n break;\n }\n }\n\n // Generate new session if needed\n if (!sessionId) {\n sessionId = generateSessionId();\n // Set cookie for 30 days\n const expires = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);\n document.cookie = `${config.sessionCookieName}=${sessionId}; expires=${expires.toUTCString()}; path=/; SameSite=Lax`;\n }\n\n const track = async (event: TrackEventInput) => {\n try {\n await fetch(config.endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n siteId: config.siteId,\n siteSlug: config.siteSlug,\n sessionId,\n eventType: event.eventType,\n metadata: {\n ...event.metadata,\n userAgent: navigator.userAgent,\n referrer: document.referrer,\n timestamp: new Date().toISOString(),\n },\n }),\n });\n } catch (error) {\n console.warn('[analytics] Failed to track event', error);\n }\n };\n\n const trackCtaClick = async (metadata?: Record<string, unknown>) => {\n await track({\n eventType: 'cta_click',\n metadata,\n });\n };\n\n const trackFormSubmit = async (metadata?: Record<string, unknown>) => {\n await track({\n eventType: 'form_submit',\n metadata,\n });\n };\n\n const destroy = () => {\n // Cleanup if needed\n };\n\n return {\n track,\n trackCtaClick,\n trackFormSubmit,\n destroy,\n };\n}\n\n/**\n * Generate a random session ID\n */\nfunction generateSessionId(): string {\n return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,89 @@
1
+ export { BookingFormClient, BookingFormConfig, BookingService, useBookingFormConfig } from '@riverbankcms/blocks/client';
2
+
3
+ /**
4
+ * Booking types for SDK consumers
5
+ *
6
+ * These types are exported for SDK sites to use when building custom booking UIs.
7
+ */
8
+ /**
9
+ * A bookable service (e.g., "30-minute consultation", "Hair cut")
10
+ * Note: Aligned with @riverbankcms/blocks Service type
11
+ */
12
+ interface Service {
13
+ id: string;
14
+ title: string;
15
+ description?: string;
16
+ durationMinutes?: number;
17
+ }
18
+ /**
19
+ * An available time slot for booking
20
+ */
21
+ interface TimeSlot {
22
+ startAt: string;
23
+ endAt: string;
24
+ resourceId: string;
25
+ }
26
+ /**
27
+ * Settings for a booking form
28
+ */
29
+ interface BookingFormSettings {
30
+ type: 'booking';
31
+ serviceId?: string;
32
+ serviceIds?: string[];
33
+ resourceId?: string;
34
+ requiresApproval?: boolean;
35
+ successMessage?: string;
36
+ }
37
+ /**
38
+ * Schema for custom fields in a booking form
39
+ */
40
+ interface BookingFormSchema {
41
+ version: string;
42
+ fields: BookingFormField[];
43
+ }
44
+ /**
45
+ * A field in the booking form schema
46
+ */
47
+ interface BookingFormField {
48
+ id: string;
49
+ type: 'text' | 'email' | 'phone' | 'select' | 'textarea' | 'checkbox';
50
+ label: string;
51
+ required?: boolean;
52
+ placeholder?: string;
53
+ options?: Array<{
54
+ label: string;
55
+ value: string;
56
+ }>;
57
+ }
58
+ /**
59
+ * Data collected during the booking flow
60
+ */
61
+ interface BookingFormData {
62
+ serviceId?: string;
63
+ resourceId?: string;
64
+ selectedDate?: string;
65
+ selectedSlot?: string;
66
+ [key: string]: unknown;
67
+ }
68
+ /**
69
+ * Data submitted to create a booking
70
+ */
71
+ interface BookingSubmissionData {
72
+ formId: string;
73
+ serviceId: string;
74
+ resourceId?: string;
75
+ startAt: string;
76
+ endAt: string;
77
+ customFields: Record<string, unknown>;
78
+ timezone: string;
79
+ }
80
+ /**
81
+ * Result of a booking submission
82
+ */
83
+ interface BookingSubmissionResult {
84
+ success: boolean;
85
+ appointmentId?: string;
86
+ error?: string;
87
+ }
88
+
89
+ export type { BookingFormData, BookingFormField, BookingFormSchema, BookingFormSettings, BookingSubmissionData, BookingSubmissionResult, Service, TimeSlot };
@@ -0,0 +1,89 @@
1
+ export { BookingFormClient, BookingFormConfig, BookingService, useBookingFormConfig } from '@riverbankcms/blocks/client';
2
+
3
+ /**
4
+ * Booking types for SDK consumers
5
+ *
6
+ * These types are exported for SDK sites to use when building custom booking UIs.
7
+ */
8
+ /**
9
+ * A bookable service (e.g., "30-minute consultation", "Hair cut")
10
+ * Note: Aligned with @riverbankcms/blocks Service type
11
+ */
12
+ interface Service {
13
+ id: string;
14
+ title: string;
15
+ description?: string;
16
+ durationMinutes?: number;
17
+ }
18
+ /**
19
+ * An available time slot for booking
20
+ */
21
+ interface TimeSlot {
22
+ startAt: string;
23
+ endAt: string;
24
+ resourceId: string;
25
+ }
26
+ /**
27
+ * Settings for a booking form
28
+ */
29
+ interface BookingFormSettings {
30
+ type: 'booking';
31
+ serviceId?: string;
32
+ serviceIds?: string[];
33
+ resourceId?: string;
34
+ requiresApproval?: boolean;
35
+ successMessage?: string;
36
+ }
37
+ /**
38
+ * Schema for custom fields in a booking form
39
+ */
40
+ interface BookingFormSchema {
41
+ version: string;
42
+ fields: BookingFormField[];
43
+ }
44
+ /**
45
+ * A field in the booking form schema
46
+ */
47
+ interface BookingFormField {
48
+ id: string;
49
+ type: 'text' | 'email' | 'phone' | 'select' | 'textarea' | 'checkbox';
50
+ label: string;
51
+ required?: boolean;
52
+ placeholder?: string;
53
+ options?: Array<{
54
+ label: string;
55
+ value: string;
56
+ }>;
57
+ }
58
+ /**
59
+ * Data collected during the booking flow
60
+ */
61
+ interface BookingFormData {
62
+ serviceId?: string;
63
+ resourceId?: string;
64
+ selectedDate?: string;
65
+ selectedSlot?: string;
66
+ [key: string]: unknown;
67
+ }
68
+ /**
69
+ * Data submitted to create a booking
70
+ */
71
+ interface BookingSubmissionData {
72
+ formId: string;
73
+ serviceId: string;
74
+ resourceId?: string;
75
+ startAt: string;
76
+ endAt: string;
77
+ customFields: Record<string, unknown>;
78
+ timezone: string;
79
+ }
80
+ /**
81
+ * Result of a booking submission
82
+ */
83
+ interface BookingSubmissionResult {
84
+ success: boolean;
85
+ appointmentId?: string;
86
+ error?: string;
87
+ }
88
+
89
+ export type { BookingFormData, BookingFormField, BookingFormSchema, BookingFormSettings, BookingSubmissionData, BookingSubmissionResult, Service, TimeSlot };
@@ -0,0 +1,34 @@
1
+ "use client";
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/bookings/index.ts
22
+ var bookings_exports = {};
23
+ __export(bookings_exports, {
24
+ BookingFormClient: () => import_client.BookingFormClient,
25
+ useBookingFormConfig: () => import_client.useBookingFormConfig
26
+ });
27
+ module.exports = __toCommonJS(bookings_exports);
28
+ var import_client = require("@riverbankcms/blocks/client");
29
+ // Annotate the CommonJS export names for ESM import in node:
30
+ 0 && (module.exports = {
31
+ BookingFormClient,
32
+ useBookingFormConfig
33
+ });
34
+ //# sourceMappingURL=bookings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/bookings/index.ts"],"sourcesContent":["/**\n * Booking system exports for SDK consumers\n *\n * This module re-exports booking components and hooks from @riverbankcms/blocks.\n * SDK sites should use the same booking components as the main platform.\n *\n * @example Using the booking form\n * ```tsx\n * import { BookingFormClient, useBookingFormConfig } from '@riverbankcms/sdk/bookings';\n *\n * function BookingPage() {\n * const { formConfig, services, isLoading, error } = useBookingFormConfig(siteId, formId);\n *\n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error}</div>;\n *\n * return (\n * <BookingFormClient\n * siteId={siteId}\n * formId={formId}\n * form={formConfig}\n * services={services}\n * />\n * );\n * }\n * ```\n *\n * @packageDocumentation\n */\n\n// Re-export components and hooks from @riverbankcms/blocks\nexport {\n BookingFormClient,\n useBookingFormConfig,\n} from '@riverbankcms/blocks/client';\n\n// Re-export types from @riverbankcms/blocks\nexport type {\n BookingService,\n BookingFormConfig,\n} from '@riverbankcms/blocks/client';\n\n// Re-export SDK-specific types that may still be useful\nexport type {\n Service,\n TimeSlot,\n BookingFormSettings,\n BookingFormSchema,\n BookingFormField,\n BookingFormData,\n BookingSubmissionData,\n BookingSubmissionResult,\n} from './types';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+BA,oBAGO;","names":[]}
@@ -0,0 +1,11 @@
1
+ "use client";
2
+ // src/bookings/index.ts
3
+ import {
4
+ BookingFormClient,
5
+ useBookingFormConfig
6
+ } from "@riverbankcms/blocks/client";
7
+ export {
8
+ BookingFormClient,
9
+ useBookingFormConfig
10
+ };
11
+ //# sourceMappingURL=bookings.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/bookings/index.ts"],"sourcesContent":["/**\n * Booking system exports for SDK consumers\n *\n * This module re-exports booking components and hooks from @riverbankcms/blocks.\n * SDK sites should use the same booking components as the main platform.\n *\n * @example Using the booking form\n * ```tsx\n * import { BookingFormClient, useBookingFormConfig } from '@riverbankcms/sdk/bookings';\n *\n * function BookingPage() {\n * const { formConfig, services, isLoading, error } = useBookingFormConfig(siteId, formId);\n *\n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error}</div>;\n *\n * return (\n * <BookingFormClient\n * siteId={siteId}\n * formId={formId}\n * form={formConfig}\n * services={services}\n * />\n * );\n * }\n * ```\n *\n * @packageDocumentation\n */\n\n// Re-export components and hooks from @riverbankcms/blocks\nexport {\n BookingFormClient,\n useBookingFormConfig,\n} from '@riverbankcms/blocks/client';\n\n// Re-export types from @riverbankcms/blocks\nexport type {\n BookingService,\n BookingFormConfig,\n} from '@riverbankcms/blocks/client';\n\n// Re-export SDK-specific types that may still be useful\nexport type {\n Service,\n TimeSlot,\n BookingFormSettings,\n BookingFormSchema,\n BookingFormField,\n BookingFormData,\n BookingSubmissionData,\n BookingSubmissionResult,\n} from './types';\n"],"mappings":";AA+BA;AAAA,EACE;AAAA,EACA;AAAA,OACK;","names":[]}