@businessdash/sdk 0.9.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +899 -0
  3. package/dist/adapters-revalidate.d.ts +44 -0
  4. package/dist/adapters-revalidate.d.ts.map +1 -0
  5. package/dist/adapters-revalidate.js +68 -0
  6. package/dist/adapters-revalidate.js.map +1 -0
  7. package/dist/alpha.d.ts +21 -0
  8. package/dist/alpha.d.ts.map +1 -0
  9. package/dist/alpha.js +21 -0
  10. package/dist/alpha.js.map +1 -0
  11. package/dist/analytics-core.d.ts +34 -0
  12. package/dist/analytics-core.d.ts.map +1 -0
  13. package/dist/analytics-core.js +138 -0
  14. package/dist/analytics-core.js.map +1 -0
  15. package/dist/analytics-server.d.ts +54 -0
  16. package/dist/analytics-server.d.ts.map +1 -0
  17. package/dist/analytics-server.js +78 -0
  18. package/dist/analytics-server.js.map +1 -0
  19. package/dist/attribution-logo.d.ts +2 -0
  20. package/dist/attribution-logo.d.ts.map +1 -0
  21. package/dist/attribution-logo.js +5 -0
  22. package/dist/attribution-logo.js.map +1 -0
  23. package/dist/auth-handler.d.ts +92 -0
  24. package/dist/auth-handler.d.ts.map +1 -0
  25. package/dist/auth-handler.js +277 -0
  26. package/dist/auth-handler.js.map +1 -0
  27. package/dist/biab-forms.css +484 -0
  28. package/dist/cli.d.ts +46 -0
  29. package/dist/cli.d.ts.map +1 -0
  30. package/dist/cli.js +1824 -0
  31. package/dist/cli.js.map +1 -0
  32. package/dist/client.d.ts +1681 -0
  33. package/dist/client.d.ts.map +1 -0
  34. package/dist/client.js +2845 -0
  35. package/dist/client.js.map +1 -0
  36. package/dist/collections.d.ts +13 -0
  37. package/dist/collections.d.ts.map +1 -0
  38. package/dist/collections.js +13 -0
  39. package/dist/collections.js.map +1 -0
  40. package/dist/contracts.d.ts +14609 -0
  41. package/dist/contracts.d.ts.map +1 -0
  42. package/dist/contracts.js +2428 -0
  43. package/dist/contracts.js.map +1 -0
  44. package/dist/data-model-schema.d.ts +962 -0
  45. package/dist/data-model-schema.d.ts.map +1 -0
  46. package/dist/data-model-schema.js +2295 -0
  47. package/dist/data-model-schema.js.map +1 -0
  48. package/dist/distribution.d.ts +38 -0
  49. package/dist/distribution.d.ts.map +1 -0
  50. package/dist/distribution.js +61 -0
  51. package/dist/distribution.js.map +1 -0
  52. package/dist/element.d.ts +121 -0
  53. package/dist/element.d.ts.map +1 -0
  54. package/dist/element.js +276 -0
  55. package/dist/element.js.map +1 -0
  56. package/dist/enums.d.ts +25 -0
  57. package/dist/enums.d.ts.map +1 -0
  58. package/dist/enums.js +38 -0
  59. package/dist/enums.js.map +1 -0
  60. package/dist/errors.d.ts +195 -0
  61. package/dist/errors.d.ts.map +1 -0
  62. package/dist/errors.js +188 -0
  63. package/dist/errors.js.map +1 -0
  64. package/dist/forms-core/autocomplete.d.ts +37 -0
  65. package/dist/forms-core/autocomplete.d.ts.map +1 -0
  66. package/dist/forms-core/autocomplete.js +82 -0
  67. package/dist/forms-core/autocomplete.js.map +1 -0
  68. package/dist/forms-core/business-function.d.ts +61 -0
  69. package/dist/forms-core/business-function.d.ts.map +1 -0
  70. package/dist/forms-core/business-function.js +149 -0
  71. package/dist/forms-core/business-function.js.map +1 -0
  72. package/dist/forms-core/calculation.d.ts +72 -0
  73. package/dist/forms-core/calculation.d.ts.map +1 -0
  74. package/dist/forms-core/calculation.js +103 -0
  75. package/dist/forms-core/calculation.js.map +1 -0
  76. package/dist/forms-core/controller.d.ts +249 -0
  77. package/dist/forms-core/controller.d.ts.map +1 -0
  78. package/dist/forms-core/controller.js +590 -0
  79. package/dist/forms-core/controller.js.map +1 -0
  80. package/dist/forms-core/elements.d.ts +44 -0
  81. package/dist/forms-core/elements.d.ts.map +1 -0
  82. package/dist/forms-core/elements.js +68 -0
  83. package/dist/forms-core/elements.js.map +1 -0
  84. package/dist/forms-core/email-domains.d.ts +10 -0
  85. package/dist/forms-core/email-domains.d.ts.map +1 -0
  86. package/dist/forms-core/email-domains.js +69 -0
  87. package/dist/forms-core/email-domains.js.map +1 -0
  88. package/dist/forms-core/file-rules.d.ts +51 -0
  89. package/dist/forms-core/file-rules.d.ts.map +1 -0
  90. package/dist/forms-core/file-rules.js +105 -0
  91. package/dist/forms-core/file-rules.js.map +1 -0
  92. package/dist/forms-core/formula.d.ts +114 -0
  93. package/dist/forms-core/formula.d.ts.map +1 -0
  94. package/dist/forms-core/formula.js +1170 -0
  95. package/dist/forms-core/formula.js.map +1 -0
  96. package/dist/forms-core/index.d.ts +24 -0
  97. package/dist/forms-core/index.d.ts.map +1 -0
  98. package/dist/forms-core/index.js +28 -0
  99. package/dist/forms-core/index.js.map +1 -0
  100. package/dist/forms-core/units.d.ts +49 -0
  101. package/dist/forms-core/units.d.ts.map +1 -0
  102. package/dist/forms-core/units.js +255 -0
  103. package/dist/forms-core/units.js.map +1 -0
  104. package/dist/forms-core/us-states.d.ts +14 -0
  105. package/dist/forms-core/us-states.d.ts.map +1 -0
  106. package/dist/forms-core/us-states.js +66 -0
  107. package/dist/forms-core/us-states.js.map +1 -0
  108. package/dist/forms-core/validation.d.ts +266 -0
  109. package/dist/forms-core/validation.d.ts.map +1 -0
  110. package/dist/forms-core/validation.js +850 -0
  111. package/dist/forms-core/validation.js.map +1 -0
  112. package/dist/forms.d.ts +19 -0
  113. package/dist/forms.d.ts.map +1 -0
  114. package/dist/forms.js +29 -0
  115. package/dist/forms.js.map +1 -0
  116. package/dist/gallery-types.d.ts +32 -0
  117. package/dist/gallery-types.d.ts.map +1 -0
  118. package/dist/gallery-types.js +2 -0
  119. package/dist/gallery-types.js.map +1 -0
  120. package/dist/graphql.d.ts +97 -0
  121. package/dist/graphql.d.ts.map +1 -0
  122. package/dist/graphql.js +212 -0
  123. package/dist/graphql.js.map +1 -0
  124. package/dist/index.cjs +19448 -0
  125. package/dist/index.d.cts +19 -0
  126. package/dist/index.d.mts +19 -0
  127. package/dist/index.d.ts +19 -0
  128. package/dist/index.d.ts.map +1 -0
  129. package/dist/index.js +20 -0
  130. package/dist/index.js.map +1 -0
  131. package/dist/marketing-schema.d.ts +216 -0
  132. package/dist/marketing-schema.d.ts.map +1 -0
  133. package/dist/marketing-schema.js +200 -0
  134. package/dist/marketing-schema.js.map +1 -0
  135. package/dist/mcp.d.ts +42 -0
  136. package/dist/mcp.d.ts.map +1 -0
  137. package/dist/mcp.js +87 -0
  138. package/dist/mcp.js.map +1 -0
  139. package/dist/native.d.ts +45 -0
  140. package/dist/native.d.ts.map +1 -0
  141. package/dist/native.js +43 -0
  142. package/dist/native.js.map +1 -0
  143. package/dist/next-revalidate.d.ts +43 -0
  144. package/dist/next-revalidate.d.ts.map +1 -0
  145. package/dist/next-revalidate.js +84 -0
  146. package/dist/next-revalidate.js.map +1 -0
  147. package/dist/parallel-pages.d.ts +102 -0
  148. package/dist/parallel-pages.d.ts.map +1 -0
  149. package/dist/parallel-pages.js +108 -0
  150. package/dist/parallel-pages.js.map +1 -0
  151. package/dist/payment-icons.d.ts +66 -0
  152. package/dist/payment-icons.d.ts.map +1 -0
  153. package/dist/payment-icons.js +160 -0
  154. package/dist/payment-icons.js.map +1 -0
  155. package/dist/proxy.d.ts +67 -0
  156. package/dist/proxy.d.ts.map +1 -0
  157. package/dist/proxy.js +97 -0
  158. package/dist/proxy.js.map +1 -0
  159. package/dist/react-analytics.d.ts +39 -0
  160. package/dist/react-analytics.d.ts.map +1 -0
  161. package/dist/react-analytics.js +59 -0
  162. package/dist/react-analytics.js.map +1 -0
  163. package/dist/react-attribution.d.ts +99 -0
  164. package/dist/react-attribution.d.ts.map +1 -0
  165. package/dist/react-attribution.js +52 -0
  166. package/dist/react-attribution.js.map +1 -0
  167. package/dist/react-marketing.d.ts +181 -0
  168. package/dist/react-marketing.d.ts.map +1 -0
  169. package/dist/react-marketing.js +215 -0
  170. package/dist/react-marketing.js.map +1 -0
  171. package/dist/react.d.ts +727 -0
  172. package/dist/react.d.ts.map +1 -0
  173. package/dist/react.js +2418 -0
  174. package/dist/react.js.map +1 -0
  175. package/dist/reserved-paths.d.ts +24 -0
  176. package/dist/reserved-paths.d.ts.map +1 -0
  177. package/dist/reserved-paths.js +60 -0
  178. package/dist/reserved-paths.js.map +1 -0
  179. package/dist/revalidate-verify.d.ts +30 -0
  180. package/dist/revalidate-verify.d.ts.map +1 -0
  181. package/dist/revalidate-verify.js +74 -0
  182. package/dist/revalidate-verify.js.map +1 -0
  183. package/dist/sdk.d.ts +678 -0
  184. package/dist/sdk.d.ts.map +1 -0
  185. package/dist/sdk.js +801 -0
  186. package/dist/sdk.js.map +1 -0
  187. package/dist/seo.d.ts +218 -0
  188. package/dist/seo.d.ts.map +1 -0
  189. package/dist/seo.js +309 -0
  190. package/dist/seo.js.map +1 -0
  191. package/dist/socials.d.ts +47 -0
  192. package/dist/socials.d.ts.map +1 -0
  193. package/dist/socials.js +172 -0
  194. package/dist/socials.js.map +1 -0
  195. package/dist/static.d.ts +14 -0
  196. package/dist/static.d.ts.map +1 -0
  197. package/dist/static.js +14 -0
  198. package/dist/static.js.map +1 -0
  199. package/dist/url-pattern.d.ts +47 -0
  200. package/dist/url-pattern.d.ts.map +1 -0
  201. package/dist/url-pattern.js +124 -0
  202. package/dist/url-pattern.js.map +1 -0
  203. package/dist/vanilla.d.ts +77 -0
  204. package/dist/vanilla.d.ts.map +1 -0
  205. package/dist/vanilla.js +903 -0
  206. package/dist/vanilla.js.map +1 -0
  207. package/openapi.json +13779 -0
  208. package/package.json +204 -0
  209. package/src/adapters-revalidate.ts +88 -0
  210. package/src/alpha.ts +89 -0
  211. package/src/analytics-core.ts +175 -0
  212. package/src/analytics-server.ts +99 -0
  213. package/src/angular/biab-form.component.ts +1443 -0
  214. package/src/angular/index.ts +26 -0
  215. package/src/attribution-logo.ts +5 -0
  216. package/src/auth-handler.ts +352 -0
  217. package/src/cli.ts +2517 -0
  218. package/src/client.ts +3578 -0
  219. package/src/collections.ts +101 -0
  220. package/src/contracts.ts +3390 -0
  221. package/src/data-model-schema.ts +4042 -0
  222. package/src/distribution.ts +73 -0
  223. package/src/element.ts +321 -0
  224. package/src/enums.ts +65 -0
  225. package/src/errors.ts +338 -0
  226. package/src/forms-core/autocomplete.ts +97 -0
  227. package/src/forms-core/business-function.ts +209 -0
  228. package/src/forms-core/calculation.ts +167 -0
  229. package/src/forms-core/controller.ts +922 -0
  230. package/src/forms-core/elements.ts +86 -0
  231. package/src/forms-core/email-domains.ts +68 -0
  232. package/src/forms-core/file-rules.ts +123 -0
  233. package/src/forms-core/formula.ts +1339 -0
  234. package/src/forms-core/index.ts +122 -0
  235. package/src/forms-core/units.ts +308 -0
  236. package/src/forms-core/us-states.ts +68 -0
  237. package/src/forms-core/validation.ts +1037 -0
  238. package/src/forms.ts +63 -0
  239. package/src/gallery-types.ts +31 -0
  240. package/src/graphql.ts +295 -0
  241. package/src/index.ts +505 -0
  242. package/src/marketing-schema.ts +395 -0
  243. package/src/mcp.ts +108 -0
  244. package/src/native.ts +73 -0
  245. package/src/next-revalidate.ts +124 -0
  246. package/src/parallel-pages.ts +192 -0
  247. package/src/payment-icons.ts +205 -0
  248. package/src/proxy.ts +173 -0
  249. package/src/qwik.tsx +1234 -0
  250. package/src/react-analytics.tsx +76 -0
  251. package/src/react-attribution.tsx +192 -0
  252. package/src/react-marketing.tsx +338 -0
  253. package/src/react.tsx +5495 -0
  254. package/src/reserved-paths.ts +65 -0
  255. package/src/revalidate-verify.ts +98 -0
  256. package/src/sdk.ts +1671 -0
  257. package/src/seo.ts +488 -0
  258. package/src/socials.ts +230 -0
  259. package/src/solid.tsx +1466 -0
  260. package/src/static.ts +21 -0
  261. package/src/styles/biab-forms.css +484 -0
  262. package/src/svelte/BiabForm.svelte +1069 -0
  263. package/src/svelte/context.ts +57 -0
  264. package/src/svelte/index.ts +79 -0
  265. package/src/url-pattern.ts +153 -0
  266. package/src/vanilla.ts +1290 -0
  267. package/src/vue/BiabForm.vue +1538 -0
  268. package/src/vue/index.ts +119 -0
