@asteby/storefront 0.2.0 → 0.4.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/mock.d.cts CHANGED
@@ -1,4 +1,5 @@
1
- import { a1 as Shop, Q as Product, p as Collection, a8 as Theme, P as Page, M as Menu, b as Article, C as Cart, A as Address, r as Customer, O as Order } from './types-CTXB8Dnl.cjs';
1
+ import { a7 as Shop, W as Product, p as Collection, ae as Theme, R as Page, M as Menu, b as Article, C as Cart, A as Address, r as Customer, P as Order } from './types-D300wdPF.cjs';
2
+ import './geo.cjs';
2
3
 
3
4
  /**
4
5
  * Placeholder image source for all seed data. Swap it (or pass `imageUrl` to
@@ -9,6 +10,11 @@ type MockImageUrl = typeof MOCK_IMAGE_URL;
9
10
  declare const MOCK_CURRENCY = "MXN";
10
11
  /** Seed customer that already exists (log in with OTP `000000`). */
11
12
  declare const MOCK_CUSTOMER_EMAIL = "cliente@example.com";
13
+ /** Postal-code centroids the mock can resolve (the real API resolves any Mexican CP). */
14
+ declare const MOCK_POSTAL_CENTROIDS: Record<string, {
15
+ lat: number;
16
+ lng: number;
17
+ }>;
12
18
 
13
19
  /**
14
20
  * In-memory implementation of the whole Storefront API v1 contract, exposed
@@ -78,6 +84,7 @@ type MockState = {
78
84
  status: number;
79
85
  body: unknown;
80
86
  }>;
87
+ checkouts: Map<string, unknown>;
81
88
  seq: number;
82
89
  };
83
90
  declare function createMockStorefront(options?: MockStorefrontOptions): {
@@ -92,4 +99,4 @@ declare function createMockStorefront(options?: MockStorefrontOptions): {
92
99
  };
93
100
  type MockStorefront = ReturnType<typeof createMockStorefront>;
94
101
 
95
- export { MOCK_CURRENCY, MOCK_CUSTOMER_EMAIL, MOCK_IMAGE_URL, type MockImageUrl, type MockState, type MockStorefront, type MockStorefrontOptions, createMockStorefront };
102
+ export { MOCK_CURRENCY, MOCK_CUSTOMER_EMAIL, MOCK_IMAGE_URL, MOCK_POSTAL_CENTROIDS, type MockImageUrl, type MockState, type MockStorefront, type MockStorefrontOptions, createMockStorefront };
package/dist/mock.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { a1 as Shop, Q as Product, p as Collection, a8 as Theme, P as Page, M as Menu, b as Article, C as Cart, A as Address, r as Customer, O as Order } from './types-CTXB8Dnl.js';
1
+ import { a7 as Shop, W as Product, p as Collection, ae as Theme, R as Page, M as Menu, b as Article, C as Cart, A as Address, r as Customer, P as Order } from './types-BmC-RDo8.js';
2
+ import './geo.js';
2
3
 
3
4
  /**
4
5
  * Placeholder image source for all seed data. Swap it (or pass `imageUrl` to
@@ -9,6 +10,11 @@ type MockImageUrl = typeof MOCK_IMAGE_URL;
9
10
  declare const MOCK_CURRENCY = "MXN";
10
11
  /** Seed customer that already exists (log in with OTP `000000`). */
11
12
  declare const MOCK_CUSTOMER_EMAIL = "cliente@example.com";
13
+ /** Postal-code centroids the mock can resolve (the real API resolves any Mexican CP). */
14
+ declare const MOCK_POSTAL_CENTROIDS: Record<string, {
15
+ lat: number;
16
+ lng: number;
17
+ }>;
12
18
 
