@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
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
import type {
|
|
23
23
|
GetSiteMarketingPageResponse,
|
|
24
24
|
ListSiteMarketingPagesResponse,
|
|
25
|
+
SiteMarketingPage,
|
|
25
26
|
} from "../contracts.js";
|
|
26
27
|
|
|
27
28
|
export type MarketingCoreClient = {
|
|
@@ -68,6 +69,67 @@ export type CreateMarketingControllerOptions = {
|
|
|
68
69
|
onError?: (error: Error) => void;
|
|
69
70
|
};
|
|
70
71
|
|
|
72
|
+
/**
|
|
73
|
+
* The snapshot, reduced to what a view actually renders.
|
|
74
|
+
*
|
|
75
|
+
* Every binding needs the same four-way answer — nothing yet, working on it,
|
|
76
|
+
* here it is, that failed — and the same precedence between them. Deriving
|
|
77
|
+
* that in each binding is how they drift, so it is derived once here and the
|
|
78
|
+
* bindings just render the result.
|
|
79
|
+
*/
|
|
80
|
+
export type MarketingPageView =
|
|
81
|
+
| { status: "idle"; page: null }
|
|
82
|
+
| { status: "loading"; page: null }
|
|
83
|
+
| { status: "ready"; page: SiteMarketingPage | null }
|
|
84
|
+
| { status: "error"; page: null; error: Error };
|
|
85
|
+
|
|
86
|
+
export type MarketingListView =
|
|
87
|
+
| { status: "idle"; pages: null }
|
|
88
|
+
| { status: "loading"; pages: null }
|
|
89
|
+
| { status: "ready"; pages: ListSiteMarketingPagesResponse["pages"] }
|
|
90
|
+
| { status: "error"; pages: null; error: Error };
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* What to render for one page key.
|
|
94
|
+
*
|
|
95
|
+
* `cachedPage` is the caller's synchronous cache read. The controller cannot
|
|
96
|
+
* do it — the cache lives in the client, one layer down — but without it a
|
|
97
|
+
* page that is already cached flashes "loading" while the controller catches
|
|
98
|
+
* up, which is the exact cost the cache exists to avoid.
|
|
99
|
+
*
|
|
100
|
+
* A page WINS over an error: a stale page beside a failed refresh is more
|
|
101
|
+
* use to a visitor than an error where the content was.
|
|
102
|
+
*/
|
|
103
|
+
export function marketingPageView(
|
|
104
|
+
snapshot: MarketingSnapshot,
|
|
105
|
+
pageKey: string,
|
|
106
|
+
cachedPage: SiteMarketingPage | null = null,
|
|
107
|
+
): MarketingPageView {
|
|
108
|
+
const fromController =
|
|
109
|
+
snapshot.pageKey === pageKey && snapshot.page ? snapshot.page.page : null;
|
|
110
|
+
const page = fromController ?? cachedPage;
|
|
111
|
+
if (page) return { status: "ready", page };
|
|
112
|
+
if (snapshot.error) {
|
|
113
|
+
return { status: "error", page: null, error: snapshot.error };
|
|
114
|
+
}
|
|
115
|
+
if (snapshot.pending.page) return { status: "loading", page: null };
|
|
116
|
+
return { status: "idle", page: null };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** What to render for the page index. */
|
|
120
|
+
export function marketingListView(
|
|
121
|
+
snapshot: MarketingSnapshot,
|
|
122
|
+
): MarketingListView {
|
|
123
|
+
if (snapshot.error) {
|
|
124
|
+
return { status: "error", pages: null, error: snapshot.error };
|
|
125
|
+
}
|
|
126
|
+
if (snapshot.pending.list) return { status: "loading", pages: null };
|
|
127
|
+
if (snapshot.status === "ready") {
|
|
128
|
+
return { status: "ready", pages: snapshot.pages };
|
|
129
|
+
}
|
|
130
|
+
return { status: "idle", pages: null };
|
|
131
|
+
}
|
|
132
|
+
|
|
71
133
|
function toError(cause: unknown, fallback: string): Error {
|
|
72
134
|
return cause instanceof Error ? cause : new Error(fallback);
|
|
73
135
|
}
|
package/src/marketing-schema.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* The consumer's codebase is the source of truth for the content model.
|
|
5
5
|
* `defineSiteMarketingSchema()` lets them declare each section as a typed
|
|
6
6
|
* zod schema + UI metadata, and produces an artifact the SDK CLI uploads
|
|
7
|
-
* to
|
|
7
|
+
* to BD:
|
|
8
8
|
*
|
|
9
9
|
* const marketing = defineSiteMarketingSchema({
|
|
10
10
|
* brandTokens: ["company.name", "company.phone", "company.email"],
|
|
@@ -130,7 +130,7 @@ export type SiteMarketingSectionDef<S extends ZodTypeAny = ZodTypeAny> = {
|
|
|
130
130
|
ui?: Record<string, SiteMarketingFieldUI>;
|
|
131
131
|
/** When set, the dashboard renders a "Configure data source →" tile
|
|
132
132
|
* instead of editing the row as a regular form. Items come from the
|
|
133
|
-
* named
|
|
133
|
+
* named BD module at render time. */
|
|
134
134
|
dataSource?: SiteMarketingDataSourceMarker;
|
|
135
135
|
};
|
|
136
136
|
|
|
@@ -148,9 +148,9 @@ export function section<S extends ZodTypeAny>(
|
|
|
148
148
|
|
|
149
149
|
/**
|
|
150
150
|
* Optional `contentSync` configuration consumed by the
|
|
151
|
-
* `
|
|
151
|
+
* `bd sync-content` CLI command. Lets the consumer declare:
|
|
152
152
|
* - Where local JSON content lives on disk
|
|
153
|
-
* - Which directories map to which
|
|
153
|
+
* - Which directories map to which BD pageKeys (explicit) or to
|
|
154
154
|
* follow a glob convention (auto-derived)
|
|
155
155
|
* - Which filename → sectionKey aliases are needed (e.g.
|
|
156
156
|
* `marquee.json` actually means `trustMarquee`)
|
|
@@ -164,12 +164,12 @@ export function section<S extends ZodTypeAny>(
|
|
|
164
164
|
* supply an explicit `pages` array.
|
|
165
165
|
*/
|
|
166
166
|
export type SiteMarketingContentSyncConfig = {
|
|
167
|
-
/** Directory (relative to `
|
|
167
|
+
/** Directory (relative to `bd.config.*`) where JSON content trees live. */
|
|
168
168
|
rootDir: string;
|
|
169
169
|
/**
|
|
170
170
|
* Explicit page directories. Each entry maps a filesystem path
|
|
171
171
|
* (relative to `rootDir`, with optional `{locale}` placeholder) to
|
|
172
|
-
* a `pageKey` in
|
|
172
|
+
* a `pageKey` in BD. When omitted, the CLI auto-discovers using
|
|
173
173
|
* `<rootDir>/<locale>/*` and uses the leaf dir name as the pageKey.
|
|
174
174
|
*
|
|
175
175
|
* Example for a `<locale>/pages/<name>/` + `<locale>/shared/` layout:
|
|
@@ -218,7 +218,7 @@ export type SiteMarketingSchemaInput<
|
|
|
218
218
|
brandTokens?: readonly string[];
|
|
219
219
|
/** Free-form metadata shipped alongside the schema (your build SHA, source repo URL, etc.). */
|
|
220
220
|
metadata?: Record<string, string | number | boolean>;
|
|
221
|
-
/** Optional config for `
|
|
221
|
+
/** Optional config for `bd sync-content`. */
|
|
222
222
|
contentSync?: SiteMarketingContentSyncConfig;
|
|
223
223
|
};
|
|
224
224
|
|
|
@@ -306,9 +306,9 @@ export type SiteMarketingClientShape<
|
|
|
306
306
|
> = {
|
|
307
307
|
/** Reusable section schemas keyed by section key — handy for runtime parsing. */
|
|
308
308
|
readonly sections: Sections;
|
|
309
|
-
/** Optional file-tree →
|
|
309
|
+
/** Optional file-tree → BD mapping for the `sync-content` CLI. */
|
|
310
310
|
readonly contentSync: SiteMarketingContentSyncConfig | undefined;
|
|
311
|
-
/** JSON-Schema artifact ready to upload to
|
|
311
|
+
/** JSON-Schema artifact ready to upload to BD. */
|
|
312
312
|
toJSONSchema(): SiteMarketingSchemaArtifact;
|
|
313
313
|
/** SHA-256 hex digest of the canonicalized JSON-Schema artifact. */
|
|
314
314
|
checksum(): Promise<string>;
|
package/src/mcp.ts
CHANGED
|
@@ -11,15 +11,15 @@
|
|
|
11
11
|
* // app/api/mcp/route.ts
|
|
12
12
|
* import { mcpHandler } from '@businessdash/sdk/mcp'
|
|
13
13
|
* export const { POST, GET } = mcpHandler({
|
|
14
|
-
* siteId: process.env.
|
|
15
|
-
* baseUrl: process.env.
|
|
14
|
+
* siteId: process.env.BD_SITE_ID!,
|
|
15
|
+
* baseUrl: process.env.NEXT_PUBLIC_BD_APP_URL!, // https://www.biab.app
|
|
16
16
|
* })
|
|
17
17
|
*
|
|
18
18
|
* // app/.well-known/mcp.json/route.ts
|
|
19
19
|
* import { mcpManifestHandler } from '@businessdash/sdk/mcp'
|
|
20
20
|
* export const GET = mcpManifestHandler({
|
|
21
|
-
* siteId: process.env.
|
|
22
|
-
* baseUrl: process.env.
|
|
21
|
+
* siteId: process.env.BD_SITE_ID!,
|
|
22
|
+
* baseUrl: process.env.NEXT_PUBLIC_BD_APP_URL!,
|
|
23
23
|
* })
|
|
24
24
|
* ```
|
|
25
25
|
*
|
package/src/native.ts
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* - **Auth** — drive the hosted flow directly: `POST auth/start`, open the URL
|
|
25
25
|
* in a web-auth session, then `POST auth/exchange` with the `code` and
|
|
26
26
|
* `state` from your deep-link callback. `client.auth` has all three.
|
|
27
|
-
* - **Forms** — `<
|
|
27
|
+
* - **Forms** — `<bd-form>` is a DOM custom element with no native
|
|
28
28
|
* counterpart. Read the schema and render it with your own components.
|
|
29
29
|
* - **Revalidation** — irrelevant. The webhook targets a server that holds a
|
|
30
30
|
* cache; an app just re-fetches.
|
|
@@ -38,26 +38,26 @@
|
|
|
38
38
|
* dependency.
|
|
39
39
|
*/
|
|
40
40
|
|
|
41
|
-
export type {
|
|
41
|
+
export type { BdApiClientOptions, FetchLike } from "./client.js";
|
|
42
42
|
export {
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
BdApiClient,
|
|
44
|
+
createBdApiClient,
|
|
45
45
|
} from "./client.js";
|
|
46
46
|
export {
|
|
47
47
|
accessRejectionFromBody,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
type
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
BdAccessRejectedError,
|
|
49
|
+
BdApiError,
|
|
50
|
+
BdFeatureNotEntitledError,
|
|
51
|
+
BdPaymentLapsedError,
|
|
52
|
+
type BdPlanGateBody,
|
|
53
|
+
BdServiceSuspendedError,
|
|
54
|
+
isBdPlanGateBody,
|
|
55
55
|
type UnwrappedAccess,
|
|
56
56
|
type UnwrappedEntitlement,
|
|
57
57
|
} from "./errors.js";
|
|
58
58
|
export type {
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
BdClient,
|
|
60
|
+
CreateBdClientOptions,
|
|
61
61
|
FormFieldDef,
|
|
62
62
|
FormRenderSettings,
|
|
63
63
|
FormSchema,
|
|
@@ -70,4 +70,4 @@ export type {
|
|
|
70
70
|
SchedulingResource,
|
|
71
71
|
SchedulingSlot,
|
|
72
72
|
} from "./sdk.js";
|
|
73
|
-
export {
|
|
73
|
+
export { createBdClient } from "./sdk.js";
|
package/src/next-revalidate.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Drop-in Next.js route handler for
|
|
2
|
+
* Drop-in Next.js route handler for BD revalidation webhooks.
|
|
3
3
|
*
|
|
4
4
|
* Consumer mounts this with literally one line:
|
|
5
5
|
*
|
|
6
|
-
* // app/api/
|
|
6
|
+
* // app/api/bd/revalidate/route.ts
|
|
7
7
|
* export { POST } from "@businessdash/sdk/next/revalidate";
|
|
8
8
|
*
|
|
9
9
|
* That's it. The handler:
|
|
10
10
|
*
|
|
11
|
-
* 1. Reads the shared secret from `
|
|
11
|
+
* 1. Reads the shared secret from `BD_REVALIDATION_SECRET`
|
|
12
12
|
* (override via `createRevalidateHandler({ secret })` if env
|
|
13
13
|
* isn't available — see below).
|
|
14
|
-
* 2. Verifies the `X-
|
|
14
|
+
* 2. Verifies the `X-Bd-Signature: t=<unix>,v1=<hex>` header.
|
|
15
15
|
* Constant-time hash compare, ±5 minute replay window.
|
|
16
16
|
* 3. Calls `revalidateTag(tag, { expire: 0 })` for each tag in
|
|
17
17
|
* the payload.
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
28
|
import {
|
|
29
|
-
type
|
|
29
|
+
type BdPublishPayload,
|
|
30
30
|
type VerifyOptions,
|
|
31
31
|
type VerifyResult,
|
|
32
32
|
verifyAndExtractTags,
|
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
// Re-export for backwards compatibility — callers that previously
|
|
36
36
|
// imported these from `@businessdash/sdk/next/revalidate` still work.
|
|
37
37
|
export {
|
|
38
|
-
type
|
|
38
|
+
type BdPublishPayload,
|
|
39
39
|
type VerifyOptions,
|
|
40
40
|
type VerifyResult,
|
|
41
41
|
verifyAndExtractTags,
|
|
@@ -48,7 +48,7 @@ export {
|
|
|
48
48
|
export interface CreateRevalidateHandlerOptions {
|
|
49
49
|
/**
|
|
50
50
|
* Override the secret instead of reading from
|
|
51
|
-
* `
|
|
51
|
+
* `BD_REVALIDATION_SECRET`. Useful in tests or when the
|
|
52
52
|
* consumer manages secrets in a non-standard place.
|
|
53
53
|
*/
|
|
54
54
|
secret?: string;
|
|
@@ -88,7 +88,7 @@ export function createRevalidateHandler(
|
|
|
88
88
|
opts: CreateRevalidateHandlerOptions = {},
|
|
89
89
|
) {
|
|
90
90
|
return async function POST(request: Request): Promise<Response> {
|
|
91
|
-
const secret = opts.secret ?? process.env["
|
|
91
|
+
const secret = opts.secret ?? process.env["BD_REVALIDATION_SECRET"];
|
|
92
92
|
if (!secret) {
|
|
93
93
|
return Response.json(
|
|
94
94
|
{ ok: false, reason: "missing_revalidation_secret_env" },
|
|
@@ -96,7 +96,7 @@ export function createRevalidateHandler(
|
|
|
96
96
|
);
|
|
97
97
|
}
|
|
98
98
|
const rawBody = await request.text();
|
|
99
|
-
const sig = request.headers.get("x-
|
|
99
|
+
const sig = request.headers.get("x-bd-signature");
|
|
100
100
|
const verified = verifyAndExtractTags({
|
|
101
101
|
secret,
|
|
102
102
|
rawBody,
|
|
@@ -119,6 +119,6 @@ export function createRevalidateHandler(
|
|
|
119
119
|
|
|
120
120
|
/**
|
|
121
121
|
* Default `POST` handler the consumer re-exports. Reads the secret
|
|
122
|
-
* from `
|
|
122
|
+
* from `BD_REVALIDATION_SECRET` env automatically.
|
|
123
123
|
*/
|
|
124
124
|
export const POST = createRevalidateHandler();
|
|
@@ -353,7 +353,7 @@ export function createNotificationFeed(
|
|
|
353
353
|
/**
|
|
354
354
|
* Push notifications relayed by the service worker, for tabs that are open.
|
|
355
355
|
*
|
|
356
|
-
* The worker shipped at `@businessdash/sdk/
|
|
356
|
+
* The worker shipped at `@businessdash/sdk/bd-sw.js` posts every push to its
|
|
357
357
|
* clients. A worker written by hand has to do the same — post
|
|
358
358
|
* `{ type: "businessdash:push", payload }` — or this source hears nothing.
|
|
359
359
|
*/
|
package/src/parallel-pages.ts
CHANGED
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
* });
|
|
29
29
|
*
|
|
30
30
|
* `defineParallelPage` is a pure builder — no DB writes, no HTTP. It
|
|
31
|
-
* returns a frozen, type-checked artifact. Push to the
|
|
32
|
-
* later via `
|
|
31
|
+
* returns a frozen, type-checked artifact. Push to the BD server
|
|
32
|
+
* later via `bd sync-parallel-pages` (or the SDK's
|
|
33
33
|
* `client.parallelPages.upsertDefinition()` when wired).
|
|
34
34
|
*/
|
|
35
35
|
|
|
@@ -78,7 +78,7 @@ export type ParallelPageInput<
|
|
|
78
78
|
export type ParallelPageDefinition<
|
|
79
79
|
V extends Record<string, ParallelPageVariableInput>,
|
|
80
80
|
> = {
|
|
81
|
-
readonly $kind: "
|
|
81
|
+
readonly $kind: "bd.parallelPage";
|
|
82
82
|
readonly key: string;
|
|
83
83
|
readonly routePattern: string;
|
|
84
84
|
readonly variables: ReadonlyArray<{
|
|
@@ -166,7 +166,7 @@ export function defineParallelPage<
|
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
return Object.freeze({
|
|
169
|
-
$kind: "
|
|
169
|
+
$kind: "bd.parallelPage",
|
|
170
170
|
key: input.key,
|
|
171
171
|
routePattern: input.routePattern,
|
|
172
172
|
variables: Object.freeze(variables),
|
|
@@ -179,7 +179,7 @@ export function defineParallelPage<
|
|
|
179
179
|
/**
|
|
180
180
|
* Type guard for the artifact `defineParallelPage` returns. Useful
|
|
181
181
|
* when consumers export a mixed array of marketing + parallel-page
|
|
182
|
-
* declarations from one `
|
|
182
|
+
* declarations from one `bd.config.ts`.
|
|
183
183
|
*/
|
|
184
184
|
export function isParallelPageDefinition(
|
|
185
185
|
value: unknown,
|
|
@@ -187,6 +187,6 @@ export function isParallelPageDefinition(
|
|
|
187
187
|
return (
|
|
188
188
|
!!value &&
|
|
189
189
|
typeof value === "object" &&
|
|
190
|
-
(value as { $kind?: unknown }).$kind === "
|
|
190
|
+
(value as { $kind?: unknown }).$kind === "bd.parallelPage"
|
|
191
191
|
);
|
|
192
192
|
}
|
package/src/portal-core/index.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* not put their own customer portal on their own domain in their own design.
|
|
9
9
|
*
|
|
10
10
|
* This is the native path. Four things about the surface shape the design, and
|
|
11
|
-
* all of them come from the audit in `Resources/
|
|
11
|
+
* all of them come from the audit in `Resources/BD-Customer-Portal-SDK-Audit.md`.
|
|
12
12
|
*
|
|
13
13
|
* ## 1. The session is not optional
|
|
14
14
|
*
|
package/src/proxy.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
type
|
|
4
|
-
|
|
2
|
+
BdApiClient,
|
|
3
|
+
type BdApiClientOptions,
|
|
4
|
+
BdCustomerPortalClient,
|
|
5
5
|
} from "./client.js";
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -14,24 +14,24 @@ import {
|
|
|
14
14
|
*
|
|
15
15
|
* Pattern (Next.js example) — your tenant ships:
|
|
16
16
|
* - this client in browser bundles, configured with `proxyBaseUrl`
|
|
17
|
-
* (e.g. `/api/
|
|
17
|
+
* (e.g. `/api/bd/customer-portal`).
|
|
18
18
|
* - a route at that path that calls {@link createCustomerPortalProxyHandler}
|
|
19
|
-
* with your real
|
|
19
|
+
* with your real BD API key + the BD org id this site is pinned to.
|
|
20
20
|
*
|
|
21
21
|
* The browser client only knows the proxy URL. The bearer key never leaves
|
|
22
22
|
* the tenant server.
|
|
23
23
|
*/
|
|
24
24
|
export type BrowserCustomerPortalClientOptions = {
|
|
25
|
-
/** Same-origin proxy path or absolute URL (e.g. "/api/
|
|
25
|
+
/** Same-origin proxy path or absolute URL (e.g. "/api/bd/customer-portal"). */
|
|
26
26
|
proxyBaseUrl: string;
|
|
27
27
|
fetch?: typeof fetch;
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
class
|
|
30
|
+
class BrowserBdApiClient extends BdApiClient {
|
|
31
31
|
constructor(options: BrowserCustomerPortalClientOptions) {
|
|
32
32
|
// Pass a placeholder API key — the proxy ignores the Authorization
|
|
33
33
|
// header from the browser and substitutes its own.
|
|
34
|
-
const init:
|
|
34
|
+
const init: BdApiClientOptions = {
|
|
35
35
|
baseUrl: options.proxyBaseUrl,
|
|
36
36
|
apiKey: "browser-proxy",
|
|
37
37
|
};
|
|
@@ -44,41 +44,41 @@ class BrowserBiabDevClient extends BiabDevClient {
|
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
46
|
* Browser-only client that talks to your tenant's same-origin proxy route.
|
|
47
|
-
* The proxy injects the
|
|
47
|
+
* The proxy injects the BD API key and the `X-BD-Customer-Portal-Org`
|
|
48
48
|
* pin, so the browser never sees either secret.
|
|
49
49
|
*/
|
|
50
50
|
export function createBrowserCustomerPortalClient(
|
|
51
51
|
options: BrowserCustomerPortalClientOptions,
|
|
52
52
|
) {
|
|
53
|
-
const inner = new
|
|
54
|
-
return new
|
|
53
|
+
const inner = new BrowserBdApiClient(options);
|
|
54
|
+
return new BdCustomerPortalClient(inner, null);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
58
|
* Helper for the *server-side* proxy route a tenant ships. Returns a fetch
|
|
59
59
|
* handler that:
|
|
60
|
-
* - rewrites incoming request paths to the
|
|
61
|
-
* - injects the
|
|
60
|
+
* - rewrites incoming request paths to the BD host's customer-portal API
|
|
61
|
+
* - injects the BD API key and `X-BD-Customer-Portal-Org` header
|
|
62
62
|
* - forwards the response unchanged.
|
|
63
63
|
*
|
|
64
|
-
* @example // app/api/
|
|
64
|
+
* @example // app/api/bd/customer-portal/[...path]/route.ts
|
|
65
65
|
* export const GET = createCustomerPortalProxyHandler({
|
|
66
|
-
*
|
|
67
|
-
* apiKey: process.env.
|
|
68
|
-
* organizationId: process.env.
|
|
66
|
+
* bdBaseUrl: "https://biab.app/api/package/v1",
|
|
67
|
+
* apiKey: process.env.BD_API_KEY!,
|
|
68
|
+
* organizationId: process.env.BD_ORG_ID!,
|
|
69
69
|
* });
|
|
70
70
|
* export const POST = GET;
|
|
71
71
|
*/
|
|
72
72
|
export type CustomerPortalProxyOptions = {
|
|
73
|
-
|
|
73
|
+
bdBaseUrl: string;
|
|
74
74
|
apiKey: string;
|
|
75
|
-
/** The
|
|
76
|
-
* pinned to. Sent as the `X-
|
|
75
|
+
/** The BD organization id (`org.id` from the portal context) this site is
|
|
76
|
+
* pinned to. Sent as the `X-BD-Customer-Portal-Org` header. */
|
|
77
77
|
organizationId?: string;
|
|
78
78
|
/**
|
|
79
|
-
* @deprecated Use {@link organizationId} (the
|
|
80
|
-
* the platform resolves the pin header by
|
|
81
|
-
* but new integrations should pass the
|
|
79
|
+
* @deprecated Use {@link organizationId} (the BD org id). Still accepted —
|
|
80
|
+
* the platform resolves the pin header by BD id or the legacy provider id —
|
|
81
|
+
* but new integrations should pass the BD org id and drop any
|
|
82
82
|
* provider-specific env var.
|
|
83
83
|
*/
|
|
84
84
|
workosOrganizationId?: string;
|
|
@@ -112,11 +112,11 @@ export function createCustomerPortalProxyHandler(
|
|
|
112
112
|
options: CustomerPortalProxyOptions,
|
|
113
113
|
) {
|
|
114
114
|
const fetchImpl = options.fetch ?? fetch;
|
|
115
|
-
const base = options.
|
|
116
|
-
? options.
|
|
117
|
-
: `${options.
|
|
115
|
+
const base = options.bdBaseUrl.endsWith("/")
|
|
116
|
+
? options.bdBaseUrl
|
|
117
|
+
: `${options.bdBaseUrl}/`;
|
|
118
118
|
const siteOrigin = normalizeSiteOriginForProxy(options.siteOrigin);
|
|
119
|
-
// Prefer the
|
|
119
|
+
// Prefer the BD org id; fall back to the deprecated provider-id alias so
|
|
120
120
|
// existing integrations keep working until they migrate.
|
|
121
121
|
const orgPin = options.organizationId ?? options.workosOrganizationId;
|
|
122
122
|
if (!orgPin) {
|
|
@@ -137,7 +137,7 @@ export function createCustomerPortalProxyHandler(
|
|
|
137
137
|
|
|
138
138
|
const upstreamHeaders = new Headers();
|
|
139
139
|
upstreamHeaders.set("Authorization", `Bearer ${options.apiKey}`);
|
|
140
|
-
upstreamHeaders.set("X-
|
|
140
|
+
upstreamHeaders.set("X-BD-Customer-Portal-Org", orgPin);
|
|
141
141
|
upstreamHeaders.set("Accept", "application/json");
|
|
142
142
|
if (siteOrigin) {
|
|
143
143
|
upstreamHeaders.set("Origin", siteOrigin);
|
package/src/push-core/index.ts
CHANGED
|
@@ -159,9 +159,11 @@ export function pushPermission(): NotificationPermission | "unsupported" {
|
|
|
159
159
|
* Backed by an explicit `ArrayBuffer` rather than `new Uint8Array(length)`:
|
|
160
160
|
* TypeScript's DOM types want a `BufferSource`, and a `Uint8Array` over the
|
|
161
161
|
* generic `ArrayBufferLike` (which could be a `SharedArrayBuffer`) does not
|
|
162
|
-
* satisfy it.
|
|
162
|
+
* satisfy it. The return type stays UNPARAMETERISED because this shipped
|
|
163
|
+
* source is compiled by consumers' own TypeScript, and `Uint8Array<T>`
|
|
164
|
+
* only parses on 5.7+ — the one `BufferSource` call site casts instead.
|
|
163
165
|
*/
|
|
164
|
-
function urlBase64ToUint8Array(base64: string): Uint8Array
|
|
166
|
+
function urlBase64ToUint8Array(base64: string): Uint8Array {
|
|
165
167
|
const padding = "=".repeat((4 - (base64.length % 4)) % 4);
|
|
166
168
|
const normalised = (base64 + padding).replace(/-/g, "+").replace(/_/g, "/");
|
|
167
169
|
const raw = atob(normalised);
|
|
@@ -200,7 +202,7 @@ export type SubscribeOptions = {
|
|
|
200
202
|
/** From `GET customer-portal/push`. */
|
|
201
203
|
vapidPublicKey: string;
|
|
202
204
|
/**
|
|
203
|
-
* Path to the service worker ON YOUR ORIGIN. Defaults to `/
|
|
205
|
+
* Path to the service worker ON YOUR ORIGIN. Defaults to `/bd-sw.js`.
|
|
204
206
|
*
|
|
205
207
|
* It must be served from your own domain — a worker on someone else's
|
|
206
208
|
* cannot receive your visitors' push. Copy the one this SDK ships.
|
|
@@ -258,7 +260,7 @@ export async function subscribeToPush(
|
|
|
258
260
|
|
|
259
261
|
try {
|
|
260
262
|
const registration = await navigator.serviceWorker.register(
|
|
261
|
-
options.serviceWorkerPath ?? "/
|
|
263
|
+
options.serviceWorkerPath ?? "/bd-sw.js",
|
|
262
264
|
{ scope: options.scope ?? "/" },
|
|
263
265
|
);
|
|
264
266
|
// A worker that is installing cannot take a subscription yet.
|
|
@@ -287,7 +289,11 @@ export async function subscribeToPush(
|
|
|
287
289
|
// Required by every browser now — a subscription without it is
|
|
288
290
|
// rejected outright rather than delivered to nobody.
|
|
289
291
|
userVisibleOnly: true,
|
|
290
|
-
|
|
292
|
+
// The cast is sound — the bytes are ArrayBuffer-backed above —
|
|
293
|
+
// and keeps the helper's signature parseable on pre-5.7 TS.
|
|
294
|
+
applicationServerKey: urlBase64ToUint8Array(
|
|
295
|
+
options.vapidPublicKey,
|
|
296
|
+
) as BufferSource,
|
|
291
297
|
}));
|
|
292
298
|
|
|
293
299
|
return { ok: true, subscription: toPayload(subscription) };
|