@businessdash/sdk 0.9.81 → 0.9.90

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 (261) hide show
  1. package/README.md +115 -902
  2. package/assets/{biab-sw.js → bd-sw.js} +2 -2
  3. package/dist/account-core/index.d.ts +1 -1
  4. package/dist/account-core/index.d.ts.map +1 -1
  5. package/dist/adapters-revalidate.d.ts +2 -2
  6. package/dist/adapters-revalidate.js +2 -2
  7. package/dist/adapters-revalidate.js.map +1 -1
  8. package/dist/analytics-core.d.ts +6 -6
  9. package/dist/analytics-core.d.ts.map +1 -1
  10. package/dist/analytics-core.js +4 -4
  11. package/dist/analytics-core.js.map +1 -1
  12. package/dist/analytics-server.d.ts +6 -6
  13. package/dist/analytics-server.d.ts.map +1 -1
  14. package/dist/analytics-server.js +5 -5
  15. package/dist/auth-handler.d.ts +14 -14
  16. package/dist/auth-handler.d.ts.map +1 -1
  17. package/dist/auth-handler.js +16 -16
  18. package/dist/auth-handler.js.map +1 -1
  19. package/dist/auth-links.d.ts +2 -2
  20. package/dist/auth-links.d.ts.map +1 -1
  21. package/dist/auth-links.js +2 -2
  22. package/dist/auth-links.js.map +1 -1
  23. package/dist/{biab-forms.css → bd-forms.css} +158 -158
  24. package/dist/cli.d.ts +4 -4
  25. package/dist/cli.js +78 -78
  26. package/dist/cli.js.map +1 -1
  27. package/dist/client.d.ts +158 -147
  28. package/dist/client.d.ts.map +1 -1
  29. package/dist/client.js +156 -137
  30. package/dist/client.js.map +1 -1
  31. package/dist/consent-core/index.cjs +2 -2
  32. package/dist/consent-core/index.d.ts +2 -2
  33. package/dist/consent-core/index.d.ts.map +1 -1
  34. package/dist/consent-core/index.js +10 -8
  35. package/dist/consent-core/index.js.map +1 -1
  36. package/dist/contracts.d.ts +411 -52
  37. package/dist/contracts.d.ts.map +1 -1
  38. package/dist/contracts.js +89 -15
  39. package/dist/contracts.js.map +1 -1
  40. package/dist/data-model-schema.d.ts +15 -15
  41. package/dist/data-model-schema.d.ts.map +1 -1
  42. package/dist/data-model-schema.js +19 -17
  43. package/dist/data-model-schema.js.map +1 -1
  44. package/dist/distribution.d.ts +5 -5
  45. package/dist/distribution.d.ts.map +1 -1
  46. package/dist/distribution.js +4 -4
  47. package/dist/element.d.ts +36 -36
  48. package/dist/element.d.ts.map +1 -1
  49. package/dist/element.js +43 -43
  50. package/dist/element.js.map +1 -1
  51. package/dist/embed-protocol.d.ts +11 -11
  52. package/dist/embed-protocol.d.ts.map +1 -1
  53. package/dist/embed-protocol.js +1 -1
  54. package/dist/embed-protocol.js.map +1 -1
  55. package/dist/errors.d.ts +15 -15
  56. package/dist/errors.d.ts.map +1 -1
  57. package/dist/errors.js +18 -18
  58. package/dist/errors.js.map +1 -1
  59. package/dist/forms-core/autocomplete.d.ts +3 -3
  60. package/dist/forms-core/autocomplete.d.ts.map +1 -1
  61. package/dist/forms-core/autocomplete.js +2 -2
  62. package/dist/forms-core/controller.d.ts +10 -10
  63. package/dist/forms-core/controller.d.ts.map +1 -1
  64. package/dist/forms-core/controller.js +4 -4
  65. package/dist/forms-core/controller.js.map +1 -1
  66. package/dist/forms-core/elements.d.ts +4 -4
  67. package/dist/forms-core/elements.d.ts.map +1 -1
  68. package/dist/forms-core/elements.js +7 -7
  69. package/dist/forms-core/elements.js.map +1 -1
  70. package/dist/forms-core/formula.d.ts +1 -1
  71. package/dist/forms-core/formula.js +1 -1
  72. package/dist/forms-core/index.d.ts +6 -6
  73. package/dist/forms-core/index.d.ts.map +1 -1
  74. package/dist/forms-core/index.js +5 -5
  75. package/dist/forms-core/index.js.map +1 -1
  76. package/dist/forms-core/units.d.ts +1 -1
  77. package/dist/forms-core/units.js +1 -1
  78. package/dist/forms-core/us-states.d.ts +1 -1
  79. package/dist/forms-core/us-states.js +1 -1
  80. package/dist/forms-core/validation.d.ts +12 -3
  81. package/dist/forms-core/validation.d.ts.map +1 -1
  82. package/dist/forms-core/validation.js +152 -17
  83. package/dist/forms-core/validation.js.map +1 -1
  84. package/dist/forms.d.ts +2 -2
  85. package/dist/forms.d.ts.map +1 -1
  86. package/dist/forms.js +2 -2
  87. package/dist/forms.js.map +1 -1
  88. package/dist/framework-support.js +1 -1
  89. package/dist/framework-support.js.map +1 -1
  90. package/dist/gallery-types.d.ts +1 -1
  91. package/dist/graphql.d.ts +3 -3
  92. package/dist/graphql.d.ts.map +1 -1
  93. package/dist/graphql.js +3 -3
  94. package/dist/graphql.js.map +1 -1
  95. package/dist/index.cjs +350 -273
  96. package/dist/index.d.cts +5 -5
  97. package/dist/index.d.mts +5 -5
  98. package/dist/index.d.ts +5 -5
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +5 -5
  101. package/dist/index.js.map +1 -1
  102. package/dist/legal-core/index.cjs +8 -8
  103. package/dist/legal-core/index.d.ts +3 -3
  104. package/dist/legal-core/index.d.ts.map +1 -1
  105. package/dist/legal-core/index.js +11 -11
  106. package/dist/legal-core/index.js.map +1 -1
  107. package/dist/marketing-core/index.d.ts +51 -1
  108. package/dist/marketing-core/index.d.ts.map +1 -1
  109. package/dist/marketing-core/index.js +35 -0
  110. package/dist/marketing-core/index.js.map +1 -1
  111. package/dist/marketing-schema.d.ts +9 -9
  112. package/dist/marketing-schema.d.ts.map +1 -1
  113. package/dist/marketing-schema.js +1 -1
  114. package/dist/mcp.d.ts +4 -4
  115. package/dist/mcp.js +4 -4
  116. package/dist/native.d.ts +6 -6
  117. package/dist/native.d.ts.map +1 -1
  118. package/dist/native.js +4 -4
  119. package/dist/native.js.map +1 -1
  120. package/dist/next-revalidate.d.ts +8 -8
  121. package/dist/next-revalidate.d.ts.map +1 -1
  122. package/dist/next-revalidate.js +7 -7
  123. package/dist/next-revalidate.js.map +1 -1
  124. package/dist/notifications-core/index.d.ts +1 -1
  125. package/dist/notifications-core/index.js +1 -1
  126. package/dist/parallel-pages.d.ts +4 -4
  127. package/dist/parallel-pages.d.ts.map +1 -1
  128. package/dist/parallel-pages.js +5 -5
  129. package/dist/parallel-pages.js.map +1 -1
  130. package/dist/portal-core/index.d.ts +1 -1
  131. package/dist/portal-core/index.js +1 -1
  132. package/dist/proxy.d.ts +18 -18
  133. package/dist/proxy.d.ts.map +1 -1
  134. package/dist/proxy.js +10 -10
  135. package/dist/proxy.js.map +1 -1
  136. package/dist/push-core/index.cjs +1 -1
  137. package/dist/push-core/index.d.ts +1 -1
  138. package/dist/push-core/index.js +1 -1
  139. package/dist/push-core/index.js.map +1 -1
  140. package/dist/react-analytics.d.ts +14 -14
  141. package/dist/react-analytics.d.ts.map +1 -1
  142. package/dist/react-analytics.js +15 -15
  143. package/dist/react-analytics.js.map +1 -1
  144. package/dist/react-attribution.d.ts +2 -2
  145. package/dist/react-attribution.d.ts.map +1 -1
  146. package/dist/react-attribution.js +1 -1
  147. package/dist/react-marketing.js +5 -5
  148. package/dist/react-marketing.js.map +1 -1
  149. package/dist/react.d.ts +38 -61
  150. package/dist/react.d.ts.map +1 -1
  151. package/dist/react.js +247 -261
  152. package/dist/react.js.map +1 -1
  153. package/dist/reserved-paths.d.ts +2 -2
  154. package/dist/reserved-paths.js +3 -3
  155. package/dist/reserved-paths.js.map +1 -1
  156. package/dist/revalidate-verify.d.ts +3 -3
  157. package/dist/revalidate-verify.d.ts.map +1 -1
  158. package/dist/revalidate-verify.js +1 -1
  159. package/dist/revalidate-verify.js.map +1 -1
  160. package/dist/sdk.d.ts +49 -49
  161. package/dist/sdk.d.ts.map +1 -1
  162. package/dist/sdk.js +47 -51
  163. package/dist/sdk.js.map +1 -1
  164. package/dist/seed-core/index.js +8 -8
  165. package/dist/seed-core/index.js.map +1 -1
  166. package/dist/seo-core/blog.d.ts +1 -1
  167. package/dist/seo-core/blog.js +1 -1
  168. package/dist/seo-core/blog.js.map +1 -1
  169. package/dist/seo-core/index.cjs +2 -2
  170. package/dist/seo-core/index.js +1 -1
  171. package/dist/seo-core/index.js.map +1 -1
  172. package/dist/seo.d.ts +1 -1
  173. package/dist/seo.d.ts.map +1 -1
  174. package/dist/seo.js +1 -1
  175. package/dist/seo.js.map +1 -1
  176. package/dist/sitemap-core/index.cjs +3 -3
  177. package/dist/sitemap-core/index.js +2 -2
  178. package/dist/sitemap-core/index.js.map +1 -1
  179. package/dist/socials.d.ts +6 -6
  180. package/dist/socials.d.ts.map +1 -1
  181. package/dist/socials.js +5 -5
  182. package/dist/socials.js.map +1 -1
  183. package/dist/solid-compat.d.ts +1 -1
  184. package/dist/solid-compat.js +4 -4
  185. package/dist/solid-compat.js.map +1 -1
  186. package/dist/store-core/index.d.ts +1 -1
  187. package/dist/vanilla.d.ts +12 -12
  188. package/dist/vanilla.d.ts.map +1 -1
  189. package/dist/vanilla.js +192 -145
  190. package/dist/vanilla.js.map +1 -1
  191. package/openapi.json +264 -1
  192. package/package.json +8 -8
  193. package/src/account-core/index.ts +1 -1
  194. package/src/adapters-revalidate.ts +3 -3
  195. package/src/analytics-core.ts +8 -8
  196. package/src/analytics-server.ts +6 -6
  197. package/src/angular/{biab-form.component.ts → bd-form.component.ts} +269 -161
  198. package/src/angular/headless.ts +12 -12
  199. package/src/angular/index.ts +9 -9
  200. package/src/auth-handler.ts +22 -22
  201. package/src/auth-links.ts +2 -2
  202. package/src/cli.ts +81 -81
  203. package/src/client.ts +218 -193
  204. package/src/consent-core/index.ts +10 -8
  205. package/src/contracts.ts +99 -15
  206. package/src/data-model-schema.ts +29 -26
  207. package/src/distribution.ts +5 -5
  208. package/src/element.ts +54 -54
  209. package/src/embed-protocol.ts +14 -14
  210. package/src/errors.ts +27 -27
  211. package/src/forms-core/autocomplete.ts +3 -3
  212. package/src/forms-core/controller.ts +12 -12
  213. package/src/forms-core/elements.ts +7 -7
  214. package/src/forms-core/formula.ts +1 -1
  215. package/src/forms-core/index.ts +8 -8
  216. package/src/forms-core/units.ts +1 -1
  217. package/src/forms-core/us-states.ts +1 -1
  218. package/src/forms-core/validation.ts +158 -14
  219. package/src/forms.ts +2 -2
  220. package/src/framework-support.ts +1 -1
  221. package/src/gallery-types.ts +1 -1
  222. package/src/graphql.ts +4 -4
  223. package/src/index.ts +38 -38
  224. package/src/legal-core/index.ts +12 -12
  225. package/src/marketing-core/index.ts +62 -0
  226. package/src/marketing-schema.ts +9 -9
  227. package/src/mcp.ts +4 -4
  228. package/src/native.ts +14 -14
  229. package/src/next-revalidate.ts +10 -10
  230. package/src/notifications-core/index.ts +1 -1
  231. package/src/parallel-pages.ts +6 -6
  232. package/src/portal-core/index.ts +1 -1
  233. package/src/proxy.ts +28 -28
  234. package/src/push-core/index.ts +2 -2
  235. package/src/qwik.tsx +262 -166
  236. package/src/react-analytics.tsx +17 -17
  237. package/src/react-attribution.tsx +2 -2
  238. package/src/react-marketing.tsx +5 -5
  239. package/src/react.tsx +541 -500
  240. package/src/reserved-paths.ts +3 -3
  241. package/src/revalidate-verify.ts +5 -5
  242. package/src/sdk.ts +106 -110
  243. package/src/seed-core/index.ts +8 -8
  244. package/src/seo-core/blog.ts +2 -2
  245. package/src/seo-core/index.ts +1 -1
  246. package/src/seo.ts +1 -1
  247. package/src/sitemap-core/index.ts +2 -2
  248. package/src/socials.ts +6 -6
  249. package/src/solid-compat.tsx +5 -5
  250. package/src/solid-surfaces.tsx +28 -28
  251. package/src/solid.tsx +264 -175
  252. package/src/store-core/index.ts +1 -1
  253. package/src/styles/{biab-forms.css → bd-forms.css} +158 -158
  254. package/src/svelte/{BiabForm.svelte → BdForm.svelte} +240 -173
  255. package/src/svelte/context.ts +16 -16
  256. package/src/svelte/headless.ts +10 -10
  257. package/src/svelte/index.ts +16 -16
  258. package/src/vanilla.ts +250 -169
  259. package/src/vue/{BiabForm.vue → BdForm.vue} +270 -157
  260. package/src/vue/headless.ts +11 -11
  261. package/src/vue/index.ts +26 -26
