@businessdash/sdk 0.9.60 → 0.9.80

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 (239) hide show
  1. package/README.md +991 -295
  2. package/assets/biab-sw.js +92 -0
  3. package/dist/account-core/index.d.ts +126 -0
  4. package/dist/account-core/index.d.ts.map +1 -0
  5. package/dist/account-core/index.js +191 -0
  6. package/dist/account-core/index.js.map +1 -0
  7. package/dist/account.d.ts +11 -0
  8. package/dist/account.d.ts.map +1 -0
  9. package/dist/account.js +11 -0
  10. package/dist/account.js.map +1 -0
  11. package/dist/auth-handler.d.ts +1 -1
  12. package/dist/auth-links.d.ts +33 -0
  13. package/dist/auth-links.d.ts.map +1 -0
  14. package/dist/auth-links.js +64 -0
  15. package/dist/auth-links.js.map +1 -0
  16. package/dist/blog-core/index.d.ts +112 -0
  17. package/dist/blog-core/index.d.ts.map +1 -0
  18. package/dist/blog-core/index.js +330 -0
  19. package/dist/blog-core/index.js.map +1 -0
  20. package/dist/blog.d.ts +11 -0
  21. package/dist/blog.d.ts.map +1 -0
  22. package/dist/blog.js +11 -0
  23. package/dist/blog.js.map +1 -0
  24. package/dist/chat-core/index.d.ts +97 -0
  25. package/dist/chat-core/index.d.ts.map +1 -0
  26. package/dist/chat-core/index.js +237 -0
  27. package/dist/chat-core/index.js.map +1 -0
  28. package/dist/chat.d.ts +11 -0
  29. package/dist/chat.d.ts.map +1 -0
  30. package/dist/chat.js +11 -0
  31. package/dist/chat.js.map +1 -0
  32. package/dist/checkout-core/index.d.ts +65 -0
  33. package/dist/checkout-core/index.d.ts.map +1 -0
  34. package/dist/checkout-core/index.js +159 -0
  35. package/dist/checkout-core/index.js.map +1 -0
  36. package/dist/checkout.d.ts +10 -0
  37. package/dist/checkout.d.ts.map +1 -0
  38. package/dist/checkout.js +10 -0
  39. package/dist/checkout.js.map +1 -0
  40. package/dist/cli.js +133 -25
  41. package/dist/cli.js.map +1 -1
  42. package/dist/client.d.ts +622 -1
  43. package/dist/client.d.ts.map +1 -1
  44. package/dist/client.js +888 -1
  45. package/dist/client.js.map +1 -1
  46. package/dist/consent-core/index.cjs +107 -0
  47. package/dist/consent-core/index.d.ts +103 -0
  48. package/dist/consent-core/index.d.ts.map +1 -0
  49. package/dist/consent-core/index.js +157 -0
  50. package/dist/consent-core/index.js.map +1 -0
  51. package/dist/contracts.d.ts +3526 -767
  52. package/dist/contracts.d.ts.map +1 -1
  53. package/dist/contracts.js +571 -4
  54. package/dist/contracts.js.map +1 -1
  55. package/dist/data-model-schema.d.ts +1 -1
  56. package/dist/data-model-schema.d.ts.map +1 -1
  57. package/dist/element.d.ts +30 -0
  58. package/dist/element.d.ts.map +1 -1
  59. package/dist/element.js +56 -0
  60. package/dist/element.js.map +1 -1
  61. package/dist/embed-protocol.d.ts +86 -0
  62. package/dist/embed-protocol.d.ts.map +1 -0
  63. package/dist/embed-protocol.js +60 -0
  64. package/dist/embed-protocol.js.map +1 -0
  65. package/dist/framework-support.d.ts +122 -0
  66. package/dist/framework-support.d.ts.map +1 -0
  67. package/dist/framework-support.js +323 -0
  68. package/dist/framework-support.js.map +1 -0
  69. package/dist/index.cjs +1355 -24
  70. package/dist/legal-core/index.cjs +115 -0
  71. package/dist/legal-core/index.d.ts +160 -0
  72. package/dist/legal-core/index.d.ts.map +1 -0
  73. package/dist/legal-core/index.js +220 -0
  74. package/dist/legal-core/index.js.map +1 -0
  75. package/dist/marketing-core/index.d.ts +66 -0
  76. package/dist/marketing-core/index.d.ts.map +1 -0
  77. package/dist/marketing-core/index.js +154 -0
  78. package/dist/marketing-core/index.js.map +1 -0
  79. package/dist/marketing.d.ts +7 -0
  80. package/dist/marketing.d.ts.map +1 -0
  81. package/dist/marketing.js +7 -0
  82. package/dist/marketing.js.map +1 -0
  83. package/dist/mcp-adapters/index.d.ts +135 -0
  84. package/dist/mcp-adapters/index.d.ts.map +1 -0
  85. package/dist/mcp-adapters/index.js +187 -0
  86. package/dist/mcp-adapters/index.js.map +1 -0
  87. package/dist/mcp-adapters.d.ts +7 -0
  88. package/dist/mcp-adapters.d.ts.map +1 -0
  89. package/dist/mcp-adapters.js +7 -0
  90. package/dist/mcp-adapters.js.map +1 -0
  91. package/dist/model3d-core/index.cjs +95 -0
  92. package/dist/model3d-core/index.d.ts +167 -0
  93. package/dist/model3d-core/index.d.ts.map +1 -0
  94. package/dist/model3d-core/index.js +158 -0
  95. package/dist/model3d-core/index.js.map +1 -0
  96. package/dist/notifications-core/index.cjs +315 -0
  97. package/dist/notifications-core/index.d.ts +229 -0
  98. package/dist/notifications-core/index.d.ts.map +1 -0
  99. package/dist/notifications-core/index.js +445 -0
  100. package/dist/notifications-core/index.js.map +1 -0
  101. package/dist/portal-core/index.d.ts +451 -0
  102. package/dist/portal-core/index.d.ts.map +1 -0
  103. package/dist/portal-core/index.js +819 -0
  104. package/dist/portal-core/index.js.map +1 -0
  105. package/dist/portal.d.ts +7 -0
  106. package/dist/portal.d.ts.map +1 -0
  107. package/dist/portal.js +7 -0
  108. package/dist/portal.js.map +1 -0
  109. package/dist/push-core/index.cjs +171 -0
  110. package/dist/push-core/index.d.ts +149 -0
  111. package/dist/push-core/index.d.ts.map +1 -0
  112. package/dist/push-core/index.js +231 -0
  113. package/dist/push-core/index.js.map +1 -0
  114. package/dist/react-marketing.d.ts +1 -17
  115. package/dist/react-marketing.d.ts.map +1 -1
  116. package/dist/react-marketing.js +4 -0
  117. package/dist/react-marketing.js.map +1 -1
  118. package/dist/react.d.ts +294 -101
  119. package/dist/react.d.ts.map +1 -1
  120. package/dist/react.js +302 -246
  121. package/dist/react.js.map +1 -1
  122. package/dist/seed-core/index.d.ts +354 -0
  123. package/dist/seed-core/index.d.ts.map +1 -0
  124. package/dist/seed-core/index.js +420 -0
  125. package/dist/seed-core/index.js.map +1 -0
  126. package/dist/seed.d.ts +7 -0
  127. package/dist/seed.d.ts.map +1 -0
  128. package/dist/seed.js +7 -0
  129. package/dist/seed.js.map +1 -0
  130. package/dist/seo-core/blog.d.ts +94 -0
  131. package/dist/seo-core/blog.d.ts.map +1 -0
  132. package/dist/seo-core/blog.js +149 -0
  133. package/dist/seo-core/blog.js.map +1 -0
  134. package/dist/seo-core/commerce.d.ts +64 -0
  135. package/dist/seo-core/commerce.d.ts.map +1 -0
  136. package/dist/seo-core/commerce.js +87 -0
  137. package/dist/seo-core/commerce.js.map +1 -0
  138. package/dist/seo-core/index.cjs +751 -0
  139. package/dist/seo-core/index.d.ts +226 -0
  140. package/dist/seo-core/index.d.ts.map +1 -0
  141. package/dist/seo-core/index.js +455 -0
  142. package/dist/seo-core/index.js.map +1 -0
  143. package/dist/seo-core/local.d.ts +181 -0
  144. package/dist/seo-core/local.d.ts.map +1 -0
  145. package/dist/seo-core/local.js +193 -0
  146. package/dist/seo-core/local.js.map +1 -0
  147. package/dist/sitemap-core/index.cjs +167 -0
  148. package/dist/sitemap-core/index.d.ts +155 -0
  149. package/dist/sitemap-core/index.d.ts.map +1 -0
  150. package/dist/sitemap-core/index.js +195 -0
  151. package/dist/sitemap-core/index.js.map +1 -0
  152. package/dist/social-core/index.d.ts +74 -0
  153. package/dist/social-core/index.d.ts.map +1 -0
  154. package/dist/social-core/index.js +72 -0
  155. package/dist/social-core/index.js.map +1 -0
  156. package/dist/social.d.ts +7 -0
  157. package/dist/social.d.ts.map +1 -0
  158. package/dist/social.js +7 -0
  159. package/dist/social.js.map +1 -0
  160. package/dist/solid-compat.d.ts +204 -0
  161. package/dist/solid-compat.d.ts.map +1 -0
  162. package/dist/solid-compat.js +221 -0
  163. package/dist/solid-compat.js.map +1 -0
  164. package/dist/store-core/index.d.ts +141 -0
  165. package/dist/store-core/index.d.ts.map +1 -0
  166. package/dist/store-core/index.js +277 -0
  167. package/dist/store-core/index.js.map +1 -0
  168. package/dist/store.d.ts +12 -0
  169. package/dist/store.d.ts.map +1 -0
  170. package/dist/store.js +12 -0
  171. package/dist/store.js.map +1 -0
  172. package/dist/vanilla.d.ts +111 -0
  173. package/dist/vanilla.d.ts.map +1 -1
  174. package/dist/vanilla.js +206 -0
  175. package/dist/vanilla.js.map +1 -1
  176. package/dist/verify-core/index.d.ts +98 -0
  177. package/dist/verify-core/index.d.ts.map +1 -0
  178. package/dist/verify-core/index.js +186 -0
  179. package/dist/verify-core/index.js.map +1 -0
  180. package/dist/verify.d.ts +8 -0
  181. package/dist/verify.d.ts.map +1 -0
  182. package/dist/verify.js +8 -0
  183. package/dist/verify.js.map +1 -0
  184. package/openapi.json +4516 -1311
  185. package/package.json +128 -11
  186. package/src/account-core/index.ts +309 -0
  187. package/src/account.ts +11 -0
  188. package/src/angular/headless.ts +519 -0
  189. package/src/angular/index.ts +3 -0
  190. package/src/auth-links.ts +76 -0
  191. package/src/blog-core/index.ts +423 -0
  192. package/src/blog.ts +11 -0
  193. package/src/chat-core/index.ts +335 -0
  194. package/src/chat.ts +11 -0
  195. package/src/checkout-core/index.ts +225 -0
  196. package/src/checkout.ts +10 -0
  197. package/src/cli.ts +184 -28
  198. package/src/client.ts +1097 -0
  199. package/src/consent-core/index.ts +213 -0
  200. package/src/contracts.ts +768 -11
  201. package/src/data-model-schema.ts +1 -1
  202. package/src/element.ts +102 -0
  203. package/src/embed-protocol.ts +100 -0
  204. package/src/framework-support.ts +440 -0
  205. package/src/legal-core/index.ts +276 -0
  206. package/src/marketing-core/index.ts +209 -0
  207. package/src/marketing.ts +7 -0
  208. package/src/mcp-adapters/index.ts +264 -0
  209. package/src/mcp-adapters.ts +7 -0
  210. package/src/model3d-core/index.ts +248 -0
  211. package/src/notifications-core/index.ts +650 -0
  212. package/src/portal-core/index.ts +1564 -0
  213. package/src/portal.ts +7 -0
  214. package/src/push-core/index.ts +335 -0
  215. package/src/qwik.tsx +602 -2
  216. package/src/react-marketing.tsx +5 -0
  217. package/src/react.tsx +434 -319
  218. package/src/seed-core/index.ts +735 -0
  219. package/src/seed.ts +7 -0
  220. package/src/seo-core/blog.ts +216 -0
  221. package/src/seo-core/commerce.ts +138 -0
  222. package/src/seo-core/index.ts +605 -0
  223. package/src/seo-core/local.ts +333 -0
  224. package/src/sitemap-core/index.ts +296 -0
  225. package/src/social-core/index.ts +103 -0
  226. package/src/social.ts +7 -0
  227. package/src/solid-compat.tsx +347 -0
  228. package/src/solid-surfaces.tsx +1311 -0
  229. package/src/solid.tsx +82 -60
  230. package/src/store-core/index.ts +426 -0
  231. package/src/store.ts +12 -0
  232. package/src/svelte/SocialLinks.svelte +84 -0
  233. package/src/svelte/headless.ts +435 -0
  234. package/src/svelte/index.ts +9 -0
  235. package/src/vanilla.ts +367 -0
  236. package/src/verify-core/index.ts +288 -0
  237. package/src/verify.ts +8 -0
  238. package/src/vue/headless.ts +527 -0
  239. package/src/vue/index.ts +3 -0
