@asteby/storefront 0.8.0 → 0.10.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/README.md CHANGED
@@ -65,6 +65,30 @@ const me = storefront.withCustomerToken(token) // sends X-Customer-Token
65
65
  await me.customer.orders()
66
66
  ```
67
67
 
68
+ Stores that also offer email + password accounts ask what the store supports and
69
+ then use the password routes (the `StorefrontError` codes are `unauthorized` for
70
+ wrong credentials or codes, `conflict` for an email already registered and
71
+ `rate_limited` for too many attempts):
72
+
73
+ ```ts
74
+ const caps = await storefront.customer.capabilities()
75
+ // { password: boolean, email_verification: boolean, otp_channels: ('email' | 'whatsapp')[] }
76
+
77
+ const res = await storefront.customer.register({ email, password, first_name, last_name })
78
+ const session =
79
+ res.status === 'created'
80
+ ? res.session // no verification required: already signed in
81
+ : await storefront.customer.verifyRegistration({ email, code }) // code from the email
82
+
83
+ const again = await storefront.customer.loginWithPassword({ email, password })
84
+
85
+ // Signed-in buyer sets or changes the password (current_password when it already has one):
86
+ await storefront.customer.setPassword({ password, current_password }, { customerToken: session.token })
87
+
88
+ // Forgot password: requestOtp({ email }) emails a code, then
89
+ await storefront.customer.resetPassword({ email, code, password })
90
+ ```
91
+
68
92
  Checkout always sends an `Idempotency-Key` (generated with
69
93
  `crypto.randomUUID()` unless you pass `{ idempotencyKey }`):
70
94
 
@@ -118,6 +142,14 @@ Mock behaviour:
118
142
  - Checkout: returns a fake order and a `redirect_url`, decrements stock and
119
143
  honours `Idempotency-Key`.
120
144
  - Buyer: OTP code `000000`; seed customer `cliente@example.com` with one order.
145
+ - Password accounts: `customer.capabilities()` is configurable
146
+ (`createMockStorefront({ customerCapabilities })`, default
147
+ `{ password: true, email_verification: true, otp_channels: ['email'] }`).
148
+ `register` answers `verification_required` and the code is `000000`; accounts
149
+ live in memory (passwords of 10-128 characters); `409` for a registered email,
150
+ `401` for wrong credentials/codes, `429` after `maxLoginAttempts` (5) failed
151
+ logins, `403` when `password` is disabled. The seed customer has no password
152
+ until `setPassword` (or `resetPassword` with the OTP code).
121
153
  - Content: theme tokens, `home` page (hero, product_grid, collection_list,
122
154
  rich_text, faq), `main` and `footer` menus, legal pages (`terminos`,
123
155
  `privacidad`, `devoluciones`) and two articles. `?preview=` returns a draft.
@@ -291,7 +323,7 @@ over language) and `hreflangLinks` for per-market SEO.
291
323
  Resources: `shop.get`, `products.list/get/recommendations`,
292
324
  `collections.list/get`, `stock.get`,
293
325
  `carts.create/get/addLines/updateLines/removeLines/setDiscountCodes/setBuyer/setShippingAddress/deliveryOptions/setDelivery/checkout`,
294
- `customer.requestOtp/createSession/get/orders/order/requestReturn/requestInvoice/addresses.{list,create,update,delete}`,
326
+ `customer.requestOtp/createSession/capabilities/register/verifyRegistration/loginWithPassword/setPassword/resetPassword/get/orders/order/requestReturn/requestInvoice/addresses.{list,create,update,delete}`,
295
327
  `content.theme/page/menu/articles/article`. Every method takes a last
296
328
  `options` argument: `{ cache, signal, next, headers, timeoutMs, customerToken, clientIp }`
297
329
  (plus `idempotencyKey` on writes and `preview` on pages/articles); unknown keys
package/dist/index.cjs CHANGED
@@ -382,6 +382,24 @@ function createStorefrontClient(config) {
382
382
  requestOtp: (identifier, options) => write("POST", "/storefront/customer/otp", identifier, options),
383
383
  /** Exchanges the code for a buyer session (`token` goes in `customerToken`). */
384
384
  createSession: (input, options) => write("POST", "/storefront/customer/session", input, options),
385
+ /** What the store supports (password login, email verification, OTP channels). Drives which forms to show. */
386
+ capabilities: (options) => get("/storefront/customer/capabilities", void 0, options),
387
+ /**
388
+ * Creates an account with email + password. `verification_required` (202): a code was emailed, finish with
389
+ * `verifyRegistration`. `created` (201): the account exists and `session` is ready. `409` when the email is taken.
390
+ */
391
+ register: async (input, options) => {
392
+ const res = await write("POST", "/storefront/customer/register", input, options);
393
+ return res && "token" in res ? { status: "created", session: res } : { status: "verification_required" };
394
+ },
395
+ /** Confirms the emailed registration code and returns the new buyer session. */
396
+ verifyRegistration: (input, options) => write("POST", "/storefront/customer/register/verify", input, options),
397
+ /** Email + password login. `401` for wrong credentials. */
398
+ loginWithPassword: (input, options) => write("POST", "/storefront/customer/login", input, options),
399
+ /** Sets or changes the password of the signed-in buyer (`options.customerToken`, or a `withCustomerToken` client). */
400
+ setPassword: (input, options) => write("PUT", "/storefront/customer/password", input, options),
401
+ /** Resets a forgotten password with the code from `requestOtp({ email })`. */
402
+ resetPassword: (input, options) => write("POST", "/storefront/customer/password/reset", input, options),
385
403
  get: (options) => get("/storefront/customer", void 0, options),
386
404
  orders: (params, options) => get("/storefront/customer/orders", params, options),
387
405
  /** `null` when the order does not exist or belongs to someone else. */
@@ -1110,8 +1128,35 @@ function hreflangLinks(markets, path, defaultMarket, protocol = "https") {
1110
1128
  return links;
1111
1129
  }
1112
1130
 
1131
+ // src/delivery.ts
1132
+ function parseDelivery(value) {
1133
+ const raw = (value ?? "").trim();
1134
+ const i = raw.indexOf(":");
1135
+ const head = i === -1 ? raw : raw.slice(0, i);
1136
+ const id = i === -1 ? "" : raw.slice(i + 1);
1137
+ const kind = head === "pickup" ? "pickup" : head === "ship" ? "ship" : "rate";
1138
+ return { kind, id, method: kind === "pickup" ? "pickup" : "shipping", addressOnly: kind === "ship" };
1139
+ }
1140
+ function deliveryInput(choice) {
1141
+ if (choice.addressOnly) return null;
1142
+ if (choice.kind === "pickup") return { method: "pickup", branch_id: choice.id };
1143
+ return { method: "shipping", rate_id: choice.id || void 0 };
1144
+ }
1145
+ var MISSING_WEIGHT = "missing_weight";
1146
+ function deliveryNotices(delivery) {
1147
+ const all = delivery?.unavailable ?? [];
1148
+ const missingWeight = all.filter((u) => u.code === MISSING_WEIGHT);
1149
+ const unavailable = all.filter((u) => u.code !== MISSING_WEIGHT);
1150
+ return {
1151
+ missingWeight,
1152
+ unavailable,
1153
+ hasNotices: missingWeight.length > 0 || unavailable.length > 0 || delivery?.partial === true
1154
+ };
1155
+ }
1156
+
1113
1157
  exports.CLIENT_IP_HEADER = CLIENT_IP_HEADER;
1114
1158
  exports.COUNTRY_HEADERS = COUNTRY_HEADERS;
1159
+ exports.MISSING_WEIGHT = MISSING_WEIGHT;
1115
1160
  exports.NOTE_MAX_LENGTH = NOTE_MAX_LENGTH;
1116
1161
  exports.StorefrontError = StorefrontError;
1117
1162
  exports.appendParams = appendParams;
@@ -1123,6 +1168,8 @@ exports.clampPercent = clampPercent;
1123
1168
  exports.createStorefrontClient = createStorefrontClient;
1124
1169
  exports.declineMessage = declineMessage;
1125
1170
  exports.declineMessageKey = declineMessageKey;
1171
+ exports.deliveryInput = deliveryInput;
1172
+ exports.deliveryNotices = deliveryNotices;
1126
1173
  exports.formatAvailabilityMessage = formatAvailabilityMessage;
1127
1174
  exports.formatMoney = formatMoney;
1128
1175
  exports.formatVoucherExpiry = formatVoucherExpiry;
@@ -1133,6 +1180,7 @@ exports.isTokenPublishable = isTokenPublishable;
1133
1180
  exports.negotiateLocale = negotiateLocale;
1134
1181
  exports.normalizeClientIp = normalizeClientIp;
1135
1182
  exports.normalizeNote = normalizeNote;
1183
+ exports.parseDelivery = parseDelivery;
1136
1184
  exports.parseMoney = parseMoney;
1137
1185
  exports.parseProductFilters = parseProductFilters;
1138
1186
  exports.paymentErrorView = paymentErrorView;