brainerce 1.52.0 → 1.53.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 +6215 -6156
- package/dist/index.d.mts +92 -3
- package/dist/index.d.ts +92 -3
- package/dist/index.js +83 -8
- package/dist/index.mjs +83 -8
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -3188,8 +3188,12 @@ interface SetShippingAddressDto {
|
|
|
3188
3188
|
* which is the correct behaviour once the two no longer agree.
|
|
3189
3189
|
*
|
|
3190
3190
|
* Note there is deliberately no `lat`/`lng` field: zone matching decides
|
|
3191
|
-
* which shipping rate is offered and charged, so
|
|
3192
|
-
*
|
|
3191
|
+
* which shipping rate is offered and charged, so the server resolves the
|
|
3192
|
+
* coordinates itself from this `placeId` and never accepts them from the
|
|
3193
|
+
* client. You can still spread `getAddressDetails().address` in here — the
|
|
3194
|
+
* SDK drops its `lat`/`lng`/`formattedAddress` before sending, because the
|
|
3195
|
+
* endpoint rejects any unknown property with a `400` that would otherwise
|
|
3196
|
+
* block checkout entirely.
|
|
3193
3197
|
*/
|
|
3194
3198
|
placeId?: string;
|
|
3195
3199
|
/**
|
|
@@ -3288,11 +3292,44 @@ interface AddressDetailsResult {
|
|
|
3288
3292
|
*/
|
|
3289
3293
|
region: string;
|
|
3290
3294
|
postalCode: string;
|
|
3295
|
+
/**
|
|
3296
|
+
* ISO-3166-1 alpha-2, or **an empty string** — Google omits the country
|
|
3297
|
+
* outright for places whose sovereignty it declines to attribute, which in
|
|
3298
|
+
* practice includes ordinary residential addresses (verified live: Ramat
|
|
3299
|
+
* Shlomo, Giv'at Ze'ev, Modi'in Ilit, Ma'ale Adumim all come back with no
|
|
3300
|
+
* country). The API deliberately does not guess one.
|
|
3301
|
+
*
|
|
3302
|
+
* Treat it exactly like `region`: when it's empty, leave your country
|
|
3303
|
+
* field for the shopper to confirm rather than submitting a blank
|
|
3304
|
+
* `SetShippingAddressDto.country`. Everything else on the address
|
|
3305
|
+
* (`line1`, `city`, `lat`/`lng`, `formattedAddress`) is still valid and
|
|
3306
|
+
* should still be filled in.
|
|
3307
|
+
*
|
|
3308
|
+
* Note that `region` is necessarily empty too whenever this is — region
|
|
3309
|
+
* codes are resolved *within* a country, so with no country there is no
|
|
3310
|
+
* region list to match against. Prompt for both.
|
|
3311
|
+
*/
|
|
3291
3312
|
country: string;
|
|
3313
|
+
/**
|
|
3314
|
+
* Resolved coordinates, **for your own use only** — a map pin, a distance
|
|
3315
|
+
* readout. They are not part of any address payload: zone matching decides
|
|
3316
|
+
* which shipping rate is offered and charged, so the server re-resolves
|
|
3317
|
+
* them from `placeId` instead of trusting the client. Sending them is
|
|
3318
|
+
* harmless (the SDK strips `lat`/`lng`/`formattedAddress` from
|
|
3319
|
+
* `setShippingAddress()` / `setBillingAddress()` bodies), but pass
|
|
3320
|
+
* `placeId` — that is what actually reaches zone matching.
|
|
3321
|
+
*/
|
|
3292
3322
|
lat: number;
|
|
3293
3323
|
lng: number;
|
|
3294
3324
|
formattedAddress: string;
|
|
3295
3325
|
};
|
|
3326
|
+
/**
|
|
3327
|
+
* Soft coverage hint, never a rejection. Note it can read `false` purely
|
|
3328
|
+
* because `country` came back empty and the store's zones are country-listed
|
|
3329
|
+
* — a polygon zone can still match this address, since the server matches it
|
|
3330
|
+
* against the coordinates it resolves from `placeId`. Show a "we'll confirm
|
|
3331
|
+
* by phone" banner; do not block the shopper.
|
|
3332
|
+
*/
|
|
3296
3333
|
inZone: boolean;
|
|
3297
3334
|
}
|
|
3298
3335
|
interface CompleteCheckoutResponse {
|
|
@@ -6303,6 +6340,14 @@ declare class BrainerceClient {
|
|
|
6303
6340
|
private _pendingRecoverCartId;
|
|
6304
6341
|
private _ga4MeasurementId;
|
|
6305
6342
|
private _ga4StitchPromise;
|
|
6343
|
+
/**
|
|
6344
|
+
* Fields present on `getAddressDetails().address` that the address endpoints
|
|
6345
|
+
* do NOT accept — stripped by `stripResolvedOnlyAddressFields()` so a
|
|
6346
|
+
* `{ ...address }` spread doesn't 400 the whole checkout.
|
|
6347
|
+
*/
|
|
6348
|
+
private static readonly RESOLVED_ONLY_ADDRESS_FIELDS;
|
|
6349
|
+
/** One warning per client, not per keystroke-driven address submit. */
|
|
6350
|
+
private _warnedResolvedOnlyAddressFields;
|
|
6306
6351
|
/** localStorage key for session cart reference (sessionToken + cartId) */
|
|
6307
6352
|
private readonly SESSION_CART_KEY;
|
|
6308
6353
|
/**
|
|
@@ -6376,10 +6421,19 @@ declare class BrainerceClient {
|
|
|
6376
6421
|
* Set the customer authentication token (obtained from login/register).
|
|
6377
6422
|
* Required for accessing customer-specific data in storefront mode.
|
|
6378
6423
|
*
|
|
6424
|
+
* This is a plain setter — it authenticates subsequent requests and nothing
|
|
6425
|
+
* else. In particular it does NOT attach the shopper's existing guest cart to
|
|
6426
|
+
* their account. Pair every sign-in with {@link syncCartOnLogin}, or the cart
|
|
6427
|
+
* stays anonymous and every feature keyed on buyer identity degrades quietly:
|
|
6428
|
+
* "first order only" discounts keep applying to returning customers,
|
|
6429
|
+
* per-customer usage caps stop being enforced at cart time, and abandoned-cart
|
|
6430
|
+
* recovery can't identify who to email.
|
|
6431
|
+
*
|
|
6379
6432
|
* @example
|
|
6380
6433
|
* ```typescript
|
|
6381
6434
|
* const auth = await client.loginCustomer('user@example.com', 'password');
|
|
6382
6435
|
* client.setCustomerToken(auth.token);
|
|
6436
|
+
* await client.syncCartOnLogin(); // claim the guest cart for this account
|
|
6383
6437
|
*
|
|
6384
6438
|
* // Now can access customer data
|
|
6385
6439
|
* const profile = await client.getMyProfile();
|
|
@@ -6525,6 +6579,24 @@ declare class BrainerceClient {
|
|
|
6525
6579
|
* called, or if it hasn't resolved any ids by the time this is awaited.
|
|
6526
6580
|
*/
|
|
6527
6581
|
private withAnalyticsStitchIds;
|
|
6582
|
+
/**
|
|
6583
|
+
* Drop the fields `getAddressDetails()` returns that no address endpoint
|
|
6584
|
+
* accepts, so spreading its `address` straight into `setShippingAddress()`
|
|
6585
|
+
* / `setBillingAddress()` works instead of failing the whole request.
|
|
6586
|
+
*
|
|
6587
|
+
* The address endpoints validate against a strict allow-list: ONE unknown
|
|
6588
|
+
* property rejects the call with `400 "property lat should not exist"`, and
|
|
6589
|
+
* the shopper cannot check out at all. `lat`/`lng`/`formattedAddress` are
|
|
6590
|
+
* the only realistic way to hit that — they come out of this SDK's own
|
|
6591
|
+
* resolved-address shape, so this SDK cleans up after itself rather than
|
|
6592
|
+
* making every storefront remember to. Nothing else is stripped: a genuine
|
|
6593
|
+
* typo still reaches the server and still fails loudly.
|
|
6594
|
+
*
|
|
6595
|
+
* Coordinates are dropped rather than forwarded because zone matching picks
|
|
6596
|
+
* which shipping rate is offered and charged — the server resolves them
|
|
6597
|
+
* itself from `placeId`, and never takes them from the caller.
|
|
6598
|
+
*/
|
|
6599
|
+
private stripResolvedOnlyAddressFields;
|
|
6528
6600
|
/**
|
|
6529
6601
|
* Get a list of products with pagination and filtering
|
|
6530
6602
|
* Works in vibe-coded, storefront (public), and admin mode
|
|
@@ -7643,6 +7715,12 @@ declare class BrainerceClient {
|
|
|
7643
7715
|
* if (params.get('oauth_success') === 'true' && params.get('auth_code')) {
|
|
7644
7716
|
* const result = await client.exchangeOAuthCode(params.get('auth_code')!);
|
|
7645
7717
|
* client.setCustomerToken(result.token);
|
|
7718
|
+
* // REQUIRED: setCustomerToken only stores the JWT — it does NOT attach the
|
|
7719
|
+
* // guest cart to the account. Without this call the cart stays anonymous,
|
|
7720
|
+
* // and anything keyed on the buyer's identity misbehaves: "first order
|
|
7721
|
+
* // only" discounts re-apply to returning customers, per-customer usage
|
|
7722
|
+
* // caps go unenforced, and abandoned-cart recovery can't reach them.
|
|
7723
|
+
* await client.syncCartOnLogin();
|
|
7646
7724
|
* // result.customer, result.isNewCustomer, result.redirectUrl, ...
|
|
7647
7725
|
* } else if (params.get('oauth_error')) {
|
|
7648
7726
|
* // Failures land on this same page, on `redirectUrl` — never on the API
|
|
@@ -7677,6 +7755,11 @@ declare class BrainerceClient {
|
|
|
7677
7755
|
*
|
|
7678
7756
|
* @param authCode - The single-use code from the `?auth_code=` URL param.
|
|
7679
7757
|
*
|
|
7758
|
+
* Always follow a successful exchange with `syncCartOnLogin()`. Storing the
|
|
7759
|
+
* token does not claim the guest cart, and an unclaimed cart has no buyer
|
|
7760
|
+
* identity — which silently breaks first-order discounts, per-customer usage
|
|
7761
|
+
* caps, and abandoned-cart recovery for everyone who signs in with OAuth.
|
|
7762
|
+
*
|
|
7680
7763
|
* @example
|
|
7681
7764
|
* ```typescript
|
|
7682
7765
|
* const params = new URLSearchParams(window.location.search);
|
|
@@ -7685,6 +7768,7 @@ declare class BrainerceClient {
|
|
|
7685
7768
|
* const { token, customer, isNewCustomer, redirectUrl } =
|
|
7686
7769
|
* await client.exchangeOAuthCode(code);
|
|
7687
7770
|
* client.setCustomerToken(token);
|
|
7771
|
+
* await client.syncCartOnLogin(); // attach the guest cart to the account
|
|
7688
7772
|
* }
|
|
7689
7773
|
* ```
|
|
7690
7774
|
*/
|
|
@@ -8840,6 +8924,11 @@ declare class BrainerceClient {
|
|
|
8840
8924
|
* address text — which is materially less accurate and can place the
|
|
8841
8925
|
* shopper in a neighbouring city's zone, or in none at all.
|
|
8842
8926
|
*
|
|
8927
|
+
* Spreading `getAddressDetails().address` in here is safe: its `lat`, `lng`
|
|
8928
|
+
* and `formattedAddress` are dropped before the request goes out (the
|
|
8929
|
+
* endpoint rejects unknown properties outright, and coordinates are never
|
|
8930
|
+
* taken from the client — the server resolves them from `placeId`).
|
|
8931
|
+
*
|
|
8843
8932
|
* @example
|
|
8844
8933
|
* ```typescript
|
|
8845
8934
|
* const { checkout, rates } = await client.setShippingAddress('checkout_123', {
|
|
@@ -11037,7 +11126,7 @@ declare class BrainerceError extends Error {
|
|
|
11037
11126
|
constructor(message: string, statusCode: number, details?: unknown);
|
|
11038
11127
|
}
|
|
11039
11128
|
|
|
11040
|
-
declare const SDK_VERSION = "1.
|
|
11129
|
+
declare const SDK_VERSION = "1.53.0";
|
|
11041
11130
|
|
|
11042
11131
|
/**
|
|
11043
11132
|
* Verify a webhook signature from Brainerce
|
package/dist/index.d.ts
CHANGED
|
@@ -3188,8 +3188,12 @@ interface SetShippingAddressDto {
|
|
|
3188
3188
|
* which is the correct behaviour once the two no longer agree.
|
|
3189
3189
|
*
|
|
3190
3190
|
* Note there is deliberately no `lat`/`lng` field: zone matching decides
|
|
3191
|
-
* which shipping rate is offered and charged, so
|
|
3192
|
-
*
|
|
3191
|
+
* which shipping rate is offered and charged, so the server resolves the
|
|
3192
|
+
* coordinates itself from this `placeId` and never accepts them from the
|
|
3193
|
+
* client. You can still spread `getAddressDetails().address` in here — the
|
|
3194
|
+
* SDK drops its `lat`/`lng`/`formattedAddress` before sending, because the
|
|
3195
|
+
* endpoint rejects any unknown property with a `400` that would otherwise
|
|
3196
|
+
* block checkout entirely.
|
|
3193
3197
|
*/
|
|
3194
3198
|
placeId?: string;
|
|
3195
3199
|
/**
|
|
@@ -3288,11 +3292,44 @@ interface AddressDetailsResult {
|
|
|
3288
3292
|
*/
|
|
3289
3293
|
region: string;
|
|
3290
3294
|
postalCode: string;
|
|
3295
|
+
/**
|
|
3296
|
+
* ISO-3166-1 alpha-2, or **an empty string** — Google omits the country
|
|
3297
|
+
* outright for places whose sovereignty it declines to attribute, which in
|
|
3298
|
+
* practice includes ordinary residential addresses (verified live: Ramat
|
|
3299
|
+
* Shlomo, Giv'at Ze'ev, Modi'in Ilit, Ma'ale Adumim all come back with no
|
|
3300
|
+
* country). The API deliberately does not guess one.
|
|
3301
|
+
*
|
|
3302
|
+
* Treat it exactly like `region`: when it's empty, leave your country
|
|
3303
|
+
* field for the shopper to confirm rather than submitting a blank
|
|
3304
|
+
* `SetShippingAddressDto.country`. Everything else on the address
|
|
3305
|
+
* (`line1`, `city`, `lat`/`lng`, `formattedAddress`) is still valid and
|
|
3306
|
+
* should still be filled in.
|
|
3307
|
+
*
|
|
3308
|
+
* Note that `region` is necessarily empty too whenever this is — region
|
|
3309
|
+
* codes are resolved *within* a country, so with no country there is no
|
|
3310
|
+
* region list to match against. Prompt for both.
|
|
3311
|
+
*/
|
|
3291
3312
|
country: string;
|
|
3313
|
+
/**
|
|
3314
|
+
* Resolved coordinates, **for your own use only** — a map pin, a distance
|
|
3315
|
+
* readout. They are not part of any address payload: zone matching decides
|
|
3316
|
+
* which shipping rate is offered and charged, so the server re-resolves
|
|
3317
|
+
* them from `placeId` instead of trusting the client. Sending them is
|
|
3318
|
+
* harmless (the SDK strips `lat`/`lng`/`formattedAddress` from
|
|
3319
|
+
* `setShippingAddress()` / `setBillingAddress()` bodies), but pass
|
|
3320
|
+
* `placeId` — that is what actually reaches zone matching.
|
|
3321
|
+
*/
|
|
3292
3322
|
lat: number;
|
|
3293
3323
|
lng: number;
|
|
3294
3324
|
formattedAddress: string;
|
|
3295
3325
|
};
|
|
3326
|
+
/**
|
|
3327
|
+
* Soft coverage hint, never a rejection. Note it can read `false` purely
|
|
3328
|
+
* because `country` came back empty and the store's zones are country-listed
|
|
3329
|
+
* — a polygon zone can still match this address, since the server matches it
|
|
3330
|
+
* against the coordinates it resolves from `placeId`. Show a "we'll confirm
|
|
3331
|
+
* by phone" banner; do not block the shopper.
|
|
3332
|
+
*/
|
|
3296
3333
|
inZone: boolean;
|
|
3297
3334
|
}
|
|
3298
3335
|
interface CompleteCheckoutResponse {
|
|
@@ -6303,6 +6340,14 @@ declare class BrainerceClient {
|
|
|
6303
6340
|
private _pendingRecoverCartId;
|
|
6304
6341
|
private _ga4MeasurementId;
|
|
6305
6342
|
private _ga4StitchPromise;
|
|
6343
|
+
/**
|
|
6344
|
+
* Fields present on `getAddressDetails().address` that the address endpoints
|
|
6345
|
+
* do NOT accept — stripped by `stripResolvedOnlyAddressFields()` so a
|
|
6346
|
+
* `{ ...address }` spread doesn't 400 the whole checkout.
|
|
6347
|
+
*/
|
|
6348
|
+
private static readonly RESOLVED_ONLY_ADDRESS_FIELDS;
|
|
6349
|
+
/** One warning per client, not per keystroke-driven address submit. */
|
|
6350
|
+
private _warnedResolvedOnlyAddressFields;
|
|
6306
6351
|
/** localStorage key for session cart reference (sessionToken + cartId) */
|
|
6307
6352
|
private readonly SESSION_CART_KEY;
|
|
6308
6353
|
/**
|
|
@@ -6376,10 +6421,19 @@ declare class BrainerceClient {
|
|
|
6376
6421
|
* Set the customer authentication token (obtained from login/register).
|
|
6377
6422
|
* Required for accessing customer-specific data in storefront mode.
|
|
6378
6423
|
*
|
|
6424
|
+
* This is a plain setter — it authenticates subsequent requests and nothing
|
|
6425
|
+
* else. In particular it does NOT attach the shopper's existing guest cart to
|
|
6426
|
+
* their account. Pair every sign-in with {@link syncCartOnLogin}, or the cart
|
|
6427
|
+
* stays anonymous and every feature keyed on buyer identity degrades quietly:
|
|
6428
|
+
* "first order only" discounts keep applying to returning customers,
|
|
6429
|
+
* per-customer usage caps stop being enforced at cart time, and abandoned-cart
|
|
6430
|
+
* recovery can't identify who to email.
|
|
6431
|
+
*
|
|
6379
6432
|
* @example
|
|
6380
6433
|
* ```typescript
|
|
6381
6434
|
* const auth = await client.loginCustomer('user@example.com', 'password');
|
|
6382
6435
|
* client.setCustomerToken(auth.token);
|
|
6436
|
+
* await client.syncCartOnLogin(); // claim the guest cart for this account
|
|
6383
6437
|
*
|
|
6384
6438
|
* // Now can access customer data
|
|
6385
6439
|
* const profile = await client.getMyProfile();
|
|
@@ -6525,6 +6579,24 @@ declare class BrainerceClient {
|
|
|
6525
6579
|
* called, or if it hasn't resolved any ids by the time this is awaited.
|
|
6526
6580
|
*/
|
|
6527
6581
|
private withAnalyticsStitchIds;
|
|
6582
|
+
/**
|
|
6583
|
+
* Drop the fields `getAddressDetails()` returns that no address endpoint
|
|
6584
|
+
* accepts, so spreading its `address` straight into `setShippingAddress()`
|
|
6585
|
+
* / `setBillingAddress()` works instead of failing the whole request.
|
|
6586
|
+
*
|
|
6587
|
+
* The address endpoints validate against a strict allow-list: ONE unknown
|
|
6588
|
+
* property rejects the call with `400 "property lat should not exist"`, and
|
|
6589
|
+
* the shopper cannot check out at all. `lat`/`lng`/`formattedAddress` are
|
|
6590
|
+
* the only realistic way to hit that — they come out of this SDK's own
|
|
6591
|
+
* resolved-address shape, so this SDK cleans up after itself rather than
|
|
6592
|
+
* making every storefront remember to. Nothing else is stripped: a genuine
|
|
6593
|
+
* typo still reaches the server and still fails loudly.
|
|
6594
|
+
*
|
|
6595
|
+
* Coordinates are dropped rather than forwarded because zone matching picks
|
|
6596
|
+
* which shipping rate is offered and charged — the server resolves them
|
|
6597
|
+
* itself from `placeId`, and never takes them from the caller.
|
|
6598
|
+
*/
|
|
6599
|
+
private stripResolvedOnlyAddressFields;
|
|
6528
6600
|
/**
|
|
6529
6601
|
* Get a list of products with pagination and filtering
|
|
6530
6602
|
* Works in vibe-coded, storefront (public), and admin mode
|
|
@@ -7643,6 +7715,12 @@ declare class BrainerceClient {
|
|
|
7643
7715
|
* if (params.get('oauth_success') === 'true' && params.get('auth_code')) {
|
|
7644
7716
|
* const result = await client.exchangeOAuthCode(params.get('auth_code')!);
|
|
7645
7717
|
* client.setCustomerToken(result.token);
|
|
7718
|
+
* // REQUIRED: setCustomerToken only stores the JWT — it does NOT attach the
|
|
7719
|
+
* // guest cart to the account. Without this call the cart stays anonymous,
|
|
7720
|
+
* // and anything keyed on the buyer's identity misbehaves: "first order
|
|
7721
|
+
* // only" discounts re-apply to returning customers, per-customer usage
|
|
7722
|
+
* // caps go unenforced, and abandoned-cart recovery can't reach them.
|
|
7723
|
+
* await client.syncCartOnLogin();
|
|
7646
7724
|
* // result.customer, result.isNewCustomer, result.redirectUrl, ...
|
|
7647
7725
|
* } else if (params.get('oauth_error')) {
|
|
7648
7726
|
* // Failures land on this same page, on `redirectUrl` — never on the API
|
|
@@ -7677,6 +7755,11 @@ declare class BrainerceClient {
|
|
|
7677
7755
|
*
|
|
7678
7756
|
* @param authCode - The single-use code from the `?auth_code=` URL param.
|
|
7679
7757
|
*
|
|
7758
|
+
* Always follow a successful exchange with `syncCartOnLogin()`. Storing the
|
|
7759
|
+
* token does not claim the guest cart, and an unclaimed cart has no buyer
|
|
7760
|
+
* identity — which silently breaks first-order discounts, per-customer usage
|
|
7761
|
+
* caps, and abandoned-cart recovery for everyone who signs in with OAuth.
|
|
7762
|
+
*
|
|
7680
7763
|
* @example
|
|
7681
7764
|
* ```typescript
|
|
7682
7765
|
* const params = new URLSearchParams(window.location.search);
|
|
@@ -7685,6 +7768,7 @@ declare class BrainerceClient {
|
|
|
7685
7768
|
* const { token, customer, isNewCustomer, redirectUrl } =
|
|
7686
7769
|
* await client.exchangeOAuthCode(code);
|
|
7687
7770
|
* client.setCustomerToken(token);
|
|
7771
|
+
* await client.syncCartOnLogin(); // attach the guest cart to the account
|
|
7688
7772
|
* }
|
|
7689
7773
|
* ```
|
|
7690
7774
|
*/
|
|
@@ -8840,6 +8924,11 @@ declare class BrainerceClient {
|
|
|
8840
8924
|
* address text — which is materially less accurate and can place the
|
|
8841
8925
|
* shopper in a neighbouring city's zone, or in none at all.
|
|
8842
8926
|
*
|
|
8927
|
+
* Spreading `getAddressDetails().address` in here is safe: its `lat`, `lng`
|
|
8928
|
+
* and `formattedAddress` are dropped before the request goes out (the
|
|
8929
|
+
* endpoint rejects unknown properties outright, and coordinates are never
|
|
8930
|
+
* taken from the client — the server resolves them from `placeId`).
|
|
8931
|
+
*
|
|
8843
8932
|
* @example
|
|
8844
8933
|
* ```typescript
|
|
8845
8934
|
* const { checkout, rates } = await client.setShippingAddress('checkout_123', {
|
|
@@ -11037,7 +11126,7 @@ declare class BrainerceError extends Error {
|
|
|
11037
11126
|
constructor(message: string, statusCode: number, details?: unknown);
|
|
11038
11127
|
}
|
|
11039
11128
|
|
|
11040
|
-
declare const SDK_VERSION = "1.
|
|
11129
|
+
declare const SDK_VERSION = "1.53.0";
|
|
11041
11130
|
|
|
11042
11131
|
/**
|
|
11043
11132
|
* Verify a webhook signature from Brainerce
|
package/dist/index.js
CHANGED
|
@@ -201,7 +201,7 @@ function isDevGuardsEnabled() {
|
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
// src/version.ts
|
|
204
|
-
var SDK_VERSION = "1.
|
|
204
|
+
var SDK_VERSION = "1.53.0";
|
|
205
205
|
|
|
206
206
|
// src/client.ts
|
|
207
207
|
var DEFAULT_BASE_URL = "https://api.brainerce.com";
|
|
@@ -241,7 +241,7 @@ function parseRetryAfterMs(response) {
|
|
|
241
241
|
function sleep(ms) {
|
|
242
242
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
243
243
|
}
|
|
244
|
-
var
|
|
244
|
+
var _BrainerceClient = class _BrainerceClient {
|
|
245
245
|
constructor(options) {
|
|
246
246
|
this.customerToken = null;
|
|
247
247
|
this.customerCartId = null;
|
|
@@ -260,6 +260,8 @@ var BrainerceClient = class {
|
|
|
260
260
|
// GA4 stitch state (see `loadGoogleAnalytics()` in the Analytics section).
|
|
261
261
|
this._ga4MeasurementId = null;
|
|
262
262
|
this._ga4StitchPromise = null;
|
|
263
|
+
/** One warning per client, not per keystroke-driven address submit. */
|
|
264
|
+
this._warnedResolvedOnlyAddressFields = false;
|
|
263
265
|
/** localStorage key for session cart reference (sessionToken + cartId) */
|
|
264
266
|
this.SESSION_CART_KEY = "brainerce_session";
|
|
265
267
|
/**
|
|
@@ -773,10 +775,19 @@ var BrainerceClient = class {
|
|
|
773
775
|
* Set the customer authentication token (obtained from login/register).
|
|
774
776
|
* Required for accessing customer-specific data in storefront mode.
|
|
775
777
|
*
|
|
778
|
+
* This is a plain setter — it authenticates subsequent requests and nothing
|
|
779
|
+
* else. In particular it does NOT attach the shopper's existing guest cart to
|
|
780
|
+
* their account. Pair every sign-in with {@link syncCartOnLogin}, or the cart
|
|
781
|
+
* stays anonymous and every feature keyed on buyer identity degrades quietly:
|
|
782
|
+
* "first order only" discounts keep applying to returning customers,
|
|
783
|
+
* per-customer usage caps stop being enforced at cart time, and abandoned-cart
|
|
784
|
+
* recovery can't identify who to email.
|
|
785
|
+
*
|
|
776
786
|
* @example
|
|
777
787
|
* ```typescript
|
|
778
788
|
* const auth = await client.loginCustomer('user@example.com', 'password');
|
|
779
789
|
* client.setCustomerToken(auth.token);
|
|
790
|
+
* await client.syncCartOnLogin(); // claim the guest cart for this account
|
|
780
791
|
*
|
|
781
792
|
* // Now can access customer data
|
|
782
793
|
* const profile = await client.getMyProfile();
|
|
@@ -1290,6 +1301,39 @@ var BrainerceClient = class {
|
|
|
1290
1301
|
return dto;
|
|
1291
1302
|
}
|
|
1292
1303
|
}
|
|
1304
|
+
/**
|
|
1305
|
+
* Drop the fields `getAddressDetails()` returns that no address endpoint
|
|
1306
|
+
* accepts, so spreading its `address` straight into `setShippingAddress()`
|
|
1307
|
+
* / `setBillingAddress()` works instead of failing the whole request.
|
|
1308
|
+
*
|
|
1309
|
+
* The address endpoints validate against a strict allow-list: ONE unknown
|
|
1310
|
+
* property rejects the call with `400 "property lat should not exist"`, and
|
|
1311
|
+
* the shopper cannot check out at all. `lat`/`lng`/`formattedAddress` are
|
|
1312
|
+
* the only realistic way to hit that — they come out of this SDK's own
|
|
1313
|
+
* resolved-address shape, so this SDK cleans up after itself rather than
|
|
1314
|
+
* making every storefront remember to. Nothing else is stripped: a genuine
|
|
1315
|
+
* typo still reaches the server and still fails loudly.
|
|
1316
|
+
*
|
|
1317
|
+
* Coordinates are dropped rather than forwarded because zone matching picks
|
|
1318
|
+
* which shipping rate is offered and charged — the server resolves them
|
|
1319
|
+
* itself from `placeId`, and never takes them from the caller.
|
|
1320
|
+
*/
|
|
1321
|
+
stripResolvedOnlyAddressFields(address) {
|
|
1322
|
+
if (!address || typeof address !== "object") return address;
|
|
1323
|
+
const present = _BrainerceClient.RESOLVED_ONLY_ADDRESS_FIELDS.filter(
|
|
1324
|
+
(field) => field in address
|
|
1325
|
+
);
|
|
1326
|
+
if (present.length === 0) return address;
|
|
1327
|
+
const cleaned = { ...address };
|
|
1328
|
+
for (const field of present) delete cleaned[field];
|
|
1329
|
+
if (!this._warnedResolvedOnlyAddressFields) {
|
|
1330
|
+
this._warnedResolvedOnlyAddressFields = true;
|
|
1331
|
+
console.warn(
|
|
1332
|
+
`BrainerceClient: dropped ${present.join("/")} from the address payload \u2014 the API does not accept coordinates from the client. Pass \`placeId\` (and \`placeSessionToken\`) instead so the server resolves them itself and matches map-drawn delivery zones against the exact location.`
|
|
1333
|
+
);
|
|
1334
|
+
}
|
|
1335
|
+
return cleaned;
|
|
1336
|
+
}
|
|
1293
1337
|
// -------------------- Products --------------------
|
|
1294
1338
|
/**
|
|
1295
1339
|
* Get a list of products with pagination and filtering
|
|
@@ -2882,6 +2926,12 @@ var BrainerceClient = class {
|
|
|
2882
2926
|
* if (params.get('oauth_success') === 'true' && params.get('auth_code')) {
|
|
2883
2927
|
* const result = await client.exchangeOAuthCode(params.get('auth_code')!);
|
|
2884
2928
|
* client.setCustomerToken(result.token);
|
|
2929
|
+
* // REQUIRED: setCustomerToken only stores the JWT — it does NOT attach the
|
|
2930
|
+
* // guest cart to the account. Without this call the cart stays anonymous,
|
|
2931
|
+
* // and anything keyed on the buyer's identity misbehaves: "first order
|
|
2932
|
+
* // only" discounts re-apply to returning customers, per-customer usage
|
|
2933
|
+
* // caps go unenforced, and abandoned-cart recovery can't reach them.
|
|
2934
|
+
* await client.syncCartOnLogin();
|
|
2885
2935
|
* // result.customer, result.isNewCustomer, result.redirectUrl, ...
|
|
2886
2936
|
* } else if (params.get('oauth_error')) {
|
|
2887
2937
|
* // Failures land on this same page, on `redirectUrl` — never on the API
|
|
@@ -2934,6 +2984,11 @@ var BrainerceClient = class {
|
|
|
2934
2984
|
*
|
|
2935
2985
|
* @param authCode - The single-use code from the `?auth_code=` URL param.
|
|
2936
2986
|
*
|
|
2987
|
+
* Always follow a successful exchange with `syncCartOnLogin()`. Storing the
|
|
2988
|
+
* token does not claim the guest cart, and an unclaimed cart has no buyer
|
|
2989
|
+
* identity — which silently breaks first-order discounts, per-customer usage
|
|
2990
|
+
* caps, and abandoned-cart recovery for everyone who signs in with OAuth.
|
|
2991
|
+
*
|
|
2937
2992
|
* @example
|
|
2938
2993
|
* ```typescript
|
|
2939
2994
|
* const params = new URLSearchParams(window.location.search);
|
|
@@ -2942,6 +2997,7 @@ var BrainerceClient = class {
|
|
|
2942
2997
|
* const { token, customer, isNewCustomer, redirectUrl } =
|
|
2943
2998
|
* await client.exchangeOAuthCode(code);
|
|
2944
2999
|
* client.setCustomerToken(token);
|
|
3000
|
+
* await client.syncCartOnLogin(); // attach the guest cart to the account
|
|
2945
3001
|
* }
|
|
2946
3002
|
* ```
|
|
2947
3003
|
*/
|
|
@@ -5121,6 +5177,11 @@ var BrainerceClient = class {
|
|
|
5121
5177
|
* address text — which is materially less accurate and can place the
|
|
5122
5178
|
* shopper in a neighbouring city's zone, or in none at all.
|
|
5123
5179
|
*
|
|
5180
|
+
* Spreading `getAddressDetails().address` in here is safe: its `lat`, `lng`
|
|
5181
|
+
* and `formattedAddress` are dropped before the request goes out (the
|
|
5182
|
+
* endpoint rejects unknown properties outright, and coordinates are never
|
|
5183
|
+
* taken from the client — the server resolves them from `placeId`).
|
|
5184
|
+
*
|
|
5124
5185
|
* @example
|
|
5125
5186
|
* ```typescript
|
|
5126
5187
|
* const { checkout, rates } = await client.setShippingAddress('checkout_123', {
|
|
@@ -5140,7 +5201,9 @@ var BrainerceClient = class {
|
|
|
5140
5201
|
* ```
|
|
5141
5202
|
*/
|
|
5142
5203
|
async setShippingAddress(checkoutId, address) {
|
|
5143
|
-
const body = await this.withAnalyticsStitchIds(
|
|
5204
|
+
const body = await this.withAnalyticsStitchIds(
|
|
5205
|
+
this.stripResolvedOnlyAddressFields(address)
|
|
5206
|
+
);
|
|
5144
5207
|
if (this.isVibeCodedMode()) {
|
|
5145
5208
|
return this.vibeCodedRequest(
|
|
5146
5209
|
"PATCH",
|
|
@@ -5453,24 +5516,25 @@ var BrainerceClient = class {
|
|
|
5453
5516
|
* ```
|
|
5454
5517
|
*/
|
|
5455
5518
|
async setBillingAddress(checkoutId, address) {
|
|
5519
|
+
const body = this.stripResolvedOnlyAddressFields(address);
|
|
5456
5520
|
if (this.isVibeCodedMode()) {
|
|
5457
5521
|
return this.vibeCodedRequest(
|
|
5458
5522
|
"PATCH",
|
|
5459
5523
|
`/checkout/${encodePathSegment(checkoutId)}/billing-address`,
|
|
5460
|
-
|
|
5524
|
+
body
|
|
5461
5525
|
);
|
|
5462
5526
|
}
|
|
5463
5527
|
if (this.storeId && !this.apiKey) {
|
|
5464
5528
|
return this.storefrontRequest(
|
|
5465
5529
|
"PATCH",
|
|
5466
5530
|
`/checkout/${encodePathSegment(checkoutId)}/billing-address`,
|
|
5467
|
-
|
|
5531
|
+
body
|
|
5468
5532
|
);
|
|
5469
5533
|
}
|
|
5470
5534
|
return this.adminRequest(
|
|
5471
5535
|
"PATCH",
|
|
5472
5536
|
`/api/v1/checkout/${encodePathSegment(checkoutId)}/billing-address`,
|
|
5473
|
-
|
|
5537
|
+
body
|
|
5474
5538
|
);
|
|
5475
5539
|
}
|
|
5476
5540
|
/**
|
|
@@ -6436,7 +6500,7 @@ var BrainerceClient = class {
|
|
|
6436
6500
|
const result = await this.vibeCodedRequest(
|
|
6437
6501
|
"PATCH",
|
|
6438
6502
|
`/checkout/${encodePathSegment(checkoutId)}/shipping-address`,
|
|
6439
|
-
data.shippingAddress
|
|
6503
|
+
this.stripResolvedOnlyAddressFields(data.shippingAddress)
|
|
6440
6504
|
);
|
|
6441
6505
|
checkout = result.checkout;
|
|
6442
6506
|
}
|
|
@@ -6444,7 +6508,7 @@ var BrainerceClient = class {
|
|
|
6444
6508
|
checkout = await this.vibeCodedRequest(
|
|
6445
6509
|
"PATCH",
|
|
6446
6510
|
`/checkout/${encodePathSegment(checkoutId)}/billing-address`,
|
|
6447
|
-
data.billingAddress
|
|
6511
|
+
this.stripResolvedOnlyAddressFields(data.billingAddress)
|
|
6448
6512
|
);
|
|
6449
6513
|
}
|
|
6450
6514
|
if (!checkout) {
|
|
@@ -9285,6 +9349,17 @@ var BrainerceClient = class {
|
|
|
9285
9349
|
);
|
|
9286
9350
|
}
|
|
9287
9351
|
};
|
|
9352
|
+
/**
|
|
9353
|
+
* Fields present on `getAddressDetails().address` that the address endpoints
|
|
9354
|
+
* do NOT accept — stripped by `stripResolvedOnlyAddressFields()` so a
|
|
9355
|
+
* `{ ...address }` spread doesn't 400 the whole checkout.
|
|
9356
|
+
*/
|
|
9357
|
+
_BrainerceClient.RESOLVED_ONLY_ADDRESS_FIELDS = [
|
|
9358
|
+
"lat",
|
|
9359
|
+
"lng",
|
|
9360
|
+
"formattedAddress"
|
|
9361
|
+
];
|
|
9362
|
+
var BrainerceClient = _BrainerceClient;
|
|
9288
9363
|
var BrainerceError = class extends Error {
|
|
9289
9364
|
constructor(message, statusCode, details) {
|
|
9290
9365
|
super(message);
|