@@ -2640,7 +2640,7 @@ export type FindFieldTypeByPath<
2640
2640
  C extends readonly CollectionDefinition[],
2641
2641
  > =
2642
2642
  C[number] extends CollectionDefinition<infer F>
2643
- ? Path extends `${infer N}.${infer K}`
2643
+ ? Path extends `${string}.${infer K}`
2644
2644
  ? K extends keyof F
2645
2645
  ? InferFieldValue<F[K]>
2646
2646
  : never
package/src/element.ts CHANGED
@@ -319,3 +319,105 @@ declare global {
319
319
  "biab-form": BiabFormElement;
320
320
  }
321
321
  }
322
+
323
+ export type {
324
+ FollowersController,
325
+ FollowersSnapshot,
326
+ UserController,
327
+ UserSnapshot,
328
+ } from "./account-core/index.js";
329
+ export type { ChatController, ChatSnapshot } from "./chat-core/index.js";
330
+ export type {
331
+ CheckoutController,
332
+ CheckoutSnapshot,
333
+ } from "./checkout-core/index.js";
334
+ export type {
335
+ MarketingController,
336
+ MarketingSnapshot,
337
+ } from "./marketing-core/index.js";
338
+ export type { PortalController, PortalSnapshot } from "./portal-core/index.js";
339
+ export type { StoreController, StoreSnapshot } from "./store-core/index.js";
340
+ // The native (non-iframe) storefront and chat controllers. `<biab-form>` is a
341
+ // custom element because forms need DOM; a storefront controller does not, so
342
+ // it is re-exported as-is from the framework-free binding rather than wrapped
343
+ // in an element that would only get in the way.
344
+ export {
345
+ type CreateChatOptions,
346
+ type CreateStorefrontOptions,
347
+ createChat,
348
+ createCheckout,
349
+ createFollowers,
350
+ createMarketing,
351
+ createPortal,
352
+ createStorefront,
353
+ createUser,
354
+ createVerify,
355
+ signIn,
356
+ signInHref,
357
+ signOut,
358
+ signOutHref,
359
+ signUp,
360
+ signUpHref,
361
+ } from "./vanilla.js";
362
+ export type {
363
+ VerifyController,
364
+ VerifyFlow,
365
+ VerifySnapshot,
366
+ } from "./verify-core/index.js";
367
+
368
+ import { mountSocialLinks } from "./vanilla.js";
369
+
370
+ export type { SocialLinkRow } from "./social-core/index.js";
371
+ export { mountSocialLinks, resolveSocialLinks } from "./vanilla.js";
372
+
373
+ /**
374
+ * `<biab-social-links>` — the social block as a custom element.
375
+ *
376
+ * Attributes: `color`, `size`, `link-class`, `icon-class`. The `socials` record
377
+ * is a PROPERTY rather than an attribute, because it is an object and an
378
+ * attribute would mean stringifying it:
379
+ *
380
+ * ```js
381
+ * const el = document.querySelector("biab-social-links");
382
+ * el.socials = company.socials;
383
+ * ```
384
+ */
385
+ export class BiabSocialLinksElement extends HTMLElement {
386
+ #socials: unknown = null;
387
+
388
+ set socials(value: unknown) {
389
+ this.#socials = value;
390
+ this.#render();
391
+ }
392
+ get socials(): unknown {
393
+ return this.#socials;
394
+ }
395
+
396
+ connectedCallback(): void {
397
+ this.#render();
398
+ }
399
+
400
+ #render(): void {
401
+ const size = Number(this.getAttribute("size") ?? 20);
402
+ mountSocialLinks(this, {
403
+ socials: this.#socials,
404
+ ...(this.getAttribute("color")
405
+ ? { color: this.getAttribute("color") as string }
406
+ : {}),
407
+ size: Number.isFinite(size) ? size : 20,
408
+ ...(this.getAttribute("link-class")
409
+ ? { linkClass: this.getAttribute("link-class") as string }
410
+ : {}),
411
+ ...(this.getAttribute("icon-class")
412
+ ? { iconClass: this.getAttribute("icon-class") as string }
413
+ : {}),
414
+ });
415
+ }
416
+ }
417
+
418
+ /** Register `<biab-social-links>`. Safe to call more than once. */
419
+ export function defineBiabSocialLinks(tagName = "biab-social-links"): void {
420
+ if (typeof customElements === "undefined") return;
421
+ if (customElements.get(tagName)) return;
422
+ customElements.define(tagName, BiabSocialLinksElement);
423
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * The postMessage protocol shared by every embed surface, and the guard that
3
+ * decides which messages are trusted.
4
+ *
5
+ * This lives in its own framework-free module because more than one binding
6
+ * renders these iframes. The React binding had it inline, and copying it into
7
+ * the Solid binding would have meant two implementations of an ORIGIN CHECK —
8
+ * the kind of duplication where the copies drift and the weaker one silently
9
+ * becomes the security posture of whichever framework a customer happened to
10
+ * pick. One implementation, imported by both.
11
+ *
12
+ * @module
13
+ */
14
+
15
+ /** Every event a BusinessDash embed posts to its host page. */
16
+ export type BiabEmbedEvent =
17
+ | { type: "biab:ready"; surface: string }
18
+ | { type: "biab:cart:update"; count: number; subtotalCents: number }
19
+ | {
20
+ type: "biab:cart:checkout-requested";
21
+ lines: Array<{
22
+ productId: string;
23
+ variantId: string;
24
+ combinationKey?: string;
25
+ quantity: number;
26
+ }>;
27
+ }
28
+ | {
29
+ type: "biab:checkout:success";
30
+ sessionId: string;
31
+ orderId?: string | null;
32
+ }
33
+ | { type: "biab:checkout:cancel"; sessionId: string }
34
+ | { type: "biab:checkout:error"; message: string }
35
+ | { type: "biab:chatbot:user-message"; content: string }
36
+ | { type: "biab:chatbot:assistant-message"; content: string; model?: string }
37
+ | { type: "biab:chatbot:error"; message: string };
38
+
39
+ /**
40
+ * The sandbox tokens every embed iframe gets. Checkout adds
41
+ * `allow-top-navigation` so Stripe can take over the tab.
42
+ */
43
+ export const DEFAULT_EMBED_SANDBOX =
44
+ "allow-scripts allow-forms allow-same-origin allow-popups";
45
+
46
+ /**
47
+ * Listen for embed messages on `window` and hand the trusted ones to `handler`.
48
+ * Returns an unsubscribe function, which each binding wires to its own cleanup
49
+ * (`useEffect` teardown in React, `onCleanup` in Solid).
50
+ *
51
+ * `getIframe` is a callback rather than an element because the iframe may not
52
+ * exist yet when the listener is attached, and because a re-render can swap it.
53
+ * When it resolves to an element, messages from any other window are dropped —
54
+ * that check is the whole point of this function.
55
+ */
56
+ export function subscribeToEmbedMessages(
57
+ getIframe: () => HTMLIFrameElement | null | undefined,
58
+ handler: (event: BiabEmbedEvent) => void,
59
+ ): () => void {
60
+ if (typeof window === "undefined") return () => {};
61
+
62
+ const onMessage = (e: MessageEvent) => {
63
+ if (!e.data || typeof e.data !== "object") return;
64
+ if ((e.data as { kind?: string }).kind !== "biab") return;
65
+ const iframe = getIframe();
66
+ if (iframe && e.source !== null && e.source !== iframe.contentWindow) {
67
+ return;
68
+ }
69
+ const { kind, ...rest } = e.data as { kind: string } & BiabEmbedEvent;
70
+ void kind;
71
+ handler(rest as BiabEmbedEvent);
72
+ };
73
+
74
+ window.addEventListener("message", onMessage);
75
+ return () => window.removeEventListener("message", onMessage);
76
+ }
77
+
78
+ /** The session shape every embed surface resolves to before it can render. */
79
+ export type EmbedSessionState<T> =
80
+ | { status: "idle" }
81
+ | { status: "loading" }
82
+ | { status: "ready"; session: T }
83
+ | { status: "error"; error: Error };
84
+
85
+ /**
86
+ * When to refresh a session, in ms from now. Sessions carry an `expiresAt`;
87
+ * both bindings refresh `refreshLeadMs` before it, with a 1s floor so a
88
+ * clock skew or an already-expired session can't spin.
89
+ */
90
+ export function refreshDelayMs(
91
+ expiresAt: string,
92
+ refreshLeadMs: number,
93
+ now: number,
94
+ ): number | null {
95
+ const expiry = Date.parse(expiresAt);
96
+ if (Number.isNaN(expiry)) return null;
97
+ return Math.max(1_000, expiry - now - refreshLeadMs);
98
+ }
99
+
100
+ export const DEFAULT_REFRESH_LEAD_MS = 30_000;
@@ -0,0 +1,440 @@
1
+ /**
2
+ * Which framework versions each adapter supports — one source of truth,
3
+ * consumed by `package.json` peer ranges, the docs matrix, and (later) the
4
+ * runtime mismatch warning.
5
+ *
6
+ * WHY THIS EXISTS
7
+ *
8
+ * Frameworks break their own APIs. When one ships a major that reworks
9
+ * reactivity or JSX, an adapter written against the old dialect stops
10
+ * compiling for anyone who upgrades — and, just as bad, our docs keep showing
11
+ * one implementation as if it were universal. A developer on the new major
12
+ * follows a page that silently describes the old one.
13
+ *
14
+ * The blast radius is already small by design: every binding is a thin view
15
+ * over the framework-agnostic core (`createFormController` in
16
+ * `@businessdash/sdk/forms`). Values, validation, conditional visibility,
17
+ * multi-step navigation, uploads and submit lifecycle all live there and
18
+ * survive any framework major untouched. Only the binding layer — how an
19
+ * external store becomes reactive state, and how a list renders — is
20
+ * version-sensitive.
21
+ *
22
+ * `frameworkApis` names exactly which imports each binding leans on, so when
23
+ * a major lands the question "does this break us?" is a diff against a list
24
+ * rather than a reread of 1,400 lines.
25
+ *
26
+ * WHEN A MAJOR BREAKS AN ADAPTER
27
+ *
28
+ * Add a second entry for the same adapter with the new range and a distinct
29
+ * `dialect`, rather than rewriting the existing one. Both ship; the docs show
30
+ * both; consumers on either major get working code. Retire the old entry only
31
+ * when that major is genuinely out of support.
32
+ */
33
+
34
+ export type FrameworkSupport = {
35
+ /** Subpath consumers import, e.g. `@businessdash/sdk/solid`. */
36
+ entry: string;
37
+ /** npm package the adapter binds to. */
38
+ pkg: string;
39
+ /** Semver range this adapter is written against and tested on. */
40
+ range: string;
41
+ /**
42
+ * Distinguishes two adapters for the same framework across a breaking
43
+ * major. `default` until a second dialect is needed.
44
+ */
45
+ dialect: string;
46
+ /**
47
+ * SOURCE ships uncompiled and is built by the consumer's toolchain (so
48
+ * their compiler version matters); COMPILED ships as JS from our build.
49
+ */
50
+ shipMode: "source" | "compiled";
51
+ /**
52
+ * The framework imports this binding depends on. A breaking major is
53
+ * assessed by diffing this list against the framework's changelog.
54
+ */
55
+ frameworkApis: readonly string[];
56
+ /** `supported` = tested. `untested` = expected to work, unverified. */
57
+ status: "supported" | "untested" | "deprecated";
58
+ /**
59
+ * What this adapter can actually DO, and — just as important — HOW.
60
+ *
61
+ * A capability recorded as `embed` is a BusinessDash-hosted page in a
62
+ * sandboxed iframe. It works, but it renders our markup inside your app, not
63
+ * yours. `native` means real components rendering into your own DOM, themed
64
+ * by your own CSS. Collapsing the two into a yes/no would let a binding that
65
+ * only wraps an iframe claim the same support as one with real components —
66
+ * which is exactly how `chatbot` briefly looked equal on React and Solid when
67
+ * React has 1,200 lines of headless chat UI and Solid has an iframe.
68
+ *
69
+ * This map is the single source of truth for that claim: the docs matrix
70
+ * renders it, and `test/framework-parity.test.ts` derives the same levels
71
+ * from the source and asserts they agree — so the page cannot promise a
72
+ * capability, or a level of it, the adapter doesn't have.
73
+ */
74
+ capabilities: CapabilityMatrix;
75
+ notes?: string;
76
+ };
77
+
78
+ /** The capability areas an adapter can expose. See `CAPABILITY_LABELS`. */
79
+ export type Capability =
80
+ | "forms"
81
+ | "client-di"
82
+ | "chatbot"
83
+ | "auth"
84
+ | "storefront"
85
+ | "cart"
86
+ | "checkout"
87
+ | "blog"
88
+ | "customer-portal"
89
+ | "marketing-pages"
90
+ | "followers"
91
+ | "social-links"
92
+ | "email-verify"
93
+ | "phone-verify";
94
+
95
+ /**
96
+ * HOW a capability is delivered.
97
+ *
98
+ * `native` — components/hooks rendering into the consumer's own DOM.
99
+ * `embed` — a BusinessDash-hosted page in a sandboxed iframe.
100
+ * `both` — the surface exists in both forms (e.g. React's chat: an iframe
101
+ * widget AND a headless hook for hosts rendering their own UI).
102
+ */
103
+ export type CapabilityLevel = "native" | "embed" | "both";
104
+
105
+ export type CapabilityMatrix = Readonly<
106
+ Partial<Record<Capability, CapabilityLevel>>
107
+ >;
108
+
109
+ /** Human-readable names, in the order the docs table renders them. */
110
+ export const CAPABILITY_LABELS: Readonly<Record<Capability, string>> = {
111
+ forms: "Forms",
112
+ "client-di": "Shared client",
113
+ chatbot: "AI chat",
114
+ auth: "Customer auth",
115
+ storefront: "Storefront",
116
+ cart: "Cart",
117
+ checkout: "Checkout",
118
+ blog: "Blog",
119
+ "customer-portal": "Customer portal",
120
+ "marketing-pages": "Marketing pages",
121
+ followers: "Followers",
122
+ "social-links": "Social links",
123
+ "email-verify": "Email verification",
124
+ "phone-verify": "Phone verification",
125
+ };
126
+
127
+ export const ALL_CAPABILITIES = Object.keys(CAPABILITY_LABELS) as Capability[];
128
+
129
+ /**
130
+ * Everything `@businessdash/sdk/react` exposes — the full product.
131
+ *
132
+ * Note how much of it is `embed`: storefront, cart and blog are hosted pages in
133
+ * every binding INCLUDING React. No framework has a native storefront, so on
134
+ * those surfaces the other bindings are not behind — there is simply nothing
135
+ * more to have yet.
136
+ */
137
+ const FULL_SURFACE: CapabilityMatrix = {
138
+ forms: "native",
139
+ "client-di": "native",
140
+ chatbot: "both",
141
+ auth: "native",
142
+ // `both`: the hosted iframe widget AND the headless controller. The native
143
+ // path is `useStorefront` / `useChatbot` over `store-core` / `chat-core`.
144
+ storefront: "both",
145
+ cart: "both",
146
+ checkout: "both",
147
+ blog: "both",
148
+ "customer-portal": "both",
149
+ "marketing-pages": "native",
150
+ followers: "native",
151
+ "social-links": "native",
152
+ "email-verify": "native",
153
+ "phone-verify": "native",
154
+ };
155
+
156
+ /**
157
+ * Forms, a shared client, and the two native surfaces every binding now has.
158
+ *
159
+ * `storefront`, `cart` and `chatbot` are `native` rather than `both` here: these
160
+ * bindings expose the headless controllers, not the hosted iframe widgets. They
161
+ * render into the consumer's own DOM, which is the harder and better half.
162
+ */
163
+ const FORMS_AND_CLIENT: CapabilityMatrix = {
164
+ forms: "native",
165
+ "client-di": "native",
166
+ storefront: "native",
167
+ cart: "native",
168
+ chatbot: "native",
169
+ blog: "native",
170
+ auth: "native",
171
+ checkout: "native",
172
+ followers: "native",
173
+ "marketing-pages": "native",
174
+ "email-verify": "native",
175
+ "phone-verify": "native",
176
+ "social-links": "native",
177
+ "customer-portal": "native",
178
+ };
179
+
180
+ export const FRAMEWORK_SUPPORT: readonly FrameworkSupport[] = [
181
+ {
182
+ entry: "@businessdash/sdk/react",
183
+ pkg: "react",
184
+ range: ">=18.0.0 <20",
185
+ dialect: "default",
186
+ shipMode: "compiled",
187
+ frameworkApis: [
188
+ "useSyncExternalStore",
189
+ "useState",
190
+ "useMemo",
191
+ "useEffect",
192
+ "useId",
193
+ "createContext",
194
+ "useContext",
195
+ ],
196
+ capabilities: FULL_SURFACE,
197
+ status: "supported",
198
+ },
199
+ {
200
+ entry: "@businessdash/sdk/solid",
201
+ pkg: "solid-js",
202
+ range: ">=1.8.0 <2",
203
+ dialect: "v1",
204
+ shipMode: "source",
205
+ frameworkApis: [
206
+ "from",
207
+ "createSignal",
208
+ "createMemo",
209
+ "createContext",
210
+ "useContext",
211
+ "createUniqueId",
212
+ "onMount",
213
+ "onCleanup",
214
+ "For",
215
+ "Show",
216
+ "Switch",
217
+ "Match",
218
+ ],
219
+ capabilities: {
220
+ forms: "native",
221
+ "client-di": "native",
222
+ // The hosted widget plus `createChat`. React additionally ships
223
+ // `<ChatbotInline>`, a rendered chat UI that Solid does not have — the
224
+ // headless controller beneath them is the same.
225
+ chatbot: "both",
226
+ auth: "native",
227
+ storefront: "both",
228
+ cart: "both",
229
+ checkout: "both",
230
+ blog: "both",
231
+ "customer-portal": "both",
232
+ followers: "native",
233
+ "social-links": "native",
234
+ "marketing-pages": "native",
235
+ "email-verify": "native",
236
+ "phone-verify": "native",
237
+ },
238
+ status: "supported",
239
+ notes:
240
+ "Solid 2.0 shipped 2026-08 with a substantial API rework. This adapter is written against the 1.x dialect and is NOT yet verified on 2.x — a `v2` entry alongside this one is the intended shape, not a rewrite of it.",
241
+ },
242
+ {
243
+ entry: "@businessdash/sdk/vue",
244
+ pkg: "vue",
245
+ range: ">=3.3.0 <4",
246
+ dialect: "default",
247
+ shipMode: "source",
248
+ frameworkApis: [
249
+ "defineComponent",
250
+ "ref",
251
+ "computed",
252
+ "onMounted",
253
+ "onUnmounted",
254
+ "provide",
255
+ "inject",
256
+ "h",
257
+ ],
258
+ capabilities: FORMS_AND_CLIENT,
259
+ status: "supported",
260
+ },
261
+ {
262
+ entry: "@businessdash/sdk/svelte",
263
+ pkg: "svelte",
264
+ range: ">=5.0.0 <6",
265
+ dialect: "runes",
266
+ shipMode: "source",
267
+ frameworkApis: ["$state", "$derived", "$effect", "onMount", "onDestroy"],
268
+ capabilities: FORMS_AND_CLIENT,
269
+ status: "supported",
270
+ notes:
271
+ "Written against Svelte 5 runes. Svelte 4's store-based dialect is a separate entry if it's ever needed.",
272
+ },
273
+ {
274
+ entry: "@businessdash/sdk/qwik",
275
+ pkg: "@builder.io/qwik",
276
+ range: ">=1.5.0 <2",
277
+ dialect: "default",
278
+ shipMode: "source",
279
+ frameworkApis: [
280
+ "component$",
281
+ "useSignal",
282
+ "useStore",
283
+ "useVisibleTask$",
284
+ "useComputed$",
285
+ ],
286
+ capabilities: {
287
+ forms: "native",
288
+ storefront: "native",
289
+ cart: "native",
290
+ chatbot: "native",
291
+ blog: "native",
292
+ auth: "native",
293
+ checkout: "native",
294
+ followers: "native",
295
+ "marketing-pages": "native",
296
+ "email-verify": "native",
297
+ "phone-verify": "native",
298
+ "social-links": "native",
299
+ "customer-portal": "native",
300
+ },
301
+ status: "untested",
302
+ },
303
+ {
304
+ entry: "@businessdash/sdk/angular",
305
+ pkg: "@angular/core",
306
+ range: ">=17.0.0",
307
+ dialect: "standalone",
308
+ shipMode: "source",
309
+ frameworkApis: ["Component", "signal", "computed", "effect", "inject"],
310
+ capabilities: FORMS_AND_CLIENT,
311
+ status: "untested",
312
+ notes: "Written against standalone components + signals (Angular 17+).",
313
+ },
314
+ {
315
+ entry: "@businessdash/sdk/vanilla",
316
+ pkg: "(none)",
317
+ range: "*",
318
+ dialect: "default",
319
+ shipMode: "compiled",
320
+ frameworkApis: [],
321
+ capabilities: {
322
+ forms: "native",
323
+ storefront: "native",
324
+ cart: "native",
325
+ chatbot: "native",
326
+ blog: "native",
327
+ auth: "native",
328
+ checkout: "native",
329
+ followers: "native",
330
+ "marketing-pages": "native",
331
+ "email-verify": "native",
332
+ "phone-verify": "native",
333
+ "social-links": "native",
334
+ "customer-portal": "native",
335
+ },
336
+ status: "supported",
337
+ notes:
338
+ "No framework dependency — the fallback that cannot be broken by anyone else's major.",
339
+ },
340
+ {
341
+ entry: "@businessdash/sdk/element",
342
+ pkg: "(none)",
343
+ range: "*",
344
+ dialect: "default",
345
+ shipMode: "compiled",
346
+ frameworkApis: ["customElements"],
347
+ capabilities: FORMS_AND_CLIENT,
348
+ status: "supported",
349
+ notes:
350
+ "Web component. Works inside any framework, and is the recommended escape hatch when a framework major outpaces its adapter.",
351
+ },
352
+ ];
353
+
354
+ /** All adapters for one framework package — several when majors diverge. */
355
+ export function supportFor(pkg: string): readonly FrameworkSupport[] {
356
+ return FRAMEWORK_SUPPORT.filter((f) => f.pkg === pkg);
357
+ }
358
+
359
+ /**
360
+ * REACT-COMPATIBLE TARGETS.
361
+ *
362
+ * These are not separate adapters and never will be: they render React (or a
363
+ * drop-in replacement for it), so they import `@businessdash/sdk/react` and get
364
+ * the FULL surface — all fourteen capabilities, not the forms-only subset the
365
+ * non-React bindings have. Someone choosing Next, Astro or Preact is not
366
+ * choosing a smaller SDK.
367
+ *
368
+ * They are listed because that was not previously discoverable anywhere. The
369
+ * adapter table names eight bindings and says nothing about the meta-frameworks
370
+ * most people actually build on, so "does Next work?" had no documented answer.
371
+ *
372
+ * `requires` is the per-target integration detail — the thing that bites on day
373
+ * one, not a general description.
374
+ */
375
+ export type ReactTarget = {
376
+ /** Framework name as its own docs spell it. */
377
+ name: string;
378
+ /** Which SDK entry point to import. */
379
+ entry: string;
380
+ /** What the consumer must do to make it work in that framework. */
381
+ requires: string;
382
+ /** Starter template that exercises it, under `SDK-Starter-Templates/`. */
383
+ starter?: string;
384
+ status: "supported" | "untested";
385
+ };
386
+
387
+ export const REACT_TARGETS: readonly ReactTarget[] = [
388
+ {
389
+ name: "React",
390
+ entry: "@businessdash/sdk/react",
391
+ requires: "Nothing — import and render.",
392
+ starter: "React-Bun",
393
+ status: "supported",
394
+ },
395
+ {
396
+ name: "Next.js (App Router)",
397
+ entry: "@businessdash/sdk/react",
398
+ requires:
399
+ 'Nothing as of 0.9.61 — the adapter now carries its own `"use client"` boundary, so components import directly into a server-rendered page. Before that, every component needed a hand-written client wrapper.',
400
+ starter: "T3-App",
401
+ status: "supported",
402
+ },
403
+ {
404
+ name: "Astro",
405
+ entry: "@businessdash/sdk/react",
406
+ requires:
407
+ "`@astrojs/react`, and a client directive on the island (`<ContactForm client:load />`) — without one Astro renders it to static HTML and no handler ever attaches.",
408
+ starter: "Astro",
409
+ status: "supported",
410
+ },
411
+ {
412
+ name: "Remix / React Router 7",
413
+ entry: "@businessdash/sdk/react",
414
+ requires: "Nothing — no RSC boundary to cross.",
415
+ starter: "Remix",
416
+ status: "supported",
417
+ },
418
+ {
419
+ name: "TanStack Start",
420
+ entry: "@businessdash/sdk/react",
421
+ requires: "Nothing — no RSC boundary to cross.",
422
+ starter: "Tanstack-Start",
423
+ status: "supported",
424
+ },
425
+ {
426
+ name: "Preact",
427
+ entry: "@businessdash/sdk/react",
428
+ requires:
429
+ "The standard `preact/compat` alias in your bundler — nothing SDK-specific. The binding imports nine runtime symbols from `react` and never imports `react-dom`, so it is renderer-agnostic; `test/preact-compat.test.ts` renders components on both and asserts identical markup.",
430
+ status: "supported",
431
+ },
432
+ {
433
+ name: "React Native / Expo",
434
+ entry: "@businessdash/sdk/native",
435
+ requires:
436
+ "The `native` entry, not `react` — the DOM components don't render there. Data access and auth are shared; the UI is yours.",
437
+ starter: "React-Native",
438
+ status: "supported",
439
+ },
440
+ ];