@misiki/gocommerce-connector 0.3.1 → 0.4.1

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 CHANGED
@@ -26,6 +26,7 @@ PUBLIC_GOCOMMERCE_API_URL=https://api.shop.example # the engine
26
26
  PUBLIC_GOCOMMERCE_PROXY_PATH=/gocommerce # see "The browser and CORS"
27
27
  # PUBLIC_GOCOMMERCE_CHANNEL=web # a sales channel, if the store has several
28
28
  # PUBLIC_GOCOMMERCE_STORE=acme # under `gocommerce platform`, on a shared API host
29
+ # PUBLIC_GOCOMMERCE_BASE_DOMAIN=shopnx.in # or every store: acme.shopnx.in is store `acme`
29
30
  # PUBLIC_GOCOMMERCE_LANGUAGE=fr # ask for this language (?lang=) on every read
30
31
  ```
31
32
 
@@ -77,6 +78,35 @@ location / { proxy_pass http://storefront:3000; }
77
78
  Serving the storefront and the engine from one origin works too; then leave the
78
79
  proxy path unset and point the API URL at that origin.
79
80
 
81
+ ### One storefront for every store
82
+
83
+ Under `gocommerce platform` a storefront can sell for one store, named in
84
+ `PUBLIC_GOCOMMERCE_STORE`, or for all of them. Set `PUBLIC_GOCOMMERCE_BASE_DOMAIN`
85
+ to the domain the engine hands out subdomains of and point every
86
+ `<slug>.<base domain>` at the one deployment: a request for `acme.shopnx.in` is
87
+ sent to the engine with `X-Store: acme`, by the same rule the engine applies to
88
+ its own host (one label, case-insensitive, a port ignored). A host outside the
89
+ base domain falls back to `PUBLIC_GOCOMMERCE_STORE`, or to no store at all.
90
+
91
+ The browser knows its own host. The server does not, so tell the connector where
92
+ to read it, once, from `src/hooks.server.ts`:
93
+
94
+ ```ts
95
+ import { getRequestEvent } from '$app/server'
96
+ import { setRequestHost } from '@misiki/gocommerce-connector'
97
+
98
+ setRequestHost(() => getRequestEvent().url.hostname)
99
+ ```
100
+
101
+ Each store renders with the name, email and phone its owner set in the panel
102
+ (`GET /api/store`); the static record's values stand only where the owner left
103
+ one empty. Store-level facts (name, plugins, currency, menus) are cached per
104
+ store, so two stores on one process never see each other's. A host under the base domain that names
105
+ a store the engine does not have makes `getStoreByIdOrDomain` throw a
106
+ `GoCommerceError` with status 404 and "store not found" in its message, which
107
+ Svelte Commerce renders as its own "Store not found" page. An engine that is
108
+ down stays best-effort: the storefront renders from its static record.
109
+
80
110
  ## What maps to what
81
111
 
82
112
  | Storefront | Engine |
@@ -31,6 +31,16 @@ interface Credentials {
31
31
  * shared API host. Leave unset when the store has a host of its own.
32
32
  */
33
33
  store?: string;
34
+ /**
35
+ * `PUBLIC_GOCOMMERCE_BASE_DOMAIN` — under `gocommerce platform`, the domain
36
+ * every store gets a subdomain of, `shopnx.in`. One storefront deployment
37
+ * then serves them all: a request for `acme.shopnx.in` is sent with
38
+ * `X-Store: acme`, the same rule the engine applies to its own host. A host
39
+ * outside the base domain falls back to `store`. Server-side the connector
40
+ * learns the request's host through `setRequestHost`; in the browser it is
41
+ * `window.location.hostname`.
42
+ */
43
+ baseDomain?: string;
34
44
  /**
35
45
  * `PUBLIC_GOCOMMERCE_CHANNEL` — the sales channel new carts and the product
36
46
  * listing belong to, when the store sells through more than one.
@@ -336,6 +346,13 @@ type Plugin = {
336
346
  title: string;
337
347
  settings: Record<string, unknown>;
338
348
  };
349
+ /** `GET /api/store`: what anyone may read about the shop. */
350
+ type StoreProfile = {
351
+ name: string;
352
+ email: string;
353
+ phone: string;
354
+ support_url: string;
355
+ };
339
356
  type Vendor = {
340
357
  id: number;
341
358
  slug: string;
@@ -1163,6 +1180,13 @@ declare class BaseService {
1163
1180
  static setCredentials(creds: Partial<Credentials>): void;
1164
1181
  static getCredentials(): Credentials;
1165
1182
  protected get creds(): Credentials;
1183
+ /**
1184
+ * The store this call is for: the request host's subdomain under
1185
+ * `baseDomain`, else the static `store`. Read per call, never stored on the
1186
+ * instance, because the server shares one process (and one credentials
1187
+ * object) across every concurrent request and each may be for a different host.
1188
+ */
1189
+ protected get store(): string | undefined;
1166
1190
  /**
1167
1191
  * The engine's base URL from wherever this code runs. In the browser a
1168
1192
  * configured proxy path wins, because the engine answers no CORS preflight.
@@ -1200,6 +1224,19 @@ declare class BaseService {
1200
1224
  delete<T = any>(path: string): Promise<T>;
1201
1225
  private raw;
1202
1226
  }
1227
+ /**
1228
+ * Where the server learns the current request's host, for `baseDomain`. A
1229
+ * SvelteKit storefront registers `() => getRequestEvent().url.hostname` once
1230
+ * at boot; the browser needs nothing, it reads `window.location`.
1231
+ */
1232
+ declare function setRequestHost(fn: () => string | undefined): void;
1233
+ /**
1234
+ * `acme.shopnx.in` under `shopnx.in` is store `acme`; anything else is nobody's.
1235
+ * The engine's own rule (`Stores.ByHost`): case-insensitive, a port and a
1236
+ * trailing dot ignored, and exactly one label, so `a.b.shopnx.in` and
1237
+ * `shopnx.in` itself name no store.
1238
+ */
1239
+ declare function storeForHost(host: string | undefined, baseDomain: string | undefined): string | undefined;
1203
1240
  /** `?a=1&b=2`, dropping what was not asked for. Arrays repeat the key. */
1204
1241
  declare function qs(query?: Query): string;
1205
1242
  /** The family's list shape, from the engine's `{data, meta}`. Totals are the engine's, never invented. */
@@ -1234,6 +1271,8 @@ declare class StoreFacts extends BaseService {
1234
1271
  language: string;
1235
1272
  version: string;
1236
1273
  }>;
1274
+ /** The store's own name and how a buyer reaches it, as set in its panel. */
1275
+ profile(): Promise<StoreProfile>;
1237
1276
  checkoutOptions(): Promise<CheckoutOptions>;
1238
1277
  /**
1239
1278
  * The whole tree, flat and depth-first. Past 500 categories the engine
@@ -5202,12 +5241,16 @@ declare const menuService: MenuService;
5202
5241
  /**
5203
5242
  * The store record every page renders from.
5204
5243
  *
5205
- * Name, logo, theme and the rest are the storefront's own (its static store,
5244
+ * Logo, theme and the rest are the storefront's own (its static store,
5206
5245
  * registered through `setStaticStore`); the engine has no opinion on them.
5207
- * Where the engine does have one, it wins: the settlement currency — every
5208
- * price on the site is formatted with it, and a store record saying USD over
5209
- * an engine charging INR would print the wrong symbol on every price — the
5210
- * modules that back a storefront feature, and the menus.
5246
+ * Where the engine does have one, it wins:
5247
+ * - the store's name and contact, as its owner set them in the panel. One
5248
+ * storefront serves every store under `baseDomain`, so a name in the static
5249
+ * record would be every store's name;
5250
+ * - the settlement currency. Every price on the site is formatted with it, and
5251
+ * a store record saying USD over an engine charging INR would print the
5252
+ * wrong symbol on every price;
5253
+ * - the modules that back a storefront feature, and the menus.
5211
5254
  *
5212
5255
  * This runs on every request and a throw here takes every page down, so the
5213
5256
  * engine's half is best-effort: unreachable, the storefront still renders
@@ -6459,4 +6502,4 @@ declare class B2bService extends BaseService {
6459
6502
  }
6460
6503
  declare const b2bService: B2bService;
6461
6504
 
6462
- export { type Menu as $, type Address as A, type B2bPlaced as B, type Cart as C, CountryService as D, CouponService as E, type Credentials as F, type Credit as G, CurrencyService as H, type Customer as I, DealService as J, DemoRequestService as K, type EngineRequest as L, EnquiryService as M, type Envelope as N, type Faq as O, FaqService as P, FeedbackService as Q, type Fulfillment as R, GalleryService as S, HomeService as T, type IdentityAddress as U, InitService as V, type Invitation as W, type Lead as X, type ListMeta as Y, MeilisearchService as Z, type Member as _, AddressService as a, contactService as a$, type MenuItem as a0, MenuService as a1, type MenuSummary as a2, type Money as a3, NewsletterService as a4, type Offer as a5, type Order as a6, type OrderLine as a7, OrderService as a8, PageService as a9, type StorefrontMenu as aA, type StorefrontOrder as aB, type StorefrontProduct as aC, UploadService as aD, UserService as aE, type Variant as aF, type VariantImage as aG, VariantService as aH, VarniCustomDesignService as aI, VarniCustomProductService as aJ, type Vendor as aK, VendorService as aL, WarrantyService as aM, type Wishlist as aN, type WishlistItem as aO, WishlistService as aP, addressService as aQ, authService as aR, autocompleteService as aS, b2bService as aT, bannerService as aU, blogService as aV, cartService as aW, categoryService as aX, chatService as aY, checkoutService as aZ, collectionService as a_, type PaymentIntent as aa, PaymentMethodService as ab, type Plugin as ac, PluginService as ad, PopularSearchService as ae, PopularityService as af, type Product as ag, type ProductOption as ah, ProductService as ai, ProfileService as aj, type Quote as ak, REDIRECT_GATEWAYS as al, ReelsService as am, RegionService as an, type RejectedLine as ao, type Review as ap, type ReviewPage as aq, ReviewService as ar, type SearchDoc as as, type SearchResult as at, SearchService as au, SettingService as av, type ShippingRate as aw, StateService as ax, StoreService as ay, type StorefrontCategory as az, type AppliedDiscount as b, varniCustomProductService as b$, countryService as b0, couponService as b1, currencyExponent as b2, currencyService as b3, dealService as b4, demoRequestService as b5, emptyCart as b6, emptyPage as b7, enquiryService as b8, faqService as b9, reviewService as bA, searchService as bB, settingService as bC, settingsService as bD, stateService as bE, staticStore as bF, storeService as bG, toCart as bH, toCartLine as bI, toCategory as bJ, toCmsPage as bK, toCollection as bL, toEngineAddress as bM, toIdentityAddress as bN, toMajor as bO, toMinor as bP, toOrder as bQ, toPage as bR, toProduct as bS, toRating as bT, toUser as bU, toVariant as bV, toVendor as bW, uploadService as bX, userService as bY, variantService as bZ, varniCustomDesignService as b_, feedbackService as ba, fromEngineAddress as bb, fromIdentityAddress as bc, fromSearchDoc as bd, galleryService as be, homeService as bf, initService as bg, mediaUrl as bh, meilisearchService as bi, menuService as bj, minorToMajor as bk, newsletterService as bl, orderService as bm, pageService as bn, paymentMethodService as bo, pluginService as bp, pluginsService as bq, popularSearchService as br, popularityService as bs, priceOf as bt, productImages as bu, productService as bv, profileService as bw, qs as bx, reelsService as by, regionService as bz, type Approval as c, vendorService as c0, warrantyService as c1, wishlistService as c2, type AuthResponse as d, AuthService as e, AutocompleteService as f, type B2bRole as g, B2bService as h, BannerService as i, BaseService as j, BlogService as k, type CartLine as l, CartService as m, CatalogService as n, type Category as o, CategoryService as p, ChatService as q, type CheckoutOptions as r, type CheckoutResult as s, CheckoutService as t, type CmsPage as u, type Collection as v, CollectionService as w, type Company as x, type CompanyOrder as y, ContactService as z };
6505
+ export { type Menu as $, type Address as A, type B2bPlaced as B, type Cart as C, CountryService as D, CouponService as E, type Credentials as F, type Credit as G, CurrencyService as H, type Customer as I, DealService as J, DemoRequestService as K, type EngineRequest as L, EnquiryService as M, type Envelope as N, type Faq as O, FaqService as P, FeedbackService as Q, type Fulfillment as R, GalleryService as S, HomeService as T, type IdentityAddress as U, InitService as V, type Invitation as W, type Lead as X, type ListMeta as Y, MeilisearchService as Z, type Member as _, AddressService as a, collectionService as a$, type MenuItem as a0, MenuService as a1, type MenuSummary as a2, type Money as a3, NewsletterService as a4, type Offer as a5, type Order as a6, type OrderLine as a7, OrderService as a8, PageService as a9, type StorefrontCategory as aA, type StorefrontMenu as aB, type StorefrontOrder as aC, type StorefrontProduct as aD, UploadService as aE, UserService as aF, type Variant as aG, type VariantImage as aH, VariantService as aI, VarniCustomDesignService as aJ, VarniCustomProductService as aK, type Vendor as aL, VendorService as aM, WarrantyService as aN, type Wishlist as aO, type WishlistItem as aP, WishlistService as aQ, addressService as aR, authService as aS, autocompleteService as aT, b2bService as aU, bannerService as aV, blogService as aW, cartService as aX, categoryService as aY, chatService as aZ, checkoutService as a_, type PaymentIntent as aa, PaymentMethodService as ab, type Plugin as ac, PluginService as ad, PopularSearchService as ae, PopularityService as af, type Product as ag, type ProductOption as ah, ProductService as ai, ProfileService as aj, type Quote as ak, REDIRECT_GATEWAYS as al, ReelsService as am, RegionService as an, type RejectedLine as ao, type Review as ap, type ReviewPage as aq, ReviewService as ar, type SearchDoc as as, type SearchResult as at, SearchService as au, SettingService as av, type ShippingRate as aw, StateService as ax, type StoreProfile as ay, StoreService as az, type AppliedDiscount as b, userService as b$, contactService as b0, countryService as b1, couponService as b2, currencyExponent as b3, currencyService as b4, dealService as b5, demoRequestService as b6, emptyCart as b7, emptyPage as b8, enquiryService as b9, regionService as bA, reviewService as bB, searchService as bC, setRequestHost as bD, settingService as bE, settingsService as bF, stateService as bG, staticStore as bH, storeForHost as bI, storeService as bJ, toCart as bK, toCartLine as bL, toCategory as bM, toCmsPage as bN, toCollection as bO, toEngineAddress as bP, toIdentityAddress as bQ, toMajor as bR, toMinor as bS, toOrder as bT, toPage as bU, toProduct as bV, toRating as bW, toUser as bX, toVariant as bY, toVendor as bZ, uploadService as b_, faqService as ba, feedbackService as bb, fromEngineAddress as bc, fromIdentityAddress as bd, fromSearchDoc as be, galleryService as bf, homeService as bg, initService as bh, mediaUrl as bi, meilisearchService as bj, menuService as bk, minorToMajor as bl, newsletterService as bm, orderService as bn, pageService as bo, paymentMethodService as bp, pluginService as bq, pluginsService as br, popularSearchService as bs, popularityService as bt, priceOf as bu, productImages as bv, productService as bw, profileService as bx, qs as by, reelsService as bz, type Approval as c, variantService as c0, varniCustomDesignService as c1, varniCustomProductService as c2, vendorService as c3, warrantyService as c4, wishlistService as c5, type AuthResponse as d, AuthService as e, AutocompleteService as f, type B2bRole as g, B2bService as h, BannerService as i, BaseService as j, BlogService as k, type CartLine as l, CartService as m, CatalogService as n, type Category as o, CategoryService as p, ChatService as q, type CheckoutOptions as r, type CheckoutResult as s, CheckoutService as t, type CmsPage as u, type Collection as v, CollectionService as w, type Company as x, type CompanyOrder as y, ContactService as z };
@@ -31,6 +31,16 @@ interface Credentials {
31
31
  * shared API host. Leave unset when the store has a host of its own.
32
32
  */
33
33
  store?: string;
34
+ /**
35
+ * `PUBLIC_GOCOMMERCE_BASE_DOMAIN` — under `gocommerce platform`, the domain
36
+ * every store gets a subdomain of, `shopnx.in`. One storefront deployment
37
+ * then serves them all: a request for `acme.shopnx.in` is sent with
38
+ * `X-Store: acme`, the same rule the engine applies to its own host. A host
39
+ * outside the base domain falls back to `store`. Server-side the connector
40
+ * learns the request's host through `setRequestHost`; in the browser it is
41
+ * `window.location.hostname`.
42
+ */
43
+ baseDomain?: string;
34
44
  /**
35
45
  * `PUBLIC_GOCOMMERCE_CHANNEL` — the sales channel new carts and the product
36
46
  * listing belong to, when the store sells through more than one.
@@ -336,6 +346,13 @@ type Plugin = {
336
346
  title: string;
337
347
  settings: Record<string, unknown>;
338
348
  };
349
+ /** `GET /api/store`: what anyone may read about the shop. */
350
+ type StoreProfile = {
351
+ name: string;
352
+ email: string;
353
+ phone: string;
354
+ support_url: string;
355
+ };
339
356
  type Vendor = {
340
357
  id: number;
341
358
  slug: string;
@@ -1163,6 +1180,13 @@ declare class BaseService {
1163
1180
  static setCredentials(creds: Partial<Credentials>): void;
1164
1181
  static getCredentials(): Credentials;
1165
1182
  protected get creds(): Credentials;
1183
+ /**
1184
+ * The store this call is for: the request host's subdomain under
1185
+ * `baseDomain`, else the static `store`. Read per call, never stored on the
1186
+ * instance, because the server shares one process (and one credentials
1187
+ * object) across every concurrent request and each may be for a different host.
1188
+ */
1189
+ protected get store(): string | undefined;
1166
1190
  /**
1167
1191
  * The engine's base URL from wherever this code runs. In the browser a
1168
1192
  * configured proxy path wins, because the engine answers no CORS preflight.
@@ -1200,6 +1224,19 @@ declare class BaseService {
1200
1224
  delete<T = any>(path: string): Promise<T>;
1201
1225
  private raw;
1202
1226
  }
1227
+ /**
1228
+ * Where the server learns the current request's host, for `baseDomain`. A
1229
+ * SvelteKit storefront registers `() => getRequestEvent().url.hostname` once
1230
+ * at boot; the browser needs nothing, it reads `window.location`.
1231
+ */
1232
+ declare function setRequestHost(fn: () => string | undefined): void;
1233
+ /**
1234
+ * `acme.shopnx.in` under `shopnx.in` is store `acme`; anything else is nobody's.
1235
+ * The engine's own rule (`Stores.ByHost`): case-insensitive, a port and a
1236
+ * trailing dot ignored, and exactly one label, so `a.b.shopnx.in` and
1237
+ * `shopnx.in` itself name no store.
1238
+ */
1239
+ declare function storeForHost(host: string | undefined, baseDomain: string | undefined): string | undefined;
1203
1240
  /** `?a=1&b=2`, dropping what was not asked for. Arrays repeat the key. */
1204
1241
  declare function qs(query?: Query): string;
1205
1242
  /** The family's list shape, from the engine's `{data, meta}`. Totals are the engine's, never invented. */
@@ -1234,6 +1271,8 @@ declare class StoreFacts extends BaseService {
1234
1271
  language: string;
1235
1272
  version: string;
1236
1273
  }>;
1274
+ /** The store's own name and how a buyer reaches it, as set in its panel. */
1275
+ profile(): Promise<StoreProfile>;
1237
1276
  checkoutOptions(): Promise<CheckoutOptions>;
1238
1277
  /**
1239
1278
  * The whole tree, flat and depth-first. Past 500 categories the engine
@@ -5202,12 +5241,16 @@ declare const menuService: MenuService;
5202
5241
  /**
5203
5242
  * The store record every page renders from.
5204
5243
  *
5205
- * Name, logo, theme and the rest are the storefront's own (its static store,
5244
+ * Logo, theme and the rest are the storefront's own (its static store,
5206
5245
  * registered through `setStaticStore`); the engine has no opinion on them.
5207
- * Where the engine does have one, it wins: the settlement currency — every
5208
- * price on the site is formatted with it, and a store record saying USD over
5209
- * an engine charging INR would print the wrong symbol on every price — the
5210
- * modules that back a storefront feature, and the menus.
5246
+ * Where the engine does have one, it wins:
5247
+ * - the store's name and contact, as its owner set them in the panel. One
5248
+ * storefront serves every store under `baseDomain`, so a name in the static
5249
+ * record would be every store's name;
5250
+ * - the settlement currency. Every price on the site is formatted with it, and
5251
+ * a store record saying USD over an engine charging INR would print the
5252
+ * wrong symbol on every price;
5253
+ * - the modules that back a storefront feature, and the menus.
5211
5254
  *
5212
5255
  * This runs on every request and a throw here takes every page down, so the
5213
5256
  * engine's half is best-effort: unreachable, the storefront still renders
@@ -6459,4 +6502,4 @@ declare class B2bService extends BaseService {
6459
6502
  }
6460
6503
  declare const b2bService: B2bService;
6461
6504
 
6462
- export { type Menu as $, type Address as A, type B2bPlaced as B, type Cart as C, CountryService as D, CouponService as E, type Credentials as F, type Credit as G, CurrencyService as H, type Customer as I, DealService as J, DemoRequestService as K, type EngineRequest as L, EnquiryService as M, type Envelope as N, type Faq as O, FaqService as P, FeedbackService as Q, type Fulfillment as R, GalleryService as S, HomeService as T, type IdentityAddress as U, InitService as V, type Invitation as W, type Lead as X, type ListMeta as Y, MeilisearchService as Z, type Member as _, AddressService as a, contactService as a$, type MenuItem as a0, MenuService as a1, type MenuSummary as a2, type Money as a3, NewsletterService as a4, type Offer as a5, type Order as a6, type OrderLine as a7, OrderService as a8, PageService as a9, type StorefrontMenu as aA, type StorefrontOrder as aB, type StorefrontProduct as aC, UploadService as aD, UserService as aE, type Variant as aF, type VariantImage as aG, VariantService as aH, VarniCustomDesignService as aI, VarniCustomProductService as aJ, type Vendor as aK, VendorService as aL, WarrantyService as aM, type Wishlist as aN, type WishlistItem as aO, WishlistService as aP, addressService as aQ, authService as aR, autocompleteService as aS, b2bService as aT, bannerService as aU, blogService as aV, cartService as aW, categoryService as aX, chatService as aY, checkoutService as aZ, collectionService as a_, type PaymentIntent as aa, PaymentMethodService as ab, type Plugin as ac, PluginService as ad, PopularSearchService as ae, PopularityService as af, type Product as ag, type ProductOption as ah, ProductService as ai, ProfileService as aj, type Quote as ak, REDIRECT_GATEWAYS as al, ReelsService as am, RegionService as an, type RejectedLine as ao, type Review as ap, type ReviewPage as aq, ReviewService as ar, type SearchDoc as as, type SearchResult as at, SearchService as au, SettingService as av, type ShippingRate as aw, StateService as ax, StoreService as ay, type StorefrontCategory as az, type AppliedDiscount as b, varniCustomProductService as b$, countryService as b0, couponService as b1, currencyExponent as b2, currencyService as b3, dealService as b4, demoRequestService as b5, emptyCart as b6, emptyPage as b7, enquiryService as b8, faqService as b9, reviewService as bA, searchService as bB, settingService as bC, settingsService as bD, stateService as bE, staticStore as bF, storeService as bG, toCart as bH, toCartLine as bI, toCategory as bJ, toCmsPage as bK, toCollection as bL, toEngineAddress as bM, toIdentityAddress as bN, toMajor as bO, toMinor as bP, toOrder as bQ, toPage as bR, toProduct as bS, toRating as bT, toUser as bU, toVariant as bV, toVendor as bW, uploadService as bX, userService as bY, variantService as bZ, varniCustomDesignService as b_, feedbackService as ba, fromEngineAddress as bb, fromIdentityAddress as bc, fromSearchDoc as bd, galleryService as be, homeService as bf, initService as bg, mediaUrl as bh, meilisearchService as bi, menuService as bj, minorToMajor as bk, newsletterService as bl, orderService as bm, pageService as bn, paymentMethodService as bo, pluginService as bp, pluginsService as bq, popularSearchService as br, popularityService as bs, priceOf as bt, productImages as bu, productService as bv, profileService as bw, qs as bx, reelsService as by, regionService as bz, type Approval as c, vendorService as c0, warrantyService as c1, wishlistService as c2, type AuthResponse as d, AuthService as e, AutocompleteService as f, type B2bRole as g, B2bService as h, BannerService as i, BaseService as j, BlogService as k, type CartLine as l, CartService as m, CatalogService as n, type Category as o, CategoryService as p, ChatService as q, type CheckoutOptions as r, type CheckoutResult as s, CheckoutService as t, type CmsPage as u, type Collection as v, CollectionService as w, type Company as x, type CompanyOrder as y, ContactService as z };
6505
+ export { type Menu as $, type Address as A, type B2bPlaced as B, type Cart as C, CountryService as D, CouponService as E, type Credentials as F, type Credit as G, CurrencyService as H, type Customer as I, DealService as J, DemoRequestService as K, type EngineRequest as L, EnquiryService as M, type Envelope as N, type Faq as O, FaqService as P, FeedbackService as Q, type Fulfillment as R, GalleryService as S, HomeService as T, type IdentityAddress as U, InitService as V, type Invitation as W, type Lead as X, type ListMeta as Y, MeilisearchService as Z, type Member as _, AddressService as a, collectionService as a$, type MenuItem as a0, MenuService as a1, type MenuSummary as a2, type Money as a3, NewsletterService as a4, type Offer as a5, type Order as a6, type OrderLine as a7, OrderService as a8, PageService as a9, type StorefrontCategory as aA, type StorefrontMenu as aB, type StorefrontOrder as aC, type StorefrontProduct as aD, UploadService as aE, UserService as aF, type Variant as aG, type VariantImage as aH, VariantService as aI, VarniCustomDesignService as aJ, VarniCustomProductService as aK, type Vendor as aL, VendorService as aM, WarrantyService as aN, type Wishlist as aO, type WishlistItem as aP, WishlistService as aQ, addressService as aR, authService as aS, autocompleteService as aT, b2bService as aU, bannerService as aV, blogService as aW, cartService as aX, categoryService as aY, chatService as aZ, checkoutService as a_, type PaymentIntent as aa, PaymentMethodService as ab, type Plugin as ac, PluginService as ad, PopularSearchService as ae, PopularityService as af, type Product as ag, type ProductOption as ah, ProductService as ai, ProfileService as aj, type Quote as ak, REDIRECT_GATEWAYS as al, ReelsService as am, RegionService as an, type RejectedLine as ao, type Review as ap, type ReviewPage as aq, ReviewService as ar, type SearchDoc as as, type SearchResult as at, SearchService as au, SettingService as av, type ShippingRate as aw, StateService as ax, type StoreProfile as ay, StoreService as az, type AppliedDiscount as b, userService as b$, contactService as b0, countryService as b1, couponService as b2, currencyExponent as b3, currencyService as b4, dealService as b5, demoRequestService as b6, emptyCart as b7, emptyPage as b8, enquiryService as b9, regionService as bA, reviewService as bB, searchService as bC, setRequestHost as bD, settingService as bE, settingsService as bF, stateService as bG, staticStore as bH, storeForHost as bI, storeService as bJ, toCart as bK, toCartLine as bL, toCategory as bM, toCmsPage as bN, toCollection as bO, toEngineAddress as bP, toIdentityAddress as bQ, toMajor as bR, toMinor as bS, toOrder as bT, toPage as bU, toProduct as bV, toRating as bW, toUser as bX, toVariant as bY, toVendor as bZ, uploadService as b_, faqService as ba, feedbackService as bb, fromEngineAddress as bc, fromIdentityAddress as bd, fromSearchDoc as be, galleryService as bf, homeService as bg, initService as bh, mediaUrl as bi, meilisearchService as bj, menuService as bk, minorToMajor as bl, newsletterService as bm, orderService as bn, pageService as bo, paymentMethodService as bp, pluginService as bq, pluginsService as br, popularSearchService as bs, popularityService as bt, priceOf as bu, productImages as bv, productService as bw, profileService as bx, qs as by, reelsService as bz, type Approval as c, variantService as c0, varniCustomDesignService as c1, varniCustomProductService as c2, vendorService as c3, warrantyService as c4, wishlistService as c5, type AuthResponse as d, AuthService as e, AutocompleteService as f, type B2bRole as g, B2bService as h, BannerService as i, BaseService as j, BlogService as k, type CartLine as l, CartService as m, CatalogService as n, type Category as o, CategoryService as p, ChatService as q, type CheckoutOptions as r, type CheckoutResult as s, CheckoutService as t, type CmsPage as u, type Collection as v, CollectionService as w, type Company as x, type CompanyOrder as y, ContactService as z };
package/dist/index.cjs CHANGED
@@ -285,6 +285,17 @@ var BaseService = class _BaseService {
285
285
  get creds() {
286
286
  return _BaseService._credentials;
287
287
  }
288
+ /**
289
+ * The store this call is for: the request host's subdomain under
290
+ * `baseDomain`, else the static `store`. Read per call, never stored on the
291
+ * instance, because the server shares one process (and one credentials
292
+ * object) across every concurrent request and each may be for a different host.
293
+ */
294
+ get store() {
295
+ const { baseDomain, store } = this.creds;
296
+ const host = typeof window !== "undefined" ? window.location?.hostname : requestHost?.();
297
+ return storeForHost(host, baseDomain) ?? store;
298
+ }
288
299
  /**
289
300
  * The engine's base URL from wherever this code runs. In the browser a
290
301
  * configured proxy path wins, because the engine answers no CORS preflight.
@@ -318,7 +329,8 @@ var BaseService = class _BaseService {
318
329
  const url = this.engineURL(path, lang ? { lang, ...req.query } : req.query);
319
330
  const headers = { Accept: "application/json", ...req.headers };
320
331
  if (req.body !== void 0) headers["Content-Type"] = "application/json";
321
- if (this.creds.store) headers["X-Store"] = this.creds.store;
332
+ const store = this.store;
333
+ if (store) headers["X-Store"] = store;
322
334
  if (req.auth) {
323
335
  const token = sessionToken();
324
336
  if (!token) throw new GoCommerceError("Please sign in to continue.", 401, "unauthorized");
@@ -420,6 +432,18 @@ var BaseService = class _BaseService {
420
432
  return body;
421
433
  }
422
434
  };
435
+ var requestHost;
436
+ function setRequestHost(fn) {
437
+ requestHost = fn;
438
+ }
439
+ function storeForHost(host, baseDomain) {
440
+ if (!host || !baseDomain) return void 0;
441
+ const h = host.toLowerCase().replace(/\.$/, "").replace(/:\d+$/, "");
442
+ const suffix = "." + baseDomain.toLowerCase().replace(/^\.+/, "").replace(/\.$/, "");
443
+ if (!h.endsWith(suffix)) return void 0;
444
+ const slug = h.slice(0, -suffix.length);
445
+ return slug && !slug.includes(".") ? slug : void 0;
446
+ }
423
447
  var unreachable = (base, cause) => new GoCommerceError(`Could not reach the commerce engine at ${base}: ${cause?.message ?? cause}`, 0);
424
448
  function qs(query) {
425
449
  if (!query) return "";
@@ -967,7 +991,7 @@ var priceOf = (m) => m ? toMajor(m) : 0;
967
991
  // src/services/facts.ts
968
992
  var StoreFacts = class extends BaseService {
969
993
  key(name) {
970
- return `${this.engineBase()}|${this.creds.store ?? ""}|${name}`;
994
+ return `${this.engineBase()}|${this.store ?? ""}|${name}`;
971
995
  }
972
996
  /** Enabled plugins by key. A module that is not installed has no key here. */
973
997
  plugins() {
@@ -987,6 +1011,10 @@ var StoreFacts = class extends BaseService {
987
1011
  ready() {
988
1012
  return remember(this.key("ready"), () => this.data("/health/ready"));
989
1013
  }
1014
+ /** The store's own name and how a buyer reaches it, as set in its panel. */
1015
+ profile() {
1016
+ return remember(this.key("profile"), () => this.data("/api/store"));
1017
+ }
990
1018
  checkoutOptions() {
991
1019
  return remember(this.key("checkout"), () => this.data("/api/checkout"));
992
1020
  }
@@ -2397,7 +2425,7 @@ var MenuService = class extends BaseService {
2397
2425
  /** The header and footer menus, or `null` when the module is not there. Cached: a menu is store-level. */
2398
2426
  async engineMenus() {
2399
2427
  if (!await this.facts.pluginOn("navigation")) return null;
2400
- return remember(`${this.engineBase()}|${this.creds.store ?? ""}|menus`, async () => {
2428
+ return remember(`${this.engineBase()}|${this.store ?? ""}|menus`, async () => {
2401
2429
  const out = [];
2402
2430
  for (const handle of ["header", "footer"]) {
2403
2431
  try {
@@ -2431,6 +2459,7 @@ var NewsletterService = class extends BaseService {
2431
2459
  var newsletterService = new NewsletterService();
2432
2460
 
2433
2461
  // src/services/store-service.ts
2462
+ var isStoreMissing = (err) => err instanceof GoCommerceError && err.status === 404 && (err.code === "store_not_found" || /store not found|no such store/i.test(err.message));
2434
2463
  function symbolFor(code) {
2435
2464
  try {
2436
2465
  const part = new Intl.NumberFormat("en", { style: "currency", currency: code }).formatToParts(0).find((p) => p.type === "currency");
@@ -2443,6 +2472,14 @@ var StoreService = class extends BaseService {
2443
2472
  facts = new StoreFacts(this._fetch);
2444
2473
  async getStoreByIdOrDomain(_args = {}) {
2445
2474
  const base = await readStaticStore();
2475
+ const store = this.store;
2476
+ if (store) {
2477
+ await this.facts.plugins().catch((err) => {
2478
+ if (isStoreMissing(err)) {
2479
+ throw new GoCommerceError(`store not found: no store "${store}" on this engine`, 404, "store_not_found");
2480
+ }
2481
+ });
2482
+ }
2446
2483
  const live = await this.live().catch(() => ({}));
2447
2484
  return { ...base, ...live, id: base.id || "gocommerce" };
2448
2485
  }
@@ -2480,17 +2517,22 @@ var StoreService = class extends BaseService {
2480
2517
  return super.post(path, data);
2481
2518
  }
2482
2519
  async live() {
2483
- const [ready, plugins, menus, base] = await Promise.all([
2520
+ const [ready, plugins, menus, base, profile] = await Promise.all([
2484
2521
  this.facts.ready(),
2485
2522
  this.facts.plugins().catch(() => /* @__PURE__ */ new Map()),
2486
2523
  new MenuService(this._fetch).engineMenus(),
2487
- readStaticStore()
2524
+ readStaticStore(),
2525
+ this.facts.profile().catch(() => null)
2488
2526
  ]);
2489
2527
  const code = ready.currency;
2490
2528
  const sameCurrency = (base.currency?.code ?? base.currencyCode) === code;
2491
2529
  const flag = (on) => ({ ...on ? { active: true } : { active: false } });
2492
2530
  const basePlugins = base.plugins ?? {};
2493
2531
  return {
2532
+ // Only what the owner filled in: an empty name keeps the static one.
2533
+ ...profile?.name ? { name: profile.name } : {},
2534
+ ...profile?.email ? { businessEmail: profile.email } : {},
2535
+ ...profile?.phone ? { businessPhone: profile.phone } : {},
2494
2536
  currencyCode: code,
2495
2537
  currencySymbol: sameCurrency ? base.currencySymbol ?? symbolFor(code) : symbolFor(code),
2496
2538
  currency: {
@@ -3189,11 +3231,13 @@ exports.regionService = regionService;
3189
3231
  exports.reviewService = reviewService;
3190
3232
  exports.searchService = searchService;
3191
3233
  exports.serveRestLocally = serveRestLocally;
3234
+ exports.setRequestHost = setRequestHost;
3192
3235
  exports.setStaticStore = setStaticStore;
3193
3236
  exports.settingService = settingService;
3194
3237
  exports.settingsService = settingsService;
3195
3238
  exports.stateService = stateService;
3196
3239
  exports.staticStore = staticStore;
3240
+ exports.storeForHost = storeForHost;
3197
3241
  exports.storeService = storeService;
3198
3242
  exports.toCart = toCart;
3199
3243
  exports.toCartLine = toCartLine;