@occluze/tether 0.6.8 → 0.7.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.
Files changed (259) hide show
  1. package/README.md +11 -11
  2. package/dist/esm/astro.js +2 -2
  3. package/dist/esm/chunks/account-UIPWJQ3Y.js +1 -0
  4. package/dist/esm/chunks/account-pages-6ROA6Y4V.js +1 -0
  5. package/dist/esm/chunks/analytics-2V632IRV.js +1 -0
  6. package/dist/esm/chunks/chunk-4GCXM764.js +1 -0
  7. package/dist/esm/chunks/chunk-56FCLJJD.js +1 -0
  8. package/dist/esm/chunks/chunk-5Z5O3767.js +1 -0
  9. package/dist/esm/chunks/chunk-6OZJCAGZ.js +1 -0
  10. package/dist/esm/chunks/chunk-A5SYCVQM.js +1 -0
  11. package/dist/esm/chunks/chunk-BA4LQJJQ.js +1 -0
  12. package/dist/esm/chunks/chunk-BFTZR4OB.js +4 -0
  13. package/dist/esm/chunks/chunk-C5JYQCWH.js +1 -0
  14. package/dist/esm/chunks/chunk-E5YO6274.js +1 -0
  15. package/dist/esm/chunks/chunk-MPDWM2NN.js +1 -0
  16. package/dist/esm/chunks/chunk-T44MUL4Y.js +1 -0
  17. package/dist/esm/chunks/chunk-YLUULATY.js +1 -0
  18. package/dist/esm/chunks/diagnose-3FEKRIEK.js +14 -0
  19. package/dist/esm/chunks/extras-6POFBNOP.js +1 -0
  20. package/dist/esm/chunks/markets-ui-FD6NI2OG.js +1 -0
  21. package/dist/esm/chunks/search-UJ73YBQ5.js +1 -0
  22. package/dist/esm/index.js +1 -1
  23. package/dist/esm/server.js +2 -2
  24. package/dist/presets/barba.esm.js +19 -23
  25. package/dist/tether.account-pages.js +320 -365
  26. package/dist/tether.account-pages.min.js +1 -1
  27. package/dist/tether.account.js +242 -491
  28. package/dist/tether.account.min.js +1 -1
  29. package/dist/tether.analytics.js +66 -88
  30. package/dist/tether.analytics.min.js +1 -1
  31. package/dist/tether.diagnose.js +36 -33
  32. package/dist/tether.diagnose.min.js +2 -2
  33. package/dist/tether.extras.js +28 -36
  34. package/dist/tether.extras.min.js +1 -1
  35. package/dist/tether.js +1270 -894
  36. package/dist/tether.markets.js +73 -90
  37. package/dist/tether.markets.min.js +1 -1
  38. package/dist/tether.min.js +0 -0
  39. package/dist/tether.min.js.map +4 -4
  40. package/dist/tether.search.js +44 -68
  41. package/dist/tether.search.min.js +1 -1
  42. package/dist/types/server/src/shared/account-orders.d.ts +44 -0
  43. package/dist/types/server/src/shared/account-routes.d.ts +153 -0
  44. package/dist/types/server/src/shared/api-versions.d.ts +13 -0
  45. package/dist/types/server/src/shared/error-message.d.ts +2 -0
  46. package/dist/types/server/src/shared/json.d.ts +25 -0
  47. package/dist/types/server/src/shared/market-codes.d.ts +16 -0
  48. package/dist/types/src/account/addresses-view.d.ts +5 -0
  49. package/dist/types/src/account/answers.d.ts +40 -0
  50. package/dist/types/src/account/markup.d.ts +19 -0
  51. package/dist/types/src/account/operations.d.ts +41 -0
  52. package/dist/types/src/account/order-lines.d.ts +13 -0
  53. package/dist/types/src/account/order-list.d.ts +12 -0
  54. package/dist/types/src/account/order-page.d.ts +6 -0
  55. package/dist/types/src/account/page-answers.d.ts +182 -0
  56. package/dist/types/src/account/page-events.d.ts +2 -0
  57. package/dist/types/src/account/server-client.d.ts +60 -0
  58. package/dist/types/src/account/subscriptions-view.d.ts +2 -0
  59. package/dist/types/src/account-api.d.ts +18 -0
  60. package/dist/types/src/account-marks.d.ts +15 -0
  61. package/dist/types/src/account-pages.d.ts +8 -0
  62. package/dist/types/src/account.d.ts +64 -0
  63. package/dist/types/src/amounts.d.ts +12 -0
  64. package/dist/types/src/analytics-shopify.d.ts +41 -0
  65. package/dist/types/src/analytics.d.ts +2 -0
  66. package/dist/types/src/api-version.d.ts +28 -0
  67. package/dist/types/src/astro.d.ts +42 -0
  68. package/dist/types/src/cart/cart-shape.d.ts +43 -0
  69. package/dist/types/src/cart/checkout.d.ts +16 -0
  70. package/dist/types/src/cart/drawer.d.ts +18 -0
  71. package/dist/types/src/cart/mutations.d.ts +79 -0
  72. package/dist/types/src/cart/render.d.ts +17 -0
  73. package/dist/types/src/cart/store.d.ts +182 -0
  74. package/dist/types/src/cart.d.ts +106 -0
  75. package/dist/types/src/client.d.ts +100 -0
  76. package/dist/types/src/collection.d.ts +25 -0
  77. package/dist/types/src/config-sections.d.ts +40 -0
  78. package/dist/types/src/config.d.ts +185 -0
  79. package/dist/types/src/controls/cart-controls.d.ts +2 -0
  80. package/dist/types/src/controls/discount.d.ts +2 -0
  81. package/dist/types/src/controls/extras.d.ts +5 -0
  82. package/dist/types/src/controls/navigation.d.ts +12 -0
  83. package/dist/types/src/diagnose-markup.d.ts +19 -0
  84. package/dist/types/src/diagnose.d.ts +60 -0
  85. package/dist/types/src/dom.d.ts +75 -0
  86. package/dist/types/src/extras.d.ts +21 -0
  87. package/dist/types/src/fragments.d.ts +158 -0
  88. package/dist/types/src/globals.d.ts +15 -0
  89. package/dist/types/src/images.d.ts +20 -0
  90. package/dist/types/src/index.d.ts +167 -0
  91. package/dist/types/src/initial.d.ts +56 -0
  92. package/dist/types/src/lazy.d.ts +28 -0
  93. package/dist/types/src/loader.d.ts +84 -0
  94. package/dist/types/src/market-codes.d.ts +6 -0
  95. package/dist/types/src/markets-ui.d.ts +32 -0
  96. package/dist/types/src/markets.d.ts +72 -0
  97. package/dist/types/src/markup.d.ts +131 -0
  98. package/dist/types/src/mounting.d.ts +46 -0
  99. package/dist/types/src/page-market.d.ts +27 -0
  100. package/dist/types/src/presets/barba.d.ts +56 -0
  101. package/dist/types/src/product-events.d.ts +2 -0
  102. package/dist/types/src/product-render.d.ts +17 -0
  103. package/dist/types/src/product-shape.d.ts +88 -0
  104. package/dist/types/src/product-state.d.ts +110 -0
  105. package/dist/types/src/product.d.ts +66 -0
  106. package/dist/types/src/repeaters.d.ts +16 -0
  107. package/dist/types/src/search.d.ts +33 -0
  108. package/dist/types/src/selling-plans.d.ts +64 -0
  109. package/dist/types/src/server.d.ts +88 -0
  110. package/dist/types/src/shopify-values.d.ts +46 -0
  111. package/dist/types/src/status.d.ts +33 -0
  112. package/dist/types/src/storage.d.ts +12 -0
  113. package/dist/types/src/store-html.d.ts +39 -0
  114. package/dist/types/src/storefront/catalog.d.ts +38 -0
  115. package/dist/types/src/storefront/json-ld.d.ts +20 -0
  116. package/dist/types/src/variant-render.d.ts +14 -0
  117. package/package.json +24 -23
  118. package/src/account/addresses-view.ts +58 -0
  119. package/src/account/answers.ts +79 -0
  120. package/src/account/markup.ts +36 -0
  121. package/src/account/operations.ts +145 -0
  122. package/src/account/{order-lines.js → order-lines.ts} +20 -41
  123. package/src/account/order-list.ts +107 -0
  124. package/src/account/order-page.ts +137 -0
  125. package/src/account/page-answers.ts +317 -0
  126. package/src/account/{page-events.js → page-events.ts} +55 -90
  127. package/src/account/server-client.ts +183 -0
  128. package/src/account/{subscriptions-view.js → subscriptions-view.ts} +25 -68
  129. package/src/account-api.ts +98 -0
  130. package/src/account-marks.ts +35 -0
  131. package/src/{account-pages.js → account-pages.ts} +29 -37
  132. package/src/account.ts +284 -0
  133. package/src/amounts.ts +64 -0
  134. package/src/{analytics-shopify.js → analytics-shopify.ts} +112 -107
  135. package/src/analytics.ts +315 -0
  136. package/src/{api-version.js → api-version.ts} +25 -31
  137. package/src/{astro.js → astro.ts} +110 -104
  138. package/src/cart/cart-shape.ts +25 -0
  139. package/src/cart/checkout.ts +101 -0
  140. package/src/cart/{drawer.js → drawer.ts} +18 -31
  141. package/src/cart/mutations.ts +237 -0
  142. package/src/cart/{render.js → render.ts} +68 -96
  143. package/src/cart/store.ts +279 -0
  144. package/src/{cart.js → cart.ts} +82 -128
  145. package/src/client.ts +391 -0
  146. package/src/{collection.js → collection.ts} +30 -38
  147. package/src/config-sections.ts +284 -0
  148. package/src/config.ts +480 -0
  149. package/src/controls/{cart-controls.js → cart-controls.ts} +22 -54
  150. package/src/controls/{discount.js → discount.ts} +13 -34
  151. package/src/controls/{extras.js → extras.ts} +15 -24
  152. package/src/controls/{navigation.js → navigation.ts} +24 -30
  153. package/src/{diagnose-markup.js → diagnose-markup.ts} +37 -72
  154. package/src/{diagnose.js → diagnose.ts} +95 -96
  155. package/src/dom.ts +268 -0
  156. package/src/{extras.js → extras.ts} +43 -52
  157. package/src/fragments.ts +261 -0
  158. package/src/globals.d.ts +15 -0
  159. package/src/{images.js → images.ts} +30 -43
  160. package/src/index.ts +415 -0
  161. package/src/initial.ts +101 -0
  162. package/src/lazy-iife.ts +197 -0
  163. package/src/lazy.ts +42 -0
  164. package/src/{loader.js → loader.ts} +149 -123
  165. package/src/market-codes.ts +6 -0
  166. package/src/{markets-ui.js → markets-ui.ts} +91 -68
  167. package/src/markets.ts +246 -0
  168. package/src/markup.ts +127 -0
  169. package/src/{mounting.js → mounting.ts} +88 -101
  170. package/src/{page-market.js → page-market.ts} +32 -38
  171. package/src/part-integrity.ts +7 -0
  172. package/src/parts/account-pages.ts +7 -0
  173. package/src/parts/account.ts +7 -0
  174. package/src/parts/analytics.ts +7 -0
  175. package/src/parts/diagnose.ts +7 -0
  176. package/src/parts/extras.ts +7 -0
  177. package/src/parts/markets.ts +7 -0
  178. package/src/parts/search.ts +7 -0
  179. package/src/presets/barba.ts +194 -0
  180. package/src/{product-events.js → product-events.ts} +33 -48
  181. package/src/{product-render.js → product-render.ts} +38 -77
  182. package/src/product-shape.ts +49 -0
  183. package/src/product-state.ts +318 -0
  184. package/src/{product.js → product.ts} +90 -126
  185. package/src/{repeaters.js → repeaters.ts} +40 -52
  186. package/src/{search.js → search.ts} +85 -103
  187. package/src/selling-plans.ts +145 -0
  188. package/src/server.ts +211 -0
  189. package/src/{shopify-values.js → shopify-values.ts} +24 -22
  190. package/src/{status.js → status.ts} +34 -54
  191. package/src/storage.ts +34 -0
  192. package/src/store-html.ts +359 -0
  193. package/src/storefront/catalog.ts +196 -0
  194. package/src/storefront/{json-ld.js → json-ld.ts} +45 -68
  195. package/src/{variant-render.js → variant-render.ts} +24 -50
  196. package/dist/esm/chunks/account-C3NP6HFB.js +0 -1
  197. package/dist/esm/chunks/account-pages-WLK374FO.js +0 -1
  198. package/dist/esm/chunks/analytics-G3SAWMNL.js +0 -1
  199. package/dist/esm/chunks/chunk-27PJJZGC.js +0 -1
  200. package/dist/esm/chunks/chunk-2FSXS55U.js +0 -1
  201. package/dist/esm/chunks/chunk-FCSWQDVV.js +0 -1
  202. package/dist/esm/chunks/chunk-FOMSMIAM.js +0 -1
  203. package/dist/esm/chunks/chunk-GZJTCLLW.js +0 -1
  204. package/dist/esm/chunks/chunk-HEQILZVR.js +0 -1
  205. package/dist/esm/chunks/chunk-JOOEXYF3.js +0 -4
  206. package/dist/esm/chunks/chunk-MPTQYLSM.js +0 -1
  207. package/dist/esm/chunks/chunk-NEHZ37TU.js +0 -3
  208. package/dist/esm/chunks/chunk-V74KGEJF.js +0 -1
  209. package/dist/esm/chunks/chunk-VT4CDUJJ.js +0 -1
  210. package/dist/esm/chunks/chunk-YJLWX2HK.js +0 -1
  211. package/dist/esm/chunks/diagnose-6VVGZNTY.js +0 -14
  212. package/dist/esm/chunks/extras-GJVRDFM3.js +0 -1
  213. package/dist/esm/chunks/markets-ui-UNB4PTA7.js +0 -1
  214. package/dist/esm/chunks/search-OU75RNQL.js +0 -1
  215. package/src/account/addresses-view.js +0 -92
  216. package/src/account/browser-session.js +0 -359
  217. package/src/account/markup.js +0 -48
  218. package/src/account/operations.js +0 -180
  219. package/src/account/order-list.js +0 -91
  220. package/src/account/order-page.js +0 -192
  221. package/src/account/server-client.js +0 -172
  222. package/src/account/shared.js +0 -111
  223. package/src/account/shopify-auth.js +0 -150
  224. package/src/account-api.js +0 -118
  225. package/src/account-links.js +0 -35
  226. package/src/account.js +0 -342
  227. package/src/amounts.js +0 -36
  228. package/src/analytics.js +0 -352
  229. package/src/cart/checkout.js +0 -97
  230. package/src/cart/mutations.js +0 -234
  231. package/src/cart/store.js +0 -326
  232. package/src/client.js +0 -267
  233. package/src/config.js +0 -349
  234. package/src/dom.js +0 -287
  235. package/src/fragments.js +0 -237
  236. package/src/index.js +0 -353
  237. package/src/initial.js +0 -87
  238. package/src/lazy-iife.js +0 -116
  239. package/src/lazy.js +0 -39
  240. package/src/market-codes.js +0 -35
  241. package/src/markets.js +0 -334
  242. package/src/markup.js +0 -64
  243. package/src/parts/account-pages.js +0 -6
  244. package/src/parts/account.js +0 -6
  245. package/src/parts/analytics.js +0 -6
  246. package/src/parts/diagnose.js +0 -6
  247. package/src/parts/extras.js +0 -6
  248. package/src/parts/markets.js +0 -6
  249. package/src/parts/search.js +0 -6
  250. package/src/presets/barba.js +0 -190
  251. package/src/product-state.js +0 -318
  252. package/src/selling-plans.js +0 -154
  253. package/src/server.js +0 -215
  254. package/src/store-html.js +0 -0
  255. package/src/storefront/catalog.js +0 -199
  256. package/types/astro.d.ts +0 -28
  257. package/types/barba.d.ts +0 -16
  258. package/types/index.d.ts +0 -577
  259. package/types/server.d.ts +0 -182
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  (() => {
3
2
  var __defProp = Object.defineProperty;
4
3
  var __export = (target, all) => {
@@ -6,21 +5,18 @@
6
5
  __defProp(target, name, { get: all[name], enumerable: true });
7
6
  };
8
7
 
9
- // src/account.js
8
+ // src/account.ts
10
9
  var account_exports = {};
11
10
  __export(account_exports, {
12
11
  addresses: () => addresses,
13
12
  customer: () => customer,
14
13
  deleteAddress: () => deleteAddress,
15
- getToken: () => getToken,
16
- handleCallback: () => handleCallback,
17
14
  isLoggedIn: () => isLoggedIn,
18
15
  login: () => login,
19
16
  logout: () => logout,
20
17
  mountAccount: () => mountAccount,
21
18
  order: () => order,
22
19
  orders: () => orders,
23
- query: () => query2,
24
20
  render: () => render,
25
21
  requestReturn: () => requestReturn,
26
22
  saveAddress: () => saveAddress,
@@ -29,412 +25,193 @@
29
25
  updateProfile: () => updateProfile
30
26
  });
31
27
 
32
- // tether-core:config.js
33
- var m = window.Tether.__core["config.js"];
34
- var { DEFAULTS, cfg, configure, isConfigured, log, reportError, resolveConfig, toMetafieldIdentifier, warn } = m;
28
+ // tether-core:config.ts
29
+ var m = window.Tether.__core["config.ts"];
30
+ var [cfg, isConfigured, log, MARKET_SOURCES, parseMarkets, reportError, warn] = m;
35
31
 
36
- // tether-core:client.js
37
- var m2 = window.Tether.__core["client.js"];
38
- var { TetherError, endpoint, gql, request, unwrap, withContext } = m2;
32
+ // tether-core:client.ts
33
+ var m2 = window.Tether.__core["client.ts"];
34
+ var [endpoint, gql, orNull, shaped, TetherError] = m2;
39
35
 
40
- // tether-core:dom.js
41
- var m3 = window.Tether.__core["dom.js"];
42
- var { attr, busy, cdnUrl, emit, formatDate, formatMoney, formatPercent, get, has, hasTemplate, imageUrl, notifyLayoutChanged, parseJSONAttr, productUrl, qsa, repeat, repeatKeyed, sameImage, scoped, sel, setImage, setSelected, setStoreHtml, setText, setTextTracked, show, toAttributes, watchImages } = m3;
36
+ // tether-core:dom.ts
37
+ var m3 = window.Tether.__core["dom.ts"];
38
+ var [ANALYTICS_EVENTS, attr, attributesFromJson, emit, formatDate, formatMoney, get, has, hasTemplate, isOwnEvent, parseJSONAttr, productUrl, qsa, repeat, sel, setImage, setText, show] = m3;
43
39
 
44
- // tether-core:cart.js
45
- var m4 = window.Tether.__core["cart.js"];
46
- var { Cart, trapFocus } = m4;
40
+ // tether-core:cart.ts
41
+ var m4 = window.Tether.__core["cart.ts"];
42
+ var [Cart] = m4;
47
43
 
48
- // tether-core:lazy.js
49
- var m5 = window.Tether.__core["lazy.js"];
50
- var { coreModules, loadPart } = m5;
44
+ // tether-core:lazy.ts
45
+ var m5 = window.Tether.__core["lazy.ts"];
46
+ var [loadPart] = m5;
51
47
 
52
- // server/src/shared/account-documents.js
53
- var MONEY = "amount currencyCode";
54
- var CUSTOMER_QUERY = "query TetherCustomer { customer { id firstName lastName displayName emailAddress { emailAddress } defaultAddress { formatted } } }";
55
- var ORDERS_QUERY = `query TetherOrders($first:Int!){customer{orders(first:$first,sortKey:PROCESSED_AT,reverse:true){nodes{id name processedAt financialStatus fulfillmentStatus statusPageUrl totalPrice{${MONEY}}lineItems(first:20){nodes{title variantTitle quantity image{url altText}}}}}}}`;
56
-
57
- // server/src/shared/base64url.js
58
- function toBase64Url(bytes) {
59
- return btoa(String.fromCharCode(...new Uint8Array(bytes))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
48
+ // server/src/shared/json.ts
49
+ function isRecord(value) {
50
+ return value !== null && typeof value === "object" && !Array.isArray(value);
51
+ }
52
+ function field(value, key) {
53
+ return isRecord(value) ? value[key] : void 0;
60
54
  }
61
- function fromBase64Url(text) {
62
- const base64 = text.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(text.length / 4) * 4, "=");
63
- return Uint8Array.from(atob(base64), (char) => char.charCodeAt(0));
55
+ function asList(value) {
56
+ return Array.isArray(value) ? value : [];
64
57
  }
65
- function randomToken(bytes = 32) {
66
- return toBase64Url(crypto.getRandomValues(new Uint8Array(bytes)));
58
+ function textOrNull(value) {
59
+ return typeof value === "string" && value !== "" ? value : null;
67
60
  }
61
+ var numberOrNull = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
62
+ var countOrZero = (value) => numberOrNull(value) ?? 0;
63
+ var listOf = (value, read) => asList(value).map((item) => read(item));
64
+ var nodesOf = (connection, read) => ({
65
+ nodes: listOf(field(connection, "nodes"), read)
66
+ });
67
+ var textList = (value) => listOf(value, textOrNull).filter((line) => line !== null);
68
68
 
69
- // src/account/shared.js
70
- var sessionKey = () => `${cfg.prefix}:account:${cfg.domain}`;
71
- var pendingLoginKey = () => `${cfg.prefix}:account-login:${cfg.domain}`;
72
- var hintKey = () => `${cfg.prefix}:account-hint:${cfg.domain}`;
73
- var sessionArea = () => cfg.account?.remember ? "local" : "session";
74
- var storageOf = (area) => area === "local" ? window.localStorage : window.sessionStorage;
75
- function readJsonIfAllowed(area, key) {
76
- try {
77
- return JSON.parse(storageOf(area).getItem(key) ?? "null");
78
- } catch {
79
- return null;
80
- }
69
+ // server/src/shared/error-message.ts
70
+ function messageOf(error) {
71
+ return error instanceof Error ? error.message : String(error);
81
72
  }
82
- function writeJsonIfAllowed(area, key, value) {
73
+
74
+ // src/storage.ts
75
+ function setStored(key, value, area = "localStorage") {
83
76
  try {
84
- if (value === null) storageOf(area).removeItem(key);
85
- else storageOf(area).setItem(key, JSON.stringify(value));
77
+ window[area].setItem(key, value);
86
78
  } catch {
87
79
  }
88
80
  }
89
- function setLoginHint(loggedIn) {
90
- writeJsonIfAllowed("local", hintKey(), loggedIn ? 1 : null);
91
- }
92
- var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
93
- var textOrNull = (value) => typeof value === "string" ? value : null;
94
- async function readJsonObjectOrEmpty(response) {
95
- let json;
81
+ function removeStored(key, area = "localStorage") {
96
82
  try {
97
- json = await response.json();
83
+ window[area].removeItem(key);
98
84
  } catch {
99
- return {};
100
85
  }
101
- return isRecord(json) ? json : {};
102
- }
103
- function navigate(url) {
104
- const replacement = cfg.account?.navigate;
105
- if (replacement) replacement(url);
106
- else window.location.assign(url);
107
86
  }
108
- var loginLanguage = (locale) => locale || cfg.account?.locale || (cfg.locale || "").split("-")[0] || "";
109
- var loginCountry = () => cfg.country ? cfg.country.toUpperCase() : "";
110
87
 
111
- // src/account/shopify-auth.js
112
- var DEFAULT_TOKEN_SECONDS = 3600;
113
- var endpoints = null;
114
- async function wellKnown(document2) {
115
- const shop = cfg.account?.shopDomain || cfg.domain;
116
- const response = await fetch(`https://${shop}/.well-known/${document2}`);
117
- if (!response.ok) {
118
- throw new TetherError(`Customer accounts: ${document2} answered ${response.status}`, { status: response.status });
88
+ // src/account-marks.ts
89
+ var hintKey = () => `${cfg.prefix}:account-hint:${cfg.domain}`;
90
+ var isLoginOutcome = (value) => value === "in" || value === "expired" || value === "error";
91
+
92
+ // server/src/shared/account-orders.ts
93
+ function moneyOrNull(value) {
94
+ const amount = textOrNull(field(value, "amount"));
95
+ const currencyCode = textOrNull(field(value, "currencyCode"));
96
+ return amount === null || currencyCode === null ? null : { amount, currencyCode };
97
+ }
98
+ function imageOrNull(value) {
99
+ const url = textOrNull(field(value, "url"));
100
+ return url === null ? null : { url, altText: textOrNull(field(value, "altText")) };
101
+ }
102
+ var toOrderLine = (value) => ({
103
+ title: textOrNull(field(value, "title")),
104
+ variantTitle: textOrNull(field(value, "variantTitle")),
105
+ quantity: countOrZero(field(value, "quantity")),
106
+ image: imageOrNull(field(value, "image"))
107
+ });
108
+ var toAccountOrder = (value, id) => ({
109
+ id,
110
+ name: textOrNull(field(value, "name")),
111
+ processedAt: textOrNull(field(value, "processedAt")),
112
+ financialStatus: textOrNull(field(value, "financialStatus")),
113
+ fulfillmentStatus: textOrNull(field(value, "fulfillmentStatus")),
114
+ statusPageUrl: textOrNull(field(value, "statusPageUrl")),
115
+ totalPrice: moneyOrNull(field(value, "totalPrice")),
116
+ lineItems: nodesOf(field(value, "lineItems"), toOrderLine)
117
+ });
118
+ function readOrders(value) {
119
+ const orders2 = [];
120
+ for (const item of asList(value)) {
121
+ const id = textOrNull(field(item, "id"));
122
+ if (id === null) return { kind: "missing-id" };
123
+ orders2.push(toAccountOrder(item, id));
119
124
  }
120
- const json = (
121
- /** @type {unknown} */
122
- await response.json()
123
- );
124
- return isRecord(json) ? json : {};
125
- }
126
- function endpointIn(json, name) {
127
- const url = textOrNull(json[name]);
128
- if (!url) throw new TetherError(`Customer accounts: Shopify named no ${name}`);
129
- return url;
130
- }
131
- async function discover() {
132
- if (endpoints) return endpoints;
133
- const [openid, api] = await Promise.all([wellKnown("openid-configuration"), wellKnown("customer-account-api")]);
134
- endpoints = {
135
- issuer: endpointIn(openid, "issuer"),
136
- authorizationEndpoint: endpointIn(openid, "authorization_endpoint"),
137
- tokenEndpoint: endpointIn(openid, "token_endpoint"),
138
- endSessionEndpoint: endpointIn(openid, "end_session_endpoint"),
139
- graphql: endpointIn(api, "graphql_api")
140
- };
141
- return endpoints;
125
+ return { kind: "read", orders: orders2 };
142
126
  }
143
- async function requestToken(params) {
144
- const { tokenEndpoint } = await discover();
145
- const response = await fetch(cfg.account?.tokenUrl || tokenEndpoint, {
146
- method: "POST",
147
- body: new URLSearchParams(params)
148
- });
149
- const data = await readJsonObjectOrEmpty(response);
150
- const access = textOrNull(data["access_token"]);
151
- if (!response.ok || !access) {
152
- const ended = response.status === 400 || response.status === 401;
153
- throw new TetherError(`Customer accounts: token ${response.status} ${textOrNull(data["error"]) ?? ""}`.trim(), {
154
- status: response.status,
155
- code: ended ? "SESSION_ENDED" : "TOKEN_FAILED"
156
- });
157
- }
127
+
128
+ // src/account/answers.ts
129
+ var unexpected = (what) => new TetherError(`Customer accounts: the answer has no ${what}`);
130
+ function toAccountCustomer(value) {
131
+ const customer2 = isRecord(value) ? value : {};
132
+ const id = textOrNull(customer2["id"]);
133
+ const email = textOrNull(customer2["email"]);
134
+ const address = customer2["address"];
158
135
  return {
159
- access,
160
- refresh: textOrNull(data["refresh_token"]) || null,
161
- idToken: textOrNull(data["id_token"]) || null,
162
- expiresInSeconds: Number(data["expires_in"]) || DEFAULT_TOKEN_SECONDS
136
+ ...id === null ? {} : { id },
137
+ firstName: textOrNull(customer2["firstName"]),
138
+ lastName: textOrNull(customer2["lastName"]),
139
+ displayName: textOrNull(customer2["displayName"]),
140
+ emailAddress: email === null ? null : { emailAddress: email },
141
+ defaultAddress: Array.isArray(address) ? { formatted: textList(address) } : null
163
142
  };
164
143
  }
165
- function idTokenClaims(idToken) {
166
- const payload = idToken.split(".")[1];
167
- if (!payload) return null;
168
- let claims;
169
- try {
170
- claims = JSON.parse(new TextDecoder().decode(fromBase64Url(payload)));
171
- } catch {
172
- return null;
173
- }
174
- return isRecord(claims) ? claims : null;
175
- }
176
- function answersLogin(idToken, { nonce, issuer, client }) {
177
- const claims = idToken ? idTokenClaims(idToken) : null;
178
- if (!claims) return false;
179
- const audience = claims["aud"];
180
- const audiences = Array.isArray(audience) ? audience : [audience];
181
- const expiresAt = claims["exp"];
182
- return claims["nonce"] === nonce && claims["iss"] === issuer && audiences.includes(client) && typeof expiresAt === "number" && expiresAt * 1e3 >= Date.now();
144
+ function toAccountOrders(value) {
145
+ const reading = readOrders(value);
146
+ if (reading.kind === "missing-id") throw unexpected("order id");
147
+ return reading.orders;
183
148
  }
184
-
185
- // src/account/browser-session.js
186
- var REFRESH_MARGIN_SECONDS = 120;
187
- var LOGIN_TIMEOUT_MS = 10 * 60 * 1e3;
188
- var session = null;
189
- var customerProfile = null;
190
- var refreshing = null;
191
- function toSession(value) {
192
- if (!isRecord(value)) return null;
193
- const access = value["access"];
194
- const expiresAt = value["expiresAt"];
195
- if (typeof access !== "string" || typeof expiresAt !== "number") return null;
196
- return { access, expiresAt, refresh: textOrNull(value["refresh"]), idToken: textOrNull(value["idToken"]) };
197
- }
198
- function toPendingLogin(value) {
199
- if (!isRecord(value)) return null;
200
- const { state, nonce, verifier, redirect, returnTo, at } = value;
201
- if (typeof state !== "string" || typeof nonce !== "string" || typeof verifier !== "string") return null;
202
- if (typeof redirect !== "string" || typeof returnTo !== "string" || typeof at !== "number") return null;
203
- return { state, nonce, verifier, redirect, returnTo, at };
204
- }
205
- var currentSession = () => session ?? toSession(readJsonIfAllowed(sessionArea(), sessionKey()));
206
- var accessToken = () => session?.access ?? null;
207
- var hasBrowserLogin = () => Boolean(session && (session.refresh || session.access && session.expiresAt > Date.now()));
208
- function clientId() {
209
- const id = cfg.account?.clientId;
210
- if (!id) throw new TetherError("Customer accounts: set account.clientId", { code: "NOT_CONFIGURED" });
211
- return id;
212
- }
213
- var sha256 = async (text) => toBase64Url(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text)));
214
- async function browserLoginRedirect({ returnTo, locale }) {
215
- const client = clientId();
216
- const endpoints2 = await discover();
217
- const pending = {
218
- state: randomToken(),
219
- nonce: randomToken(),
220
- verifier: randomToken(),
221
- redirect: cfg.account?.callbackUrl || `${window.location.origin}${window.location.pathname}`,
222
- returnTo,
223
- at: Date.now()
224
- };
225
- writeJsonIfAllowed("session", pendingLoginKey(), pending);
226
- const url = new URL(endpoints2.authorizationEndpoint);
227
- const params = {
228
- client_id: client,
229
- scope: "openid email customer-account-api:full",
230
- response_type: "code",
231
- redirect_uri: pending.redirect,
232
- state: pending.state,
233
- nonce: pending.nonce,
234
- code_challenge: await sha256(pending.verifier),
235
- code_challenge_method: "S256"
149
+ function toUserError(value) {
150
+ const message = textOrNull(field(value, "message"));
151
+ if (message === null) return null;
152
+ const fieldPath = field(value, "field");
153
+ return {
154
+ message,
155
+ field: Array.isArray(fieldPath) ? textList(fieldPath) : null,
156
+ code: textOrNull(field(value, "code"))
236
157
  };
237
- const language = loginLanguage(locale);
238
- if (language) params["locale"] = language;
239
- const country = loginCountry();
240
- if (country) params["region_country"] = country;
241
- Object.entries(params).forEach(([name, value]) => {
242
- url.searchParams.set(name, value);
243
- });
244
- navigate(url.toString());
245
158
  }
246
- function keep(answer, previous) {
247
- session = {
248
- access: answer.access,
249
- expiresAt: Date.now() + Math.max(0, answer.expiresInSeconds - REFRESH_MARGIN_SECONDS) * 1e3,
250
- refresh: answer.refresh ?? previous?.refresh ?? null,
251
- idToken: answer.idToken ?? previous?.idToken ?? null
252
- };
253
- writeJsonIfAllowed(sessionArea(), sessionKey(), session);
254
- }
255
- async function handleCallback() {
256
- const params = new URLSearchParams(window.location.search);
257
- const pending = toPendingLogin(readJsonIfAllowed("session", pendingLoginKey()));
258
- if (!pending || !params.has("code") && !params.has("error") || params.get("state") !== pending.state) return false;
259
- writeJsonIfAllowed("session", pendingLoginKey(), null);
260
- const clean = new URL(window.location.href);
261
- ["code", "state", "iss", "error", "error_description"].forEach((name) => {
262
- clean.searchParams.delete(name);
263
- });
264
- window.history.replaceState(window.history.state, "", clean);
265
- const error = params.get("error");
266
- if (error !== null) {
267
- emit("account-error", { error });
268
- return false;
269
- }
270
- if (Date.now() - pending.at > LOGIN_TIMEOUT_MS) {
271
- throw new TetherError("Customer accounts: the login took too long, please try again");
272
- }
273
- const client = clientId();
274
- const answer = await requestToken({
275
- grant_type: "authorization_code",
276
- client_id: client,
277
- redirect_uri: pending.redirect,
278
- code: params.get("code") ?? "",
279
- code_verifier: pending.verifier
280
- });
281
- const { issuer } = await discover();
282
- if (!answersLogin(answer.idToken, { nonce: pending.nonce, issuer, client })) {
283
- throw new TetherError("Customer accounts: the login answer did not check out (nonce/issuer/audience)");
284
- }
285
- keep(answer, null);
286
- await linkCart();
287
- emit("account-login", {});
288
- const back = pending.returnTo ? new URL(pending.returnTo, window.location.href) : null;
289
- if (back?.origin === window.location.origin && back.href !== clean.href) navigate(back.href);
290
- return true;
291
- }
292
- function endSession() {
293
- session = null;
294
- customerProfile = null;
295
- writeJsonIfAllowed(sessionArea(), sessionKey(), null);
296
- Cart.setCustomer({ accessToken: null });
297
- }
298
- async function refresh(expired) {
299
- try {
300
- const answer = await requestToken({
301
- grant_type: "refresh_token",
302
- client_id: clientId(),
303
- refresh_token: expired.refresh ?? ""
304
- });
305
- keep(answer, expired);
306
- await linkCart();
307
- } catch (error) {
308
- if (error instanceof TetherError && error.code === "SESSION_ENDED") endSession();
309
- else throw error;
159
+ var toUserErrors = (value) => listOf(value, toUserError).filter((error) => error !== null);
160
+
161
+ // src/account/server-client.ts
162
+ var known = null;
163
+ function serverBase() {
164
+ const server = cfg.account?.server;
165
+ if (!server) {
166
+ throw new TetherError("Customer accounts need the Worker: set account.server", { code: "NOT_CONFIGURED" });
310
167
  }
168
+ return new URL(server, window.location.href).href.replace(/\/$/, "");
311
169
  }
312
- async function getToken() {
313
- session = currentSession();
314
- if (!session) return null;
315
- if (session.access && session.expiresAt > Date.now()) return session.access;
316
- if (!session.refresh) {
317
- endSession();
318
- return null;
319
- }
320
- const expired = session;
321
- refreshing ?? (refreshing = refresh(expired).finally(() => {
322
- refreshing = null;
323
- }));
324
- await refreshing;
325
- return accessToken();
170
+ function setLoginHint(loggedIn) {
171
+ if (loggedIn) setStored(hintKey(), "1");
172
+ else removeStored(hintKey());
326
173
  }
327
- async function linkCart() {
328
- const token = accessToken();
329
- Cart.setCustomer({ accessToken: token });
330
- if (!Cart.id() || !token) return;
174
+ async function fetchFromWorker(url, init) {
331
175
  try {
332
- await Cart.setBuyerIdentity({ customerAccessToken: token }, { create: false });
176
+ return await fetch(url, init);
333
177
  } catch (error) {
334
- reportError(error, "account cart");
178
+ throw new TetherError(`Network error: ${messageOf(error)}`, {
179
+ code: "NETWORK"
180
+ });
335
181
  }
336
182
  }
337
- async function unlinkCart() {
338
- if (!Cart.id()) return;
183
+ async function readJsonObjectOrEmpty(response) {
184
+ let json;
339
185
  try {
340
- await Cart.setBuyerIdentity({ customerAccessToken: null }, { create: false });
341
- } catch (error) {
342
- reportError(error, "account cart unlink");
343
- writeJsonIfAllowed("local", cfg.storageKey, null);
344
- }
345
- }
346
- async function browserLogout(returnTo) {
347
- const idToken = currentSession()?.idToken ?? null;
348
- await unlinkCart();
349
- endSession();
350
- emit("account-logout", {});
351
- if (!idToken) return "stayed";
352
- const url = new URL((await discover()).endSessionEndpoint);
353
- url.searchParams.set("id_token_hint", idToken);
354
- url.searchParams.set("post_logout_redirect_uri", returnTo);
355
- navigate(url.toString());
356
- return "redirected";
357
- }
358
- async function query(document2, variables = {}) {
359
- const token = await getToken();
360
- if (!token) throw new TetherError("Not logged in", { code: "NOT_LOGGED_IN" });
361
- const { graphql } = await discover();
362
- const send = (accessToken2) => fetch(graphql, {
363
- method: "POST",
364
- headers: { "Content-Type": "application/json", Authorization: accessToken2 },
365
- body: JSON.stringify({ query: document2, variables })
366
- });
367
- let response = await send(token);
368
- if (response.status === 401 && session?.refresh) {
369
- session.expiresAt = 0;
370
- response = await send(await getToken() ?? "");
371
- }
372
- const json = await readJsonObjectOrEmpty(response);
373
- const errors = Array.isArray(json["errors"]) ? json["errors"] : [];
374
- if (!response.ok || errors.length) {
375
- const messages = errors.map((error) => isRecord(error) ? textOrNull(error["message"]) : null).filter(Boolean);
376
- throw new TetherError(messages.join(" | ") || `Customer accounts: ${response.status}`, {
377
- status: response.status
378
- });
186
+ json = await response.json();
187
+ } catch {
188
+ return {};
379
189
  }
380
- return (
381
- /** @type {T} */
382
- json["data"]
383
- );
384
- }
385
- async function browserCustomer() {
386
- if (customerProfile) return customerProfile;
387
- const data = await query(CUSTOMER_QUERY);
388
- customerProfile = data.customer;
389
- return customerProfile;
390
- }
391
- function forgetBrowserCustomer() {
392
- customerProfile = null;
393
- }
394
-
395
- // src/account/server-client.js
396
- var known = null;
397
- function serverBase() {
398
- const server = cfg.account?.server;
399
- if (!server) return "";
400
- return new URL(server, window.location.href).href.replace(/\/$/, "");
190
+ return isRecord(json) ? json : {};
401
191
  }
402
192
  async function serverFetch(path, { method = "GET", body } = {}) {
403
193
  const init = { method, credentials: "include" };
404
194
  if (method === "POST") init.headers = { "Content-Type": "application/json", "X-Tether-Account": "1" };
405
195
  if (body) init.body = JSON.stringify(body);
406
- const response = await fetch(`${serverBase()}${path}`, init);
196
+ const response = await fetchFromWorker(`${serverBase()}${path}`, init);
407
197
  if (response.status === 401) return { kind: "logged-out" };
408
198
  const data = await readJsonObjectOrEmpty(response);
409
199
  if (!response.ok) {
410
200
  const reason = textOrNull(data["error"]) ?? String(response.status);
411
- const userErrors = Array.isArray(data["userErrors"]) ? (
412
- // The Worker sends Shopify's own `userErrors` list unchanged.
413
- /** @type {UserError[]} */
414
- data["userErrors"]
415
- ) : void 0;
201
+ const userErrors = toUserErrors(data["userErrors"]);
416
202
  throw new TetherError(`Customer accounts: ${reason}`, {
417
203
  status: response.status,
418
- ...userErrors && { userErrors }
204
+ ...userErrors.length > 0 && { userErrors },
205
+ // The Worker marks refused input (a 400, or a 404 for a contract that isn't the customer's) with `code`.
206
+ ...data["code"] === "INVALID" && { code: "INVALID" }
419
207
  });
420
208
  }
421
209
  return { kind: "answer", data };
422
210
  }
423
- function toServerCustomer(value) {
424
- const customer2 = isRecord(value) ? value : {};
425
- const address = customer2["address"];
426
- return {
427
- firstName: textOrNull(customer2["firstName"]),
428
- lastName: textOrNull(customer2["lastName"]),
429
- displayName: textOrNull(customer2["displayName"]),
430
- email: textOrNull(customer2["email"]),
431
- address: Array.isArray(address) ? address.filter((line) => typeof line === "string") : null
432
- };
433
- }
434
211
  async function serverLogin() {
435
212
  if (!known) {
436
213
  const answer = await serverFetch("/me");
437
- known = answer.kind === "answer" && answer.data["loggedIn"] === true ? { loggedIn: true, customer: toServerCustomer(answer.data["customer"]) } : { loggedIn: false };
214
+ known = answer.kind === "answer" && answer.data["loggedIn"] === true ? { loggedIn: true, customer: toAccountCustomer(answer.data["customer"]) } : { loggedIn: false };
438
215
  }
439
216
  setLoginHint(known.loggedIn);
440
217
  return known;
@@ -443,13 +220,18 @@
443
220
  function forgetServerLogin() {
444
221
  known = null;
445
222
  }
223
+ function navigate(url) {
224
+ const replacement = cfg.account?.navigate;
225
+ if (replacement) replacement(url);
226
+ else window.location.assign(url);
227
+ }
228
+ var loginLanguage = (locale) => locale || cfg.account?.locale || (cfg.locale || "").split("-")[0] || "";
446
229
  function serverLoginRedirect({ returnTo, locale }) {
447
230
  const url = new URL(`${serverBase()}/login`);
448
231
  url.searchParams.set("returnTo", returnTo);
449
232
  const language = loginLanguage(locale);
450
233
  if (language) url.searchParams.set("locale", language);
451
- const country = loginCountry();
452
- if (country) url.searchParams.set("country", country);
234
+ if (cfg.country) url.searchParams.set("country", cfg.country.toUpperCase());
453
235
  navigate(url.toString());
454
236
  }
455
237
  async function serverCheckoutUrl() {
@@ -457,9 +239,7 @@
457
239
  if (!(await serverLogin()).loggedIn || !cartId) return null;
458
240
  const answer = await serverFetch("/cart", { method: "POST", body: { cartId } });
459
241
  if (answer.kind === "logged-out") return null;
460
- const url = textOrNull(answer.data["checkoutUrl"]);
461
- if (!url) return null;
462
- return `${url}${url.includes("?") ? "&" : "?"}logged_in=true`;
242
+ return textOrNull(answer.data["checkoutUrl"]);
463
243
  }
464
244
  async function serverLogout(returnTo) {
465
245
  const answer = await serverFetch("/logout", { method: "POST", body: { returnTo, cartId: Cart.id() } });
@@ -472,29 +252,11 @@
472
252
  return "redirected";
473
253
  }
474
254
 
475
- // tether-core:shopify-values.js
476
- var m6 = window.Tether.__core["shopify-values.js"];
477
- var { STORE_ENV_NAMES, formatMoney: formatMoney2, isHttpsUrl, isSecretShopifyToken, productKey, productUrl: productUrl2 } = m6;
255
+ // tether-core:shopify-values.ts
256
+ var m6 = window.Tether.__core["shopify-values.ts"];
257
+ var [isHttpsUrl] = m6;
478
258
 
479
- // src/account-links.js
480
- function localDate(iso) {
481
- try {
482
- return new Date(iso).toLocaleDateString(cfg.locale);
483
- } catch (error) {
484
- if (error instanceof RangeError) return iso;
485
- throw error;
486
- }
487
- }
488
- function orderUrl(order2) {
489
- const template = cfg.account?.orderUrl;
490
- if (template) {
491
- const numericId = order2.id.split("/").pop()?.split("?")[0] ?? "";
492
- return template.replace("{id}", encodeURIComponent(numericId));
493
- }
494
- return isHttpsUrl(order2.statusPageUrl) ? order2.statusPageUrl ?? null : null;
495
- }
496
-
497
- // src/account/markup.js
259
+ // src/account/markup.ts
498
260
  function showIn(root, name, conditions) {
499
261
  qsa(root, sel(name)).forEach((el) => {
500
262
  const key = get(el, name) ?? "";
@@ -504,9 +266,9 @@
504
266
  var bindsIn = (row, name) => qsa(row, sel(name)).concat(row.matches(sel(name)) ? [row] : []);
505
267
  var ownValue = (values, key) => Object.hasOwn(values, key) ? values[key] : void 0;
506
268
 
507
- // src/account/order-lines.js
269
+ // src/account/order-lines.ts
508
270
  var lineTexts = (line, returnable) => ({
509
- title: line.title || line.name,
271
+ title: line.title || line.name || "",
510
272
  "variant-title": line.variantTitle || "",
511
273
  quantity: String(line.quantity),
512
274
  price: formatMoney(line.price),
@@ -528,7 +290,7 @@
528
290
  if (select.dataset["tetherFilled"] === line.id) return;
529
291
  select.dataset["tetherFilled"] = line.id;
530
292
  (line.suggestedReturnReasonDefinitions?.nodes ?? []).forEach((reason) => {
531
- select.appendChild(new Option(reason.name, reason.id));
293
+ select.appendChild(new Option(reason.name ?? "", reason.id));
532
294
  });
533
295
  });
534
296
  }
@@ -541,7 +303,7 @@
541
303
  bindsIn(row, "order-line").forEach((el) => {
542
304
  const key = get(el, "order-line") ?? "";
543
305
  if (key === "image") {
544
- if (line.image) setImage(el, line.image.url, line.image.altText || line.title);
306
+ if (line.image) setImage(el, line.image.url, line.image.altText || line.title || "");
545
307
  return;
546
308
  }
547
309
  const text = ownValue(texts, key);
@@ -551,15 +313,28 @@
551
313
  });
552
314
  }
553
315
 
554
- // src/account/order-list.js
316
+ // src/account/order-list.ts
555
317
  var DEFAULT_ORDER_COUNT = 10;
318
+ var MAX_ORDER_COUNT = 50;
319
+ var isOrderCount = (value) => typeof value === "number" && Number.isInteger(value) && value >= 1 && value <= MAX_ORDER_COUNT;
320
+ function listLimit(limit) {
321
+ const asked = Number.parseInt(limit || String(DEFAULT_ORDER_COUNT), 10) || DEFAULT_ORDER_COUNT;
322
+ return Math.min(Math.max(asked, 1), MAX_ORDER_COUNT);
323
+ }
324
+ var numericId = (gid) => gid.replace(/\?.*$/, "").replace(/^.*\//, "");
325
+ function orderUrl(order2) {
326
+ const template = cfg.account?.orderUrl;
327
+ if (template) return template.replaceAll("{id}", encodeURIComponent(numericId(order2.id)));
328
+ const statusPage = order2.statusPageUrl;
329
+ return statusPage !== null && isHttpsUrl(statusPage) ? statusPage : null;
330
+ }
556
331
  var orderTexts = (order2) => ({
557
- name: order2.name,
558
- date: localDate(order2.processedAt),
332
+ name: order2.name ?? "",
333
+ date: formatDate(order2.processedAt),
559
334
  total: formatMoney(order2.totalPrice),
560
335
  status: order2.financialStatus?.toLowerCase(),
561
336
  fulfillment: order2.fulfillmentStatus?.toLowerCase(),
562
- items: order2.lineItems.nodes.map((line) => `${line.quantity}\xD7 ${line.title}`).join(", ")
337
+ items: order2.lineItems.nodes.map((line) => `${String(line.quantity)}\xD7 ${line.title ?? ""}`).join(", ")
563
338
  });
564
339
  function fillOrder(node, order2) {
565
340
  const lines = order2.lineItems.nodes;
@@ -589,80 +364,70 @@
589
364
  const first = lists[0];
590
365
  if (!first) return;
591
366
  showIn(root, "show", { "orders-loading": true, "orders-empty": false });
592
- const limit = Number.parseInt(get(first, "limit") || String(DEFAULT_ORDER_COUNT), 10) || DEFAULT_ORDER_COUNT;
593
- const orders2 = await loadOrders(limit).catch((error) => {
367
+ const limit = listLimit(get(first, "limit"));
368
+ let orders2;
369
+ try {
370
+ orders2 = await loadOrders(limit);
371
+ } catch (error) {
594
372
  reportError(error, "orders");
595
- return null;
596
- });
373
+ orders2 = null;
374
+ }
597
375
  showIn(root, "show", { "orders-loading": false, "orders-empty": orders2?.length === 0 });
598
376
  lists.forEach((list) => {
599
377
  repeat(list, orders2 ?? [], fillOrder);
600
378
  });
601
379
  }
602
380
 
603
- // src/account.js
381
+ // src/account.ts
604
382
  var PAGE_ATTRIBUTES = ["order", "addresses", "subscriptions", "profile-form", "address-form"];
605
- function isLoggedIn() {
606
- return serverBase() ? isServerLoggedIn() : hasBrowserLogin();
607
- }
608
- async function login({ returnTo = window.location.href, locale } = {}) {
609
- if (serverBase()) serverLoginRedirect({ returnTo, locale });
610
- else await browserLoginRedirect({ returnTo, locale });
611
- }
612
- async function query2(document2, variables = {}) {
613
- if (serverBase()) {
614
- throw new TetherError("Customer accounts in server mode only answer customer() and orders()", {
615
- code: "NOT_ALLOWED"
616
- });
617
- }
618
- return query(document2, variables);
383
+ var isLoggedIn = isServerLoggedIn;
384
+ function login({
385
+ returnTo = window.location.href,
386
+ locale
387
+ } = {}) {
388
+ return new Promise((resolve) => {
389
+ serverLoginRedirect({ returnTo, locale });
390
+ resolve();
391
+ });
619
392
  }
620
393
  async function customer() {
621
- if (!serverBase()) return browserCustomer();
622
394
  const me = await serverLogin();
623
- if (!me.loggedIn) return null;
624
- return {
625
- ...me.customer,
626
- emailAddress: { emailAddress: me.customer.email },
627
- defaultAddress: { formatted: me.customer.address }
628
- };
395
+ return me.loggedIn ? me.customer : null;
629
396
  }
630
- async function orders({ first = 10 } = {}) {
631
- if (serverBase()) {
632
- const answer = await serverFetch(`/orders?first=${first}`);
633
- if (answer.kind === "logged-out") return [];
634
- const list = answer.data["orders"];
635
- return Array.isArray(list) ? (
636
- /** @type {AccountOrder[]} */
637
- list
638
- ) : [];
397
+ async function orders({ first = DEFAULT_ORDER_COUNT } = {}) {
398
+ if (!isOrderCount(first)) {
399
+ throw new TetherError(`Customer accounts: orders() takes first from 1 to ${String(MAX_ORDER_COUNT)}`, {
400
+ code: "INVALID"
401
+ });
639
402
  }
640
- const data = await query(ORDERS_QUERY, { first });
641
- return data.customer?.orders.nodes ?? [];
403
+ const answer = await serverFetch(`/orders?${new URLSearchParams({ first: String(first) }).toString()}`);
404
+ return answer.kind === "logged-out" ? [] : toAccountOrders(answer.data["orders"]);
642
405
  }
643
- async function logout({ returnTo = cfg.account?.logoutUrl || `${window.location.origin}/` } = {}) {
644
- const outcome = serverBase() ? await serverLogout(returnTo) : await browserLogout(returnTo);
645
- if (outcome === "stayed") await render(document);
406
+ async function logout({
407
+ returnTo = cfg.account?.logoutUrl || `${window.location.origin}/`
408
+ } = {}) {
409
+ if (await serverLogout(returnTo) === "stayed") await render(document);
646
410
  }
647
411
  async function loginState() {
648
412
  try {
649
- if (serverBase()) return (await serverLogin()).loggedIn ? { kind: "logged-in" } : { kind: "logged-out" };
650
- if (hasBrowserLogin() || await getToken()) return { kind: "logged-in" };
651
- return { kind: "logged-out" };
413
+ return (await serverLogin()).loggedIn ? { kind: "logged-in" } : { kind: "logged-out" };
652
414
  } catch (error) {
653
415
  return { kind: "unknown", error };
654
416
  }
655
417
  }
656
418
  var usesPages = (root) => PAGE_ATTRIBUTES.some((name) => qsa(root, sel(name)).length > 0);
657
419
  function linkShopifyPages(root) {
658
- const account = cfg.account;
659
420
  qsa(root, sel("account-link")).forEach((link) => {
660
- const page = get(link, "account-link");
661
- const subscriptions2 = account?.subscriptionsUrl;
662
- const url = page === "payment" && (account?.paymentUrl || subscriptions2) || page === "subscriptions" && subscriptions2;
663
- link.setAttribute("href", url || `https://${cfg.domain}/account`);
421
+ link.setAttribute("href", shopifyPageUrl(get(link, "account-link")));
664
422
  });
665
423
  }
424
+ function shopifyPageUrl(page) {
425
+ const account = cfg.account;
426
+ const fallback = `https://${cfg.domain}/account`;
427
+ if (page === "payment") return account?.paymentUrl || account?.subscriptionsUrl || fallback;
428
+ if (page === "subscriptions") return account?.subscriptionsUrl || fallback;
429
+ return fallback;
430
+ }
666
431
  async function render(root = document) {
667
432
  const state = await loginState();
668
433
  if (state.kind === "unknown") reportError(state.error, "account");
@@ -687,16 +452,20 @@
687
452
  async function bindCustomer(root) {
688
453
  const binds = qsa(root, sel("account-bind"));
689
454
  if (!binds.length) return;
690
- const profile = await customer().catch((error) => {
455
+ let profile;
456
+ try {
457
+ profile = await customer();
458
+ } catch (error) {
691
459
  reportError(error, "account");
692
- return null;
693
- });
460
+ return;
461
+ }
462
+ if (!profile) return;
694
463
  const texts = {
695
- "first-name": profile?.firstName,
696
- "last-name": profile?.lastName,
697
- name: profile?.displayName,
698
- email: profile?.emailAddress?.emailAddress,
699
- address: profile?.defaultAddress?.formatted?.join(", ")
464
+ "first-name": profile.firstName,
465
+ "last-name": profile.lastName,
466
+ name: profile.displayName,
467
+ email: profile.emailAddress?.emailAddress,
468
+ address: profile.defaultAddress?.formatted.join(", ")
700
469
  };
701
470
  binds.forEach((el) => {
702
471
  const text = ownValue(texts, get(el, "account-bind") ?? "");
@@ -706,17 +475,7 @@
706
475
  var pagesPart = null;
707
476
  function pages() {
708
477
  pagesPart ?? (pagesPart = loadPart("account-pages").then((part) => {
709
- part.setup({
710
- serverBase,
711
- serverFetch,
712
- query: query2,
713
- customer,
714
- bindCustomer,
715
- reset: () => {
716
- forgetBrowserCustomer();
717
- forgetServerLogin();
718
- }
719
- });
478
+ part.setup({ serverFetch, customer, bindCustomer, reset: forgetServerLogin });
720
479
  return part;
721
480
  }));
722
481
  return pagesPart;
@@ -744,46 +503,38 @@
744
503
  });
745
504
  }
746
505
  }
747
- function startServerMode() {
506
+ function finishServerLogin() {
748
507
  const url = new URL(window.location.href);
749
- if (url.searchParams.get("account")) {
750
- url.searchParams.delete("account");
751
- window.history.replaceState(window.history.state, "", url);
752
- emit("account-login", {});
753
- }
754
- Cart.setCustomer({ beforeCheckout: serverCheckoutUrl });
755
- }
756
- async function startBrowserMode() {
757
- try {
758
- await handleCallback();
759
- } catch (error) {
760
- reportError(error, "login");
761
- }
762
- if (Cart.customerAccessToken) return;
763
- try {
764
- const accessToken2 = await getToken();
765
- if (accessToken2) Cart.setCustomer({ accessToken: accessToken2 });
766
- } catch (error) {
767
- reportError(error, "account");
508
+ const outcome = url.searchParams.get("account");
509
+ if (!isLoginOutcome(outcome)) return;
510
+ url.searchParams.delete("account");
511
+ window.history.replaceState(window.history.state, "", url);
512
+ switch (outcome) {
513
+ case "in":
514
+ emit("account-login", {});
515
+ break;
516
+ case "expired":
517
+ case "error":
518
+ emit("account-error", { error: outcome });
519
+ break;
768
520
  }
769
521
  }
770
522
  var started = false;
771
523
  async function mountAccount(root = document) {
772
- if (!started) {
773
- started = true;
774
- document.addEventListener("click", onClick);
775
- if (serverBase()) startServerMode();
776
- else await startBrowserMode();
777
- log("account", isLoggedIn() ? "logged in" : "logged out");
524
+ if (started) {
525
+ await render(root);
526
+ return;
778
527
  }
528
+ started = true;
529
+ document.addEventListener("click", onClick);
530
+ finishServerLogin();
531
+ Cart.setCheckoutResolver(serverCheckoutUrl);
779
532
  await render(root);
533
+ log("account", isLoggedIn() ? "logged in" : "logged out");
780
534
  }
781
535
 
782
- // src/parts/account.js
783
- var { Tether } = (
784
- /** @type {Window & { Tether?: { __parts: Record<string, unknown> } }} */
785
- window
786
- );
536
+ // src/parts/account.ts
537
+ var { Tether } = window;
787
538
  if (!Tether) throw new Error("tether.account.js runs after the Tether script, which loads it");
788
- Tether.__parts["account"] = account_exports;
539
+ Tether.__parts.account = account_exports;
789
540
  })();