@businessdash/sdk 0.9.60 → 0.9.80

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 (239) hide show
  1. package/README.md +991 -295
  2. package/assets/biab-sw.js +92 -0
  3. package/dist/account-core/index.d.ts +126 -0
  4. package/dist/account-core/index.d.ts.map +1 -0
  5. package/dist/account-core/index.js +191 -0
  6. package/dist/account-core/index.js.map +1 -0
  7. package/dist/account.d.ts +11 -0
  8. package/dist/account.d.ts.map +1 -0
  9. package/dist/account.js +11 -0
  10. package/dist/account.js.map +1 -0
  11. package/dist/auth-handler.d.ts +1 -1
  12. package/dist/auth-links.d.ts +33 -0
  13. package/dist/auth-links.d.ts.map +1 -0
  14. package/dist/auth-links.js +64 -0
  15. package/dist/auth-links.js.map +1 -0
  16. package/dist/blog-core/index.d.ts +112 -0
  17. package/dist/blog-core/index.d.ts.map +1 -0
  18. package/dist/blog-core/index.js +330 -0
  19. package/dist/blog-core/index.js.map +1 -0
  20. package/dist/blog.d.ts +11 -0
  21. package/dist/blog.d.ts.map +1 -0
  22. package/dist/blog.js +11 -0
  23. package/dist/blog.js.map +1 -0
  24. package/dist/chat-core/index.d.ts +97 -0
  25. package/dist/chat-core/index.d.ts.map +1 -0
  26. package/dist/chat-core/index.js +237 -0
  27. package/dist/chat-core/index.js.map +1 -0
  28. package/dist/chat.d.ts +11 -0
  29. package/dist/chat.d.ts.map +1 -0
  30. package/dist/chat.js +11 -0
  31. package/dist/chat.js.map +1 -0
  32. package/dist/checkout-core/index.d.ts +65 -0
  33. package/dist/checkout-core/index.d.ts.map +1 -0
  34. package/dist/checkout-core/index.js +159 -0
  35. package/dist/checkout-core/index.js.map +1 -0
  36. package/dist/checkout.d.ts +10 -0
  37. package/dist/checkout.d.ts.map +1 -0
  38. package/dist/checkout.js +10 -0
  39. package/dist/checkout.js.map +1 -0
  40. package/dist/cli.js +133 -25
  41. package/dist/cli.js.map +1 -1
  42. package/dist/client.d.ts +622 -1
  43. package/dist/client.d.ts.map +1 -1
  44. package/dist/client.js +888 -1
  45. package/dist/client.js.map +1 -1
  46. package/dist/consent-core/index.cjs +107 -0
  47. package/dist/consent-core/index.d.ts +103 -0
  48. package/dist/consent-core/index.d.ts.map +1 -0
  49. package/dist/consent-core/index.js +157 -0
  50. package/dist/consent-core/index.js.map +1 -0
  51. package/dist/contracts.d.ts +3526 -767
  52. package/dist/contracts.d.ts.map +1 -1
  53. package/dist/contracts.js +571 -4
  54. package/dist/contracts.js.map +1 -1
  55. package/dist/data-model-schema.d.ts +1 -1
  56. package/dist/data-model-schema.d.ts.map +1 -1
  57. package/dist/element.d.ts +30 -0
  58. package/dist/element.d.ts.map +1 -1
  59. package/dist/element.js +56 -0
  60. package/dist/element.js.map +1 -1
  61. package/dist/embed-protocol.d.ts +86 -0
  62. package/dist/embed-protocol.d.ts.map +1 -0
  63. package/dist/embed-protocol.js +60 -0
  64. package/dist/embed-protocol.js.map +1 -0
  65. package/dist/framework-support.d.ts +122 -0
  66. package/dist/framework-support.d.ts.map +1 -0
  67. package/dist/framework-support.js +323 -0
  68. package/dist/framework-support.js.map +1 -0
  69. package/dist/index.cjs +1355 -24
  70. package/dist/legal-core/index.cjs +115 -0
  71. package/dist/legal-core/index.d.ts +160 -0
  72. package/dist/legal-core/index.d.ts.map +1 -0
  73. package/dist/legal-core/index.js +220 -0
  74. package/dist/legal-core/index.js.map +1 -0
  75. package/dist/marketing-core/index.d.ts +66 -0
  76. package/dist/marketing-core/index.d.ts.map +1 -0
  77. package/dist/marketing-core/index.js +154 -0
  78. package/dist/marketing-core/index.js.map +1 -0
  79. package/dist/marketing.d.ts +7 -0
  80. package/dist/marketing.d.ts.map +1 -0
  81. package/dist/marketing.js +7 -0
  82. package/dist/marketing.js.map +1 -0
  83. package/dist/mcp-adapters/index.d.ts +135 -0
  84. package/dist/mcp-adapters/index.d.ts.map +1 -0
  85. package/dist/mcp-adapters/index.js +187 -0
  86. package/dist/mcp-adapters/index.js.map +1 -0
  87. package/dist/mcp-adapters.d.ts +7 -0
  88. package/dist/mcp-adapters.d.ts.map +1 -0
  89. package/dist/mcp-adapters.js +7 -0
  90. package/dist/mcp-adapters.js.map +1 -0
  91. package/dist/model3d-core/index.cjs +95 -0
  92. package/dist/model3d-core/index.d.ts +167 -0
  93. package/dist/model3d-core/index.d.ts.map +1 -0
  94. package/dist/model3d-core/index.js +158 -0
  95. package/dist/model3d-core/index.js.map +1 -0
  96. package/dist/notifications-core/index.cjs +315 -0
  97. package/dist/notifications-core/index.d.ts +229 -0
  98. package/dist/notifications-core/index.d.ts.map +1 -0
  99. package/dist/notifications-core/index.js +445 -0
  100. package/dist/notifications-core/index.js.map +1 -0
  101. package/dist/portal-core/index.d.ts +451 -0
  102. package/dist/portal-core/index.d.ts.map +1 -0
  103. package/dist/portal-core/index.js +819 -0
  104. package/dist/portal-core/index.js.map +1 -0
  105. package/dist/portal.d.ts +7 -0
  106. package/dist/portal.d.ts.map +1 -0
  107. package/dist/portal.js +7 -0
  108. package/dist/portal.js.map +1 -0
  109. package/dist/push-core/index.cjs +171 -0
  110. package/dist/push-core/index.d.ts +149 -0
  111. package/dist/push-core/index.d.ts.map +1 -0
  112. package/dist/push-core/index.js +231 -0
  113. package/dist/push-core/index.js.map +1 -0
  114. package/dist/react-marketing.d.ts +1 -17
  115. package/dist/react-marketing.d.ts.map +1 -1
  116. package/dist/react-marketing.js +4 -0
  117. package/dist/react-marketing.js.map +1 -1
  118. package/dist/react.d.ts +294 -101
  119. package/dist/react.d.ts.map +1 -1
  120. package/dist/react.js +302 -246
  121. package/dist/react.js.map +1 -1
  122. package/dist/seed-core/index.d.ts +354 -0
  123. package/dist/seed-core/index.d.ts.map +1 -0
  124. package/dist/seed-core/index.js +420 -0
  125. package/dist/seed-core/index.js.map +1 -0
  126. package/dist/seed.d.ts +7 -0
  127. package/dist/seed.d.ts.map +1 -0
  128. package/dist/seed.js +7 -0
  129. package/dist/seed.js.map +1 -0
  130. package/dist/seo-core/blog.d.ts +94 -0
  131. package/dist/seo-core/blog.d.ts.map +1 -0
  132. package/dist/seo-core/blog.js +149 -0
  133. package/dist/seo-core/blog.js.map +1 -0
  134. package/dist/seo-core/commerce.d.ts +64 -0
  135. package/dist/seo-core/commerce.d.ts.map +1 -0
  136. package/dist/seo-core/commerce.js +87 -0
  137. package/dist/seo-core/commerce.js.map +1 -0
  138. package/dist/seo-core/index.cjs +751 -0
  139. package/dist/seo-core/index.d.ts +226 -0
  140. package/dist/seo-core/index.d.ts.map +1 -0
  141. package/dist/seo-core/index.js +455 -0
  142. package/dist/seo-core/index.js.map +1 -0
  143. package/dist/seo-core/local.d.ts +181 -0
  144. package/dist/seo-core/local.d.ts.map +1 -0
  145. package/dist/seo-core/local.js +193 -0
  146. package/dist/seo-core/local.js.map +1 -0
  147. package/dist/sitemap-core/index.cjs +167 -0
  148. package/dist/sitemap-core/index.d.ts +155 -0
  149. package/dist/sitemap-core/index.d.ts.map +1 -0
  150. package/dist/sitemap-core/index.js +195 -0
  151. package/dist/sitemap-core/index.js.map +1 -0
  152. package/dist/social-core/index.d.ts +74 -0
  153. package/dist/social-core/index.d.ts.map +1 -0
  154. package/dist/social-core/index.js +72 -0
  155. package/dist/social-core/index.js.map +1 -0
  156. package/dist/social.d.ts +7 -0
  157. package/dist/social.d.ts.map +1 -0
  158. package/dist/social.js +7 -0
  159. package/dist/social.js.map +1 -0
  160. package/dist/solid-compat.d.ts +204 -0
  161. package/dist/solid-compat.d.ts.map +1 -0
  162. package/dist/solid-compat.js +221 -0
  163. package/dist/solid-compat.js.map +1 -0
  164. package/dist/store-core/index.d.ts +141 -0
  165. package/dist/store-core/index.d.ts.map +1 -0
  166. package/dist/store-core/index.js +277 -0
  167. package/dist/store-core/index.js.map +1 -0
  168. package/dist/store.d.ts +12 -0
  169. package/dist/store.d.ts.map +1 -0
  170. package/dist/store.js +12 -0
  171. package/dist/store.js.map +1 -0
  172. package/dist/vanilla.d.ts +111 -0
  173. package/dist/vanilla.d.ts.map +1 -1
  174. package/dist/vanilla.js +206 -0
  175. package/dist/vanilla.js.map +1 -1
  176. package/dist/verify-core/index.d.ts +98 -0
  177. package/dist/verify-core/index.d.ts.map +1 -0
  178. package/dist/verify-core/index.js +186 -0
  179. package/dist/verify-core/index.js.map +1 -0
  180. package/dist/verify.d.ts +8 -0
  181. package/dist/verify.d.ts.map +1 -0
  182. package/dist/verify.js +8 -0
  183. package/dist/verify.js.map +1 -0
  184. package/openapi.json +4516 -1311
  185. package/package.json +128 -11
  186. package/src/account-core/index.ts +309 -0
  187. package/src/account.ts +11 -0
  188. package/src/angular/headless.ts +519 -0
  189. package/src/angular/index.ts +3 -0
  190. package/src/auth-links.ts +76 -0
  191. package/src/blog-core/index.ts +423 -0
  192. package/src/blog.ts +11 -0
  193. package/src/chat-core/index.ts +335 -0
  194. package/src/chat.ts +11 -0
  195. package/src/checkout-core/index.ts +225 -0
  196. package/src/checkout.ts +10 -0
  197. package/src/cli.ts +184 -28
  198. package/src/client.ts +1097 -0
  199. package/src/consent-core/index.ts +213 -0
  200. package/src/contracts.ts +768 -11
  201. package/src/data-model-schema.ts +1 -1
  202. package/src/element.ts +102 -0
  203. package/src/embed-protocol.ts +100 -0
  204. package/src/framework-support.ts +440 -0
  205. package/src/legal-core/index.ts +276 -0
  206. package/src/marketing-core/index.ts +209 -0
  207. package/src/marketing.ts +7 -0
  208. package/src/mcp-adapters/index.ts +264 -0
  209. package/src/mcp-adapters.ts +7 -0
  210. package/src/model3d-core/index.ts +248 -0
  211. package/src/notifications-core/index.ts +650 -0
  212. package/src/portal-core/index.ts +1564 -0
  213. package/src/portal.ts +7 -0
  214. package/src/push-core/index.ts +335 -0
  215. package/src/qwik.tsx +602 -2
  216. package/src/react-marketing.tsx +5 -0
  217. package/src/react.tsx +434 -319
  218. package/src/seed-core/index.ts +735 -0
  219. package/src/seed.ts +7 -0
  220. package/src/seo-core/blog.ts +216 -0
  221. package/src/seo-core/commerce.ts +138 -0
  222. package/src/seo-core/index.ts +605 -0
  223. package/src/seo-core/local.ts +333 -0
  224. package/src/sitemap-core/index.ts +296 -0
  225. package/src/social-core/index.ts +103 -0
  226. package/src/social.ts +7 -0
  227. package/src/solid-compat.tsx +347 -0
  228. package/src/solid-surfaces.tsx +1311 -0
  229. package/src/solid.tsx +82 -60
  230. package/src/store-core/index.ts +426 -0
  231. package/src/store.ts +12 -0
  232. package/src/svelte/SocialLinks.svelte +84 -0
  233. package/src/svelte/headless.ts +435 -0
  234. package/src/svelte/index.ts +9 -0
  235. package/src/vanilla.ts +367 -0
  236. package/src/verify-core/index.ts +288 -0
  237. package/src/verify.ts +8 -0
  238. package/src/vue/headless.ts +527 -0
  239. package/src/vue/index.ts +3 -0