13
19
  /**
14
20
  * In-memory implementation of the whole Storefront API v1 contract, exposed
@@ -78,6 +84,7 @@ type MockState = {
78
84
  status: number;
79
85
  body: unknown;
80
86
  }>;
87
+ checkouts: Map<string, unknown>;
81
88
  seq: number;
82
89
  };
83
90
  declare function createMockStorefront(options?: MockStorefrontOptions): {
@@ -92,4 +99,4 @@ declare function createMockStorefront(options?: MockStorefrontOptions): {
92
99
  };
93
100
  type MockStorefront = ReturnType<typeof createMockStorefront>;
94
101
 
95
- export { MOCK_CURRENCY, MOCK_CUSTOMER_EMAIL, MOCK_IMAGE_URL, type MockImageUrl, type MockState, type MockStorefront, type MockStorefrontOptions, createMockStorefront };
102
+ export { MOCK_CURRENCY, MOCK_CUSTOMER_EMAIL, MOCK_IMAGE_URL, MOCK_POSTAL_CENTROIDS, type MockImageUrl, type MockState, type MockStorefront, type MockStorefrontOptions, createMockStorefront };
package/dist/mock.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { isValidPoint, rankByDistance } from './chunk-45R47HYO.js';
2
+
1
3
  // src/mock/seed.ts
2
4
  var MOCK_IMAGE_URL = (seed, width = 800, height = 800) => `https://picsum.photos/seed/${encodeURIComponent(seed)}/${width}/${height}`;
3
5
  var MOCK_CURRENCY = "MXN";
@@ -128,6 +130,73 @@ function buildCollections(imageUrl = MOCK_IMAGE_URL) {
128
130
  parent_handle: c.parent ?? null
129
131
  }));
130
132
  }
133
+ var MX_TZ = "America/Mexico_City";
134
+ var weekdays = (open, close, days = [1, 2, 3, 4, 5]) => days.map((day) => ({ day, open, close }));
135
+ function buildLocations(currency) {
136
+ const contacts = (phone) => ({ phone, email: null, whatsapp: null });
137
+ return [
138
+ {
139
+ id: "br_centro",
140
+ name: "Sucursal Centro",
141
+ kind: "store",
142
+ address: "Av. Principal 100, Col. Centro",
143
+ city: "Ciudad de M\xE9xico",
144
+ postal_code: "06000",
145
+ phone: "+52 55 0000 0001",
146
+ lat: 19.4326,
147
+ lng: -99.1332,
148
+ timezone: MX_TZ,
149
+ hours: "Mo-Fr 09:00-19:00, Sa 09:00-14:00",
150
+ opening_hours_text: "Lun\u2013Vie 9:00\u201319:00 \xB7 S\xE1b 9:00\u201314:00",
151
+ opening_hours: { weekly: [...weekdays("09:00", "19:00"), { day: 6, open: "09:00", close: "14:00" }] },
152
+ services: ["pickup", "returns"],
153
+ contacts: contacts("+52 55 0000 0001"),
154
+ pickup: { enabled: true, fee: null, prep_days: 0 }
155
+ },
156
+ {
157
+ id: "br_norte",
158
+ name: "Sucursal Norte",
159
+ kind: "store",
160
+ address: "Calle Secundaria 25, Col. Norte",
161
+ city: "Monterrey",
162
+ postal_code: "64000",
163
+ phone: null,
164
+ lat: 25.6866,
165
+ lng: -100.3161,
166
+ timezone: MX_TZ,
167
+ hours: "Mo-Sa 10:00-18:00",
168
+ opening_hours_text: "Lun\u2013S\xE1b 10:00\u201318:00",
169
+ opening_hours: { weekly: weekdays("10:00", "18:00", [1, 2, 3, 4, 5, 6]) },
170
+ services: ["pickup"],
171
+ contacts: contacts(null),
172
+ pickup: { enabled: true, fee: money(30, currency), prep_days: 1 }
173
+ },
174
+ {
175
+ id: "br_occidente",
176
+ name: "Punto de recolecci\xF3n Occidente",
177
+ kind: "pickup_point",
178
+ address: "Av. Vallarta 1500, Col. Americana",
179
+ city: "Guadalajara",
180
+ postal_code: "44100",
181
+ phone: "+52 33 0000 0003",
182
+ lat: 20.6736,
183
+ lng: -103.3897,
184
+ timezone: MX_TZ,
185
+ hours: "Mo-Fr 11:00-20:00",
186
+ opening_hours_text: "Lun\u2013Vie 11:00\u201320:00",
187
+ opening_hours: { weekly: weekdays("11:00", "20:00") },
188
+ services: ["pickup"],
189
+ contacts: contacts("+52 33 0000 0003"),
190
+ pickup: { enabled: false, fee: null, prep_days: 2 }
191
+ }
192
+ ];
193
+ }
194
+ var MOCK_POSTAL_CENTROIDS = {
195
+ "06000": { lat: 19.4326, lng: -99.1332 },
196
+ "64000": { lat: 25.6714, lng: -100.309 },
197
+ "44100": { lat: 20.6767, lng: -103.3475 },
198
+ "03100": { lat: 19.3885, lng: -99.1719 }
199
+ };
131
200
  function buildShop(currency, imageUrl = MOCK_IMAGE_URL) {
132
201
  return {
133
202
  name: "Mi tienda",
@@ -139,10 +208,7 @@ function buildShop(currency, imageUrl = MOCK_IMAGE_URL) {
139
208
  country_code: "MX",
140
209
  logo: { url: imageUrl("logo", 256, 256), alt: "Mi tienda", width: 256, height: 256 },
141
210
  contact: { email: "hola@mi-tienda.example", phone: "+52 55 0000 0000", whatsapp: "+5215500000000" },
142
- branches: [
143
- { id: "br_centro", name: "Sucursal Centro", address: "Av. Principal 100, Col. Centro", city: "Ciudad de M\xE9xico", phone: "+52 55 0000 0001", lat: 19.4326, lng: -99.1332, hours: "Mo-Fr 09:00-19:00, Sa 09:00-14:00" },
144
- { id: "br_norte", name: "Sucursal Norte", address: "Calle Secundaria 25, Col. Norte", city: "Monterrey", phone: null, lat: 25.6866, lng: -100.3161, hours: "Mo-Sa 10:00-18:00" }
145
- ],
211
+ branches: buildLocations(currency),
146
212
  policies: { free_shipping_min: money(999, currency), returns_days: 30 }
147
213
  };
148
214
  }
@@ -360,6 +426,7 @@ function createMockStorefront(options = {}) {
360
426
  otps: /* @__PURE__ */ new Map(),
