@saastemly/voidcommerce 0.1.0

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 (62) hide show
  1. package/README.md +271 -0
  2. package/bin/vc +2 -0
  3. package/dist/catalog.d.ts +69 -0
  4. package/dist/catalog.js +34 -0
  5. package/dist/cli.d.ts +24 -0
  6. package/dist/cli.js +544 -0
  7. package/dist/deploy/cloudflare.d.ts +25 -0
  8. package/dist/deploy/index.d.ts +16 -0
  9. package/dist/deploy/jsonc.d.ts +8 -0
  10. package/dist/deploy/preflight.d.ts +29 -0
  11. package/dist/deploy/wrangler.d.ts +37 -0
  12. package/dist/dist.d.ts +22 -0
  13. package/dist/generate/auth.d.ts +2 -0
  14. package/dist/generate/ci.d.ts +24 -0
  15. package/dist/generate/env.d.ts +13 -0
  16. package/dist/generate/frontend.d.ts +47 -0
  17. package/dist/generate/index.d.ts +28 -0
  18. package/dist/generate/requirements.d.ts +13 -0
  19. package/dist/generate/strict.d.ts +72 -0
  20. package/dist/generate/support.d.ts +23 -0
  21. package/dist/help.d.ts +31 -0
  22. package/dist/import.d.ts +2 -0
  23. package/dist/index-s7sq41qs.js +590 -0
  24. package/dist/index-ssv3a6wc.js +172 -0
  25. package/dist/index-wzy1xtr1.js +3155 -0
  26. package/dist/index.d.ts +24 -0
  27. package/dist/index.js +190 -0
  28. package/dist/init.d.ts +1 -0
  29. package/dist/manifest.d.ts +131 -0
  30. package/dist/manifest.js +41 -0
  31. package/dist/project.d.ts +20 -0
  32. package/dist/regenerate.d.ts +9 -0
  33. package/dist/scripts.d.ts +12 -0
  34. package/dist/void.d.ts +30 -0
  35. package/dist/wizard.d.ts +7 -0
  36. package/package.json +50 -0
  37. package/src/catalog.ts +673 -0
  38. package/src/cli.ts +78 -0
  39. package/src/deploy/cloudflare.ts +166 -0
  40. package/src/deploy/index.ts +101 -0
  41. package/src/deploy/jsonc.ts +148 -0
  42. package/src/deploy/preflight.ts +137 -0
  43. package/src/deploy/wrangler.ts +111 -0
  44. package/src/dist.ts +157 -0
  45. package/src/generate/auth.ts +386 -0
  46. package/src/generate/ci.ts +208 -0
  47. package/src/generate/env.ts +164 -0
  48. package/src/generate/frontend.ts +275 -0
  49. package/src/generate/index.ts +390 -0
  50. package/src/generate/requirements.ts +48 -0
  51. package/src/generate/strict.ts +692 -0
  52. package/src/generate/support.ts +252 -0
  53. package/src/help.ts +172 -0
  54. package/src/import.ts +237 -0
  55. package/src/index.ts +37 -0
  56. package/src/init.ts +187 -0
  57. package/src/manifest.ts +303 -0
  58. package/src/project.ts +63 -0
  59. package/src/regenerate.ts +51 -0
  60. package/src/scripts.ts +53 -0
  61. package/src/void.ts +115 -0
  62. package/src/wizard.ts +234 -0