@@ -25,7 +25,7 @@ export function shouldSearchOptions(
25
25
  }
26
26
 
27
27
  /**
28
- * Where BIAB serves icon art.
28
+ * Where BD serves icon art.
29
29
  *
30
30
  * The `icon_select` element stores an icon NAME, and rendering it back needs the
31
31
  * icon set. The SDK deliberately doesn't bundle one: it's ~1,600 icons, and
@@ -33,10 +33,10 @@ export function shouldSearchOptions(
33
33
  * `<img src="…/api/icons/<name>.svg">`, so the platform stays the single source
34
34
  * of truth for what a name means.
35
35
  *
36
- * Override with `NEXT_PUBLIC_BIAB_ORIGIN` when pointing a consumer app at a
37
- * non-production BIAB.
36
+ * Override with `NEXT_PUBLIC_BD_ORIGIN` when pointing a consumer app at a
37
+ * non-production BD.
38
38
  */
39
- export const BIAB_ICON_BASE: string = (() => {
39
+ export const BD_ICON_BASE: string = (() => {
40
40
  // Read through `globalThis` rather than the bare `process` identifier: the
41
41
  // SDK is consumed by browser bundlers that have no `@types/node`, where
42
42
  // naming `process` directly fails to compile (and can throw at runtime).
@@ -45,17 +45,17 @@ export const BIAB_ICON_BASE: string = (() => {
45
45
  process?: { env?: Record<string, string | undefined> };
46
46
  }
47
47
  ).process?.env;
48
- return env?.["NEXT_PUBLIC_BIAB_ORIGIN"] || "https://www.biab.app";
48
+ return env?.["NEXT_PUBLIC_BD_ORIGIN"] || "https://www.biab.app";
49
49
  })();
50
50
 
51
51
  /** SVG URL for one icon name. */
52
52
  export function iconUrl(name: string): string {
53
- return `${BIAB_ICON_BASE}/api/icons/${encodeURIComponent(name)}.svg`;
53
+ return `${BD_ICON_BASE}/api/icons/${encodeURIComponent(name)}.svg`;
54
54
  }
55
55
 
56
56
  /** The lazily-fetched icon-name index (only needed when an author hasn't
57
57
  * curated `iconConfig.allowedIcons`). */
58
- export const ICON_INDEX_URL = `${BIAB_ICON_BASE}/api/icons`;
58
+ export const ICON_INDEX_URL = `${BD_ICON_BASE}/api/icons`;
59
59
 
60
60
  /** Narrow an icon list by a search query, capped so the grid never mounts
61
61
  * thousands of nodes at once. */
@@ -7,7 +7,7 @@
7
7
  * identifiers (that aren't a provided variable) and unknown functions are hard
8
8
  * errors. The same module runs on the client (non-sensitive functions, live) and
9
9
  * the server (all functions) so results never disagree. The SDK keeps a mirror at
10
- * `biab-dev/src/forms-core/formula.ts`.
10
+ * `sdk/src/forms-core/formula.ts`.
11
11
  *
12
12
  * Values are scalars: number | string | boolean. (Tables / arrays are a
13
13
  * fast-follow.) Function reference: see FORMULA_FUNCTIONS.
@@ -1,23 +1,23 @@
1
1
  /**
2
2
  * `@businessdash/sdk/forms` headless core — framework-agnostic form runtime.
3
3
  *
4
- * Everything a `<BiabForm>` binding needs that ISN'T framework-specific:
4
+ * Everything a `<BdForm>` binding needs that ISN'T framework-specific:
5
5
  * - `createFormController` — the observable store (values, errors, steps,
6
6
  * visibility, submit lifecycle, file uploads).
7
- * - validation + condition primitives mirrored 1:1 from the BIAB server so the
7
+ * - validation + condition primitives mirrored 1:1 from the BD server so the
8
8
  * client never disagrees with what the platform enforces.
9
9
  *
10
10
  * Bindings (React / Vue / Svelte / Solid / Qwik / Angular / web-component /
11
11
  * vanilla) import from here, subscribe to `snapshot()`, and render by field
12
- * `type` using the `biab-*` CSS class convention.
12
+ * `type` using the `bd-*` CSS class convention.
13
13
  */
14
14
 
15
15
  // Re-export the SDK form types so a binding can import schema/result/field types
16
16
  // from the single `/forms` entry without reaching into the root export.
17
- // `BiabClient` is included because `CreateFormControllerOptions.client` is typed
17
+ // `BdClient` is included because `CreateFormControllerOptions.client` is typed
18
18
  // to it — a binding that accepts/injects a client needs the type from here.
19
19
  export type {
20
- BiabClient,
20
+ BdClient,
21
21
  FormActionPreview,
22
22
  FormActionType,
23
23
  FormFieldDef,
@@ -60,7 +60,7 @@ export {
60
60
  formatCalcValue,
61
61
  } from "./calculation.js";
62
62
  export {
63
- type BiabFormsClient,
63
+ type BdFormsClient,
64
64
  type CreateFormControllerOptions,
65
65
  concurrentRevealCount,
66
66
  createFormController,
@@ -78,7 +78,7 @@ export {
78
78
  seedInitialData,
79
79
  } from "./controller.js";
80
80
  export {
81
- BIAB_ICON_BASE,
81
+ BD_ICON_BASE,
82
82
  fetchIconNames,
83
83
  filterIconNames,
84
84
  ICON_INDEX_URL,
@@ -88,7 +88,7 @@ export {
88
88
  } from "./elements.js";
89
89
 
90
90
  // File-upload rules — accept-attribute building (incl. iOS HEIC/HEVC), per-file
91
- // validation, and the form-wide file cap. Shared 1:1 with the BIAB server.
91
+ // validation, and the form-wide file cap. Shared 1:1 with the BD server.
92
92
  export {
93
93
  buildAcceptAttr,
94
94
  expandAllowedTypes,
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * Each linear category defines a `baseUnit` and a `factor` per unit such that
6
6
  * `valueInBase = value * factor`. Temperature is affine (offset + scale), so it
7
- * is special-cased. `<BiabForm/>` uses these to render the unit picker, show a
7
+ * is special-cased. `<BdForm/>` uses these to render the unit picker, show a
8
8
  * live conversion hint, and compute the value's base — the server recomputes the
9
9
  * base authoritatively on submit, so this is convenience only.
10
10
  */
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * US states (+ DC) for the Address element's State dropdown, and the US ZIP code
3
3
  * format. Shared by the server validator, the FormPreview/editor renders, and the
4
- * SDK (mirrored at `biab-dev/src/forms-core/us-states.ts`). Keep the two in sync.
4
+ * SDK (mirrored at `sdk/src/forms-core/us-states.ts`). Keep the two in sync.
5
5
  */
6
6
 
7
7
  export const US_STATES: ReadonlyArray<{ name: string; abbr: string }> = [
@@ -2,15 +2,15 @@
2
2
  * Framework-agnostic, isomorphic form validation + condition evaluation.
3
3
  *
4
4
  * Zero UI deps, zero React, zero DOM. This is the single source of truth every
5
- * `<BiabForm>` binding (React / Vue / Svelte / Solid / Qwik / Angular / Element /
6
- * vanilla) shares. It is a faithful port of three existing BIAB modules so the
5
+ * `<BdForm>` binding (React / Vue / Svelte / Solid / Qwik / Angular / Element /
6
+ * vanilla) shares. It is a faithful port of three existing BD modules so the
7
7
  * client never disagrees with the server:
8
8
  *
9
9
  * - `src/server/forms/validate.ts` — isEmpty / validateValue /
10
10
  * evalCondition / findMissingRequired
11
11
  * - `src/app/.../builder/FormPreview.tsx` — seedInitialData / concurrentRevealCount /
12
12
  * the or_condition + condition_block walk
13
- * - `biab-dev/src/sdk.ts` validateFormSubmission — the wire-level submission check
13
+ * - `sdk/src/sdk.ts` validateFormSubmission — the wire-level submission check
14
14
  *
15
15
  * The schema published by `client.forms.schema(slug)` carries the FULL nested
16
16
  * field tree (layout nodes, `condition_block`, `or_condition`, `input_group`,
@@ -117,6 +117,15 @@ export interface FormCoreField {
117
117
  sources?: "both" | "upload" | "url";
118
118
  };
119
119
  phoneConfig?: { international?: boolean; showFlags?: boolean };
120
+ /** `name` composite: which optional parts render. First/last are always on.
121
+ * Value is { prefix?, first, middle?, last?, suffix?, nicknames?, full, short }
122
+ * — `full`/`short` are recomputed server-side at submission validation. */
123
+ nameConfig?: {
124
+ prefix?: boolean;
125
+ middle?: boolean;
126
+ suffix?: boolean;
127
+ nicknames?: boolean;
128
+ };
120
129
  timeConfig?: {
121
130
  mode?: "simple" | "time_block" | "appointment";
122
131
  format?: "12h" | "24h";
@@ -217,6 +226,10 @@ const MAX_ARRAY_LEN = 500;
217
226
  const MAX_PHONE_LEN = 64;
218
227
  const MAX_DATE_LEN = 64;
219
228
  const MAX_ADDRESS_FIELD_LEN = 512;
229
+ const MAX_NAME_PART_LEN = 128;
230
+ // Computed `full`/`short` can span several parts; bounded but roomier.
231
+ const MAX_NAME_STRING_LEN = 1024;
232
+ const MAX_NICKNAMES = 20;
220
233
  const MAX_FILE_FIELD_LEN = 4096;
221
234
 
222
235
  /**
@@ -264,6 +277,77 @@ const NO_SEED_STATIC = new Set([
264
277
  "calculation",
265
278
  ]);
266
279
 
280
+ // ─────────────────────────────────────────────────────────────────────────────
281
+ // Name helpers — the `name` composite's parts + derived strings. Mirrors
282
+ // validate.ts / the server's name-format module: the server recomputes
283
+ // `full`/`short` authoritatively at submission validation; the client
284
+ // normalizes too so payloads leave here canonical.
285
+ // ─────────────────────────────────────────────────────────────────────────────
286
+
287
+ /** The user-entered parts, in display order. */
288
+ const NAME_PART_ORDER = [
289
+ "prefix",
290
+ "first",
291
+ "middle",
292
+ "last",
293
+ "suffix",
294
+ ] as const;
295
+
296
+ const NAME_VALUE_KEYS = new Set<string>([
297
+ ...NAME_PART_ORDER,
298
+ "nicknames",
299
+ "full",
300
+ "short",
301
+ ]);
302
+
303
+ function namePart(v: unknown): string {
304
+ return typeof v === "string" ? v.trim() : "";
305
+ }
306
+
307
+ /** Every provided part joined with single spaces ("Dr. Jane Quinn Doe Jr."). */
308
+ function composeFullName(v: Record<string, unknown>): string {
309
+ return NAME_PART_ORDER.map((k) => namePart(v[k]))
310
+ .filter(Boolean)
311
+ .join(" ");
312
+ }
313
+
314
+ /** First + last (whichever of the two exist) — "Jane Doe". */
315
+ function composeShortName(v: Record<string, unknown>): string {
316
+ return [namePart(v["first"]), namePart(v["last"])].filter(Boolean).join(" ");
317
+ }
318
+
319
+ /** Nicknames: the input holds a raw comma-separated string while the visitor
320
+ * types; a string and an array both become trimmed, non-empty items. */
321
+ function normalizeNicknames(raw: unknown): string[] {
322
+ const items =
323
+ typeof raw === "string" ? raw.split(",") : Array.isArray(raw) ? raw : [];
324
+ return items
325
+ .filter((n): n is string => typeof n === "string")
326
+ .map((n) => n.trim())
327
+ .filter(Boolean);
328
+ }
329
+
330
+ /**
331
+ * Canonicalize a `name` value: trim every part, drop empty ones, normalize
332
+ * nicknames into a string[], and RECOMPUTE `full`/`short` — whatever the
333
+ * working data held for those is discarded (the server does the same again,
334
+ * authoritatively).
335
+ */
336
+ function normalizeNameValue(
337
+ raw: Record<string, unknown>,
338
+ ): Record<string, unknown> {
339
+ const out: Record<string, unknown> = {};
340
+ for (const key of NAME_PART_ORDER) {
341
+ const v = namePart(raw[key]);
342
+ if (v) out[key] = v;
343
+ }
344
+ const nicknames = normalizeNicknames(raw["nicknames"]);
345
+ if (nicknames.length > 0) out["nicknames"] = nicknames;
346
+ out["full"] = composeFullName(out);
347
+ out["short"] = composeShortName(out);
348
+ return out;
349
+ }
350
+
267
351
  // ─────────────────────────────────────────────────────────────────────────────
268
352
  // isEmpty — per-type "is this answered?" rule. Mirrors validate.ts isEmpty.
269
353
  // ─────────────────────────────────────────────────────────────────────────────
@@ -334,6 +418,12 @@ export function isEmpty(field: FormCoreField, value: unknown): boolean {
334
418
  | undefined;
335
419
  return !v?.line1 || !v.city || !v.state || !v.zip;
336
420
  }
421
+ case "name": {
422
+ // Answered when both always-on parts are present. Optional parts
423
+ // (prefix, middle, suffix, nicknames) never satisfy a required name.
424
+ const v = value as { first?: string; last?: string } | undefined;
425
+ return !v?.first?.trim() || !v.last?.trim();
426
+ }
337
427
  case "time_picker": {
338
428
  const mode = field.timeConfig?.mode ?? "simple";
339
429
  if (mode === "time_block") {
@@ -360,14 +450,32 @@ export function isEmpty(field: FormCoreField, value: unknown): boolean {
360
450
  // pass here (required-ness is checked separately).
361
451
  // ─────────────────────────────────────────────────────────────────────────────
362
452
 
363
- function regexFail(field: FormCoreField, value: string): string | null {
364
- const pattern = field.regexPattern;
365
- if (!pattern) return null;
453
+ /**
454
+ * Compile an author-supplied pattern: a bare source (`^foo$`) or a
455
+ * slash-delimited literal with flags (`/^foo$/i`) the way authors actually
456
+ * write them. Returns null when nothing compiles; a broken stored pattern
457
+ * must never block a submission. Mirrors the platform's shared helper.
458
+ */
459
+ function compileFieldRegex(raw: string): RegExp | null {
460
+ const m = /^\/(.*)\/([dgimsuvy]*)$/s.exec(raw.trim());
461
+ const source = m ? (m[1] as string) : raw.trim();
462
+ const flags = m ? (m[2] as string) : "";
366
463
  try {
367
- if (!new RegExp(pattern).test(value)) return "regex";
464
+ return new RegExp(source, flags);
368
465
  } catch {
369
- // A broken stored pattern shouldn't block a submission.
466
+ try {
467
+ return new RegExp(raw);
468
+ } catch {
469
+ return null;
470
+ }
370
471
  }
472
+ }
473
+
474
+ function regexFail(field: FormCoreField, value: string): string | null {
475
+ const pattern = field.regexPattern;
476
+ if (!pattern) return null;
477
+ const re = compileFieldRegex(pattern);
478
+ if (re && !re.test(value)) return "regex";
371
479
  return null;
372
480
  }
373
481
 
@@ -635,6 +743,38 @@ export function validateValue(
635
743
  if (typeof zip === "string" && !isValidUsZip(zip)) return "format";
636
744
  return null;
637
745
  }
746
+ case "name": {
747
+ // { prefix?, first, middle?, last?, suffix?, nicknames?, full?, short? }.
748
+ // Client-sent `full`/`short` are accepted here but recomputed at the
749
+ // pre-submit normalization step; `nicknames` may still be the raw comma
750
+ // string. Mirrors validate.ts.
751
+ if (!isPlainObject(value)) return "type";
752
+ for (const [key, v] of Object.entries(value)) {
753
+ if (!NAME_VALUE_KEYS.has(key)) return "options";
754
+ if (v === undefined || key === "nicknames") continue;
755
+ if (typeof v !== "string") return "type";
756
+ const cap =
757
+ key === "full" || key === "short"
758
+ ? MAX_NAME_STRING_LEN
759
+ : MAX_NAME_PART_LEN;
760
+ if (v.length > cap) return "max";
761
+ }
762
+ const nn = (value as { nicknames?: unknown }).nicknames;
763
+ if (nn !== undefined) {
764
+ if (typeof nn === "string") {
765
+ if (nn.length > MAX_NAME_STRING_LEN) return "max";
766
+ } else if (Array.isArray(nn)) {
767
+ if (nn.length > MAX_NICKNAMES) return "max";
768
+ for (const item of nn) {
769
+ if (typeof item !== "string") return "type";
770
+ if (item.length > MAX_NAME_PART_LEN) return "max";
771
+ }
772
+ } else {
773
+ return "type";
774
+ }
775
+ }
776
+ return null;
777
+ }
638
778
  case "schedule": {
639
779
  // Availability value: { asap?, days?: string[], times?: string[], notes? }.
640
780
  // Auto value: { slotStartAt: <ISO> } (the chosen instant-booking slot).
@@ -860,12 +1000,10 @@ export function findMissingRequired(
860
1000
  const pattern = f.regexPattern;
861
1001
  const v = String(scope[f.id] ?? "");
862
1002
  if (pattern && v) {
863
- try {
864
- if (!new RegExp(pattern).test(v)) {
865
- missing.push({ id: f.id, label: f.label || "Invalid format" });
866
- }
867
- } catch {
868
- /* ignore an invalid pattern */
1003
+ // Shared delimiter-aware compile; invalid patterns never block.
1004
+ const re = compileFieldRegex(pattern);
1005
+ if (re && !re.test(v)) {
1006
+ missing.push({ id: f.id, label: f.label || "Invalid format" });
869
1007
  }
870
1008
  }
871
1009
  }
@@ -1027,6 +1165,12 @@ export function toSubmissionPayload(
1027
1165
  : instance,
1028
1166
  );
1029
1167
  }
1168
+ // A name submits canonically: trimmed parts, nicknames comma string →
1169
+ // string[], freshly computed `full`/`short` (the server recomputes them
1170
+ // again, authoritatively).
1171
+ if (field.type === "name" && isPlainObject(inputValue)) {
1172
+ value = normalizeNameValue(inputValue);
1173
+ }
1030
1174
  out[field.key ?? id] = value;
1031
1175
  }
1032
1176
 
package/src/forms.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `@businessdash/sdk/forms` — public entry for the headless `<BiabForm>` core.
2
+ * `@businessdash/sdk/forms` — public entry for the headless `<BdForm>` core.
3
3
  *
4
4
  * This is the compiled (tsc → dist) entry the framework bindings depend on. It
5
5
  * re-exports the framework-agnostic controller + validation primitives from
@@ -60,4 +60,4 @@ export {
60
60
  * platform default, so a starter renders a working contact form with zero
61
61
  * dashboard setup. Swap in your own org's form slug once you've built one.
62
62
  */
63
- export const BIAB_DEFAULT_FORM_SLUG = "general-inquiry";
63
+ export const BD_DEFAULT_FORM_SLUG = "general-inquiry";
@@ -419,7 +419,7 @@ export const REACT_TARGETS: readonly ReactTarget[] = [
419
419
  name: "TanStack Start",
420
420
  entry: "@businessdash/sdk/react",
421
421
  requires: "Nothing — no RSC boundary to cross.",
422
- starter: "Tanstack-Start",
422
+ starter: "Tanstack-Start-Solid",
423
423
  status: "supported",
424
424
  },
425
425
  {
@@ -6,7 +6,7 @@
6
6
  * return type via const generics in `sdk.ts`).
7
7
  *
8
8
  * Kept as a flat type — no SDK dependency on zod or runtime
9
- * validation here, since `createBiabClient` trusts the platform
9
+ * validation here, since `createBdClient` trusts the platform
10
10
  * response (the platform owns the schema; the SDK is a typed
11
11
  * facade).
12
12
  */
package/src/graphql.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Generate a GraphQL SDL schema from a BIAB data model.
2
+ * Generate a GraphQL SDL schema from a BD data model.
3
3
  *
4
4
  * "GraphQL layer compatibility" for a data-model-as-code platform starts here:
5
5
  * a real, typed GraphQL schema of the org's custom database that any GraphQL
@@ -13,7 +13,7 @@
13
13
  * heavier layer that needs a runtime.
14
14
  *
15
15
  * Shape decisions:
16
- * - Every relation is a LIST. BIAB relations are link rows (`sync-records`
16
+ * - Every relation is a LIST. BD relations are link rows (`sync-records`
17
17
  * converges an array of target ids), and the records API always returns
18
18
  * `relations` as arrays — so `[Target!]!` is faithful, one-to-one included.
19
19
  * - SELECT/MULTI_SELECT become a GraphQL enum WHEN every option value is a
@@ -190,7 +190,7 @@ export function dataModelToGraphqlSdl(
190
190
 
191
191
  const header =
192
192
  opts.header ??
193
- "# GraphQL schema generated from your BIAB data model by `biab-dev export-graphql-schema`.\n# Regenerate on schema change; commit it for a git-diffable, AI-readable contract.";
193
+ "# GraphQL schema generated from your BD data model by `bd export-graphql-schema`.\n# Regenerate on schema change; commit it for a git-diffable, AI-readable contract.";
194
194
 
195
195
  const scalars =
196
196
  "scalar DateTime\nscalar JSON\n\n# Cents; money is integer cents platform-wide.\n";
@@ -248,7 +248,7 @@ export function createGraphqlClient(input: {
248
248
  /** Package API base, e.g. `https://biab.app/api/package/v1`. */
249
249
  baseUrl: string;
250
250
  siteId: string;
251
- /** A secret (`biab_…`) key holding `graphql:query`. */
251
+ /** A secret (`bd_…`) key holding `graphql:query`. */
252
252
  apiKey: string;
253
253
  fetch?: typeof fetch;
254
254
  }): GraphqlClient {
package/src/index.ts CHANGED
@@ -6,35 +6,35 @@ export {
6
6
  DEFAULT_AUTH_COOKIE_NAME,
7
7
  getTenantSession,
8
8
  } from "./auth-handler.js";
9
- export type { BiabDevClientOptions, FetchLike } from "./client.js";
9
+ export type { BdApiClientOptions, FetchLike } from "./client.js";
10
10
  export {
11
- BiabDevActionsClient,
12
- BiabDevAnalyticsClient,
13
- BiabDevAssetsClient,
14
- BiabDevAttributionClient,
15
- BiabDevAuthClient,
16
- BiabDevBlogClient,
17
- BiabDevCartClient,
18
- BiabDevChatbotClient,
19
- BiabDevCheckoutClient,
20
- BiabDevClient,
21
- BiabDevCollectionsClient,
22
- BiabDevCustomerPortalClient,
23
- BiabDevDashboardClient,
24
- BiabDevDataModelClient,
25
- BiabDevEmailTemplatesClient,
26
- BiabDevFollowersClient,
27
- BiabDevHiringClient,
28
- BiabDevMarketingClient,
29
- BiabDevMarketingPagesClient,
30
- BiabDevParallelPagesClient,
31
- BiabDevReviewsClient,
32
- BiabDevRowsClient,
33
- BiabDevSiteClient,
34
- BiabDevStorefrontClient,
11
+ BdActionsClient,
12
+ BdAnalyticsClient,
13
+ BdApiClient,
14
+ BdAssetsClient,
15
+ BdAttributionClient,
16
+ BdAuthClient,
17
+ BdBlogClient,
18
+ BdCartClient,
19
+ BdChatbotClient,
20
+ BdCheckoutClient,
21
+ BdCollectionsClient,
22
+ BdCustomerPortalClient,
23
+ BdDashboardClient,
24
+ BdDataModelClient,
25
+ BdEmailTemplatesClient,
26
+ BdFollowersClient,
27
+ BdHiringClient,
28
+ BdMarketingClient,
29
+ BdMarketingPagesClient,
30
+ BdParallelPagesClient,
31
+ BdReviewsClient,
32
+ BdRowsClient,
33
+ BdSiteClient,
34
+ BdStorefrontClient,
35
35
  clearMarketingCache,
36
36
  clearMarketingPageCache,
37
- createBiabDevClient,
37
+ createBdApiClient,
38
38
  type ParallelPagesListResponse,
39
39
  type ParallelPagesRenderResponse,
40
40
  type ParallelPagesVariantsResponse,
@@ -371,13 +371,13 @@ export {
371
371
  type InferEnumValues,
372
372
  } from "./enums.js";
373
373
  export {
374
- BiabAccessRejectedError,
375
- BiabApiError,
376
- BiabFeatureNotEntitledError,
377
- BiabPaymentLapsedError,
378
- type BiabPlanGateBody,
379
- BiabServiceSuspendedError,
380
- isBiabPlanGateBody,
374
+ BdAccessRejectedError,
375
+ BdApiError,
376
+ BdFeatureNotEntitledError,
377
+ BdPaymentLapsedError,
378
+ type BdPlanGateBody,
379
+ BdServiceSuspendedError,
380
+ isBdPlanGateBody,
381
381
  type UnwrappedAccess,
382
382
  type UnwrappedEntitlement,
383
383
  unwrapAccess,
@@ -432,11 +432,11 @@ export {
432
432
  // High-level SDK surface — the consumer DX entry point.
433
433
  // (See sdk.ts for the design principle: consumer writes design +
434
434
  // granular data requests; auth, caching, revalidation, tagging all
435
- // live inside biab-dev.)
435
+ // live inside bd.)
436
436
  export {
437
- type BiabClient,
438
- type CreateBiabClientOptions,
439
- createBiabClient,
437
+ type BdClient,
438
+ type CreateBdClientOptions,
439
+ createBdClient,
440
440
  type FormFieldDef,
441
441
  type FormFileValue,
442
442
  type FormSchema,
@@ -464,7 +464,7 @@ export {
464
464
  type ArticleInput,
465
465
  article,
466
466
  type BreadcrumbInput,
467
- biabSchemas,
467
+ bdSchemas,
468
468
  breadcrumb,
469
469
  type FaqInput,
470
470
  faq,
@@ -42,7 +42,7 @@
42
42
  * to inject. The page is deliberately unstyled markup: legal pages should look
43
43
  * like the rest of the site, and an SDK that shipped its own typography would
44
44
  * be one more thing to override. `renderLegalPageHtml()` produces semantic HTML
45
- * with stable `data-biab-legal-*` hooks you can style, or ignore entirely and
45
+ * with stable `data-bd-legal-*` hooks you can style, or ignore entirely and
46
46
  * build your own from the same data.
47
47
  *
48
48
  * @module
@@ -170,7 +170,7 @@ export function legalLastUpdated(
170
170
  }
171
171
 
172
172
  export type RenderLegalPageOptions = {
173
- /** Wrapped around everything. Defaults to `biab-legal`. */
173
+ /** Wrapped around everything. Defaults to `bd-legal`. */
174
174
  className?: string;
175
175
  /** Locale for the "Last updated" line. */
176
176
  locale?: string;
@@ -181,7 +181,7 @@ export type RenderLegalPageOptions = {
181
181
  /**
182
182
  * Semantic markup for one document: header, title, body, footer.
183
183
  *
184
- * Unstyled by design. Every element carries a stable `data-biab-legal-*`
184
+ * Unstyled by design. Every element carries a stable `data-bd-legal-*`
185
185
  * attribute so a stylesheet can reach it, and none carries a class you would
186
186
  * have to fight. If you want a different structure, read the same fields off
187
187
  * the document and build your own — this is a convenience, not a requirement.
@@ -195,7 +195,7 @@ export function renderLegalPageHtml(
195
195
  options: RenderLegalPageOptions = {},
196
196
  ): string {
197
197
  const presentation = document.presentation;
198
- const className = options.className ?? "biab-legal";
198
+ const className = options.className ?? "bd-legal";
199
199
  const homeHref = options.homeHref ?? "/";
200
200
  const updated = legalLastUpdated(document, options.locale);
201
201
 
@@ -206,24 +206,24 @@ export function renderLegalPageHtml(
206
206
  : presentation.showLogoInFooter;
207
207
  if (!show || !presentation.logoUrl) return "";
208
208
  return (
209
- `<a href="${escapeHtml(homeHref)}" data-biab-legal-logo-link>` +
210
- `<img src="${escapeHtml(presentation.logoUrl)}" alt="" data-biab-legal-logo="${where}" />` +
209
+ `<a href="${escapeHtml(homeHref)}" data-bd-legal-logo-link>` +
210
+ `<img src="${escapeHtml(presentation.logoUrl)}" alt="" data-bd-legal-logo="${where}" />` +
211
211
  "</a>"
212
212
  );
213
213
  };
214
214
 
215
215
  const parts = [
216
- `<article class="${escapeHtml(className)}" data-biab-legal>`,
217
- "<header data-biab-legal-header>",
216
+ `<article class="${escapeHtml(className)}" data-bd-legal>`,
217
+ "<header data-bd-legal-header>",
218
218
  logo("header"),
219
219
  presentation.headerHtml ?? "",
220
- `<h1 data-biab-legal-title>${escapeHtml(document.title)}</h1>`,
220
+ `<h1 data-bd-legal-title>${escapeHtml(document.title)}</h1>`,
221
221
  updated
222
- ? `<p data-biab-legal-updated>Last updated: ${escapeHtml(updated)}</p>`
222
+ ? `<p data-bd-legal-updated>Last updated: ${escapeHtml(updated)}</p>`
223
223
  : "",
224
224
  "</header>",
225
- `<div data-biab-legal-body>${document.contentHtml}</div>`,
226
- "<footer data-biab-legal-footer>",
225
+ `<div data-bd-legal-body>${document.contentHtml}</div>`,
226
+ "<footer data-bd-legal-footer>",
227
227
  presentation.footerHtml ?? "",
228
228
  logo("footer"),
229
229
  "</footer>",