@@ -0,0 +1,420 @@
1
+ /**
2
+ * `@businessdash/sdk/seed` — define a schema, push it, and seed data, from any
3
+ * framework's build step.
4
+ *
5
+ * ## Why this exists alongside the CLI
6
+ *
7
+ * `businessdash sync-data-model` and friends already do this, and they are the
8
+ * right tool at a terminal. They are the wrong tool everywhere else: a Nuxt
9
+ * module, a SvelteKit prerender hook, an Angular builder, a Vite plugin, a
10
+ * Next `instrumentation.ts` or a CI step that already has the credentials
11
+ * loaded cannot shell out to an interactive command and read its output.
12
+ *
13
+ * So the same operations are exposed as plain async functions. Nothing here is
14
+ * framework-specific, because seeding happens at BUILD time — there is no
15
+ * reactivity to bridge, only an integration point per framework, and every
16
+ * framework has one that can call a function.
17
+ *
18
+ * The CLI imports this module rather than the other way round, so there is one
19
+ * implementation of the transport, the auth header and the error handling.
20
+ *
21
+ * ## What can and cannot be seeded
22
+ *
23
+ * The package API decides this, not the SDK:
24
+ *
25
+ * | Target | Seedable | Endpoint |
26
+ * |-----------------------|----------|----------|
27
+ * | Custom-database schema| yes | `data-model/plan` + `draft-schema` |
28
+ * | Custom-database records| yes | `data-model/records` |
29
+ * | Static collections | yes | `collections`, `collections/{slug}/rows` |
30
+ * | Coupons | yes | `coupons` |
31
+ * | Products (+ variants) | yes | `storefront/products` |
32
+ * | Blog posts | yes | `blog/posts` |
33
+ *
34
+ * Products and blog posts were absent from the first version of this module
35
+ * because the package API had no create route for either — the dashboard could
36
+ * do it and the SDK could not. Both routes now exist, so a site can be seeded
37
+ * whole: schema, records, collections, catalogue, content and coupons.
38
+ *
39
+ * ## Pushing a schema does not apply it
40
+ *
41
+ * `pushDataModel` writes the DRAFT slot and returns the plan describing what
42
+ * promoting it would do. Promotion is a separate, deliberate step in the
43
+ * dashboard. That is the platform's design and this module does not route
44
+ * around it: an automated deploy that silently altered a live customer
45
+ * database would be the wrong default.
46
+ *
47
+ * @module
48
+ */
49
+ function normalizeBaseUrl(raw) {
50
+ return raw.replace(/\/+$/, "");
51
+ }
52
+ /**
53
+ * One request to the package API, shared by every function here AND by the CLI.
54
+ *
55
+ * Errors carry the server's own message when it sent one. A seeder that failed
56
+ * with `HTTP 403` and nothing else would send someone hunting through their
57
+ * own code for a problem the API already described.
58
+ */
59
+ export async function callPackageApi(target, input) {
60
+ const url = `${normalizeBaseUrl(target.baseUrl)}/${input.path}`;
61
+ const res = await fetch(url, {
62
+ method: input.method,
63
+ headers: {
64
+ "content-type": "application/json",
65
+ authorization: `Bearer ${target.apiKey}`,
66
+ },
67
+ ...(input.body !== undefined ? { body: JSON.stringify(input.body) } : {}),
68
+ });
69
+ const text = await res.text();
70
+ let parsed = null;
71
+ try {
72
+ parsed = JSON.parse(text);
73
+ }
74
+ catch {
75
+ parsed = null;
76
+ }
77
+ if (!res.ok) {
78
+ const message = typeof parsed?.message === "string"
79
+ ? parsed.message
80
+ : `HTTP ${res.status} ${res.statusText} — ${text.slice(0, 240)}`;
81
+ throw new Error(`${input.method} ${input.path}: ${message}`);
82
+ }
83
+ if (!parsed) {
84
+ throw new Error(`${input.method} ${input.path}: server replied ${res.status} but the body wasn't JSON — first 240 chars: ${text.slice(0, 240)}`);
85
+ }
86
+ return parsed;
87
+ }
88
+ /** Data-model routes are all under the site's data-model namespace. */
89
+ function dataModelPath(target, suffix) {
90
+ return `sites/${encodeURIComponent(target.siteId)}/data-model/${suffix}`;
91
+ }
92
+ /**
93
+ * Plan, then push a schema into the DRAFT slot.
94
+ *
95
+ * The plan is always computed, even when pushing, because a push whose
96
+ * consequences nobody looked at is how a destructive migration reaches a live
97
+ * database. The returned `plan.changes` carry a `class` — `safe`, `backfill`,
98
+ * `destructive` or `exposure` — which is what a CI gate should branch on.
99
+ */
100
+ export async function pushDataModel(target, schema, options = {}) {
101
+ const planRes = await callPackageApi(target, {
102
+ path: dataModelPath(target, "plan"),
103
+ method: "POST",
104
+ body: { schema, prune: options.prune ?? false },
105
+ });
106
+ const plan = (planRes.plan ?? { changes: [] });
107
+ if (options.dryRun) {
108
+ return { plan, version: null, noop: false, planOnly: true };
109
+ }
110
+ const res = await callPackageApi(target, {
111
+ path: dataModelPath(target, "draft-schema"),
112
+ method: "POST",
113
+ body: {
114
+ schema,
115
+ ...(options.checksum ? { checksum: options.checksum } : {}),
116
+ note: options.note ?? null,
117
+ },
118
+ });
119
+ return {
120
+ plan,
121
+ version: typeof res.version === "number" ? res.version : null,
122
+ noop: res.noop === true,
123
+ planOnly: false,
124
+ };
125
+ }
126
+ /** Does this plan contain anything that would lose or expose data? */
127
+ export function planHasDangerousChanges(plan) {
128
+ return (plan.changes ?? []).some((c) => c.class === "destructive" || c.class === "exposure");
129
+ }
130
+ /**
131
+ * Seed rows into the CUSTOM DATABASE (the metadata engine).
132
+ *
133
+ * This is not the same store as `seedCollectionRows` below. The custom database
134
+ * is the schema you defined and promoted; static collections are a simpler
135
+ * key/value-ish store on the site. Mixing them up is easy and the failure is
136
+ * silent — the rows land somewhere real, just not where they were wanted — so
137
+ * the two functions are named for the store rather than for the verb.
138
+ */
139
+ export async function seedRecords(target, records) {
140
+ const res = await callPackageApi(target, {
141
+ path: dataModelPath(target, "records"),
142
+ method: "POST",
143
+ body: { records },
144
+ });
145
+ const written = (res.written ?? {});
146
+ return { written };
147
+ }
148
+ /** Create a STATIC collection on the site. Idempotent by slug server-side. */
149
+ export async function seedCollection(target, definition) {
150
+ return callPackageApi(target, {
151
+ path: `sites/${encodeURIComponent(target.siteId)}/collections`,
152
+ method: "POST",
153
+ body: definition,
154
+ });
155
+ }
156
+ /**
157
+ * Insert rows into a static collection.
158
+ *
159
+ * Rows go one request each because the route takes one row — batching would
160
+ * mean inventing a bulk endpoint that does not exist. `concurrency` keeps a
161
+ * large seed from opening hundreds of sockets at once.
162
+ */
163
+ export async function seedCollectionRows(target, slug, rows, options = {}) {
164
+ const concurrency = Math.max(1, options.concurrency ?? 4);
165
+ const path = `sites/${encodeURIComponent(target.siteId)}/collections/${encodeURIComponent(slug)}/rows`;
166
+ let written = 0;
167
+ for (let i = 0; i < rows.length; i += concurrency) {
168
+ const batch = rows.slice(i, i + concurrency);
169
+ await Promise.all(batch.map(async (row) => {
170
+ await callPackageApi(target, { path, method: "POST", body: row });
171
+ written += 1;
172
+ }));
173
+ }
174
+ return { written };
175
+ }
176
+ /**
177
+ * Create products, each with its variants and cross-variants.
178
+ *
179
+ * The whole tree goes in ONE request per product, because the route writes it
180
+ * in a transaction — a seed that created a product and then failed partway
181
+ * through its variants would leave a catalogue nobody could trust.
182
+ *
183
+ * Products land unpublished unless `isLive` says otherwise, and are NOT pushed
184
+ * to Stripe: that is a separate deliberate call, because it mints objects in an
185
+ * account the org is billed against.
186
+ */
187
+ export async function seedProducts(target, products) {
188
+ const results = [];
189
+ for (const product of products) {
190
+ const res = await callPackageApi(target, {
191
+ path: "storefront/products",
192
+ method: "POST",
193
+ body: product,
194
+ });
195
+ results.push({
196
+ name: product.name,
197
+ id: String(res.id ?? ""),
198
+ variantCount: Number(res.variantCount ?? 0),
199
+ crossVariantCount: Number(res.crossVariantCount ?? 0),
200
+ });
201
+ }
202
+ return results;
203
+ }
204
+ /**
205
+ * Create blog posts.
206
+ *
207
+ * An existing slug is REPORTED rather than thrown, on the same reasoning as
208
+ * coupons: re-running a seed must be safe, and a conflict on the third post
209
+ * must not abandon the remaining seven.
210
+ */
211
+ export async function seedBlogPosts(target, posts) {
212
+ const results = [];
213
+ for (const post of posts) {
214
+ try {
215
+ const res = await callPackageApi(target, {
216
+ path: "blog/posts",
217
+ method: "POST",
218
+ body: post,
219
+ });
220
+ results.push({
221
+ slug: post.slug,
222
+ created: true,
223
+ published: res.published === true,
224
+ });
225
+ }
226
+ catch (cause) {
227
+ const message = cause instanceof Error ? cause.message : String(cause);
228
+ if (/already exists|conflict/i.test(message)) {
229
+ results.push({
230
+ slug: post.slug,
231
+ created: false,
232
+ published: false,
233
+ message: "already exists — left alone",
234
+ });
235
+ continue;
236
+ }
237
+ throw cause;
238
+ }
239
+ }
240
+ return results;
241
+ }
242
+ /**
243
+ * Create coupons in the org's own Stripe account as well as locally.
244
+ *
245
+ * An existing code is REPORTED, not treated as a failure: re-running a seed
246
+ * should be safe, and a 409 on the third of ten coupons must not abandon the
247
+ * remaining seven. Anything else still throws — a bad key or a malformed
248
+ * coupon is a real problem and swallowing it would leave a half-seeded store
249
+ * looking successful.
250
+ */
251
+ export async function seedCoupons(target, coupons) {
252
+ const results = [];
253
+ for (const coupon of coupons) {
254
+ try {
255
+ const res = await callPackageApi(target, {
256
+ path: "coupons",
257
+ method: "POST",
258
+ body: {
259
+ ...coupon,
260
+ ...(coupon.validFrom
261
+ ? {
262
+ validFrom: coupon.validFrom instanceof Date
263
+ ? coupon.validFrom.toISOString()
264
+ : coupon.validFrom,
265
+ }
266
+ : {}),
267
+ ...(coupon.validUntil
268
+ ? {
269
+ validUntil: coupon.validUntil instanceof Date
270
+ ? coupon.validUntil.toISOString()
271
+ : coupon.validUntil,
272
+ }
273
+ : {}),
274
+ },
275
+ });
276
+ results.push({
277
+ code: coupon.code,
278
+ created: true,
279
+ stripeSynced: res.stripeSynced === true,
280
+ ...(typeof res.stripeError === "string" && res.stripeError
281
+ ? { message: res.stripeError }
282
+ : {}),
283
+ });
284
+ }
285
+ catch (cause) {
286
+ const message = cause instanceof Error ? cause.message : String(cause);
287
+ // The route answers 409 for a code that already exists.
288
+ if (/already exists|conflict/i.test(message)) {
289
+ results.push({
290
+ code: coupon.code,
291
+ created: false,
292
+ stripeSynced: false,
293
+ message: "already exists — left alone",
294
+ });
295
+ continue;
296
+ }
297
+ throw cause;
298
+ }
299
+ }
300
+ return results;
301
+ }
302
+ /**
303
+ * Run a whole seed, in dependency order: schema first, then the records that
304
+ * depend on it, then static collections, then products, posts and coupons.
305
+ *
306
+ * Order matters and is not configurable — seeding records into a collection
307
+ * whose schema has not been promoted yet fails in a way that reads as a
308
+ * permissions problem.
309
+ */
310
+ export async function runSeed(target, seed, options = {}) {
311
+ const log = options.onProgress ?? (() => { });
312
+ const failOnDangerous = options.failOnDangerousPlan ?? true;
313
+ const result = {};
314
+ if (seed.dataModel) {
315
+ // `DataModelArtifact` is a Record, so `"toJSONSchema" in x` narrows the
316
+ // union to the record branch rather than the schema branch — the property
317
+ // check has to be on the VALUE being callable, not on the key existing.
318
+ const candidate = seed.dataModel;
319
+ const artifact = typeof candidate.toJSONSchema === "function"
320
+ ? candidate.toJSONSchema()
321
+ : seed.dataModel;
322
+ log("Pushing data model…");
323
+ const pushed = await pushDataModel(target, artifact, seed.dataModelOptions);
324
+ result.dataModel = pushed;
325
+ if (failOnDangerous && planHasDangerousChanges(pushed.plan)) {
326
+ const summary = pushed.plan.changes
327
+ .filter((c) => c.class === "destructive" || c.class === "exposure")
328
+ .map((c) => ` ${c.class}: ${c.summary}`)
329
+ .join("\n");
330
+ throw new Error(`The schema plan contains changes that would lose or expose data:\n${summary}\n\nThe draft was ${pushed.planOnly ? "not uploaded" : "uploaded but NOT promoted"}. Review and promote it deliberately, or pass \`failOnDangerousPlan: false\` if you have already decided.`);
331
+ }
332
+ log(pushed.planOnly
333
+ ? "Plan only — nothing uploaded."
334
+ : pushed.noop
335
+ ? "Data model unchanged."
336
+ : `Draft v${pushed.version} uploaded (promote it in the dashboard to apply).`);
337
+ }
338
+ if (seed.records) {
339
+ log("Seeding custom-database records…");
340
+ result.records = await seedRecords(target, seed.records);
341
+ const total = Object.values(result.records.written).reduce((a, b) => a + b, 0);
342
+ log(`Wrote ${total} record(s).`);
343
+ }
344
+ if (seed.collections?.length) {
345
+ result.collections = [];
346
+ for (const definition of seed.collections) {
347
+ const { rows, ...collectionInput } = definition;
348
+ log(`Creating static collection "${collectionInput.name}"…`);
349
+ const created = await seedCollection(target, collectionInput);
350
+ const slug = (typeof created.slug === "string" ? created.slug : undefined) ??
351
+ collectionInput.slug ??
352
+ collectionInput.name;
353
+ let rowsWritten = 0;
354
+ if (rows?.length) {
355
+ rowsWritten = (await seedCollectionRows(target, slug, rows)).written;
356
+ log(` ${rowsWritten} row(s).`);
357
+ }
358
+ result.collections.push({ slug, rowsWritten });
359
+ }
360
+ }
361
+ if (seed.products?.length) {
362
+ log(`Seeding ${seed.products.length} product(s)…`);
363
+ result.products = await seedProducts(target, seed.products);
364
+ const variants = result.products.reduce((a, p) => a + p.variantCount, 0);
365
+ log(`${result.products.length} product(s), ${variants} variant(s).`);
366
+ }
367
+ if (seed.posts?.length) {
368
+ log(`Seeding ${seed.posts.length} blog post(s)…`);
369
+ result.posts = await seedBlogPosts(target, seed.posts);
370
+ const created = result.posts.filter((p) => p.created).length;
371
+ log(`${created} created, ${result.posts.length - created} already existed.`);
372
+ }
373
+ if (seed.coupons?.length) {
374
+ log(`Seeding ${seed.coupons.length} coupon(s)…`);
375
+ result.coupons = await seedCoupons(target, seed.coupons);
376
+ const created = result.coupons.filter((c) => c.created).length;
377
+ log(`${created} created, ${result.coupons.length - created} already existed.`);
378
+ }
379
+ return result;
380
+ }
381
+ /**
382
+ * Read a seed target from environment variables.
383
+ *
384
+ * The names match what the CLI already reads, so a project that has the CLI
385
+ * working needs no new configuration to call these functions from a build step.
386
+ */
387
+ export function seedTargetFromEnv(env = typeof process === "undefined"
388
+ ? {}
389
+ : process.env) {
390
+ // BIAB_API_KEY first, because that is the name the CLI reads and the name
391
+ // every starter's .env.example sets. Reading a different name would mean a
392
+ // project whose CLI works fine still fails here, with an error naming a
393
+ // variable the consumer has never seen.
394
+ const apiKey = env.BIAB_API_KEY ?? env.BUSINESSDASH_API_KEY ?? env.BIAB_PACKAGE_API_KEY;
395
+ const siteId = env.BIAB_SITE_ID ?? env.BUSINESSDASH_SITE_ID;
396
+ const baseUrl = env.BIAB_PACKAGE_API_BASE_URL ??
397
+ env.BUSINESSDASH_API_BASE_URL ??
398
+ env.NEXT_PUBLIC_BIAB_PACKAGE_API_BASE_URL;
399
+ const missing = [
400
+ !apiKey && "BIAB_API_KEY",
401
+ !siteId && "BIAB_SITE_ID",
402
+ !baseUrl && "BIAB_PACKAGE_API_BASE_URL",
403
+ ].filter(Boolean);
404
+ if (missing.length > 0) {
405
+ throw new Error(`Missing ${missing.join(", ")}. Seeding needs a package API key, a site id and the API base URL — the same three the CLI reads from .env.local.`);
406
+ }
407
+ return {
408
+ apiKey: apiKey,
409
+ siteId: siteId,
410
+ baseUrl: baseUrl,
411
+ };
412
+ }
413
+ /**
414
+ * Type-only helper for a `businessdash.seed.ts`, so a config file gets
415
+ * completion and checking without importing anything at runtime.
416
+ */
417
+ export function defineSeed(seed) {
418
+ return seed;
419
+ }
420
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/seed-core/index.ts"],"names":[],"mappings":"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"}
package/dist/seed.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * `@businessdash/sdk/seed` — schema push and data seeding from any build step.
3
+ *
4
+ * @module
5
+ */
6
+ export * from "./seed-core/index.js";
7
+ //# sourceMappingURL=seed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../src/seed.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,sBAAsB,CAAC"}
package/dist/seed.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * `@businessdash/sdk/seed` — schema push and data seeding from any build step.
3
+ *
4
+ * @module
5
+ */
6
+ export * from "./seed-core/index.js";
7
+ //# sourceMappingURL=seed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seed.js","sourceRoot":"","sources":["../src/seed.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,sBAAsB,CAAC"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * SEO for blog posts and blog listings.
3
+ *
4
+ * ## Why a post needs more than a title
5
+ *
6
+ * A `BlogPosting` node is what turns a link in search results into a dated,
7
+ * attributed article card. Without it a post competes as a bare URL, and the
8
+ * publish date — the thing readers use to decide whether it is still true —
9
+ * never appears.
10
+ *
11
+ * ## Gated posts stay indexed, and say so
12
+ *
13
+ * A subscriber-only post should still be findable: being discoverable is how
14
+ * anyone subscribes. But serving a full article to a crawler and a paywall to
15
+ * a reader is **cloaking**, which is penalised.
16
+ *
17
+ * The correct answer is schema.org's paywall markup — `isAccessibleForFree:
18
+ * false` plus a `hasPart` naming the gated region. That tells a crawler the
19
+ * content is restricted, so the difference between what it sees and what a
20
+ * reader sees is declared rather than deceptive.
21
+ *
22
+ * @module
23
+ */
24
+ import type { SeoInput } from "./index.js";
25
+ /** A blog post, as it arrives from the platform. */
26
+ export type BlogPostSeoSource = {
27
+ title: string;
28
+ slug: string;
29
+ excerpt?: string | null;
30
+ imageUrl?: string | null;
31
+ publishedAt?: string | null;
32
+ updatedAt?: string | null;
33
+ authorName?: string | null;
34
+ tags?: string[];
35
+ /**
36
+ * `public` is open. Anything else is gated — the platform writes both
37
+ * `members`/`subscribers` and `followers`/`paid` into this column, so
38
+ * anything that is not `public` is treated as restricted.
39
+ */
40
+ accessLevel?: string | null;
41
+ };
42
+ export type BlogPostSeoInput = {
43
+ siteUrl: string;
44
+ post: BlogPostSeoSource;
45
+ /** Path of this post, e.g. `/blog/my-post`. Defaults to `/blog/{slug}`. */
46
+ path?: string;
47
+ /** Extra crumbs between Home and the post. */
48
+ breadcrumbs?: Array<{
49
+ name: string;
50
+ url: string;
51
+ }>;
52
+ /**
53
+ * CSS selector wrapping the gated body, for the paywall markup.
54
+ *
55
+ * Defaults to `.biab-post-body`. It only has to match the element your
56
+ * template actually hides — a selector that matches nothing makes the
57
+ * markup a claim you are not backing up.
58
+ */
59
+ paywallSelector?: string;
60
+ };
61
+ /**
62
+ * SEO for one blog post.
63
+ *
64
+ * ```ts
65
+ * const seo = resolveSeo(layoutDefaults, blogPostSeo({ siteUrl, post }))
66
+ * ```
67
+ */
68
+ export declare function blogPostSeo(input: BlogPostSeoInput): SeoInput;
69
+ export type BlogListingSeoInput = {
70
+ siteUrl: string;
71
+ /** Path of the listing, e.g. `/blog` or `/blog/tag/plumbing`. */
72
+ path?: string;
73
+ title?: string;
74
+ description?: string;
75
+ posts: readonly BlogPostSeoSource[];
76
+ /** Path builder, when posts do not live at `/blog/{slug}`. */
77
+ postPath?: (post: BlogPostSeoSource) => string;
78
+ /**
79
+ * Page number, for paginated archives.
80
+ *
81
+ * Pages 2+ are marked `noindex, follow` by convention: the individual posts
82
+ * are what should rank, and thin archive pages competing with them splits
83
+ * the signal. Links are still followed so the posts stay reachable.
84
+ */
85
+ page?: number;
86
+ };
87
+ /**
88
+ * SEO for a blog index or archive.
89
+ *
90
+ * Emits a `Blog` node with an `ItemList` of the posts on this page, so a
91
+ * crawler can see the structure without fetching every post.
92
+ */
93
+ export declare function blogListingSeo(input: BlogListingSeoInput): SeoInput;
94
+ //# sourceMappingURL=blog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blog.d.ts","sourceRoot":"","sources":["../../src/seo-core/blog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,OAAO,KAAK,EAAW,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEpD,oDAAoD;AACpD,MAAM,MAAM,iBAAiB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,iBAAiB,CAAC;IACxB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAUF;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,QAAQ,CA8E7D;AAED,MAAM,MAAM,mBAAmB,GAAG;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACpC,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,MAAM,CAAC;IAC/C;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,QAAQ,CAgCnE"}