@businessdash/sdk 0.9.80 → 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.
- package/README.md +133 -949
- package/assets/{biab-sw.js → bd-sw.js} +2 -2
- package/dist/account-core/index.d.ts +1 -1
- package/dist/account-core/index.d.ts.map +1 -1
- package/dist/adapters-revalidate.d.ts +2 -2
- package/dist/adapters-revalidate.js +2 -2
- package/dist/adapters-revalidate.js.map +1 -1
- package/dist/analytics-core.d.ts +6 -6
- package/dist/analytics-core.d.ts.map +1 -1
- package/dist/analytics-core.js +4 -4
- package/dist/analytics-core.js.map +1 -1
- package/dist/analytics-server.d.ts +6 -6
- package/dist/analytics-server.d.ts.map +1 -1
- package/dist/analytics-server.js +5 -5
- package/dist/auth-handler.d.ts +14 -14
- package/dist/auth-handler.d.ts.map +1 -1
- package/dist/auth-handler.js +16 -16
- package/dist/auth-handler.js.map +1 -1
- package/dist/auth-links.d.ts +2 -2
- package/dist/auth-links.d.ts.map +1 -1
- package/dist/auth-links.js +2 -2
- package/dist/auth-links.js.map +1 -1
- package/dist/{biab-forms.css → bd-forms.css} +158 -158
- package/dist/cli.d.ts +4 -4
- package/dist/cli.js +78 -78
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +158 -147
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +156 -137
- package/dist/client.js.map +1 -1
- package/dist/consent-core/index.cjs +2 -2
- package/dist/consent-core/index.d.ts +2 -2
- package/dist/consent-core/index.d.ts.map +1 -1
- package/dist/consent-core/index.js +10 -8
- package/dist/consent-core/index.js.map +1 -1
- package/dist/contracts.d.ts +411 -52
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +89 -15
- package/dist/contracts.js.map +1 -1
- package/dist/data-model-schema.d.ts +15 -15
- package/dist/data-model-schema.d.ts.map +1 -1
- package/dist/data-model-schema.js +19 -17
- package/dist/data-model-schema.js.map +1 -1
- package/dist/distribution.d.ts +5 -5
- package/dist/distribution.d.ts.map +1 -1
- package/dist/distribution.js +4 -4
- package/dist/element.d.ts +36 -36
- package/dist/element.d.ts.map +1 -1
- package/dist/element.js +43 -43
- package/dist/element.js.map +1 -1
- package/dist/embed-protocol.d.ts +11 -11
- package/dist/embed-protocol.d.ts.map +1 -1
- package/dist/embed-protocol.js +1 -1
- package/dist/embed-protocol.js.map +1 -1
- package/dist/errors.d.ts +15 -15
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +18 -18
- package/dist/errors.js.map +1 -1
- package/dist/forms-core/autocomplete.d.ts +3 -3
- package/dist/forms-core/autocomplete.d.ts.map +1 -1
- package/dist/forms-core/autocomplete.js +2 -2
- package/dist/forms-core/controller.d.ts +10 -10
- package/dist/forms-core/controller.d.ts.map +1 -1
- package/dist/forms-core/controller.js +4 -4
- package/dist/forms-core/controller.js.map +1 -1
- package/dist/forms-core/elements.d.ts +4 -4
- package/dist/forms-core/elements.d.ts.map +1 -1
- package/dist/forms-core/elements.js +7 -7
- package/dist/forms-core/elements.js.map +1 -1
- package/dist/forms-core/formula.d.ts +1 -1
- package/dist/forms-core/formula.js +1 -1
- package/dist/forms-core/index.d.ts +6 -6
- package/dist/forms-core/index.d.ts.map +1 -1
- package/dist/forms-core/index.js +5 -5
- package/dist/forms-core/index.js.map +1 -1
- package/dist/forms-core/units.d.ts +1 -1
- package/dist/forms-core/units.js +1 -1
- package/dist/forms-core/us-states.d.ts +1 -1
- package/dist/forms-core/us-states.js +1 -1
- package/dist/forms-core/validation.d.ts +12 -3
- package/dist/forms-core/validation.d.ts.map +1 -1
- package/dist/forms-core/validation.js +152 -17
- package/dist/forms-core/validation.js.map +1 -1
- package/dist/forms.d.ts +2 -2
- package/dist/forms.d.ts.map +1 -1
- package/dist/forms.js +2 -2
- package/dist/forms.js.map +1 -1
- package/dist/framework-support.js +1 -1
- package/dist/framework-support.js.map +1 -1
- package/dist/gallery-types.d.ts +1 -1
- package/dist/graphql.d.ts +3 -3
- package/dist/graphql.d.ts.map +1 -1
- package/dist/graphql.js +3 -3
- package/dist/graphql.js.map +1 -1
- package/dist/index.cjs +351 -272
- package/dist/index.d.cts +5 -5
- package/dist/index.d.mts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/legal-core/index.cjs +8 -8
- package/dist/legal-core/index.d.ts +3 -3
- package/dist/legal-core/index.d.ts.map +1 -1
- package/dist/legal-core/index.js +11 -11
- package/dist/legal-core/index.js.map +1 -1
- package/dist/marketing-core/index.d.ts +51 -1
- package/dist/marketing-core/index.d.ts.map +1 -1
- package/dist/marketing-core/index.js +35 -0
- package/dist/marketing-core/index.js.map +1 -1
- package/dist/marketing-schema.d.ts +9 -9
- package/dist/marketing-schema.d.ts.map +1 -1
- package/dist/marketing-schema.js +1 -1
- package/dist/mcp.d.ts +4 -4
- package/dist/mcp.js +4 -4
- package/dist/native.d.ts +6 -6
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js +4 -4
- package/dist/native.js.map +1 -1
- package/dist/next-revalidate.d.ts +8 -8
- package/dist/next-revalidate.d.ts.map +1 -1
- package/dist/next-revalidate.js +7 -7
- package/dist/next-revalidate.js.map +1 -1
- package/dist/notifications-core/index.d.ts +1 -1
- package/dist/notifications-core/index.js +1 -1
- package/dist/parallel-pages.d.ts +4 -4
- package/dist/parallel-pages.d.ts.map +1 -1
- package/dist/parallel-pages.js +5 -5
- package/dist/parallel-pages.js.map +1 -1
- package/dist/portal-core/index.d.ts +1 -1
- package/dist/portal-core/index.js +1 -1
- package/dist/proxy.d.ts +18 -18
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +10 -10
- package/dist/proxy.js.map +1 -1
- package/dist/push-core/index.cjs +6 -2
- package/dist/push-core/index.d.ts +1 -1
- package/dist/push-core/index.d.ts.map +1 -1
- package/dist/push-core/index.js +6 -2
- package/dist/push-core/index.js.map +1 -1
- package/dist/react-analytics.d.ts +14 -14
- package/dist/react-analytics.d.ts.map +1 -1
- package/dist/react-analytics.js +15 -15
- package/dist/react-analytics.js.map +1 -1
- package/dist/react-attribution.d.ts +2 -2
- package/dist/react-attribution.d.ts.map +1 -1
- package/dist/react-attribution.js +1 -1
- package/dist/react-marketing.js +5 -5
- package/dist/react-marketing.js.map +1 -1
- package/dist/react.d.ts +38 -61
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +247 -261
- package/dist/react.js.map +1 -1
- package/dist/reserved-paths.d.ts +2 -2
- package/dist/reserved-paths.js +3 -3
- package/dist/reserved-paths.js.map +1 -1
- package/dist/revalidate-verify.d.ts +3 -3
- package/dist/revalidate-verify.d.ts.map +1 -1
- package/dist/revalidate-verify.js +1 -1
- package/dist/revalidate-verify.js.map +1 -1
- package/dist/sdk.d.ts +51 -45
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +48 -50
- package/dist/sdk.js.map +1 -1
- package/dist/seed-core/index.js +8 -8
- package/dist/seed-core/index.js.map +1 -1
- package/dist/seo-core/blog.d.ts +1 -1
- package/dist/seo-core/blog.js +1 -1
- package/dist/seo-core/blog.js.map +1 -1
- package/dist/seo-core/index.cjs +2 -2
- package/dist/seo-core/index.js +1 -1
- package/dist/seo-core/index.js.map +1 -1
- package/dist/seo.d.ts +1 -1
- package/dist/seo.d.ts.map +1 -1
- package/dist/seo.js +1 -1
- package/dist/seo.js.map +1 -1
- package/dist/sitemap-core/index.cjs +5 -5
- package/dist/sitemap-core/index.d.ts +13 -5
- package/dist/sitemap-core/index.d.ts.map +1 -1
- package/dist/sitemap-core/index.js +4 -4
- package/dist/sitemap-core/index.js.map +1 -1
- package/dist/socials.d.ts +6 -6
- package/dist/socials.d.ts.map +1 -1
- package/dist/socials.js +5 -5
- package/dist/socials.js.map +1 -1
- package/dist/solid-compat.d.ts +1 -1
- package/dist/solid-compat.js +4 -4
- package/dist/solid-compat.js.map +1 -1
- package/dist/store-core/index.d.ts +1 -1
- package/dist/vanilla.d.ts +12 -12
- package/dist/vanilla.d.ts.map +1 -1
- package/dist/vanilla.js +192 -145
- package/dist/vanilla.js.map +1 -1
- package/openapi.json +264 -1
- package/package.json +8 -8
- package/src/account-core/index.ts +1 -1
- package/src/adapters-revalidate.ts +3 -3
- package/src/analytics-core.ts +8 -8
- package/src/analytics-server.ts +6 -6
- package/src/angular/{biab-form.component.ts → bd-form.component.ts} +269 -161
- package/src/angular/headless.ts +12 -12
- package/src/angular/index.ts +9 -9
- package/src/auth-handler.ts +22 -22
- package/src/auth-links.ts +2 -2
- package/src/cli.ts +81 -81
- package/src/client.ts +218 -193
- package/src/consent-core/index.ts +10 -8
- package/src/contracts.ts +99 -15
- package/src/data-model-schema.ts +29 -26
- package/src/distribution.ts +5 -5
- package/src/element.ts +54 -54
- package/src/embed-protocol.ts +14 -14
- package/src/errors.ts +27 -27
- package/src/forms-core/autocomplete.ts +3 -3
- package/src/forms-core/controller.ts +12 -12
- package/src/forms-core/elements.ts +7 -7
- package/src/forms-core/formula.ts +1 -1
- package/src/forms-core/index.ts +8 -8
- package/src/forms-core/units.ts +1 -1
- package/src/forms-core/us-states.ts +1 -1
- package/src/forms-core/validation.ts +158 -14
- package/src/forms.ts +2 -2
- package/src/framework-support.ts +1 -1
- package/src/gallery-types.ts +1 -1
- package/src/graphql.ts +4 -4
- package/src/index.ts +38 -38
- package/src/legal-core/index.ts +12 -12
- package/src/marketing-core/index.ts +62 -0
- package/src/marketing-schema.ts +9 -9
- package/src/mcp.ts +4 -4
- package/src/native.ts +14 -14
- package/src/next-revalidate.ts +10 -10
- package/src/notifications-core/index.ts +1 -1
- package/src/parallel-pages.ts +6 -6
- package/src/portal-core/index.ts +1 -1
- package/src/proxy.ts +28 -28
- package/src/push-core/index.ts +11 -5
- package/src/qwik.tsx +262 -166
- package/src/react-analytics.tsx +17 -17
- package/src/react-attribution.tsx +2 -2
- package/src/react-marketing.tsx +5 -5
- package/src/react.tsx +541 -500
- package/src/reserved-paths.ts +3 -3
- package/src/revalidate-verify.ts +5 -5
- package/src/sdk.ts +131 -101
- package/src/seed-core/index.ts +8 -8
- package/src/seo-core/blog.ts +2 -2
- package/src/seo-core/index.ts +1 -1
- package/src/seo.ts +1 -1
- package/src/sitemap-core/index.ts +17 -9
- package/src/socials.ts +6 -6
- package/src/solid-compat.tsx +5 -5
- package/src/solid-surfaces.tsx +28 -28
- package/src/solid.tsx +264 -175
- package/src/store-core/index.ts +1 -1
- package/src/styles/{biab-forms.css → bd-forms.css} +158 -158
- package/src/svelte/{BiabForm.svelte → BdForm.svelte} +240 -173
- package/src/svelte/context.ts +16 -16
- package/src/svelte/headless.ts +10 -10
- package/src/svelte/index.ts +16 -16
- package/src/vanilla.ts +250 -169
- package/src/vue/{BiabForm.vue → BdForm.vue} +270 -157
- package/src/vue/headless.ts +11 -11
- package/src/vue/index.ts +26 -26
package/src/element.ts
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `@businessdash/sdk/element` — the `<
|
|
2
|
+
* `@businessdash/sdk/element` — the `<bd-form>` custom element binding.
|
|
3
3
|
*
|
|
4
|
-
* A drop-in web component that renders a
|
|
4
|
+
* A drop-in web component that renders a BD form anywhere a tag can go:
|
|
5
5
|
*
|
|
6
|
-
* <
|
|
6
|
+
* <bd-form slug="contact" submit-label="Send"></bd-form>
|
|
7
7
|
*
|
|
8
|
-
* It is a thin custom-element shell around the framework-free `
|
|
8
|
+
* It is a thin custom-element shell around the framework-free `mountBdForm`
|
|
9
9
|
* (`@businessdash/sdk/vanilla`): the element owns the lifecycle (connect / attribute
|
|
10
|
-
* changes / disconnect) and `
|
|
10
|
+
* changes / disconnect) and `mountBdForm` owns all rendering + the headless
|
|
11
11
|
* controller. It renders into LIGHT DOM (no shadow root) so the consumer's
|
|
12
|
-
* `
|
|
12
|
+
* `bd-*` CSS cascades straight in — identical to every other binding.
|
|
13
13
|
*
|
|
14
14
|
* ── Passing the SDK client ───────────────────────────────────────────────────
|
|
15
|
-
* A `
|
|
15
|
+
* A `BdClient` can't travel through an HTML attribute, so there are three ways
|
|
16
16
|
* to give the element one (checked in this order):
|
|
17
|
-
* 1. The `.client` JS property: el.client =
|
|
18
|
-
* 2. A DI default set once at startup:
|
|
19
|
-
* (the "Provider equivalent" — every <
|
|
17
|
+
* 1. The `.client` JS property: el.client = createBdClient(...)
|
|
18
|
+
* 2. A DI default set once at startup: setBdFormClient(createBdClient(...))
|
|
19
|
+
* (the "Provider equivalent" — every <bd-form> on the page uses it)
|
|
20
20
|
* 3. A pre-fetched schema (SSR), via the `.schema` property — no client needed
|
|
21
21
|
* to render; a client is still required to actually submit.
|
|
22
22
|
*
|
|
@@ -24,63 +24,63 @@
|
|
|
24
24
|
* slug — form slug to load via the client
|
|
25
25
|
* submit-label — label for the final submit button (default "Submit")
|
|
26
26
|
* dry-run — present ⇒ validate server-side but store nothing
|
|
27
|
-
* class — extra class(es) added to the inner `.
|
|
27
|
+
* class — extra class(es) added to the inner `.bd-form`
|
|
28
28
|
* auto-complete — global HTML autofill switch: "false" ⇒ off, "true" or
|
|
29
29
|
* absent ⇒ infer tokens per field
|
|
30
30
|
* field-auto-complete — JSON object of per-field overrides keyed by field id
|
|
31
31
|
* ({ "<id>": token | true | false })
|
|
32
32
|
*
|
|
33
33
|
* ── Properties (JS, richer types) ────────────────────────────────────────────
|
|
34
|
-
* .client :
|
|
34
|
+
* .client : BdClient — the SDK client
|
|
35
35
|
* .schema : FormSchema — pre-fetched schema (SSR / adopt)
|
|
36
36
|
* .submitOptions : FormSubmitOptions
|
|
37
37
|
* .autoComplete : boolean | undefined — mirrors `auto-complete`
|
|
38
38
|
* .fieldAutoComplete : Record<string, string | boolean> | undefined
|
|
39
39
|
*
|
|
40
40
|
* ── Events (bubbling, composed) ──────────────────────────────────────────────
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
41
|
+
* bd-form-success — detail: the ok FormSubmitResult
|
|
42
|
+
* bd-form-error — detail: the failed FormSubmitResult
|
|
43
|
+
* bd-form-submit — detail: { data } working values at submit time
|
|
44
44
|
*
|
|
45
45
|
* Compiled to dist (plain TS, no JSX). Importing this module registers the
|
|
46
46
|
* element once (idempotent).
|
|
47
47
|
*/
|
|
48
48
|
|
|
49
|
-
import type {
|
|
49
|
+
import type { BdClient, FormSchema, FormSubmitResult } from "./sdk.js";
|
|
50
50
|
import {
|
|
51
|
-
type
|
|
51
|
+
type BdFormInstance,
|
|
52
52
|
type FormSubmitOptions,
|
|
53
|
-
|
|
53
|
+
mountBdForm,
|
|
54
54
|
} from "./vanilla.js";
|
|
55
55
|
|
|
56
56
|
// Re-export the core + the vanilla mount so this subpath is a complete entry.
|
|
57
57
|
export * from "./forms-core/index.js";
|
|
58
58
|
export type {
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
BdFormInstance,
|
|
60
|
+
MountBdFormOptions,
|
|
61
61
|
} from "./vanilla.js";
|
|
62
|
-
export {
|
|
62
|
+
export { mountBdForm } from "./vanilla.js";
|
|
63
63
|
|
|
64
64
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
65
|
-
// Provider equivalent — a process-wide default client for every <
|
|
65
|
+
// Provider equivalent — a process-wide default client for every <bd-form>.
|
|
66
66
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
67
67
|
|
|
68
|
-
let defaultClient:
|
|
68
|
+
let defaultClient: BdClient | null = null;
|
|
69
69
|
|
|
70
70
|
/**
|
|
71
|
-
* Set (or clear) the default SDK client used by every `<
|
|
71
|
+
* Set (or clear) the default SDK client used by every `<bd-form>` that doesn't
|
|
72
72
|
* have its own `.client` property. The web-component analogue of a React
|
|
73
|
-
* `<
|
|
73
|
+
* `<BdFormProvider client={…}>`. Call once at startup:
|
|
74
74
|
*
|
|
75
|
-
* import {
|
|
76
|
-
*
|
|
75
|
+
* import { setBdFormClient } from "@businessdash/sdk/element";
|
|
76
|
+
* setBdFormClient(createBdClient({ apiKey, siteId, baseUrl }));
|
|
77
77
|
*/
|
|
78
|
-
export function
|
|
78
|
+
export function setBdFormClient(client: BdClient | null): void {
|
|
79
79
|
defaultClient = client;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
/** Read the current default client (mostly for tests / introspection). */
|
|
83
|
-
export function
|
|
83
|
+
export function getBdFormClient(): BdClient | null {
|
|
84
84
|
return defaultClient;
|
|
85
85
|
}
|
|
86
86
|
|
|
@@ -88,7 +88,7 @@ export function getBiabFormClient(): BiabClient | null {
|
|
|
88
88
|
// The custom element.
|
|
89
89
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
90
90
|
|
|
91
|
-
export class
|
|
91
|
+
export class BdFormElement extends HTMLElement {
|
|
92
92
|
static get observedAttributes(): string[] {
|
|
93
93
|
return [
|
|
94
94
|
"slug",
|
|
@@ -101,10 +101,10 @@ export class BiabFormElement extends HTMLElement {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
/** The mounted instance (null until connected with enough config). */
|
|
104
|
-
private instance:
|
|
104
|
+
private instance: BdFormInstance | null = null;
|
|
105
105
|
|
|
106
106
|
/** Property-only backing fields (can't ride on attributes). */
|
|
107
|
-
private _client:
|
|
107
|
+
private _client: BdClient | undefined;
|
|
108
108
|
private _schema: FormSchema | undefined;
|
|
109
109
|
private _submitOptions: FormSubmitOptions | undefined;
|
|
110
110
|
/** Per-field autofill overrides set via the JS property; the
|
|
@@ -113,10 +113,10 @@ export class BiabFormElement extends HTMLElement {
|
|
|
113
113
|
|
|
114
114
|
// ── Property accessors ─────────────────────────────────────────────────────
|
|
115
115
|
|
|
116
|
-
get client():
|
|
116
|
+
get client(): BdClient | undefined {
|
|
117
117
|
return this._client;
|
|
118
118
|
}
|
|
119
|
-
set client(value:
|
|
119
|
+
set client(value: BdClient | undefined) {
|
|
120
120
|
this._client = value;
|
|
121
121
|
this.remount();
|
|
122
122
|
}
|
|
@@ -204,7 +204,7 @@ export class BiabFormElement extends HTMLElement {
|
|
|
204
204
|
this.remount();
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
-
/** Imperatively submit the form (parity with `
|
|
207
|
+
/** Imperatively submit the form (parity with `mountBdForm`'s handle). */
|
|
208
208
|
submit(options?: FormSubmitOptions): Promise<FormSubmitResult> | undefined {
|
|
209
209
|
return this.instance?.submit(options);
|
|
210
210
|
}
|
|
@@ -231,9 +231,9 @@ export class BiabFormElement extends HTMLElement {
|
|
|
231
231
|
if (!this._schema && (!client || !slug)) {
|
|
232
232
|
this.replaceChildren();
|
|
233
233
|
const hint = document.createElement("div");
|
|
234
|
-
hint.className = "
|
|
234
|
+
hint.className = "bd-form bd-form__error";
|
|
235
235
|
hint.textContent =
|
|
236
|
-
"<
|
|
236
|
+
"<bd-form> needs a `slug` + a client (set `.client` or call setBdFormClient), or a pre-fetched `.schema`.";
|
|
237
237
|
this.append(hint);
|
|
238
238
|
return;
|
|
239
239
|
}
|
|
@@ -243,7 +243,7 @@ export class BiabFormElement extends HTMLElement {
|
|
|
243
243
|
const autoComplete = this.autoComplete;
|
|
244
244
|
const fieldAutoComplete = this.fieldAutoComplete;
|
|
245
245
|
|
|
246
|
-
this.instance =
|
|
246
|
+
this.instance = mountBdForm(this, {
|
|
247
247
|
...(client ? { client } : {}),
|
|
248
248
|
...(slug ? { slug } : {}),
|
|
249
249
|
...(this._schema ? { schema: this._schema } : {}),
|
|
@@ -253,9 +253,9 @@ export class BiabFormElement extends HTMLElement {
|
|
|
253
253
|
...(this._submitOptions ? { submitOptions: this._submitOptions } : {}),
|
|
254
254
|
...(autoComplete !== undefined ? { autoComplete } : {}),
|
|
255
255
|
...(fieldAutoComplete ? { fieldAutoComplete } : {}),
|
|
256
|
-
onSubmit: (data) => this.emit("
|
|
257
|
-
onSuccess: (result) => this.emit("
|
|
258
|
-
onError: (result) => this.emit("
|
|
256
|
+
onSubmit: (data) => this.emit("bd-form-submit", { data }),
|
|
257
|
+
onSuccess: (result) => this.emit("bd-form-success", result),
|
|
258
|
+
onError: (result) => this.emit("bd-form-error", result),
|
|
259
259
|
});
|
|
260
260
|
}
|
|
261
261
|
|
|
@@ -299,24 +299,24 @@ function parseFieldAutoComplete(
|
|
|
299
299
|
}
|
|
300
300
|
|
|
301
301
|
/**
|
|
302
|
-
* Register `<
|
|
302
|
+
* Register `<bd-form>` once. Idempotent and SSR-safe (no-op when
|
|
303
303
|
* `customElements` is unavailable, e.g. on the server). Called automatically on
|
|
304
304
|
* import; also exported so a consumer can register under a custom tag name.
|
|
305
305
|
*/
|
|
306
|
-
export function
|
|
306
|
+
export function defineBdForm(tagName = "bd-form"): void {
|
|
307
307
|
if (typeof customElements === "undefined") return;
|
|
308
308
|
if (customElements.get(tagName)) return;
|
|
309
|
-
customElements.define(tagName,
|
|
309
|
+
customElements.define(tagName, BdFormElement);
|
|
310
310
|
}
|
|
311
311
|
|
|
312
312
|
// Auto-register on import (the common case: `import "@businessdash/sdk/element"`).
|
|
313
|
-
|
|
313
|
+
defineBdForm();
|
|
314
314
|
|
|
315
|
-
// Ambient typing so `document.createElement("
|
|
315
|
+
// Ambient typing so `document.createElement("bd-form")` is typed in TS apps
|
|
316
316
|
// that pull this module in.
|
|
317
317
|
declare global {
|
|
318
318
|
interface HTMLElementTagNameMap {
|
|
319
|
-
"
|
|
319
|
+
"bd-form": BdFormElement;
|
|
320
320
|
}
|
|
321
321
|
}
|
|
322
322
|
|
|
@@ -337,7 +337,7 @@ export type {
|
|
|
337
337
|
} from "./marketing-core/index.js";
|
|
338
338
|
export type { PortalController, PortalSnapshot } from "./portal-core/index.js";
|
|
339
339
|
export type { StoreController, StoreSnapshot } from "./store-core/index.js";
|
|
340
|
-
// The native (non-iframe) storefront and chat controllers. `<
|
|
340
|
+
// The native (non-iframe) storefront and chat controllers. `<bd-form>` is a
|
|
341
341
|
// custom element because forms need DOM; a storefront controller does not, so
|
|
342
342
|
// it is re-exported as-is from the framework-free binding rather than wrapped
|
|
343
343
|
// in an element that would only get in the way.
|
|
@@ -371,18 +371,18 @@ export type { SocialLinkRow } from "./social-core/index.js";
|
|
|
371
371
|
export { mountSocialLinks, resolveSocialLinks } from "./vanilla.js";
|
|
372
372
|
|
|
373
373
|
/**
|
|
374
|
-
* `<
|
|
374
|
+
* `<bd-social-links>` — the social block as a custom element.
|
|
375
375
|
*
|
|
376
376
|
* Attributes: `color`, `size`, `link-class`, `icon-class`. The `socials` record
|
|
377
377
|
* is a PROPERTY rather than an attribute, because it is an object and an
|
|
378
378
|
* attribute would mean stringifying it:
|
|
379
379
|
*
|
|
380
380
|
* ```js
|
|
381
|
-
* const el = document.querySelector("
|
|
381
|
+
* const el = document.querySelector("bd-social-links");
|
|
382
382
|
* el.socials = company.socials;
|
|
383
383
|
* ```
|
|
384
384
|
*/
|
|
385
|
-
export class
|
|
385
|
+
export class BdSocialLinksElement extends HTMLElement {
|
|
386
386
|
#socials: unknown = null;
|
|
387
387
|
|
|
388
388
|
set socials(value: unknown) {
|
|
@@ -415,9 +415,9 @@ export class BiabSocialLinksElement extends HTMLElement {
|
|
|
415
415
|
}
|
|
416
416
|
}
|
|
417
417
|
|
|
418
|
-
/** Register `<
|
|
419
|
-
export function
|
|
418
|
+
/** Register `<bd-social-links>`. Safe to call more than once. */
|
|
419
|
+
export function defineBdSocialLinks(tagName = "bd-social-links"): void {
|
|
420
420
|
if (typeof customElements === "undefined") return;
|
|
421
421
|
if (customElements.get(tagName)) return;
|
|
422
|
-
customElements.define(tagName,
|
|
422
|
+
customElements.define(tagName, BdSocialLinksElement);
|
|
423
423
|
}
|
package/src/embed-protocol.ts
CHANGED
|
@@ -13,11 +13,11 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
/** Every event a BusinessDash embed posts to its host page. */
|
|
16
|
-
export type
|
|
17
|
-
| { type: "
|
|
18
|
-
| { type: "
|
|
16
|
+
export type BdEmbedEvent =
|
|
17
|
+
| { type: "bd:ready"; surface: string }
|
|
18
|
+
| { type: "bd:cart:update"; count: number; subtotalCents: number }
|
|
19
19
|
| {
|
|
20
|
-
type: "
|
|
20
|
+
type: "bd:cart:checkout-requested";
|
|
21
21
|
lines: Array<{
|
|
22
22
|
productId: string;
|
|
23
23
|
variantId: string;
|
|
@@ -26,15 +26,15 @@ export type BiabEmbedEvent =
|
|
|
26
26
|
}>;
|
|
27
27
|
}
|
|
28
28
|
| {
|
|
29
|
-
type: "
|
|
29
|
+
type: "bd:checkout:success";
|
|
30
30
|
sessionId: string;
|
|
31
31
|
orderId?: string | null;
|
|
32
32
|
}
|
|
33
|
-
| { type: "
|
|
34
|
-
| { type: "
|
|
35
|
-
| { type: "
|
|
36
|
-
| { type: "
|
|
37
|
-
| { type: "
|
|
33
|
+
| { type: "bd:checkout:cancel"; sessionId: string }
|
|
34
|
+
| { type: "bd:checkout:error"; message: string }
|
|
35
|
+
| { type: "bd:chatbot:user-message"; content: string }
|
|
36
|
+
| { type: "bd:chatbot:assistant-message"; content: string; model?: string }
|
|
37
|
+
| { type: "bd:chatbot:error"; message: string };
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
40
|
* The sandbox tokens every embed iframe gets. Checkout adds
|
|
@@ -55,20 +55,20 @@ export const DEFAULT_EMBED_SANDBOX =
|
|
|
55
55
|
*/
|
|
56
56
|
export function subscribeToEmbedMessages(
|
|
57
57
|
getIframe: () => HTMLIFrameElement | null | undefined,
|
|
58
|
-
handler: (event:
|
|
58
|
+
handler: (event: BdEmbedEvent) => void,
|
|
59
59
|
): () => void {
|
|
60
60
|
if (typeof window === "undefined") return () => {};
|
|
61
61
|
|
|
62
62
|
const onMessage = (e: MessageEvent) => {
|
|
63
63
|
if (!e.data || typeof e.data !== "object") return;
|
|
64
|
-
if ((e.data as { kind?: string }).kind !== "
|
|
64
|
+
if ((e.data as { kind?: string }).kind !== "bd") return;
|
|
65
65
|
const iframe = getIframe();
|
|
66
66
|
if (iframe && e.source !== null && e.source !== iframe.contentWindow) {
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
69
|
-
const { kind, ...rest } = e.data as { kind: string } &
|
|
69
|
+
const { kind, ...rest } = e.data as { kind: string } & BdEmbedEvent;
|
|
70
70
|
void kind;
|
|
71
|
-
handler(rest as
|
|
71
|
+
handler(rest as BdEmbedEvent);
|
|
72
72
|
};
|
|
73
73
|
|
|
74
74
|
window.addEventListener("message", onMessage);
|
package/src/errors.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export class
|
|
1
|
+
export class BdApiError extends Error {
|
|
2
2
|
readonly status: number;
|
|
3
3
|
readonly body: unknown;
|
|
4
4
|
readonly path: string;
|
|
@@ -10,7 +10,7 @@ export class BiabApiError extends Error {
|
|
|
10
10
|
body: unknown;
|
|
11
11
|
}) {
|
|
12
12
|
super(input.message);
|
|
13
|
-
this.name = "
|
|
13
|
+
this.name = "BdApiError";
|
|
14
14
|
this.status = input.status;
|
|
15
15
|
this.body = input.body;
|
|
16
16
|
this.path = input.path;
|
|
@@ -18,7 +18,7 @@ export class BiabApiError extends Error {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
* Discriminated body
|
|
21
|
+
* Discriminated body BD returns when the package API refuses to
|
|
22
22
|
* run a handler — three reasons:
|
|
23
23
|
*
|
|
24
24
|
* - `plan_required` — feature not in the org's plan (customer can
|
|
@@ -35,7 +35,7 @@ export class BiabApiError extends Error {
|
|
|
35
35
|
* cleanly without try/catch; WRITE endpoints return 402 so
|
|
36
36
|
* accidental mutations surface as exceptions.
|
|
37
37
|
*/
|
|
38
|
-
export type
|
|
38
|
+
export type BdPlanGateBody =
|
|
39
39
|
| {
|
|
40
40
|
available: false;
|
|
41
41
|
reason: "plan_required";
|
|
@@ -61,7 +61,7 @@ export type BiabPlanGateBody =
|
|
|
61
61
|
message: string;
|
|
62
62
|
};
|
|
63
63
|
|
|
64
|
-
export function
|
|
64
|
+
export function isBdPlanGateBody(value: unknown): value is BdPlanGateBody {
|
|
65
65
|
if (!value || typeof value !== "object") return false;
|
|
66
66
|
const v = value as Record<string, unknown>;
|
|
67
67
|
if (v["available"] !== false) return false;
|
|
@@ -83,7 +83,7 @@ export function isBiabPlanGateBody(value: unknown): value is BiabPlanGateBody {
|
|
|
83
83
|
* subclasses (or `instanceof`-narrow on this class) to branch on the
|
|
84
84
|
* specific reason.
|
|
85
85
|
*/
|
|
86
|
-
export class
|
|
86
|
+
export class BdAccessRejectedError extends Error {
|
|
87
87
|
readonly reason: "plan_required" | "payment_required" | "service_suspended";
|
|
88
88
|
readonly upgradeUrl: string;
|
|
89
89
|
readonly featureMessage: string;
|
|
@@ -91,12 +91,12 @@ export class BiabAccessRejectedError extends Error {
|
|
|
91
91
|
readonly status: number;
|
|
92
92
|
|
|
93
93
|
constructor(input: {
|
|
94
|
-
body:
|
|
94
|
+
body: BdPlanGateBody;
|
|
95
95
|
path: string;
|
|
96
96
|
status: number;
|
|
97
97
|
}) {
|
|
98
98
|
super(input.body.message);
|
|
99
|
-
this.name = "
|
|
99
|
+
this.name = "BdAccessRejectedError";
|
|
100
100
|
this.reason = input.body.reason;
|
|
101
101
|
this.upgradeUrl = input.body.upgradeUrl;
|
|
102
102
|
this.featureMessage = input.body.message;
|
|
@@ -110,18 +110,18 @@ export class BiabAccessRejectedError extends Error {
|
|
|
110
110
|
* needs. The org can resolve this by upgrading (or by adding the
|
|
111
111
|
* specific feature à la carte once that surface ships).
|
|
112
112
|
*/
|
|
113
|
-
export class
|
|
113
|
+
export class BdFeatureNotEntitledError extends BdAccessRejectedError {
|
|
114
114
|
readonly feature: string;
|
|
115
115
|
readonly requiredPlan: string;
|
|
116
116
|
readonly planDisplayName: string;
|
|
117
117
|
|
|
118
118
|
constructor(input: {
|
|
119
|
-
body: Extract<
|
|
119
|
+
body: Extract<BdPlanGateBody, { reason: "plan_required" }>;
|
|
120
120
|
path: string;
|
|
121
121
|
status: number;
|
|
122
122
|
}) {
|
|
123
123
|
super(input);
|
|
124
|
-
this.name = "
|
|
124
|
+
this.name = "BdFeatureNotEntitledError";
|
|
125
125
|
this.feature = input.body.requiredFeature;
|
|
126
126
|
this.requiredPlan = input.body.requiredPlan;
|
|
127
127
|
this.planDisplayName = input.body.planDisplayName;
|
|
@@ -134,17 +134,17 @@ export class BiabFeatureNotEntitledError extends BiabAccessRejectedError {
|
|
|
134
134
|
* gallery/blog reads) continue serving normally — interactive ones
|
|
135
135
|
* (forms, cart, scheduling bookings, chatbot writes) throw this.
|
|
136
136
|
*/
|
|
137
|
-
export class
|
|
137
|
+
export class BdPaymentLapsedError extends BdAccessRejectedError {
|
|
138
138
|
readonly daysLapsed: number;
|
|
139
139
|
readonly daysUntilSuspension: number;
|
|
140
140
|
|
|
141
141
|
constructor(input: {
|
|
142
|
-
body: Extract<
|
|
142
|
+
body: Extract<BdPlanGateBody, { reason: "payment_required" }>;
|
|
143
143
|
path: string;
|
|
144
144
|
status: number;
|
|
145
145
|
}) {
|
|
146
146
|
super(input);
|
|
147
|
-
this.name = "
|
|
147
|
+
this.name = "BdPaymentLapsedError";
|
|
148
148
|
this.daysLapsed = input.body.daysLapsed;
|
|
149
149
|
this.daysUntilSuspension = input.body.daysUntilSuspension;
|
|
150
150
|
}
|
|
@@ -158,16 +158,16 @@ export class BiabPaymentLapsedError extends BiabAccessRejectedError {
|
|
|
158
158
|
* as temporary. `robots.txt` and `sitemap.xml` separately switch to
|
|
159
159
|
* suspended-mode bodies (`Disallow: /` / empty) for the same reason.
|
|
160
160
|
*/
|
|
161
|
-
export class
|
|
161
|
+
export class BdServiceSuspendedError extends BdAccessRejectedError {
|
|
162
162
|
readonly daysLapsed: number;
|
|
163
163
|
|
|
164
164
|
constructor(input: {
|
|
165
|
-
body: Extract<
|
|
165
|
+
body: Extract<BdPlanGateBody, { reason: "service_suspended" }>;
|
|
166
166
|
path: string;
|
|
167
167
|
status: number;
|
|
168
168
|
}) {
|
|
169
169
|
super(input);
|
|
170
|
-
this.name = "
|
|
170
|
+
this.name = "BdServiceSuspendedError";
|
|
171
171
|
this.daysLapsed = input.body.daysLapsed;
|
|
172
172
|
}
|
|
173
173
|
}
|
|
@@ -176,25 +176,25 @@ export class BiabServiceSuspendedError extends BiabAccessRejectedError {
|
|
|
176
176
|
* Factory the transport uses to throw the right subclass.
|
|
177
177
|
*/
|
|
178
178
|
export function accessRejectionFromBody(input: {
|
|
179
|
-
body:
|
|
179
|
+
body: BdPlanGateBody;
|
|
180
180
|
path: string;
|
|
181
181
|
status: number;
|
|
182
|
-
}):
|
|
182
|
+
}): BdAccessRejectedError {
|
|
183
183
|
switch (input.body.reason) {
|
|
184
184
|
case "plan_required":
|
|
185
|
-
return new
|
|
185
|
+
return new BdFeatureNotEntitledError({
|
|
186
186
|
body: input.body,
|
|
187
187
|
path: input.path,
|
|
188
188
|
status: input.status,
|
|
189
189
|
});
|
|
190
190
|
case "payment_required":
|
|
191
|
-
return new
|
|
191
|
+
return new BdPaymentLapsedError({
|
|
192
192
|
body: input.body,
|
|
193
193
|
path: input.path,
|
|
194
194
|
status: input.status,
|
|
195
195
|
});
|
|
196
196
|
case "service_suspended":
|
|
197
|
-
return new
|
|
197
|
+
return new BdServiceSuspendedError({
|
|
198
198
|
body: input.body,
|
|
199
199
|
path: input.path,
|
|
200
200
|
status: input.status,
|
|
@@ -255,7 +255,7 @@ export async function unwrapAccess<T>(
|
|
|
255
255
|
const data = await fn();
|
|
256
256
|
return { data, rejected: null };
|
|
257
257
|
} catch (err) {
|
|
258
|
-
if (err instanceof
|
|
258
|
+
if (err instanceof BdFeatureNotEntitledError) {
|
|
259
259
|
return {
|
|
260
260
|
data: null,
|
|
261
261
|
rejected: {
|
|
@@ -268,7 +268,7 @@ export async function unwrapAccess<T>(
|
|
|
268
268
|
},
|
|
269
269
|
};
|
|
270
270
|
}
|
|
271
|
-
if (err instanceof
|
|
271
|
+
if (err instanceof BdPaymentLapsedError) {
|
|
272
272
|
return {
|
|
273
273
|
data: null,
|
|
274
274
|
rejected: {
|
|
@@ -280,7 +280,7 @@ export async function unwrapAccess<T>(
|
|
|
280
280
|
},
|
|
281
281
|
};
|
|
282
282
|
}
|
|
283
|
-
if (err instanceof
|
|
283
|
+
if (err instanceof BdServiceSuspendedError) {
|
|
284
284
|
return {
|
|
285
285
|
data: null,
|
|
286
286
|
rejected: {
|
|
@@ -297,7 +297,7 @@ export async function unwrapAccess<T>(
|
|
|
297
297
|
|
|
298
298
|
/**
|
|
299
299
|
* Back-compat alias for the plan-only escape hatch. Same shape as
|
|
300
|
-
* `unwrapAccess` but only catches `
|
|
300
|
+
* `unwrapAccess` but only catches `BdFeatureNotEntitledError` —
|
|
301
301
|
* other access rejections (payment lapse, suspension) still throw.
|
|
302
302
|
* Prefer `unwrapAccess` for new code.
|
|
303
303
|
*/
|
|
@@ -321,7 +321,7 @@ export async function unwrapEntitlement<T>(
|
|
|
321
321
|
const data = await fn();
|
|
322
322
|
return { data, notEntitled: null };
|
|
323
323
|
} catch (err) {
|
|
324
|
-
if (err instanceof
|
|
324
|
+
if (err instanceof BdFeatureNotEntitledError) {
|
|
325
325
|
return {
|
|
326
326
|
data: null,
|
|
327
327
|
notEntitled: {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* HTML autofill (`autocomplete`) resolution for `<
|
|
2
|
+
* HTML autofill (`autocomplete`) resolution for `<BdForm>` inputs.
|
|
3
3
|
*
|
|
4
4
|
* Browsers autofill an input when it carries a recognized `autocomplete` token
|
|
5
5
|
* (https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill).
|
|
6
6
|
* The SDK infers a sensible token per field (so a "Full name" text field gets
|
|
7
7
|
* `name`, an email field gets `email`, etc.), and lets the consumer:
|
|
8
8
|
*
|
|
9
|
-
* - turn it off globally (`<
|
|
9
|
+
* - turn it off globally (`<BdForm autoComplete={false}>` → every input
|
|
10
10
|
* gets `autocomplete="off"`), and
|
|
11
11
|
* - override per field (`fieldAutoComplete={{ [fieldId]: "off" | true | token }}`),
|
|
12
12
|
*
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
import type { FormCoreField } from "./validation.js";
|
|
18
18
|
|
|
19
|
-
/** Global + per-field autofill configuration, threaded from `<
|
|
19
|
+
/** Global + per-field autofill configuration, threaded from `<BdForm>`. */
|
|
20
20
|
export type AutocompleteConfig = {
|
|
21
21
|
/** Global default. `false` emits `autocomplete="off"` on every input.
|
|
22
22
|
* Defaults to `true` (infer tokens). */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* createFormController — the framework-agnostic observable store that drives
|
|
3
|
-
* every `<
|
|
3
|
+
* every `<BdForm>` binding (React / Vue / Svelte / Solid / Qwik / Angular /
|
|
4
4
|
* web-component / vanilla).
|
|
5
5
|
*
|
|
6
6
|
* It owns ALL of the form's runtime state and behaviour:
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* - file uploads via the SDK.
|
|
13
13
|
*
|
|
14
14
|
* Bindings stay dumb: subscribe to `snapshot()`, render by field `type` using
|
|
15
|
-
* the `
|
|
15
|
+
* the `bd-*` class convention (light DOM, no shadow root, so consumer CSS
|
|
16
16
|
* cascades), and call `setValue` / `next` / `back` / `submit` / `uploadFile` /
|
|
17
17
|
* `reset`. The store is a tiny subscribe/notify observable — no framework
|
|
18
18
|
* reactivity primitives leak in.
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* Data flows entirely through the SDK: it calls `client.forms.schema(slug)` to
|
|
21
21
|
* load and `client.forms.submit(slug, data, opts)` to submit, so auth, caching,
|
|
22
22
|
* revalidation, HMAC, retries, and CRM fan-out all stay invisible inside
|
|
23
|
-
*
|
|
23
|
+
* bd. SSR callers can hand a pre-fetched schema instead of a client.
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
import type {
|
|
@@ -114,8 +114,8 @@ export interface FormSubmitOptions {
|
|
|
114
114
|
/**
|
|
115
115
|
* The slice of the SDK client the form controller actually needs. Any object exposing a
|
|
116
116
|
* `forms` resource with `schema` / `submit` / `uploadFile` satisfies it — the
|
|
117
|
-
* full `
|
|
118
|
-
* forwards to `/api/
|
|
117
|
+
* full `BdClient` from `createBdClient()`, or a thin same-origin proxy that
|
|
118
|
+
* forwards to `/api/bd/forms/*` (the pattern every starter template uses so the
|
|
119
119
|
* bearer key never reaches the browser).
|
|
120
120
|
*
|
|
121
121
|
* It lives here rather than in `react.tsx` because `forms-core` is the layer
|
|
@@ -123,7 +123,7 @@ export interface FormSubmitOptions {
|
|
|
123
123
|
* run this controller, and none of them should reach through React for a type.
|
|
124
124
|
* `react.tsx` re-exports the name, so the public API is unchanged.
|
|
125
125
|
*/
|
|
126
|
-
export interface
|
|
126
|
+
export interface BdFormsClient {
|
|
127
127
|
forms: {
|
|
128
128
|
schema(slug: string): Promise<FormSchema>;
|
|
129
129
|
submit(
|
|
@@ -146,7 +146,7 @@ export interface BiabFormsClient {
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
/**
|
|
149
|
-
* `uploadFile` is optional on `
|
|
149
|
+
* `uploadFile` is optional on `BdFormsClient`, and legitimately so: a
|
|
150
150
|
* same-origin proxy that forwards only `schema` and `submit` is a valid client,
|
|
151
151
|
* and that is exactly what the starter templates ship so the bearer key never
|
|
152
152
|
* reaches the browser. A form with a file field needs more than that.
|
|
@@ -156,7 +156,7 @@ export interface BiabFormsClient {
|
|
|
156
156
|
* the old typing that was invisible, and a proxy client hit
|
|
157
157
|
* `client.forms.uploadFile is not a function` from inside a submit handler.
|
|
158
158
|
*/
|
|
159
|
-
function requireUploadFile(client:
|
|
159
|
+
function requireUploadFile(client: BdFormsClient) {
|
|
160
160
|
const upload = client.forms.uploadFile;
|
|
161
161
|
if (!upload) {
|
|
162
162
|
throw new Error(
|
|
@@ -171,14 +171,14 @@ export interface CreateFormControllerOptions {
|
|
|
171
171
|
* The SDK client. Required unless `schema` is supplied (SSR / pre-fetched).
|
|
172
172
|
* When both are given, `client` is still used for `submit` / `uploadFile`.
|
|
173
173
|
*
|
|
174
|
-
* Typed as `
|
|
175
|
-
* `
|
|
174
|
+
* Typed as `BdFormsClient` — the `forms` surface — rather than the whole
|
|
175
|
+
* `BdClient`, because that is all this controller ever touches. Demanding
|
|
176
176
|
* the full client was what forced `client as never` at the React call site:
|
|
177
177
|
* the hook resolves a forms-shaped client from a provider or a token, which
|
|
178
|
-
* is not a `
|
|
178
|
+
* is not a `BdClient` and never needed to be. A full `BdClient` still
|
|
179
179
|
* satisfies this structurally, so existing callers are unaffected.
|
|
180
180
|
*/
|
|
181
|
-
client?:
|
|
181
|
+
client?: BdFormsClient;
|
|
182
182
|
/** Form slug. Required when loading via `client`; optional with a pre-fetched
|
|
183
183
|
* `schema` that already carries its own `slug`. */
|
|
184
184
|
slug?: string;
|