package/package.json ADDED
@@ -0,0 +1,204 @@
1
+ {
2
+ "name": "@businessdash/sdk",
3
+ "version": "0.9.60",
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
+ "type": "module",
6
+ "sideEffects": false,
7
+ "files": [
8
+ "dist",
9
+ "openapi.json",
10
+ "src"
11
+ ],
12
+ "main": "./dist/index.js",
13
+ "module": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "bin": {
16
+ "biab-dev": "./dist/cli.js",
17
+ "businessdash": "./dist/cli.js"
18
+ },
19
+ "exports": {
20
+ ".": {
21
+ "import": {
22
+ "types": "./dist/index.d.mts",
23
+ "default": "./dist/index.js"
24
+ },
25
+ "require": {
26
+ "types": "./dist/index.d.cts",
27
+ "default": "./dist/index.cjs"
28
+ }
29
+ },
30
+ "./contracts": {
31
+ "types": "./dist/contracts.d.ts",
32
+ "import": "./dist/contracts.js"
33
+ },
34
+ "./native": {
35
+ "types": "./dist/native.d.ts",
36
+ "import": "./dist/native.js"
37
+ },
38
+ "./enums": {
39
+ "types": "./dist/enums.d.ts",
40
+ "import": "./dist/enums.js"
41
+ },
42
+ "./graphql": {
43
+ "types": "./dist/graphql.d.ts",
44
+ "import": "./dist/graphql.js"
45
+ },
46
+ "./react": {
47
+ "types": "./dist/react.d.ts",
48
+ "import": "./dist/react.js"
49
+ },
50
+ "./forms": {
51
+ "types": "./dist/forms.d.ts",
52
+ "import": "./dist/forms.js"
53
+ },
54
+ "./collections": {
55
+ "types": "./dist/collections.d.ts",
56
+ "import": "./dist/collections.js"
57
+ },
58
+ "./static": {
59
+ "types": "./dist/static.d.ts",
60
+ "import": "./dist/static.js"
61
+ },
62
+ "./element": {
63
+ "types": "./dist/element.d.ts",
64
+ "import": "./dist/element.js"
65
+ },
66
+ "./vanilla": {
67
+ "types": "./dist/vanilla.d.ts",
68
+ "import": "./dist/vanilla.js"
69
+ },
70
+ "./vue": {
71
+ "types": "./src/vue/index.ts",
72
+ "import": "./src/vue/index.ts"
73
+ },
74
+ "./svelte": {
75
+ "svelte": "./src/svelte/index.ts",
76
+ "types": "./src/svelte/index.ts",
77
+ "import": "./src/svelte/index.ts"
78
+ },
79
+ "./solid": {
80
+ "types": "./src/solid.tsx",
81
+ "solid": "./src/solid.tsx",
82
+ "import": "./src/solid.tsx"
83
+ },
84
+ "./qwik": {
85
+ "types": "./src/qwik.tsx",
86
+ "import": "./src/qwik.tsx"
87
+ },
88
+ "./angular": {
89
+ "types": "./src/angular/index.ts",
90
+ "import": "./src/angular/index.ts"
91
+ },
92
+ "./react-analytics": {
93
+ "types": "./dist/react-analytics.d.ts",
94
+ "import": "./dist/react-analytics.js"
95
+ },
96
+ "./react-attribution": {
97
+ "types": "./dist/react-attribution.d.ts",
98
+ "import": "./dist/react-attribution.js"
99
+ },
100
+ "./analytics-core": {
101
+ "types": "./dist/analytics-core.d.ts",
102
+ "import": "./dist/analytics-core.js"
103
+ },
104
+ "./analytics-server": {
105
+ "types": "./dist/analytics-server.d.ts",
106
+ "import": "./dist/analytics-server.js"
107
+ },
108
+ "./distribution": {
109
+ "types": "./dist/distribution.d.ts",
110
+ "import": "./dist/distribution.js"
111
+ },
112
+ "./mcp": {
113
+ "types": "./dist/mcp.d.ts",
114
+ "import": "./dist/mcp.js"
115
+ },
116
+ "./proxy": {
117
+ "types": "./dist/proxy.d.ts",
118
+ "import": "./dist/proxy.js"
119
+ },
120
+ "./seo": {
121
+ "types": "./dist/seo.d.ts",
122
+ "import": "./dist/seo.js"
123
+ },
124
+ "./data-model-schema": {
125
+ "types": "./dist/data-model-schema.d.ts",
126
+ "import": "./dist/data-model-schema.js"
127
+ },
128
+ "./alpha": {
129
+ "types": "./dist/alpha.d.ts",
130
+ "import": "./dist/alpha.js"
131
+ },
132
+ "./marketing-schema": {
133
+ "types": "./dist/marketing-schema.d.ts",
134
+ "import": "./dist/marketing-schema.js"
135
+ },
136
+ "./next/revalidate": {
137
+ "types": "./dist/next-revalidate.d.ts",
138
+ "import": "./dist/next-revalidate.js"
139
+ },
140
+ "./adapters/revalidate": {
141
+ "types": "./dist/adapters-revalidate.d.ts",
142
+ "import": "./dist/adapters-revalidate.js"
143
+ },
144
+ "./biab-forms.css": "./dist/biab-forms.css"
145
+ },
146
+ "scripts": {
147
+ "clean": "node -e \"const fs=require('node:fs');fs.rmSync('dist',{recursive:true,force:true})\"",
148
+ "build": "npm run clean && tsc -p tsconfig.build.json && node scripts/build-cjs.js && node -e \"require('node:fs').copyFileSync('src/styles/biab-forms.css','dist/biab-forms.css')\"",
149
+ "openapi": "tsx scripts/openapi.ts",
150
+ "openapi:check": "tsx scripts/openapi.ts --check",
151
+ "postbuild": "node scripts/publish-types.js",
152
+ "typecheck": "tsc -p tsconfig.json --noEmit",
153
+ "test:types": "tsc -p tsconfig.type-tests.json --noEmit",
154
+ "test": "tsx --test test/*.test.ts test/*.test.tsx",
155
+ "lint": "biome check .",
156
+ "lint:fix": "biome check --write .",
157
+ "prepublishOnly": "npm run build"
158
+ },
159
+ "publishConfig": {
160
+ "access": "public"
161
+ },
162
+ "repository": {
163
+ "type": "git",
164
+ "url": "git+https://github.com/Gold240sx/business-in-a-box.git",
165
+ "directory": "biab-dev"
166
+ },
167
+ "license": "MIT",
168
+ "homepage": "https://businessdash.us",
169
+ "keywords": [
170
+ "businessdash",
171
+ "biab",
172
+ "business-in-a-box",
173
+ "alpha"
174
+ ],
175
+ "dependencies": {
176
+ "@js-temporal/polyfill": "^0.5.1",
177
+ "zod": "^3.25.76",
178
+ "zod-to-json-schema": "^3.25.2"
179
+ },
180
+ "peerDependencies": {
181
+ "react": ">=18.0.0",
182
+ "react-dom": ">=18.0.0"
183
+ },
184
+ "peerDependenciesMeta": {
185
+ "react": {
186
+ "optional": true
187
+ },
188
+ "react-dom": {
189
+ "optional": true
190
+ }
191
+ },
192
+ "devDependencies": {
193
+ "@biomejs/biome": "^2.5.1",
194
+ "@types/node": "^20.19.43",
195
+ "@types/react": "^19.2.17",
196
+ "esbuild": "^0.28.1",
197
+ "react": "^19.2.7",
198
+ "tsx": "^4.22.4",
199
+ "typescript": "^5.9.3"
200
+ },
201
+ "engines": {
202
+ "node": ">=18"
203
+ }
204
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Framework-agnostic revalidation handler builder.
3
+ *
4
+ * The Next.js drop-in at `@businessdash/sdk/next/revalidate` is the
5
+ * happy path for Next consumers — one-line `export { POST } from`
6
+ * and the handler verifies the HMAC + calls `revalidateTag`.
7
+ *
8
+ * For everything else (Cloudflare Workers, plain Node HTTP,
9
+ * SvelteKit, Remix, static-site rebuilds), this adapter exposes
10
+ * the same verification logic without the Next dependency. The
11
+ * consumer plugs in their own cache-invalidation callback —
12
+ * KV.delete, fetch(`/purge-cache`), trigger a static rebuild, etc.
13
+ *
14
+ * Usage example (Cloudflare Workers):
15
+ *
16
+ * import { createGenericRevalidateHandler } from "@businessdash/sdk/adapters/revalidate";
17
+ *
18
+ * const handler = createGenericRevalidateHandler({
19
+ * secret: env.BIAB_REVALIDATION_SECRET,
20
+ * onTagsRevalidated: async (tags) => {
21
+ * for (const tag of tags) {
22
+ * await env.PURGE_CACHE.fetch(new Request(`/?tag=${tag}`));
23
+ * }
24
+ * },
25
+ * });
26
+ *
27
+ * export default { fetch: (req) => handler(req) };
28
+ *
29
+ * The HMAC verification + replay-window logic lives in
30
+ * `verifyAndExtractTags` (next-revalidate.ts) and is shared.
31
+ */
32
+
33
+ // Import directly from the framework-agnostic verifier so this
34
+ // adapter file doesn't transitively pull in `next/cache` (which
35
+ // some non-Next bundlers — Nuxt's Nitro, Cloudflare's workerd —
36
+ // try to resolve at build time even when it's behind a runtime
37
+ // dynamic import).
38
+ export { verifyAndExtractTags } from "./revalidate-verify.js";
39
+
40
+ import { verifyAndExtractTags } from "./revalidate-verify.js";
41
+
42
+ export interface CreateGenericRevalidateHandlerOptions {
43
+ secret: string;
44
+ /**
45
+ * Called when the request verifies and a publish event is
46
+ * received. The consumer's framework-appropriate cache purge
47
+ * goes here. Failures should throw so the response is 500 —
48
+ * BIAB-side retry can re-deliver.
49
+ */
50
+ onTagsRevalidated: (tags: string[], orgId: string) => Promise<void> | void;
51
+ }
52
+
53
+ export function createGenericRevalidateHandler(
54
+ opts: CreateGenericRevalidateHandlerOptions,
55
+ ) {
56
+ if (!opts.secret) {
57
+ throw new Error("createGenericRevalidateHandler: secret is required.");
58
+ }
59
+ return async function handle(request: Request): Promise<Response> {
60
+ const rawBody = await request.text();
61
+ const sig = request.headers.get("x-biab-signature");
62
+ const verified = verifyAndExtractTags({
63
+ secret: opts.secret,
64
+ rawBody,
65
+ signatureHeader: sig,
66
+ });
67
+ if (!verified.ok || !verified.payload) {
68
+ return Response.json(
69
+ { ok: false, reason: verified.reason ?? "verify_failed" },
70
+ { status: 401 },
71
+ );
72
+ }
73
+ try {
74
+ await opts.onTagsRevalidated(
75
+ verified.payload.tags,
76
+ verified.payload.orgId,
77
+ );
78
+ } catch (err) {
79
+ const message = err instanceof Error ? err.message : "callback_failed";
80
+ return Response.json({ ok: false, reason: message }, { status: 500 });
81
+ }
82
+ return Response.json({
83
+ ok: true,
84
+ revalidated: verified.payload.tags,
85
+ orgId: verified.payload.orgId,
86
+ });
87
+ };
88
+ }
package/src/alpha.ts ADDED
@@ -0,0 +1,89 @@
1
+ /**
2
+ * `@businessdash/sdk/alpha` — legacy/deprecated schema API for backward compatibility.
3
+ *
4
+ * This entrypoint re-exports the original `data-model-schema` surface exactly as
5
+ * it was available from `@businessdash/sdk` prior to the `0.9` entrypoint split.
6
+ *
7
+ * Use it when migrating old codebases that rely on the deprecated API:
8
+ *
9
+ * ```ts
10
+ * // old: import { defineDataModel, defineField, defineObject } from "@businessdash/sdk"
11
+ * // new:
12
+ * import { defineDataModel, defineField, defineObject } from "@businessdash/sdk/alpha"
13
+ *
14
+ * // Or for the full legacy surface:
15
+ * import * as Alpha from "@businessdash/sdk/alpha"
16
+ * ```
17
+ *
18
+ * New projects should use `@businessdash/sdk/collections` or `@businessdash/sdk/forms` instead.
19
+ */
20
+
21
+ export {
22
+ type AddressDef,
23
+ type AllFormElements,
24
+ type BoundaryMetadata,
25
+ bd,
26
+ type ChoiceCardDef,
27
+ type CollectionDefinition,
28
+ type CollectionOptions,
29
+ collection,
30
+ computeDataModelChecksum,
31
+ createSchema,
32
+ type DataModelArtifact,
33
+ type DataModelClientShape,
34
+ type DataModelInput,
35
+ type DeleteAction,
36
+ type DynamicOptionsDef,
37
+ defineCollection,
38
+ defineDataModel,
39
+ defineField,
40
+ defineObject,
41
+ type ElementMetadata,
42
+ type EncryptionMode,
43
+ type ExtArrayType,
44
+ type ExtBooleanType,
45
+ type ExtNumberType,
46
+ type ExtObjectType,
47
+ type ExtractFieldPaths,
48
+ type ExtTextType,
49
+ FIELD_TYPES,
50
+ type FieldBuilder,
51
+ type FieldDefinition,
52
+ type FieldOptions,
53
+ type FieldSpec,
54
+ type Fields,
55
+ type FieldType,
56
+ type FileDef,
57
+ type FindFieldTypeByPath,
58
+ fields,
59
+ type InferJsType,
60
+ isFieldType,
61
+ isRelationFieldType,
62
+ type MeasurementCategory,
63
+ type MeasurementDef,
64
+ type ObjectDefinition,
65
+ type ObjectKind,
66
+ type ObjectPropertyDef,
67
+ type ObjectSchemaDef,
68
+ type ObjectVisibility,
69
+ objectVisibilityValues,
70
+ PREDEFINED_UNITS,
71
+ type PrimaryKeyType,
72
+ type RangeDef,
73
+ RELATION_FIELD_TYPES,
74
+ type RelationMetadata,
75
+ type RelationOnDelete,
76
+ type RequiredIfCondition,
77
+ type RlsPolicyConfig,
78
+ SchemaBoundary,
79
+ type SchemaBoundaryNode,
80
+ type SchemaOptions,
81
+ type SecureEvalRule,
82
+ type SelectOption,
83
+ type SpecialDateValue,
84
+ type StorageStrategy,
85
+ UNSUPPORTED_FIELD_TYPES,
86
+ type ValidationRules,
87
+ validateAndResolveMeasurement,
88
+ validateFieldValue,
89
+ } from "./data-model-schema.js";
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Framework-agnostic core for BIAB site analytics. The React
3
+ * component (`<BIABAnalytics />`) wraps this; Svelte/Qwik/Vue/
4
+ * vanilla-JS consumers call `initBiabAnalytics(opts)` directly
5
+ * from their framework's "on mount" hook and call the returned
6
+ * cleanup function in their "on unmount" hook.
7
+ *
8
+ * Same privacy posture as the React component:
9
+ * - No cookies, no localStorage, no third-party requests
10
+ * - Honours navigator.doNotTrack + globalPrivacyControl
11
+ * - Never sees the visitor's IP or UA — those are read
12
+ * server-side by the ingest endpoint and used only to
13
+ * derive country + device family + a daily-rotating
14
+ * anon-id hash that resets every UTC midnight.
15
+ */
16
+
17
+ export type InitBiabAnalyticsOptions = {
18
+ siteId: string;
19
+ baseUrl: string;
20
+ apiKey: string;
21
+ /** Defaults to true. Set false only if your privacy policy
22
+ * already commits to honouring DNT/GPC and you want to
23
+ * count those visitors. */
24
+ respectDnt?: boolean;
25
+ };
26
+
27
+ export type BiabAnalyticsTracker = {
28
+ /** Tear down the listeners. Safe to call multiple times. */
29
+ stop: () => void;
30
+ /** Fire a custom event. */
31
+ track: (name: string, opts?: { path?: string }) => void;
32
+ };
33
+
34
+ export function initBiabAnalytics(
35
+ options: InitBiabAnalyticsOptions,
36
+ ): BiabAnalyticsTracker {
37
+ if (typeof window === "undefined") {
38
+ return { stop: () => {}, track: () => {} };
39
+ }
40
+ const respectDnt = options.respectDnt ?? true;
41
+ if (respectDnt && shouldOptOut()) {
42
+ return { stop: () => {}, track: () => {} };
43
+ }
44
+
45
+ const endpoint = `${options.baseUrl.replace(/\/$/, "")}/sites/${encodeURIComponent(
46
+ options.siteId,
47
+ )}/analytics/events`;
48
+
49
+ let lastPath: string | null = null;
50
+ let lastEnterAt = 0;
51
+ let stopped = false;
52
+
53
+ const send = (
54
+ kind: "pageview" | "session_start" | "custom",
55
+ payload: {
56
+ path?: string;
57
+ referer?: string | null;
58
+ durationMs?: number;
59
+ customEventName?: string;
60
+ } = {},
61
+ ) => {
62
+ if (stopped) return;
63
+ const body = JSON.stringify({
64
+ kind,
65
+ path: payload.path ?? window.location.pathname,
66
+ referer:
67
+ payload.referer === undefined
68
+ ? document.referrer || null
69
+ : payload.referer,
70
+ ...(payload.durationMs != null ? { durationMs: payload.durationMs } : {}),
71
+ ...(payload.customEventName
72
+ ? { customEventName: payload.customEventName }
73
+ : {}),
74
+ });
75
+ const blob = new Blob([body], { type: "application/json" });
76
+ try {
77
+ if (
78
+ typeof navigator !== "undefined" &&
79
+ "sendBeacon" in navigator &&
80
+ navigator.sendBeacon(endpoint, blob)
81
+ ) {
82
+ return;
83
+ }
84
+ } catch {
85
+ /* fallthrough */
86
+ }
87
+ fetch(endpoint, {
88
+ method: "POST",
89
+ body,
90
+ headers: {
91
+ "Content-Type": "application/json",
92
+ Authorization: `Bearer ${options.apiKey}`,
93
+ },
94
+ keepalive: true,
95
+ }).catch(() => {
96
+ /* drop silently — analytics shouldn't break the page */
97
+ });
98
+ };
99
+
100
+ const trackPageview = (nextPath: string) => {
101
+ const now = Date.now();
102
+ if (lastPath && lastEnterAt > 0) {
103
+ const dur = now - lastEnterAt;
104
+ send("custom", {
105
+ path: lastPath,
106
+ durationMs: Math.max(0, Math.min(dur, 24 * 60 * 60 * 1000)),
107
+ customEventName: "pageview_duration",
108
+ });
109
+ }
110
+ lastPath = nextPath;
111
+ lastEnterAt = now;
112
+ send("pageview", { path: nextPath });
113
+ };
114
+
115
+ // Session start once per init.
116
+ send("session_start");
117
+ trackPageview(window.location.pathname);
118
+
119
+ const origPush = history.pushState;
120
+ const origReplace = history.replaceState;
121
+ history.pushState = function (...args: Parameters<typeof history.pushState>) {
122
+ const ret = origPush.apply(this, args);
123
+ queueMicrotask(() => trackPageview(window.location.pathname));
124
+ return ret;
125
+ };
126
+ history.replaceState = function (
127
+ ...args: Parameters<typeof history.replaceState>
128
+ ) {
129
+ const ret = origReplace.apply(this, args);
130
+ queueMicrotask(() => trackPageview(window.location.pathname));
131
+ return ret;
132
+ };
133
+ const onPop = () => trackPageview(window.location.pathname);
134
+ window.addEventListener("popstate", onPop);
135
+
136
+ const onVisibility = () => {
137
+ if (document.visibilityState !== "hidden") return;
138
+ if (!lastPath || lastEnterAt === 0) return;
139
+ const dur = Date.now() - lastEnterAt;
140
+ send("custom", {
141
+ path: lastPath,
142
+ durationMs: Math.max(0, Math.min(dur, 24 * 60 * 60 * 1000)),
143
+ customEventName: "pageview_duration",
144
+ });
145
+ };
146
+ document.addEventListener("visibilitychange", onVisibility);
147
+
148
+ return {
149
+ stop: () => {
150
+ if (stopped) return;
151
+ stopped = true;
152
+ history.pushState = origPush;
153
+ history.replaceState = origReplace;
154
+ window.removeEventListener("popstate", onPop);
155
+ document.removeEventListener("visibilitychange", onVisibility);
156
+ },
157
+ track: (name, opts) =>
158
+ send("custom", {
159
+ ...(opts?.path !== undefined ? { path: opts.path } : {}),
160
+ customEventName: name,
161
+ }),
162
+ };
163
+ }
164
+
165
+ function shouldOptOut(): boolean {
166
+ if (typeof navigator === "undefined") return false;
167
+ const dnt =
168
+ (navigator as Navigator & { doNotTrack?: string }).doNotTrack ??
169
+ (window as Window & { doNotTrack?: string }).doNotTrack;
170
+ if (dnt === "1" || dnt === "yes") return true;
171
+ const gpc = (navigator as Navigator & { globalPrivacyControl?: boolean })
172
+ .globalPrivacyControl;
173
+ if (gpc === true) return true;
174
+ return false;
175
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Server-side analytics reporting — the half the browser tracker can't do.
3
+ *
4
+ * AI crawlers (GPTBot, ClaudeBot, PerplexityBot, …) fetch your HTML without
5
+ * executing JavaScript, so `<BIABAnalytics />` never sees them. Your server
6
+ * does. Call `reportAiCrawlerHit` from your middleware / request handler and
7
+ * BIAB records which pages the answer engines actually read — first-party
8
+ * AEO visibility, per page, per crawler.
9
+ *
10
+ * Next.js example (middleware.ts):
11
+ *
12
+ * ```ts
13
+ * import { isAiCrawlerUserAgent, reportAiCrawlerHit } from "@businessdash/sdk/analytics-server";
14
+ *
15
+ * export function middleware(request: Request) {
16
+ * const ua = request.headers.get("user-agent");
17
+ * if (isAiCrawlerUserAgent(ua)) {
18
+ * // Fire-and-forget — never block or fail the crawler's request.
19
+ * void reportAiCrawlerHit({
20
+ * siteId: process.env.BIAB_SITE_ID!,
21
+ * baseUrl: process.env.NEXT_PUBLIC_BIAB_API_URL!,
22
+ * apiKey: process.env.NEXT_PUBLIC_BIAB_PUBLISHABLE_KEY!,
23
+ * userAgent: ua,
24
+ * path: new URL(request.url).pathname,
25
+ * });
26
+ * }
27
+ * }
28
+ * ```
29
+ *
30
+ * Abuse posture: the ingest endpoint accepts a forwarded user-agent ONLY
31
+ * when it matches a known AI crawler — a forwarded human UA is dropped
32
+ * server-side, so this path can record crawler visibility but can never
33
+ * inflate the site's human visitor counts. If this local pattern list ever
34
+ * lags the platform's, the result is under-reporting, never bad data.
35
+ */
36
+
37
+ /**
38
+ * Cheap prefilter mirroring the platform's AI-crawler classifier, so your
39
+ * middleware only spends a network call on requests that will be kept.
40
+ * The platform's list is authoritative — this one just saves the round trip.
41
+ */
42
+ const AI_CRAWLER_UA_PATTERN =
43
+ /GPTBot|OAI-SearchBot|ChatGPT-User|ClaudeBot|Claude-User|Claude-SearchBot|Claude-Web|anthropic-ai|PerplexityBot|Perplexity-User|GrokBot|xAI-Crawler|Google-CloudVertexBot|GoogleOther|Applebot-Extended|meta-externalagent|Bytespider|CCBot|Amazonbot|cohere-ai|cohere-training-data-crawler|MistralAI-User|DuckAssistBot|YouBot|AI2Bot/i;
44
+
45
+ export function isAiCrawlerUserAgent(
46
+ userAgent: string | null | undefined,
47
+ ): boolean {
48
+ return userAgent != null && AI_CRAWLER_UA_PATTERN.test(userAgent);
49
+ }
50
+
51
+ export type ReportAiCrawlerHitOptions = {
52
+ siteId: string;
53
+ /** Package-API base URL, e.g. "https://www.biab.app/api/package/v1". */
54
+ baseUrl: string;
55
+ /** Publishable key — same one `<BIABAnalytics />` uses. */
56
+ apiKey: string;
57
+ /** The crawler request's user-agent, verbatim. */
58
+ userAgent: string;
59
+ /** The path the crawler fetched, e.g. "/pricing". */
60
+ path: string;
61
+ };
62
+
63
+ /**
64
+ * Report one crawler fetch. Resolves quietly on every outcome — analytics
65
+ * must never break page serving — and returns whether the platform accepted
66
+ * the event (false for non-crawler UAs, network failures, etc.).
67
+ */
68
+ export async function reportAiCrawlerHit(
69
+ options: ReportAiCrawlerHitOptions,
70
+ ): Promise<boolean> {
71
+ const endpoint = `${options.baseUrl.replace(/\/$/, "")}/sites/${encodeURIComponent(
72
+ options.siteId,
73
+ )}/analytics/events`;
74
+ try {
75
+ const res = await fetch(endpoint, {
76
+ method: "POST",
77
+ headers: {
78
+ "Content-Type": "application/json",
79
+ Authorization: `Bearer ${options.apiKey}`,
80
+ },
81
+ body: JSON.stringify({
82
+ kind: "pageview",
83
+ path: options.path,
84
+ referer: null,
85
+ visitorUserAgent: options.userAgent,
86
+ }),
87
+ // Middleware runtimes kill slow side-requests anyway; keepalive
88
+ // lets the report outlive the response where supported.
89
+ keepalive: true,
90
+ });
91
+ if (!res.ok) return false;
92
+ const body = (await res.json().catch(() => null)) as {
93
+ accepted?: boolean;
94
+ } | null;
95
+ return body?.accepted === true;
96
+ } catch {
97
+ return false;
98
+ }
99
+ }