361
427
  sessions: /* @__PURE__ */ new Map(),
362
428
  idempotency: /* @__PURE__ */ new Map(),
429
+ checkouts: /* @__PURE__ */ new Map(),
363
430
  seq: 0
364
431
  };
365
432
  }
@@ -547,7 +614,7 @@ function createMockStorefront(options = {}) {
547
614
  const percent = codes.filter((d) => d.applicable).reduce((max, d) => Math.max(max, percentFor(d.code)), 0);
548
615
  const discount = Math.round(subtotal * percent / 100);
549
616
  let shipping = null;
550
- if (cart.delivery.method === "pickup") shipping = 0;
617
+ if (cart.delivery.method === "pickup") shipping = toCents(state.shop.branches.find((b) => b.id === cart.delivery.branch_id)?.pickup?.fee?.amount ?? "0");
551
618
  else if (cart.delivery.method === "shipping" && cart.delivery.rate_id) {
552
619
  const rate = shippingRates(subtotal - discount).find((r) => r.id === cart.delivery.rate_id);
553
620
  shipping = rate ? toCents(rate.cost.amount) : null;
@@ -628,6 +695,25 @@ function createMockStorefront(options = {}) {
628
695
  body: requireNode(state.collections.find((c) => c.handle === params[0]), `Collection ${params[0]}`),
629
696
  cache: "public"
630
697
  }));
