@occluze/tether 0.6.0 → 0.6.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 +1 -1
- package/dist/esm/chunks/account-JBZJN7X7.js +1 -0
- package/dist/esm/index.js +1 -1
- package/dist/tether.account.js +9 -3
- package/dist/tether.account.min.js +1 -1
- package/dist/tether.js +1 -1
- package/dist/tether.min.js +1 -1
- package/dist/tether.min.js.map +1 -1
- package/package.json +2 -2
- package/src/account.js +4 -4
- package/src/index.js +1 -1
- package/dist/esm/chunks/account-WAWNASZU.js +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@occluze/tether",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Free, open-source alternative to Smootify and Storesynk (Shopyflow): Shopify products, cart and subscriptions in Webflow with HTML attributes. Optional Shopify to Webflow CMS sync.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/esm/index.js",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"presmoke": "node scripts/build.mjs",
|
|
44
44
|
"test:types": "tsc -p types/tsconfig.json",
|
|
45
45
|
"release": "node scripts/release.mjs",
|
|
46
|
-
"e2e:build": "npm run build && cd examples/astro && (test -f .env || cp .env.example .env) && npm install --no-audit --no-fund
|
|
46
|
+
"e2e:build": "npm run build && cd examples/astro && (test -f .env || cp .env.example .env) && npm install --no-audit --no-fund && npm install --no-save ../.. && npx astro build",
|
|
47
47
|
"e2e": "npm run e2e:build && playwright test -c e2e/playwright.config.js"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
package/src/account.js
CHANGED
|
@@ -81,8 +81,7 @@ export function isLoggedIn() { return server() ? Boolean(serverState?.loggedIn)
|
|
|
81
81
|
export async function login({ returnTo = window.location.href, locale } = {}) {
|
|
82
82
|
if (server()) {
|
|
83
83
|
const u = new URL(`${server()}/login`);
|
|
84
|
-
u.searchParams.set('returnTo', returnTo);
|
|
85
|
-
if (Cart.id()) u.searchParams.set('cart', Cart.id());
|
|
84
|
+
u.searchParams.set('returnTo', returnTo); // the cart is linked later, through the Worker's protected POST /cart
|
|
86
85
|
const lang = locale || cfg.account.locale || (cfg.locale || '').split('-')[0];
|
|
87
86
|
if (lang) u.searchParams.set('locale', lang);
|
|
88
87
|
if (cfg.country) u.searchParams.set('country', String(cfg.country).toUpperCase());
|
|
@@ -251,6 +250,7 @@ export async function logout({ returnTo = cfg.account?.logoutUrl || `${window.lo
|
|
|
251
250
|
|
|
252
251
|
// ---------------------------------------------------------------- markup
|
|
253
252
|
|
|
253
|
+
const https = (u) => { try { return new URL(u).protocol === 'https:'; } catch { return false; } }; // links from Shopify: https only
|
|
254
254
|
const date = (s) => { try { return new Date(s).toLocaleDateString(cfg.locale || undefined); } catch { return s; } };
|
|
255
255
|
|
|
256
256
|
export async function render(root = document) {
|
|
@@ -275,11 +275,11 @@ export async function render(root = document) {
|
|
|
275
275
|
lists.forEach((c) => repeat(c, list, (node, o) => {
|
|
276
276
|
qsa(node, sel('order-bind')).forEach((el) => {
|
|
277
277
|
const k = get(el, 'order-bind');
|
|
278
|
-
if (k === 'url') { el.setAttribute('href', o.statusPageUrl); return; }
|
|
278
|
+
if (k === 'url') { if (https(o.statusPageUrl)) el.setAttribute('href', o.statusPageUrl); return; }
|
|
279
279
|
const v = { name: o.name, date: date(o.processedAt), total: formatMoney(o.totalPrice), status: o.financialStatus?.toLowerCase(), fulfillment: o.fulfillmentStatus?.toLowerCase(), items: o.lineItems.nodes.map((l) => `${l.quantity}× ${l.title}`).join(', ') }[k];
|
|
280
280
|
if (v != null) setText(el, v);
|
|
281
281
|
});
|
|
282
|
-
if (get(node, 'order-bind') === 'url') node.setAttribute('href', o.statusPageUrl);
|
|
282
|
+
if (get(node, 'order-bind') === 'url' && https(o.statusPageUrl)) node.setAttribute('href', o.statusPageUrl);
|
|
283
283
|
}));
|
|
284
284
|
}
|
|
285
285
|
}
|
package/src/index.js
CHANGED
|
@@ -21,7 +21,7 @@ import { attr, sel, get, qsa, emit, formatMoney, busy, parseJSONAttr, toAttribut
|
|
|
21
21
|
import { loadPart, coreModules } from './lazy.js';
|
|
22
22
|
import { mountedLists, liveLists, pruneLive, within, mountProduct, retryFailed, hydrateFromPage, settleMarket, trackMarket } from './mounting.js';
|
|
23
23
|
|
|
24
|
-
export const VERSION = '0.6.
|
|
24
|
+
export const VERSION = '0.6.1';
|
|
25
25
|
|
|
26
26
|
let initPromise = null;
|
|
27
27
|
let observer = null;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{b as u}from"./chunk-BGIKQY6H.js";import"./chunk-ZVUPVSLF.js";import"./chunk-YXCXIPQV.js";import{B as x,D as O,G as F,b as a,e as G,g,h as w,o as p,p as y,s as _,u as S,w as z}from"./chunk-KARKXC6G.js";import"./chunk-VC46IEJQ.js";var b=()=>`${a.prefix}:account:${a.domain}`,L=()=>`${a.prefix}:account-login:${a.domain}`,C=()=>a.account?.remember?window.localStorage:window.sessionStorage,M=t=>btoa(String.fromCharCode(...new Uint8Array(t))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,""),v=()=>M(crypto.getRandomValues(new Uint8Array(32))),Q=async t=>M(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(t))),A=t=>(a.account?.navigate||(e=>window.location.assign(e)))(t),B=(t,e)=>{try{return JSON.parse(t.getItem(e)||"null")}catch{return null}},P=(t,e,n)=>{try{n?t.setItem(e,JSON.stringify(n)):t.removeItem(e)}catch{}},E=null,s=null,D=null,I=null,d=()=>a.account?.server?String(a.account.server).replace(/\/$/,""):"",q=()=>`${a.prefix}:account-hint:${a.domain}`,T=null;async function U(t,{method:e="GET",body:n}={}){let r=await fetch(`${d()}${t}`,{method:e,credentials:"include",headers:e==="POST"?{"Content-Type":"application/json","X-Tether-Account":"1"}:{},body:n?JSON.stringify(n):void 0}),c=await r.json().catch(()=>({}));if(!r.ok&&r.status!==401)throw new w(`Customer accounts: ${c.error||r.status}`,{status:r.status});return c}async function J(){T||(T=await U("/me"));try{T.loggedIn?window.localStorage.setItem(q(),"1"):window.localStorage.removeItem(q())}catch{}return T}async function $(){if(E)return E;let t=a.account?.shopDomain||a.domain,e=c=>fetch(`https://${t}/.well-known/${c}`).then(o=>{if(!o.ok)throw new w(`Customer accounts: ${c} answered ${o.status}`,{status:o.status});return o.json()}),[n,r]=await Promise.all([e("openid-configuration"),e("customer-account-api")]);return E={...n,graphql:r.graphql_api},E}var Z=()=>a.account?.callbackUrl||`${window.location.origin}${window.location.pathname}`;function H(){return d()?!!T?.loggedIn:!!(s?.refresh||s?.access&&s.expiresAt>Date.now())}async function tt({returnTo:t=window.location.href,locale:e}={}){if(d()){let f=new URL(`${d()}/login`);f.searchParams.set("returnTo",t),u.id()&&f.searchParams.set("cart",u.id());let m=e||a.account.locale||(a.locale||"").split("-")[0];m&&f.searchParams.set("locale",m),a.country&&f.searchParams.set("country",String(a.country).toUpperCase()),A(f.toString());return}if(!a.account?.clientId)throw new w("Customer accounts: set account.clientId",{code:"NOT_CONFIGURED"});let n=await $(),r=v(),c=v(),o=v(),l=Z();P(window.sessionStorage,L(),{state:r,nonce:c,verifier:o,redirect:l,returnTo:t,at:Date.now()});let i=new URL(n.authorization_endpoint),h={client_id:a.account.clientId,scope:"openid email customer-account-api:full",response_type:"code",redirect_uri:l,state:r,nonce:c,code_challenge:await Q(o),code_challenge_method:"S256"},k=e||a.account.locale||(a.locale||"").split("-")[0];k&&(h.locale=k),a.country&&(h.region_country=String(a.country).toUpperCase()),Object.entries(h).forEach(([f,m])=>i.searchParams.set(f,m)),A(i.toString())}async function V(t){let e=await $(),n=await fetch(a.account.tokenUrl||e.token_endpoint,{method:"POST",body:new URLSearchParams(t)}),r=await n.json().catch(()=>({}));if(!n.ok||!r.access_token)throw new w(`Customer accounts: token ${n.status} ${r.error||""}`.trim(),{status:n.status,code:n.status===400||n.status===401?"SESSION_ENDED":"TOKEN_FAILED"});return r}function et(t){try{return JSON.parse(atob(t.split(".")[1].replace(/-/g,"+").replace(/_/g,"/")))}catch{return null}}function W(t,e=s){s={access:t.access_token,expiresAt:Date.now()+Math.max(0,(Number(t.expires_in)||3600)-120)*1e3,refresh:t.refresh_token||e?.refresh,idToken:t.id_token||e?.idToken},P(C(),b(),s)}async function nt(){let t=new URLSearchParams(window.location.search),e=B(window.sessionStorage,L());if(!e||!t.has("code")&&!t.has("error")||t.get("state")!==e.state)return!1;P(window.sessionStorage,L(),null);let n=new URL(window.location.href);if(["code","state","iss","error","error_description"].forEach(h=>n.searchParams.delete(h)),window.history.replaceState(window.history.state,"",n),t.has("error"))return S("account-error",{error:t.get("error")}),!1;if(Date.now()-e.at>10*6e4)throw new w("Customer accounts: the login took too long, please try again");let r=await V({grant_type:"authorization_code",client_id:a.account.clientId,redirect_uri:e.redirect,code:t.get("code"),code_verifier:e.verifier}),c=await $(),o=et(r.id_token||""),l=[].concat(o?.aud||[]);if(!o||o.nonce!==e.nonce||o.iss!==c.issuer||!l.includes(a.account.clientId)||o.exp*1e3<Date.now())throw new w("Customer accounts: the login answer did not check out (nonce/issuer/audience)");W(r,null),await X(),S("account-login",{});let i=e.returnTo&&new URL(e.returnTo,window.location.href);return i&&i.origin===window.location.origin&&i.href!==n.href&&A(i.href),!0}async function N(){return d()||(s||(s=B(C(),b())),!s)?null:s.access&&s.expiresAt>Date.now()?s.access:s.refresh?(D||(D=(async()=>{try{W(await V({grant_type:"refresh_token",client_id:a.account.clientId,refresh_token:s.refresh})),await X()}catch(t){if(t.code==="SESSION_ENDED")R();else throw t}finally{D=null}})()),await D,s?.access||null):(R(),null)}function R(){s=null,I=null,P(C(),b(),null),u.customerAccessToken=null}async function X(){u.customerAccessToken=s?.access||null,u.id()&&s?.access&&await u.setBuyerIdentity({customerAccessToken:s.access},{create:!1}).catch(t=>g(t,"account cart"))}async function Y(t,e={}){if(d())throw new w("Customer accounts in server mode only answer customer() and orders()",{code:"NOT_ALLOWED"});let n=await N();if(!n)throw new w("Not logged in",{code:"NOT_LOGGED_IN"});let r=await $(),c=i=>fetch(r.graphql,{method:"POST",headers:{"Content-Type":"application/json",Authorization:i},body:JSON.stringify({query:t,variables:e})}),o=await c(n);o.status===401&&s?.refresh&&(s.expiresAt=0,o=await c(await N()));let l=await o.json().catch(()=>({}));if(!o.ok||l.errors?.length)throw new w(l.errors?.map(i=>i.message).join(" | ")||`Customer accounts: ${o.status}`,{status:o.status});return l.data}async function ot(){if(d()){let e=await J();return e.loggedIn?{...e.customer,emailAddress:{emailAddress:e.customer.email},defaultAddress:{formatted:e.customer.address}}:null}return I||(I=(await Y("query TetherCustomer{customer{id firstName lastName displayName emailAddress{emailAddress}defaultAddress{formatted}}}")).customer,I)}async function rt({first:t=10}={}){return d()?(await U(`/orders?first=${t}`)).orders||[]:(await Y("query TetherOrders($first:Int!){customer{orders(first:$first,sortKey:PROCESSED_AT,reverse:true){nodes{id name processedAt financialStatus fulfillmentStatus statusPageUrl totalPrice{amount currencyCode}lineItems(first:20){nodes{title variantTitle quantity image{url altText}}}}}}}",{first:t})).customer?.orders?.nodes||[]}async function at({returnTo:t=a.account?.logoutUrl||`${window.location.origin}/`}={}){if(d()){let c=await U("/logout",{method:"POST",body:{returnTo:t,cartId:u.id()}});T={loggedIn:!1};try{window.localStorage.removeItem(q())}catch{}S("account-logout",{}),c.logoutUrl?A(c.logoutUrl):j(document);return}let e=s?.idToken||B(C(),b())?.idToken;if(u.id()&&await u.setBuyerIdentity({customerAccessToken:null},{create:!1}).catch(()=>{}),R(),S("account-logout",{}),!e){j(document);return}let n=await $(),r=new URL(n.end_session_endpoint);r.searchParams.set("id_token_hint",e),r.searchParams.set("post_logout_redirect_uri",t),A(r.toString())}var ct=t=>{try{return new Date(t).toLocaleDateString(a.locale||void 0)}catch{return t}};async function j(t=document){let e=d()?!!(await J().catch(()=>({loggedIn:!1}))).loggedIn:H()||!!await N().catch(()=>null);if(_(t,p("show")).forEach(c=>{let o=y(c,"show");o==="logged-in"&&O(c,e),o==="logged-out"&&O(c,!e)}),!e)return;let n=_(t,p("account-bind"));if(n.length){let c=await ot().catch(o=>(g(o,"account"),null));n.forEach(o=>{let l={"first-name":c?.firstName,"last-name":c?.lastName,name:c?.displayName,email:c?.emailAddress?.emailAddress,address:c?.defaultAddress?.formatted?.join(", ")}[y(o,"account-bind")];l!=null&&x(o,l)})}let r=_(t,p("orders"));if(r.length){let c=await rt({first:parseInt(y(r[0],"limit")||"10",10)}).catch(o=>(g(o,"orders"),[]));r.forEach(o=>F(o,c,(l,i)=>{_(l,p("order-bind")).forEach(h=>{let k=y(h,"order-bind");if(k==="url"){h.setAttribute("href",i.statusPageUrl);return}let f={name:i.name,date:ct(i.processedAt),total:z(i.totalPrice),status:i.financialStatus?.toLowerCase(),fulfillment:i.fulfillmentStatus?.toLowerCase(),items:i.lineItems.nodes.map(m=>`${m.quantity}\xD7 ${m.title}`).join(", ")}[k];f!=null&&x(h,f)}),y(l,"order-bind")==="url"&&l.setAttribute("href",i.statusPageUrl)}))}}var K=!1;async function dt(t=document){if(!K){if(K=!0,document.addEventListener("click",e=>{let n=e.target;n.closest?.(p("account-login"))?(e.preventDefault(),tt().catch(r=>g(r,"login"))):n.closest?.(p("account-logout"))&&(e.preventDefault(),at().catch(r=>g(r,"logout")))}),d()){let e=new URL(window.location.href);e.searchParams.get("account")&&(e.searchParams.delete("account"),window.history.replaceState(window.history.state,"",e),S("account-login",{})),u.beforeCheckout=async()=>{if(!(await J()).loggedIn||!u.id())return null;let n=await U("/cart",{method:"POST",body:{cartId:u.id()}}).catch(()=>null);return n?.checkoutUrl?`${n.checkoutUrl}${n.checkoutUrl.includes("?")?"&":"?"}logged_in=true`:null}}else{try{await nt()}catch(e){g(e,"login")}!u.customerAccessToken&&await N().catch(()=>null)&&(u.customerAccessToken=s.access)}G("account",H()?"logged in":"logged out")}await j(t)}export{ot as customer,N as getToken,nt as handleCallback,H as isLoggedIn,tt as login,at as logout,dt as mountAccount,rt as orders,Y as query,j as render};
|