@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/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@businessdash/sdk",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.70",
|
|
4
4
|
"description": "BusinessDash developer SDK \u2014 the data layer that lets you build customer-facing surfaces on your own domain while BusinessDash handles the operations stack behind the scenes. 0.9.x ships a comprehensive programmatic surface: storefront (products, categories, cart, checkout via Stripe Connect with Link payment), customer portal (work feed, per-item detail, quote accept/reject, job activity, comment threads, reviews, notification preferences), blog (posts, categories, threaded comments, reactions, paywalls, Mux video), Front Desk chat (sessions, AI bot, live human handoff, queue + place-in-line), coupons (validation against synced Stripe Promotion Codes \u2014 BOGO/BXGY/free-shipping kinds), shipping (multi-carrier rates + tracking via Shippo), address validation (Google Places, platform-proxied), customer notification preferences across in-app/email/SMS/webhook, subscriptions admin + Stripe sync, and followers/subscribers. Also: tenant sign-in/up/out via the auth handler, schema-driven marketing pages with restore semantics, typed JSON-LD SEO builders (LocalBusiness/Service/FAQ/Article/Breadcrumb/Review), and a CLI (`biab-dev sync-schema`) for the schema flow. The consumer renders the UI in their own design system on their own domain; BusinessDash supplies the data, the business logic, and the Stripe/Mux/Google/Shippo plumbing.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"files": [
|
|
8
8
|
"dist",
|
|
9
9
|
"openapi.json",
|
|
10
|
-
"src"
|
|
10
|
+
"src",
|
|
11
|
+
"assets"
|
|
11
12
|
],
|
|
12
13
|
"main": "./dist/index.js",
|
|
13
14
|
"module": "./dist/index.js",
|
|
@@ -31,6 +32,10 @@
|
|
|
31
32
|
"types": "./dist/contracts.d.ts",
|
|
32
33
|
"import": "./dist/contracts.js"
|
|
33
34
|
},
|
|
35
|
+
"./framework-support": {
|
|
36
|
+
"types": "./dist/framework-support.d.ts",
|
|
37
|
+
"import": "./dist/framework-support.js"
|
|
38
|
+
},
|
|
34
39
|
"./native": {
|
|
35
40
|
"types": "./dist/native.d.ts",
|
|
36
41
|
"import": "./dist/native.js"
|
|
@@ -51,6 +56,46 @@
|
|
|
51
56
|
"types": "./dist/forms.d.ts",
|
|
52
57
|
"import": "./dist/forms.js"
|
|
53
58
|
},
|
|
59
|
+
"./store": {
|
|
60
|
+
"types": "./dist/store.d.ts",
|
|
61
|
+
"import": "./dist/store.js"
|
|
62
|
+
},
|
|
63
|
+
"./chat": {
|
|
64
|
+
"types": "./dist/chat.d.ts",
|
|
65
|
+
"import": "./dist/chat.js"
|
|
66
|
+
},
|
|
67
|
+
"./blog": {
|
|
68
|
+
"types": "./dist/blog.d.ts",
|
|
69
|
+
"import": "./dist/blog.js"
|
|
70
|
+
},
|
|
71
|
+
"./checkout": {
|
|
72
|
+
"types": "./dist/checkout.d.ts",
|
|
73
|
+
"import": "./dist/checkout.js"
|
|
74
|
+
},
|
|
75
|
+
"./account": {
|
|
76
|
+
"types": "./dist/account.d.ts",
|
|
77
|
+
"import": "./dist/account.js"
|
|
78
|
+
},
|
|
79
|
+
"./marketing": {
|
|
80
|
+
"types": "./dist/marketing.d.ts",
|
|
81
|
+
"import": "./dist/marketing.js"
|
|
82
|
+
},
|
|
83
|
+
"./verify": {
|
|
84
|
+
"types": "./dist/verify.d.ts",
|
|
85
|
+
"import": "./dist/verify.js"
|
|
86
|
+
},
|
|
87
|
+
"./portal": {
|
|
88
|
+
"types": "./dist/portal.d.ts",
|
|
89
|
+
"import": "./dist/portal.js"
|
|
90
|
+
},
|
|
91
|
+
"./social": {
|
|
92
|
+
"types": "./dist/social.d.ts",
|
|
93
|
+
"import": "./dist/social.js"
|
|
94
|
+
},
|
|
95
|
+
"./seed": {
|
|
96
|
+
"types": "./dist/seed.d.ts",
|
|
97
|
+
"import": "./dist/seed.js"
|
|
98
|
+
},
|
|
54
99
|
"./collections": {
|
|
55
100
|
"types": "./dist/collections.d.ts",
|
|
56
101
|
"import": "./dist/collections.js"
|
|
@@ -113,6 +158,10 @@
|
|
|
113
158
|
"types": "./dist/mcp.d.ts",
|
|
114
159
|
"import": "./dist/mcp.js"
|
|
115
160
|
},
|
|
161
|
+
"./mcp-adapters": {
|
|
162
|
+
"types": "./dist/mcp-adapters.d.ts",
|
|
163
|
+
"import": "./dist/mcp-adapters.js"
|
|
164
|
+
},
|
|
116
165
|
"./proxy": {
|
|
117
166
|
"types": "./dist/proxy.d.ts",
|
|
118
167
|
"import": "./dist/proxy.js"
|
|
@@ -141,7 +190,38 @@
|
|
|
141
190
|
"types": "./dist/adapters-revalidate.d.ts",
|
|
142
191
|
"import": "./dist/adapters-revalidate.js"
|
|
143
192
|
},
|
|
144
|
-
"./biab-forms.css": "./dist/biab-forms.css"
|
|
193
|
+
"./biab-forms.css": "./dist/biab-forms.css",
|
|
194
|
+
"./seo-core": {
|
|
195
|
+
"types": "./dist/seo-core/index.d.ts",
|
|
196
|
+
"import": "./dist/seo-core/index.js",
|
|
197
|
+
"require": "./dist/seo-core/index.cjs"
|
|
198
|
+
},
|
|
199
|
+
"./push-core": {
|
|
200
|
+
"types": "./dist/push-core/index.d.ts",
|
|
201
|
+
"import": "./dist/push-core/index.js",
|
|
202
|
+
"require": "./dist/push-core/index.cjs"
|
|
203
|
+
},
|
|
204
|
+
"./notifications": {
|
|
205
|
+
"types": "./dist/notifications-core/index.d.ts",
|
|
206
|
+
"import": "./dist/notifications-core/index.js",
|
|
207
|
+
"require": "./dist/notifications-core/index.cjs"
|
|
208
|
+
},
|
|
209
|
+
"./legal": {
|
|
210
|
+
"types": "./dist/legal-core/index.d.ts",
|
|
211
|
+
"import": "./dist/legal-core/index.js",
|
|
212
|
+
"require": "./dist/legal-core/index.cjs"
|
|
213
|
+
},
|
|
214
|
+
"./sitemap": {
|
|
215
|
+
"types": "./dist/sitemap-core/index.d.ts",
|
|
216
|
+
"import": "./dist/sitemap-core/index.js",
|
|
217
|
+
"require": "./dist/sitemap-core/index.cjs"
|
|
218
|
+
},
|
|
219
|
+
"./model3d": {
|
|
220
|
+
"types": "./dist/model3d-core/index.d.ts",
|
|
221
|
+
"import": "./dist/model3d-core/index.js",
|
|
222
|
+
"require": "./dist/model3d-core/index.cjs"
|
|
223
|
+
},
|
|
224
|
+
"./biab-sw.js": "./assets/biab-sw.js"
|
|
145
225
|
},
|
|
146
226
|
"scripts": {
|
|
147
227
|
"clean": "node -e \"const fs=require('node:fs');fs.rmSync('dist',{recursive:true,force:true})\"",
|
|
@@ -149,19 +229,25 @@
|
|
|
149
229
|
"openapi": "tsx scripts/openapi.ts",
|
|
150
230
|
"openapi:check": "tsx scripts/openapi.ts --check",
|
|
151
231
|
"postbuild": "node scripts/publish-types.js",
|
|
152
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
232
|
+
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.solid.json --noEmit && tsc -p tsconfig.qwik.json --noEmit && tsc -p tsconfig.headless.json --noEmit",
|
|
153
233
|
"test:types": "tsc -p tsconfig.type-tests.json --noEmit",
|
|
154
234
|
"test": "tsx --test test/*.test.ts test/*.test.tsx",
|
|
155
235
|
"lint": "biome check .",
|
|
156
236
|
"lint:fix": "biome check --write .",
|
|
157
|
-
"prepublishOnly": "npm run build"
|
|
237
|
+
"prepublishOnly": "npm run build",
|
|
238
|
+
"typecheck:solid": "tsc -p tsconfig.solid.json --noEmit",
|
|
239
|
+
"typecheck:headless": "tsc -p tsconfig.headless.json --noEmit",
|
|
240
|
+
"typecheck:qwik": "tsc -p tsconfig.qwik.json --noEmit",
|
|
241
|
+
"gen:socials": "tsx scripts/gen-social-tables.ts",
|
|
242
|
+
"gen:socials:check": "tsx scripts/gen-social-tables.ts --check",
|
|
243
|
+
"typecheck:solid2": "tsc -p tsconfig.solid2.json --noEmit"
|
|
158
244
|
},
|
|
159
245
|
"publishConfig": {
|
|
160
246
|
"access": "public"
|
|
161
247
|
},
|
|
162
248
|
"repository": {
|
|
163
249
|
"type": "git",
|
|
164
|
-
"url": "git+https://github.com/
|
|
250
|
+
"url": "git+https://github.com/businessdash/platform.git",
|
|
165
251
|
"directory": "biab-dev"
|
|
166
252
|
},
|
|
167
253
|
"license": "MIT",
|
|
@@ -178,8 +264,13 @@
|
|
|
178
264
|
"zod-to-json-schema": "^3.25.2"
|
|
179
265
|
},
|
|
180
266
|
"peerDependencies": {
|
|
181
|
-
"
|
|
182
|
-
"
|
|
267
|
+
"@angular/core": ">=17.0.0",
|
|
268
|
+
"@builder.io/qwik": ">=1.5.0 <2",
|
|
269
|
+
"react": ">=18.0.0 <20",
|
|
270
|
+
"react-dom": ">=18.0.0 <20",
|
|
271
|
+
"solid-js": ">=1.8.0 <3",
|
|
272
|
+
"svelte": ">=5.0.0 <6",
|
|
273
|
+
"vue": ">=3.3.0 <4"
|
|
183
274
|
},
|
|
184
275
|
"peerDependenciesMeta": {
|
|
185
276
|
"react": {
|
|
@@ -187,14 +278,35 @@
|
|
|
187
278
|
},
|
|
188
279
|
"react-dom": {
|
|
189
280
|
"optional": true
|
|
281
|
+
},
|
|
282
|
+
"solid-js": {
|
|
283
|
+
"optional": true
|
|
284
|
+
},
|
|
285
|
+
"vue": {
|
|
286
|
+
"optional": true
|
|
287
|
+
},
|
|
288
|
+
"svelte": {
|
|
289
|
+
"optional": true
|
|
290
|
+
},
|
|
291
|
+
"@builder.io/qwik": {
|
|
292
|
+
"optional": true
|
|
293
|
+
},
|
|
294
|
+
"@angular/core": {
|
|
295
|
+
"optional": true
|
|
190
296
|
}
|
|
191
297
|
},
|
|
192
298
|
"devDependencies": {
|
|
193
299
|
"@biomejs/biome": "^2.5.1",
|
|
300
|
+
"@builder.io/qwik": "^1.5.0",
|
|
301
|
+
"@solidjs/web": "2.0.0-rc.1",
|
|
194
302
|
"@types/node": "^20.19.43",
|
|
195
303
|
"@types/react": "^19.2.17",
|
|
196
304
|
"esbuild": "^0.28.1",
|
|
197
|
-
"
|
|
305
|
+
"preact": "^10.29.8",
|
|
306
|
+
"preact-render-to-string": "^6.7.0",
|
|
307
|
+
"react": "^19.2.8",
|
|
308
|
+
"react-dom": "^19.2.8",
|
|
309
|
+
"solid-js-v2": "npm:solid-js@2.0.0-rc.1",
|
|
198
310
|
"tsx": "^4.22.4",
|
|
199
311
|
"typescript": "^5.9.3"
|
|
200
312
|
},
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@businessdash/sdk/account` — headless customer session and followers.
|
|
3
|
+
*
|
|
4
|
+
* Two small controllers that were React-only (plus Solid) and had no reason to
|
|
5
|
+
* be: neither has any framework-specific logic.
|
|
6
|
+
*
|
|
7
|
+
* ## Session
|
|
8
|
+
*
|
|
9
|
+
* `createUserController` reads the auth handler's `/me` route with the session
|
|
10
|
+
* cookie. It never touches an API key — the handler the consumer mounts owns
|
|
11
|
+
* the credential, and this only asks it who is signed in.
|
|
12
|
+
*
|
|
13
|
+
* Sign-in, sign-up and sign-out are navigations, not requests, so they are
|
|
14
|
+
* plain functions over `buildAuthHref` rather than controller actions. Every
|
|
15
|
+
* one of them no-ops outside a browser instead of throwing, so an SSR render
|
|
16
|
+
* that touches them degrades rather than crashes.
|
|
17
|
+
*
|
|
18
|
+
* ## Followers
|
|
19
|
+
*
|
|
20
|
+
* `createFollowersController` wraps subscribe/unsubscribe with the local
|
|
21
|
+
* "this browser already subscribed" hint. The hint is a convenience for hiding
|
|
22
|
+
* a footer form without a round trip — it is NOT authority. `me()` is.
|
|
23
|
+
*
|
|
24
|
+
* @module
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import {
|
|
28
|
+
buildAuthHref,
|
|
29
|
+
clearLocalFollow,
|
|
30
|
+
DEFAULT_AUTH_BASE_PATH,
|
|
31
|
+
followerStoreKey,
|
|
32
|
+
type LocalFollow,
|
|
33
|
+
readLocalFollow,
|
|
34
|
+
writeLocalFollow,
|
|
35
|
+
} from "../auth-links.js";
|
|
36
|
+
import type { TenantAuthMeResponse } from "../contracts.js";
|
|
37
|
+
|
|
38
|
+
// ─── Session ─────────────────────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
export type UserStatus = "loading" | "signed-in" | "signed-out";
|
|
41
|
+
|
|
42
|
+
export type UserSnapshot = {
|
|
43
|
+
status: UserStatus;
|
|
44
|
+
user: TenantAuthMeResponse | null;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type UserController = {
|
|
48
|
+
snapshot(): UserSnapshot;
|
|
49
|
+
subscribe(callback: (snapshot: UserSnapshot) => void): () => void;
|
|
50
|
+
/** Read `/me`. Called once by `start()`; call again to re-check. */
|
|
51
|
+
refresh(): Promise<UserSnapshot>;
|
|
52
|
+
/** Kick off the first read. Bindings call this on mount. */
|
|
53
|
+
start(): void;
|
|
54
|
+
destroy(): void;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export type CreateUserControllerOptions = {
|
|
58
|
+
/** Where `createAuthHandler` is mounted. Defaults to `/api/biab-auth`. */
|
|
59
|
+
basePath?: string;
|
|
60
|
+
/** Injectable for tests; defaults to global `fetch`. */
|
|
61
|
+
fetchImpl?: typeof fetch;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export function createUserController(
|
|
65
|
+
options: CreateUserControllerOptions = {},
|
|
66
|
+
): UserController {
|
|
67
|
+
const basePath = (options.basePath ?? DEFAULT_AUTH_BASE_PATH).replace(
|
|
68
|
+
/\/$/,
|
|
69
|
+
"",
|
|
70
|
+
);
|
|
71
|
+
const doFetch = options.fetchImpl ?? globalThis.fetch;
|
|
72
|
+
|
|
73
|
+
let destroyed = false;
|
|
74
|
+
const subscribers = new Set<(s: UserSnapshot) => void>();
|
|
75
|
+
let state: UserSnapshot = { status: "loading", user: null };
|
|
76
|
+
|
|
77
|
+
function notify(): void {
|
|
78
|
+
if (destroyed) return;
|
|
79
|
+
for (const cb of subscribers) cb(state);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function refresh(): Promise<UserSnapshot> {
|
|
83
|
+
if (destroyed) return state;
|
|
84
|
+
try {
|
|
85
|
+
const res = await doFetch(`${basePath}/me`, { credentials: "include" });
|
|
86
|
+
const body = res.ok ? ((await res.json()) as TenantAuthMeResponse) : null;
|
|
87
|
+
if (destroyed) return state;
|
|
88
|
+
state = body
|
|
89
|
+
? { status: "signed-in", user: body }
|
|
90
|
+
: { status: "signed-out", user: null };
|
|
91
|
+
} catch {
|
|
92
|
+
// A network failure is indistinguishable from "not signed in" from the
|
|
93
|
+
// page's point of view, and treating it as an error would leave every
|
|
94
|
+
// consumer writing the same fallback.
|
|
95
|
+
if (!destroyed) state = { status: "signed-out", user: null };
|
|
96
|
+
}
|
|
97
|
+
notify();
|
|
98
|
+
return state;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
snapshot: () => state,
|
|
103
|
+
subscribe(callback) {
|
|
104
|
+
subscribers.add(callback);
|
|
105
|
+
return () => {
|
|
106
|
+
subscribers.delete(callback);
|
|
107
|
+
};
|
|
108
|
+
},
|
|
109
|
+
refresh,
|
|
110
|
+
start() {
|
|
111
|
+
void refresh();
|
|
112
|
+
},
|
|
113
|
+
destroy() {
|
|
114
|
+
destroyed = true;
|
|
115
|
+
subscribers.clear();
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export type ProgrammaticAuthOptions = {
|
|
121
|
+
/** Where to send the customer afterwards. */
|
|
122
|
+
returnTo?: string;
|
|
123
|
+
/** Pre-fill the email on the hosted page (sign-in / sign-up only). */
|
|
124
|
+
loginHint?: string;
|
|
125
|
+
/** Override the auth-handler basePath. */
|
|
126
|
+
basePath?: string;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/** Href for the auth handler's sign-in route — render it in your own link. */
|
|
130
|
+
export function signInHref(options: ProgrammaticAuthOptions = {}): string {
|
|
131
|
+
return buildAuthHref("sign-in", options);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Href for the auth handler's sign-up route. */
|
|
135
|
+
export function signUpHref(options: ProgrammaticAuthOptions = {}): string {
|
|
136
|
+
return buildAuthHref("sign-up", options);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Href for the auth handler's sign-out route. */
|
|
140
|
+
export function signOutHref(options: { basePath?: string } = {}): string {
|
|
141
|
+
return buildAuthHref("sign-out", options);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** Navigate to sign-in. No-ops outside a browser. */
|
|
145
|
+
export function signIn(options: ProgrammaticAuthOptions = {}): void {
|
|
146
|
+
if (typeof window === "undefined") return;
|
|
147
|
+
window.location.assign(signInHref(options));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Navigate to sign-up. No-ops outside a browser. */
|
|
151
|
+
export function signUp(options: ProgrammaticAuthOptions = {}): void {
|
|
152
|
+
if (typeof window === "undefined") return;
|
|
153
|
+
window.location.assign(signUpHref(options));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Navigate to sign-out. No-ops outside a browser. */
|
|
157
|
+
export function signOut(options: { basePath?: string } = {}): void {
|
|
158
|
+
if (typeof window === "undefined") return;
|
|
159
|
+
window.location.assign(signOutHref(options));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ─── Followers ───────────────────────────────────────────────────────────────
|
|
163
|
+
|
|
164
|
+
export type FollowersCoreClient = {
|
|
165
|
+
followers: {
|
|
166
|
+
join(input: {
|
|
167
|
+
email: string;
|
|
168
|
+
name?: string;
|
|
169
|
+
source?: string;
|
|
170
|
+
}): Promise<unknown>;
|
|
171
|
+
leave(input: { email: string }): Promise<unknown>;
|
|
172
|
+
me(input: { email: string }): Promise<unknown>;
|
|
173
|
+
edit(input: {
|
|
174
|
+
email: string;
|
|
175
|
+
patch: { name?: string; source?: string };
|
|
176
|
+
}): Promise<unknown>;
|
|
177
|
+
};
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
export type FollowersSnapshot = {
|
|
181
|
+
/** This browser already subscribed. A hint for hiding a form, not authority. */
|
|
182
|
+
subscribedLocally: boolean;
|
|
183
|
+
/** The email this browser subscribed with, or `null`. */
|
|
184
|
+
localEmail: string | null;
|
|
185
|
+
isPending: boolean;
|
|
186
|
+
error: Error | null;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
export type FollowersController = {
|
|
190
|
+
snapshot(): FollowersSnapshot;
|
|
191
|
+
subscribe(callback: (snapshot: FollowersSnapshot) => void): () => void;
|
|
192
|
+
join(input: {
|
|
193
|
+
email: string;
|
|
194
|
+
name?: string;
|
|
195
|
+
source?: string;
|
|
196
|
+
}): Promise<unknown>;
|
|
197
|
+
leave(email: string): Promise<unknown>;
|
|
198
|
+
/** Authoritative status for an email — unlike `subscribedLocally`. */
|
|
199
|
+
me(email: string): Promise<unknown>;
|
|
200
|
+
edit(
|
|
201
|
+
email: string,
|
|
202
|
+
patch: { name?: string; source?: string },
|
|
203
|
+
): Promise<unknown>;
|
|
204
|
+
destroy(): void;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export type CreateFollowersControllerOptions = {
|
|
208
|
+
client: FollowersCoreClient;
|
|
209
|
+
/** Site id — namespaces the local hint so two sites don't share it. */
|
|
210
|
+
siteId: string;
|
|
211
|
+
onError?: (error: Error) => void;
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
export function createFollowersController(
|
|
215
|
+
options: CreateFollowersControllerOptions,
|
|
216
|
+
): FollowersController {
|
|
217
|
+
const { client, siteId, onError } = options;
|
|
218
|
+
const storeKey = followerStoreKey(siteId);
|
|
219
|
+
|
|
220
|
+
let destroyed = false;
|
|
221
|
+
const subscribers = new Set<(s: FollowersSnapshot) => void>();
|
|
222
|
+
let local: LocalFollow | null = readLocalFollow(storeKey);
|
|
223
|
+
let isPending = false;
|
|
224
|
+
let error: Error | null = null;
|
|
225
|
+
let cached: FollowersSnapshot | null = null;
|
|
226
|
+
|
|
227
|
+
function snapshot(): FollowersSnapshot {
|
|
228
|
+
if (!cached) {
|
|
229
|
+
cached = {
|
|
230
|
+
subscribedLocally: local !== null,
|
|
231
|
+
localEmail: local?.email ?? null,
|
|
232
|
+
isPending,
|
|
233
|
+
error,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
return cached;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function notify(): void {
|
|
240
|
+
if (destroyed) return;
|
|
241
|
+
cached = null;
|
|
242
|
+
const next = snapshot();
|
|
243
|
+
for (const cb of subscribers) cb(next);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async function run<T>(work: () => Promise<T>, fallback: string): Promise<T> {
|
|
247
|
+
isPending = true;
|
|
248
|
+
error = null;
|
|
249
|
+
notify();
|
|
250
|
+
try {
|
|
251
|
+
return await work();
|
|
252
|
+
} catch (cause) {
|
|
253
|
+
const err = cause instanceof Error ? cause : new Error(fallback);
|
|
254
|
+
error = err;
|
|
255
|
+
onError?.(err);
|
|
256
|
+
throw err;
|
|
257
|
+
} finally {
|
|
258
|
+
isPending = false;
|
|
259
|
+
notify();
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return {
|
|
264
|
+
snapshot,
|
|
265
|
+
subscribe(callback) {
|
|
266
|
+
subscribers.add(callback);
|
|
267
|
+
return () => {
|
|
268
|
+
subscribers.delete(callback);
|
|
269
|
+
};
|
|
270
|
+
},
|
|
271
|
+
|
|
272
|
+
join(input) {
|
|
273
|
+
return run(async () => {
|
|
274
|
+
const res = await client.followers.join(input);
|
|
275
|
+
local = { email: input.email, at: Date.now() };
|
|
276
|
+
writeLocalFollow(storeKey, local);
|
|
277
|
+
return res;
|
|
278
|
+
}, "Could not subscribe.");
|
|
279
|
+
},
|
|
280
|
+
|
|
281
|
+
leave(email) {
|
|
282
|
+
return run(async () => {
|
|
283
|
+
const res = await client.followers.leave({ email });
|
|
284
|
+
clearLocalFollow(storeKey);
|
|
285
|
+
local = null;
|
|
286
|
+
return res;
|
|
287
|
+
}, "Could not unsubscribe.");
|
|
288
|
+
},
|
|
289
|
+
|
|
290
|
+
me(email) {
|
|
291
|
+
return run(
|
|
292
|
+
() => client.followers.me({ email }),
|
|
293
|
+
"Could not read status.",
|
|
294
|
+
);
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
edit(email, patch) {
|
|
298
|
+
return run(
|
|
299
|
+
() => client.followers.edit({ email, patch }),
|
|
300
|
+
"Could not update the subscription.",
|
|
301
|
+
);
|
|
302
|
+
},
|
|
303
|
+
|
|
304
|
+
destroy() {
|
|
305
|
+
destroyed = true;
|
|
306
|
+
subscribers.clear();
|
|
307
|
+
},
|
|
308
|
+
};
|
|
309
|
+
}
|
package/src/account.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@businessdash/sdk/account` — the framework-agnostic customer session and
|
|
3
|
+
* followers cores.
|
|
4
|
+
*
|
|
5
|
+
* Source-shipped bindings import through this public subpath, as they do for
|
|
6
|
+
* `forms`, `store`, `chat` and `blog`.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export * from "./account-core/index.js";
|