@@ -0,0 +1,590 @@
1
+ import { createRequire } from "node:module";
2
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
+
4
+ // src/catalog.ts
5
+ var SIGN_IN = {
6
+ id: "signIn",
7
+ title: "How do people sign in?",
8
+ intro: "Every method proves the address; a shop needs that for the order confirmation anyway.",
9
+ kind: "multiselect",
10
+ choices: [
11
+ {
12
+ id: "magic-link",
13
+ label: "Magic link",
14
+ hint: "one tap on the device the email is open on — signs up too",
15
+ recommended: true
16
+ },
17
+ {
18
+ id: "email-otp",
19
+ label: "Email code",
20
+ hint: "for when the email is on a different device from the checkout — signs up too",
21
+ recommended: true
22
+ },
23
+ {
24
+ id: "passkey",
25
+ label: "Passkeys",
26
+ hint: "returning customers, no email round-trip; sign-in only",
27
+ packages: ["@better-auth/passkey"],
28
+ recommended: true
29
+ },
30
+ {
31
+ id: "google",
32
+ label: "Google",
33
+ hint: "Better Auth's own social provider — not a hand-rolled OAuth flow",
34
+ recommended: true,
35
+ env: [
36
+ { key: "GOOGLE_CLIENT_ID", breaks: "the Google button is drawn and fails", where: "Google Cloud console" },
37
+ { key: "GOOGLE_CLIENT_SECRET", breaks: "the same", where: "Google Cloud console" }
38
+ ]
39
+ },
40
+ {
41
+ id: "apple",
42
+ label: "Apple",
43
+ hint: "required by Apple if you also offer Google in an iOS app",
44
+ env: [
45
+ { key: "APPLE_CLIENT_ID", breaks: "the Apple button is drawn and fails", where: "Apple developer console" },
46
+ { key: "APPLE_CLIENT_SECRET", breaks: "the same", where: "Apple developer console" }
47
+ ]
48
+ },
49
+ {
50
+ id: "github",
51
+ label: "GitHub",
52
+ hint: "developer-audience shops",
53
+ env: [
54
+ { key: "GITHUB_CLIENT_ID", breaks: "the GitHub button is drawn and fails" },
55
+ { key: "GITHUB_CLIENT_SECRET", breaks: "the same" }
56
+ ]
57
+ },
58
+ {
59
+ id: "password",
60
+ label: "Password",
61
+ hint: "reused from somewhere already breached, needs a reset flow that is itself a takeover path — off unless you have a reason"
62
+ },
63
+ {
64
+ id: "username",
65
+ label: "Username",
66
+ hint: "sign in by a handle instead of an address; only with password",
67
+ requires: ["password"]
68
+ },
69
+ {
70
+ id: "phone",
71
+ label: "Phone number",
72
+ hint: "SMS codes — needs an SMS provider you wire yourself"
73
+ },
74
+ {
75
+ id: "anonymous",
76
+ label: "Guest accounts",
77
+ hint: "a cart before an address; upgraded to a real account on first sign-in"
78
+ }
79
+ ]
80
+ };
81
+ var AUTH_PLUGINS = {
82
+ id: "auth",
83
+ title: "Account features",
84
+ intro: "Better Auth's official plugins. Each adds tables and endpoints; the admin panel grows screens for them.",
85
+ kind: "multiselect",
86
+ choices: [
87
+ {
88
+ id: "admin",
89
+ label: "Admin roles",
90
+ hint: "who may open the panel — required, because a shop has operators",
91
+ required: true
92
+ },
93
+ {
94
+ id: "system-user",
95
+ label: "System identity",
96
+ hint: "the deployment authenticates as ITSELF to import its own catalogue — no human sign-in to bootstrap",
97
+ packages: ["@saastemly/better-system-user"],
98
+ required: true,
99
+ env: [
100
+ {
101
+ key: "SYSTEM_API_KEY",
102
+ breaks: "nothing can be imported — no catalogue, no content, no DNS",
103
+ where: "openssl rand -base64 48"
104
+ }
105
+ ]
106
+ },
107
+ {
108
+ id: "api-key",
109
+ label: "API keys",
110
+ hint: "machine access for integrations and the storefront build — 10 requests/day by default, raised for you",
111
+ packages: ["@better-auth/api-key"],
112
+ recommended: true
113
+ },
114
+ {
115
+ id: "two-factor",
116
+ label: "Two-factor",
117
+ hint: "TOTP for operators; a customer account rarely warrants it",
118
+ recommended: true
119
+ },
120
+ {
121
+ id: "organization",
122
+ label: "Organizations",
123
+ hint: "teams that share a shop account — a club ordering trophies as one buyer with several members"
124
+ },
125
+ {
126
+ id: "multi-session",
127
+ label: "Multiple sessions",
128
+ hint: "switch between accounts without signing out — support staff who impersonate"
129
+ },
130
+ {
131
+ id: "jwt",
132
+ label: "JWT",
133
+ hint: "tokens for a service that cannot hold a cookie — a mobile app, a partner API"
134
+ },
135
+ {
136
+ id: "bearer",
137
+ label: "Bearer tokens",
138
+ hint: "the session token in a header instead of a cookie; the mobile-app case"
139
+ },
140
+ {
141
+ id: "haveibeenpwned",
142
+ label: "Breached-password check",
143
+ hint: "refuses a password that has appeared in a breach; only with password sign-in",
144
+ requires: ["password"]
145
+ },
146
+ {
147
+ id: "one-time-token",
148
+ label: "One-time tokens",
149
+ hint: "hand a signed-in session to another origin for one request — the storefront to the panel"
150
+ },
151
+ {
152
+ id: "generic-oauth",
153
+ label: "Custom OAuth provider",
154
+ hint: "an identity provider Better Auth does not ship — a national eID, a corporate SSO"
155
+ },
156
+ {
157
+ id: "oauth-proxy",
158
+ label: "OAuth proxy",
159
+ hint: "OAuth callbacks that work on preview deployments with changing URLs"
160
+ },
161
+ {
162
+ id: "siwe",
163
+ label: "Sign in with Ethereum",
164
+ hint: "wallet-based sign-in; almost certainly not for a trophy shop"
165
+ },
166
+ {
167
+ id: "device-authorization",
168
+ label: "Device flow",
169
+ hint: "sign in on a TV or a CLI by confirming on a phone"
170
+ },
171
+ {
172
+ id: "custom-session",
173
+ label: "Custom session data",
174
+ hint: "attach computed fields to every session response"
175
+ }
176
+ ]
177
+ };
178
+ var COMMERCE_CATALOG = {
179
+ id: "catalog",
180
+ title: "Catalogue",
181
+ kind: "multiselect",
182
+ choices: [
183
+ {
184
+ id: "catalog",
185
+ label: "Products as rows",
186
+ hint: "products, variants, prices, images, categories, collections, tags — editable in the panel",
187
+ required: true
188
+ },
189
+ {
190
+ id: "catalog-import",
191
+ label: "Catalogue import",
192
+ hint: "push products from a file, a PIM or a spreadsheet — matched on handle, never deletes",
193
+ required: true
194
+ },
195
+ {
196
+ id: "metafields",
197
+ label: "Custom fields",
198
+ hint: "typed data on any row without a new table — Shopify's metafields",
199
+ recommended: true
200
+ },
201
+ {
202
+ id: "personalization",
203
+ label: "Personalization",
204
+ hint: "engraving, monograms, gift messages: validated at add-to-cart and priced per character, per unit or once per order"
205
+ },
206
+ {
207
+ id: "inventory",
208
+ label: "Inventory",
209
+ hint: "stock levels and reservations per location",
210
+ recommended: true
211
+ },
212
+ {
213
+ id: "bundles",
214
+ label: "Bundles",
215
+ hint: "a kit is its components at a set price"
216
+ },
217
+ {
218
+ id: "price-lists",
219
+ label: "Price lists",
220
+ hint: "override or discount prices per customer group or date range"
221
+ },
222
+ {
223
+ id: "translations",
224
+ label: "Translations",
225
+ hint: "product copy in more than one language"
226
+ },
227
+ {
228
+ id: "search",
229
+ label: "Search",
230
+ hint: "a search index over the catalogue; memory locally, Meilisearch in production",
231
+ recommended: true
232
+ }
233
+ ]
234
+ };
235
+ var COMMERCE_SALES = {
236
+ id: "sales",
237
+ title: "Selling",
238
+ kind: "multiselect",
239
+ choices: [
240
+ {
241
+ id: "regions",
242
+ label: "Regions",
243
+ hint: "which countries you sell to, in which currency — required",
244
+ required: true
245
+ },
246
+ {
247
+ id: "sales-channels",
248
+ label: "Sales channels",
249
+ hint: "the web shop, a POS, a marketplace — scope products and prices per channel",
250
+ recommended: true
251
+ },
252
+ {
253
+ id: "discounts",
254
+ label: "Discounts and campaigns",
255
+ hint: "codes, automatic promotions, funded campaigns with a spend cap",
256
+ recommended: true
257
+ },
258
+ {
259
+ id: "gift-cards",
260
+ label: "Gift cards",
261
+ hint: "sold as products, redeemed at checkout; balance derived from the ledger"
262
+ },
263
+ {
264
+ id: "loyalty",
265
+ label: "Loyalty points",
266
+ hint: "earn on paid orders, spend at checkout"
267
+ },
268
+ {
269
+ id: "subscriptions",
270
+ label: "Subscriptions",
271
+ hint: "recurring orders on a schedule"
272
+ },
273
+ {
274
+ id: "draft-orders",
275
+ label: "Draft orders",
276
+ hint: "an operator builds a cart for a buyer and converts it — quotes, phone orders",
277
+ recommended: true
278
+ },
279
+ {
280
+ id: "order-edits",
281
+ label: "Order edits",
282
+ hint: "change a paid order — add a line, swap a size — with the difference charged or refunded"
283
+ },
284
+ {
285
+ id: "returns",
286
+ label: "Returns",
287
+ hint: "the buyer-facing road to a refund",
288
+ recommended: true
289
+ },
290
+ {
291
+ id: "wishlists",
292
+ label: "Wishlists",
293
+ hint: "save for later; prices resolved on read, so a saved item shows today's price",
294
+ recommended: true
295
+ },
296
+ {
297
+ id: "reviews",
298
+ label: "Reviews",
299
+ hint: "held for moderation; the verified badge is derived from a paid order, never claimed",
300
+ recommended: true
301
+ },
302
+ {
303
+ id: "customer-groups",
304
+ label: "Customer groups",
305
+ hint: "segments with their own prices and rules — trade, VIP, staff"
306
+ },
307
+ {
308
+ id: "acp",
309
+ label: "Agentic commerce",
310
+ hint: "let an AI agent shop on a buyer's behalf through the Agentic Commerce Protocol"
311
+ }
312
+ ]
313
+ };
314
+ var COMMERCE_OPERATIONS = {
315
+ id: "operations",
316
+ title: "Operations",
317
+ kind: "multiselect",
318
+ choices: [
319
+ {
320
+ id: "fulfillments",
321
+ label: "Fulfilment",
322
+ hint: "what happens when the money is confirmed — ship it, grant it, hand it to the ERP",
323
+ required: true
324
+ },
325
+ {
326
+ id: "shipping-zones",
327
+ label: "Shipping zones",
328
+ hint: "what a buyer can be charged for delivery, by country — required to quote shipping",
329
+ required: true
330
+ },
331
+ {
332
+ id: "tax-regions",
333
+ label: "Tax",
334
+ hint: "VAT by country, declared in code so a fresh deploy is never tax-free",
335
+ required: true
336
+ },
337
+ {
338
+ id: "notifications",
339
+ label: "Notifications",
340
+ hint: "order confirmations and shipping updates, queued and retried",
341
+ required: true
342
+ },
343
+ {
344
+ id: "nft",
345
+ label: "Token instead of a parcel",
346
+ hint: "a buyer who would rather not have the object can take an NFT of it instead — same price, same order, nothing shipped. Needs a mint provider before it mints anything",
347
+ recommended: false
348
+ },
349
+ {
350
+ id: "events",
351
+ label: "Webhooks",
352
+ hint: "deliver commerce events to subscribers with retries and dead-lettering",
353
+ recommended: true
354
+ },
355
+ {
356
+ id: "workflows",
357
+ label: "Workflows",
358
+ hint: "multi-step operations that survive a crash mid-way"
359
+ },
360
+ {
361
+ id: "files",
362
+ label: "Files",
363
+ hint: "uploads — product images, a customer's logo for engraving",
364
+ recommended: true
365
+ },
366
+ {
367
+ id: "merchants",
368
+ label: "Marketplace",
369
+ hint: "several sellers in one shop, with payouts"
370
+ },
371
+ {
372
+ id: "store",
373
+ label: "Store settings",
374
+ hint: "name, support address, public settings the storefront reads",
375
+ required: true
376
+ },
377
+ {
378
+ id: "runtime",
379
+ label: "Cache and locking",
380
+ hint: "required — the kernel's cache and lock providers",
381
+ required: true
382
+ }
383
+ ]
384
+ };
385
+ var PAYMENT = {
386
+ id: "payment",
387
+ title: "Payment rail",
388
+ intro: "Exactly one. Carrying two means every reader works out which half is live.",
389
+ kind: "select",
390
+ choices: [
391
+ {
392
+ id: "adyen",
393
+ label: "Adyen",
394
+ hint: "European rails, MobilePay, local methods",
395
+ env: [
396
+ { key: "ADYEN_API_KEY", breaks: "the shop cannot take money", where: "Adyen Customer Area" },
397
+ { key: "ADYEN_MERCHANT_ACCOUNT", breaks: "the same", where: "Adyen Customer Area" },
398
+ { key: "ADYEN_HMAC_KEY", breaks: "webhooks cannot be verified, so no order becomes paid", where: "Adyen Customer Area" },
399
+ { key: "ADYEN_ENVIRONMENT", breaks: "anything but live charges real customers on the test rail", plaintext: true, dev: "test" },
400
+ { key: "ADYEN_LIVE_PREFIX", breaks: "live Checkout calls are rejected", where: "Adyen Customer Area" }
401
+ ]
402
+ },
403
+ {
404
+ id: "stripe",
405
+ label: "Stripe",
406
+ hint: "the default almost everywhere else",
407
+ env: [
408
+ { key: "STRIPE_SECRET_KEY", breaks: "the shop cannot take money", where: "Stripe dashboard" }
409
+ ]
410
+ }
411
+ ]
412
+ };
413
+ var TAX = {
414
+ id: "tax",
415
+ title: "Tax calculation",
416
+ kind: "select",
417
+ choices: [
418
+ {
419
+ id: "stripe-tax",
420
+ label: "Stripe Tax",
421
+ hint: "asked per basket, so an unregistered shop charges nothing and a registered one charges the buyer's own rate — no rate to declare and none to keep up to date",
422
+ recommended: true
423
+ },
424
+ {
425
+ id: "declared",
426
+ label: "Declared rates",
427
+ hint: "VAT per country in code, editable in the panel — right for one or a few countries"
428
+ },
429
+ {
430
+ id: "taxjar",
431
+ label: "TaxJar",
432
+ hint: "US sales tax by jurisdiction",
433
+ env: [{ key: "TAXJAR_API_KEY", breaks: "no tax is calculated" }]
434
+ },
435
+ {
436
+ id: "avalara",
437
+ label: "Avalara",
438
+ hint: "enterprise tax across many jurisdictions",
439
+ env: [
440
+ { key: "AVALARA_ACCOUNT_ID", breaks: "no tax is calculated" },
441
+ { key: "AVALARA_LICENSE_KEY", breaks: "the same" }
442
+ ]
443
+ }
444
+ ]
445
+ };
446
+ var CARRIERS = {
447
+ id: "carriers",
448
+ title: "Carriers for calculated shipping rates",
449
+ intro: "Optional. Flat-rate shipping needs none of these.",
450
+ kind: "multiselect",
451
+ choices: [
452
+ { id: "shippo", label: "Shippo", hint: "many carriers through one API", env: [{ key: "SHIPPO_API_KEY", breaks: "calculated rates fall back to flat" }] },
453
+ { id: "easypost", label: "EasyPost", hint: "the same, US-leaning", env: [{ key: "EASYPOST_API_KEY", breaks: "calculated rates fall back to flat" }] },
454
+ { id: "ups", label: "UPS", hint: "your own UPS account, for negotiated rates an aggregator cannot see", env: [{ key: "UPS_CLIENT_ID", breaks: "UPS rates are not quoted" }, { key: "UPS_CLIENT_SECRET", breaks: "the same" }] },
455
+ { id: "fedex", label: "FedEx", hint: "your own FedEx account, for negotiated rates an aggregator cannot see", env: [{ key: "FEDEX_CLIENT_ID", breaks: "FedEx rates are not quoted" }, { key: "FEDEX_CLIENT_SECRET", breaks: "the same" }] },
456
+ { id: "dhl-express", label: "DHL Express", hint: "international", env: [{ key: "DHL_API_KEY", breaks: "DHL rates are not quoted" }] },
457
+ { id: "usps", label: "USPS", hint: "US domestic post — the cheapest way to ship a small parcel inside the US", env: [{ key: "USPS_CLIENT_ID", breaks: "USPS rates are not quoted" }, { key: "USPS_CLIENT_SECRET", breaks: "the same" }] },
458
+ { id: "royal-mail", label: "Royal Mail", hint: "UK post, for a shop whose customers are mostly in Britain", env: [{ key: "ROYAL_MAIL_CLIENT_ID", breaks: "Royal Mail rates are not quoted" }] },
459
+ { id: "aramex", label: "Aramex", hint: "the carrier to reach the Gulf and wider Middle East reliably", env: [{ key: "ARAMEX_API_KEY", breaks: "Aramex rates are not quoted" }] },
460
+ { id: "doordash-drive", label: "DoorDash Drive", hint: "same-day local delivery", env: [{ key: "DOORDASH_DEVELOPER_ID", breaks: "DoorDash is not offered" }] },
461
+ { id: "stuart", label: "Stuart", hint: "same-day courier, Europe", env: [{ key: "STUART_CLIENT_ID", breaks: "Stuart is not offered" }] }
462
+ ]
463
+ };
464
+ var ERP = {
465
+ id: "erp",
466
+ title: "ERP",
467
+ intro: "Where a paid order goes after the shop.",
468
+ kind: "select",
469
+ choices: [
470
+ { id: "none", label: "None", hint: "orders live in the shop", recommended: true },
471
+ {
472
+ id: "business-central",
473
+ label: "Microsoft Dynamics 365 Business Central",
474
+ hint: "a paid order becomes a sales order",
475
+ env: [
476
+ { key: "BC_TENANT_ID", breaks: "paid orders never reach the ERP — the shop and the warehouse disagree", where: "Azure app registration" },
477
+ { key: "BC_CLIENT_ID", breaks: "the same", where: "Azure app registration" },
478
+ { key: "BC_CLIENT_SECRET", breaks: "the same", where: "Azure app registration" },
479
+ { key: "BC_COMPANY_ID", breaks: "the same", where: "Business Central" },
480
+ { key: "BC_ENVIRONMENT", breaks: "calls go to the wrong tenant environment", plaintext: true, dev: "production" }
481
+ ]
482
+ }
483
+ ]
484
+ };
485
+ var EMAIL = {
486
+ id: "email",
487
+ title: "Email",
488
+ intro: "One transport for sign-in codes, magic links and order confirmations. Without it nobody can sign in, because every sign-in method proves an address.",
489
+ kind: "select",
490
+ choices: [
491
+ {
492
+ id: "cloudflare-email",
493
+ label: "Cloudflare Email",
494
+ hint: "the Worker's own binding — no API key to issue, store or rotate; Cloudflare writes the SPF, DKIM and DMARC records itself. Needs the domain onboarded once, and a Workers Paid plan to reach anyone but you",
495
+ packages: ["@saastemly/better-email"],
496
+ recommended: true,
497
+ env: [
498
+ {
499
+ key: "EMAIL_FROM",
500
+ breaks: "Cloudflare refuses a sender outside the onboarded domain",
501
+ plaintext: true,
502
+ where: "an address at a domain onboarded for Email Sending"
503
+ }
504
+ ]
505
+ },
506
+ {
507
+ id: "resend",
508
+ label: "Resend",
509
+ hint: "an API key and a verified domain; the free tier is 3,000 a month. MailDev stands in locally either way",
510
+ packages: ["@saastemly/better-email"],
511
+ env: [
512
+ { key: "RESEND_API_KEY", breaks: "no mail at all: nobody can sign in, no confirmations", where: "resend.com" },
513
+ { key: "EMAIL_FROM", breaks: "Resend refuses an unverified sender", plaintext: true, where: "a domain verified at Resend" }
514
+ ]
515
+ }
516
+ ]
517
+ };
518
+ var DNS = {
519
+ id: "dns",
520
+ title: "DNS",
521
+ intro: "So the deploy writes the zone's records, not a person in a registrar's UI. The worker's own hostname is a Cloudflare custom domain and needs no record here; the mail sender's do.",
522
+ kind: "select",
523
+ choices: [
524
+ {
525
+ id: "cloudflare",
526
+ label: "Cloudflare",
527
+ hint: "the zone the shop's domain is in — the deploy writes the mail records so confirmations are not spam",
528
+ packages: ["@saastemly/better-dns"],
529
+ recommended: true,
530
+ env: [
531
+ { key: "CLOUDFLARE_DNS_TOKEN", breaks: "the storefront records are never written; the domain does not reach the shop", where: "a token with Zone:DNS:Edit and Zone:Zone:Read" }
532
+ ]
533
+ },
534
+ {
535
+ id: "simply",
536
+ label: "Simply.com",
537
+ hint: "for a zone that stays there — but then the worker cannot have a custom domain, so the shop has no hostname",
538
+ packages: ["@saastemly/better-dns"],
539
+ env: [{ key: "SIMPLY_API_KEY", breaks: "the storefront records are never written", where: "Simply control panel" }]
540
+ },
541
+ { id: "none", label: "None", hint: "you write the mail records by hand, and a deploy does not mean mail is trusted" }
542
+ ]
543
+ };
544
+ var CONTENT = {
545
+ id: "content",
546
+ title: "Content",
547
+ kind: "multiselect",
548
+ choices: [
549
+ { id: "blogs", label: "Blog", hint: "posts with scheduling, drafts and a public slug", packages: ["@saastemly/better-blogs"], recommended: true },
550
+ { id: "faqs", label: "FAQ", hint: "grouped, ordered, localized — with launch content you declare in code", packages: ["@saastemly/better-faqs"], recommended: true }
551
+ ]
552
+ };
553
+ var UI = {
554
+ id: "ui",
555
+ title: "Interfaces",
556
+ kind: "multiselect",
557
+ choices: [
558
+ {
559
+ id: "admin",
560
+ label: "Generated storefront and panel",
561
+ hint: "better-admin-ui — every table becomes a screen at /api-dashboard, each caller seeing their own scope: a customer their orders, staff everything. Standard theming; one line to turn off once you have built your own",
562
+ packages: ["@saastemly/better-admin-ui"],
563
+ recommended: true
564
+ },
565
+ {
566
+ id: "custom",
567
+ label: "Custom storefront kit",
568
+ hint: "better-auth-ui and better-commerce-ui — hooks, query options and shadcn components you host in your own app, for full freedom in theming and branding",
569
+ packages: ["@better-auth-ui/react", "@saastemly/better-commerce-ui"]
570
+ }
571
+ ]
572
+ };
573
+ var GROUPS = [
574
+ SIGN_IN,
575
+ AUTH_PLUGINS,
576
+ COMMERCE_CATALOG,
577
+ COMMERCE_SALES,
578
+ COMMERCE_OPERATIONS,
579
+ PAYMENT,
580
+ TAX,
581
+ CARRIERS,
582
+ ERP,
583
+ EMAIL,
584
+ DNS,
585
+ CONTENT,
586
+ UI
587
+ ];
588
+ var CHOICES = new Map(GROUPS.flatMap((group) => group.choices.map((choice) => [choice.id, choice])));
589
+
590
+ export { __require, SIGN_IN, AUTH_PLUGINS, COMMERCE_CATALOG, COMMERCE_SALES, COMMERCE_OPERATIONS, PAYMENT, TAX, CARRIERS, ERP, EMAIL, DNS, CONTENT, UI, GROUPS, CHOICES };