brainerce 2.1.0 → 2.2.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.mjs CHANGED
@@ -115,7 +115,7 @@ function isDevGuardsEnabled() {
115
115
  }
116
116
 
117
117
  // src/version.ts
118
- var SDK_VERSION = "2.0.3";
118
+ var SDK_VERSION = "2.2.0";
119
119
 
120
120
  // src/client.ts
121
121
  var DEFAULT_BASE_URL = "https://api.brainerce.com";
@@ -361,7 +361,7 @@ var _BrainerceClient = class _BrainerceClient {
361
361
  * Works in all three SDK modes (vibe-coded, storefront, admin):
362
362
  * - **Public reads** (`get`, `list`, `getBySlug`): work in any mode.
363
363
  * - **Write operations** (`create`, `update`, `publish`, `unpublish`,
364
- * `remove`): admin mode only — they call `/api/v1/content/...` with
364
+ * `remove`): admin mode only — they call `/api/content/...` with
365
365
  * the API key. Calling from storefront / vibe-coded mode throws.
366
366
  *
367
367
  * **Default key:** every type has `'main'` as its universal default key.
@@ -398,7 +398,7 @@ var _BrainerceClient = class _BrainerceClient {
398
398
  this.content = (() => {
399
399
  const DEFAULT_KEY = "main";
400
400
  const publicGetPath = (type, key) => `/content/${encodeURIComponent(type)}/${encodeURIComponent(key)}`;
401
- const adminBase = () => "/api/v1/content";
401
+ const adminBase = () => "/api/content";
402
402
  const publicGet = async (type, key, locale) => {
403
403
  const query = locale ? { locale } : void 0;
404
404
  const path = publicGetPath(type, key);
@@ -2018,11 +2018,9 @@ var _BrainerceClient = class _BrainerceClient {
2018
2018
  queryParams
2019
2019
  );
2020
2020
  }
2021
- return this.adminRequest(
2022
- "GET",
2023
- "/api/v1/search/suggestions",
2024
- void 0,
2025
- queryParams
2021
+ throw new BrainerceError(
2022
+ "getSearchSuggestions is a storefront API. There is no admin suggestions endpoint \u2014 construct the client with `salesChannelId` or `storeId` to use it, or call getProducts({ search }) in admin mode.",
2023
+ 400
2026
2024
  );
2027
2025
  }
2028
2026
  /**
@@ -5723,6 +5721,166 @@ var _BrainerceClient = class _BrainerceClient {
5723
5721
  return this.adminRequest("POST", "/api/v1/gift-cards/balance", { code });
5724
5722
  }
5725
5723
  // ==========================================================================
5724
+ // Gift cards — administration (API key only)
5725
+ //
5726
+ // Full programmatic management, unlike Shopify, which requires you to ask
5727
+ // their support for the equivalent scope. The gate here is the SCOPE the
5728
+ // merchant granted your key, so the separation matters: `gift_cards:issue`
5729
+ // mints stored value and `gift_cards:adjust` rewrites a balance, and neither
5730
+ // is implied by `gift_cards:read`. Ask for the least your integration needs.
5731
+ //
5732
+ // Every call reaches the same service the dashboard uses, so the rules hold
5733
+ // identically: a note is mandatory on anything that moves value, a debit
5734
+ // cannot cross what live checkout holds have reserved, and there is no delete
5735
+ // anywhere — the ledger is append-only.
5736
+ // ==========================================================================
5737
+ /**
5738
+ * List gift cards.
5739
+ *
5740
+ * `search` matches the LAST FOUR of a code or part of a recipient email. It
5741
+ * cannot match a full code: only an HMAC is stored, so there is nothing to
5742
+ * search against.
5743
+ *
5744
+ * Requires `gift_cards:read`.
5745
+ */
5746
+ async listGiftCards(params) {
5747
+ const q = new URLSearchParams();
5748
+ if (params?.page) q.set("page", String(params.page));
5749
+ if (params?.limit) q.set("limit", String(params.limit));
5750
+ if (params?.filter) q.set("filter", params.filter);
5751
+ if (params?.search) q.set("search", params.search);
5752
+ const qs = q.toString();
5753
+ return this.adminRequest(
5754
+ "GET",
5755
+ `/api/v1/gift-cards${qs ? `?${qs}` : ""}`
5756
+ );
5757
+ }
5758
+ /**
5759
+ * Outstanding gift card liability, per currency.
5760
+ *
5761
+ * This is the month-end number. Read `byCurrency` if the store sells in more
5762
+ * than one — currencies are never summed together.
5763
+ *
5764
+ * Requires `gift_cards:read`.
5765
+ */
5766
+ async getGiftCardLiability() {
5767
+ return this.adminRequest("GET", "/api/v1/gift-cards/liability");
5768
+ }
5769
+ /**
5770
+ * One gift card with its full ledger.
5771
+ *
5772
+ * Requires `gift_cards:read`.
5773
+ */
5774
+ async getGiftCard(giftCardId) {
5775
+ return this.adminRequest(
5776
+ "GET",
5777
+ `/api/v1/gift-cards/${encodePathSegment(giftCardId)}`
5778
+ );
5779
+ }
5780
+ /**
5781
+ * Issue a gift card.
5782
+ *
5783
+ * ⚠️ **The code comes back exactly once.** It is stored only as an HMAC, so
5784
+ * this response is the only time it exists in readable form anywhere. Persist
5785
+ * it or deliver it before you discard the response — no later call, dashboard
5786
+ * screen or database query can recover it.
5787
+ *
5788
+ * A `note` is required. Refused when gift cards are switched off for the
5789
+ * store. Pass an `Idempotency-Key` header to make a retry safe.
5790
+ *
5791
+ * Requires `gift_cards:issue`.
5792
+ *
5793
+ * @example
5794
+ * ```typescript
5795
+ * const card = await client.issueGiftCard({
5796
+ * amount: '200.00',
5797
+ * note: 'Compensation for order #1042',
5798
+ * recipientEmail: 'dana@example.com',
5799
+ * });
5800
+ * await sendToCustomer(card.plaintextCode); // your only chance
5801
+ * ```
5802
+ */
5803
+ async issueGiftCard(data) {
5804
+ return this.adminRequest("POST", "/api/v1/gift-cards", data);
5805
+ }
5806
+ /**
5807
+ * Re-issue a gift card onto a new code.
5808
+ *
5809
+ * The answer to a customer losing their code. Mints a new code, moves the
5810
+ * WHOLE balance to it, and REVOKES the old card.
5811
+ *
5812
+ * **This is not a resend.** The old code stops working the moment this
5813
+ * returns — if the customer still holds a printed card, it dies. Refused
5814
+ * while a checkout holds value on the card. The original expiry carries
5815
+ * forward, so this cannot be used to restart an expiry clock.
5816
+ *
5817
+ * The new code is returned exactly once, under the same rules as issuance.
5818
+ *
5819
+ * Requires `gift_cards:issue`.
5820
+ */
5821
+ async reissueGiftCard(giftCardId, note) {
5822
+ return this.adminRequest(
5823
+ "POST",
5824
+ `/api/v1/gift-cards/${encodePathSegment(giftCardId)}/reissue`,
5825
+ { note }
5826
+ );
5827
+ }
5828
+ /**
5829
+ * Adjust a gift card balance.
5830
+ *
5831
+ * `delta` is a SIGNED decimal string: `"25.00"` adds, `"-25.00"` takes away.
5832
+ * The `note` is required and is written to the ledger permanently — it is the
5833
+ * row a finance review reads a year from now.
5834
+ *
5835
+ * A debit cannot take the balance below what live checkout holds have already
5836
+ * reserved; that refusal names the held amount so you can act on it.
5837
+ *
5838
+ * Requires `gift_cards:adjust`.
5839
+ */
5840
+ async adjustGiftCardBalance(giftCardId, delta, note) {
5841
+ return this.adminRequest(
5842
+ "PATCH",
5843
+ `/api/v1/gift-cards/${encodePathSegment(giftCardId)}/adjust`,
5844
+ { delta, note }
5845
+ );
5846
+ }
5847
+ /**
5848
+ * Enable, disable or revoke one gift card.
5849
+ *
5850
+ * Deliberately does NOT touch live holds: a checkout that already reserved
5851
+ * value settles normally, because pulling it out from under a shopper
5852
+ * mid-payment would strand a provider charge already in flight. Disabling
5853
+ * stops NEW holds, which is what "off" actually means.
5854
+ *
5855
+ * Requires `gift_cards:write`.
5856
+ */
5857
+ async setGiftCardStatus(giftCardId, status) {
5858
+ return this.adminRequest(
5859
+ "PATCH",
5860
+ `/api/v1/gift-cards/${encodePathSegment(giftCardId)}/status`,
5861
+ { status }
5862
+ );
5863
+ }
5864
+ /**
5865
+ * Disable or reactivate many gift cards at once.
5866
+ *
5867
+ * `REVOKED` is not accepted here — it belongs to re-issue, which moves the
5868
+ * balance to a replacement first. Revoking in bulk would strand balances with
5869
+ * nowhere to go. Cards already revoked are skipped, so the returned count is
5870
+ * the honest one and may be lower than the ids you sent.
5871
+ *
5872
+ * There is no bulk delete, here or anywhere: the ledger is append-only and a
5873
+ * card may carry a statutory retention life.
5874
+ *
5875
+ * Requires `gift_cards:write`.
5876
+ */
5877
+ async bulkSetGiftCardStatus(giftCardIds, status) {
5878
+ return this.adminRequest("PATCH", "/api/v1/gift-cards/bulk/status", {
5879
+ giftCardIds,
5880
+ status
5881
+ });
5882
+ }
5883
+ // ==========================================================================
5726
5884
  // Donations
5727
5885
  // ==========================================================================
5728
5886
  /**
@@ -5865,10 +6023,7 @@ var _BrainerceClient = class _BrainerceClient {
5865
6023
  "/checkouts/shipping-destinations"
5866
6024
  );
5867
6025
  }
5868
- return this.adminRequest(
5869
- "GET",
5870
- "/api/v1/checkouts/shipping-destinations"
5871
- );
6026
+ return this.adminRequest("GET", "/api/checkouts/shipping-destinations");
5872
6027
  }
5873
6028
  /**
5874
6029
  * Set shipping address on checkout (includes customer email).
@@ -6127,7 +6282,7 @@ var _BrainerceClient = class _BrainerceClient {
6127
6282
  if (this.storeId && !this.apiKey) {
6128
6283
  return this.storefrontRequest("GET", "/pickup-locations");
6129
6284
  }
6130
- return this.adminRequest("GET", "/api/v1/checkouts/pickup-locations");
6285
+ return this.adminRequest("GET", "/api/checkouts/pickup-locations");
6131
6286
  }
6132
6287
  /**
6133
6288
  * Set delivery type on checkout (shipping or pickup).
@@ -9101,10 +9256,7 @@ var _BrainerceClient = class _BrainerceClient {
9101
9256
  * ```
9102
9257
  */
9103
9258
  async applyTaxPreset(presetKey) {
9104
- return this.adminRequest(
9105
- "POST",
9106
- `/api/v1/tax/presets/${encodePathSegment(presetKey)}/apply`
9107
- );
9259
+ return this.adminRequest("POST", `/api/v1/tax/presets/${encodePathSegment(presetKey)}/apply`);
9108
9260
  }
9109
9261
  /**
9110
9262
  * Get a single tax rate by ID
@@ -9734,6 +9886,27 @@ var _BrainerceClient = class _BrainerceClient {
9734
9886
  }
9735
9887
  // -------------------- Store Team Management (Admin) --------------------
9736
9888
  // Store-level team management. Each store has its own team with roles and permissions.
9889
+ /**
9890
+ * Every store-level team operation is dashboard-only.
9891
+ *
9892
+ * `store-team.controller.ts:53` carries `DashboardOnlyGuard`, which rejects
9893
+ * `api_key` and `app_installation` principals outright, so no SDK caller can
9894
+ * reach these however the URL is spelled. They additionally pointed at
9895
+ * `/api/v1/stores/:storeId/team*`, and `@Controller('v1')`
9896
+ * (external-api.controller.ts:181) has no `stores` root — so what they
9897
+ * actually returned was a 404, not the 403 you would expect from the guard.
9898
+ *
9899
+ * Throwing beats either status code: a 404 reads as "wrong id" and a 403 as
9900
+ * "missing permission", and both send the caller looking for a fix that does
9901
+ * not exist. Use the account-level `getTeamMembers()` family, or the
9902
+ * dashboard.
9903
+ */
9904
+ dashboardOnlyTeamOperation(operation) {
9905
+ throw new BrainerceError(
9906
+ `${operation} is a dashboard-only operation. Store-level team management sits behind DashboardOnlyGuard, which rejects API-key principals, so there is no SDK path to it in any mode. Use the account-level team methods (getTeamMembers, inviteTeamMember, ...) or the Brainerce dashboard.`,
9907
+ 403
9908
+ );
9909
+ }
9737
9910
  /**
9738
9911
  * Get the team for a specific store (members + pending invitations)
9739
9912
  * Requires Admin mode (apiKey) and MANAGE_TEAM permission
@@ -9743,11 +9916,8 @@ var _BrainerceClient = class _BrainerceClient {
9743
9916
  * const { members, invitations } = await client.getStoreTeam('store_id');
9744
9917
  * ```
9745
9918
  */
9746
- async getStoreTeam(storeId) {
9747
- return this.adminRequest(
9748
- "GET",
9749
- `/api/v1/stores/${encodePathSegment(storeId)}/team`
9750
- );
9919
+ async getStoreTeam(_storeId) {
9920
+ return this.dashboardOnlyTeamOperation("getStoreTeam");
9751
9921
  }
9752
9922
  /**
9753
9923
  * Invite a new member to a store
@@ -9764,12 +9934,8 @@ var _BrainerceClient = class _BrainerceClient {
9764
9934
  * });
9765
9935
  * ```
9766
9936
  */
9767
- async inviteStoreMember(storeId, data) {
9768
- return this.adminRequest(
9769
- "POST",
9770
- `/api/v1/stores/${encodePathSegment(storeId)}/team/invite`,
9771
- data
9772
- );
9937
+ async inviteStoreMember(_storeId, _data) {
9938
+ return this.dashboardOnlyTeamOperation("inviteStoreMember");
9773
9939
  }
9774
9940
  /**
9775
9941
  * Update a store team member's role and/or permissions
@@ -9786,12 +9952,8 @@ var _BrainerceClient = class _BrainerceClient {
9786
9952
  * });
9787
9953
  * ```
9788
9954
  */
9789
- async updateStoreMember(storeId, memberId, data) {
9790
- return this.adminRequest(
9791
- "PATCH",
9792
- `/api/v1/stores/${encodePathSegment(storeId)}/team/${encodePathSegment(memberId)}`,
9793
- data
9794
- );
9955
+ async updateStoreMember(_storeId, _memberId, _data) {
9956
+ return this.dashboardOnlyTeamOperation("updateStoreMember");
9795
9957
  }
9796
9958
  /**
9797
9959
  * Replace the set of vibe-coded sales channels a store member is restricted to.
@@ -9812,42 +9974,29 @@ var _BrainerceClient = class _BrainerceClient {
9812
9974
  * });
9813
9975
  * ```
9814
9976
  */
9815
- async updateStoreMemberSalesChannels(storeId, memberId, data) {
9816
- return this.adminRequest(
9817
- "PATCH",
9818
- `/api/v1/stores/${encodePathSegment(storeId)}/team/${encodePathSegment(memberId)}/sales-channels`,
9819
- data
9820
- );
9977
+ async updateStoreMemberSalesChannels(_storeId, _memberId, _data) {
9978
+ return this.dashboardOnlyTeamOperation("updateStoreMemberSalesChannels");
9821
9979
  }
9822
9980
  /**
9823
9981
  * Remove a member from a store team
9824
9982
  * Requires Admin mode (apiKey) and MANAGE_TEAM permission
9825
9983
  */
9826
- async removeStoreMember(storeId, memberId) {
9827
- await this.adminRequest(
9828
- "DELETE",
9829
- `/api/v1/stores/${encodePathSegment(storeId)}/team/${encodePathSegment(memberId)}`
9830
- );
9984
+ async removeStoreMember(_storeId, _memberId) {
9985
+ return this.dashboardOnlyTeamOperation("removeStoreMember");
9831
9986
  }
9832
9987
  /**
9833
9988
  * Resend a store invitation email
9834
9989
  * Requires Admin mode (apiKey) and MANAGE_TEAM permission
9835
9990
  */
9836
- async resendStoreInvitation(storeId, invitationId) {
9837
- return this.adminRequest(
9838
- "POST",
9839
- `/api/v1/stores/${encodePathSegment(storeId)}/team/invitations/${encodePathSegment(invitationId)}/resend`
9840
- );
9991
+ async resendStoreInvitation(_storeId, _invitationId) {
9992
+ return this.dashboardOnlyTeamOperation("resendStoreInvitation");
9841
9993
  }
9842
9994
  /**
9843
9995
  * Revoke a store invitation
9844
9996
  * Requires Admin mode (apiKey) and MANAGE_TEAM permission
9845
9997
  */
9846
- async revokeStoreInvitation(storeId, invitationId) {
9847
- await this.adminRequest(
9848
- "DELETE",
9849
- `/api/v1/stores/${encodePathSegment(storeId)}/team/invitations/${encodePathSegment(invitationId)}`
9850
- );
9998
+ async revokeStoreInvitation(_storeId, _invitationId) {
9999
+ return this.dashboardOnlyTeamOperation("revokeStoreInvitation");
9851
10000
  }
9852
10001
  /**
9853
10002
  * Get public invitation details by token (no auth required)
@@ -9856,7 +10005,7 @@ var _BrainerceClient = class _BrainerceClient {
9856
10005
  async getStoreInvitationByToken(token) {
9857
10006
  return this.request(
9858
10007
  "GET",
9859
- `/api/v1/store-invitations/${encodePathSegment(token)}`
10008
+ `/api/store-invitations/${encodePathSegment(token)}`
9860
10009
  );
9861
10010
  }
9862
10011
  /**
@@ -9864,9 +10013,9 @@ var _BrainerceClient = class _BrainerceClient {
9864
10013
  * Requires Admin mode (apiKey)
9865
10014
  */
9866
10015
  async acceptStoreInvitation(token) {
9867
- await this.adminRequest(
9868
- "POST",
9869
- `/api/v1/store-invitations/${encodePathSegment(token)}/accept`
10016
+ throw new BrainerceError(
10017
+ "acceptStoreInvitation requires a dashboard session belonging to the invited user: the invitation is matched against the email address of that user, which an API key does not have. Send the invitee to the invitation link instead.",
10018
+ 403
9870
10019
  );
9871
10020
  }
9872
10021
  /**
@@ -9883,7 +10032,7 @@ var _BrainerceClient = class _BrainerceClient {
9883
10032
  * ```
9884
10033
  */
9885
10034
  async getMyStores() {
9886
- return this.adminRequest("GET", "/api/v1/me/stores");
10035
+ return this.dashboardOnlyUserContext("getMyStores");
9887
10036
  }
9888
10037
  /**
9889
10038
  * Get the current user's resolved permissions for a specific store
@@ -9897,10 +10046,23 @@ var _BrainerceClient = class _BrainerceClient {
9897
10046
  * }
9898
10047
  * ```
9899
10048
  */
9900
- async getMyStorePermissions(storeId) {
9901
- return this.adminRequest(
9902
- "GET",
9903
- `/api/v1/me/stores/${encodePathSegment(storeId)}/permissions`
10049
+ async getMyStorePermissions(_storeId) {
10050
+ return this.dashboardOnlyUserContext("getMyStorePermissions");
10051
+ }
10052
+ /**
10053
+ * `/me/*` answers "who am I and what can I reach", which only a real user can
10054
+ * ask. `UserContextController` (store-team.controller.ts:246) is guarded by
10055
+ * `DashboardOnlyGuard` for a load-bearing reason its own G16 comment spells
10056
+ * out: both routes resolve access purely from `@CurrentUserId()`, which is
10057
+ * `undefined` for an api_key principal, so the store filter would be stripped
10058
+ * and every store on the platform returned. The guard is the control. These
10059
+ * also pointed at `/api/v1/me/*`, which no controller serves, so the observed
10060
+ * failure was a 404 rather than the guard's 403.
10061
+ */
10062
+ dashboardOnlyUserContext(operation) {
10063
+ throw new BrainerceError(
10064
+ `${operation} resolves the CURRENT USER, so it requires a dashboard session and is rejected for API-key principals by design. An API key is already scoped to one store: read it with getStore(), and read the permissions of a member from getStoreTeam() in the dashboard.`,
10065
+ 403
9904
10066
  );
9905
10067
  }
9906
10068
  // -------------------- Email Settings & Templates (Admin) --------------------
@@ -10043,7 +10205,7 @@ var _BrainerceClient = class _BrainerceClient {
10043
10205
  * Requires Admin mode (apiKey)
10044
10206
  */
10045
10207
  async getSyncConflicts() {
10046
- return this.adminRequest("GET", "/api/v1/sync-conflicts");
10208
+ return this.syncConflictsNotImplemented("getSyncConflicts");
10047
10209
  }
10048
10210
  /**
10049
10211
  * Resolve a sync conflict
@@ -10053,12 +10215,28 @@ var _BrainerceClient = class _BrainerceClient {
10053
10215
  * @param resolution - 'MERGE' to link to existing product, 'CREATE_NEW' to create new product
10054
10216
  */
10055
10217
  async resolveSyncConflict(conflictId, resolution) {
10056
- return this.adminRequest(
10057
- "POST",
10058
- `/api/v1/sync-conflicts/${encodePathSegment(conflictId)}/resolve`,
10059
- {
10060
- resolution
10061
- }
10218
+ void conflictId;
10219
+ void resolution;
10220
+ return this.syncConflictsNotImplemented("resolveSyncConflict");
10221
+ }
10222
+ /**
10223
+ * Sync conflicts were never implemented on the server.
10224
+ *
10225
+ * There is no `sync-conflict` route anywhere in the backend — not under
10226
+ * `@Controller('v1')`, not on any other controller. These two methods have
10227
+ * called a URL that has never existed, and `SyncConflict` /
10228
+ * `SyncConflictResolution` / `ResolveSyncConflictDto` are exported types with
10229
+ * no producer. The METAFIELD conflict siblings below are real
10230
+ * (external-api.controller.ts:4788, :4802) and are easy to mistake for these.
10231
+ *
10232
+ * Kept as throwing stubs rather than deleted: removing exported methods from a
10233
+ * published package is a breaking change, and a caller who has been swallowing
10234
+ * a 404 deserves to be told why.
10235
+ */
10236
+ syncConflictsNotImplemented(operation) {
10237
+ throw new BrainerceError(
10238
+ `${operation} is not implemented: the platform exposes no sync-conflict endpoint. If you are looking for metafield sync conflicts, use getMetafieldConflicts() / resolveMetafieldConflict().`,
10239
+ 501
10062
10240
  );
10063
10241
  }
10064
10242
  // -------------------- Metafield Conflicts (Admin) --------------------
package/package.json CHANGED
@@ -1,84 +1,85 @@
1
- {
2
- "name": "brainerce",
3
- "version": "2.1.0",
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
- "main": "dist/index.js",
6
- "module": "dist/index.mjs",
7
- "types": "dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.ts",
11
- "require": "./dist/index.js",
12
- "import": "./dist/index.mjs"
13
- },
14
- "./bot": {
15
- "types": "./dist/bot/index.d.ts",
16
- "require": "./dist/bot/index.js",
17
- "import": "./dist/bot/index.mjs"
18
- }
19
- },
20
- "files": [
21
- "dist",
22
- "README.md"
23
- ],
24
- "scripts": {
25
- "build": "tsup src/index.ts --format cjs,esm --dts && tsup src/bot/index.ts --format cjs,esm --dts --out-dir dist/bot && tsup src/bot/bootstrap.ts --format iife --minify --out-dir dist/bot",
26
- "type-check": "tsc --noEmit",
27
- "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
28
- "lint": "eslint \"src/**/*.ts\"",
29
- "test": "vitest run",
30
- "test:watch": "vitest",
31
- "release": "pnpm build && node ../../scripts/publish-workspace-package.js .",
32
- "prepublishOnly": "pnpm build"
33
- },
34
- "keywords": [
35
- "brainerce",
36
- "e-commerce",
37
- "ecommerce",
38
- "sdk",
39
- "vibe-coding",
40
- "vibe-coded",
41
- "ai-commerce",
42
- "storefront",
43
- "headless-commerce",
44
- "multi-platform",
45
- "shopify",
46
- "tiktok",
47
- "cursor",
48
- "lovable",
49
- "v0",
50
- "cart",
51
- "checkout",
52
- "products",
53
- "sync"
54
- ],
55
- "author": "Brainerce",
56
- "license": "MIT",
57
- "repository": {
58
- "type": "git",
59
- "url": "https://github.com/brainerce/brainerce.git",
60
- "directory": "packages/sdk"
61
- },
62
- "homepage": "https://brainerce.com",
63
- "bugs": {
64
- "url": "https://github.com/brainerce/brainerce/issues"
65
- },
66
- "devDependencies": {
67
- "@brainerce/types": "workspace:*",
68
- "@types/node": "^25.0.3",
69
- "@typescript-eslint/eslint-plugin": "^8.50.1",
70
- "@typescript-eslint/parser": "^8.50.1",
71
- "eslint": "^9.39.2",
72
- "tsup": "^8.0.0",
73
- "typescript": "^5.3.0",
74
- "vitest": "^1.0.0"
75
- },
76
- "peerDependencies": {
77
- "typescript": ">=4.7.0"
78
- },
79
- "peerDependenciesMeta": {
80
- "typescript": {
81
- "optional": true
82
- }
83
- }
84
- }
1
+ {
2
+ "name": "brainerce",
3
+ "version": "2.2.0",
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
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "require": "./dist/index.js",
12
+ "import": "./dist/index.mjs"
13
+ },
14
+ "./bot": {
15
+ "types": "./dist/bot/index.d.ts",
16
+ "require": "./dist/bot/index.js",
17
+ "import": "./dist/bot/index.mjs"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "README.md"
23
+ ],
24
+ "scripts": {
25
+ "build": "node ../../scripts/sync-sdk-version.js && tsup src/index.ts --format cjs,esm --dts && tsup src/bot/index.ts --format cjs,esm --dts --out-dir dist/bot && tsup src/bot/bootstrap.ts --format iife --minify --out-dir dist/bot",
26
+ "type-check": "tsc --noEmit",
27
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
28
+ "lint": "eslint \"src/**/*.ts\"",
29
+ "test": "vitest run",
30
+ "test:watch": "vitest",
31
+ "release": "pnpm build && node ../../scripts/publish-workspace-package.js .",
32
+ "check:routes": "node ../../scripts/check-sdk-routes.js",
33
+ "prepublishOnly": "node ../../scripts/check-sdk-routes.js && node ../../scripts/check-publishable.js ./package.json && pnpm build",
34
+ "sync:version": "node ../../scripts/sync-sdk-version.js"
35
+ },
36
+ "keywords": [
37
+ "brainerce",
38
+ "e-commerce",
39
+ "ecommerce",
40
+ "sdk",
41
+ "vibe-coding",
42
+ "vibe-coded",
43
+ "ai-commerce",
44
+ "storefront",
45
+ "headless-commerce",
46
+ "multi-platform",
47
+ "shopify",
48
+ "tiktok",
49
+ "cursor",
50
+ "lovable",
51
+ "v0",
52
+ "cart",
53
+ "checkout",
54
+ "products",
55
+ "sync"
56
+ ],
57
+ "author": "Brainerce",
58
+ "license": "MIT",
59
+ "repository": {
60
+ "type": "git",
61
+ "url": "https://github.com/brainerce/brainerce.git",
62
+ "directory": "packages/sdk"
63
+ },
64
+ "homepage": "https://brainerce.com",
65
+ "bugs": {
66
+ "url": "https://github.com/brainerce/brainerce/issues"
67
+ },
68
+ "devDependencies": {
69
+ "@types/node": "^25.0.3",
70
+ "@typescript-eslint/eslint-plugin": "^8.50.1",
71
+ "@typescript-eslint/parser": "^8.50.1",
72
+ "eslint": "^9.39.2",
73
+ "tsup": "^8.0.0",
74
+ "typescript": "^5.3.0",
75
+ "vitest": "^1.0.0"
76
+ },
77
+ "peerDependencies": {
78
+ "typescript": ">=4.7.0"
79
+ },
80
+ "peerDependenciesMeta": {
81
+ "typescript": {
82
+ "optional": true
83
+ }
84
+ }
85
+ }