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.mjs
CHANGED
|
@@ -115,7 +115,7 @@ function isDevGuardsEnabled() {
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
// src/version.ts
|
|
118
|
-
var SDK_VERSION = "1.
|
|
118
|
+
var SDK_VERSION = "1.53.0";
|
|
119
119
|
|
|
120
120
|
// src/client.ts
|
|
121
121
|
var DEFAULT_BASE_URL = "https://api.brainerce.com";
|
|
@@ -155,7 +155,7 @@ function parseRetryAfterMs(response) {
|
|
|
155
155
|
function sleep(ms) {
|
|
156
156
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
157
157
|
}
|
|
158
|
-
var
|
|
158
|
+
var _BrainerceClient = class _BrainerceClient {
|
|
159
159
|
constructor(options) {
|
|
160
160
|
this.customerToken = null;
|
|
161
161
|
this.customerCartId = null;
|
|
@@ -174,6 +174,8 @@ var BrainerceClient = class {
|
|
|
174
174
|
// GA4 stitch state (see `loadGoogleAnalytics()` in the Analytics section).
|
|
175
175
|
this._ga4MeasurementId = null;
|
|
176
176
|
this._ga4StitchPromise = null;
|
|
177
|
+
/** One warning per client, not per keystroke-driven address submit. */
|
|
178
|
+
this._warnedResolvedOnlyAddressFields = false;
|
|
177
179
|
/** localStorage key for session cart reference (sessionToken + cartId) */
|
|
178
180
|
this.SESSION_CART_KEY = "brainerce_session";
|
|
179
181
|
/**
|
|
@@ -687,10 +689,19 @@ var BrainerceClient = class {
|
|
|
687
689
|
* Set the customer authentication token (obtained from login/register).
|
|
688
690
|
* Required for accessing customer-specific data in storefront mode.
|
|
689
691
|
*
|
|
692
|
+
* This is a plain setter — it authenticates subsequent requests and nothing
|
|
693
|
+
* else. In particular it does NOT attach the shopper's existing guest cart to
|
|
694
|
+
* their account. Pair every sign-in with {@link syncCartOnLogin}, or the cart
|
|
695
|
+
* stays anonymous and every feature keyed on buyer identity degrades quietly:
|
|
696
|
+
* "first order only" discounts keep applying to returning customers,
|
|
697
|
+
* per-customer usage caps stop being enforced at cart time, and abandoned-cart
|
|
698
|
+
* recovery can't identify who to email.
|
|
699
|
+
*
|
|
690
700
|
* @example
|
|
691
701
|
* ```typescript
|
|
692
702
|
* const auth = await client.loginCustomer('user@example.com', 'password');
|
|
693
703
|
* client.setCustomerToken(auth.token);
|
|
704
|
+
* await client.syncCartOnLogin(); // claim the guest cart for this account
|
|
694
705
|
*
|
|
695
706
|
* // Now can access customer data
|
|
696
707
|
* const profile = await client.getMyProfile();
|
|
@@ -1204,6 +1215,39 @@ var BrainerceClient = class {
|
|
|
1204
1215
|
return dto;
|
|
1205
1216
|
}
|
|
1206
1217
|
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Drop the fields `getAddressDetails()` returns that no address endpoint
|
|
1220
|
+
* accepts, so spreading its `address` straight into `setShippingAddress()`
|
|
1221
|
+
* / `setBillingAddress()` works instead of failing the whole request.
|
|
1222
|
+
*
|
|
1223
|
+
* The address endpoints validate against a strict allow-list: ONE unknown
|
|
1224
|
+
* property rejects the call with `400 "property lat should not exist"`, and
|
|
1225
|
+
* the shopper cannot check out at all. `lat`/`lng`/`formattedAddress` are
|
|
1226
|
+
* the only realistic way to hit that — they come out of this SDK's own
|
|
1227
|
+
* resolved-address shape, so this SDK cleans up after itself rather than
|
|
1228
|
+
* making every storefront remember to. Nothing else is stripped: a genuine
|
|
1229
|
+
* typo still reaches the server and still fails loudly.
|
|
1230
|
+
*
|
|
1231
|
+
* Coordinates are dropped rather than forwarded because zone matching picks
|
|
1232
|
+
* which shipping rate is offered and charged — the server resolves them
|
|
1233
|
+
* itself from `placeId`, and never takes them from the caller.
|
|
1234
|
+
*/
|
|
1235
|
+
stripResolvedOnlyAddressFields(address) {
|
|
1236
|
+
if (!address || typeof address !== "object") return address;
|
|
1237
|
+
const present = _BrainerceClient.RESOLVED_ONLY_ADDRESS_FIELDS.filter(
|
|
1238
|
+
(field) => field in address
|
|
1239
|
+
);
|
|
1240
|
+
if (present.length === 0) return address;
|
|
1241
|
+
const cleaned = { ...address };
|
|
1242
|
+
for (const field of present) delete cleaned[field];
|
|
1243
|
+
if (!this._warnedResolvedOnlyAddressFields) {
|
|
1244
|
+
this._warnedResolvedOnlyAddressFields = true;
|
|
1245
|
+
console.warn(
|
|
1246
|
+
`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.`
|
|
1247
|
+
);
|
|
1248
|
+
}
|
|
1249
|
+
return cleaned;
|
|
1250
|
+
}
|
|
1207
1251
|
// -------------------- Products --------------------
|
|
1208
1252
|
/**
|
|
1209
1253
|
* Get a list of products with pagination and filtering
|
|
@@ -2796,6 +2840,12 @@ var BrainerceClient = class {
|
|
|
2796
2840
|
* if (params.get('oauth_success') === 'true' && params.get('auth_code')) {
|
|
2797
2841
|
* const result = await client.exchangeOAuthCode(params.get('auth_code')!);
|
|
2798
2842
|
* client.setCustomerToken(result.token);
|
|
2843
|
+
* // REQUIRED: setCustomerToken only stores the JWT — it does NOT attach the
|
|
2844
|
+
* // guest cart to the account. Without this call the cart stays anonymous,
|
|
2845
|
+
* // and anything keyed on the buyer's identity misbehaves: "first order
|
|
2846
|
+
* // only" discounts re-apply to returning customers, per-customer usage
|
|
2847
|
+
* // caps go unenforced, and abandoned-cart recovery can't reach them.
|
|
2848
|
+
* await client.syncCartOnLogin();
|
|
2799
2849
|
* // result.customer, result.isNewCustomer, result.redirectUrl, ...
|
|
2800
2850
|
* } else if (params.get('oauth_error')) {
|
|
2801
2851
|
* // Failures land on this same page, on `redirectUrl` — never on the API
|
|
@@ -2848,6 +2898,11 @@ var BrainerceClient = class {
|
|
|
2848
2898
|
*
|
|
2849
2899
|
* @param authCode - The single-use code from the `?auth_code=` URL param.
|
|
2850
2900
|
*
|
|
2901
|
+
* Always follow a successful exchange with `syncCartOnLogin()`. Storing the
|
|
2902
|
+
* token does not claim the guest cart, and an unclaimed cart has no buyer
|
|
2903
|
+
* identity — which silently breaks first-order discounts, per-customer usage
|
|
2904
|
+
* caps, and abandoned-cart recovery for everyone who signs in with OAuth.
|
|
2905
|
+
*
|
|
2851
2906
|
* @example
|
|
2852
2907
|
* ```typescript
|
|
2853
2908
|
* const params = new URLSearchParams(window.location.search);
|
|
@@ -2856,6 +2911,7 @@ var BrainerceClient = class {
|
|
|
2856
2911
|
* const { token, customer, isNewCustomer, redirectUrl } =
|
|
2857
2912
|
* await client.exchangeOAuthCode(code);
|
|
2858
2913
|
* client.setCustomerToken(token);
|
|
2914
|
+
* await client.syncCartOnLogin(); // attach the guest cart to the account
|
|
2859
2915
|
* }
|
|
2860
2916
|
* ```
|
|
2861
2917
|
*/
|
|
@@ -5035,6 +5091,11 @@ var BrainerceClient = class {
|
|
|
5035
5091
|
* address text — which is materially less accurate and can place the
|
|
5036
5092
|
* shopper in a neighbouring city's zone, or in none at all.
|
|
5037
5093
|
*
|
|
5094
|
+
* Spreading `getAddressDetails().address` in here is safe: its `lat`, `lng`
|
|
5095
|
+
* and `formattedAddress` are dropped before the request goes out (the
|
|
5096
|
+
* endpoint rejects unknown properties outright, and coordinates are never
|
|
5097
|
+
* taken from the client — the server resolves them from `placeId`).
|
|
5098
|
+
*
|
|
5038
5099
|
* @example
|
|
5039
5100
|
* ```typescript
|
|
5040
5101
|
* const { checkout, rates } = await client.setShippingAddress('checkout_123', {
|
|
@@ -5054,7 +5115,9 @@ var BrainerceClient = class {
|
|
|
5054
5115
|
* ```
|
|
5055
5116
|
*/
|
|
5056
5117
|
async setShippingAddress(checkoutId, address) {
|
|
5057
|
-
const body = await this.withAnalyticsStitchIds(
|
|
5118
|
+
const body = await this.withAnalyticsStitchIds(
|
|
5119
|
+
this.stripResolvedOnlyAddressFields(address)
|
|
5120
|
+
);
|
|
5058
5121
|
if (this.isVibeCodedMode()) {
|
|
5059
5122
|
return this.vibeCodedRequest(
|
|
5060
5123
|
"PATCH",
|
|
@@ -5367,24 +5430,25 @@ var BrainerceClient = class {
|
|
|
5367
5430
|
* ```
|
|
5368
5431
|
*/
|
|
5369
5432
|
async setBillingAddress(checkoutId, address) {
|
|
5433
|
+
const body = this.stripResolvedOnlyAddressFields(address);
|
|
5370
5434
|
if (this.isVibeCodedMode()) {
|
|
5371
5435
|
return this.vibeCodedRequest(
|
|
5372
5436
|
"PATCH",
|
|
5373
5437
|
`/checkout/${encodePathSegment(checkoutId)}/billing-address`,
|
|
5374
|
-
|
|
5438
|
+
body
|
|
5375
5439
|
);
|
|
5376
5440
|
}
|
|
5377
5441
|
if (this.storeId && !this.apiKey) {
|
|
5378
5442
|
return this.storefrontRequest(
|
|
5379
5443
|
"PATCH",
|
|
5380
5444
|
`/checkout/${encodePathSegment(checkoutId)}/billing-address`,
|
|
5381
|
-
|
|
5445
|
+
body
|
|
5382
5446
|
);
|
|
5383
5447
|
}
|
|
5384
5448
|
return this.adminRequest(
|
|
5385
5449
|
"PATCH",
|
|
5386
5450
|
`/api/v1/checkout/${encodePathSegment(checkoutId)}/billing-address`,
|
|
5387
|
-
|
|
5451
|
+
body
|
|
5388
5452
|
);
|
|
5389
5453
|
}
|
|
5390
5454
|
/**
|
|
@@ -6350,7 +6414,7 @@ var BrainerceClient = class {
|
|
|
6350
6414
|
const result = await this.vibeCodedRequest(
|
|
6351
6415
|
"PATCH",
|
|
6352
6416
|
`/checkout/${encodePathSegment(checkoutId)}/shipping-address`,
|
|
6353
|
-
data.shippingAddress
|
|
6417
|
+
this.stripResolvedOnlyAddressFields(data.shippingAddress)
|
|
6354
6418
|
);
|
|
6355
6419
|
checkout = result.checkout;
|
|
6356
6420
|
}
|
|
@@ -6358,7 +6422,7 @@ var BrainerceClient = class {
|
|
|
6358
6422
|
checkout = await this.vibeCodedRequest(
|
|
6359
6423
|
"PATCH",
|
|
6360
6424
|
`/checkout/${encodePathSegment(checkoutId)}/billing-address`,
|
|
6361
|
-
data.billingAddress
|
|
6425
|
+
this.stripResolvedOnlyAddressFields(data.billingAddress)
|
|
6362
6426
|
);
|
|
6363
6427
|
}
|
|
6364
6428
|
if (!checkout) {
|
|
@@ -9199,6 +9263,17 @@ var BrainerceClient = class {
|
|
|
9199
9263
|
);
|
|
9200
9264
|
}
|
|
9201
9265
|
};
|
|
9266
|
+
/**
|
|
9267
|
+
* Fields present on `getAddressDetails().address` that the address endpoints
|
|
9268
|
+
* do NOT accept — stripped by `stripResolvedOnlyAddressFields()` so a
|
|
9269
|
+
* `{ ...address }` spread doesn't 400 the whole checkout.
|
|
9270
|
+
*/
|
|
9271
|
+
_BrainerceClient.RESOLVED_ONLY_ADDRESS_FIELDS = [
|
|
9272
|
+
"lat",
|
|
9273
|
+
"lng",
|
|
9274
|
+
"formattedAddress"
|
|
9275
|
+
];
|
|
9276
|
+
var BrainerceClient = _BrainerceClient;
|
|
9202
9277
|
var BrainerceError = class extends Error {
|
|
9203
9278
|
constructor(message, statusCode, details) {
|
|
9204
9279
|
super(message);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brainerce",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.53.0",
|
|
4
4
|
"description": "Official SDK for building e-commerce storefronts with Brainerce Platform. Perfect for vibe-coded sites, AI-built stores (Cursor, Lovable, v0), and custom storefronts.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|