698
+ const visibleLocations = () => state.shop.branches;
699
+ const round2 = (n) => Math.round(n * 100) / 100;
700
+ const withDistance = (origin) => rankByDistance(visibleLocations(), origin).map(({ item, distanceKm }) => ({ ...item, distance_km: Math.round(distanceKm * 10) / 10 }));
701
+ route("GET", "/locations", "catalog:read", ({ search }) => {
702
+ const cp = search.get("postal_code");
703
+ const origin = cp ? MOCK_POSTAL_CENTROIDS[cp] : void 0;
704
+ return { body: { nodes: origin ? withDistance(origin) : visibleLocations() }, cache: "public" };
705
+ });
706
+ route("GET", "/locations/nearest", "catalog:read", ({ search }) => {
707
+ const origin = { lat: Number(search.get("lat") ?? NaN), lng: Number(search.get("lng") ?? NaN) };
708
+ if (search.get("lat") === null || search.get("lng") === null || !isValidPoint(origin)) {
709
+ throw new HttpError(400, "validation", "lat and lng must be a valid point", "lat");
710
+ }
711
+ return { body: { nodes: withDistance({ lat: round2(origin.lat), lng: round2(origin.lng) }) }, cache: "private" };
712
+ });
713
+ route("GET", "/locations/:id", "catalog:read", ({ params }) => ({
714
+ body: requireNode(visibleLocations().find((b) => b.id === params[0]), `Location ${params[0]}`, "id"),
715
+ cache: "public"
716
+ }));
631
717
  route("GET", "/stock", "catalog:read", ({ search }) => {
632
718
  const skus = search.getAll("sku");
633
719
  if (skus.length > 250) throw new HttpError(400, "validation", "At most 250 SKUs", "sku");
@@ -711,7 +797,7 @@ function createMockStorefront(options = {}) {
711
797
  const cart = renderCart(getCartRecord(params[0]));
712
798
  const net = toCents(cart.cost.subtotal.amount) - toCents(cart.cost.discount.amount);
713
799
  return {
714
- body: { rates: shippingRates(net), pickup: state.shop.branches.map((b) => ({ branch_id: b.id, name: b.name })), partial: false, unavailable: [] },
800
+ body: { rates: shippingRates(net), pickup: state.shop.branches.filter((b) => b.pickup?.enabled !== false).map((b) => ({ branch_id: b.id, name: b.name, address: b.address, city: b.city })), partial: false, unavailable: [] },
715
801
  cache: "private"
716
802
  };
717
803
  });
@@ -729,7 +815,7 @@ function createMockStorefront(options = {}) {
729
815
  cart.delivery = { method: "shipping", rate_id: rateId, branch_id: null };
730
816
  } else if (body.method === "pickup") {
731
817
  const branchId = body.branch_id;
732
- if (typeof branchId !== "string" || !state.shop.branches.some((b) => b.id === branchId)) {
818
+ if (typeof branchId !== "string" || !state.shop.branches.some((b) => b.id === branchId && b.pickup?.enabled !== false)) {
733
819
  throw new HttpError(400, "validation", "Unknown branch_id", "branch_id");
734
820
  }
735
821
  cart.delivery = { method: "pickup", rate_id: null, branch_id: branchId };
@@ -798,9 +884,15 @@ function createMockStorefront(options = {}) {
798
884
  stock_hold_expires_at: new Date(Date.now() + 30 * 6e4).toISOString()
799
885
  }
800
886
  };
887
+ state.checkouts.set(checkoutId, result);
801
888
  if (key) state.idempotency.set(`${params[0]}:${key}`, { status: 201, body: result });
802
889
  return { status: 201, body: result, cache: "private" };
803
890
  });
891
+ route("GET", "/checkouts/:id", "checkout:write", ({ params }) => {
892
+ const found = state.checkouts.get(params[0]);
893
+ if (!found) throw new HttpError(404, "not_found", "Checkout not found");
894
+ return { body: found, cache: "private" };
895
+ });
804
896
  route("POST", "/customer/otp", "customer:write", ({ body }) => {
805
897
  state.otps.set(identifierOf(body), otpCode);
806
898
  return { status: 204 };
@@ -988,6 +1080,6 @@ function createMockStorefront(options = {}) {
988
1080
  };
989
1081
  }
990
1082
 
991
- export { MOCK_CURRENCY, MOCK_CUSTOMER_EMAIL, MOCK_IMAGE_URL, createMockStorefront };
1083
+ export { MOCK_CURRENCY, MOCK_CUSTOMER_EMAIL, MOCK_IMAGE_URL, MOCK_POSTAL_CENTROIDS, createMockStorefront };
992
1084
  //# sourceMappingURL=mock.js.map
993
1085
  //# sourceMappingURL=mock.js.map