@moonbase.sh/storefront 3.2.0 → 3.4.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.
package/README.md CHANGED
@@ -83,7 +83,7 @@ Moonbase.checkout()
83
83
  Moonbase.view_products()
84
84
  ```
85
85
 
86
- All intents are snake_case methods on the `Moonbase` instance (for example `view_product`, `manage_subscription`, `redeem_voucher`).
86
+ All intents are snake_case methods on the `Moonbase` instance (for example `view_product`, `manage_subscription`, `redeem_voucher`, `join_group`).
87
87
 
88
88
  ## Configure behavior and theme
89
89
 
@@ -140,6 +140,47 @@ A redirected buyer is always brought back to your page once they've paid, so
140
140
  The hosted checkout stays anonymous for the trip — it prefills from the order rather
141
141
  than signing the buyer into a Moonbase account, matching the overlay's behavior.
142
142
 
143
+ ### Customer groups
144
+
145
+ If you keep customer lists in Moonbase and have opened one to public sign-ups,
146
+ name it by ID and the widget enrolls people who use the matching form:
147
+
148
+ ```ts
149
+ Moonbase.configure({
150
+ groups: {
151
+ signUp: ['newsletter-2026'],
152
+ subscribe: ['newsletter-2026'],
153
+ checkout: ['buyers-2026'],
154
+ },
155
+ })
156
+ ```
157
+
158
+ Enrollment is silent. There is no checkbox and no label, because the API
159
+ deliberately tells a storefront nothing about a group: an ID naming a list the
160
+ merchant has not opened to public sign-ups is skipped without a word, so a stale
161
+ ID here can never fail somebody's registration or somebody's purchase. At most
162
+ five groups per request are applied, and IDs are matched lowercase.
163
+
164
+ `signUp` and `subscribe` can be added to per link with `mb_groups`:
165
+
166
+ ```html
167
+ <a href="?mb_intent=sign_up&mb_groups=beta,vip">Join the beta</a>
168
+ ```
169
+
170
+ The two are unioned rather than overridden: `configure` names the lists everyone
171
+ signing up through your site joins, the link adds whichever the campaign is for.
172
+ `checkout` is configuration-only, because the cart outlives any one link.
173
+
174
+ For somebody who already has an account, `join_group` does it as a request of its
175
+ own, and unlike the three above it reports whether it worked:
176
+
177
+ ```html
178
+ <a href="?mb_intent=join_group&mb_group_id=beta">Join the beta list</a>
179
+ ```
180
+
181
+ It signs the visitor in first if they aren't, and emits `joined-group` on
182
+ success. Joining a list twice is not an error.
183
+
143
184
  ### Fonts
144
185
 
145
186
  `theme.fonts.heading` and `theme.fonts.body` each take one of:
@@ -195,8 +236,10 @@ code (`USD 10`), and `'name'` spells it out in the visitor's language
195
236
  (`10 US dollars`). The symbol and its placement still follow the visitor's own
196
237
  locale — this only chooses between the four forms.
197
238
 
198
- Both `pricing` options cover the widget's UI and your `data-moonbase-render` price
199
- elements. The checkout itself is rendered by Moonbase and formats its own prices.
239
+ Both `pricing` options cover the widget's UI, your `data-moonbase-render` price
240
+ elements, and the checkout itself: the widget passes them to Moonbase's own
241
+ checkout page, so the prices a buyer pays are written the same way as the ones
242
+ that got them there.
200
243
 
201
244
  `cart.offers.cartWide` covers offers keyed off the cart as a whole, such as "10% off orders
202
245
  over $50", rather than off a single product. These apply themselves the moment the
@@ -312,6 +355,7 @@ Available events include:
312
355
  - `promotion-clicked`
313
356
  - `promotion-dismissed`
314
357
  - `redeemed-voucher`
358
+ - `joined-group`
315
359
  - `downloaded-product`
316
360
  - `activated-product`
317
361
  - `added-to-cart`
@@ -381,7 +425,7 @@ Moonbase.configure({ integrations: { metaPixel: undefined } })
381
425
 
382
426
  ### Data conventions
383
427
 
384
- Forwarded order `value` is the amount the customer pays — `total.due`, post-discount and **tax-inclusive** (no separate tax field is sent). Per-item prices are the net (post-discount) unit price. `checkout-completed` events carry the order id as a dedup key (Meta `eventID`, TikTok `event_id`, GA4/GTM `transaction_id`) so a completion isn't double-counted.
428
+ Forwarded order `value` is the amount the customer pays — `total.due`, post-discount and **tax-inclusive** (no separate tax field is sent). Per-item prices are the net (post-discount) unit price. `checkout-initiated` is the one exception: an order has no settled total until billing details are entered, so its `value` is the cart's own post-discount total and excludes tax. `checkout-completed` events carry the order id as a dedup key (Meta `eventID`, TikTok `event_id`, GA4/GTM `transaction_id`) so a completion isn't double-counted.
385
429
 
386
430
  ### Event mapping
387
431
 
@@ -1,6 +1,7 @@
1
1
  import { ActivationRequestFulfillmentType } from '@moonbase.sh/vue';
2
2
  import { CartItem } from '@moonbase.sh/vue';
3
3
  import { CheckoutRedirectMode } from '@moonbase.sh/vue';
4
+ import { CurrencyDisplay } from '@moonbase.sh/vue';
4
5
  import { Download } from '@moonbase.sh/vue';
5
6
  import { InjectionKey } from 'vue';
6
7
  import { MarketingConsentType } from '@moonbase.sh/vue';
@@ -11,18 +12,10 @@ import { OwnedProduct } from '@moonbase.sh/vue';
11
12
  import { Storefront } from '@moonbase.sh/vue';
12
13
  import { StorefrontProduct } from '@moonbase.sh/vue';
13
14
  import { StorefrontPromotion } from '@moonbase.sh/vue';
15
+ import { TrailingZeros } from '@moonbase.sh/vue';
14
16
  import { User } from '@moonbase.sh/vue';
15
17
  import { Voucher } from '@moonbase.sh/vue';
16
18
 
17
- /**
18
- * Which marker identifies the currency, for `10` USD read in a British locale:
19
- * - `'narrowSymbol'` (default) — the shortest symbol: `$10`.
20
- * - `'symbol'` — the locale's usual symbol, disambiguated where it needs to be: `US$10`.
21
- * - `'code'` — the ISO 4217 code: `USD 10`.
22
- * - `'name'` — the currency spelled out in the visitor's language: `10 US dollars`.
23
- */
24
- declare type CurrencyDisplay = 'narrowSymbol' | 'symbol' | 'code' | 'name';
25
-
26
19
  declare type DeepPartial<T> = T extends object ? {
27
20
  [P in keyof T]?: T[P] extends HTMLElement | undefined ? T[P] : DeepPartial<T[P]>;
28
21
  } : T;
@@ -83,6 +76,7 @@ export declare enum MoonbaseEvent {
83
76
  SignedUp = "signed-up",
84
77
  SignedOut = "signed-out",
85
78
  RedeemedVoucher = "redeemed-voucher",
79
+ JoinedGroup = "joined-group",
86
80
  StorefrontUpdated = "storefront-updated",
87
81
  PromotionShown = "promotion-shown",
88
82
  PromotionClicked = "promotion-clicked",
@@ -110,6 +104,11 @@ export declare interface MoonbaseEventArgs {
110
104
  voucher: Voucher;
111
105
  user: User;
112
106
  };
107
+ [MoonbaseEvent.JoinedGroup]: {
108
+ /** The group's ID. The API never tells a storefront a group's name. */
109
+ groupId: string;
110
+ user: User;
111
+ };
113
112
  [MoonbaseEvent.StorefrontUpdated]: {
114
113
  storefront: Storefront;
115
114
  user?: User | null;
@@ -196,6 +195,7 @@ declare class MoonbaseImpl implements MoonbaseInstance {
196
195
  confirm_communication_preferences(parameters?: MoonbaseIntentArgs['confirm_communication_preferences']): void;
197
196
  manage_communication_preferences(parameters?: MoonbaseIntentArgs['manage_communication_preferences']): void;
198
197
  connect_account(parameters?: MoonbaseIntentArgs['connect_account']): void;
198
+ join_group(parameters?: MoonbaseIntentArgs['join_group']): void;
199
199
  view_account(): void;
200
200
  view_products(): void;
201
201
  view_subscriptions(): void;
@@ -238,6 +238,7 @@ export declare enum MoonbaseIntent {
238
238
  ViewSubscriptions = "view_subscriptions",
239
239
  RedeemVoucher = "redeem_voucher",
240
240
  ConnectAccount = "connect_account",
241
+ JoinGroup = "join_group",
241
242
  ViewProduct = "view_product",
242
243
  DownloadProduct = "download_product",
243
244
  ActivateProduct = "activate_product",
@@ -256,6 +257,11 @@ export declare interface MoonbaseIntentArgs {
256
257
  };
257
258
  [MoonbaseIntent.SignUp]: {
258
259
  email?: string;
260
+ /**
261
+ * Comma-separated merchant-owned group IDs to join on sign-up, added to
262
+ * whatever `options.groups.signUp` already names.
263
+ */
264
+ groups?: string;
259
265
  };
260
266
  [MoonbaseIntent.ForgotPassword]: {
261
267
  email?: string;
@@ -278,6 +284,11 @@ export declare interface MoonbaseIntentArgs {
278
284
  };
279
285
  [MoonbaseIntent.Subscribe]: {
280
286
  email?: string;
287
+ /**
288
+ * Comma-separated merchant-owned group IDs to join on subscribe, added to
289
+ * whatever `options.groups.subscribe` already names.
290
+ */
291
+ groups?: string;
281
292
  };
282
293
  [MoonbaseIntent.ConfirmCommunicationPreferences]: {
283
294
  email: string;
@@ -296,6 +307,9 @@ export declare interface MoonbaseIntentArgs {
296
307
  [MoonbaseIntent.ConnectAccount]: {
297
308
  provider_id: string;
298
309
  };
310
+ [MoonbaseIntent.JoinGroup]: {
311
+ group_id: string;
312
+ };
299
313
  [MoonbaseIntent.ViewProduct]: {
300
314
  product_id: string;
301
315
  version?: string;
@@ -368,6 +382,29 @@ export declare interface MoonbaseOptions {
368
382
  productUpdates: boolean;
369
383
  };
370
384
  };
385
+ /**
386
+ * Merchant-owned customer groups a visitor joins when they use one of these
387
+ * forms. Named by ID, because the API deliberately tells a storefront nothing
388
+ * about a group: an ID that names a group the merchant has not opened to
389
+ * public sign-ups is skipped in silence, so a stale one here can never fail a
390
+ * registration or a sale. Enrollment is therefore silent too, and there is
391
+ * nothing to label.
392
+ *
393
+ * `signUp` and `subscribe` can be added to per link with `mb_groups`, e.g.
394
+ * `?mb_intent=sign_up&mb_groups=beta,vip`. The two are unioned: the options
395
+ * say which lists everyone signing up through this site joins, the link adds
396
+ * whichever the campaign is for.
397
+ *
398
+ * `checkout` is options-only. The cart outlives any one intent, and a buyer
399
+ * pressing the drawer's own checkout button never went through a link, so a
400
+ * URL-scoped group there would apply or not depending on which button they
401
+ * happened to press.
402
+ */
403
+ groups: {
404
+ signUp: string[];
405
+ subscribe: string[];
406
+ checkout: string[];
407
+ };
371
408
  checkout: {
372
409
  /**
373
410
  * Where checkout happens.
@@ -544,12 +581,6 @@ export declare interface TikTokPixelConfig {
544
581
  pixelId: string;
545
582
  }
546
583
 
547
- /**
548
- * How a whole-number price renders: `'auto'` drops the fraction (`$10`),
549
- * `'always'` keeps the currency's own fraction digits (`$10.00`, `¥1000`).
550
- */
551
- declare type TrailingZeros = 'auto' | 'always';
552
-
553
584
  export declare const urlKey: InjectionKey<string>;
554
585
 
555
586
  export { }