brainerce 2.3.0 → 2.5.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
@@ -776,6 +776,52 @@ interface ProductMetafield {
776
776
  * platform. Archiving exists for modifier groups and modifiers, not products.
777
777
  */
778
778
  type ProductStatus = 'active' | 'draft';
779
+ /** One product inside a KIT, as the storefront sees it. Display only. */
780
+ interface KitComponentSummary {
781
+ productId: string;
782
+ /** Set when the kit pins one variant of a variable component. */
783
+ variantId: string | null;
784
+ /** Component name, variant included when one is pinned. */
785
+ name: string;
786
+ sku: string | null;
787
+ /** Units of this component in ONE kit. A box with two glasses reads `2`. */
788
+ quantity: number;
789
+ /** Thumbnail: the pinned variant's image, else the product's first. */
790
+ image: string | null;
791
+ }
792
+ /** A kit's contents and derived pricing, from `getKitComponents`. */
793
+ interface KitDetail {
794
+ components: Array<KitComponentSummary & {
795
+ id: string;
796
+ position: number;
797
+ /** Effective unit price of the component. String decimal. */
798
+ unitPrice: string;
799
+ /** `null` = not stock-tracked, and never limits the kit. */
800
+ available: number | null;
801
+ }>;
802
+ /** How the kit is priced. */
803
+ pricingMode: 'FIXED' | 'SUM' | 'SUM_MINUS_PERCENT';
804
+ /** Percent off the component sum. Only for `SUM_MINUS_PERCENT`. */
805
+ discountValue: number | null;
806
+ /** Resolved kit price. String decimal. */
807
+ price: string;
808
+ /**
809
+ * How `price` divides across the components, in order, in MINOR units.
810
+ * Sums exactly to `price`. This is the taxable amount per component and the
811
+ * credit amount per component on a refund.
812
+ */
813
+ allocationMinor: number[];
814
+ /** Sellable kits. `null` = unlimited; `0` = not sellable. */
815
+ available: number | null;
816
+ }
817
+ /** One component slot to write with `setKitComponents`. */
818
+ interface KitComponentWriteInput {
819
+ componentProductId: string;
820
+ /** Required when the component product is VARIABLE. */
821
+ componentVariantId?: string | null;
822
+ /** Units of this component in ONE kit. */
823
+ quantity: number;
824
+ }
779
825
  interface Product {
780
826
  id: string;
781
827
  name: string;
@@ -866,12 +912,46 @@ interface Product {
866
912
  /** Product status (active, draft). Always returned by backend. */
867
913
  status: ProductStatus;
868
914
  /**
869
- * Catalog structure. `KIT` is a sellable kit ("maaraz") whose price and
870
- * availability derive from its component products it carries no inventory
871
- * row of its own, and outside FIXED pricing its `basePrice` is a placeholder.
872
- * Treat it as not-directly-purchasable unless you resolve its components.
915
+ * Catalog structure. `KIT` is a sellable kit ("maaraz") assembled from other
916
+ * catalog products. It IS directly purchasable: add the KIT'S OWN `productId`
917
+ * as ONE cart line, with no `variantId` (a kit has no variants and passing
918
+ * one is rejected) and no modifier `selections`. NEVER add its components as
919
+ * separate lines — that charges twice and reserves twice. It carries no
920
+ * inventory row of its own (read `kitAvailable`), and outside FIXED pricing
921
+ * its stored `basePrice` is a placeholder, though storefront reads overlay it
922
+ * with the resolved price.
873
923
  */
874
924
  type: 'SIMPLE' | 'VARIABLE' | 'KIT';
925
+ /**
926
+ * What a KIT contains, returned on the single-product (by slug) read only.
927
+ * Absent on every other product type and on list responses.
928
+ *
929
+ * Render it: a shopper looking at a gift box needs to see what is inside
930
+ * before buying. These are display rows, NOT separate line items — the kit is
931
+ * added to the cart as ONE line, and its components are reserved behind the
932
+ * scenes. Do not add them individually.
933
+ */
934
+ kitComponents?: KitComponentSummary[];
935
+ /**
936
+ * How many of this KIT can be sold: the component that runs out first decides.
937
+ * `null` means unlimited (every component untracked). `0` means not sellable,
938
+ * including a kit with no components. Absent on non-kits — a kit has no
939
+ * `inventory` block, so this is the field to read for stock.
940
+ */
941
+ kitAvailable?: number | null;
942
+ /**
943
+ * How this KIT is priced, and therefore whether its prices are real numbers
944
+ * or placeholders. Absent on non-kits.
945
+ *
946
+ * `FIXED` — `basePrice` and `salePrice` are the merchant's own values and
947
+ * behave exactly like any other product's, sale logic included.
948
+ * `SUM` / `SUM_MINUS_PERCENT` — the price is recomputed from the components on
949
+ * every read, so the storefront read overlays `basePrice` with the resolved
950
+ * figure and returns `salePrice: null`. Never cache a kit price or recompute
951
+ * one client-side in these modes, and do not present a "was" price: there
952
+ * isn't one.
953
+ */
954
+ kitPricingMode?: 'FIXED' | 'SUM' | 'SUM_MINUS_PERCENT';
875
955
  /** Whether product is downloadable/digital. */
876
956
  isDownloadable?: boolean;
877
957
  /** Download files available for this product (when isDownloadable is true) */
@@ -1806,6 +1886,15 @@ interface CreateProductDto {
1806
1886
  * its contents set before it can be sold.
1807
1887
  */
1808
1888
  type?: 'SIMPLE' | 'VARIABLE' | 'KIT';
1889
+ /**
1890
+ * How a `KIT` is priced. `FIXED` (default) — you set `basePrice` and it stays.
1891
+ * `SUM` — the kit costs what its components cost, recomputed on every read.
1892
+ * `SUM_MINUS_PERCENT` — that sum less `kitDiscountValue` percent.
1893
+ * Ignored on `SIMPLE` and `VARIABLE`.
1894
+ */
1895
+ kitPricingMode?: 'FIXED' | 'SUM' | 'SUM_MINUS_PERCENT';
1896
+ /** Percent off the component sum, 0-100. Only for `SUM_MINUS_PERCENT`. */
1897
+ kitDiscountValue?: number;
1809
1898
  isDownloadable?: boolean;
1810
1899
  /** Existing category IDs to assign. Unknown/cross-store IDs are rejected with 400. To assign by name (auto-creating if missing), use `categoryNames`. */
1811
1900
  categories?: string[];
@@ -1927,6 +2016,15 @@ interface BulkCreateProductsError {
1927
2016
  message: string;
1928
2017
  }
1929
2018
  interface UpdateProductDto {
2019
+ /**
2020
+ * How a `KIT` is priced. `FIXED` (default) — you set `basePrice` and it stays.
2021
+ * `SUM` — the kit costs what its components cost, recomputed on every read.
2022
+ * `SUM_MINUS_PERCENT` — that sum less `kitDiscountValue` percent.
2023
+ * Omit to leave the kit's current mode unchanged.
2024
+ */
2025
+ kitPricingMode?: 'FIXED' | 'SUM' | 'SUM_MINUS_PERCENT';
2026
+ /** Percent off the component sum, 0-100. Only for `SUM_MINUS_PERCENT`. */
2027
+ kitDiscountValue?: number;
1930
2028
  name?: string;
1931
2029
  slug?: string;
1932
2030
  sku?: string;
@@ -3401,8 +3499,20 @@ interface TaxBreakdownItem {
3401
3499
  * ```
3402
3500
  */
3403
3501
  interface TaxBreakdown {
3404
- /** Subtotal before tax */
3502
+ /**
3503
+ * Subtotal before tax — and it INCLUDES the shipping net.
3504
+ *
3505
+ * Rendering `subtotal + shipping + tax` therefore counts shipping twice. Use
3506
+ * `subtotal - shippingNet` for a goods-only row beside a separate shipping
3507
+ * line, or the three rows will not add up to the total you are charging.
3508
+ */
3405
3509
  subtotal: number;
3510
+ /**
3511
+ * The shipping net already counted inside `subtotal`. Zero when there is no
3512
+ * shipping. Subtract this rather than the gross `shippingAmount`: they differ
3513
+ * whenever shipping is taxed.
3514
+ */
3515
+ shippingNet?: number;
3406
3516
  /** Total tax amount */
3407
3517
  totalTax: number;
3408
3518
  /** Total including tax */
@@ -8579,6 +8689,52 @@ declare class BrainerceClient {
8579
8689
  * console.log('Product type:', product.type); // 'VARIABLE'
8580
8690
  * ```
8581
8691
  */
8692
+ /**
8693
+ * Read a kit's contents, with its resolved price and how many can be sold.
8694
+ *
8695
+ * A KIT is one purchasable product assembled from other catalog products. It
8696
+ * holds no inventory of its own: `available` is whichever component runs out
8697
+ * first. Outside `FIXED` pricing the product row's `basePrice` is a
8698
+ * placeholder, so use the `price` returned here.
8699
+ *
8700
+ * Safe to call for any product — a non-KIT returns an empty, unsellable
8701
+ * shape rather than throwing, so callers need not branch on product type.
8702
+ *
8703
+ * @example
8704
+ * ```typescript
8705
+ * const kit = await client.getKitComponents('prod_123');
8706
+ * console.log(kit.price, kit.available, kit.components.length);
8707
+ * ```
8708
+ */
8709
+ getKitComponents(productId: string): Promise<KitDetail>;
8710
+ /**
8711
+ * Replace a kit's contents, and optionally how it is priced.
8712
+ *
8713
+ * A full replace, not a patch: send the list you want the kit to end up with.
8714
+ * Omit `pricingMode` to leave the kit's current mode untouched.
8715
+ *
8716
+ * Rejected: a product that is not a KIT, a component from another store, a
8717
+ * component that is itself a KIT, a VARIABLE component with no variant
8718
+ * pinned, a variant that does not belong to its product, and the same slot
8719
+ * listed twice.
8720
+ *
8721
+ * @example
8722
+ * ```typescript
8723
+ * await client.setKitComponents('prod_123', {
8724
+ * components: [
8725
+ * { componentProductId: 'prod_bottle', quantity: 1 },
8726
+ * { componentProductId: 'prod_glass', quantity: 2 },
8727
+ * ],
8728
+ * pricingMode: 'SUM_MINUS_PERCENT',
8729
+ * discountValue: 10,
8730
+ * });
8731
+ * ```
8732
+ */
8733
+ setKitComponents(productId: string, body: {
8734
+ components: KitComponentWriteInput[];
8735
+ pricingMode?: 'FIXED' | 'SUM' | 'SUM_MINUS_PERCENT';
8736
+ discountValue?: number;
8737
+ }): Promise<KitDetail>;
8582
8738
  convertToVariable(productId: string): Promise<Product>;
8583
8739
  /**
8584
8740
  * Convert a VARIABLE product back to SIMPLE.
@@ -9789,10 +9945,20 @@ declare class BrainerceClient {
9789
9945
  * Rich Text, and Page.
9790
9946
  *
9791
9947
  * Works in all three SDK modes (vibe-coded, storefront, admin):
9792
- * - **Public reads** (`get`, `list`, `getBySlug`): work in any mode.
9793
- * - **Write operations** (`create`, `update`, `publish`, `unpublish`,
9794
- * `remove`): admin mode only they call `/api/content/...` with
9795
- * the API key. Calling from storefront / vibe-coded mode throws.
9948
+ * - **Public reads** (`get`, `list`, `getBySlug`): storefront and
9949
+ * vibe-coded mode. There is no admin equivalent of a by-key/by-slug
9950
+ * read — in admin mode they throw and point you at `listAdmin()` /
9951
+ * `findById()`.
9952
+ * - **Admin reads** (`listAdmin`, `findById`) and **writes** (`create`,
9953
+ * `update`, `publish`, `unpublish`, `remove`): admin mode only — they
9954
+ * call `/api/content/...` with the API key. Calling from storefront /
9955
+ * vibe-coded mode throws.
9956
+ *
9957
+ * **⚠️ Every admin method takes an explicit `storeId`.** Admin mode has no
9958
+ * ambient store (`storeId` is only set in storefront mode), and the routes
9959
+ * are store-scoped: omitting it is rejected fail-closed by the store scope
9960
+ * guard (`403 STORE_SCOPE_REQUIRED`). Pass the id of the store your API key
9961
+ * is bound to — naming any other store is rejected as cross-tenant.
9796
9962
  *
9797
9963
  * **Default key:** every type has `'main'` as its universal default key.
9798
9964
  * Pass no argument to fetch the main entry; pass a custom key (e.g.
@@ -9817,12 +9983,15 @@ declare class BrainerceClient {
9817
9983
  * });
9818
9984
  * }
9819
9985
  *
9820
- * // Admin — create a shipping FAQ in DRAFT
9821
- * await client.content.faq.create({
9822
- * key: 'shipping',
9823
- * name: 'Shipping FAQ',
9824
- * data: { items: [{ question: '…', answer: '…' }] },
9825
- * });
9986
+ * // Admin — create a shipping FAQ in DRAFT (storeId is required)
9987
+ * await client.content.faq.create(
9988
+ * {
9989
+ * key: 'shipping',
9990
+ * name: 'Shipping FAQ',
9991
+ * data: { items: [{ question: '…', answer: '…' }] },
9992
+ * },
9993
+ * 'store_123'
9994
+ * );
9826
9995
  * ```
9827
9996
  */
9828
9997
  content: {
@@ -9833,10 +10002,17 @@ declare class BrainerceClient {
9833
10002
  * hasn't seeded yet.
9834
10003
  */
9835
10004
  get: (key?: string, locale?: string) => Promise<Content<"FAQ"> | null>;
9836
- /** List all PUBLISHED entries of this type. */
10005
+ /**
10006
+ * List all PUBLISHED entries of this type (storefront / vibe-coded
10007
+ * mode). In admin mode this throws — use
10008
+ * `client.content.listAdmin({ storeId, type })`.
10009
+ */
9837
10010
  list: (locale?: string) => Promise<Content<"FAQ">[]>;
9838
- /** Create a new entry in DRAFT (admin mode). */
9839
- create: (input: Omit<CreateContentInput<"FAQ">, "type">) => Promise<Content<"FAQ">>;
10011
+ /**
10012
+ * Create a new entry in DRAFT (admin mode).
10013
+ * `storeId` is required — see the namespace docs above.
10014
+ */
10015
+ create: (input: Omit<CreateContentInput<"FAQ">, "type">, storeId: string) => Promise<Content<"FAQ">>;
9840
10016
  };
9841
10017
  footer: {
9842
10018
  /**
@@ -9845,10 +10021,17 @@ declare class BrainerceClient {
9845
10021
  * hasn't seeded yet.
9846
10022
  */
9847
10023
  get: (key?: string, locale?: string) => Promise<Content<"FOOTER"> | null>;
9848
- /** List all PUBLISHED entries of this type. */
10024
+ /**
10025
+ * List all PUBLISHED entries of this type (storefront / vibe-coded
10026
+ * mode). In admin mode this throws — use
10027
+ * `client.content.listAdmin({ storeId, type })`.
10028
+ */
9849
10029
  list: (locale?: string) => Promise<Content<"FOOTER">[]>;
9850
- /** Create a new entry in DRAFT (admin mode). */
9851
- create: (input: Omit<CreateContentInput<"FOOTER">, "type">) => Promise<Content<"FOOTER">>;
10030
+ /**
10031
+ * Create a new entry in DRAFT (admin mode).
10032
+ * `storeId` is required — see the namespace docs above.
10033
+ */
10034
+ create: (input: Omit<CreateContentInput<"FOOTER">, "type">, storeId: string) => Promise<Content<"FOOTER">>;
9852
10035
  };
9853
10036
  header: {
9854
10037
  /**
@@ -9857,10 +10040,17 @@ declare class BrainerceClient {
9857
10040
  * hasn't seeded yet.
9858
10041
  */
9859
10042
  get: (key?: string, locale?: string) => Promise<Content<"HEADER"> | null>;
9860
- /** List all PUBLISHED entries of this type. */
10043
+ /**
10044
+ * List all PUBLISHED entries of this type (storefront / vibe-coded
10045
+ * mode). In admin mode this throws — use
10046
+ * `client.content.listAdmin({ storeId, type })`.
10047
+ */
9861
10048
  list: (locale?: string) => Promise<Content<"HEADER">[]>;
9862
- /** Create a new entry in DRAFT (admin mode). */
9863
- create: (input: Omit<CreateContentInput<"HEADER">, "type">) => Promise<Content<"HEADER">>;
10049
+ /**
10050
+ * Create a new entry in DRAFT (admin mode).
10051
+ * `storeId` is required — see the namespace docs above.
10052
+ */
10053
+ create: (input: Omit<CreateContentInput<"HEADER">, "type">, storeId: string) => Promise<Content<"HEADER">>;
9864
10054
  };
9865
10055
  announcement: {
9866
10056
  /**
@@ -9869,10 +10059,17 @@ declare class BrainerceClient {
9869
10059
  * hasn't seeded yet.
9870
10060
  */
9871
10061
  get: (key?: string, locale?: string) => Promise<Content<"ANNOUNCEMENT"> | null>;
9872
- /** List all PUBLISHED entries of this type. */
10062
+ /**
10063
+ * List all PUBLISHED entries of this type (storefront / vibe-coded
10064
+ * mode). In admin mode this throws — use
10065
+ * `client.content.listAdmin({ storeId, type })`.
10066
+ */
9873
10067
  list: (locale?: string) => Promise<Content<"ANNOUNCEMENT">[]>;
9874
- /** Create a new entry in DRAFT (admin mode). */
9875
- create: (input: Omit<CreateContentInput<"ANNOUNCEMENT">, "type">) => Promise<Content<"ANNOUNCEMENT">>;
10068
+ /**
10069
+ * Create a new entry in DRAFT (admin mode).
10070
+ * `storeId` is required — see the namespace docs above.
10071
+ */
10072
+ create: (input: Omit<CreateContentInput<"ANNOUNCEMENT">, "type">, storeId: string) => Promise<Content<"ANNOUNCEMENT">>;
9876
10073
  };
9877
10074
  richText: {
9878
10075
  /**
@@ -9881,10 +10078,17 @@ declare class BrainerceClient {
9881
10078
  * hasn't seeded yet.
9882
10079
  */
9883
10080
  get: (key?: string, locale?: string) => Promise<Content<"RICH_TEXT"> | null>;
9884
- /** List all PUBLISHED entries of this type. */
10081
+ /**
10082
+ * List all PUBLISHED entries of this type (storefront / vibe-coded
10083
+ * mode). In admin mode this throws — use
10084
+ * `client.content.listAdmin({ storeId, type })`.
10085
+ */
9885
10086
  list: (locale?: string) => Promise<Content<"RICH_TEXT">[]>;
9886
- /** Create a new entry in DRAFT (admin mode). */
9887
- create: (input: Omit<CreateContentInput<"RICH_TEXT">, "type">) => Promise<Content<"RICH_TEXT">>;
10087
+ /**
10088
+ * Create a new entry in DRAFT (admin mode).
10089
+ * `storeId` is required — see the namespace docs above.
10090
+ */
10091
+ create: (input: Omit<CreateContentInput<"RICH_TEXT">, "type">, storeId: string) => Promise<Content<"RICH_TEXT">>;
9888
10092
  };
9889
10093
  page: {
9890
10094
  /**
@@ -9899,62 +10103,191 @@ declare class BrainerceClient {
9899
10103
  * hasn't seeded yet.
9900
10104
  */
9901
10105
  get: (key?: string, locale?: string) => Promise<Content<"PAGE"> | null>;
9902
- /** List all PUBLISHED entries of this type. */
10106
+ /**
10107
+ * List all PUBLISHED entries of this type (storefront / vibe-coded
10108
+ * mode). In admin mode this throws — use
10109
+ * `client.content.listAdmin({ storeId, type })`.
10110
+ */
9903
10111
  list: (locale?: string) => Promise<Content<"PAGE">[]>;
9904
- /** Create a new entry in DRAFT (admin mode). */
9905
- create: (input: Omit<CreateContentInput<"PAGE">, "type">) => Promise<Content<"PAGE">>;
10112
+ /**
10113
+ * Create a new entry in DRAFT (admin mode).
10114
+ * `storeId` is required — see the namespace docs above.
10115
+ */
10116
+ create: (input: Omit<CreateContentInput<"PAGE">, "type">, storeId: string) => Promise<Content<"PAGE">>;
9906
10117
  };
9907
- /** Find a single row by its admin id (admin mode). */
9908
- findById: <T_1 extends ContentType = ContentType>(id: string) => Promise<Content<T_1>>;
9909
- /** List rows in admin mode with optional filters. */
9910
- listAdmin: <T_1 extends ContentType = ContentType>(filters?: {
10118
+ /**
10119
+ * Find a single row by its admin id (admin mode).
10120
+ *
10121
+ * @example
10122
+ * ```typescript
10123
+ * const row = await client.content.findById('cnt_123', 'store_123');
10124
+ * ```
10125
+ */
10126
+ findById: <T_1 extends ContentType = ContentType>(id: string, storeId: string) => Promise<Content<T_1>>;
10127
+ /**
10128
+ * List rows in admin mode. `storeId` is required; `type` and `status`
10129
+ * are optional filters.
10130
+ *
10131
+ * @example
10132
+ * ```typescript
10133
+ * const faqs = await client.content.listAdmin({
10134
+ * storeId: 'store_123',
10135
+ * type: 'FAQ',
10136
+ * status: 'DRAFT',
10137
+ * });
10138
+ * ```
10139
+ */
10140
+ listAdmin: <T_1 extends ContentType = ContentType>(filters: {
10141
+ storeId: string;
9911
10142
  type?: T_1;
9912
10143
  status?: "DRAFT" | "PUBLISHED";
9913
10144
  }) => Promise<Array<Content<T_1>>>;
9914
- /** Replace `data` (and optional metadata) on an existing row. */
9915
- update: <T_1 extends ContentType>(id: string, input: UpdateContentInput<T_1>) => Promise<Content<T_1>>;
9916
- /** Transition status DRAFT → PUBLISHED. */
9917
- publish: (id: string) => Promise<Content>;
9918
- /** Transition status PUBLISHED → DRAFT. */
9919
- unpublish: (id: string) => Promise<Content>;
9920
- /** Hard delete the row. Admin mode only. */
9921
- remove: (id: string) => Promise<void>;
10145
+ /**
10146
+ * Replace `data` (and optional metadata) on an existing row.
10147
+ *
10148
+ * @example
10149
+ * ```typescript
10150
+ * await client.content.update('cnt_123', { name: 'Shipping FAQ' }, 'store_123');
10151
+ * ```
10152
+ */
10153
+ update: <T_1 extends ContentType>(id: string, input: UpdateContentInput<T_1>, storeId: string) => Promise<Content<T_1>>;
10154
+ /**
10155
+ * Transition status DRAFT → PUBLISHED.
10156
+ *
10157
+ * @example
10158
+ * ```typescript
10159
+ * await client.content.publish('cnt_123', 'store_123');
10160
+ * ```
10161
+ */
10162
+ publish: (id: string, storeId: string) => Promise<Content>;
10163
+ /**
10164
+ * Transition status PUBLISHED → DRAFT.
10165
+ *
10166
+ * @example
10167
+ * ```typescript
10168
+ * await client.content.unpublish('cnt_123', 'store_123');
10169
+ * ```
10170
+ */
10171
+ unpublish: (id: string, storeId: string) => Promise<Content>;
10172
+ /**
10173
+ * Hard delete the row. Admin mode only.
10174
+ *
10175
+ * @example
10176
+ * ```typescript
10177
+ * await client.content.remove('cnt_123', 'store_123');
10178
+ * ```
10179
+ */
10180
+ remove: (id: string, storeId: string) => Promise<void>;
9922
10181
  };
9923
10182
  /**
9924
10183
  * Read and manage blog posts.
9925
10184
  *
10185
+ * **⚠️ Every admin call takes an explicit `storeId`.** Admin mode has no
10186
+ * ambient store (`storeId` is only set in storefront mode) and the admin
10187
+ * routes are store-scoped: omitting it is rejected fail-closed by the store
10188
+ * scope guard (`403 STORE_SCOPE_REQUIRED`). Pass the id of the store your
10189
+ * API key is bound to — naming any other store is rejected as cross-tenant.
10190
+ *
10191
+ * Admin lookups are **by id**, not by slug (`getPost(slug)` is a public read
10192
+ * and throws in admin mode — use `findById(id, storeId)`).
10193
+ *
9926
10194
  * ```typescript
9927
10195
  * // Storefront / vibe-coded: list published posts
9928
10196
  * const { data: posts } = await brainerce.blog.getPosts({ category: 'news' });
9929
10197
  *
9930
- * // Fetch one by slug
10198
+ * // Fetch one by slug (storefront / vibe-coded)
9931
10199
  * const post = await brainerce.blog.getPost('my-first-post');
9932
10200
  *
9933
- * // Admin: create a draft
9934
- * const draft = await brainerce.blog.create({ title: 'Hello World' });
10201
+ * // Admin: list, read one, and create a draft
10202
+ * const all = await brainerce.blog.getPosts({}, 'store_123');
10203
+ * const one = await brainerce.blog.findById('post_123', 'store_123');
10204
+ * const draft = await brainerce.blog.create({ title: 'Hello World' }, 'store_123');
9935
10205
  * ```
9936
10206
  */
9937
10207
  blog: {
9938
10208
  /**
9939
- * List published posts. Works in all modes.
9940
- * Filters: `category`, `tag`, `page`, `limit`.
10209
+ * List posts. Filters: `category`, `tag`, `page`, `limit`.
10210
+ *
10211
+ * Storefront / vibe-coded mode lists PUBLISHED posts and ignores
10212
+ * `storeId` (the store is already in the base URL). Admin mode lists
10213
+ * drafts too and REQUIRES `storeId`.
10214
+ *
10215
+ * @example
10216
+ * ```typescript
10217
+ * const { data } = await client.blog.getPosts({ category: 'news' }); // storefront
10218
+ * const { data } = await client.blog.getPosts({}, 'store_123'); // admin
10219
+ * ```
9941
10220
  */
9942
- getPosts: (params?: BlogPostListParams) => Promise<BlogPostListResponse>;
10221
+ getPosts: (params?: BlogPostListParams, storeId?: string) => Promise<BlogPostListResponse>;
9943
10222
  /**
9944
- * Fetch one published post by its slug. Returns `null` on 404.
9945
- * Works in all modes.
10223
+ * Fetch one PUBLISHED post by its slug. Returns `null` on 404.
10224
+ *
10225
+ * Storefront / vibe-coded mode only — the admin API has no by-slug
10226
+ * lookup (`GET /api/blog/posts/:id` is by id), so this throws in admin
10227
+ * mode rather than issuing a request that can only 404.
10228
+ *
10229
+ * @example
10230
+ * ```typescript
10231
+ * const post = await client.blog.getPost('my-first-post');
10232
+ * ```
9946
10233
  */
9947
10234
  getPost: (slug: string) => Promise<BlogPost | null>;
9948
- /** Create a blog post in DRAFT status. Admin mode only. */
9949
- create: (input: CreateBlogPostInput) => Promise<BlogPost>;
9950
- /** Update a blog post by ID. Admin mode only. */
9951
- update: (id: string, input: UpdateBlogPostInput) => Promise<BlogPost>;
9952
- /** Transition status → PUBLISHED (sets publishedAt = now if unset). Admin mode only. */
9953
- publish: (id: string) => Promise<BlogPost>;
9954
- /** Transition status PUBLISHED DRAFT. Admin mode only. */
9955
- unpublish: (id: string) => Promise<BlogPost>;
9956
- /** Hard-delete a blog post. Admin mode only. */
9957
- remove: (id: string) => Promise<void>;
10235
+ /**
10236
+ * Fetch one post by its admin id — drafts included. Admin mode only.
10237
+ * Returns `null` on 404.
10238
+ *
10239
+ * @example
10240
+ * ```typescript
10241
+ * const post = await client.blog.findById('post_123', 'store_123');
10242
+ * ```
10243
+ */
10244
+ findById: (id: string, storeId: string) => Promise<BlogPost | null>;
10245
+ /**
10246
+ * Create a blog post in DRAFT status. Admin mode only.
10247
+ *
10248
+ * @example
10249
+ * ```typescript
10250
+ * const draft = await client.blog.create({ title: 'Hello World' }, 'store_123');
10251
+ * ```
10252
+ */
10253
+ create: (input: CreateBlogPostInput, storeId: string) => Promise<BlogPost>;
10254
+ /**
10255
+ * Update a blog post by ID. Admin mode only.
10256
+ *
10257
+ * @example
10258
+ * ```typescript
10259
+ * await client.blog.update('post_123', { title: 'Renamed' }, 'store_123');
10260
+ * ```
10261
+ */
10262
+ update: (id: string, input: UpdateBlogPostInput, storeId: string) => Promise<BlogPost>;
10263
+ /**
10264
+ * Transition status → PUBLISHED (sets publishedAt = now if unset).
10265
+ * Admin mode only.
10266
+ *
10267
+ * @example
10268
+ * ```typescript
10269
+ * await client.blog.publish('post_123', 'store_123');
10270
+ * ```
10271
+ */
10272
+ publish: (id: string, storeId: string) => Promise<BlogPost>;
10273
+ /**
10274
+ * Transition status PUBLISHED → DRAFT. Admin mode only.
10275
+ *
10276
+ * @example
10277
+ * ```typescript
10278
+ * await client.blog.unpublish('post_123', 'store_123');
10279
+ * ```
10280
+ */
10281
+ unpublish: (id: string, storeId: string) => Promise<BlogPost>;
10282
+ /**
10283
+ * Hard-delete a blog post. Admin mode only.
10284
+ *
10285
+ * @example
10286
+ * ```typescript
10287
+ * await client.blog.remove('post_123', 'store_123');
10288
+ * ```
10289
+ */
10290
+ remove: (id: string, storeId: string) => Promise<void>;
9958
10291
  };
9959
10292
  /**
9960
10293
  * Submit a contact inquiry from a storefront contact form.
@@ -13067,41 +13400,43 @@ declare class BrainerceClient {
13067
13400
  * ```
13068
13401
  */
13069
13402
  uploadReviewPhoto(productId: string, file: File | Blob): Promise<ReviewPhotoUpload>;
13403
+ /** The message every team method throws. One string so they cannot drift. */
13404
+ private teamIsDashboardOnly;
13070
13405
  /**
13071
- * @deprecated Retiring, but there is no API-key replacement yet: `getStoreTeam`
13072
- * is dashboard-only (403 for api_key). Keep using this until one ships.
13406
+ * @deprecated Retiring, but this ALWAYS throws: `/v1/team/*` rejects the
13407
+ * api_key principal and `getStoreTeam` is dashboard-only. Use the dashboard.
13073
13408
  */
13074
13409
  getTeamMembers(): Promise<TeamMembersResponse>;
13075
13410
  /**
13076
- * @deprecated Retiring, but there is no API-key replacement yet: `getStoreTeam`
13077
- * is dashboard-only (403 for api_key). Keep using this until one ships.
13411
+ * @deprecated Retiring, but this ALWAYS throws: `/v1/team/*` rejects the
13412
+ * api_key principal and `getStoreTeam` is dashboard-only. Use the dashboard.
13078
13413
  */
13079
13414
  getTeamInvitations(): Promise<TeamInvitationsResponse>;
13080
13415
  /**
13081
- * @deprecated Retiring, but there is no API-key replacement yet: `inviteStoreMember`
13082
- * is dashboard-only (403 for api_key). Keep using this until one ships.
13416
+ * @deprecated Retiring, but this ALWAYS throws: `/v1/team/*` rejects the
13417
+ * api_key principal and the store-level route is dashboard-only. Use the dashboard.
13083
13418
  */
13084
- inviteTeamMember(data: InviteMemberDto): Promise<TeamInvitation>;
13419
+ inviteTeamMember(_data: InviteMemberDto): Promise<TeamInvitation>;
13085
13420
  /**
13086
- * @deprecated Retiring, but there is no API-key replacement yet: `resendStoreInvitation`
13087
- * is dashboard-only (403 for api_key). Keep using this until one ships.
13421
+ * @deprecated Retiring, but this ALWAYS throws: `/v1/team/*` rejects the
13422
+ * api_key principal and the store-level route is dashboard-only. Use the dashboard.
13088
13423
  */
13089
- resendTeamInvitation(invitationId: string): Promise<TeamInvitation>;
13424
+ resendTeamInvitation(_invitationId: string): Promise<TeamInvitation>;
13090
13425
  /**
13091
- * @deprecated Retiring, but there is no API-key replacement yet: `revokeStoreInvitation`
13092
- * is dashboard-only (403 for api_key). Keep using this until one ships.
13426
+ * @deprecated Retiring, but this ALWAYS throws: `/v1/team/*` rejects the
13427
+ * api_key principal and the store-level route is dashboard-only. Use the dashboard.
13093
13428
  */
13094
- revokeTeamInvitation(invitationId: string): Promise<void>;
13429
+ revokeTeamInvitation(_invitationId: string): Promise<void>;
13095
13430
  /**
13096
- * @deprecated Retiring, but there is no API-key replacement yet: `updateStoreMember`
13097
- * is dashboard-only (403 for api_key). Keep using this until one ships.
13431
+ * @deprecated Retiring, but this ALWAYS throws: `/v1/team/*` rejects the
13432
+ * api_key principal and the store-level route is dashboard-only. Use the dashboard.
13098
13433
  */
13099
- updateTeamMemberRole(memberId: string, data: UpdateMemberRoleDto): Promise<TeamMember>;
13434
+ updateTeamMemberRole(_memberId: string, _data: UpdateMemberRoleDto): Promise<TeamMember>;
13100
13435
  /**
13101
- * @deprecated Retiring, but there is no API-key replacement yet: `removeStoreMember`
13102
- * is dashboard-only (403 for api_key). Keep using this until one ships.
13436
+ * @deprecated Retiring, but this ALWAYS throws: `/v1/team/*` rejects the
13437
+ * api_key principal and the store-level route is dashboard-only. Use the dashboard.
13103
13438
  */
13104
- removeTeamMember(memberId: string): Promise<void>;
13439
+ removeTeamMember(_memberId: string): Promise<void>;
13105
13440
  /**
13106
13441
  * Every store-level team operation is dashboard-only.
13107
13442
  *
@@ -13522,7 +13857,7 @@ declare class BrainerceError extends Error {
13522
13857
  constructor(message: string, statusCode: number, details?: unknown);
13523
13858
  }
13524
13859
 
13525
- declare const SDK_VERSION = "2.3.0";
13860
+ declare const SDK_VERSION = "2.5.0";
13526
13861
 
13527
13862
  /**
13528
13863
  * Verify a webhook signature from Brainerce