brainerce 2.2.0 → 2.3.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.js CHANGED
@@ -204,7 +204,7 @@ function isDevGuardsEnabled() {
204
204
  }
205
205
 
206
206
  // src/version.ts
207
- var SDK_VERSION = "2.2.0";
207
+ var SDK_VERSION = "2.3.0";
208
208
 
209
209
  // src/client.ts
210
210
  var DEFAULT_BASE_URL = "https://api.brainerce.com";
@@ -926,10 +926,19 @@ var _BrainerceClient = class _BrainerceClient {
926
926
  this.customerToken = null;
927
927
  }
928
928
  // -------------------- Private Methods --------------------
929
+ /**
930
+ * Turn an `idempotencyKey` option into the header the backend reads.
931
+ *
932
+ * Returns `undefined` when there is no key, so the header is absent rather
933
+ * than empty — the interceptor rejects a present-but-blank key with a 400.
934
+ */
935
+ idempotencyHeaders(options) {
936
+ return options?.idempotencyKey ? { "Idempotency-Key": options.idempotencyKey } : void 0;
937
+ }
929
938
  /**
930
939
  * Make a request to the Admin API (requires apiKey)
931
940
  */
932
- async adminRequest(method, path, body, queryParams, responseType = "json") {
941
+ async adminRequest(method, path, body, queryParams, responseType = "json", extraHeaders) {
933
942
  if (!this.apiKey) {
934
943
  throw new BrainerceError(
935
944
  "This operation requires an API key. Initialize with apiKey instead of storeId.",
@@ -959,6 +968,11 @@ var _BrainerceClient = class _BrainerceClient {
959
968
  if (this.locale) {
960
969
  headers["Accept-Language"] = this.locale;
961
970
  }
971
+ if (extraHeaders) {
972
+ for (const [key, value] of Object.entries(extraHeaders)) {
973
+ if (value) headers[key] = value;
974
+ }
975
+ }
962
976
  for (let attempt = 0; attempt < 2; attempt++) {
963
977
  const controller = new AbortController();
964
978
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
@@ -2283,21 +2297,25 @@ var _BrainerceClient = class _BrainerceClient {
2283
2297
  );
2284
2298
  }
2285
2299
  /**
2286
- * Publish a product to specific platforms
2300
+ * Publish a product to specific platforms.
2287
2301
  *
2288
- * @example
2289
- * ```typescript
2290
- * const result = await client.publishProduct('prod_123', ['SHOPIFY', 'WOOCOMMERCE']);
2291
- * console.log('Publish results:', result.results);
2292
- * ```
2302
+ * **Not callable.** The API-key `/v1` surface has no `products/:id/publish`
2303
+ * route. Platform publishing for products exists only on the dashboard
2304
+ * surface (`POST /api/products/:id/publish?storeId=`,
2305
+ * `products.controller.ts:556`), which resolves the acting user from a
2306
+ * dashboard session an API key does not carry. The generic trigger
2307
+ * `POST /v1/sync` answers `501 Not Implemented` and points at per-resource
2308
+ * publish endpoints — and products have none.
2309
+ *
2310
+ * {@link publishProductToSalesChannel} is a DIFFERENT operation: it controls
2311
+ * visibility on a vibe-coded storefront, not a push to an external platform.
2293
2312
  */
2294
2313
  async publishProduct(productId, platforms) {
2295
- return this.request(
2296
- "POST",
2297
- `/api/v1/products/${encodePathSegment(productId)}/publish`,
2298
- {
2299
- platforms
2300
- }
2314
+ void productId;
2315
+ void platforms;
2316
+ throw new BrainerceError(
2317
+ "publishProduct is not a route on the API-key /v1 surface. There is no products/:id/publish endpoint to call, so nothing was published; publish the product to a platform from the Brainerce dashboard. Note that publishProductToSalesChannel is a different operation \u2014 it controls vibe-coded storefront visibility, not an external-platform push.",
2318
+ 400
2301
2319
  );
2302
2320
  }
2303
2321
  // -------------------- Variants --------------------
@@ -4292,6 +4310,9 @@ var _BrainerceClient = class _BrainerceClient {
4292
4310
  * flags reflect the live state. Call this on cart load if you want to
4293
4311
  * surface drift to the customer before they reach checkout.
4294
4312
  *
4313
+ * **Storefront and vibe-coded modes only.** There is no admin (`apiKey`)
4314
+ * route for this, so an admin-mode client throws instead of 404ing.
4315
+ *
4295
4316
  * @example
4296
4317
  * ```typescript
4297
4318
  * const cart = await client.recalculateCart('cart_123');
@@ -4316,9 +4337,9 @@ var _BrainerceClient = class _BrainerceClient {
4316
4337
  "cart"
4317
4338
  );
4318
4339
  }
4319
- return this.withGuards(
4320
- this.adminRequest("POST", `/api/v1/cart/${encodePathSegment(cartId)}/recalculate`),
4321
- "cart"
4340
+ throw new BrainerceError(
4341
+ "recalculateCart is not a route on the API-key /v1 surface. There is no cart/:cartId/recalculate endpoint to call, so nothing was recalculated. Cart recalculation is a storefront operation \u2014 call it from a client constructed with `salesChannelId` (vibe-coded) or `storeId` (public storefront), where the route exists.",
4342
+ 400
4322
4343
  );
4323
4344
  }
4324
4345
  /**
@@ -4327,6 +4348,9 @@ var _BrainerceClient = class _BrainerceClient {
4327
4348
  * subsequent `createCheckout` call will then succeed (it would otherwise
4328
4349
  * throw `PRICE_DRIFT`).
4329
4350
  *
4351
+ * **Storefront and vibe-coded modes only.** There is no admin (`apiKey`)
4352
+ * route for this, so an admin-mode client throws instead of 404ing.
4353
+ *
4330
4354
  * @example
4331
4355
  * ```typescript
4332
4356
  * try {
@@ -4361,12 +4385,9 @@ var _BrainerceClient = class _BrainerceClient {
4361
4385
  "cart"
4362
4386
  );
4363
4387
  }
4364
- return this.withGuards(
4365
- this.adminRequest(
4366
- "POST",
4367
- `/api/v1/cart/${encodePathSegment(cartId)}/refresh-snapshots`
4368
- ),
4369
- "cart"
4388
+ throw new BrainerceError(
4389
+ "refreshCartSnapshots is not a route on the API-key /v1 surface. There is no cart/:cartId/refresh-snapshots endpoint to call, so no price snapshots were refreshed. Snapshot refresh is a storefront operation \u2014 call it from a client constructed with `salesChannelId` (vibe-coded) or `storeId` (public storefront), where the route exists.",
4390
+ 400
4370
4391
  );
4371
4392
  }
4372
4393
  /**
@@ -5875,22 +5896,39 @@ var _BrainerceClient = class _BrainerceClient {
5875
5896
  * screen or database query can recover it.
5876
5897
  *
5877
5898
  * A `note` is required. Refused when gift cards are switched off for the
5878
- * store. Pass an `Idempotency-Key` header to make a retry safe.
5899
+ * store.
5900
+ *
5901
+ * ⚠️ **Pass an `idempotencyKey`.** It is the ONLY recovery that exists here:
5902
+ * re-sending the identical request with the same key inside 24 hours replays
5903
+ * the cached response, code included. Without one, a retried timeout mints a
5904
+ * SECOND card and a second real liability. The key is sent as the
5905
+ * `Idempotency-Key` header; reuse the same value across retries of the same
5906
+ * logical issue, never a fresh random one.
5879
5907
  *
5880
5908
  * Requires `gift_cards:issue`.
5881
5909
  *
5882
5910
  * @example
5883
5911
  * ```typescript
5884
- * const card = await client.issueGiftCard({
5885
- * amount: '200.00',
5886
- * note: 'Compensation for order #1042',
5887
- * recipientEmail: 'dana@example.com',
5888
- * });
5912
+ * const card = await client.issueGiftCard(
5913
+ * {
5914
+ * amount: '200.00',
5915
+ * note: 'Compensation for order #1042',
5916
+ * recipientEmail: 'dana@example.com',
5917
+ * },
5918
+ * { idempotencyKey: 'compensation-order-1042' }
5919
+ * );
5889
5920
  * await sendToCustomer(card.plaintextCode); // your only chance
5890
5921
  * ```
5891
5922
  */
5892
- async issueGiftCard(data) {
5893
- return this.adminRequest("POST", "/api/v1/gift-cards", data);
5923
+ async issueGiftCard(data, options) {
5924
+ return this.adminRequest(
5925
+ "POST",
5926
+ "/api/v1/gift-cards",
5927
+ data,
5928
+ void 0,
5929
+ "json",
5930
+ this.idempotencyHeaders(options)
5931
+ );
5894
5932
  }
5895
5933
  /**
5896
5934
  * Re-issue a gift card onto a new code.
@@ -5903,15 +5941,21 @@ var _BrainerceClient = class _BrainerceClient {
5903
5941
  * while a checkout holds value on the card. The original expiry carries
5904
5942
  * forward, so this cannot be used to restart an expiry clock.
5905
5943
  *
5906
- * The new code is returned exactly once, under the same rules as issuance.
5944
+ * The new code is returned exactly once, under the same rules as issuance
5945
+ * so pass an `idempotencyKey` here for the same reason, and with the same
5946
+ * force: a retried timeout without one revokes the replacement it just made
5947
+ * and mints another.
5907
5948
  *
5908
5949
  * Requires `gift_cards:issue`.
5909
5950
  */
5910
- async reissueGiftCard(giftCardId, note) {
5951
+ async reissueGiftCard(giftCardId, note, options) {
5911
5952
  return this.adminRequest(
5912
5953
  "POST",
5913
5954
  `/api/v1/gift-cards/${encodePathSegment(giftCardId)}/reissue`,
5914
- { note }
5955
+ { note },
5956
+ void 0,
5957
+ "json",
5958
+ this.idempotencyHeaders(options)
5915
5959
  );
5916
5960
  }
5917
5961
  /**
@@ -5924,13 +5968,19 @@ var _BrainerceClient = class _BrainerceClient {
5924
5968
  * A debit cannot take the balance below what live checkout holds have already
5925
5969
  * reserved; that refusal names the held amount so you can act on it.
5926
5970
  *
5971
+ * Pass an `idempotencyKey`: an adjustment is a relative move, so a retried
5972
+ * timeout without one applies the delta twice.
5973
+ *
5927
5974
  * Requires `gift_cards:adjust`.
5928
5975
  */
5929
- async adjustGiftCardBalance(giftCardId, delta, note) {
5976
+ async adjustGiftCardBalance(giftCardId, delta, note, options) {
5930
5977
  return this.adminRequest(
5931
5978
  "PATCH",
5932
5979
  `/api/v1/gift-cards/${encodePathSegment(giftCardId)}/adjust`,
5933
- { delta, note }
5980
+ { delta, note },
5981
+ void 0,
5982
+ "json",
5983
+ this.idempotencyHeaders(options)
5934
5984
  );
5935
5985
  }
5936
5986
  /**
@@ -5943,11 +5993,14 @@ var _BrainerceClient = class _BrainerceClient {
5943
5993
  *
5944
5994
  * Requires `gift_cards:write`.
5945
5995
  */
5946
- async setGiftCardStatus(giftCardId, status) {
5996
+ async setGiftCardStatus(giftCardId, status, options) {
5947
5997
  return this.adminRequest(
5948
5998
  "PATCH",
5949
5999
  `/api/v1/gift-cards/${encodePathSegment(giftCardId)}/status`,
5950
- { status }
6000
+ { status },
6001
+ void 0,
6002
+ "json",
6003
+ this.idempotencyHeaders(options)
5951
6004
  );
5952
6005
  }
5953
6006
  /**
@@ -5963,11 +6016,15 @@ var _BrainerceClient = class _BrainerceClient {
5963
6016
  *
5964
6017
  * Requires `gift_cards:write`.
5965
6018
  */
5966
- async bulkSetGiftCardStatus(giftCardIds, status) {
5967
- return this.adminRequest("PATCH", "/api/v1/gift-cards/bulk/status", {
5968
- giftCardIds,
5969
- status
5970
- });
6019
+ async bulkSetGiftCardStatus(giftCardIds, status, options) {
6020
+ return this.adminRequest(
6021
+ "PATCH",
6022
+ "/api/v1/gift-cards/bulk/status",
6023
+ { giftCardIds, status },
6024
+ void 0,
6025
+ "json",
6026
+ this.idempotencyHeaders(options)
6027
+ );
5971
6028
  }
5972
6029
  // ==========================================================================
5973
6030
  // Donations
@@ -6376,6 +6433,9 @@ var _BrainerceClient = class _BrainerceClient {
6376
6433
  /**
6377
6434
  * Set delivery type on checkout (shipping or pickup).
6378
6435
  *
6436
+ * **Storefront and vibe-coded modes only.** There is no admin (`apiKey`)
6437
+ * route for this, so an admin-mode client throws instead of 404ing.
6438
+ *
6379
6439
  * @example
6380
6440
  * ```typescript
6381
6441
  * const checkout = await client.setDeliveryType('checkout_123', 'pickup');
@@ -6400,12 +6460,9 @@ var _BrainerceClient = class _BrainerceClient {
6400
6460
  }
6401
6461
  );
6402
6462
  }
6403
- return this.adminRequest(
6404
- "PATCH",
6405
- `/api/v1/checkout/${encodePathSegment(checkoutId)}/delivery-type`,
6406
- {
6407
- deliveryType
6408
- }
6463
+ throw new BrainerceError(
6464
+ "setDeliveryType is not a route on the API-key /v1 surface. There is no checkout/:checkoutId/delivery-type endpoint to call, so the delivery type was not changed. Set it from the storefront session that owns the checkout \u2014 a client constructed with `salesChannelId` (vibe-coded) or `storeId` (public storefront) \u2014 or from the Brainerce dashboard.",
6465
+ 400
6409
6466
  );
6410
6467
  }
6411
6468
  /**
@@ -6413,6 +6470,9 @@ var _BrainerceClient = class _BrainerceClient {
6413
6470
  * This sets the delivery type to "pickup", records customer info, and prepares for payment.
6414
6471
  * Equivalent to setShippingAddress + selectShippingMethod for delivery orders.
6415
6472
  *
6473
+ * **Storefront and vibe-coded modes only.** There is no admin (`apiKey`)
6474
+ * route for this, so an admin-mode client throws instead of 404ing.
6475
+ *
6416
6476
  * @example
6417
6477
  * ```typescript
6418
6478
  * const checkout = await client.selectPickupLocation('checkout_123', {
@@ -6439,10 +6499,9 @@ var _BrainerceClient = class _BrainerceClient {
6439
6499
  data
6440
6500
  );
6441
6501
  }
6442
- return this.adminRequest(
6443
- "PATCH",
6444
- `/api/v1/checkout/${encodePathSegment(checkoutId)}/pickup-location`,
6445
- data
6502
+ throw new BrainerceError(
6503
+ "selectPickupLocation is not a route on the API-key /v1 surface. There is no checkout/:checkoutId/pickup-location endpoint to call, so no pickup location was selected. Select it from the storefront session that owns the checkout \u2014 a client constructed with `salesChannelId` (vibe-coded) or `storeId` (public storefront) \u2014 or from the Brainerce dashboard.",
6504
+ 400
6446
6505
  );
6447
6506
  }
6448
6507
  /**
@@ -7767,13 +7826,17 @@ var _BrainerceClient = class _BrainerceClient {
7767
7826
  * lifetime earned, the program's display config, earned milestone `badges`,
7768
7827
  * and the `paidMembership` subscription state (null for free members).
7769
7828
  * Requires customerToken. Only available in storefront mode. `program` is
7770
- * null when the store has no loyalty program.
7829
+ * null when the store has no loyalty program. `pointsBalance` excludes points
7830
+ * still inside the return window - those are in `pendingPoints`, and a panel
7831
+ * that ignores them shows a shopper 0 the day they order.
7771
7832
  *
7772
7833
  * @example
7773
7834
  * ```typescript
7774
7835
  * client.setCustomerToken(auth.token);
7775
7836
  * const status = await client.getLoyaltyStatus();
7776
7837
  * if (status.enrolled) console.log(`${status.pointsBalance} ${status.program?.pointsName}`);
7838
+ * // Points from an order just placed are in pendingPoints, NOT pointsBalance.
7839
+ * if (status.pendingPoints > 0) console.log(`+${status.pendingPoints} on ${status.pendingPointsConfirmAt}`);
7777
7840
  * status.badges?.forEach((b) => console.log(`🏅 ${b.name}`));
7778
7841
  * if (status.paidMembership?.status === 'ACTIVE') showPremiumPerks(status.paidMembership.plan);
7779
7842
  * ```
@@ -8620,11 +8683,28 @@ var _BrainerceClient = class _BrainerceClient {
8620
8683
  return this.adminRequest("POST", "/api/v1/tags", data);
8621
8684
  }
8622
8685
  /**
8623
- * Update an existing tag
8624
- * Requires Admin mode (apiKey)
8686
+ * Update an existing tag.
8687
+ *
8688
+ * **Not callable.** The API-key `/v1` surface serves `GET`, `POST` and
8689
+ * `DELETE` on tags (`external-api.controller.ts:3276`, `:3310`, `:3331`) but
8690
+ * no update verb — `PATCH /api/v1/tags/:id` 404'd silently. Tag editing lives
8691
+ * only on the dashboard surface (`PATCH /api/stores/:storeId/tags/:id`,
8692
+ * `tags.controller.ts:127`), which needs a `storeId` in the path that this
8693
+ * signature does not carry, and resolves the acting user from a dashboard
8694
+ * session an API key does not have.
8695
+ *
8696
+ * Edit the tag in the Brainerce dashboard. {@link deleteTag} +
8697
+ * {@link createTag} is NOT an equivalent workaround: it drops the tag's
8698
+ * product assignments, and `CreateTagDto` has no `translations` field, so any
8699
+ * per-locale names are lost too.
8625
8700
  */
8626
8701
  async updateTag(tagId, data) {
8627
- return this.adminRequest("PATCH", `/api/v1/tags/${encodePathSegment(tagId)}`, data);
8702
+ void tagId;
8703
+ void data;
8704
+ throw new BrainerceError(
8705
+ "updateTag is not a route on the API-key /v1 surface. Tags are served there for read, create and delete only, so the tag was not changed; edit it in the Brainerce dashboard. Deleting and recreating the tag is not equivalent \u2014 it drops the product assignments and the translations.",
8706
+ 400
8707
+ );
8628
8708
  }
8629
8709
  /**
8630
8710
  * Delete a tag
@@ -8722,24 +8802,41 @@ var _BrainerceClient = class _BrainerceClient {
8722
8802
  );
8723
8803
  }
8724
8804
  /**
8725
- * Update an attribute option
8726
- * Requires Admin mode (apiKey)
8805
+ * Update an attribute option.
8806
+ *
8807
+ * **Not callable.** The API-key `/v1` surface serves attribute options for
8808
+ * list and create only (`external-api.controller.ts:3517`, `:3543`); there is
8809
+ * no per-option route, so this 404'd silently. Editing an option lives on the
8810
+ * dashboard surface (`PUT /api/stores/:storeId/attributes/:id/options/:optionId`,
8811
+ * `attributes.controller.ts:132` — note it is `PUT` there, not `PATCH`), which
8812
+ * needs a path `storeId` this signature does not carry.
8813
+ *
8814
+ * Edit the option in the Brainerce dashboard.
8727
8815
  */
8728
8816
  async updateAttributeOption(attributeId, optionId, data) {
8729
- return this.adminRequest(
8730
- "PATCH",
8731
- `/api/v1/attributes/${encodePathSegment(attributeId)}/options/${encodePathSegment(optionId)}`,
8732
- data
8817
+ void attributeId;
8818
+ void optionId;
8819
+ void data;
8820
+ throw new BrainerceError(
8821
+ "updateAttributeOption is not a route on the API-key /v1 surface. Attribute options are served there for list and create only, so the option was not changed; edit it in the Brainerce dashboard.",
8822
+ 400
8733
8823
  );
8734
8824
  }
8735
8825
  /**
8736
- * Delete an attribute option
8737
- * Requires Admin mode (apiKey)
8826
+ * Delete an attribute option.
8827
+ *
8828
+ * **Not callable.** Same gap as {@link updateAttributeOption}: the `/v1`
8829
+ * surface has no per-option route. Deleting an option lives on the dashboard
8830
+ * surface (`DELETE /api/stores/:storeId/attributes/:id/options/:optionId`,
8831
+ * `attributes.controller.ts:145`), which needs a path `storeId` this signature
8832
+ * does not carry.
8738
8833
  */
8739
8834
  async deleteAttributeOption(attributeId, optionId) {
8740
- await this.adminRequest(
8741
- "DELETE",
8742
- `/api/v1/attributes/${encodePathSegment(attributeId)}/options/${encodePathSegment(optionId)}`
8835
+ void attributeId;
8836
+ void optionId;
8837
+ throw new BrainerceError(
8838
+ "deleteAttributeOption is not a route on the API-key /v1 surface. Attribute options are served there for list and create only, so nothing was deleted; delete the option in the Brainerce dashboard.",
8839
+ 400
8743
8840
  );
8744
8841
  }
8745
8842
  // -------------------- Modifier Groups (Admin) --------------------
@@ -9562,25 +9659,48 @@ var _BrainerceClient = class _BrainerceClient {
9562
9659
  // Products/Coupons. When no publishes exist for an entity, it remains
9563
9660
  // visible to all vibe-coded sites of the store (legacy default).
9564
9661
  /**
9565
- * Publish a metafield definition to a vibe-coded site (admin mode).
9566
- * @example
9567
- * ```typescript
9568
- * await client.publishMetafieldDefinitionToVibeCodedSite('def_123', 'conn_456');
9569
- * ```
9662
+ * Publish a metafield definition to a sales channel (admin mode).
9663
+ *
9664
+ * **Not callable.** This asked for `publish-vibe-coded`, which is a
9665
+ * deprecated backend alias, not the canonical route. The canonical spelling
9666
+ * is `publish-sales-channel`, and the `/v1` surface serves it for products
9667
+ * (`external-api.controller.ts:862`), coupons (`:947`), customers (`:1548`),
9668
+ * categories (`:3039`), brands (`:3211`) and tags (`:3349`) — but NOT for
9669
+ * metafield definitions. Both spellings 404 there.
9670
+ *
9671
+ * The operation exists only on the dashboard surface
9672
+ * (`POST /api/stores/:storeId/metafield-definitions/:id/publish-sales-channel`,
9673
+ * `metafields.controller.ts:190`), which needs a path `storeId` this signature
9674
+ * does not carry.
9675
+ *
9676
+ * Publish the definition to a sales channel from the Brainerce dashboard. A
9677
+ * definition with no publishes stays visible to every sales channel of the
9678
+ * store, so leaving it unpublished is the permissive default, not a lockout.
9570
9679
  */
9571
9680
  async publishMetafieldDefinitionToVibeCodedSite(definitionId, vibeCodedConnectionId) {
9572
- return this.adminRequest(
9573
- "POST",
9574
- `/api/v1/metafield-definitions/${encodePathSegment(definitionId)}/publish-vibe-coded`,
9575
- { vibeCodedConnectionId }
9681
+ void definitionId;
9682
+ void vibeCodedConnectionId;
9683
+ throw new BrainerceError(
9684
+ "publishMetafieldDefinitionToVibeCodedSite is not a route on the API-key /v1 surface. Per-sales-channel publishing is served there for products, coupons, customers, categories, brands and tags, but not for metafield definitions, so nothing was published; publish it in the Brainerce dashboard. A definition with no publishes remains visible to every sales channel of the store.",
9685
+ 400
9576
9686
  );
9577
9687
  }
9578
- /** Unpublish a metafield definition from a vibe-coded site (admin mode). */
9688
+ /**
9689
+ * Unpublish a metafield definition from a sales channel (admin mode).
9690
+ *
9691
+ * **Not callable.** Same gap as
9692
+ * {@link publishMetafieldDefinitionToVibeCodedSite} — the `/v1` surface
9693
+ * carries no per-sales-channel routes for metafield definitions under either
9694
+ * the canonical `unpublish-sales-channel` spelling or the deprecated
9695
+ * `unpublish-vibe-coded` alias. The dashboard route is
9696
+ * `metafields.controller.ts:217`.
9697
+ */
9579
9698
  async unpublishMetafieldDefinitionFromVibeCodedSite(definitionId, vibeCodedConnectionId) {
9580
- return this.adminRequest(
9581
- "POST",
9582
- `/api/v1/metafield-definitions/${encodePathSegment(definitionId)}/unpublish-vibe-coded`,
9583
- { vibeCodedConnectionId }
9699
+ void definitionId;
9700
+ void vibeCodedConnectionId;
9701
+ throw new BrainerceError(
9702
+ "unpublishMetafieldDefinitionFromVibeCodedSite is not a route on the API-key /v1 surface. Per-sales-channel publishing is served there for products, coupons, customers, categories, brands and tags, but not for metafield definitions, so nothing was unpublished; unpublish it in the Brainerce dashboard.",
9703
+ 400
9584
9704
  );
9585
9705
  }
9586
9706
  /**
@@ -9726,10 +9846,11 @@ var _BrainerceClient = class _BrainerceClient {
9726
9846
  * ```
9727
9847
  */
9728
9848
  async setDefinitionProducts(definitionId, data) {
9729
- return this.adminRequest(
9730
- "PATCH",
9731
- `/api/v1/metafield-definitions/${encodePathSegment(definitionId)}/products`,
9732
- data
9849
+ void definitionId;
9850
+ void data;
9851
+ throw new BrainerceError(
9852
+ "setDefinitionProducts is not a route on the API-key /v1 surface. There is no metafield-definitions/:id/products endpoint to call, so the definition's product list was not changed; set it in the Brainerce dashboard.",
9853
+ 400
9733
9854
  );
9734
9855
  }
9735
9856
  // -------------------- Metafields: Product Values --------------------
@@ -9775,24 +9896,41 @@ var _BrainerceClient = class _BrainerceClient {
9775
9896
  // -------------------- Product Customization Fields (Admin) --------------------
9776
9897
  /**
9777
9898
  * Get customization fields assigned to a product.
9778
- * Requires Admin mode (apiKey).
9899
+ *
9900
+ * **Not callable.** The API-key `/v1` surface has no
9901
+ * `metafield-definitions/products/:productId/customization-fields` route, so
9902
+ * this 404'd silently. It exists only on the dashboard surface
9903
+ * (`GET /api/stores/:storeId/metafield-definitions/products/:productId/customization-fields`,
9904
+ * `metafields.controller.ts:277`), which needs a path `storeId` this signature
9905
+ * does not carry.
9906
+ *
9907
+ * {@link getProductMetafields} is the closest working call — it returns the
9908
+ * metafield VALUES stored on a product over
9909
+ * `GET /api/v1/products/:productId/metafields`, not the customer-input field
9910
+ * definitions attached to it.
9779
9911
  */
9780
9912
  async getProductCustomizationFields(productId) {
9781
- return this.adminRequest(
9782
- "GET",
9783
- `/api/v1/metafield-definitions/products/${encodePathSegment(productId)}/customization-fields`
9913
+ void productId;
9914
+ throw new BrainerceError(
9915
+ "getProductCustomizationFields is not a route on the API-key /v1 surface. There is no metafield-definitions/products/:productId/customization-fields endpoint to call; read the assignments in the Brainerce dashboard. getProductMetafields returns the product's stored metafield values, which is a different thing.",
9916
+ 400
9784
9917
  );
9785
9918
  }
9786
9919
  /**
9787
9920
  * Set customization fields for a product (replaces all existing assignments).
9788
- * Only definitions marked as `isCustomerInput: true` can be assigned.
9789
- * Requires Admin mode (apiKey).
9921
+ *
9922
+ * **Not callable.** Same gap as {@link getProductCustomizationFields}: the
9923
+ * `/v1` surface carries no customization-field routes. The dashboard route is
9924
+ * `PATCH /api/stores/:storeId/metafield-definitions/products/:productId/customization-fields`
9925
+ * (`metafields.controller.ts:298`), which needs a path `storeId` this
9926
+ * signature does not carry.
9790
9927
  */
9791
9928
  async setProductCustomizationFields(productId, definitionIds) {
9792
- return this.adminRequest(
9793
- "PATCH",
9794
- `/api/v1/metafield-definitions/products/${encodePathSegment(productId)}/customization-fields`,
9795
- { definitionIds }
9929
+ void productId;
9930
+ void definitionIds;
9931
+ throw new BrainerceError(
9932
+ "setProductCustomizationFields is not a route on the API-key /v1 surface. There is no metafield-definitions/products/:productId/customization-fields endpoint to call, so the assignments were not changed; set them in the Brainerce dashboard.",
9933
+ 400
9796
9934
  );
9797
9935
  }
9798
9936
  /**
@@ -11187,6 +11325,7 @@ function buildProductJsonLd(product, opts) {
11187
11325
  const inv = product.inventory;
11188
11326
  const availability = !inv ? "https://schema.org/InStock" : inv.inStock ?? (inv.available ?? 0) > 0 ? "https://schema.org/InStock" : inv.canPurchase ? "https://schema.org/BackOrder" : "https://schema.org/OutOfStock";
11189
11327
  const isVariable = product.type === "VARIABLE" && product.priceMin && product.priceMax;
11328
+ const omitOffer = product.type === "KIT";
11190
11329
  const itemCondition = "https://schema.org/NewCondition";
11191
11330
  const shippingDetails = (opts.shipping ?? []).filter((z) => z.amount !== null).map((z) => ({
11192
11331
  "@type": "OfferShippingDetails",
@@ -11249,7 +11388,7 @@ function buildProductJsonLd(product, opts) {
11249
11388
  ...product.gtin ? { gtin: product.gtin } : {},
11250
11389
  ...product.mpn ? { mpn: product.mpn } : {},
11251
11390
  ...brand ? { brand: { "@type": "Brand", name: brand } } : {},
11252
- offers: offer,
11391
+ ...omitOffer ? {} : { offers: offer },
11253
11392
  // Google policy: never emit an empty/zero rating block. bestRating /
11254
11393
  // worstRating make the 1-5 scale explicit so aggregators can't misread
11255
11394
  // a 4.8 on an assumed 0-10 scale.