@uninspired/auth-client 1.0.5 → 1.0.7
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/AuthClient.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{emailOTPClient as e,magicLinkClient as t}from"better-auth/client/plugins";import{passkeyClient as n}from"@better-auth/passkey/client";import{createAuthClient as r}from"better-auth/client";import{hc as i}from"hono/client";var a=class{#e;#t;#n;#r;constructor(a,o,s,c){this.#e=o,this.#t=r({baseURL:a,plugins:[t(),e(),n()],headers:{cookie:s}}),this.#n=i(new URL(`/api/app`,a).toString(),{fetch:(e,t)=>fetch(e,{...t,credentials:`include`})}),this.#r=i(new URL(`/api/mailing-list`,a).toString(),{fetch:(e,t)=>fetch(e,{...t,headers:{
|
|
1
|
+
import{emailOTPClient as e,magicLinkClient as t}from"better-auth/client/plugins";import{passkeyClient as n}from"@better-auth/passkey/client";import{createAuthClient as r}from"better-auth/client";import{hc as i}from"hono/client";var a=class{#e;#t;#n;#r;constructor(a,o,s,c){this.#e=o,this.#t=r({baseURL:a,plugins:[t(),e(),n()],headers:{cookie:s}}),this.#n=i(new URL(`/api/app`,a).toString(),{fetch:(e,t)=>fetch(e,{...t,credentials:`include`})}),this.#r=i(new URL(`/api/mailing-list`,a).toString(),{fetch:(e,t)=>fetch(e,{...t,headers:{"Content-Type":`application/json`,"X-Public-Key":c,...t.headers}})})}getSession=async()=>{let{data:e,error:t}=await this.#t.getSession();if(t)throw t;return e};signOut=async e=>{let{error:t}=await this.#t.signOut({fetchOptions:{onSuccess:e}});if(t)throw t};getPurchases=async()=>{let e=await this.#n.purchases.$get();if(!e.ok)throw Error(`Failed to get purchases`,{cause:await e.text()});return await e.json()};#i=(e,t)=>JSON.stringify({type:`redirect`,redirectUrl:e,appName:t});newsletterSubscribe=async(e,t,n)=>{let r=await this.#r.subscribe.$post({json:{email:e,userGroup:t??`us-auth`,callbackUrl:n??``}});if(!r.ok)throw Error(await r.text())};newsletterUnsubscribe=async e=>{let t=await this.#r.unsubscribe.$post({query:{email:e}});if(!t.ok)throw Error(await t.text())};getLoginUrl=e=>{let t=new URL(`/login`,this.#e);return e?.redirectUrl&&t.searchParams.set(`intent`,this.#i(e.redirectUrl,e.appName)),t.toString()};getCheckoutUrl=e=>{let t=new URL(`/auth/checkout`,this.#e);return t.searchParams.set(`priceId`,e.priceId),e.discountCode&&t.searchParams.set(`discountCode`,e.discountCode),e.successUrl&&t.searchParams.set(`successUrl`,e.successUrl),t.searchParams.set(`quantity`,e.quantity?.toString()??`1`),t.toString()}};export{a as AuthClient};
|
|
2
2
|
//# sourceMappingURL=AuthClient.js.map
|
package/dist/AuthClient.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthClient.js","names":["#frontendUrl","#authClient","#appClient","#mailingListClient","#getRedirectIntent"],"sources":["../src/AuthClient.ts"],"sourcesContent":["import { magicLinkClient, emailOTPClient } from \"better-auth/client/plugins\";\nimport { passkeyClient
|
|
1
|
+
{"version":3,"file":"AuthClient.js","names":["#frontendUrl","#authClient","#appClient","#mailingListClient","#getRedirectIntent"],"sources":["../src/AuthClient.ts"],"sourcesContent":["import { magicLinkClient, emailOTPClient } from \"better-auth/client/plugins\";\nimport { passkeyClient } from \"@better-auth/passkey/client\";\nimport { createAuthClient } from \"better-auth/client\";\nimport { hc } from \"hono/client\";\nimport type { AppRouter, MailingListRouter } from \"@us-auth/api\";\nimport type { UserPurchases, Session, RedirectIntent } from \"@us-auth/types\";\n\nexport class AuthClient {\n #frontendUrl: string;\n #authClient;\n #appClient: ReturnType<typeof hc<AppRouter>>;\n #mailingListClient: ReturnType<typeof hc<MailingListRouter>>;\n\n constructor(\n apiUrl: string,\n frontendUrl: string,\n cookie?: string,\n mailingListPublicKey?: string,\n ) {\n this.#frontendUrl = frontendUrl;\n this.#authClient = createAuthClient({\n baseURL: apiUrl,\n plugins: [magicLinkClient(), emailOTPClient(), passkeyClient()],\n headers: {\n cookie,\n },\n });\n this.#appClient = hc<AppRouter>(new URL(\"/api/app\", apiUrl).toString(), {\n fetch: (url: any, init: any) =>\n fetch(url, {\n ...init,\n credentials: \"include\",\n }),\n });\n this.#mailingListClient = hc<MailingListRouter>(\n new URL(\"/api/mailing-list\", apiUrl).toString(),\n {\n fetch: (url: any, init: any) =>\n fetch(url, {\n ...init,\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Public-Key\": mailingListPublicKey,\n ...init.headers,\n },\n }),\n },\n );\n }\n\n // Authentication\n getSession = async (): Promise<Session | null> => {\n const { data, error } = await this.#authClient.getSession();\n if (error) throw error;\n return data;\n };\n\n signOut = async (onSuccess?: () => void): Promise<void> => {\n const { error } = await this.#authClient.signOut({\n fetchOptions: { onSuccess },\n });\n if (error) throw error;\n return;\n };\n\n // Purchases\n getPurchases = async (): Promise<UserPurchases | null> => {\n const res = await this.#appClient.purchases.$get();\n if (!res.ok) {\n throw new Error(\"Failed to get purchases\", {\n cause: await res.text(),\n });\n }\n const data = await res.json();\n return data satisfies UserPurchases;\n };\n\n #getRedirectIntent = (redirectUrl: string, appName?: string) => {\n return JSON.stringify({\n type: \"redirect\",\n redirectUrl,\n appName,\n } satisfies RedirectIntent);\n };\n\n // Mailing List\n newsletterSubscribe = async (\n email: string,\n userGroup?: string,\n callbackUrl?: string,\n ): Promise<void> => {\n const res = await this.#mailingListClient.subscribe.$post({\n json: {\n email,\n userGroup: userGroup ?? \"us-auth\",\n callbackUrl: callbackUrl ?? \"\",\n },\n });\n if (!res.ok) {\n throw new Error(await res.text());\n }\n return;\n };\n\n newsletterUnsubscribe = async (email: string): Promise<void> => {\n const res = await this.#mailingListClient.unsubscribe.$post({\n query: {\n email,\n },\n });\n if (!res.ok) {\n throw new Error(await res.text());\n }\n return;\n };\n\n // Utils\n getLoginUrl = (options?: { redirectUrl?: string; appName?: string }) => {\n const url = new URL(\"/login\", this.#frontendUrl);\n if (options?.redirectUrl) {\n url.searchParams.set(\n \"intent\",\n this.#getRedirectIntent(options.redirectUrl, options.appName),\n );\n }\n return url.toString();\n };\n\n getCheckoutUrl = (options: {\n priceId: string;\n discountCode?: string;\n successUrl?: string;\n quantity?: number;\n }) => {\n const url = new URL(\"/auth/checkout\", this.#frontendUrl);\n url.searchParams.set(\"priceId\", options.priceId);\n if (options.discountCode) {\n url.searchParams.set(\"discountCode\", options.discountCode);\n }\n if (options.successUrl) {\n url.searchParams.set(\"successUrl\", options.successUrl);\n }\n url.searchParams.set(\"quantity\", options.quantity?.toString() ?? \"1\");\n return url.toString();\n };\n}\n"],"mappings":"oOAOA,IAAa,EAAb,KAAwB,CACtB,GACA,GACA,GACA,GAEA,YACE,EACA,EACA,EACA,EACA,CACA,MAAA,EAAoB,EACpB,MAAA,EAAmB,EAAiB,CAClC,QAAS,EACT,QAAS,CAAC,GAAiB,CAAE,GAAgB,CAAE,GAAe,CAAC,CAC/D,QAAS,CACP,SACD,CACF,CAAC,CACF,MAAA,EAAkB,EAAc,IAAI,IAAI,WAAY,EAAO,CAAC,UAAU,CAAE,CACtE,OAAQ,EAAU,IAChB,MAAM,EAAK,CACT,GAAG,EACH,YAAa,UACd,CAAC,CACL,CAAC,CACF,MAAA,EAA0B,EACxB,IAAI,IAAI,oBAAqB,EAAO,CAAC,UAAU,CAC/C,CACE,OAAQ,EAAU,IAChB,MAAM,EAAK,CACT,GAAG,EACH,QAAS,CACP,eAAgB,mBAChB,eAAgB,EAChB,GAAG,EAAK,QACT,CACF,CAAC,CACL,CACF,CAIH,WAAa,SAAqC,CAChD,GAAM,CAAE,OAAM,SAAU,MAAM,MAAA,EAAiB,YAAY,CAC3D,GAAI,EAAO,MAAM,EACjB,OAAO,GAGT,QAAU,KAAO,IAA0C,CACzD,GAAM,CAAE,SAAU,MAAM,MAAA,EAAiB,QAAQ,CAC/C,aAAc,CAAE,YAAW,CAC5B,CAAC,CACF,GAAI,EAAO,MAAM,GAKnB,aAAe,SAA2C,CACxD,IAAM,EAAM,MAAM,MAAA,EAAgB,UAAU,MAAM,CAClD,GAAI,CAAC,EAAI,GACP,MAAU,MAAM,0BAA2B,CACzC,MAAO,MAAM,EAAI,MAAM,CACxB,CAAC,CAGJ,OADa,MAAM,EAAI,MAAM,EAI/B,IAAsB,EAAqB,IAClC,KAAK,UAAU,CACpB,KAAM,WACN,cACA,UACD,CAA0B,CAI7B,oBAAsB,MACpB,EACA,EACA,IACkB,CAClB,IAAM,EAAM,MAAM,MAAA,EAAwB,UAAU,MAAM,CACxD,KAAM,CACJ,QACA,UAAW,GAAa,UACxB,YAAa,GAAe,GAC7B,CACF,CAAC,CACF,GAAI,CAAC,EAAI,GACP,MAAU,MAAM,MAAM,EAAI,MAAM,CAAC,EAKrC,sBAAwB,KAAO,IAAiC,CAC9D,IAAM,EAAM,MAAM,MAAA,EAAwB,YAAY,MAAM,CAC1D,MAAO,CACL,QACD,CACF,CAAC,CACF,GAAI,CAAC,EAAI,GACP,MAAU,MAAM,MAAM,EAAI,MAAM,CAAC,EAMrC,YAAe,GAAyD,CACtE,IAAM,EAAM,IAAI,IAAI,SAAU,MAAA,EAAkB,CAOhD,OANI,GAAS,aACX,EAAI,aAAa,IACf,SACA,MAAA,EAAwB,EAAQ,YAAa,EAAQ,QAAQ,CAC9D,CAEI,EAAI,UAAU,EAGvB,eAAkB,GAKZ,CACJ,IAAM,EAAM,IAAI,IAAI,iBAAkB,MAAA,EAAkB,CASxD,OARA,EAAI,aAAa,IAAI,UAAW,EAAQ,QAAQ,CAC5C,EAAQ,cACV,EAAI,aAAa,IAAI,eAAgB,EAAQ,aAAa,CAExD,EAAQ,YACV,EAAI,aAAa,IAAI,aAAc,EAAQ,WAAW,CAExD,EAAI,aAAa,IAAI,WAAY,EAAQ,UAAU,UAAU,EAAI,IAAI,CAC9D,EAAI,UAAU"}
|
|
@@ -13,6 +13,7 @@ interface AuthProviderProps extends PropsWithChildren {
|
|
|
13
13
|
frontendUrl: string;
|
|
14
14
|
initialSession?: Session | null;
|
|
15
15
|
initialPurchases?: UserPurchases | null;
|
|
16
|
+
mailingListPublicKey?: string;
|
|
16
17
|
}
|
|
17
18
|
declare const AuthProvider: ({
|
|
18
19
|
children,
|
|
@@ -21,7 +22,8 @@ declare const AuthProvider: ({
|
|
|
21
22
|
initialSession,
|
|
22
23
|
initialPurchases,
|
|
23
24
|
authClient: providedAuthClient,
|
|
24
|
-
queryClient: providedQueryClient
|
|
25
|
+
queryClient: providedQueryClient,
|
|
26
|
+
mailingListPublicKey
|
|
25
27
|
}: AuthProviderProps) => react_jsx_runtime0.JSX.Element;
|
|
26
28
|
//#endregion
|
|
27
29
|
export { AuthProvider, AuthProviderProps };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{AuthClient as e}from"../AuthClient.js";import{AuthContext as t}from"./AuthContext.js";import{useCallback as n,useEffect as r,useMemo as i}from"react";import{QueryClient as a,useQuery as o}from"@tanstack/react-query";import{usePostHog as s}from"@posthog/react";import{jsx as c}from"react/jsx-runtime";const l=({children:l,baseUrl:u,frontendUrl:d,initialSession:f,initialPurchases:p,authClient:m,queryClient:h})=>{let
|
|
1
|
+
import{AuthClient as e}from"../AuthClient.js";import{AuthContext as t}from"./AuthContext.js";import{useCallback as n,useEffect as r,useMemo as i}from"react";import{QueryClient as a,useQuery as o}from"@tanstack/react-query";import{usePostHog as s}from"@posthog/react";import{jsx as c}from"react/jsx-runtime";const l=({children:l,baseUrl:u,frontendUrl:d,initialSession:f,initialPurchases:p,authClient:m,queryClient:h,mailingListPublicKey:g})=>{let _=s(),v=i(()=>m??new e(u,d,void 0,g),[u,m,g]),y=i(()=>h??new a,[h]),{data:b,isFetching:x,refetch:S}=o({queryKey:[`us-auth-session`],staleTime:1e3*60,initialData:f,queryFn:v.getSession},y);r(()=>{b?.user&&_&&_.get_distinct_id()!==b.user.id&&_.identify(b.user.id,{email:b.user.email})},[b,_]);let{data:C,isFetching:w,refetch:T}=o({queryKey:[`us-auth-purchases`],staleTime:1e3*60,initialData:p,queryFn:v.getPurchases},y),E=i(()=>v.getLoginUrl,[v]),D=i(()=>v.getCheckoutUrl,[v]),O=i(()=>v.signOut,[v]),k=i(()=>v.newsletterSubscribe,[v]),A=i(()=>v.newsletterUnsubscribe,[v]),j=n(e=>C?C.paddle.transactions.some(t=>t.items.some(t=>e.includes(t))&&!t.adjustments.some(e=>e.status===`approved`&&e.action===`refund`&&e.type===`full`)):!1,[C]),M=n(e=>{if(!C)return!1;let t=C.paddle.subscriptions.some(t=>t.items.some(t=>e.includes(t))&&t.status===`active`),n=C.stripe.some(t=>t.status===`active`&&t.items.some(t=>e.includes(t)));return t||n},[C]);return c(t.Provider,{value:{session:b??null,isSessionFetching:x,refetchSession:async()=>{await S()},purchases:C??null,isPurchasesFetching:w,refetchPurchases:async()=>{await T()},signOut:O,newsletterSubscribe:k,newsletterUnsubscribe:A,getLoginUrl:E,getCheckoutUrl:D,isSubscribed:M,isPurchased:j},children:l})};export{l as AuthProvider};
|
|
2
2
|
//# sourceMappingURL=AuthProvider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthProvider.js","names":[],"sources":["../../src/react/AuthProvider.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, type PropsWithChildren } from \"react\";\nimport { AuthContext } from \"./AuthContext\";\nimport { AuthClient } from \"../AuthClient\";\nimport type { Session, UserPurchases } from \"@us-auth/types\";\nimport { QueryClient, useQuery } from \"@tanstack/react-query\";\nimport { usePostHog } from \"@posthog/react\";\n\nexport interface AuthProviderProps extends PropsWithChildren {\n authClient?: AuthClient;\n queryClient?: QueryClient;\n baseUrl: string;\n frontendUrl: string;\n initialSession?: Session | null;\n initialPurchases?: UserPurchases | null;\n}\n\nexport const AuthProvider = ({\n children,\n baseUrl,\n frontendUrl,\n initialSession,\n initialPurchases,\n authClient: providedAuthClient,\n queryClient: providedQueryClient,\n}: AuthProviderProps) => {\n const ph = usePostHog();\n\n const authClient = useMemo(\n ()
|
|
1
|
+
{"version":3,"file":"AuthProvider.js","names":[],"sources":["../../src/react/AuthProvider.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, type PropsWithChildren } from \"react\";\nimport { AuthContext } from \"./AuthContext\";\nimport { AuthClient } from \"../AuthClient\";\nimport type { Session, UserPurchases } from \"@us-auth/types\";\nimport { QueryClient, useQuery } from \"@tanstack/react-query\";\nimport { usePostHog } from \"@posthog/react\";\n\nexport interface AuthProviderProps extends PropsWithChildren {\n authClient?: AuthClient;\n queryClient?: QueryClient;\n baseUrl: string;\n frontendUrl: string;\n initialSession?: Session | null;\n initialPurchases?: UserPurchases | null;\n mailingListPublicKey?: string;\n}\n\nexport const AuthProvider = ({\n children,\n baseUrl,\n frontendUrl,\n initialSession,\n initialPurchases,\n authClient: providedAuthClient,\n queryClient: providedQueryClient,\n mailingListPublicKey,\n}: AuthProviderProps) => {\n const ph = usePostHog();\n\n const authClient = useMemo(\n () =>\n providedAuthClient ??\n new AuthClient(baseUrl, frontendUrl, undefined, mailingListPublicKey),\n [baseUrl, providedAuthClient, mailingListPublicKey],\n );\n const queryClient = useMemo(\n () => providedQueryClient ?? new QueryClient(),\n [providedQueryClient],\n );\n\n const {\n data: session,\n isFetching: isSessionFetching,\n refetch: refetchSession,\n } = useQuery(\n {\n queryKey: [\"us-auth-session\"],\n staleTime: 1000 * 60,\n initialData: initialSession,\n queryFn: authClient.getSession,\n },\n queryClient,\n );\n\n useEffect(() => {\n if (session?.user && ph) {\n const distinctId = ph.get_distinct_id();\n if (distinctId !== session.user.id) {\n ph.identify(session.user.id, {\n email: session.user.email,\n });\n }\n }\n }, [session, ph]);\n\n const {\n data: purchases,\n isFetching: isPurchasesFetching,\n refetch: refetchPurchases,\n } = useQuery(\n {\n queryKey: [\"us-auth-purchases\"],\n staleTime: 1000 * 60,\n initialData: initialPurchases,\n queryFn: authClient.getPurchases,\n },\n queryClient,\n );\n\n const getLoginUrl = useMemo(() => authClient.getLoginUrl, [authClient]);\n const getCheckoutUrl = useMemo(() => authClient.getCheckoutUrl, [authClient]);\n const signOut = useMemo(() => authClient.signOut, [authClient]);\n const newsletterSubscribe = useMemo(\n () => authClient.newsletterSubscribe,\n [authClient],\n );\n const newsletterUnsubscribe = useMemo(\n () => authClient.newsletterUnsubscribe,\n [authClient],\n );\n\n const isPurchased = useCallback(\n (priceIds: string[]): boolean => {\n if (!purchases) return false;\n return purchases.paddle.transactions.some(\n (tra) =>\n tra.items.some((item) => priceIds.includes(item)) &&\n !tra.adjustments.some(\n (adj) =>\n adj.status === \"approved\" &&\n adj.action === \"refund\" &&\n adj.type === \"full\",\n ),\n );\n },\n [purchases],\n );\n\n const isSubscribed = useCallback(\n (priceIds: string[]): boolean => {\n if (!purchases) return false;\n\n const paddleSubscriptions = purchases.paddle.subscriptions.some(\n (sub) =>\n sub.items.some((item) => priceIds.includes(item)) &&\n sub.status === \"active\",\n );\n\n const stripeSubscriptions = purchases.stripe.some(\n (sub) =>\n sub.status === \"active\" &&\n sub.items.some((item) => priceIds.includes(item)),\n );\n\n return paddleSubscriptions || stripeSubscriptions;\n },\n [purchases],\n );\n\n return (\n <AuthContext.Provider\n value={{\n session: session ?? null,\n isSessionFetching,\n refetchSession: async () => {\n await refetchSession();\n },\n purchases: purchases ?? null,\n isPurchasesFetching,\n refetchPurchases: async () => {\n await refetchPurchases();\n },\n signOut,\n newsletterSubscribe,\n newsletterUnsubscribe,\n getLoginUrl,\n getCheckoutUrl,\n isSubscribed,\n isPurchased,\n }}\n >\n {children}\n </AuthContext.Provider>\n );\n};\n"],"mappings":"mTAiBA,MAAa,GAAgB,CAC3B,WACA,UACA,cACA,iBACA,mBACA,WAAY,EACZ,YAAa,EACb,0BACuB,CACvB,IAAM,EAAK,GAAY,CAEjB,EAAa,MAEf,GACA,IAAI,EAAW,EAAS,EAAa,IAAA,GAAW,EAAqB,CACvE,CAAC,EAAS,EAAoB,EAAqB,CACpD,CACK,EAAc,MACZ,GAAuB,IAAI,EACjC,CAAC,EAAoB,CACtB,CAEK,CACJ,KAAM,EACN,WAAY,EACZ,QAAS,GACP,EACF,CACE,SAAU,CAAC,kBAAkB,CAC7B,UAAW,IAAO,GAClB,YAAa,EACb,QAAS,EAAW,WACrB,CACD,EACD,CAED,MAAgB,CACV,GAAS,MAAQ,GACA,EAAG,iBAAiB,GACpB,EAAQ,KAAK,IAC9B,EAAG,SAAS,EAAQ,KAAK,GAAI,CAC3B,MAAO,EAAQ,KAAK,MACrB,CAAC,EAGL,CAAC,EAAS,EAAG,CAAC,CAEjB,GAAM,CACJ,KAAM,EACN,WAAY,EACZ,QAAS,GACP,EACF,CACE,SAAU,CAAC,oBAAoB,CAC/B,UAAW,IAAO,GAClB,YAAa,EACb,QAAS,EAAW,aACrB,CACD,EACD,CAEK,EAAc,MAAc,EAAW,YAAa,CAAC,EAAW,CAAC,CACjE,EAAiB,MAAc,EAAW,eAAgB,CAAC,EAAW,CAAC,CACvE,EAAU,MAAc,EAAW,QAAS,CAAC,EAAW,CAAC,CACzD,EAAsB,MACpB,EAAW,oBACjB,CAAC,EAAW,CACb,CACK,EAAwB,MACtB,EAAW,sBACjB,CAAC,EAAW,CACb,CAEK,EAAc,EACjB,GACM,EACE,EAAU,OAAO,aAAa,KAClC,GACC,EAAI,MAAM,KAAM,GAAS,EAAS,SAAS,EAAK,CAAC,EACjD,CAAC,EAAI,YAAY,KACd,GACC,EAAI,SAAW,YACf,EAAI,SAAW,UACf,EAAI,OAAS,OAChB,CACJ,CAVsB,GAYzB,CAAC,EAAU,CACZ,CAEK,EAAe,EAClB,GAAgC,CAC/B,GAAI,CAAC,EAAW,MAAO,GAEvB,IAAM,EAAsB,EAAU,OAAO,cAAc,KACxD,GACC,EAAI,MAAM,KAAM,GAAS,EAAS,SAAS,EAAK,CAAC,EACjD,EAAI,SAAW,SAClB,CAEK,EAAsB,EAAU,OAAO,KAC1C,GACC,EAAI,SAAW,UACf,EAAI,MAAM,KAAM,GAAS,EAAS,SAAS,EAAK,CAAC,CACpD,CAED,OAAO,GAAuB,GAEhC,CAAC,EAAU,CACZ,CAED,OACE,EAAC,EAAY,SAAb,CACE,MAAO,CACL,QAAS,GAAW,KACpB,oBACA,eAAgB,SAAY,CAC1B,MAAM,GAAgB,EAExB,UAAW,GAAa,KACxB,sBACA,iBAAkB,SAAY,CAC5B,MAAM,GAAkB,EAE1B,UACA,sBACA,wBACA,cACA,iBACA,eACA,cACD,CAEA,WACoB,CAAA"}
|