@businessdash/sdk 0.9.60 → 0.9.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1012 -186
- package/assets/biab-sw.js +92 -0
- package/dist/account-core/index.d.ts +126 -0
- package/dist/account-core/index.d.ts.map +1 -0
- package/dist/account-core/index.js +191 -0
- package/dist/account-core/index.js.map +1 -0
- package/dist/account.d.ts +11 -0
- package/dist/account.d.ts.map +1 -0
- package/dist/account.js +11 -0
- package/dist/account.js.map +1 -0
- package/dist/auth-handler.d.ts +1 -1
- package/dist/auth-links.d.ts +33 -0
- package/dist/auth-links.d.ts.map +1 -0
- package/dist/auth-links.js +64 -0
- package/dist/auth-links.js.map +1 -0
- package/dist/blog-core/index.d.ts +112 -0
- package/dist/blog-core/index.d.ts.map +1 -0
- package/dist/blog-core/index.js +330 -0
- package/dist/blog-core/index.js.map +1 -0
- package/dist/blog.d.ts +11 -0
- package/dist/blog.d.ts.map +1 -0
- package/dist/blog.js +11 -0
- package/dist/blog.js.map +1 -0
- package/dist/chat-core/index.d.ts +97 -0
- package/dist/chat-core/index.d.ts.map +1 -0
- package/dist/chat-core/index.js +237 -0
- package/dist/chat-core/index.js.map +1 -0
- package/dist/chat.d.ts +11 -0
- package/dist/chat.d.ts.map +1 -0
- package/dist/chat.js +11 -0
- package/dist/chat.js.map +1 -0
- package/dist/checkout-core/index.d.ts +65 -0
- package/dist/checkout-core/index.d.ts.map +1 -0
- package/dist/checkout-core/index.js +159 -0
- package/dist/checkout-core/index.js.map +1 -0
- package/dist/checkout.d.ts +10 -0
- package/dist/checkout.d.ts.map +1 -0
- package/dist/checkout.js +10 -0
- package/dist/checkout.js.map +1 -0
- package/dist/cli.js +133 -25
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +567 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +807 -1
- package/dist/client.js.map +1 -1
- package/dist/contracts.d.ts +3309 -761
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +541 -4
- package/dist/contracts.js.map +1 -1
- package/dist/data-model-schema.d.ts +1 -1
- package/dist/data-model-schema.d.ts.map +1 -1
- package/dist/element.d.ts +30 -0
- package/dist/element.d.ts.map +1 -1
- package/dist/element.js +56 -0
- package/dist/element.js.map +1 -1
- package/dist/embed-protocol.d.ts +86 -0
- package/dist/embed-protocol.d.ts.map +1 -0
- package/dist/embed-protocol.js +60 -0
- package/dist/embed-protocol.js.map +1 -0
- package/dist/framework-support.d.ts +122 -0
- package/dist/framework-support.d.ts.map +1 -0
- package/dist/framework-support.js +323 -0
- package/dist/framework-support.js.map +1 -0
- package/dist/index.cjs +1244 -5
- package/dist/legal-core/index.cjs +115 -0
- package/dist/legal-core/index.d.ts +160 -0
- package/dist/legal-core/index.d.ts.map +1 -0
- package/dist/legal-core/index.js +220 -0
- package/dist/legal-core/index.js.map +1 -0
- package/dist/marketing-core/index.d.ts +66 -0
- package/dist/marketing-core/index.d.ts.map +1 -0
- package/dist/marketing-core/index.js +154 -0
- package/dist/marketing-core/index.js.map +1 -0
- package/dist/marketing.d.ts +7 -0
- package/dist/marketing.d.ts.map +1 -0
- package/dist/marketing.js +7 -0
- package/dist/marketing.js.map +1 -0
- package/dist/mcp-adapters/index.d.ts +135 -0
- package/dist/mcp-adapters/index.d.ts.map +1 -0
- package/dist/mcp-adapters/index.js +187 -0
- package/dist/mcp-adapters/index.js.map +1 -0
- package/dist/mcp-adapters.d.ts +7 -0
- package/dist/mcp-adapters.d.ts.map +1 -0
- package/dist/mcp-adapters.js +7 -0
- package/dist/mcp-adapters.js.map +1 -0
- package/dist/model3d-core/index.cjs +95 -0
- package/dist/model3d-core/index.d.ts +167 -0
- package/dist/model3d-core/index.d.ts.map +1 -0
- package/dist/model3d-core/index.js +158 -0
- package/dist/model3d-core/index.js.map +1 -0
- package/dist/notifications-core/index.cjs +315 -0
- package/dist/notifications-core/index.d.ts +229 -0
- package/dist/notifications-core/index.d.ts.map +1 -0
- package/dist/notifications-core/index.js +445 -0
- package/dist/notifications-core/index.js.map +1 -0
- package/dist/portal-core/index.d.ts +451 -0
- package/dist/portal-core/index.d.ts.map +1 -0
- package/dist/portal-core/index.js +819 -0
- package/dist/portal-core/index.js.map +1 -0
- package/dist/portal.d.ts +7 -0
- package/dist/portal.d.ts.map +1 -0
- package/dist/portal.js +7 -0
- package/dist/portal.js.map +1 -0
- package/dist/push-core/index.cjs +171 -0
- package/dist/push-core/index.d.ts +149 -0
- package/dist/push-core/index.d.ts.map +1 -0
- package/dist/push-core/index.js +231 -0
- package/dist/push-core/index.js.map +1 -0
- package/dist/react-marketing.d.ts +1 -17
- package/dist/react-marketing.d.ts.map +1 -1
- package/dist/react-marketing.js +4 -0
- package/dist/react-marketing.js.map +1 -1
- package/dist/react.d.ts +294 -101
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +302 -246
- package/dist/react.js.map +1 -1
- package/dist/seed-core/index.d.ts +354 -0
- package/dist/seed-core/index.d.ts.map +1 -0
- package/dist/seed-core/index.js +420 -0
- package/dist/seed-core/index.js.map +1 -0
- package/dist/seed.d.ts +7 -0
- package/dist/seed.d.ts.map +1 -0
- package/dist/seed.js +7 -0
- package/dist/seed.js.map +1 -0
- package/dist/seo-core/blog.d.ts +94 -0
- package/dist/seo-core/blog.d.ts.map +1 -0
- package/dist/seo-core/blog.js +149 -0
- package/dist/seo-core/blog.js.map +1 -0
- package/dist/seo-core/commerce.d.ts +64 -0
- package/dist/seo-core/commerce.d.ts.map +1 -0
- package/dist/seo-core/commerce.js +87 -0
- package/dist/seo-core/commerce.js.map +1 -0
- package/dist/seo-core/index.cjs +751 -0
- package/dist/seo-core/index.d.ts +226 -0
- package/dist/seo-core/index.d.ts.map +1 -0
- package/dist/seo-core/index.js +455 -0
- package/dist/seo-core/index.js.map +1 -0
- package/dist/seo-core/local.d.ts +181 -0
- package/dist/seo-core/local.d.ts.map +1 -0
- package/dist/seo-core/local.js +193 -0
- package/dist/seo-core/local.js.map +1 -0
- package/dist/sitemap-core/index.cjs +167 -0
- package/dist/sitemap-core/index.d.ts +155 -0
- package/dist/sitemap-core/index.d.ts.map +1 -0
- package/dist/sitemap-core/index.js +195 -0
- package/dist/sitemap-core/index.js.map +1 -0
- package/dist/social-core/index.d.ts +74 -0
- package/dist/social-core/index.d.ts.map +1 -0
- package/dist/social-core/index.js +72 -0
- package/dist/social-core/index.js.map +1 -0
- package/dist/social.d.ts +7 -0
- package/dist/social.d.ts.map +1 -0
- package/dist/social.js +7 -0
- package/dist/social.js.map +1 -0
- package/dist/solid-compat.d.ts +204 -0
- package/dist/solid-compat.d.ts.map +1 -0
- package/dist/solid-compat.js +221 -0
- package/dist/solid-compat.js.map +1 -0
- package/dist/store-core/index.d.ts +141 -0
- package/dist/store-core/index.d.ts.map +1 -0
- package/dist/store-core/index.js +277 -0
- package/dist/store-core/index.js.map +1 -0
- package/dist/store.d.ts +12 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +12 -0
- package/dist/store.js.map +1 -0
- package/dist/vanilla.d.ts +111 -0
- package/dist/vanilla.d.ts.map +1 -1
- package/dist/vanilla.js +206 -0
- package/dist/vanilla.js.map +1 -1
- package/dist/verify-core/index.d.ts +98 -0
- package/dist/verify-core/index.d.ts.map +1 -0
- package/dist/verify-core/index.js +186 -0
- package/dist/verify-core/index.js.map +1 -0
- package/dist/verify.d.ts +8 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +8 -0
- package/dist/verify.js.map +1 -0
- package/openapi.json +4316 -1313
- package/package.json +121 -9
- package/src/account-core/index.ts +309 -0
- package/src/account.ts +11 -0
- package/src/angular/headless.ts +519 -0
- package/src/angular/index.ts +3 -0
- package/src/auth-links.ts +76 -0
- package/src/blog-core/index.ts +423 -0
- package/src/blog.ts +11 -0
- package/src/chat-core/index.ts +335 -0
- package/src/chat.ts +11 -0
- package/src/checkout-core/index.ts +225 -0
- package/src/checkout.ts +10 -0
- package/src/cli.ts +184 -28
- package/src/client.ts +998 -0
- package/src/contracts.ts +730 -11
- package/src/data-model-schema.ts +1 -1
- package/src/element.ts +102 -0
- package/src/embed-protocol.ts +100 -0
- package/src/framework-support.ts +440 -0
- package/src/legal-core/index.ts +276 -0
- package/src/marketing-core/index.ts +209 -0
- package/src/marketing.ts +7 -0
- package/src/mcp-adapters/index.ts +264 -0
- package/src/mcp-adapters.ts +7 -0
- package/src/model3d-core/index.ts +248 -0
- package/src/notifications-core/index.ts +650 -0
- package/src/portal-core/index.ts +1564 -0
- package/src/portal.ts +7 -0
- package/src/push-core/index.ts +335 -0
- package/src/qwik.tsx +602 -2
- package/src/react-marketing.tsx +5 -0
- package/src/react.tsx +434 -319
- package/src/seed-core/index.ts +735 -0
- package/src/seed.ts +7 -0
- package/src/seo-core/blog.ts +216 -0
- package/src/seo-core/commerce.ts +138 -0
- package/src/seo-core/index.ts +605 -0
- package/src/seo-core/local.ts +333 -0
- package/src/sitemap-core/index.ts +296 -0
- package/src/social-core/index.ts +103 -0
- package/src/social.ts +7 -0
- package/src/solid-compat.tsx +347 -0
- package/src/solid-surfaces.tsx +1311 -0
- package/src/solid.tsx +82 -60
- package/src/store-core/index.ts +426 -0
- package/src/store.ts +12 -0
- package/src/svelte/SocialLinks.svelte +84 -0
- package/src/svelte/headless.ts +435 -0
- package/src/svelte/index.ts +9 -0
- package/src/vanilla.ts +367 -0
- package/src/verify-core/index.ts +288 -0
- package/src/verify.ts +8 -0
- package/src/vue/headless.ts +527 -0
- package/src/vue/index.ts +3 -0
package/src/data-model-schema.ts
CHANGED
|
@@ -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 `${
|
|
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
|
+
];
|