brainerce 1.27.1 → 1.28.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/dist/index.d.ts CHANGED
@@ -248,12 +248,38 @@ interface Product {
248
248
  id: string;
249
249
  name: string;
250
250
  slug?: string | null;
251
+ /**
252
+ * Product description as HTML. **Always sanitize before rendering**, e.g.:
253
+ *
254
+ * import { sanitizeHTML } from '@brainerce/utils';
255
+ * <div dangerouslySetInnerHTML={{ __html: sanitizeHTML(product.description) }} />
256
+ *
257
+ * The backend strips dangerous tags/attributes on write, but storefronts should
258
+ * still treat product description as untrusted HTML and sanitize on render.
259
+ */
251
260
  description?: string | null;
252
261
  descriptionFormat?: 'text' | 'html' | 'markdown' | null;
253
262
  sku: string;
254
- /** Base price as string (e.g., "29.99"). Use parseFloat() for calculations. */
263
+ /**
264
+ * Base price as string (e.g., "29.99"). Use parseFloat() for calculations.
265
+ *
266
+ * For `VARIABLE` products the API returns the effective base price
267
+ * aggregated from the product's variants — `MIN(variants.price)` — so a
268
+ * single product card always shows the lowest available price. Matches
269
+ * WooCommerce / Shopify storefront semantics. For `SIMPLE` products it is
270
+ * the product's own stored price.
271
+ */
255
272
  basePrice: string;
256
- /** Sale price as string. Use parseFloat() for calculations. */
273
+ /**
274
+ * Sale price as string. Use parseFloat() for calculations. `null` when the
275
+ * product is not on sale.
276
+ *
277
+ * For `VARIABLE` products the API returns the effective sale price
278
+ * aggregated from the product's variants — `MIN(variants.salePrice WHERE
279
+ * NOT NULL)`. `null` only when no variant is on sale. Matches WooCommerce
280
+ * `is_on_sale()` ("any variation on sale" → product is on sale). For
281
+ * `SIMPLE` products it is the product's own stored sale price.
282
+ */
257
283
  salePrice?: string | null;
258
284
  /** Cost price as string. Use parseFloat() for calculations. */
259
285
  costPrice?: string | null;
@@ -263,6 +289,16 @@ interface Product {
263
289
  priceMax?: string | null;
264
290
  /** True when variant prices differ (VARIABLE products only). Use for "From X – Y" display. */
265
291
  priceVaries?: boolean;
292
+ /** PRD §23: product price converted to the region's currency via the daily
293
+ * FX snapshot. Present only when the read was made with `getProducts({ regionId })`
294
+ * and the region currency differs from the store currency. Display-only —
295
+ * the basePrice/salePrice fields stay in the store currency. */
296
+ displayPrice?: string;
297
+ displaySalePrice?: string;
298
+ displayPriceMin?: string;
299
+ displayPriceMax?: string;
300
+ /** ISO 4217 currency of `displayPrice` (the buyer's region currency). */
301
+ displayCurrency?: string;
266
302
  /** Product status (active, draft). Always returned by backend. */
267
303
  status: string;
268
304
  type: 'SIMPLE' | 'VARIABLE';
@@ -444,6 +480,12 @@ interface ProductVariant {
444
480
  price?: string | null;
445
481
  /** Variant sale price as string. Use parseFloat() for calculations. */
446
482
  salePrice?: string | null;
483
+ /** PRD §23: variant price converted to the region's currency via the daily
484
+ * FX snapshot. Present only with `getProducts({ regionId })`. Display-only. */
485
+ displayPrice?: string;
486
+ displaySalePrice?: string;
487
+ /** ISO 4217 currency of `displayPrice` (the buyer's region currency). */
488
+ displayCurrency?: string;
447
489
  /** Variant attributes (e.g., { "Color": "Red", "Size": "M" }) */
448
490
  attributes?: Record<string, string> | null;
449
491
  /**
@@ -466,6 +508,8 @@ interface ProductVariant {
466
508
  status?: string | null;
467
509
  createdAt: string;
468
510
  updatedAt: string;
511
+ /** Per-sales-channel field overrides keyed by connectionId */
512
+ channels?: Record<string, unknown> | null;
469
513
  }
470
514
  /**
471
515
  * Inventory tracking mode determines how stock is managed:
@@ -520,7 +564,9 @@ interface InventoryInfo {
520
564
  * if (!product.description) return null;
521
565
  *
522
566
  * if (isHtmlDescription(product)) {
523
- * return <div dangerouslySetInnerHTML={{ __html: product.description }} />;
567
+ * // Always sanitize before rendering backend strips dangerous tags on write,
568
+ * // but defense-in-depth on the storefront keeps a regressed/legacy DB safe too.
569
+ * return <div dangerouslySetInnerHTML={{ __html: sanitizeHTML(product.description) }} />;
524
570
  * }
525
571
  *
526
572
  * return <p>{product.description}</p>;
@@ -922,6 +968,13 @@ interface ProductQueryParams {
922
968
  sortOrder?: 'asc' | 'desc';
923
969
  /** Locale for translated content (e.g., "he", "es"). Falls back to store default. */
924
970
  locale?: string;
971
+ /** PRD §23: resolve DISPLAY prices for this region. When set and the region
972
+ * currency differs from the store currency, each product/variant gets
973
+ * additive `displayPrice` / `displayCurrency` (+ `displaySalePrice`,
974
+ * `displayPriceMin/Max`) from the daily FX snapshot. Original `basePrice` /
975
+ * `salePrice` stay in the store currency. Display-only — checkout still
976
+ * charges in the store currency. */
977
+ regionId?: string;
925
978
  type?: 'SIMPLE' | 'VARIABLE';
926
979
  isDownloadable?: boolean;
927
980
  }
@@ -1183,6 +1236,12 @@ interface OrderItem {
1183
1236
  value: string | string[];
1184
1237
  type: string;
1185
1238
  }>;
1239
+ /**
1240
+ * Slug of the tax class resolved for this line at order time (e.g. "reduced").
1241
+ * A frozen snapshot — immune to later TaxClass renames/deletes. Omitted when
1242
+ * the line resolved to no class (the store's Standard fallback).
1243
+ */
1244
+ taxClassSlug?: string;
1186
1245
  }
1187
1246
  /** A downloadable file attached to a product */
1188
1247
  interface DownloadFile {
@@ -1279,6 +1338,12 @@ interface Coupon {
1279
1338
  applicableCategories?: EntityRef[] | null;
1280
1339
  /** Categories explicitly excluded from this coupon. */
1281
1340
  excludedCategories?: EntityRef[] | null;
1341
+ /**
1342
+ * Region restriction (PRD §24). Region IDs this coupon is valid in. Empty =
1343
+ * applies in all regions. Non-empty = only buyers whose checkout region is in
1344
+ * the list can redeem it.
1345
+ */
1346
+ regionIds: string[];
1282
1347
  combinesWithOther: boolean;
1283
1348
  /** Whether coupon needs sync to platforms */
1284
1349
  needsSync?: boolean;
@@ -1351,6 +1416,8 @@ interface CreateCouponDto {
1351
1416
  applicableCategories?: string[];
1352
1417
  /** Category IDs explicitly excluded from this coupon */
1353
1418
  excludedCategories?: string[];
1419
+ /** Region IDs this coupon is valid in (PRD §24). Empty/omitted = all regions. */
1420
+ regionIds?: string[];
1354
1421
  combinesWithOther?: boolean;
1355
1422
  /** Platforms to publish this coupon to */
1356
1423
  platforms?: ConnectorPlatform[];
@@ -1376,6 +1443,8 @@ interface UpdateCouponDto {
1376
1443
  excludedProducts?: string[] | null;
1377
1444
  applicableCategories?: string[] | null;
1378
1445
  excludedCategories?: string[] | null;
1446
+ /** Region IDs this coupon is valid in (PRD §24). Empty = all regions. */
1447
+ regionIds?: string[];
1379
1448
  combinesWithOther?: boolean;
1380
1449
  }
1381
1450
  /**
@@ -2096,6 +2165,10 @@ interface TaxBreakdownItem {
2096
2165
  rate: number;
2097
2166
  /** Calculated tax amount for this rate */
2098
2167
  amount: number;
2168
+ /** The rate's tax class id (null = Standard / no class). */
2169
+ taxClassId?: string | null;
2170
+ /** Slug of the rate's tax class for attribution (e.g. "reduced"; null = Standard). */
2171
+ taxClassSlug?: string | null;
2099
2172
  }
2100
2173
  /**
2101
2174
  * Tax calculation result with itemized breakdown.
@@ -2412,6 +2485,12 @@ interface Checkout {
2412
2485
  shippingMethod?: ShippingRate | null;
2413
2486
  /** Currency code (e.g., "USD") */
2414
2487
  currency: string;
2488
+ /**
2489
+ * Region this checkout is associated with (multi-region commerce), or null.
2490
+ * Recorded for reporting + provider scoping; currency follows the cart until
2491
+ * FX price conversion lands.
2492
+ */
2493
+ regionId?: string | null;
2415
2494
  /** Subtotal as string - use parseFloat() */
2416
2495
  subtotal: string;
2417
2496
  /** Discount amount as string - use parseFloat() */
@@ -2492,6 +2571,13 @@ interface CreateCheckoutDto {
2492
2571
  * ```
2493
2572
  */
2494
2573
  selectedItemIds?: string[];
2574
+ /**
2575
+ * Region ID for multi-region commerce. The region must belong to the store.
2576
+ * Recorded on the checkout for reporting + payment-provider scoping. Currency
2577
+ * still follows the cart until FX price conversion lands. Omit for no region.
2578
+ * Resolve a buyer's country to a region client-side with `detectRegion`.
2579
+ */
2580
+ regionId?: string;
2495
2581
  }
2496
2582
  interface SetCheckoutCustomerDto {
2497
2583
  email: string;
@@ -3475,6 +3561,12 @@ interface ShippingZone {
3475
3561
  regions?: Record<string, string[]> | null;
3476
3562
  /** Postal code patterns */
3477
3563
  postalCodes?: Record<string, string[]> | null;
3564
+ /**
3565
+ * Region restriction (PRD §25). Region IDs this zone is limited to. Empty =
3566
+ * available for any region (default). Non-empty = the zone is only offered to
3567
+ * checkouts whose region is in the list.
3568
+ */
3569
+ regionIds: string[];
3478
3570
  /** Zone priority (lower = higher priority) */
3479
3571
  priority: number;
3480
3572
  isActive: boolean;
@@ -3513,6 +3605,8 @@ interface CreateShippingZoneDto {
3513
3605
  countries: string[];
3514
3606
  regions?: Record<string, string[]>;
3515
3607
  postalCodes?: Record<string, string[]>;
3608
+ /** Region restriction (PRD §25). Region IDs; empty/omitted = any region. */
3609
+ regionIds?: string[];
3516
3610
  priority?: number;
3517
3611
  isActive?: boolean;
3518
3612
  }
@@ -3521,6 +3615,8 @@ interface UpdateShippingZoneDto {
3521
3615
  countries?: string[];
3522
3616
  regions?: Record<string, string[]> | null;
3523
3617
  postalCodes?: Record<string, string[]> | null;
3618
+ /** Region restriction (PRD §25). Empty array = clear; omit = leave unchanged. */
3619
+ regionIds?: string[];
3524
3620
  priority?: number;
3525
3621
  isActive?: boolean;
3526
3622
  platformSettings?: Record<string, unknown>;
@@ -3585,6 +3681,8 @@ interface TaxRate {
3585
3681
  isActive: boolean;
3586
3682
  /** Countries where this tax rate applies as exception */
3587
3683
  exceptionCountries: string[];
3684
+ /** Tax class this rate applies to. null = Standard (applies to unclassed products). */
3685
+ taxClassId?: string | null;
3588
3686
  createdAt: string;
3589
3687
  updatedAt: string;
3590
3688
  }
@@ -3597,6 +3695,8 @@ interface CreateTaxRateDto {
3597
3695
  taxType?: string;
3598
3696
  isCompound?: boolean;
3599
3697
  isInclusive?: boolean;
3698
+ /** Tax class this rate applies to. Omit/null = Standard. */
3699
+ taxClassId?: string;
3600
3700
  priority?: number;
3601
3701
  isActive?: boolean;
3602
3702
  exceptionCountries?: string[];
@@ -3613,6 +3713,114 @@ interface UpdateTaxRateDto {
3613
3713
  priority?: number;
3614
3714
  isActive?: boolean;
3615
3715
  exceptionCountries?: string[];
3716
+ /** Tax class this rate applies to. null clears it (back to Standard). */
3717
+ taxClassId?: string | null;
3718
+ }
3719
+ /**
3720
+ * Tax class — product classification for differential tax rates (Standard /
3721
+ * Reduced / Zero / Food / …). A TaxRate may target one class; a rate with
3722
+ * taxClassId = null is the Standard fallback. See docs concepts/tax-classes.
3723
+ */
3724
+ interface TaxClass {
3725
+ id: string;
3726
+ accountId: string;
3727
+ storeId: string;
3728
+ name: string;
3729
+ slug: string;
3730
+ description?: string | null;
3731
+ /** The class auto-applied to products without an explicit class. */
3732
+ isDefault: boolean;
3733
+ createdAt: string;
3734
+ updatedAt: string;
3735
+ }
3736
+ /** A tax class as exposed on the public storefront (no internal fields). */
3737
+ interface PublicTaxClass {
3738
+ id: string;
3739
+ name: string;
3740
+ slug: string;
3741
+ description?: string | null;
3742
+ isDefault: boolean;
3743
+ }
3744
+ interface CreateTaxClassDto {
3745
+ name: string;
3746
+ /** kebab-case, unique per store */
3747
+ slug: string;
3748
+ description?: string;
3749
+ isDefault?: boolean;
3750
+ }
3751
+ type UpdateTaxClassDto = Partial<CreateTaxClassDto>;
3752
+ /** Bulk-assign a class to products / variants / categories. */
3753
+ interface AssignTaxClassDto {
3754
+ productIds?: string[];
3755
+ variantIds?: string[];
3756
+ categoryIds?: string[];
3757
+ }
3758
+ /** A payment provider (AppInstallation) enabled for a region. */
3759
+ interface RegionPaymentProvider {
3760
+ id: string;
3761
+ regionId: string;
3762
+ appInstallationId: string;
3763
+ isEnabled: boolean;
3764
+ createdAt: string;
3765
+ }
3766
+ /**
3767
+ * Region — binds a set of countries to a currency, tax-display mode, and the
3768
+ * payment providers enabled there. See docs concepts/regions.
3769
+ */
3770
+ interface Region {
3771
+ id: string;
3772
+ accountId: string;
3773
+ storeId: string;
3774
+ name: string;
3775
+ slug: string;
3776
+ /** ISO 4217 currency code. */
3777
+ currency: string;
3778
+ /** ISO 3166-1 alpha-2 country codes. */
3779
+ countries: string[];
3780
+ /** Prices shown tax-inclusive? */
3781
+ taxInclusive: boolean;
3782
+ automaticTaxes: boolean;
3783
+ /** Fallback region for buyers whose country maps to no explicit region. */
3784
+ isDefault: boolean;
3785
+ isActive: boolean;
3786
+ paymentProviders?: RegionPaymentProvider[];
3787
+ createdAt: string;
3788
+ updatedAt: string;
3789
+ }
3790
+ /** Public storefront shape — active regions only, no internal fields. */
3791
+ interface PublicRegion {
3792
+ id: string;
3793
+ name: string;
3794
+ slug: string;
3795
+ currency: string;
3796
+ countries: string[];
3797
+ taxInclusive: boolean;
3798
+ isDefault: boolean;
3799
+ }
3800
+ /** A payment provider enabled for a region, as exposed on the public storefront. */
3801
+ interface PublicRegionPaymentProvider {
3802
+ id: string;
3803
+ appId: string;
3804
+ name: string | null;
3805
+ }
3806
+ /** A single public region with its enabled payment providers (storefront detail). */
3807
+ interface PublicRegionDetail extends PublicRegion {
3808
+ paymentProviders: PublicRegionPaymentProvider[];
3809
+ }
3810
+ interface CreateRegionDto {
3811
+ name: string;
3812
+ /** ISO 4217 */
3813
+ currency: string;
3814
+ /** ISO 3166-1 alpha-2 */
3815
+ countries: string[];
3816
+ taxInclusive?: boolean;
3817
+ automaticTaxes?: boolean;
3818
+ isDefault?: boolean;
3819
+ /** AppInstallation IDs to enable as payment providers. */
3820
+ paymentProviderIds?: string[];
3821
+ }
3822
+ interface UpdateRegionDto extends Partial<CreateRegionDto> {
3823
+ isActive?: boolean;
3616
3824
  }
3617
3825
  /**
3618
3826
  * Metafield type for defining value structure
@@ -3938,6 +4146,15 @@ interface StoreMember {
3938
4146
  context: 'owner' | 'member';
3939
4147
  joinedAt: string | null;
3940
4148
  createdAt: string;
4149
+ /**
4150
+ * Vibe-coded sales channels this member is restricted to (by public
4151
+ * `connectionId`, `vc_*` format). Empty array = unrestricted (all channels).
4152
+ * Owners are never channel-scoped. Optional for backward compatibility.
4153
+ */
4154
+ salesChannels?: {
4155
+ connectionId: string;
4156
+ name: string;
4157
+ }[];
3941
4158
  }
3942
4159
  /** Response for listing store team (members + invitations) */
3943
4160
  interface StoreTeamResponse {
@@ -3954,6 +4171,15 @@ interface StoreInvitation {
3954
4171
  inviterEmail?: string;
3955
4172
  expiresAt: string;
3956
4173
  createdAt: string;
4174
+ /**
4175
+ * Vibe-coded sales channels the invitee will be restricted to once they
4176
+ * accept (by public `connectionId`, `vc_*` format). Empty array =
4177
+ * unrestricted (all channels). Optional for backward compatibility.
4178
+ */
4179
+ salesChannels?: {
4180
+ connectionId: string;
4181
+ name: string;
4182
+ }[];
3957
4183
  }
3958
4184
  /** Public invitation details (for invitation acceptance page) */
3959
4185
  interface StoreInvitationDetails {
@@ -3965,12 +4191,23 @@ interface StoreInvitationDetails {
3965
4191
  expiresAt: string;
3966
4192
  isExpired: boolean;
3967
4193
  isValid: boolean;
4194
+ /** Channels this invite will scope the member to. Empty = unrestricted (all channels). */
4195
+ salesChannels?: {
4196
+ connectionId: string;
4197
+ name: string;
4198
+ }[];
3968
4199
  }
3969
4200
  /** DTO for inviting a store team member */
3970
4201
  interface InviteStoreMemberDto {
3971
4202
  email: string;
3972
4203
  /** Defaults to 'STAFF'. Cannot assign 'OWNER'. */
3973
4204
  role?: StoreRole;
4205
+ /**
4206
+ * Restrict the member to specific vibe-coded sales channels, identified by
4207
+ * their public `connectionId` (`vc_*` format). Empty array or omitted =
4208
+ * unrestricted (access to all channels).
4209
+ */
4210
+ salesChannelIds?: string[];
3974
4211
  }
3975
4212
  /** DTO for updating a store team member's role and/or permissions */
3976
4213
  interface UpdateStoreMemberDto {
@@ -3978,6 +4215,15 @@ interface UpdateStoreMemberDto {
3978
4215
  /** Custom permissions override role defaults when set */
3979
4216
  permissions?: StorePermission[];
3980
4217
  }
4218
+ /**
4219
+ * DTO for replacing the full set of vibe-coded sales channels a member is
4220
+ * restricted to. Channels are identified by their public `connectionId`
4221
+ * (`vc_*` format). An empty array clears all restrictions (member becomes
4222
+ * unrestricted).
4223
+ */
4224
+ interface UpdateStoreMemberSalesChannelsDto {
4225
+ salesChannelIds: string[];
4226
+ }
3981
4227
  /** A store accessible by the current user */
3982
4228
  interface UserStore {
3983
4229
  id: string;
@@ -5066,6 +5312,7 @@ declare class BrainerceClient {
5066
5312
  */
5067
5313
  getProduct(productId: string, options?: {
5068
5314
  locale?: string;
5315
+ regionId?: string;
5069
5316
  }): Promise<Product>;
5070
5317
  /**
5071
5318
  * Get a single product by slug
@@ -5730,18 +5977,25 @@ declare class BrainerceClient {
5730
5977
  *
5731
5978
  * Apps mode requires `customers:read` and `payments:read` scopes.
5732
5979
  *
5733
- * @param storeId - The store this customer belongs to
5980
+ * The store is derived from the SDK instance config (`storeId` passed to
5981
+ * `new BrainerceClient(...)`); the SDK is instantiated per-store so callers
5982
+ * MUST NOT supply it explicitly. A deprecated overload that accepts a
5983
+ * leading `storeId` is kept for backwards-compat — it logs a warning and
5984
+ * verifies the value matches the SDK config.
5985
+ *
5734
5986
  * @param customerId - The customer's ID
5735
5987
  * @returns Array of saved payment methods
5736
5988
  *
5737
5989
  * @example
5738
5990
  * ```typescript
5739
- * const methods = await client.listSavedPaymentMethods(storeId, customerId);
5991
+ * const methods = await client.listSavedPaymentMethods(customerId);
5740
5992
  * methods.forEach((m) => {
5741
5993
  * console.log(`${m.brand} ending in ${m.last4} (expires ${m.expMonth}/${m.expYear})`);
5742
5994
  * });
5743
5995
  * ```
5744
5996
  */
5997
+ listSavedPaymentMethods(customerId: string): Promise<SavedPaymentMethodSummary[]>;
5998
+ /** @deprecated Pass only `customerId`; `storeId` is derived from the SDK config. */
5745
5999
  listSavedPaymentMethods(storeId: string, customerId: string): Promise<SavedPaymentMethodSummary[]>;
5746
6000
  /**
5747
6001
  * Remove a customer's saved payment method.
@@ -5753,18 +6007,45 @@ declare class BrainerceClient {
5753
6007
  *
5754
6008
  * Apps mode requires `customers:write` scope.
5755
6009
  *
5756
- * @param storeId - The store this customer belongs to
6010
+ * The store is derived from the SDK instance config (`storeId` passed to
6011
+ * `new BrainerceClient(...)`); the SDK is instantiated per-store so callers
6012
+ * MUST NOT supply it explicitly. A deprecated overload that accepts a
6013
+ * leading `storeId` is kept for backwards-compat — it logs a warning and
6014
+ * verifies the value matches the SDK config.
6015
+ *
5757
6016
  * @param customerId - The customer's ID
5758
6017
  * @param paymentMethodId - The saved payment method ID to remove
5759
6018
  *
5760
6019
  * @example
5761
6020
  * ```typescript
5762
- * await client.removeSavedPaymentMethod(storeId, customerId, methodId);
6021
+ * await client.removeSavedPaymentMethod(customerId, methodId);
5763
6022
  * ```
5764
6023
  */
6024
+ removeSavedPaymentMethod(customerId: string, paymentMethodId: string): Promise<{
6025
+ success: true;
6026
+ }>;
6027
+ /** @deprecated Pass only `customerId` + `paymentMethodId`; `storeId` is derived from the SDK config. */
5765
6028
  removeSavedPaymentMethod(storeId: string, customerId: string, paymentMethodId: string): Promise<{
5766
6029
  success: true;
5767
6030
  }>;
6031
+ /**
6032
+ * Internal helper: normalize legacy `(storeId, customerId)` callers to the
6033
+ * new `(customerId)` signature for `listSavedPaymentMethods`.
6034
+ *
6035
+ * Throws if the SDK instance has no `storeId` (these endpoints are
6036
+ * storefront-scoped) and warns when the deprecated overload is detected.
6037
+ */
6038
+ private resolveSavedPaymentMethodsArgs;
6039
+ /**
6040
+ * Internal helper: normalize legacy `(storeId, customerId, paymentMethodId)`
6041
+ * callers to the new `(customerId, paymentMethodId)` signature.
6042
+ */
6043
+ private resolveRemovePaymentMethodArgs;
6044
+ /**
6045
+ * One-shot deprecation warning per (method, mismatch?) — verifies the
6046
+ * caller-supplied storeId matches the SDK config and warns regardless.
6047
+ */
6048
+ private warnDeprecatedStoreIdArg;
5768
6049
  /**
5769
6050
  * Login an existing customer (returns JWT token)
5770
6051
  * Works in vibe-coded, storefront, and admin mode
@@ -5796,9 +6077,18 @@ declare class BrainerceClient {
5796
6077
  * Request a password reset email for a customer
5797
6078
  * Works in vibe-coded, storefront, and admin mode
5798
6079
  *
6080
+ * The `resetUrl` MUST be supplied explicitly in non-browser (SSR / Node)
6081
+ * contexts — auto-deriving it from `window.location.origin` is impossible
6082
+ * there and historically resulted in `undefined` being sent to the backend,
6083
+ * which then bounced the email to a broken link. In browser contexts the
6084
+ * origin is still used as a fallback but the SDK logs a one-time warning
6085
+ * recommending an explicit value so server-rendered + proxied dashboards
6086
+ * don't silently rely on the wrong host.
6087
+ *
5799
6088
  * @param email - Customer email address
5800
6089
  * @param options - Optional settings
5801
- * @param options.resetUrl - Override the auto-detected reset URL (e.g. for BFF proxy callback)
6090
+ * @param options.resetUrl - Reset URL the email links should point to.
6091
+ * Required outside the browser; recommended inside it.
5802
6092
  */
5803
6093
  forgotPassword(email: string, options?: {
5804
6094
  resetUrl?: string;
@@ -5899,12 +6189,14 @@ declare class BrainerceClient {
5899
6189
  * // Redirect user to Google
5900
6190
  * window.location.href = authorizationUrl;
5901
6191
  *
5902
- * // On /auth/callback page — the backend handles code exchange and redirects with params:
6192
+ * // On /auth/callback page — exchange the one-time auth_code for the JWT.
6193
+ * // (The backend used to put the JWT directly in the redirect URL; that path
6194
+ * // is deprecated because URL params leak into browser history and logs.)
5903
6195
  * const params = new URLSearchParams(window.location.search);
5904
- * if (params.get('oauth_success') === 'true') {
5905
- * const token = params.get('token');
5906
- * client.setCustomerToken(token);
5907
- * // Also available: customer_id, customer_email, is_new
6196
+ * if (params.get('oauth_success') === 'true' && params.get('auth_code')) {
6197
+ * const result = await client.exchangeOAuthCode(params.get('auth_code')!);
6198
+ * client.setCustomerToken(result.token);
6199
+ * // result.customer, result.isNewCustomer, result.redirectUrl, ...
5908
6200
  * } else if (params.get('oauth_error')) {
5909
6201
  * // Show error
5910
6202
  * }
@@ -5913,6 +6205,33 @@ declare class BrainerceClient {
5913
6205
  getOAuthAuthorizeUrl(provider: CustomerOAuthProvider, options?: {
5914
6206
  redirectUrl?: string;
5915
6207
  }): Promise<OAuthAuthorizeResponse>;
6208
+ /**
6209
+ * Exchange a one-time `auth_code` (returned in the post-OAuth redirect URL)
6210
+ * for the customer JWT. Use this on the `/auth/callback` storefront page
6211
+ * after reading `auth_code` from `window.location.search`.
6212
+ *
6213
+ * The code is single-use and expires 2 minutes after the OAuth callback
6214
+ * issued it. A second call with the same code returns 400.
6215
+ *
6216
+ * This replaces the legacy flow where the JWT was placed directly in the
6217
+ * redirect URL (`?token=...`). The legacy URL params still ship behind a
6218
+ * server feature flag during the migration window, but they will be
6219
+ * removed in the next major release — migrate now.
6220
+ *
6221
+ * @param authCode - The single-use code from the `?auth_code=` URL param.
6222
+ *
6223
+ * @example
6224
+ * ```typescript
6225
+ * const params = new URLSearchParams(window.location.search);
6226
+ * const code = params.get('auth_code');
6227
+ * if (code) {
6228
+ * const { token, customer, isNewCustomer, redirectUrl } =
6229
+ * await client.exchangeOAuthCode(code);
6230
+ * client.setCustomerToken(token);
6231
+ * }
6232
+ * ```
6233
+ */
6234
+ exchangeOAuthCode(authCode: string): Promise<OAuthCallbackResponse>;
5916
6235
  /**
5917
6236
  * Handle OAuth callback - exchange code for customer token (server-to-server)
5918
6237
  *
@@ -8263,6 +8582,71 @@ declare class BrainerceClient {
8263
8582
  * Requires Admin mode (apiKey)
8264
8583
  */
8265
8584
  deleteZoneShippingRate(zoneId: string, rateId: string): Promise<void>;
8585
+ /** List the store's regions (paginated). */
8586
+ getRegions(): Promise<PaginatedResponse<Region>>;
8587
+ getRegion(regionId: string): Promise<Region>;
8588
+ createRegion(data: CreateRegionDto): Promise<Region>;
8589
+ updateRegion(regionId: string, data: UpdateRegionDto): Promise<Region>;
8590
+ deleteRegion(regionId: string): Promise<void>;
8591
+ setDefaultRegion(regionId: string): Promise<Region>;
8592
+ /** Replace the region's enabled payment providers (AppInstallation IDs). */
8593
+ updateRegionPaymentProviders(regionId: string, providerIds: string[]): Promise<Region>;
8594
+ addRegionCountries(regionId: string, countries: string[]): Promise<Region>;
8595
+ removeRegionCountry(regionId: string, countryCode: string): Promise<Region>;
8596
+ /** Installed payment providers compatible with this region's countries. */
8597
+ getRegionCompatibleProviders(regionId: string): Promise<Array<{
8598
+ id: string;
8599
+ appId: string;
8600
+ name?: string | null;
8601
+ }>>;
8602
+ /**
8603
+ * List the store's ACTIVE regions (public, no apiKey). Requires storeId mode.
8604
+ * Returns only storefront-safe fields (no internal flags). Default region first.
8605
+ */
8606
+ getStoreRegions(): Promise<{
8607
+ data: PublicRegion[];
8608
+ }>;
8609
+ /**
8610
+ * Get one active public region plus its enabled payment providers (public).
8611
+ * Requires storeId mode. Throws 404 if the region is inactive or not found.
8612
+ */
8613
+ getStoreRegion(regionId: string): Promise<PublicRegionDetail>;
8614
+ /**
8615
+ * Client-side region detection — no network call. Returns the region whose
8616
+ * `countries` includes `country`, else the default region, else null.
8617
+ */
8618
+ detectRegion(country: string, regions: Array<Region | PublicRegion>): Region | PublicRegion | null;
8619
+ /**
8620
+ * List the store's tax classes (public, no apiKey — storeId mode). Storefront-
8621
+ * safe fields only (id/name/slug/description/isDefault) for transparency UIs
8622
+ * such as a "9% VAT" badge. Admin/api-key callers use getTaxClasses().
8623
+ */
8624
+ getStoreTaxClasses(): Promise<{
8625
+ data: PublicTaxClass[];
8626
+ }>;
8627
+ /** List the store's tax classes. */
8628
+ getTaxClasses(): Promise<{
8629
+ data: TaxClass[];
8630
+ }>;
8631
+ /** Get a tax class with its dependent counts (products/variants/categories/rates). */
8632
+ getTaxClass(id: string): Promise<TaxClass & {
8633
+ dependents: {
8634
+ productCount: number;
8635
+ variantCount: number;
8636
+ categoryCount: number;
8637
+ taxRateCount: number;
8638
+ };
8639
+ }>;
8640
+ createTaxClass(data: CreateTaxClassDto): Promise<TaxClass>;
8641
+ updateTaxClass(id: string, data: UpdateTaxClassDto): Promise<TaxClass>;
8642
+ deleteTaxClass(id: string): Promise<void>;
8643
+ setDefaultTaxClass(id: string): Promise<TaxClass>;
8644
+ /** Bulk-assign this tax class to products / variants / categories. */
8645
+ assignTaxClass(id: string, data: AssignTaxClassDto): Promise<{
8646
+ updated: number;
8647
+ }>;
8648
+ /** Merge this tax class into another, moving all FKs, then delete it. */
8649
+ mergeTaxClasses(id: string, targetId: string): Promise<void>;
8266
8650
  /**
8267
8651
  * Get all tax rates for the store
8268
8652
  * Requires Admin mode (apiKey)
@@ -8535,6 +8919,9 @@ declare class BrainerceClient {
8535
8919
  * const invitation = await client.inviteStoreMember('store_id', {
8536
8920
  * email: 'newmember@example.com',
8537
8921
  * role: 'MANAGER', // 'MANAGER' | 'STAFF' | 'VIEWER'
8922
+ * // Optional: restrict to specific vibe-coded channels (connectionId, vc_*).
8923
+ * // Omit or pass [] for unrestricted access to all channels.
8924
+ * salesChannelIds: ['vc_abc123', 'vc_def456'],
8538
8925
  * });
8539
8926
  * ```
8540
8927
  */
@@ -8555,6 +8942,26 @@ declare class BrainerceClient {
8555
8942
  * ```
8556
8943
  */
8557
8944
  updateStoreMember(storeId: string, memberId: string, data: UpdateStoreMemberDto): Promise<StoreMember>;
8945
+ /**
8946
+ * Replace the set of vibe-coded sales channels a store member is restricted to.
8947
+ * Channels are identified by their public `connectionId` (`vc_*` format). Pass
8948
+ * an empty array to clear all restrictions (member becomes unrestricted).
8949
+ * Requires Admin mode (apiKey) and MANAGE_TEAM permission
8950
+ *
8951
+ * @example
8952
+ * ```typescript
8953
+ * // Restrict to two vibe-coded channels
8954
+ * await client.updateStoreMemberSalesChannels('store_id', 'member_id', {
8955
+ * salesChannelIds: ['vc_abc123', 'vc_def456'],
8956
+ * });
8957
+ *
8958
+ * // Clear all restrictions (unrestricted access)
8959
+ * await client.updateStoreMemberSalesChannels('store_id', 'member_id', {
8960
+ * salesChannelIds: [],
8961
+ * });
8962
+ * ```
8963
+ */
8964
+ updateStoreMemberSalesChannels(storeId: string, memberId: string, data: UpdateStoreMemberSalesChannelsDto): Promise<StoreMember>;
8558
8965
  /**
8559
8966
  * Remove a member from a store team
8560
8967
  * Requires Admin mode (apiKey) and MANAGE_TEAM permission