@cimplify/sdk 0.108.0 → 0.110.2
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/LICENSE +21 -0
- package/dist/advanced.d.mts +4 -3
- package/dist/advanced.d.ts +4 -3
- package/dist/advanced.js +24 -24
- package/dist/advanced.mjs +5 -5
- package/dist/animation-4EXBXRVX.js +27 -0
- package/dist/animation-6DICNWUP.mjs +6 -0
- package/dist/audio-DhvyjqdA.d.mts +249 -0
- package/dist/audio-m0w8cnxq.d.ts +249 -0
- package/dist/avatars.d.mts +110 -0
- package/dist/avatars.d.ts +110 -0
- package/dist/avatars.js +82 -0
- package/dist/avatars.mjs +5 -0
- package/dist/backend-gUCzs5Kg.d.mts +3866 -0
- package/dist/backend-gUCzs5Kg.d.ts +3866 -0
- package/dist/{catalogue-B4eLL8Mi.d.ts → catalogue-CPTMyBUz.d.mts} +109 -221
- package/dist/catalogue-DzrTXP3v.d.mts +541 -0
- package/dist/catalogue-DzrTXP3v.d.ts +541 -0
- package/dist/{catalogue-OT89_Ifs.d.mts → catalogue-OTuS5zp-.d.ts} +109 -221
- package/dist/chunk-22BD3RHN.mjs +1809 -0
- package/dist/chunk-25T4JHEA.mjs +21 -0
- package/dist/chunk-2AQ237Y4.js +508 -0
- package/dist/chunk-2IC4H6OV.mjs +48 -0
- package/dist/chunk-2LHLG4OB.mjs +71 -0
- package/dist/chunk-2O2CG465.js +1709 -0
- package/dist/chunk-2Q4DTHXK.js +316 -0
- package/dist/chunk-2QTQ6BUH.mjs +46 -0
- package/dist/chunk-2UN4SFLR.mjs +100 -0
- package/dist/chunk-2V75I7K3.js +454 -0
- package/dist/chunk-2V7IL4HC.js +10 -0
- package/dist/chunk-34XBXUMW.js +296 -0
- package/dist/chunk-3C4C654I.js +71 -0
- package/dist/chunk-3DAD2LDF.mjs +72 -0
- package/dist/chunk-3GXH2NFD.mjs +4 -0
- package/dist/chunk-3O47ZFW3.js +961 -0
- package/dist/chunk-3OY3VYNF.mjs +11 -0
- package/dist/chunk-3S6WPBZL.js +2936 -0
- package/dist/chunk-3TUOUP5T.js +399 -0
- package/dist/chunk-3VEH23I5.mjs +1380 -0
- package/dist/chunk-3ZYSAW2T.mjs +263 -0
- package/dist/chunk-4ANVF274.js +103 -0
- package/dist/chunk-4C7I3ELN.js +388 -0
- package/dist/chunk-4DYKAYFO.mjs +8 -0
- package/dist/chunk-4ZDR72SG.js +329 -0
- package/dist/chunk-52YS45RR.js +1066 -0
- package/dist/chunk-5325XSCH.js +107 -0
- package/dist/chunk-5AD5X6AV.js +13 -0
- package/dist/chunk-5BYDGGWO.mjs +197 -0
- package/dist/chunk-5C3C7VDM.mjs +55 -0
- package/dist/chunk-5HFMY3D7.js +660 -0
- package/dist/chunk-5LH2QN3T.js +1862 -0
- package/dist/chunk-5PJEXSOW.js +44 -0
- package/dist/chunk-5SXDH3Y7.js +90 -0
- package/dist/chunk-5YFBGGCK.mjs +502 -0
- package/dist/chunk-5YWN6H5Q.mjs +133 -0
- package/dist/chunk-66QP3SMN.js +402 -0
- package/dist/chunk-6DAEZKIG.mjs +385 -0
- package/dist/chunk-6DATW7TB.mjs +420 -0
- package/dist/{chunk-JRGK3NXR.mjs → chunk-6ETDAU62.mjs} +72 -212
- package/dist/chunk-6H254EVP.mjs +178 -0
- package/dist/chunk-6PFNJPBJ.mjs +820 -0
- package/dist/chunk-6PJWXIFX.mjs +357 -0
- package/dist/chunk-6SWKWCMS.js +80 -0
- package/dist/chunk-6VVXXX7S.js +808 -0
- package/dist/chunk-6WUBSMTX.js +1403 -0
- package/dist/chunk-73SGZLAQ.mjs +35 -0
- package/dist/chunk-76L2V6KD.mjs +4 -0
- package/dist/chunk-7AAIAVAA.js +1531 -0
- package/dist/chunk-7ARSJPV3.mjs +93 -0
- package/dist/chunk-7BHW5GTC.mjs +1234 -0
- package/dist/chunk-7DQSDKDU.js +6 -0
- package/dist/chunk-7IQQQENP.mjs +401 -0
- package/dist/chunk-7KFTYENS.js +11357 -0
- package/dist/chunk-7SM6XSPZ.js +3171 -0
- package/dist/chunk-7SXOHAIR.mjs +28 -0
- package/dist/chunk-A2MAX6S4.js +90 -0
- package/dist/chunk-A33OORT7.mjs +1530 -0
- package/dist/{chunk-U6ACF76H.mjs → chunk-A36JRXXH.mjs} +1075 -1845
- package/dist/chunk-A7BU3BK4.js +52 -0
- package/dist/chunk-A7MQSN2V.mjs +77 -0
- package/dist/chunk-A7V4L2IT.mjs +416 -0
- package/dist/chunk-AABEK6XU.js +226 -0
- package/dist/chunk-AGV33FWC.mjs +5005 -0
- package/dist/chunk-AHNR3BXI.js +108 -0
- package/dist/chunk-AQ5RLBU2.mjs +286 -0
- package/dist/chunk-AQOE6WCG.js +1270 -0
- package/dist/chunk-ATAWRACV.mjs +62 -0
- package/dist/chunk-ATCURNUV.js +14 -0
- package/dist/chunk-AWPV33OO.js +6 -0
- package/dist/chunk-AYJPHKYV.js +337 -0
- package/dist/chunk-AZ5BGWHB.js +162 -0
- package/dist/chunk-AZAXD44P.js +1373 -0
- package/dist/chunk-BBGKQIJJ.mjs +406 -0
- package/dist/chunk-BP4JLSUA.js +1453 -0
- package/dist/{chunk-SUCE7FWA.mjs → chunk-BTUSVHIE.mjs} +539 -978
- package/dist/chunk-BU6OK542.mjs +818 -0
- package/dist/chunk-CVSRWM6W.js +418 -0
- package/dist/chunk-CYBMFMJD.mjs +247 -0
- package/dist/chunk-DDJLDOUX.mjs +217 -0
- package/dist/{chunk-V32BCG7M.js → chunk-DFZWHNRG.js} +75 -215
- package/dist/chunk-DJ2C7AVG.js +644 -0
- package/dist/chunk-DS2VU4WW.mjs +102 -0
- package/dist/chunk-DSAG7T5P.js +7290 -0
- package/dist/chunk-E2QPPH7I.js +327 -0
- package/dist/chunk-E65WCTIG.mjs +1187 -0
- package/dist/{chunk-33VCYWVL.mjs → chunk-E6QQKDNE.mjs} +30 -42
- package/dist/chunk-ECDK6QBF.mjs +981 -0
- package/dist/chunk-EIB4OWVQ.mjs +620 -0
- package/dist/chunk-EQUZYCGO.js +250 -0
- package/dist/chunk-F3UJ6ZRM.mjs +313 -0
- package/dist/chunk-F63N2ZTQ.js +7023 -0
- package/dist/chunk-F6XRYEM3.mjs +26 -0
- package/dist/chunk-FE6VCE4K.js +5030 -0
- package/dist/chunk-FLWD6GRR.js +1372 -0
- package/dist/chunk-FQBFWJBS.mjs +110 -0
- package/dist/chunk-FXVJ2HFU.js +26 -0
- package/dist/chunk-FZMQMQBW.js +312 -0
- package/dist/chunk-G3EEC44R.js +53 -0
- package/dist/{chunk-KG3WT4PR.mjs → chunk-GCKWKLZF.mjs} +73 -104
- package/dist/chunk-GCX7TY4D.mjs +6826 -0
- package/dist/chunk-GDB6TCSD.js +450 -0
- package/dist/chunk-GDCV4IWO.mjs +21 -0
- package/dist/chunk-GDZT5LZ5.js +170 -0
- package/dist/chunk-GHPUYD4I.mjs +213 -0
- package/dist/chunk-GHS6MIL6.mjs +1432 -0
- package/dist/chunk-GPS2THCL.mjs +11 -0
- package/dist/{chunk-EV2EVOYS.js → chunk-GTJWQAGU.js} +31 -42
- package/dist/chunk-GVTI6UJQ.mjs +130 -0
- package/dist/chunk-GXKI64OT.mjs +1138 -0
- package/dist/chunk-GYDYF2WX.js +275 -0
- package/dist/chunk-GYLP6UG4.mjs +705 -0
- package/dist/chunk-H3OQKK6X.js +1158 -0
- package/dist/chunk-H5DFSCJ6.js +40 -0
- package/dist/chunk-HAGEIC2L.mjs +186 -0
- package/dist/chunk-HAJ4JRFO.js +293 -0
- package/dist/chunk-HDR72GB6.js +188 -0
- package/dist/chunk-HF5HPS4T.mjs +40 -0
- package/dist/chunk-HK6LOFDS.js +218 -0
- package/dist/chunk-HMWYTXCY.mjs +143 -0
- package/dist/chunk-HPCSRCMA.js +89 -0
- package/dist/chunk-HSEO6TPU.js +247 -0
- package/dist/chunk-I5FOHCLH.js +132 -0
- package/dist/chunk-IDLW4NWA.mjs +85 -0
- package/dist/chunk-IIDZ5WUX.js +61 -0
- package/dist/chunk-IR74FJHU.js +2332 -0
- package/dist/chunk-IRVFYAKP.mjs +100 -0
- package/dist/{chunk-XBL3TMPC.mjs → chunk-IZDWAL53.mjs} +1795 -3287
- package/dist/chunk-J2KZXIU3.js +51 -0
- package/dist/chunk-J2U6PJSO.js +91 -0
- package/dist/chunk-J5AJNY2N.js +283 -0
- package/dist/chunk-J6KQZ4FO.mjs +821 -0
- package/dist/{chunk-OWW5GUSB.js → chunk-JGBCIKJV.js} +7 -6
- package/dist/chunk-JKGTBMU7.mjs +25 -0
- package/dist/chunk-JR3TNEQC.js +422 -0
- package/dist/chunk-JURRXY2J.mjs +29 -0
- package/dist/chunk-K3HW5I2A.mjs +317 -0
- package/dist/chunk-K46SMZ66.mjs +103 -0
- package/dist/chunk-K4UDGE3Z.mjs +6 -0
- package/dist/chunk-KDQOR4QQ.mjs +350 -0
- package/dist/chunk-KDTVOLHI.mjs +288 -0
- package/dist/chunk-KGHJH5KJ.mjs +35 -0
- package/dist/chunk-KIZOA5LX.mjs +140 -0
- package/dist/chunk-KK6HYVBI.mjs +242 -0
- package/dist/chunk-KMKWGXMK.js +856 -0
- package/dist/chunk-KPA6K5IB.js +80 -0
- package/dist/chunk-KU7O4IXU.mjs +260 -0
- package/dist/chunk-KVFNRJOR.mjs +11142 -0
- package/dist/chunk-KZJRSXHK.js +2432 -0
- package/dist/chunk-LHWPRUJL.js +79 -0
- package/dist/chunk-LIV3KXJG.mjs +369 -0
- package/dist/chunk-LKV4LACG.js +21 -0
- package/dist/chunk-LUY45X3U.mjs +263 -0
- package/dist/chunk-LYEZZEEF.mjs +17 -0
- package/dist/chunk-M5EXQZYY.mjs +1519 -0
- package/dist/chunk-ME6HGG4I.mjs +1338 -0
- package/dist/chunk-MEXP6DA6.js +31 -0
- package/dist/chunk-MG52AW3H.js +902 -0
- package/dist/chunk-MIPO6F72.js +334 -0
- package/dist/{chunk-5QW7CQBA.js → chunk-MKIJQL5Q.js} +211 -321
- package/dist/chunk-MN3YETVN.mjs +17 -0
- package/dist/chunk-MOBSBXVE.mjs +2391 -0
- package/dist/chunk-MOMOZEUM.mjs +88 -0
- package/dist/chunk-MRFUNRAP.js +62 -0
- package/dist/chunk-MTIHEW2M.js +433 -0
- package/dist/chunk-N4RGGDEL.mjs +73 -0
- package/dist/chunk-NH654HAT.js +10 -0
- package/dist/chunk-NHJUGZUR.mjs +253 -0
- package/dist/chunk-NMQT4HG3.mjs +757 -0
- package/dist/chunk-NPSYB6DC.mjs +906 -0
- package/dist/chunk-NW2GPMSO.js +857 -0
- package/dist/chunk-NXKQOQ6L.js +76 -0
- package/dist/chunk-NXLAZIJZ.js +309 -0
- package/dist/chunk-NYWNA5CF.js +148 -0
- package/dist/chunk-NZTKLY2W.js +1442 -0
- package/dist/chunk-O2ICABUD.js +36 -0
- package/dist/chunk-OIVVQQ22.js +862 -0
- package/dist/chunk-OKC2B4O3.mjs +312 -0
- package/dist/chunk-OLWFPDBK.js +2220 -0
- package/dist/chunk-OMTVH334.js +3779 -0
- package/dist/chunk-OQRVEM56.mjs +362 -0
- package/dist/chunk-OXMIBOD4.js +337 -0
- package/dist/chunk-PBL6YL5L.mjs +288 -0
- package/dist/chunk-PDOELNNQ.js +97 -0
- package/dist/chunk-PDQJY2GZ.js +136 -0
- package/dist/chunk-PKOZXD2Q.js +1274 -0
- package/dist/chunk-PPF2BYFL.mjs +2191 -0
- package/dist/chunk-PQTQKNKD.js +539 -0
- package/dist/chunk-PRSR4FAV.mjs +81 -0
- package/dist/chunk-PTRNO5UD.js +95 -0
- package/dist/chunk-Q2Y3VMKH.js +2000 -0
- package/dist/chunk-QCZOE65N.js +96 -0
- package/dist/chunk-QDYFLATW.mjs +52 -0
- package/dist/chunk-QQABGCMM.js +22 -0
- package/dist/chunk-QS6TRHMR.js +345 -0
- package/dist/chunk-R56P64LB.mjs +208 -0
- package/dist/chunk-RCQ2MPBV.js +428 -0
- package/dist/chunk-RFVRPYR2.mjs +856 -0
- package/dist/chunk-RKBLPGPV.js +11521 -0
- package/dist/chunk-RM2V4IND.mjs +327 -0
- package/dist/chunk-RQXN5A34.mjs +613 -0
- package/dist/chunk-RUVGVNOF.mjs +2687 -0
- package/dist/chunk-SAFJIGYB.mjs +165 -0
- package/dist/chunk-SKQFLBDD.js +263 -0
- package/dist/chunk-SMK6JU2F.mjs +2092 -0
- package/dist/{chunk-UVRPC2P7.js → chunk-SNNEOS5Z.js} +1984 -3476
- package/dist/chunk-SPCRQ6NO.mjs +1246 -0
- package/dist/chunk-SWX4SALA.mjs +19 -0
- package/dist/{chunk-JVODCGFP.mjs → chunk-SYEO2WV4.mjs} +128 -238
- package/dist/chunk-T2QQMX2N.js +10 -0
- package/dist/chunk-T3AFF3L7.mjs +57 -0
- package/dist/chunk-T6Z2EXYL.js +712 -0
- package/dist/chunk-T7LOXGYX.js +118 -0
- package/dist/chunk-TJCAE7RC.mjs +1315 -0
- package/dist/chunk-TJI3K6RP.js +137 -0
- package/dist/chunk-TL2SVO4P.mjs +55 -0
- package/dist/chunk-TM63CYGN.mjs +399 -0
- package/dist/chunk-TU5RYTYU.mjs +13 -0
- package/dist/chunk-TVJZ4GPS.js +1553 -0
- package/dist/chunk-TWM6DLYF.js +371 -0
- package/dist/chunk-U63OC4TQ.js +30 -0
- package/dist/{chunk-L5GKVQVJ.js → chunk-U6BVSJZ6.js} +25 -57
- package/dist/chunk-U6UVWEAK.mjs +792 -0
- package/dist/chunk-UCEPNO6N.mjs +11048 -0
- package/dist/{chunk-ANT574FD.js → chunk-UCR5HRYM.js} +74 -105
- package/dist/chunk-UG5BTOTF.mjs +334 -0
- package/dist/chunk-UGH37BQW.mjs +157 -0
- package/dist/chunk-V7ZRH3PY.mjs +271 -0
- package/dist/chunk-VBGHBL3E.mjs +1394 -0
- package/dist/chunk-VRBDAS5I.js +920 -0
- package/dist/chunk-VVE3Y76O.js +230 -0
- package/dist/chunk-W65JIRI4.mjs +1182 -0
- package/dist/chunk-WHYKAT7G.js +62 -0
- package/dist/{chunk-YOIVZ6OA.mjs → chunk-WIZRUIZB.mjs} +25 -57
- package/dist/chunk-WKWTDZS7.js +385 -0
- package/dist/chunk-WLMINRC4.mjs +78 -0
- package/dist/chunk-WOF3AD3J.js +22 -0
- package/dist/chunk-WWKMOA76.js +1262 -0
- package/dist/chunk-X5A5FOWW.js +615 -0
- package/dist/chunk-X6CN6KQF.mjs +192 -0
- package/dist/chunk-XD2PMH46.mjs +517 -0
- package/dist/chunk-XJA2NGTI.mjs +88 -0
- package/dist/chunk-XJIHN3BY.mjs +8 -0
- package/dist/chunk-XK6UDWJS.js +203 -0
- package/dist/chunk-XPG3N5CF.mjs +415 -0
- package/dist/chunk-XVZ2NKSU.mjs +74 -0
- package/dist/chunk-XYP45OLE.js +117 -0
- package/dist/chunk-XZSDGZX6.mjs +301 -0
- package/dist/chunk-Y2EMGN4T.mjs +120 -0
- package/dist/chunk-Y3XWP5XW.mjs +298 -0
- package/dist/chunk-Y4K22JL6.js +228 -0
- package/dist/chunk-Y65LXQGA.mjs +3164 -0
- package/dist/chunk-Y66WVMO5.mjs +87 -0
- package/dist/chunk-Y7JWLB25.mjs +7280 -0
- package/dist/chunk-YCDXAJKU.js +175 -0
- package/dist/chunk-YRDQCCIS.js +152 -0
- package/dist/chunk-YV52DGSA.js +111 -0
- package/dist/chunk-YXGZQPUD.js +94 -0
- package/dist/chunk-Z3A3AFVU.mjs +102 -0
- package/dist/chunk-ZCY6YKKP.mjs +475 -0
- package/dist/chunk-ZEQHXVU5.js +215 -0
- package/dist/chunk-ZF7JCXCI.js +284 -0
- package/dist/chunk-ZJBRUH6V.js +29 -0
- package/dist/chunk-ZMIL4ZOA.js +365 -0
- package/dist/chunk-ZR5ULMN2.mjs +337 -0
- package/dist/chunk-ZXREOYOW.js +87 -0
- package/dist/{client-BSP9U1O1.d.mts → client-CX_WR0-J.d.mts} +2 -2
- package/dist/client-Dytx_ZTC.d.ts +230 -0
- package/dist/{client-B878xeAP.d.ts → client-dqOhP9Nc.d.ts} +2 -2
- package/dist/client-hTKbCuhG.d.mts +230 -0
- package/dist/clock-B-UAjkKa.d.mts +5 -0
- package/dist/clock-B-UAjkKa.d.ts +5 -0
- package/dist/config-BlXQluJR.d.mts +36 -0
- package/dist/config-BlXQluJR.d.ts +36 -0
- package/dist/courier-Cnn-edJ4.d.ts +95 -0
- package/dist/courier-FmGfkvIN.d.mts +95 -0
- package/dist/crowd-DdHFbqKK.d.ts +186 -0
- package/dist/crowd-hOVSAmA3.d.mts +186 -0
- package/dist/danfo-BEBapFlX.d.mts +146 -0
- package/dist/danfo-UQ_PTIIx.d.ts +146 -0
- package/dist/{elements-Bty6Qs_N.d.mts → elements-DdsRig-2.d.mts} +1548 -257
- package/dist/{elements-Bty6Qs_N.d.ts → elements-DdsRig-2.d.ts} +1548 -257
- package/dist/engines/godot.d.mts +56 -0
- package/dist/engines/godot.d.ts +56 -0
- package/dist/engines/godot.js +28 -0
- package/dist/engines/godot.mjs +3 -0
- package/dist/engines/wasm.d.mts +11 -0
- package/dist/engines/wasm.d.ts +11 -0
- package/dist/engines/wasm.js +178 -0
- package/dist/engines/wasm.mjs +176 -0
- package/dist/fallback-CrG_lTFk.d.mts +270 -0
- package/dist/fallback-CrG_lTFk.d.ts +270 -0
- package/dist/fallback-KDB4Y2CE.mjs +6 -0
- package/dist/fallback-Y26TQENE.js +19 -0
- package/dist/features-CZB4rmcD.d.mts +118 -0
- package/dist/features-CZB4rmcD.d.ts +118 -0
- package/dist/fit-BWiE7rgA.d.mts +44 -0
- package/dist/fit-DK0oT7zO.d.ts +44 -0
- package/dist/five-a-side-Bv1AOUy3.d.mts +115 -0
- package/dist/five-a-side-EC51SJY1.d.ts +115 -0
- package/dist/fluid-ARr0qUIL.d.ts +939 -0
- package/dist/fluid-DLlEj2cs.d.mts +939 -0
- package/dist/game/conformance.d.mts +84 -0
- package/dist/game/conformance.d.ts +84 -0
- package/dist/game/conformance.js +1025 -0
- package/dist/game/conformance.mjs +994 -0
- package/dist/game/heap.d.mts +40 -0
- package/dist/game/heap.d.ts +40 -0
- package/dist/game/heap.js +48 -0
- package/dist/game/heap.mjs +7 -0
- package/dist/game/kit/canvas.d.mts +240 -0
- package/dist/game/kit/canvas.d.ts +240 -0
- package/dist/game/kit/canvas.js +3566 -0
- package/dist/game/kit/canvas.mjs +1039 -0
- package/dist/game/kit/courier.d.mts +17 -0
- package/dist/game/kit/courier.d.ts +17 -0
- package/dist/game/kit/courier.js +66 -0
- package/dist/game/kit/courier.mjs +49 -0
- package/dist/game/kit/danfo.d.mts +11 -0
- package/dist/game/kit/danfo.d.ts +11 -0
- package/dist/game/kit/danfo.js +109 -0
- package/dist/game/kit/danfo.mjs +44 -0
- package/dist/game/kit/engine.d.mts +29 -0
- package/dist/game/kit/engine.d.ts +29 -0
- package/dist/game/kit/engine.js +183 -0
- package/dist/game/kit/engine.mjs +30 -0
- package/dist/game/kit/five-a-side.d.mts +11 -0
- package/dist/game/kit/five-a-side.d.ts +11 -0
- package/dist/game/kit/five-a-side.js +86 -0
- package/dist/game/kit/five-a-side.mjs +41 -0
- package/dist/game/kit/frontier.d.mts +344 -0
- package/dist/game/kit/frontier.d.ts +344 -0
- package/dist/game/kit/frontier.js +435 -0
- package/dist/game/kit/frontier.mjs +14 -0
- package/dist/game/kit/genesis.d.mts +752 -0
- package/dist/game/kit/genesis.d.ts +752 -0
- package/dist/game/kit/genesis.js +380 -0
- package/dist/game/kit/genesis.mjs +15 -0
- package/dist/game/kit/ludo.d.mts +15 -0
- package/dist/game/kit/ludo.d.ts +15 -0
- package/dist/game/kit/ludo.js +87 -0
- package/dist/game/kit/ludo.mjs +42 -0
- package/dist/game/kit/runner.d.mts +12 -0
- package/dist/game/kit/runner.d.ts +12 -0
- package/dist/game/kit/runner.js +83 -0
- package/dist/game/kit/runner.mjs +46 -0
- package/dist/game/kit/shootout.d.mts +13 -0
- package/dist/game/kit/shootout.d.ts +13 -0
- package/dist/game/kit/shootout.js +122 -0
- package/dist/game/kit/shootout.mjs +57 -0
- package/dist/game/kit/slots.d.mts +392 -0
- package/dist/game/kit/slots.d.ts +392 -0
- package/dist/game/kit/slots.js +215 -0
- package/dist/game/kit/slots.mjs +6 -0
- package/dist/game/kit/tycoon.d.mts +16 -0
- package/dist/game/kit/tycoon.d.ts +16 -0
- package/dist/game/kit/tycoon.js +145 -0
- package/dist/game/kit/tycoon.mjs +44 -0
- package/dist/game/kit/word.d.mts +11 -0
- package/dist/game/kit/word.d.ts +11 -0
- package/dist/game/kit/word.js +78 -0
- package/dist/game/kit/word.mjs +41 -0
- package/dist/game/kit/worlds.d.mts +18 -0
- package/dist/game/kit/worlds.d.ts +18 -0
- package/dist/game/kit/worlds.js +74 -0
- package/dist/game/kit/worlds.mjs +49 -0
- package/dist/game/kit.d.mts +53 -0
- package/dist/game/kit.d.ts +53 -0
- package/dist/game/kit.js +2610 -0
- package/dist/game/kit.mjs +101 -0
- package/dist/game/prepared.d.mts +14 -0
- package/dist/game/prepared.d.ts +14 -0
- package/dist/game/prepared.js +81 -0
- package/dist/game/prepared.mjs +32 -0
- package/dist/game-Bx8onkhX.d.mts +1451 -0
- package/dist/game-fgQy2YIm.d.ts +1451 -0
- package/dist/game-theme-CBTw1b_d.d.mts +35 -0
- package/dist/game-theme-Dg-ict5A.d.ts +35 -0
- package/dist/game.d.mts +3546 -0
- package/dist/game.d.ts +3546 -0
- package/dist/game.js +4455 -0
- package/dist/game.mjs +50 -0
- package/dist/graphics-C6YjWYvP.d.ts +5 -0
- package/dist/graphics-Dk2yQnYN.d.mts +5 -0
- package/dist/guest-DrsA00XD.d.mts +732 -0
- package/dist/guest-wIdfoT05.d.ts +732 -0
- package/dist/hit-stop-BKkVwTq7.d.mts +43 -0
- package/dist/hit-stop-D-8pPYnM.d.ts +43 -0
- package/dist/hot-Crn9XpHJ.d.ts +29 -0
- package/dist/hot-DH3nOhQD.d.mts +29 -0
- package/dist/{index-CQStGb3B.d.mts → index-6gkHMGAq.d.mts} +2 -2
- package/dist/index-B8ybCKJI.d.ts +41 -0
- package/dist/{index-DJwXmoaP.d.ts → index-B98Xac8e.d.ts} +2 -2
- package/dist/{index-B7oA_1XI.d.ts → index-B_ByTtIT.d.ts} +2 -2
- package/dist/index-DHjNHb1c.d.mts +41 -0
- package/dist/{index-DhUSTAhT.d.mts → index-DbAN_VQE.d.mts} +2 -2
- package/dist/index.d.mts +134 -24
- package/dist/index.d.ts +134 -24
- package/dist/index.js +407 -248
- package/dist/index.mjs +184 -58
- package/dist/interactives-authoring.d.mts +231 -0
- package/dist/interactives-authoring.d.ts +231 -0
- package/dist/interactives-authoring.js +1743 -0
- package/dist/interactives-authoring.mjs +1704 -0
- package/dist/interactives-canvas.global.js +148 -0
- package/dist/interactives-guest.d.mts +20 -0
- package/dist/interactives-guest.d.ts +20 -0
- package/dist/interactives-guest.js +63 -0
- package/dist/interactives-guest.json +1 -0
- package/dist/interactives-guest.mjs +61 -0
- package/dist/interactives-jsc.global.js +9357 -0
- package/dist/interactives-meters.d.mts +93 -0
- package/dist/interactives-meters.d.ts +93 -0
- package/dist/interactives-meters.js +252 -0
- package/dist/interactives-meters.mjs +68 -0
- package/dist/interactives-production.d.mts +430 -0
- package/dist/interactives-production.d.ts +430 -0
- package/dist/interactives-production.js +1231 -0
- package/dist/interactives-production.mjs +1170 -0
- package/dist/interactives-record.d.mts +112 -0
- package/dist/interactives-record.d.ts +112 -0
- package/dist/interactives-record.js +302 -0
- package/dist/interactives-record.mjs +295 -0
- package/dist/interactives-runtime.d.mts +61 -0
- package/dist/interactives-runtime.d.ts +61 -0
- package/dist/interactives-runtime.js +442 -0
- package/dist/interactives-runtime.mjs +25 -0
- package/dist/interactives-studio-kernel.global.js +1 -0
- package/dist/interactives-studio.d.mts +806 -0
- package/dist/interactives-studio.d.ts +806 -0
- package/dist/interactives-studio.js +5741 -0
- package/dist/interactives-studio.mjs +5651 -0
- package/dist/interactives-tick.d.mts +90 -0
- package/dist/interactives-tick.d.ts +90 -0
- package/dist/interactives-tick.js +203 -0
- package/dist/interactives-tick.mjs +6 -0
- package/dist/interactives-web.d.mts +762 -0
- package/dist/interactives-web.d.ts +762 -0
- package/dist/interactives-web.js +5000 -0
- package/dist/interactives-web.mjs +4628 -0
- package/dist/interactives.d.mts +2430 -0
- package/dist/interactives.d.ts +2430 -0
- package/dist/interactives.js +5723 -0
- package/dist/interactives.mjs +4333 -0
- package/dist/juice-CoHxlpKA.d.ts +42 -0
- package/dist/juice-DQztFS43.d.mts +42 -0
- package/dist/launch-T2f4_Di4.d.mts +151 -0
- package/dist/launch-d6oreMzR.d.ts +151 -0
- package/dist/library-DXYaMFhi.d.mts +69 -0
- package/dist/library-DXYaMFhi.d.ts +69 -0
- package/dist/link-BUTqGmyi.d.mts +38 -0
- package/dist/link-BUTqGmyi.d.ts +38 -0
- package/dist/lint.js +104 -204
- package/dist/lint.mjs +103 -203
- package/dist/local-D8_I6UeL.d.mts +6967 -0
- package/dist/local-VZkqsCzR.d.ts +6967 -0
- package/dist/lockstep-BLf6dglI.d.mts +321 -0
- package/dist/lockstep-D50Ia0JW.d.ts +321 -0
- package/dist/ludo-B8ClkDqr.d.ts +205 -0
- package/dist/ludo-BOuohQ-M.d.mts +205 -0
- package/dist/mock/cli.mjs +200 -56
- package/dist/mock/library.js +200 -56
- package/dist/mock/library.mjs +200 -56
- package/dist/mock/msw.js +200 -56
- package/dist/mock/msw.mjs +200 -56
- package/dist/native-BodxSh03.d.mts +16 -0
- package/dist/native-DUHMT8gA.d.ts +16 -0
- package/dist/network-ZXLD7l1b.d.mts +19 -0
- package/dist/network-ZXLD7l1b.d.ts +19 -0
- package/dist/online-XeymeM9s.d.ts +381 -0
- package/dist/online-d7W_Al9a.d.mts +381 -0
- package/dist/params-DxFb5G_U.d.mts +155 -0
- package/dist/params-DxFb5G_U.d.ts +155 -0
- package/dist/play-BRRlfLhX.d.ts +940 -0
- package/dist/play-ClrMd_e8.d.mts +940 -0
- package/dist/policy-CCw8tXLm.d.mts +3078 -0
- package/dist/policy-CMqOSQIu.d.ts +3078 -0
- package/dist/ports-B_0v_P3A.d.mts +13 -0
- package/dist/ports-CGU_3e_0.d.ts +13 -0
- package/dist/prefetch-BHnicOQj.d.ts +117 -0
- package/dist/prefetch-CBXgYacv.d.mts +117 -0
- package/dist/{price-CSztR02F.d.mts → price-BOzexBww.d.mts} +1 -1
- package/dist/{price-C_vasx9A.d.ts → price-C1h9sPxE.d.ts} +1 -1
- package/dist/protocol-C8qbpUbT.d.mts +242 -0
- package/dist/protocol-C8qbpUbT.d.ts +242 -0
- package/dist/rapier-AZHT4YI7.js +7886 -0
- package/dist/rapier-ODEPCQA6.mjs +7792 -0
- package/dist/react.d.mts +157 -15
- package/dist/react.d.ts +157 -15
- package/dist/react.js +5564 -5904
- package/dist/react.mjs +5451 -5808
- package/dist/runner-CQcLL7By.d.ts +189 -0
- package/dist/runner-D46Yj-wE.d.mts +189 -0
- package/dist/runtime-BRWfkf_q.d.mts +51 -0
- package/dist/runtime-DyuBMkKM.d.ts +51 -0
- package/dist/scheduling-D2ajXpMC.d.ts +224 -0
- package/dist/scheduling-DSRbbaZb.d.mts +224 -0
- package/dist/schema-BrWxzKp6.d.mts +63 -0
- package/dist/schema-BrWxzKp6.d.ts +63 -0
- package/dist/server/evict.js +34 -37
- package/dist/server/evict.mjs +34 -37
- package/dist/server/tanstack.d.mts +49 -3
- package/dist/server/tanstack.d.ts +49 -3
- package/dist/server/tanstack.js +169 -117
- package/dist/server/tanstack.mjs +166 -118
- package/dist/{server-Dckg4Vdr.d.ts → server-D29IIuDV.d.ts} +136 -130
- package/dist/{server-B6dW7-Lj.d.mts → server-DQMWPnc8.d.mts} +136 -130
- package/dist/server.d.mts +45 -5
- package/dist/server.d.ts +45 -5
- package/dist/server.js +171 -227
- package/dist/server.mjs +165 -225
- package/dist/session-grant-CJ27DwrT.d.mts +19 -0
- package/dist/session-grant-CJ27DwrT.d.ts +19 -0
- package/dist/shootout-BJZeX6FG.d.ts +140 -0
- package/dist/shootout-tcZd1Rxt.d.mts +140 -0
- package/dist/state-replica-stMtdkVD.d.mts +42 -0
- package/dist/state-replica-stMtdkVD.d.ts +42 -0
- package/dist/studio-CowqWqez.d.mts +14 -0
- package/dist/studio-CowqWqez.d.ts +14 -0
- package/dist/styles.css +1 -1
- package/dist/template-AhCdB1kW.d.mts +190 -0
- package/dist/template-BkEGVTQj.d.ts +190 -0
- package/dist/terrain-BMxEc6Oc.d.ts +429 -0
- package/dist/terrain-C-XC1Oui.d.mts +429 -0
- package/dist/testing/msw.d.mts +28 -4
- package/dist/testing/msw.d.ts +28 -4
- package/dist/testing/msw.js +15 -21
- package/dist/testing/msw.mjs +15 -21
- package/dist/testing/suite.d.mts +6 -5
- package/dist/testing/suite.d.ts +6 -5
- package/dist/testing/suite.js +89 -124
- package/dist/testing/suite.mjs +81 -116
- package/dist/testing.d.mts +27 -1227
- package/dist/testing.d.ts +27 -1227
- package/dist/testing.js +127 -131
- package/dist/testing.mjs +19 -23
- package/dist/tick-transport-C8QEh8Uw.d.mts +50 -0
- package/dist/tick-transport-UjHY3xK1.d.ts +50 -0
- package/dist/timeline-protocol-hp6e8zFB.d.mts +47 -0
- package/dist/timeline-protocol-hp6e8zFB.d.ts +47 -0
- package/dist/tokens-DhanQRQS.d.mts +21 -0
- package/dist/tokens-K8yxwd6G.d.ts +21 -0
- package/dist/tree-C-Io2Hbx.d.mts +35 -0
- package/dist/tree-CP_qSW4H.d.ts +35 -0
- package/dist/tycoon-B5KHk2Xx.d.mts +255 -0
- package/dist/tycoon-hmHo-3HX.d.ts +255 -0
- package/dist/types-BQkxPwZP.d.mts +219 -0
- package/dist/types-D_f6UUxM.d.ts +219 -0
- package/dist/ui-DwHicuFv.d.mts +563 -0
- package/dist/ui-hi7S2YcH.d.ts +563 -0
- package/dist/{sign-in-DQlIdqsi.d.mts → url-52ndUruG.d.mts} +15 -1
- package/dist/{sign-in-DQlIdqsi.d.ts → url-52ndUruG.d.ts} +15 -1
- package/dist/utils.d.mts +3 -3
- package/dist/utils.d.ts +3 -3
- package/dist/utils.js +37 -37
- package/dist/utils.mjs +4 -4
- package/dist/vars-Dc_PrhBK.d.mts +511 -0
- package/dist/vars-Dc_PrhBK.d.ts +511 -0
- package/dist/vm-IUARFFAI.mjs +63 -0
- package/dist/vm-N7L6MGGH.js +65 -0
- package/dist/weave-delivery-CW-Kstut.d.mts +360 -0
- package/dist/weave-delivery-CW-Kstut.d.ts +360 -0
- package/dist/web-Dss74a7v.d.ts +883 -0
- package/dist/web-f9ZQPoyw.d.mts +883 -0
- package/dist/web-transport-C7MkBL0a.d.ts +19 -0
- package/dist/web-transport-aYEqXMd9.d.mts +19 -0
- package/dist/weight-CPGjsgjV.d.ts +92 -0
- package/dist/weight-tF1ODR1p.d.mts +92 -0
- package/dist/word-BcX9Jcmv.d.mts +70 -0
- package/dist/word-C7sVPLHm.d.ts +70 -0
- package/dist/world-PvILHDR1.d.ts +2285 -0
- package/dist/world-qekkXjJv.d.mts +2285 -0
- package/dist/worlds-Br2Pb0Cs.d.ts +109 -0
- package/dist/worlds-D5ydYr7d.d.mts +109 -0
- package/engines/c/cimplify.h +108 -0
- package/engines/c/cimplify.lib.js +11 -0
- package/engines/godot/addons/cimplify/cimplify.gd +97 -0
- package/engines/rust/interactives-ctx/Cargo.toml +9 -0
- package/engines/rust/interactives-ctx/src/lib.rs +189 -0
- package/package.json +189 -3
- package/vendor/rapier3d-compat/LICENSE +201 -0
- package/vendor/rapier3d-compat/PATCHES.md +61 -0
- package/dist/chunk-2P4KXFB6.js +0 -274
- package/dist/chunk-3G6RQLXK.mjs +0 -21
- package/dist/chunk-3V4DVXV3.mjs +0 -254
- package/dist/chunk-EDK3LNM6.js +0 -2436
- package/dist/chunk-F7J3HK27.js +0 -4549
- package/dist/chunk-U4MW6PYU.mjs +0 -23
- package/dist/chunk-XREIZ56K.js +0 -26
|
@@ -0,0 +1,3779 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkGTJWQAGU_js = require('./chunk-GTJWQAGU.js');
|
|
4
|
+
var chunkDFZWHNRG_js = require('./chunk-DFZWHNRG.js');
|
|
5
|
+
var chunkUCR5HRYM_js = require('./chunk-UCR5HRYM.js');
|
|
6
|
+
|
|
7
|
+
// src/types/result.ts
|
|
8
|
+
function ok(value) {
|
|
9
|
+
return { ok: true, value };
|
|
10
|
+
}
|
|
11
|
+
function err(error) {
|
|
12
|
+
return { ok: false, error };
|
|
13
|
+
}
|
|
14
|
+
function isOk(result) {
|
|
15
|
+
return result.ok === true;
|
|
16
|
+
}
|
|
17
|
+
function isErr(result) {
|
|
18
|
+
return result.ok === false;
|
|
19
|
+
}
|
|
20
|
+
function mapResult(result, fn) {
|
|
21
|
+
return result.ok ? ok(fn(result.value)) : result;
|
|
22
|
+
}
|
|
23
|
+
function mapError(result, fn) {
|
|
24
|
+
return result.ok ? result : err(fn(result.error));
|
|
25
|
+
}
|
|
26
|
+
function flatMap(result, fn) {
|
|
27
|
+
return result.ok ? fn(result.value) : result;
|
|
28
|
+
}
|
|
29
|
+
function getOrElse(result, defaultFn) {
|
|
30
|
+
return result.ok ? result.value : defaultFn();
|
|
31
|
+
}
|
|
32
|
+
function unwrap(result) {
|
|
33
|
+
if (result.ok)
|
|
34
|
+
return result.value;
|
|
35
|
+
throw result.error;
|
|
36
|
+
}
|
|
37
|
+
function toNullable(result) {
|
|
38
|
+
return result.ok ? result.value : void 0;
|
|
39
|
+
}
|
|
40
|
+
async function fromPromise(promise, mapError2) {
|
|
41
|
+
try {
|
|
42
|
+
let value = await promise;
|
|
43
|
+
return ok(value);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
return err(mapError2(error));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function tryCatch(fn, mapError2) {
|
|
49
|
+
try {
|
|
50
|
+
return ok(fn());
|
|
51
|
+
} catch (error) {
|
|
52
|
+
return err(mapError2(error));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function combine(results) {
|
|
56
|
+
let values = [];
|
|
57
|
+
for (let result of results) {
|
|
58
|
+
if (!result.ok)
|
|
59
|
+
return result;
|
|
60
|
+
values.push(result.value);
|
|
61
|
+
}
|
|
62
|
+
return ok(values);
|
|
63
|
+
}
|
|
64
|
+
function combineObject(results) {
|
|
65
|
+
let values = {};
|
|
66
|
+
for (let [key, result] of Object.entries(results)) {
|
|
67
|
+
if (!result.ok)
|
|
68
|
+
return result;
|
|
69
|
+
values[key] = result.value;
|
|
70
|
+
}
|
|
71
|
+
return ok(values);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/internal/idempotency.ts
|
|
75
|
+
function generateIdempotencyKey(prefix = "idem") {
|
|
76
|
+
if (typeof crypto < "u" && crypto.randomUUID)
|
|
77
|
+
return `${prefix}_${crypto.randomUUID()}`;
|
|
78
|
+
let timestamp = Date.now().toString(36), random = Math.random().toString(36).substring(2, 15);
|
|
79
|
+
return `${prefix}_${timestamp}_${random}`;
|
|
80
|
+
}
|
|
81
|
+
var INTENT_PREFIX = "cimplify-intent:";
|
|
82
|
+
function sessionStorageOrNull() {
|
|
83
|
+
try {
|
|
84
|
+
return typeof window < "u" ? window.sessionStorage : null;
|
|
85
|
+
} catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function intentIdempotencyKey(scope, fingerprint, storage = sessionStorageOrNull()) {
|
|
90
|
+
let slot = INTENT_PREFIX + scope;
|
|
91
|
+
try {
|
|
92
|
+
let raw = storage?.getItem(slot);
|
|
93
|
+
if (raw) {
|
|
94
|
+
let stored = JSON.parse(raw);
|
|
95
|
+
if (stored.fingerprint === fingerprint && typeof stored.key == "string") return stored.key;
|
|
96
|
+
}
|
|
97
|
+
} catch {
|
|
98
|
+
}
|
|
99
|
+
let key = generateIdempotencyKey();
|
|
100
|
+
try {
|
|
101
|
+
storage?.setItem(slot, JSON.stringify({ key, fingerprint }));
|
|
102
|
+
} catch {
|
|
103
|
+
}
|
|
104
|
+
return key;
|
|
105
|
+
}
|
|
106
|
+
function clearIntentIdempotencyKey(scope, storage = sessionStorageOrNull()) {
|
|
107
|
+
try {
|
|
108
|
+
storage?.removeItem(INTENT_PREFIX + scope);
|
|
109
|
+
} catch {
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/internal/safe.ts
|
|
114
|
+
function toCimplifyError(error) {
|
|
115
|
+
return error instanceof chunkUCR5HRYM_js.CimplifyError ? chunkUCR5HRYM_js.enrichError(error) : error instanceof Error ? chunkUCR5HRYM_js.enrichError(new chunkUCR5HRYM_js.CimplifyError(chunkUCR5HRYM_js.ErrorCode.UNKNOWN_ERROR, error.message, false)) : chunkUCR5HRYM_js.enrichError(new chunkUCR5HRYM_js.CimplifyError(chunkUCR5HRYM_js.ErrorCode.UNKNOWN_ERROR, String(error), false));
|
|
116
|
+
}
|
|
117
|
+
async function safe(promise) {
|
|
118
|
+
try {
|
|
119
|
+
return ok(await promise);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
return err(toCimplifyError(error));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/catalogue.ts
|
|
126
|
+
function withQuery(path, params) {
|
|
127
|
+
let query = new URLSearchParams();
|
|
128
|
+
for (let [key, value] of Object.entries(params))
|
|
129
|
+
value !== void 0 && query.set(key, String(value));
|
|
130
|
+
let queryString = query.toString();
|
|
131
|
+
return queryString ? `${path}?${queryString}` : path;
|
|
132
|
+
}
|
|
133
|
+
function isRecord(value) {
|
|
134
|
+
return typeof value == "object" && value !== null;
|
|
135
|
+
}
|
|
136
|
+
function readFinalPrice(value) {
|
|
137
|
+
if (!isRecord(value)) return;
|
|
138
|
+
let finalPrice = value.final_price;
|
|
139
|
+
if (typeof finalPrice == "string" || typeof finalPrice == "number")
|
|
140
|
+
return finalPrice;
|
|
141
|
+
}
|
|
142
|
+
function needsDefaultPriceNormalization(value) {
|
|
143
|
+
return value == null || value === "";
|
|
144
|
+
}
|
|
145
|
+
function optionNeedsNormalization(option) {
|
|
146
|
+
return isRecord(option) && needsDefaultPriceNormalization(option.default_price);
|
|
147
|
+
}
|
|
148
|
+
function addOnNeedsNormalization(addOn) {
|
|
149
|
+
if (!isRecord(addOn)) return false;
|
|
150
|
+
let options = addOn.options;
|
|
151
|
+
return Array.isArray(options) && options.some((option) => optionNeedsNormalization(option));
|
|
152
|
+
}
|
|
153
|
+
function normalizeAddOnPayload(addOn) {
|
|
154
|
+
if (!isRecord(addOn)) return addOn;
|
|
155
|
+
let options = addOn.options;
|
|
156
|
+
if (!Array.isArray(options) || !options.some((option) => optionNeedsNormalization(option))) return addOn;
|
|
157
|
+
let normalizedAddOn = { ...addOn };
|
|
158
|
+
return normalizedAddOn.options = options.map((option) => {
|
|
159
|
+
if (!isRecord(option) || !optionNeedsNormalization(option)) return option;
|
|
160
|
+
let normalizedOption = { ...option }, optionPrice = normalizedOption.default_price;
|
|
161
|
+
return needsDefaultPriceNormalization(optionPrice) && (normalizedOption.default_price = readFinalPrice(normalizedOption.default_price_info) || readFinalPrice(normalizedOption.price_info) || "0"), normalizedOption;
|
|
162
|
+
}), normalizedAddOn;
|
|
163
|
+
}
|
|
164
|
+
function normalizeCatalogueProductPayload(product) {
|
|
165
|
+
let productRecord = product, defaultPrice = productRecord.default_price, addOns = productRecord.add_ons, needsPriceFix = needsDefaultPriceNormalization(defaultPrice), needsAddOnFix = Array.isArray(addOns) && addOns.some((addOn) => addOnNeedsNormalization(addOn));
|
|
166
|
+
if (!needsPriceFix && !needsAddOnFix)
|
|
167
|
+
return product;
|
|
168
|
+
let normalized = { ...productRecord };
|
|
169
|
+
if (needsPriceFix) {
|
|
170
|
+
let derivedDefaultPrice = readFinalPrice(normalized.default_price_info) || readFinalPrice(normalized.price_info) || (typeof normalized.final_price == "string" || typeof normalized.final_price == "number" ? normalized.final_price : void 0);
|
|
171
|
+
normalized.default_price = derivedDefaultPrice ?? "0";
|
|
172
|
+
}
|
|
173
|
+
return needsAddOnFix && Array.isArray(addOns) && (normalized.add_ons = addOns.map((addOn) => normalizeAddOnPayload(addOn))), normalized;
|
|
174
|
+
}
|
|
175
|
+
function toFiniteNumber(value) {
|
|
176
|
+
if (typeof value == "number" && Number.isFinite(value))
|
|
177
|
+
return value;
|
|
178
|
+
if (typeof value == "string" && value.trim().length > 0) {
|
|
179
|
+
let parsed = Number(value);
|
|
180
|
+
if (Number.isFinite(parsed))
|
|
181
|
+
return parsed;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function normalizePagination(value) {
|
|
185
|
+
if (!isRecord(value))
|
|
186
|
+
return;
|
|
187
|
+
let totalCount = toFiniteNumber(value.total_count), currentPage = toFiniteNumber(value.current_page), pageSize = toFiniteNumber(value.page_size), totalPages = toFiniteNumber(value.total_pages);
|
|
188
|
+
if (!(totalCount === void 0 || currentPage === void 0 || pageSize === void 0 || totalPages === void 0))
|
|
189
|
+
return {
|
|
190
|
+
total_count: totalCount,
|
|
191
|
+
current_page: currentPage,
|
|
192
|
+
page_size: pageSize,
|
|
193
|
+
total_pages: totalPages,
|
|
194
|
+
has_more: value.has_more === true,
|
|
195
|
+
next_cursor: typeof value.next_cursor == "string" ? value.next_cursor : void 0
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function normalizeCatalogueResult(payload) {
|
|
199
|
+
return Array.isArray(payload) ? {
|
|
200
|
+
items: payload.map((product) => normalizeCatalogueProductPayload(product)),
|
|
201
|
+
is_complete: true
|
|
202
|
+
} : isRecord(payload) ? {
|
|
203
|
+
items: (Array.isArray(payload.products) ? payload.products : Array.isArray(payload.items) ? payload.items : []).map((product) => normalizeCatalogueProductPayload(product)),
|
|
204
|
+
is_complete: typeof payload.is_complete == "boolean" ? payload.is_complete : true,
|
|
205
|
+
total_available: toFiniteNumber(payload.total_available),
|
|
206
|
+
pagination: normalizePagination(payload.pagination)
|
|
207
|
+
} : {
|
|
208
|
+
items: [],
|
|
209
|
+
is_complete: true
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function normalizeCatalogueSnapshot(payload) {
|
|
213
|
+
if (Array.isArray(payload))
|
|
214
|
+
return {
|
|
215
|
+
categories: [],
|
|
216
|
+
products: payload.map((product) => normalizeCatalogueProductPayload(product)),
|
|
217
|
+
add_ons: [],
|
|
218
|
+
is_complete: true
|
|
219
|
+
};
|
|
220
|
+
if (!isRecord(payload))
|
|
221
|
+
return {
|
|
222
|
+
categories: [],
|
|
223
|
+
products: [],
|
|
224
|
+
add_ons: [],
|
|
225
|
+
is_complete: true
|
|
226
|
+
};
|
|
227
|
+
let rawProducts = Array.isArray(payload.products) ? payload.products : Array.isArray(payload.items) ? payload.items : [], rawCategories = Array.isArray(payload.categories) ? payload.categories : [], rawAddOns = Array.isArray(payload.add_ons) ? payload.add_ons : [];
|
|
228
|
+
return {
|
|
229
|
+
categories: rawCategories,
|
|
230
|
+
products: rawProducts.map((product) => normalizeCatalogueProductPayload(product)),
|
|
231
|
+
add_ons: rawAddOns.map((addOn) => normalizeAddOnPayload(addOn)),
|
|
232
|
+
is_complete: typeof payload.is_complete == "boolean" ? payload.is_complete : true,
|
|
233
|
+
total_available: toFiniteNumber(payload.total_available),
|
|
234
|
+
pagination: normalizePagination(payload.pagination)
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
var CatalogueQueries = class {
|
|
238
|
+
constructor(client) {
|
|
239
|
+
this.client = client;
|
|
240
|
+
}
|
|
241
|
+
async getCatalogue(opts) {
|
|
242
|
+
let result = await safe(
|
|
243
|
+
this.client.get("/api/v1/catalogue", opts)
|
|
244
|
+
);
|
|
245
|
+
return result.ok ? ok(normalizeCatalogueSnapshot(result.value)) : result;
|
|
246
|
+
}
|
|
247
|
+
async getProducts(options, opts) {
|
|
248
|
+
let path = withQuery("/api/v1/catalogue/products", {
|
|
249
|
+
category_id: options?.category,
|
|
250
|
+
taxonomy_id: options?.taxonomy,
|
|
251
|
+
search: options?.search,
|
|
252
|
+
page: options?.page,
|
|
253
|
+
tags: options?.tags?.join(","),
|
|
254
|
+
featured: options?.featured,
|
|
255
|
+
in_stock: options?.in_stock,
|
|
256
|
+
min_price: options?.min_price,
|
|
257
|
+
max_price: options?.max_price,
|
|
258
|
+
sort_by: options?.sort_by,
|
|
259
|
+
sort_order: options?.sort_order,
|
|
260
|
+
limit: options?.limit,
|
|
261
|
+
offset: options?.offset,
|
|
262
|
+
cursor: options?.cursor,
|
|
263
|
+
properties: options?.properties ? JSON.stringify(options.properties) : void 0
|
|
264
|
+
}), result = await safe(this.client.get(path, opts));
|
|
265
|
+
return result.ok ? ok(normalizeCatalogueResult(result.value)) : result;
|
|
266
|
+
}
|
|
267
|
+
async getProduct(id, opts) {
|
|
268
|
+
let encodedId = encodeURIComponent(id), result = await safe(
|
|
269
|
+
this.client.get(`/api/v1/catalogue/products/${encodedId}`, opts)
|
|
270
|
+
);
|
|
271
|
+
if (!result.ok) return result;
|
|
272
|
+
let payload = result.value, rawProduct = isRecord(payload.item) ? payload.item : payload, product = normalizeCatalogueProductPayload(rawProduct);
|
|
273
|
+
isRecord(payload.category) && (product.category = payload.category);
|
|
274
|
+
let addOnIds = rawProduct.add_on_ids;
|
|
275
|
+
if (Array.isArray(addOnIds) && addOnIds.length > 0) {
|
|
276
|
+
let addOnsResult = await this.getAddOns(product.id, opts);
|
|
277
|
+
addOnsResult.ok && (product.add_ons = addOnsResult.value);
|
|
278
|
+
}
|
|
279
|
+
return ok(product);
|
|
280
|
+
}
|
|
281
|
+
async getProductBySlug(slug, opts) {
|
|
282
|
+
return this.getProduct(slug, opts);
|
|
283
|
+
}
|
|
284
|
+
async getVariants(productId) {
|
|
285
|
+
let encodedId = encodeURIComponent(productId);
|
|
286
|
+
return safe(
|
|
287
|
+
this.client.get(`/api/v1/catalogue/products/${encodedId}/variants`)
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
async getVariantAxes(productId) {
|
|
291
|
+
let encodedId = encodeURIComponent(productId);
|
|
292
|
+
return safe(
|
|
293
|
+
this.client.get(`/api/v1/catalogue/products/${encodedId}/variant-axes`)
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
async getVariantByAxisSelections(productId, selections) {
|
|
297
|
+
let encodedId = encodeURIComponent(productId);
|
|
298
|
+
return safe(
|
|
299
|
+
this.client.post(
|
|
300
|
+
`/api/v1/catalogue/products/${encodedId}/variants/find`,
|
|
301
|
+
{ axis_selections: selections }
|
|
302
|
+
)
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
async getVariantById(productId, variantId) {
|
|
306
|
+
let encodedProductId = encodeURIComponent(productId), encodedVariantId = encodeURIComponent(variantId);
|
|
307
|
+
return safe(
|
|
308
|
+
this.client.get(
|
|
309
|
+
`/api/v1/catalogue/products/${encodedProductId}/variants/${encodedVariantId}`
|
|
310
|
+
)
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
async getAddOns(productId, opts) {
|
|
314
|
+
let encodedId = encodeURIComponent(productId);
|
|
315
|
+
return safe(this.client.get(`/api/v1/catalogue/products/${encodedId}/add-ons`, opts));
|
|
316
|
+
}
|
|
317
|
+
async getCategories(opts) {
|
|
318
|
+
return safe(this.client.get("/api/v1/catalogue/categories", opts));
|
|
319
|
+
}
|
|
320
|
+
async getCategory(id, opts) {
|
|
321
|
+
let encodedId = encodeURIComponent(id);
|
|
322
|
+
return safe(this.client.get(`/api/v1/catalogue/categories/${encodedId}`, opts));
|
|
323
|
+
}
|
|
324
|
+
async getCategoryBySlug(slug, opts) {
|
|
325
|
+
return this.getCategory(slug, opts);
|
|
326
|
+
}
|
|
327
|
+
async getCategoryProducts(categoryId, options, opts) {
|
|
328
|
+
let encodedId = encodeURIComponent(categoryId), path = withQuery(`/api/v1/catalogue/categories/${encodedId}/products`, {
|
|
329
|
+
limit: options?.limit,
|
|
330
|
+
offset: options?.offset
|
|
331
|
+
});
|
|
332
|
+
return safe(this.client.get(path, opts));
|
|
333
|
+
}
|
|
334
|
+
async getCollections(opts) {
|
|
335
|
+
return safe(this.client.get("/api/v1/catalogue/collections", opts));
|
|
336
|
+
}
|
|
337
|
+
async getCollection(id, opts) {
|
|
338
|
+
let encodedId = encodeURIComponent(id);
|
|
339
|
+
return safe(this.client.get(`/api/v1/catalogue/collections/${encodedId}`, opts));
|
|
340
|
+
}
|
|
341
|
+
async getCollectionBySlug(slug, opts) {
|
|
342
|
+
return this.getCollection(slug, opts);
|
|
343
|
+
}
|
|
344
|
+
async getCollectionProducts(collectionId, options, opts) {
|
|
345
|
+
let encodedId = encodeURIComponent(collectionId), path = withQuery(`/api/v1/catalogue/collections/${encodedId}/products`, {
|
|
346
|
+
limit: options?.limit,
|
|
347
|
+
offset: options?.offset
|
|
348
|
+
});
|
|
349
|
+
return safe(this.client.get(path, opts));
|
|
350
|
+
}
|
|
351
|
+
async searchCollections(query, limit = 20) {
|
|
352
|
+
let path = withQuery("/api/v1/catalogue/collections", { search: query, limit });
|
|
353
|
+
return safe(this.client.get(path));
|
|
354
|
+
}
|
|
355
|
+
async getBundles() {
|
|
356
|
+
return safe(this.client.get("/api/v1/catalogue/bundles"));
|
|
357
|
+
}
|
|
358
|
+
async getBundle(id) {
|
|
359
|
+
let encodedId = encodeURIComponent(id);
|
|
360
|
+
return safe(this.client.get(`/api/v1/catalogue/bundles/${encodedId}`));
|
|
361
|
+
}
|
|
362
|
+
async getBundleBySlug(slug) {
|
|
363
|
+
return this.getBundle(slug);
|
|
364
|
+
}
|
|
365
|
+
async searchBundles(query, limit = 20) {
|
|
366
|
+
let path = withQuery("/api/v1/catalogue/bundles", { search: query, limit });
|
|
367
|
+
return safe(this.client.get(path));
|
|
368
|
+
}
|
|
369
|
+
async getComposites(options) {
|
|
370
|
+
let path = withQuery("/api/v1/catalogue/composites", { limit: options?.limit });
|
|
371
|
+
return safe(this.client.get(path));
|
|
372
|
+
}
|
|
373
|
+
async getComposite(id) {
|
|
374
|
+
let encodedId = encodeURIComponent(id);
|
|
375
|
+
return safe(this.client.get(`/api/v1/catalogue/composites/${encodedId}`));
|
|
376
|
+
}
|
|
377
|
+
async getCompositeByProduct(productId) {
|
|
378
|
+
let encodedId = encodeURIComponent(productId);
|
|
379
|
+
return safe(this.client.get(`/api/v1/catalogue/composites/by-product/${encodedId}`));
|
|
380
|
+
}
|
|
381
|
+
async calculateCompositePrice(compositeId, selections, locationId) {
|
|
382
|
+
let encodedId = encodeURIComponent(compositeId);
|
|
383
|
+
return safe(
|
|
384
|
+
this.client.post(
|
|
385
|
+
`/api/v1/catalogue/composites/${encodedId}/calculate-price`,
|
|
386
|
+
{
|
|
387
|
+
selections,
|
|
388
|
+
location_id: locationId
|
|
389
|
+
}
|
|
390
|
+
)
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
async fetchQuote(input, opts) {
|
|
394
|
+
let idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
395
|
+
return safe(
|
|
396
|
+
this.client.post("/api/v1/catalogue/quotes", input, { idempotencyKey })
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
async getQuote(quoteId) {
|
|
400
|
+
let encodedQuoteId = encodeURIComponent(quoteId);
|
|
401
|
+
return safe(this.client.get(`/api/v1/catalogue/quotes/${encodedQuoteId}`));
|
|
402
|
+
}
|
|
403
|
+
async refreshQuote(input) {
|
|
404
|
+
let encodedQuoteId = encodeURIComponent(input.quote_id);
|
|
405
|
+
return safe(
|
|
406
|
+
this.client.post(
|
|
407
|
+
`/api/v1/catalogue/quotes/${encodedQuoteId}/refresh`,
|
|
408
|
+
input
|
|
409
|
+
)
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
async getTaxonomies(parentId) {
|
|
413
|
+
let path = withQuery("/api/v1/catalogue/taxonomies", { parent_id: parentId });
|
|
414
|
+
return safe(this.client.get(path));
|
|
415
|
+
}
|
|
416
|
+
async getTaxonomy(id) {
|
|
417
|
+
let encodedId = encodeURIComponent(id);
|
|
418
|
+
return safe(this.client.get(`/api/v1/catalogue/taxonomies/${encodedId}`));
|
|
419
|
+
}
|
|
420
|
+
async getTaxonomyPath(id) {
|
|
421
|
+
let encodedId = encodeURIComponent(id);
|
|
422
|
+
return safe(
|
|
423
|
+
this.client.get(`/api/v1/catalogue/taxonomies/${encodedId}/path`)
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
async searchTaxonomies(query, limit) {
|
|
427
|
+
let path = withQuery("/api/v1/catalogue/taxonomies/search", { q: query, limit });
|
|
428
|
+
return safe(this.client.get(path));
|
|
429
|
+
}
|
|
430
|
+
async getEligibleBillingPlans(productId, query) {
|
|
431
|
+
let encodedId = encodeURIComponent(productId), path = withQuery(`/api/v1/catalogue/products/${encodedId}/billing-plans/eligible`, {
|
|
432
|
+
customer_id: query?.customer_id,
|
|
433
|
+
quantity: query?.quantity,
|
|
434
|
+
order_value: query?.order_value
|
|
435
|
+
});
|
|
436
|
+
return safe(this.client.get(path));
|
|
437
|
+
}
|
|
438
|
+
async getProductSchedules(productId) {
|
|
439
|
+
let encodedId = encodeURIComponent(productId);
|
|
440
|
+
return safe(
|
|
441
|
+
this.client.get(`/api/v1/catalogue/products/${encodedId}/schedules`)
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
async checkProductAvailableNow(productId, locationId) {
|
|
445
|
+
let encodedId = encodeURIComponent(productId), path = withQuery(`/api/v1/catalogue/products/${encodedId}/available-now`, {
|
|
446
|
+
location_id: locationId
|
|
447
|
+
});
|
|
448
|
+
return safe(this.client.get(path));
|
|
449
|
+
}
|
|
450
|
+
async getDeals(locationId) {
|
|
451
|
+
let path = withQuery("/api/v1/catalogue/deals", { location_id: locationId });
|
|
452
|
+
return safe(this.client.get(path));
|
|
453
|
+
}
|
|
454
|
+
async getProductsOnSale() {
|
|
455
|
+
return safe(this.client.get("/api/v1/catalogue/deals/on-sale"));
|
|
456
|
+
}
|
|
457
|
+
async getProductDeals(productId) {
|
|
458
|
+
let encodedId = encodeURIComponent(productId);
|
|
459
|
+
return safe(this.client.get(`/api/v1/catalogue/products/${encodedId}/deals`));
|
|
460
|
+
}
|
|
461
|
+
async getCategoryDeals(categoryId) {
|
|
462
|
+
let encodedId = encodeURIComponent(categoryId);
|
|
463
|
+
return safe(this.client.get(`/api/v1/catalogue/categories/${encodedId}/deals`));
|
|
464
|
+
}
|
|
465
|
+
async getCollectionDeals(collectionId) {
|
|
466
|
+
let encodedId = encodeURIComponent(collectionId);
|
|
467
|
+
return safe(this.client.get(`/api/v1/catalogue/collections/${encodedId}/deals`));
|
|
468
|
+
}
|
|
469
|
+
async validateDiscountCode(code, orderSubtotal, locationId) {
|
|
470
|
+
return safe(
|
|
471
|
+
this.client.post("/api/v1/catalogue/deals/validate", {
|
|
472
|
+
discount_code: code,
|
|
473
|
+
order_subtotal: orderSubtotal,
|
|
474
|
+
location_id: locationId
|
|
475
|
+
})
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
async search(query, options, opts) {
|
|
479
|
+
let result = await this.getProducts(
|
|
480
|
+
{
|
|
481
|
+
...options,
|
|
482
|
+
search: query,
|
|
483
|
+
limit: options?.limit ?? 20
|
|
484
|
+
},
|
|
485
|
+
opts
|
|
486
|
+
);
|
|
487
|
+
return result.ok ? ok(result.value.items) : result;
|
|
488
|
+
}
|
|
489
|
+
async searchProducts(query, options, opts) {
|
|
490
|
+
return this.search(query, options, opts);
|
|
491
|
+
}
|
|
492
|
+
async getMenu(options) {
|
|
493
|
+
let path = withQuery("/api/v1/catalogue/menu", {
|
|
494
|
+
category_id: options?.category,
|
|
495
|
+
limit: options?.limit
|
|
496
|
+
});
|
|
497
|
+
return safe(this.client.get(path));
|
|
498
|
+
}
|
|
499
|
+
async getMenuCategory(categoryId) {
|
|
500
|
+
let encodedId = encodeURIComponent(categoryId);
|
|
501
|
+
return safe(this.client.get(`/api/v1/catalogue/menu/categories/${encodedId}`));
|
|
502
|
+
}
|
|
503
|
+
async getMenuItem(itemId) {
|
|
504
|
+
let encodedId = encodeURIComponent(itemId);
|
|
505
|
+
return safe(this.client.get(`/api/v1/catalogue/menu/items/${encodedId}`));
|
|
506
|
+
}
|
|
507
|
+
async getTags(options) {
|
|
508
|
+
let path = withQuery("/api/v1/catalogue/tags", {
|
|
509
|
+
tag_group: options?.tag_group,
|
|
510
|
+
search: options?.search,
|
|
511
|
+
min_usage: options?.min_usage,
|
|
512
|
+
limit: options?.limit,
|
|
513
|
+
offset: options?.offset
|
|
514
|
+
});
|
|
515
|
+
return safe(this.client.get(path));
|
|
516
|
+
}
|
|
517
|
+
async getAttributeDefinitions(namespace) {
|
|
518
|
+
let params = namespace ? `?namespace=${encodeURIComponent(namespace)}` : "";
|
|
519
|
+
return safe(
|
|
520
|
+
this.client.get(`/api/v1/catalogue/attributes${params}`)
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
async getProductAttributes(productId) {
|
|
524
|
+
let encodedId = encodeURIComponent(productId);
|
|
525
|
+
return safe(
|
|
526
|
+
this.client.get(`/api/v1/catalogue/products/${encodedId}/attributes`)
|
|
527
|
+
);
|
|
528
|
+
}
|
|
529
|
+
async getCategoryAttributes(categoryId) {
|
|
530
|
+
let encodedId = encodeURIComponent(categoryId);
|
|
531
|
+
return safe(
|
|
532
|
+
this.client.get(
|
|
533
|
+
`/api/v1/catalogue/categories/${encodedId}/attributes`
|
|
534
|
+
)
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
async getCollectionAttributes(collectionId) {
|
|
538
|
+
let encodedId = encodeURIComponent(collectionId);
|
|
539
|
+
return safe(
|
|
540
|
+
this.client.get(
|
|
541
|
+
`/api/v1/catalogue/collections/${encodedId}/attributes`
|
|
542
|
+
)
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
async getPropertyFacets(options) {
|
|
546
|
+
let path = withQuery("/api/v1/catalogue/properties/facets", {
|
|
547
|
+
category_id: options?.category_id,
|
|
548
|
+
product_type: options?.product_type
|
|
549
|
+
});
|
|
550
|
+
return safe(this.client.get(path));
|
|
551
|
+
}
|
|
552
|
+
async getTaxonomyAttributes(taxonomyId) {
|
|
553
|
+
let encodedId = encodeURIComponent(taxonomyId);
|
|
554
|
+
return safe(
|
|
555
|
+
this.client.get(
|
|
556
|
+
`/api/v1/catalogue/taxonomies/${encodedId}/attributes`
|
|
557
|
+
)
|
|
558
|
+
);
|
|
559
|
+
}
|
|
560
|
+
async searchKnowledge(query, limit) {
|
|
561
|
+
let path = withQuery("/api/v1/catalogue/knowledge-base/search", {
|
|
562
|
+
q: query,
|
|
563
|
+
limit: limit ?? 5
|
|
564
|
+
});
|
|
565
|
+
return safe(this.client.get(path));
|
|
566
|
+
}
|
|
567
|
+
async getKnowledgeArticles() {
|
|
568
|
+
return safe(this.client.get("/api/v1/catalogue/knowledge-base/articles"));
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
// src/cart.ts
|
|
573
|
+
function lineItemToCartInput(item) {
|
|
574
|
+
let config = item.configuration, input = {
|
|
575
|
+
item_id: item.product_id,
|
|
576
|
+
quantity: item.quantity
|
|
577
|
+
};
|
|
578
|
+
return config.variant && (input.variant_id = config.variant.variant_id), config.add_ons && config.add_ons.selected_options.length > 0 && (input.add_on_options = config.add_ons.selected_options.map((o) => o.option_id)), config.type === "bundle" ? input.bundle_selections = config.input : config.type === "composite" && (input.composite_selections = config.input), input;
|
|
579
|
+
}
|
|
580
|
+
var CartOperations = class {
|
|
581
|
+
constructor(client) {
|
|
582
|
+
this.client = client;
|
|
583
|
+
}
|
|
584
|
+
async get() {
|
|
585
|
+
return safe(this.client.get("/api/v1/cart"));
|
|
586
|
+
}
|
|
587
|
+
async getItems() {
|
|
588
|
+
return safe(this.client.get("/api/v1/cart/items"));
|
|
589
|
+
}
|
|
590
|
+
async getCount() {
|
|
591
|
+
return safe(this.client.get("/api/v1/cart/count"));
|
|
592
|
+
}
|
|
593
|
+
async getTotal() {
|
|
594
|
+
return safe(this.client.get("/api/v1/cart/total"));
|
|
595
|
+
}
|
|
596
|
+
async quoteDestination(input) {
|
|
597
|
+
return safe(this.client.post("/api/v1/cart/destination-quote", input));
|
|
598
|
+
}
|
|
599
|
+
async getSummary() {
|
|
600
|
+
let cartResult = await this.get();
|
|
601
|
+
if (!cartResult.ok) return cartResult;
|
|
602
|
+
let cart = cartResult.value;
|
|
603
|
+
return ok({
|
|
604
|
+
item_count: cart.items.length,
|
|
605
|
+
total_items: cart.items.reduce((sum, item) => sum + item.quantity, 0),
|
|
606
|
+
subtotal: cart.pricing.subtotal,
|
|
607
|
+
discount_amount: cart.pricing.total_discounts,
|
|
608
|
+
tax_amount: cart.pricing.tax_amount,
|
|
609
|
+
total: cart.pricing.total_price,
|
|
610
|
+
currency: cart.pricing.currency
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
async addItem(input, opts) {
|
|
614
|
+
let idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
615
|
+
return safe(
|
|
616
|
+
this.client.post("/api/v1/cart/items", input, { idempotencyKey })
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
async updateItem(cartItemId, updates) {
|
|
620
|
+
return typeof updates.quantity != "number" ? {
|
|
621
|
+
ok: false,
|
|
622
|
+
error: new chunkUCR5HRYM_js.CimplifyError(
|
|
623
|
+
"VALIDATION_ERROR",
|
|
624
|
+
"updateItem requires a quantity; richer mid-cart edits are not supported"
|
|
625
|
+
)
|
|
626
|
+
} : this.updateQuantity(cartItemId, updates.quantity);
|
|
627
|
+
}
|
|
628
|
+
async updateQuantity(cartItemId, quantity) {
|
|
629
|
+
let encodedId = encodeURIComponent(cartItemId);
|
|
630
|
+
return safe(
|
|
631
|
+
this.client.patch(`/api/v1/cart/items/${encodedId}`, {
|
|
632
|
+
quantity
|
|
633
|
+
})
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
async removeItem(cartItemId) {
|
|
637
|
+
let encodedId = encodeURIComponent(cartItemId);
|
|
638
|
+
return safe(this.client.delete(`/api/v1/cart/items/${encodedId}`));
|
|
639
|
+
}
|
|
640
|
+
async clear() {
|
|
641
|
+
return safe(this.client.delete("/api/v1/cart"));
|
|
642
|
+
}
|
|
643
|
+
async applyCoupon(code, opts) {
|
|
644
|
+
let idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
645
|
+
return safe(
|
|
646
|
+
this.client.post(
|
|
647
|
+
"/api/v1/cart/coupons",
|
|
648
|
+
{ coupon_code: code },
|
|
649
|
+
{ idempotencyKey }
|
|
650
|
+
)
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
async removeCoupon() {
|
|
654
|
+
return safe(this.client.delete("/api/v1/cart/coupons/current"));
|
|
655
|
+
}
|
|
656
|
+
async reorderFromOrder(orderId) {
|
|
657
|
+
let orderResult = await this.client.orders.get(orderId);
|
|
658
|
+
if (!orderResult.ok) return orderResult;
|
|
659
|
+
let order = orderResult.value;
|
|
660
|
+
if (!order.items || order.items.length === 0)
|
|
661
|
+
return ok({ added: [], failed: [] });
|
|
662
|
+
let added = [], failed = [];
|
|
663
|
+
for (let item of order.items) {
|
|
664
|
+
let input = lineItemToCartInput(item), result = await this.addItem(input);
|
|
665
|
+
result.ok ? added.push({ item_id: input.item_id }) : failed.push({ item_id: input.item_id, error: result.error });
|
|
666
|
+
}
|
|
667
|
+
return ok({ added, failed });
|
|
668
|
+
}
|
|
669
|
+
async isEmpty() {
|
|
670
|
+
let countResult = await this.getCount();
|
|
671
|
+
return countResult.ok ? ok(countResult.value === 0) : countResult;
|
|
672
|
+
}
|
|
673
|
+
async hasItem(productId, variantId) {
|
|
674
|
+
let itemsResult = await this.getItems();
|
|
675
|
+
if (!itemsResult.ok) return itemsResult;
|
|
676
|
+
let found = itemsResult.value.some((item) => {
|
|
677
|
+
let matchesProduct = item.item_id === productId;
|
|
678
|
+
if (!variantId) return matchesProduct;
|
|
679
|
+
let config = item.configuration;
|
|
680
|
+
return "variant" in config && config.variant ? matchesProduct && config.variant.variant_id === variantId : matchesProduct;
|
|
681
|
+
});
|
|
682
|
+
return ok(found);
|
|
683
|
+
}
|
|
684
|
+
async findItem(productId, variantId) {
|
|
685
|
+
let itemsResult = await this.getItems();
|
|
686
|
+
if (!itemsResult.ok) return itemsResult;
|
|
687
|
+
let found = itemsResult.value.find((item) => {
|
|
688
|
+
let matchesProduct = item.item_id === productId;
|
|
689
|
+
if (!variantId) return matchesProduct;
|
|
690
|
+
let config = item.configuration;
|
|
691
|
+
return "variant" in config && config.variant ? matchesProduct && config.variant.variant_id === variantId : matchesProduct;
|
|
692
|
+
});
|
|
693
|
+
return ok(found);
|
|
694
|
+
}
|
|
695
|
+
};
|
|
696
|
+
|
|
697
|
+
// src/payment-authorization/types.ts
|
|
698
|
+
var PAYMENT_AUTHORIZATION_OUTCOME_STATUS = {
|
|
699
|
+
SUBMITTED: "submitted",
|
|
700
|
+
CANCELLED: "cancelled",
|
|
701
|
+
FAILED: "failed"
|
|
702
|
+
}, PAYMENT_AUTHORIZATION_PROVIDER = {
|
|
703
|
+
PAYSTACK: "paystack",
|
|
704
|
+
STRIPE: "stripe"
|
|
705
|
+
};
|
|
706
|
+
|
|
707
|
+
// src/payment-authorization/providers/paystack.ts
|
|
708
|
+
var PAYSTACK_POPUP_ERROR = {
|
|
709
|
+
PROVIDER_UNAVAILABLE: chunkUCR5HRYM_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
710
|
+
SUBMISSION_UNKNOWN: "SUBMISSION_UNKNOWN",
|
|
711
|
+
CANCELLED: "CANCELLED",
|
|
712
|
+
PAYMENT_CANCELLED: chunkUCR5HRYM_js.ErrorCode.PAYMENT_CANCELLED,
|
|
713
|
+
PAYMENT_FAILED: chunkUCR5HRYM_js.ErrorCode.PAYMENT_FAILED,
|
|
714
|
+
POPUP_BLOCKED: chunkUCR5HRYM_js.ErrorCode.POPUP_BLOCKED
|
|
715
|
+
};
|
|
716
|
+
async function openPaystackPopup(options, signal) {
|
|
717
|
+
if (typeof window > "u")
|
|
718
|
+
return { success: false, error: PAYSTACK_POPUP_ERROR.PROVIDER_UNAVAILABLE };
|
|
719
|
+
let PaystackPop;
|
|
720
|
+
try {
|
|
721
|
+
PaystackPop = (await import('@paystack/inline-js')).default;
|
|
722
|
+
} catch {
|
|
723
|
+
return { success: false, error: PAYSTACK_POPUP_ERROR.PROVIDER_UNAVAILABLE };
|
|
724
|
+
}
|
|
725
|
+
return new Promise((resolve) => {
|
|
726
|
+
let settled = false, providerStarted = false, resolveOnce = (result) => {
|
|
727
|
+
settled || (settled = true, signal && signal.removeEventListener("abort", onAbort), resolve(result));
|
|
728
|
+
}, onAbort = () => {
|
|
729
|
+
resolveOnce({
|
|
730
|
+
success: false,
|
|
731
|
+
// Once Paystack owns the transaction, cancellation is ambiguous. The
|
|
732
|
+
// adapter converts this into submitted so Cimplify polling decides.
|
|
733
|
+
error: providerStarted ? PAYSTACK_POPUP_ERROR.SUBMISSION_UNKNOWN : PAYSTACK_POPUP_ERROR.CANCELLED
|
|
734
|
+
});
|
|
735
|
+
};
|
|
736
|
+
if (signal?.aborted) {
|
|
737
|
+
resolveOnce({ success: false, error: PAYSTACK_POPUP_ERROR.CANCELLED });
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
signal && signal.addEventListener("abort", onAbort, { once: true });
|
|
741
|
+
try {
|
|
742
|
+
new PaystackPop().newTransaction({
|
|
743
|
+
key: options.key,
|
|
744
|
+
email: options.email,
|
|
745
|
+
amount: options.amount,
|
|
746
|
+
currency: options.currency,
|
|
747
|
+
reference: options.reference,
|
|
748
|
+
accessCode: options.accessCode,
|
|
749
|
+
onSuccess: (transaction) => {
|
|
750
|
+
resolveOnce({
|
|
751
|
+
success: !0,
|
|
752
|
+
reference: transaction.reference ?? options.reference
|
|
753
|
+
});
|
|
754
|
+
},
|
|
755
|
+
onCancel: () => {
|
|
756
|
+
resolveOnce({ success: !1, error: PAYSTACK_POPUP_ERROR.PAYMENT_CANCELLED });
|
|
757
|
+
},
|
|
758
|
+
onError: (error) => {
|
|
759
|
+
resolveOnce({
|
|
760
|
+
success: !1,
|
|
761
|
+
error: error?.message || PAYSTACK_POPUP_ERROR.PAYMENT_FAILED
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
}), providerStarted = !0;
|
|
765
|
+
} catch {
|
|
766
|
+
resolveOnce({ success: false, error: PAYSTACK_POPUP_ERROR.POPUP_BLOCKED });
|
|
767
|
+
}
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
var PaystackAuthorizationAdapter = class {
|
|
771
|
+
constructor(openPopup = openPaystackPopup) {
|
|
772
|
+
this.openPopup = openPopup;
|
|
773
|
+
this.provider = PAYMENT_AUTHORIZATION_PROVIDER.PAYSTACK;
|
|
774
|
+
}
|
|
775
|
+
async authorize(context) {
|
|
776
|
+
let result = await this.openPopup(
|
|
777
|
+
{
|
|
778
|
+
key: context.action.public_key,
|
|
779
|
+
email: context.email,
|
|
780
|
+
accessCode: context.action.client_secret,
|
|
781
|
+
reference: context.reference || context.action.client_secret,
|
|
782
|
+
currency: context.currency
|
|
783
|
+
},
|
|
784
|
+
context.signal
|
|
785
|
+
);
|
|
786
|
+
return result.success ? {
|
|
787
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.SUBMITTED,
|
|
788
|
+
reference: result.reference || context.reference
|
|
789
|
+
} : result.error === PAYSTACK_POPUP_ERROR.SUBMISSION_UNKNOWN ? {
|
|
790
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.SUBMITTED,
|
|
791
|
+
reference: context.reference
|
|
792
|
+
} : !result.error || result.error === PAYSTACK_POPUP_ERROR.CANCELLED || result.error === PAYSTACK_POPUP_ERROR.PAYMENT_CANCELLED ? { status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED } : result.error === PAYSTACK_POPUP_ERROR.POPUP_BLOCKED ? {
|
|
793
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
794
|
+
code: chunkUCR5HRYM_js.ErrorCode.POPUP_BLOCKED,
|
|
795
|
+
message: "Unable to open the Paystack payment popup. Please allow popups and try again.",
|
|
796
|
+
recoverable: true
|
|
797
|
+
} : result.error === PAYSTACK_POPUP_ERROR.PROVIDER_UNAVAILABLE ? {
|
|
798
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
799
|
+
code: chunkUCR5HRYM_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
800
|
+
message: "Paystack is unavailable in this environment.",
|
|
801
|
+
recoverable: false
|
|
802
|
+
} : {
|
|
803
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
804
|
+
code: chunkUCR5HRYM_js.ErrorCode.PAYMENT_FAILED,
|
|
805
|
+
message: result.error || "Paystack payment could not be submitted.",
|
|
806
|
+
recoverable: true
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
};
|
|
810
|
+
|
|
811
|
+
// src/payment-authorization/providers/stripe.ts
|
|
812
|
+
var STRIPE_REDIRECT_MODE = "if_required", STRIPE_PAYMENT_ELEMENT_TYPE = "payment";
|
|
813
|
+
async function loadStripeFromPeer(publicKey, options) {
|
|
814
|
+
try {
|
|
815
|
+
let imported = await import('@stripe/stripe-js');
|
|
816
|
+
return imported.loadStripe ? imported.loadStripe(publicKey, options) : null;
|
|
817
|
+
} catch {
|
|
818
|
+
return null;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
function createStripeModal() {
|
|
822
|
+
if (typeof document > "u" || !document.body) return null;
|
|
823
|
+
let previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null, root = document.createElement("div");
|
|
824
|
+
root.setAttribute("role", "dialog"), root.setAttribute("aria-modal", "true"), root.setAttribute("aria-label", "Secure card payment"), Object.assign(root.style, {
|
|
825
|
+
position: "fixed",
|
|
826
|
+
inset: "0",
|
|
827
|
+
zIndex: "2147483647",
|
|
828
|
+
display: "grid",
|
|
829
|
+
placeItems: "center",
|
|
830
|
+
padding: "16px",
|
|
831
|
+
background: "rgba(15, 23, 42, 0.58)"
|
|
832
|
+
});
|
|
833
|
+
let form = document.createElement("form");
|
|
834
|
+
Object.assign(form.style, {
|
|
835
|
+
width: "min(100%, 480px)",
|
|
836
|
+
maxHeight: "calc(100vh - 32px)",
|
|
837
|
+
overflow: "auto",
|
|
838
|
+
borderRadius: "12px",
|
|
839
|
+
padding: "24px",
|
|
840
|
+
background: "#fff",
|
|
841
|
+
boxShadow: "0 24px 80px rgba(15, 23, 42, 0.32)"
|
|
842
|
+
});
|
|
843
|
+
let title = document.createElement("h2");
|
|
844
|
+
title.textContent = "Complete card payment", Object.assign(title.style, { margin: "0 0 18px", font: "600 18px/1.4 system-ui" });
|
|
845
|
+
let paymentMount = document.createElement("div");
|
|
846
|
+
paymentMount.setAttribute("data-cimplify-stripe-payment-element", "");
|
|
847
|
+
let error = document.createElement("p");
|
|
848
|
+
error.setAttribute("role", "alert"), Object.assign(error.style, {
|
|
849
|
+
minHeight: "20px",
|
|
850
|
+
margin: "14px 0 0",
|
|
851
|
+
color: "#b91c1c",
|
|
852
|
+
font: "14px/1.4 system-ui"
|
|
853
|
+
});
|
|
854
|
+
let actions = document.createElement("div");
|
|
855
|
+
Object.assign(actions.style, {
|
|
856
|
+
display: "flex",
|
|
857
|
+
justifyContent: "flex-end",
|
|
858
|
+
gap: "10px",
|
|
859
|
+
marginTop: "18px"
|
|
860
|
+
});
|
|
861
|
+
let cancelButton = document.createElement("button");
|
|
862
|
+
cancelButton.type = "button", cancelButton.textContent = "Cancel", Object.assign(cancelButton.style, {
|
|
863
|
+
border: "1px solid #cbd5e1",
|
|
864
|
+
borderRadius: "8px",
|
|
865
|
+
padding: "10px 16px",
|
|
866
|
+
background: "#fff",
|
|
867
|
+
color: "#0f172a",
|
|
868
|
+
cursor: "pointer"
|
|
869
|
+
});
|
|
870
|
+
let submitButton = document.createElement("button");
|
|
871
|
+
return submitButton.type = "submit", submitButton.textContent = "Pay securely", Object.assign(submitButton.style, {
|
|
872
|
+
border: "0",
|
|
873
|
+
borderRadius: "8px",
|
|
874
|
+
padding: "10px 16px",
|
|
875
|
+
background: "#0f172a",
|
|
876
|
+
color: "#fff",
|
|
877
|
+
cursor: "pointer"
|
|
878
|
+
}), actions.append(cancelButton, submitButton), form.append(title, paymentMount, error, actions), root.append(form), document.body.append(root), cancelButton.focus(), { root, form, paymentMount, submitButton, cancelButton, error, previousFocus };
|
|
879
|
+
}
|
|
880
|
+
function stripeFailure(error) {
|
|
881
|
+
let message = error?.message || "Stripe could not authorize this payment.";
|
|
882
|
+
return error?.code === "payment_intent_authentication_failure" || error?.type === "invalid_request_error" ? {
|
|
883
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
884
|
+
code: chunkUCR5HRYM_js.ErrorCode.AUTHORIZATION_FAILED,
|
|
885
|
+
message,
|
|
886
|
+
recoverable: true
|
|
887
|
+
} : {
|
|
888
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
889
|
+
code: chunkUCR5HRYM_js.ErrorCode.PAYMENT_FAILED,
|
|
890
|
+
message,
|
|
891
|
+
recoverable: true
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
var StripeAuthorizationAdapter = class {
|
|
895
|
+
constructor(loadStripe = loadStripeFromPeer) {
|
|
896
|
+
this.loadStripe = loadStripe;
|
|
897
|
+
this.provider = PAYMENT_AUTHORIZATION_PROVIDER.STRIPE;
|
|
898
|
+
}
|
|
899
|
+
async authorize(context) {
|
|
900
|
+
if (typeof window > "u" || typeof document > "u" || context.signal?.aborted)
|
|
901
|
+
return context.signal?.aborted ? { status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED } : {
|
|
902
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
903
|
+
code: chunkUCR5HRYM_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
904
|
+
message: "Stripe Payment Element is unavailable in this environment.",
|
|
905
|
+
recoverable: false
|
|
906
|
+
};
|
|
907
|
+
let stripe;
|
|
908
|
+
try {
|
|
909
|
+
stripe = await this.loadStripe(
|
|
910
|
+
context.action.public_key,
|
|
911
|
+
context.action.provider_account_id ? { stripeAccount: context.action.provider_account_id } : void 0
|
|
912
|
+
);
|
|
913
|
+
} catch (error) {
|
|
914
|
+
return {
|
|
915
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
916
|
+
code: chunkUCR5HRYM_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
917
|
+
message: error instanceof Error ? error.message : "Stripe.js could not be loaded.",
|
|
918
|
+
recoverable: true
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
if (context.signal?.aborted)
|
|
922
|
+
return { status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED };
|
|
923
|
+
if (!stripe)
|
|
924
|
+
return {
|
|
925
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
926
|
+
code: chunkUCR5HRYM_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
927
|
+
message: "Stripe.js could not be loaded.",
|
|
928
|
+
recoverable: false
|
|
929
|
+
};
|
|
930
|
+
let modal = createStripeModal();
|
|
931
|
+
if (!modal)
|
|
932
|
+
return {
|
|
933
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
934
|
+
code: chunkUCR5HRYM_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
935
|
+
message: "Stripe Payment Element could not be mounted.",
|
|
936
|
+
recoverable: false
|
|
937
|
+
};
|
|
938
|
+
let paymentElement, elements;
|
|
939
|
+
try {
|
|
940
|
+
elements = stripe.elements({ clientSecret: context.action.client_secret }), paymentElement = elements.create(STRIPE_PAYMENT_ELEMENT_TYPE), paymentElement.mount(modal.paymentMount);
|
|
941
|
+
} catch {
|
|
942
|
+
return modal.root.remove(), modal.previousFocus?.focus(), {
|
|
943
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
944
|
+
code: chunkUCR5HRYM_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
945
|
+
message: "Stripe Payment Element could not be initialized.",
|
|
946
|
+
recoverable: false
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
return context.signal?.aborted ? (paymentElement.destroy ? paymentElement.destroy() : paymentElement.unmount?.(), modal.root.remove(), modal.previousFocus?.focus(), { status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED }) : new Promise((resolve) => {
|
|
950
|
+
let settled = false, submitting = false, confirmationStarted = false, cleanup = () => {
|
|
951
|
+
context.signal?.removeEventListener("abort", onAbort), modal.form.removeEventListener("submit", onSubmit), modal.cancelButton.removeEventListener("click", onCancel), paymentElement.destroy ? paymentElement.destroy() : paymentElement.unmount?.(), modal.root.remove(), modal.previousFocus?.focus();
|
|
952
|
+
}, settle = (outcome) => {
|
|
953
|
+
settled || (settled = true, cleanup(), resolve(outcome));
|
|
954
|
+
}, onAbort = () => {
|
|
955
|
+
if (confirmationStarted) {
|
|
956
|
+
settle({
|
|
957
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.SUBMITTED,
|
|
958
|
+
reference: context.reference
|
|
959
|
+
});
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
settle({ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED });
|
|
963
|
+
}, onCancel = () => {
|
|
964
|
+
confirmationStarted || settle({ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED });
|
|
965
|
+
}, onSubmit = async (event) => {
|
|
966
|
+
if (event.preventDefault(), !(submitting || settled)) {
|
|
967
|
+
submitting = true, modal.submitButton.disabled = true, modal.error.textContent = "";
|
|
968
|
+
try {
|
|
969
|
+
let validation = elements.submit ? await elements.submit() : {};
|
|
970
|
+
if (validation.error) {
|
|
971
|
+
modal.error.textContent = validation.error.message || "Check your payment details.", submitting = !1, modal.submitButton.disabled = !1;
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
if (settled || context.signal?.aborted) {
|
|
975
|
+
settle({ status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED });
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
confirmationStarted = !0, modal.cancelButton.disabled = !0;
|
|
979
|
+
let confirmation = await stripe.confirmPayment({
|
|
980
|
+
elements,
|
|
981
|
+
confirmParams: { return_url: context.returnUrl || window.location.href },
|
|
982
|
+
redirect: STRIPE_REDIRECT_MODE
|
|
983
|
+
});
|
|
984
|
+
if (settled) return;
|
|
985
|
+
if (confirmation.error) {
|
|
986
|
+
settle(stripeFailure(confirmation.error));
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
settle({
|
|
990
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.SUBMITTED,
|
|
991
|
+
reference: confirmation.paymentIntent?.id || context.reference
|
|
992
|
+
});
|
|
993
|
+
} catch (error) {
|
|
994
|
+
if (confirmationStarted) {
|
|
995
|
+
settle({
|
|
996
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.SUBMITTED,
|
|
997
|
+
reference: context.reference
|
|
998
|
+
});
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
settle(
|
|
1002
|
+
stripeFailure({
|
|
1003
|
+
message: error instanceof Error ? error.message : "Stripe confirmation failed."
|
|
1004
|
+
})
|
|
1005
|
+
);
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
};
|
|
1009
|
+
modal.form.addEventListener("submit", onSubmit), modal.cancelButton.addEventListener("click", onCancel), context.signal?.addEventListener("abort", onAbort, { once: true }), paymentElement.on?.("escape", onCancel), paymentElement.on?.("loaderror", (event) => {
|
|
1010
|
+
confirmationStarted || settle({
|
|
1011
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
1012
|
+
code: chunkUCR5HRYM_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
1013
|
+
message: event?.error?.message || "Stripe Payment Element failed to load.",
|
|
1014
|
+
recoverable: true
|
|
1015
|
+
});
|
|
1016
|
+
});
|
|
1017
|
+
});
|
|
1018
|
+
}
|
|
1019
|
+
};
|
|
1020
|
+
|
|
1021
|
+
// src/payment-authorization/registry.ts
|
|
1022
|
+
function normalizeProvider(provider) {
|
|
1023
|
+
return typeof provider == "string" ? provider.trim().toLowerCase() : "";
|
|
1024
|
+
}
|
|
1025
|
+
var PaymentAuthorizationAdapterRegistry = class {
|
|
1026
|
+
constructor(adapters = []) {
|
|
1027
|
+
this.adapters = /* @__PURE__ */ new Map();
|
|
1028
|
+
for (let adapter of adapters)
|
|
1029
|
+
this.register(adapter);
|
|
1030
|
+
}
|
|
1031
|
+
register(adapter) {
|
|
1032
|
+
let provider = normalizeProvider(adapter.provider);
|
|
1033
|
+
if (!provider)
|
|
1034
|
+
throw new TypeError("Payment authorization adapter provider cannot be empty.");
|
|
1035
|
+
return this.adapters.set(provider, adapter), this;
|
|
1036
|
+
}
|
|
1037
|
+
unregister(provider) {
|
|
1038
|
+
return this.adapters.delete(normalizeProvider(provider));
|
|
1039
|
+
}
|
|
1040
|
+
get(provider) {
|
|
1041
|
+
return this.adapters.get(normalizeProvider(provider));
|
|
1042
|
+
}
|
|
1043
|
+
supports(provider) {
|
|
1044
|
+
return this.adapters.has(normalizeProvider(provider));
|
|
1045
|
+
}
|
|
1046
|
+
providers() {
|
|
1047
|
+
return [...this.adapters.keys()];
|
|
1048
|
+
}
|
|
1049
|
+
async authorize(action, options) {
|
|
1050
|
+
let provider = normalizeProvider(action.provider);
|
|
1051
|
+
if (!provider)
|
|
1052
|
+
return {
|
|
1053
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
1054
|
+
code: chunkUCR5HRYM_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
1055
|
+
message: "Card authorization response did not identify a payment provider.",
|
|
1056
|
+
recoverable: false
|
|
1057
|
+
};
|
|
1058
|
+
let adapter = this.adapters.get(provider);
|
|
1059
|
+
if (!adapter)
|
|
1060
|
+
return {
|
|
1061
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
1062
|
+
code: chunkUCR5HRYM_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
1063
|
+
message: `Card authorization provider '${provider}' is not supported by this SDK client.`,
|
|
1064
|
+
recoverable: false
|
|
1065
|
+
};
|
|
1066
|
+
try {
|
|
1067
|
+
let normalizedAction = action.provider === provider ? action : { ...action, provider };
|
|
1068
|
+
return await adapter.authorize({ ...options, action: normalizedAction });
|
|
1069
|
+
} catch (error) {
|
|
1070
|
+
return {
|
|
1071
|
+
status: PAYMENT_AUTHORIZATION_OUTCOME_STATUS.FAILED,
|
|
1072
|
+
code: chunkUCR5HRYM_js.ErrorCode.PAYMENT_FAILED,
|
|
1073
|
+
message: error instanceof Error ? error.message : `Card authorization provider '${provider}' failed unexpectedly.`,
|
|
1074
|
+
recoverable: true
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
};
|
|
1079
|
+
function createDefaultPaymentAuthorizationAdapterRegistry() {
|
|
1080
|
+
return new PaymentAuthorizationAdapterRegistry([
|
|
1081
|
+
new PaystackAuthorizationAdapter(),
|
|
1082
|
+
new StripeAuthorizationAdapter()
|
|
1083
|
+
]);
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
// src/utils/purchase-intent-confirmation.ts
|
|
1087
|
+
var EXACT_ZERO_MONEY = /^[+-]?0+(?:\.0+)?(?:[eE][+-]?\d+)?$/;
|
|
1088
|
+
function isExactlyZeroMoney(value) {
|
|
1089
|
+
return typeof value == "number" ? Object.is(value, 0) || Object.is(value, -0) : EXACT_ZERO_MONEY.test(value.trim());
|
|
1090
|
+
}
|
|
1091
|
+
function selectPurchaseIntentPaymentOption(terms, selection) {
|
|
1092
|
+
return terms.payment_options.filter((option) => option.status === chunkUCR5HRYM_js.PAYMENT_OPTION_STATUS.ELIGIBLE).sort((left, right) => left.rank - right.rank).find(
|
|
1093
|
+
(option) => option.method_kind === selection.method_kind && (selection.payment_option_id === void 0 || option.id === selection.payment_option_id)
|
|
1094
|
+
);
|
|
1095
|
+
}
|
|
1096
|
+
function createPurchaseIntentConfirmation(terms, paymentOption, idempotencyKey) {
|
|
1097
|
+
let normalizedKey = idempotencyKey.trim();
|
|
1098
|
+
if (!normalizedKey) throw new TypeError("idempotencyKey must not be empty");
|
|
1099
|
+
let requiresOption = purchaseIntentRequiresPaymentOption(terms);
|
|
1100
|
+
if (!paymentOption && requiresOption)
|
|
1101
|
+
throw new TypeError("Nonzero rail terms require an eligible payment option");
|
|
1102
|
+
if (paymentOption && !requiresOption)
|
|
1103
|
+
throw new TypeError("Zero-rail terms must not name a payment option");
|
|
1104
|
+
let authoritativeOption = paymentOption ? terms.payment_options.find(
|
|
1105
|
+
(candidate) => candidate.id === paymentOption.id && candidate.status === chunkUCR5HRYM_js.PAYMENT_OPTION_STATUS.ELIGIBLE
|
|
1106
|
+
) : void 0;
|
|
1107
|
+
if (paymentOption && !authoritativeOption)
|
|
1108
|
+
throw new TypeError("Payment option is not eligible for these checkout terms");
|
|
1109
|
+
return {
|
|
1110
|
+
accepted_intent_revision: terms.intent_revision,
|
|
1111
|
+
accepted_terms_version: terms.terms_version,
|
|
1112
|
+
accepted_due_now: terms.money.due_now,
|
|
1113
|
+
// Rail fees and routes may differ by option. Consent is to the exact
|
|
1114
|
+
// server-issued buyer debit, never an ambiguous principal/fee aggregate.
|
|
1115
|
+
accepted_customer_debit_amount: authoritativeOption?.customer_debit_amount ?? terms.money.rail_amount,
|
|
1116
|
+
currency: terms.money.currency,
|
|
1117
|
+
payment_option_id: authoritativeOption?.id ?? null,
|
|
1118
|
+
idempotency_key: normalizedKey
|
|
1119
|
+
};
|
|
1120
|
+
}
|
|
1121
|
+
function purchaseIntentRequiresPaymentOption(terms) {
|
|
1122
|
+
return terms.payment_options.length > 0 || !isExactlyZeroMoney(terms.money.rail_amount);
|
|
1123
|
+
}
|
|
1124
|
+
var PLAIN_DECIMAL = /^([+-]?)(\d+)(?:\.(\d+))?$/;
|
|
1125
|
+
function canonicalDecimal(value) {
|
|
1126
|
+
let match = PLAIN_DECIMAL.exec(typeof value == "number" ? String(value) : value.trim());
|
|
1127
|
+
if (!match) return null;
|
|
1128
|
+
let whole = match[2].replace(/^0+(?=\d)/, ""), fraction = (match[3] ?? "").replace(/0+$/, ""), isZero = whole === "0" && fraction === "";
|
|
1129
|
+
return `${match[1] === "-" && !isZero ? "-" : ""}${whole}${fraction ? `.${fraction}` : ""}`;
|
|
1130
|
+
}
|
|
1131
|
+
function isSameAmount(left, right) {
|
|
1132
|
+
let canonicalLeft = canonicalDecimal(left);
|
|
1133
|
+
return canonicalLeft !== null && canonicalLeft === canonicalDecimal(right);
|
|
1134
|
+
}
|
|
1135
|
+
function confirmationForUnchangedReplacement(response, selection, idempotencyKey) {
|
|
1136
|
+
let { replacement, deltas } = response, paymentDeltas = deltas.filter(
|
|
1137
|
+
(delta2) => delta2.kind === chunkUCR5HRYM_js.CHECKOUT_TERMS_DELTA_KIND.PAYMENT_OPTION
|
|
1138
|
+
);
|
|
1139
|
+
if (paymentDeltas.length !== deltas.length) return null;
|
|
1140
|
+
if (!purchaseIntentRequiresPaymentOption(replacement))
|
|
1141
|
+
return paymentDeltas.length === 0 ? createPurchaseIntentConfirmation(replacement, null, idempotencyKey) : null;
|
|
1142
|
+
if (!selection || paymentDeltas.length !== 1) return null;
|
|
1143
|
+
let option = selectPurchaseIntentPaymentOption(replacement, {
|
|
1144
|
+
method_kind: selection.method_kind
|
|
1145
|
+
}), [delta] = paymentDeltas;
|
|
1146
|
+
return !option || delta.kind !== chunkUCR5HRYM_js.CHECKOUT_TERMS_DELTA_KIND.PAYMENT_OPTION || !isSameAmount(option.customer_debit_amount, delta.accepted_customer_debit_amount) ? null : createPurchaseIntentConfirmation(replacement, option, idempotencyKey);
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
// src/utils/purchase-intent-adapter.ts
|
|
1150
|
+
function tenderPreference(form) {
|
|
1151
|
+
if (form.payment_method === chunkUCR5HRYM_js.PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY) {
|
|
1152
|
+
if (form.link_payment_method_id)
|
|
1153
|
+
return {
|
|
1154
|
+
method_kind: chunkUCR5HRYM_js.PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY,
|
|
1155
|
+
authority: {
|
|
1156
|
+
authority_kind: chunkUCR5HRYM_js.MOBILE_MONEY_TENDER_AUTHORITY_KIND.SAVED_REFERENCE,
|
|
1157
|
+
stored_instrument_id: form.link_payment_method_id
|
|
1158
|
+
}
|
|
1159
|
+
};
|
|
1160
|
+
let details = form.mobile_money_details;
|
|
1161
|
+
if (!details?.phone_number || !details.provider)
|
|
1162
|
+
throw new chunkUCR5HRYM_js.CimplifyError(
|
|
1163
|
+
chunkUCR5HRYM_js.ErrorCode.INVALID_PAYMENT_METHOD,
|
|
1164
|
+
"Mobile money requires a phone number and network.",
|
|
1165
|
+
false
|
|
1166
|
+
);
|
|
1167
|
+
let network = chunkDFZWHNRG_js.purchaseIntentMobileMoneyNetwork(details.provider);
|
|
1168
|
+
if (!network)
|
|
1169
|
+
throw new chunkUCR5HRYM_js.CimplifyError(
|
|
1170
|
+
chunkUCR5HRYM_js.ErrorCode.INVALID_PAYMENT_METHOD,
|
|
1171
|
+
"That mobile money network is not available for PurchaseIntent checkout.",
|
|
1172
|
+
false
|
|
1173
|
+
);
|
|
1174
|
+
return {
|
|
1175
|
+
method_kind: chunkUCR5HRYM_js.PURCHASE_INTENT_PAYMENT_METHOD.MOBILE_MONEY,
|
|
1176
|
+
authority: {
|
|
1177
|
+
authority_kind: chunkUCR5HRYM_js.MOBILE_MONEY_TENDER_AUTHORITY_KIND.TRANSIENT,
|
|
1178
|
+
phone_number: details.phone_number,
|
|
1179
|
+
network
|
|
1180
|
+
}
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1183
|
+
if (form.payment_method === chunkUCR5HRYM_js.LEGACY_CHECKOUT_PAYMENT_METHOD_ALIAS.CASH || form.payment_method === chunkUCR5HRYM_js.PURCHASE_INTENT_PAYMENT_METHOD.OFFLINE)
|
|
1184
|
+
throw new chunkUCR5HRYM_js.CimplifyError(
|
|
1185
|
+
chunkUCR5HRYM_js.ErrorCode.INVALID_PAYMENT_METHOD,
|
|
1186
|
+
"Offline tender requires an authenticated staff checkout.",
|
|
1187
|
+
false
|
|
1188
|
+
);
|
|
1189
|
+
if (form.payment_method === chunkUCR5HRYM_js.PURCHASE_INTENT_PAYMENT_METHOD.CARD)
|
|
1190
|
+
return {
|
|
1191
|
+
method_kind: chunkUCR5HRYM_js.PURCHASE_INTENT_PAYMENT_METHOD.CARD,
|
|
1192
|
+
stored_instrument_id: form.link_payment_method_id
|
|
1193
|
+
};
|
|
1194
|
+
if (form.payment_method !== chunkUCR5HRYM_js.LEGACY_CHECKOUT_PAYMENT_METHOD_ALIAS.STORE_CREDIT)
|
|
1195
|
+
throw new chunkUCR5HRYM_js.CimplifyError(
|
|
1196
|
+
chunkUCR5HRYM_js.ErrorCode.INVALID_PAYMENT_METHOD,
|
|
1197
|
+
"Checkout payment method is not supported.",
|
|
1198
|
+
false
|
|
1199
|
+
);
|
|
1200
|
+
}
|
|
1201
|
+
function checkoutFormToIntentRequest(form, clientIntentKey) {
|
|
1202
|
+
return {
|
|
1203
|
+
client_intent_key: clientIntentKey,
|
|
1204
|
+
source: { kind: chunkUCR5HRYM_js.PURCHASE_INTENT_SOURCE_KIND.CART, cart_id: form.cart_id },
|
|
1205
|
+
checkout: {
|
|
1206
|
+
customer: form.customer,
|
|
1207
|
+
order_type: form.order_type,
|
|
1208
|
+
address_info: form.address_info,
|
|
1209
|
+
location_id: form.location_id,
|
|
1210
|
+
delivery_rate_id: form.delivery_rate_id,
|
|
1211
|
+
special_instructions: form.special_instructions,
|
|
1212
|
+
link_address_id: form.link_address_id,
|
|
1213
|
+
metadata: form.metadata,
|
|
1214
|
+
pay_currency: form.pay_currency,
|
|
1215
|
+
fx_quote_id: form.fx_quote_id,
|
|
1216
|
+
use_store_credit: form.use_store_credit || form.payment_method === chunkUCR5HRYM_js.LEGACY_CHECKOUT_PAYMENT_METHOD_ALIAS.STORE_CREDIT,
|
|
1217
|
+
voucher_code: form.voucher_code,
|
|
1218
|
+
pay_deposit: form.pay_deposit,
|
|
1219
|
+
tender_preference: tenderPreference(form)
|
|
1220
|
+
}
|
|
1221
|
+
};
|
|
1222
|
+
}
|
|
1223
|
+
function selectCheckoutPaymentOption(terms, form) {
|
|
1224
|
+
let preference = tenderPreference(form);
|
|
1225
|
+
if (preference)
|
|
1226
|
+
return terms.payment_options.filter((option) => option.status === chunkUCR5HRYM_js.PAYMENT_OPTION_STATUS.ELIGIBLE).sort((left, right) => left.rank - right.rank).find((option) => option.method_kind === preference.method_kind);
|
|
1227
|
+
}
|
|
1228
|
+
function checkoutFormToConfirmation(_form, terms, paymentOption, idempotencyKey) {
|
|
1229
|
+
return createPurchaseIntentConfirmation(terms, paymentOption, idempotencyKey);
|
|
1230
|
+
}
|
|
1231
|
+
function committedBase(response) {
|
|
1232
|
+
return {
|
|
1233
|
+
intent_id: response.intent_id,
|
|
1234
|
+
attempt_id: response.attempt_id,
|
|
1235
|
+
order_id: response.order_id,
|
|
1236
|
+
order_number: response.order_number || response.order_id,
|
|
1237
|
+
payment_id: response.payment_id
|
|
1238
|
+
};
|
|
1239
|
+
}
|
|
1240
|
+
function confirmationToCheckoutResult(response) {
|
|
1241
|
+
switch (response.status) {
|
|
1242
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.ORDER_CREATED:
|
|
1243
|
+
return ok({
|
|
1244
|
+
...committedBase(response),
|
|
1245
|
+
payment_status: chunkUCR5HRYM_js.LEGACY_CHECKOUT_PAYMENT_STATUS.SUCCEEDED,
|
|
1246
|
+
requires_authorization: false,
|
|
1247
|
+
next_action: { type: chunkGTJWQAGU_js.CHECKOUT_NEXT_ACTION.NONE }
|
|
1248
|
+
});
|
|
1249
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.COLLECTION_PROCESSING:
|
|
1250
|
+
return ok({
|
|
1251
|
+
...committedBase(response),
|
|
1252
|
+
payment_status: chunkUCR5HRYM_js.LEGACY_CHECKOUT_PAYMENT_STATUS.PROCESSING,
|
|
1253
|
+
requires_authorization: false,
|
|
1254
|
+
next_action: { type: chunkGTJWQAGU_js.CHECKOUT_NEXT_ACTION.POLL }
|
|
1255
|
+
});
|
|
1256
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.PAYMENT_OUTCOME_UNKNOWN:
|
|
1257
|
+
return ok({
|
|
1258
|
+
...committedBase(response),
|
|
1259
|
+
payment_status: chunkUCR5HRYM_js.LEGACY_CHECKOUT_PAYMENT_STATUS.UNKNOWN,
|
|
1260
|
+
requires_authorization: false,
|
|
1261
|
+
next_action: { type: chunkGTJWQAGU_js.CHECKOUT_NEXT_ACTION.POLL }
|
|
1262
|
+
});
|
|
1263
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.PAYMENT_FAILED:
|
|
1264
|
+
return err(
|
|
1265
|
+
new chunkUCR5HRYM_js.CimplifyError(
|
|
1266
|
+
chunkUCR5HRYM_js.PURCHASE_INTENT_ERROR_CODE.PAYMENT_FAILED,
|
|
1267
|
+
"Payment failed. The order remains recorded, but collection did not succeed.",
|
|
1268
|
+
true
|
|
1269
|
+
)
|
|
1270
|
+
);
|
|
1271
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.REDIRECT_REQUIRED:
|
|
1272
|
+
return ok({
|
|
1273
|
+
...committedBase(response),
|
|
1274
|
+
payment_status: chunkUCR5HRYM_js.LEGACY_CHECKOUT_PAYMENT_STATUS.REQUIRES_ACTION,
|
|
1275
|
+
requires_authorization: false,
|
|
1276
|
+
authorization_url: response.authorization_url,
|
|
1277
|
+
next_action: {
|
|
1278
|
+
type: chunkGTJWQAGU_js.CHECKOUT_NEXT_ACTION.REDIRECT,
|
|
1279
|
+
authorization_url: response.authorization_url
|
|
1280
|
+
}
|
|
1281
|
+
});
|
|
1282
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.CARD_POPUP_REQUIRED:
|
|
1283
|
+
return ok({
|
|
1284
|
+
...committedBase(response),
|
|
1285
|
+
payment_status: chunkUCR5HRYM_js.LEGACY_CHECKOUT_PAYMENT_STATUS.REQUIRES_ACTION,
|
|
1286
|
+
requires_authorization: false,
|
|
1287
|
+
provider: response.provider,
|
|
1288
|
+
client_secret: response.client_secret,
|
|
1289
|
+
public_key: response.public_key,
|
|
1290
|
+
next_action: {
|
|
1291
|
+
type: chunkGTJWQAGU_js.CHECKOUT_NEXT_ACTION.CARD_POPUP,
|
|
1292
|
+
provider: response.provider,
|
|
1293
|
+
client_secret: response.client_secret,
|
|
1294
|
+
public_key: response.public_key,
|
|
1295
|
+
provider_account_id: response.provider_account_id ?? void 0
|
|
1296
|
+
}
|
|
1297
|
+
});
|
|
1298
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.AUTHORIZATION_REQUIRED:
|
|
1299
|
+
return ok({
|
|
1300
|
+
...committedBase(response),
|
|
1301
|
+
payment_status: chunkUCR5HRYM_js.LEGACY_CHECKOUT_PAYMENT_STATUS.REQUIRES_ACTION,
|
|
1302
|
+
requires_authorization: true,
|
|
1303
|
+
authorization_type: response.authorization_type,
|
|
1304
|
+
display_text: response.display_text,
|
|
1305
|
+
next_action: {
|
|
1306
|
+
type: chunkGTJWQAGU_js.CHECKOUT_NEXT_ACTION.AUTHORIZATION,
|
|
1307
|
+
authorization_type: response.authorization_type,
|
|
1308
|
+
display_text: response.display_text
|
|
1309
|
+
}
|
|
1310
|
+
});
|
|
1311
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.TERMS_CHANGED:
|
|
1312
|
+
return err(
|
|
1313
|
+
new chunkUCR5HRYM_js.CimplifyError(
|
|
1314
|
+
chunkUCR5HRYM_js.PURCHASE_INTENT_ERROR_CODE.TERMS_CHANGED,
|
|
1315
|
+
"Checkout terms changed. Review the replacement terms before confirming again.",
|
|
1316
|
+
true
|
|
1317
|
+
)
|
|
1318
|
+
);
|
|
1319
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.SELECTION_UNAVAILABLE:
|
|
1320
|
+
return err(
|
|
1321
|
+
new chunkUCR5HRYM_js.CimplifyError(
|
|
1322
|
+
chunkUCR5HRYM_js.PURCHASE_INTENT_ERROR_CODE.SELECTION_UNAVAILABLE,
|
|
1323
|
+
"One or more checkout selections are no longer available.",
|
|
1324
|
+
true
|
|
1325
|
+
)
|
|
1326
|
+
);
|
|
1327
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.OFFER_ENDED:
|
|
1328
|
+
return err(
|
|
1329
|
+
new chunkUCR5HRYM_js.CimplifyError(
|
|
1330
|
+
chunkUCR5HRYM_js.PURCHASE_INTENT_ERROR_CODE.OFFER_ENDED,
|
|
1331
|
+
"This offer has ended.",
|
|
1332
|
+
false
|
|
1333
|
+
)
|
|
1334
|
+
);
|
|
1335
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.SOURCE_UNAVAILABLE:
|
|
1336
|
+
return err(
|
|
1337
|
+
new chunkUCR5HRYM_js.CimplifyError(
|
|
1338
|
+
chunkUCR5HRYM_js.PURCHASE_INTENT_ERROR_CODE.SOURCE_UNAVAILABLE,
|
|
1339
|
+
"This purchase source is unavailable.",
|
|
1340
|
+
false
|
|
1341
|
+
)
|
|
1342
|
+
);
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
// src/checkout.ts
|
|
1347
|
+
function checkoutActionAuthority(response) {
|
|
1348
|
+
if (response.status !== chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.CARD_POPUP_REQUIRED && response.status !== chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.AUTHORIZATION_REQUIRED)
|
|
1349
|
+
return null;
|
|
1350
|
+
let paymentId = response.payment_id?.trim();
|
|
1351
|
+
return paymentId ? {
|
|
1352
|
+
intentId: response.intent_id,
|
|
1353
|
+
attemptId: response.attempt_id,
|
|
1354
|
+
paymentId
|
|
1355
|
+
} : null;
|
|
1356
|
+
}
|
|
1357
|
+
function isAmbiguousCheckoutError(error) {
|
|
1358
|
+
return error.code === chunkUCR5HRYM_js.ErrorCode.NETWORK_ERROR || error.code === chunkUCR5HRYM_js.ErrorCode.TIMEOUT;
|
|
1359
|
+
}
|
|
1360
|
+
function authorizationKind(value) {
|
|
1361
|
+
if (value && typeof value == "object" && chunkGTJWQAGU_js.AUTHORIZATION_TYPE.ADDRESS in value)
|
|
1362
|
+
return chunkGTJWQAGU_js.AUTHORIZATION_TYPE.ADDRESS;
|
|
1363
|
+
if (value === chunkGTJWQAGU_js.AUTHORIZATION_TYPE.OTP || value === chunkGTJWQAGU_js.AUTHORIZATION_TYPE.PIN || value === chunkGTJWQAGU_js.AUTHORIZATION_TYPE.PHONE || value === chunkGTJWQAGU_js.AUTHORIZATION_TYPE.BIRTHDAY)
|
|
1364
|
+
return value;
|
|
1365
|
+
}
|
|
1366
|
+
function normalizeAuthorizationSubmission(expected, submission) {
|
|
1367
|
+
if (submission.type !== expected) throw new Error(`Expected ${expected} authorization details.`);
|
|
1368
|
+
if (submission.type === chunkGTJWQAGU_js.AUTHORIZATION_TYPE.ADDRESS) {
|
|
1369
|
+
let address = submission.address.trim(), city = submission.city.trim(), state = submission.state.trim(), zipCode = submission.zip_code.trim();
|
|
1370
|
+
if (!address || !city || !state || !zipCode)
|
|
1371
|
+
throw new Error("Complete all authorization address fields.");
|
|
1372
|
+
return { type: chunkGTJWQAGU_js.AUTHORIZATION_TYPE.ADDRESS, address, city, state, zip_code: zipCode };
|
|
1373
|
+
}
|
|
1374
|
+
let value = submission.value.trim();
|
|
1375
|
+
if (!value) throw new Error("Authorization value is required.");
|
|
1376
|
+
return { type: submission.type, value };
|
|
1377
|
+
}
|
|
1378
|
+
var DECIMAL_WIRE_VALUE = /^([+-]?)(\d+)(?:\.(\d+))?(?:[eE][+-]?\d+)?$/;
|
|
1379
|
+
function decimalSign(value) {
|
|
1380
|
+
if (typeof value == "number")
|
|
1381
|
+
return Number.isFinite(value) ? Object.is(value, 0) || Object.is(value, -0) ? 0 : value > 0 ? 1 : -1 : null;
|
|
1382
|
+
let match = DECIMAL_WIRE_VALUE.exec(value.trim());
|
|
1383
|
+
return match ? [...match[2], ...match[3] ?? ""].some((digit) => digit !== "0") ? match[1] === "-" ? -1 : 1 : 0 : null;
|
|
1384
|
+
}
|
|
1385
|
+
function toTerminalFailure(code, message, recoverable) {
|
|
1386
|
+
return {
|
|
1387
|
+
success: false,
|
|
1388
|
+
error: {
|
|
1389
|
+
code,
|
|
1390
|
+
message,
|
|
1391
|
+
recoverable
|
|
1392
|
+
}
|
|
1393
|
+
};
|
|
1394
|
+
}
|
|
1395
|
+
function isValidCustomerName(name) {
|
|
1396
|
+
let trimmed = (name ?? "").trim();
|
|
1397
|
+
return trimmed.length >= 2 && /\p{L}/u.test(trimmed);
|
|
1398
|
+
}
|
|
1399
|
+
function isOfflinePaymentMethod(method) {
|
|
1400
|
+
return method === chunkUCR5HRYM_js.LEGACY_CHECKOUT_PAYMENT_METHOD_ALIAS.CASH || method === chunkUCR5HRYM_js.PURCHASE_INTENT_PAYMENT_METHOD.OFFLINE;
|
|
1401
|
+
}
|
|
1402
|
+
function notifyCheckoutStatus(observer, status, context = {}) {
|
|
1403
|
+
try {
|
|
1404
|
+
observer?.(status, context);
|
|
1405
|
+
} catch {
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
function notifyAuthorizationUi(observer, open) {
|
|
1409
|
+
try {
|
|
1410
|
+
observer?.(open);
|
|
1411
|
+
} catch {
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
var MAX_STOREFRONT_COLLECTION_OPTIONS = 32, CHECKOUT_INTENT_SCOPE_PREFIX = "checkout:", CHECKOUT_CONFIRMATION_SCOPE_PREFIX = "checkout-confirm:", CHECKOUT_INTENT_RECOVERY_FINGERPRINT = "cart-intent-v1", ABORT_ERROR_NAME = "AbortError", AUTHORIZATION_POPUP_NAME = "cimplify-auth", AUTHORIZATION_POPUP_FEATURES = "width=520,height=760", ORDER_TOKEN_QUERY_PARAMETER = "token", CHECKOUT_API_ROUTE = {
|
|
1415
|
+
COLLECTION_OPTIONS: "/api/v1/payments/collection-options",
|
|
1416
|
+
paymentStatus: (orderId) => `/api/v1/orders/${orderId}/payment-status`,
|
|
1417
|
+
updateCustomer: (orderId) => `/api/v1/orders/${orderId}/customer`,
|
|
1418
|
+
verifyPayment: (orderId) => `/api/v1/orders/${orderId}/verify-payment`
|
|
1419
|
+
}, CHECKOUT_STATUS_BY_PURCHASE_INTENT_RESOLVE_STATUS = {
|
|
1420
|
+
[chunkUCR5HRYM_js.PURCHASE_INTENT_RESOLVE_STATUS.CONFIRMING]: chunkGTJWQAGU_js.CHECKOUT_STATUS.PROCESSING,
|
|
1421
|
+
[chunkUCR5HRYM_js.PURCHASE_INTENT_RESOLVE_STATUS.POLLING]: chunkGTJWQAGU_js.CHECKOUT_STATUS.POLLING,
|
|
1422
|
+
[chunkUCR5HRYM_js.PURCHASE_INTENT_RESOLVE_STATUS.RECONNECTING]: chunkGTJWQAGU_js.CHECKOUT_STATUS.POLLING,
|
|
1423
|
+
[chunkUCR5HRYM_js.PURCHASE_INTENT_RESOLVE_STATUS.AWAITING_ACTION]: chunkGTJWQAGU_js.CHECKOUT_STATUS.AWAITING_AUTHORIZATION,
|
|
1424
|
+
[chunkUCR5HRYM_js.PURCHASE_INTENT_RESOLVE_STATUS.REVIEWING_TERMS]: chunkGTJWQAGU_js.CHECKOUT_STATUS.REVIEWING_TERMS,
|
|
1425
|
+
[chunkUCR5HRYM_js.PURCHASE_INTENT_RESOLVE_STATUS.COMPLETED]: chunkGTJWQAGU_js.CHECKOUT_STATUS.FINALIZING,
|
|
1426
|
+
[chunkUCR5HRYM_js.PURCHASE_INTENT_RESOLVE_STATUS.FAILED]: chunkGTJWQAGU_js.CHECKOUT_STATUS.FAILED,
|
|
1427
|
+
[chunkUCR5HRYM_js.PURCHASE_INTENT_RESOLVE_STATUS.OUTCOME_UNKNOWN]: chunkGTJWQAGU_js.CHECKOUT_STATUS.RECOVERING
|
|
1428
|
+
};
|
|
1429
|
+
function normalizeCollectionOptions(value, expectedCurrency) {
|
|
1430
|
+
if (!value || typeof value != "object") return null;
|
|
1431
|
+
let response = value;
|
|
1432
|
+
if (response.presentment_currency !== expectedCurrency || !Array.isArray(response.options) || response.options.length > (32)) return null;
|
|
1433
|
+
let options = [], seen = /* @__PURE__ */ new Set();
|
|
1434
|
+
for (let candidate of response.options) {
|
|
1435
|
+
if (!candidate || typeof candidate != "object") continue;
|
|
1436
|
+
let option = candidate;
|
|
1437
|
+
if (option.method === chunkGTJWQAGU_js.PAYMENT_METHOD.CARD && option.network == null) {
|
|
1438
|
+
seen.has(chunkGTJWQAGU_js.PAYMENT_METHOD.CARD) || (seen.add(chunkGTJWQAGU_js.PAYMENT_METHOD.CARD), options.push({ method: chunkGTJWQAGU_js.PAYMENT_METHOD.CARD, network: null }));
|
|
1439
|
+
continue;
|
|
1440
|
+
}
|
|
1441
|
+
if (option.method !== chunkGTJWQAGU_js.PAYMENT_METHOD.MOBILE_MONEY || typeof option.network != "string" || !option.network.trim())
|
|
1442
|
+
continue;
|
|
1443
|
+
let network = chunkDFZWHNRG_js.purchaseIntentMobileMoneyNetwork(option.network);
|
|
1444
|
+
if (!network) continue;
|
|
1445
|
+
let key = `${chunkGTJWQAGU_js.PAYMENT_METHOD.MOBILE_MONEY}:${network}`;
|
|
1446
|
+
seen.has(key) || (seen.add(key), options.push({ method: chunkGTJWQAGU_js.PAYMENT_METHOD.MOBILE_MONEY, network }));
|
|
1447
|
+
}
|
|
1448
|
+
return { presentment_currency: expectedCurrency, options };
|
|
1449
|
+
}
|
|
1450
|
+
var CheckoutService = class {
|
|
1451
|
+
constructor(client) {
|
|
1452
|
+
this.client = client;
|
|
1453
|
+
/** Raw checkout material is component-lifetime only, never browser storage. */
|
|
1454
|
+
this.intentCommands = /* @__PURE__ */ new Map();
|
|
1455
|
+
/** Opaque owner/attempt authority for deprecated action submission. */
|
|
1456
|
+
this.actionAuthorities = /* @__PURE__ */ new Map();
|
|
1457
|
+
}
|
|
1458
|
+
validateCheckoutData(data) {
|
|
1459
|
+
return isOfflinePaymentMethod(data.payment_method) ? new chunkUCR5HRYM_js.CimplifyError(
|
|
1460
|
+
chunkUCR5HRYM_js.ErrorCode.INVALID_PAYMENT_METHOD,
|
|
1461
|
+
"Offline payment isn't available for online checkout. Please pay by card or mobile money.",
|
|
1462
|
+
false
|
|
1463
|
+
) : isValidCustomerName(data.customer?.name) ? null : new chunkUCR5HRYM_js.CimplifyError(
|
|
1464
|
+
chunkUCR5HRYM_js.ErrorCode.INVALID_CUSTOMER_NAME,
|
|
1465
|
+
"Enter your name, not a phone number.",
|
|
1466
|
+
false
|
|
1467
|
+
);
|
|
1468
|
+
}
|
|
1469
|
+
orderTokenParam(orderId) {
|
|
1470
|
+
let token = this.client.getOrderToken(orderId);
|
|
1471
|
+
return token ? `?${ORDER_TOKEN_QUERY_PARAMETER}=${encodeURIComponent(token)}` : "";
|
|
1472
|
+
}
|
|
1473
|
+
/** Available storefront collection methods for one presentment currency. */
|
|
1474
|
+
async collectionOptions(currency) {
|
|
1475
|
+
let normalized = currency.trim().toUpperCase();
|
|
1476
|
+
if (!chunkUCR5HRYM_js.isSupportedCurrency(normalized))
|
|
1477
|
+
return err(
|
|
1478
|
+
new chunkUCR5HRYM_js.CimplifyError(
|
|
1479
|
+
chunkUCR5HRYM_js.ErrorCode.UNSUPPORTED_CURRENCY,
|
|
1480
|
+
"No online payment method is available for this currency.",
|
|
1481
|
+
false
|
|
1482
|
+
)
|
|
1483
|
+
);
|
|
1484
|
+
let response = await safe(
|
|
1485
|
+
this.client.get(
|
|
1486
|
+
`${CHECKOUT_API_ROUTE.COLLECTION_OPTIONS}?currency=${encodeURIComponent(normalized)}`
|
|
1487
|
+
)
|
|
1488
|
+
);
|
|
1489
|
+
if (!response.ok) return response;
|
|
1490
|
+
let options = normalizeCollectionOptions(response.value, normalized);
|
|
1491
|
+
return options ? ok(options) : err(
|
|
1492
|
+
new chunkUCR5HRYM_js.CimplifyError(
|
|
1493
|
+
chunkUCR5HRYM_js.ErrorCode.PAYMENT_CAPABILITY_MISMATCH,
|
|
1494
|
+
"Payment methods could not be verified for this currency.",
|
|
1495
|
+
false
|
|
1496
|
+
)
|
|
1497
|
+
);
|
|
1498
|
+
}
|
|
1499
|
+
/**
|
|
1500
|
+
* Run provider-owned UI for a backend `card_popup` action. A submitted
|
|
1501
|
+
* outcome is not proof of payment; callers must poll/verify with Cimplify.
|
|
1502
|
+
*/
|
|
1503
|
+
authorizeCardPopup(action, options) {
|
|
1504
|
+
return this.client.authorizationAdapters.authorize(action, options);
|
|
1505
|
+
}
|
|
1506
|
+
async startIntentCheckout(data, options) {
|
|
1507
|
+
let invalid = this.validateCheckoutData(data);
|
|
1508
|
+
if (invalid) return err(invalid);
|
|
1509
|
+
let intentScope = `${CHECKOUT_INTENT_SCOPE_PREFIX}${data.cart_id}`, inMemoryCommand = JSON.stringify(data), previousCommand = this.intentCommands.get(intentScope);
|
|
1510
|
+
previousCommand !== void 0 && previousCommand !== inMemoryCommand && clearIntentIdempotencyKey(intentScope), this.intentCommands.set(intentScope, inMemoryCommand);
|
|
1511
|
+
let clientIntentKey = data.idempotency_key || intentIdempotencyKey(intentScope, CHECKOUT_INTENT_RECOVERY_FINGERPRINT), checkoutData = { ...data, idempotency_key: clientIntentKey }, mintRequest;
|
|
1512
|
+
try {
|
|
1513
|
+
mintRequest = checkoutFormToIntentRequest(checkoutData, clientIntentKey);
|
|
1514
|
+
} catch (error) {
|
|
1515
|
+
return clearIntentIdempotencyKey(intentScope), this.intentCommands.delete(intentScope), err(
|
|
1516
|
+
error instanceof chunkUCR5HRYM_js.CimplifyError ? error : new chunkUCR5HRYM_js.CimplifyError(
|
|
1517
|
+
chunkUCR5HRYM_js.ErrorCode.CHECKOUT_VALIDATION_FAILED,
|
|
1518
|
+
"Checkout details are invalid.",
|
|
1519
|
+
false
|
|
1520
|
+
)
|
|
1521
|
+
);
|
|
1522
|
+
}
|
|
1523
|
+
let minted = await this.client.purchaseIntents.mint(mintRequest, options);
|
|
1524
|
+
if (!minted.ok)
|
|
1525
|
+
return isAmbiguousCheckoutError(minted.error) || (clearIntentIdempotencyKey(intentScope), this.intentCommands.delete(intentScope)), minted;
|
|
1526
|
+
let terms = minted.value.current_terms;
|
|
1527
|
+
if (!terms)
|
|
1528
|
+
return clearIntentIdempotencyKey(intentScope), this.intentCommands.delete(intentScope), err(
|
|
1529
|
+
new chunkUCR5HRYM_js.CimplifyError(
|
|
1530
|
+
chunkUCR5HRYM_js.ErrorCode.CHECKOUT_TERMS_UNAVAILABLE,
|
|
1531
|
+
"Checkout terms are not available for this purchase intent.",
|
|
1532
|
+
true
|
|
1533
|
+
)
|
|
1534
|
+
);
|
|
1535
|
+
let paymentOption;
|
|
1536
|
+
try {
|
|
1537
|
+
paymentOption = selectCheckoutPaymentOption(terms, checkoutData);
|
|
1538
|
+
} catch (error) {
|
|
1539
|
+
return err(
|
|
1540
|
+
error instanceof chunkUCR5HRYM_js.CimplifyError ? error : new chunkUCR5HRYM_js.CimplifyError(
|
|
1541
|
+
chunkUCR5HRYM_js.ErrorCode.INVALID_PAYMENT_METHOD,
|
|
1542
|
+
"Payment details are invalid.",
|
|
1543
|
+
false
|
|
1544
|
+
)
|
|
1545
|
+
);
|
|
1546
|
+
}
|
|
1547
|
+
if (!paymentOption && purchaseIntentRequiresPaymentOption(terms))
|
|
1548
|
+
return err(
|
|
1549
|
+
new chunkUCR5HRYM_js.CimplifyError(
|
|
1550
|
+
chunkUCR5HRYM_js.ErrorCode.PAYMENT_CAPABILITY_MISMATCH,
|
|
1551
|
+
"The selected payment method is not eligible for these checkout terms.",
|
|
1552
|
+
true
|
|
1553
|
+
)
|
|
1554
|
+
);
|
|
1555
|
+
let confirmationScope = `${CHECKOUT_CONFIRMATION_SCOPE_PREFIX}${minted.value.id}`, confirmationFingerprint = JSON.stringify([
|
|
1556
|
+
terms.intent_revision,
|
|
1557
|
+
terms.terms_version,
|
|
1558
|
+
terms.terms_digest,
|
|
1559
|
+
paymentOption?.id ?? null,
|
|
1560
|
+
terms.money.due_now,
|
|
1561
|
+
paymentOption?.customer_debit_amount ?? terms.money.rail_amount,
|
|
1562
|
+
terms.money.currency
|
|
1563
|
+
]), confirmationKey = intentIdempotencyKey(
|
|
1564
|
+
confirmationScope,
|
|
1565
|
+
confirmationFingerprint
|
|
1566
|
+
), confirmation = checkoutFormToConfirmation(
|
|
1567
|
+
checkoutData,
|
|
1568
|
+
terms,
|
|
1569
|
+
paymentOption,
|
|
1570
|
+
confirmationKey
|
|
1571
|
+
), confirmed = await this.client.purchaseIntents.confirm(
|
|
1572
|
+
minted.value.id,
|
|
1573
|
+
confirmation,
|
|
1574
|
+
options
|
|
1575
|
+
);
|
|
1576
|
+
return confirmed.ok ? ok({
|
|
1577
|
+
intentId: minted.value.id,
|
|
1578
|
+
intentScope,
|
|
1579
|
+
confirmationScope,
|
|
1580
|
+
confirmation,
|
|
1581
|
+
initialResponse: confirmed.value,
|
|
1582
|
+
terms
|
|
1583
|
+
}) : (isAmbiguousCheckoutError(confirmed.error) || clearIntentIdempotencyKey(confirmationScope), confirmed);
|
|
1584
|
+
}
|
|
1585
|
+
/** @deprecated Use `client.purchaseIntents.mint()` then `confirm()`. */
|
|
1586
|
+
async process(data, options) {
|
|
1587
|
+
let started = await this.startIntentCheckout(data, options);
|
|
1588
|
+
if (!started.ok) return started;
|
|
1589
|
+
this.reconcileActionAuthority(started.value.initialResponse);
|
|
1590
|
+
let result = confirmationToCheckoutResult(started.value.initialResponse);
|
|
1591
|
+
return (started.value.initialResponse.status === chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.ORDER_CREATED || started.value.initialResponse.status === chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.PAYMENT_FAILED) && (clearIntentIdempotencyKey(started.value.intentScope), clearIntentIdempotencyKey(started.value.confirmationScope), this.intentCommands.delete(started.value.intentScope)), result;
|
|
1592
|
+
}
|
|
1593
|
+
async initializePayment(_orderId, _method) {
|
|
1594
|
+
return err(
|
|
1595
|
+
new chunkUCR5HRYM_js.CimplifyError(
|
|
1596
|
+
chunkUCR5HRYM_js.ErrorCode.NOT_IMPLEMENTED,
|
|
1597
|
+
"initializePayment is not available in REST mode.",
|
|
1598
|
+
false
|
|
1599
|
+
)
|
|
1600
|
+
);
|
|
1601
|
+
}
|
|
1602
|
+
/**
|
|
1603
|
+
* @deprecated Use `client.purchaseIntents.submitAction()`. This adapter works
|
|
1604
|
+
* only while this CheckoutService instance retains the opaque authority
|
|
1605
|
+
* returned by its own `process()` call; it never falls back to a payment-id
|
|
1606
|
+
* mutation.
|
|
1607
|
+
*/
|
|
1608
|
+
async submitAuthorization(input, options) {
|
|
1609
|
+
let paymentId = input.payment_id.trim(), authority = this.actionAuthorities.get(paymentId);
|
|
1610
|
+
if (!authority)
|
|
1611
|
+
return err(
|
|
1612
|
+
new chunkUCR5HRYM_js.CimplifyError(
|
|
1613
|
+
chunkUCR5HRYM_js.ErrorCode.CHECKOUT_AUTHORITY_REQUIRED,
|
|
1614
|
+
"The purchase-intent action authority is unavailable. Restart checkout before submitting authorization.",
|
|
1615
|
+
false
|
|
1616
|
+
)
|
|
1617
|
+
);
|
|
1618
|
+
let submitted = await this.client.purchaseIntents.submitAction(
|
|
1619
|
+
authority.intentId,
|
|
1620
|
+
authority.attemptId,
|
|
1621
|
+
{ authorization: input.authorization },
|
|
1622
|
+
{
|
|
1623
|
+
signal: options?.signal,
|
|
1624
|
+
timeoutMs: options?.timeoutMs
|
|
1625
|
+
}
|
|
1626
|
+
);
|
|
1627
|
+
return submitted.ok ? (this.reconcileActionAuthority(submitted.value, paymentId), confirmationToCheckoutResult(submitted.value)) : submitted;
|
|
1628
|
+
}
|
|
1629
|
+
reconcileActionAuthority(response, previousPaymentId) {
|
|
1630
|
+
previousPaymentId && this.actionAuthorities.delete(previousPaymentId), "payment_id" in response && typeof response.payment_id == "string" && response.payment_id.trim() && this.actionAuthorities.delete(response.payment_id.trim());
|
|
1631
|
+
let authority = checkoutActionAuthority(response);
|
|
1632
|
+
authority && this.actionAuthorities.set(authority.paymentId, authority);
|
|
1633
|
+
}
|
|
1634
|
+
async pollPaymentStatus(orderId, options) {
|
|
1635
|
+
let encodedId = encodeURIComponent(orderId), tokenParam = this.orderTokenParam(orderId);
|
|
1636
|
+
return safe(
|
|
1637
|
+
this.client.get(
|
|
1638
|
+
`${CHECKOUT_API_ROUTE.paymentStatus(encodedId)}${tokenParam}`,
|
|
1639
|
+
options
|
|
1640
|
+
)
|
|
1641
|
+
);
|
|
1642
|
+
}
|
|
1643
|
+
async updateOrderCustomer(orderId, customer) {
|
|
1644
|
+
let encodedId = encodeURIComponent(orderId), tokenParam = this.orderTokenParam(orderId);
|
|
1645
|
+
return safe(
|
|
1646
|
+
this.client.post(`${CHECKOUT_API_ROUTE.updateCustomer(encodedId)}${tokenParam}`, customer)
|
|
1647
|
+
);
|
|
1648
|
+
}
|
|
1649
|
+
async verifyPayment(orderId) {
|
|
1650
|
+
let encodedId = encodeURIComponent(orderId), tokenParam = this.orderTokenParam(orderId);
|
|
1651
|
+
return safe(
|
|
1652
|
+
this.client.post(`${CHECKOUT_API_ROUTE.verifyPayment(encodedId)}${tokenParam}`)
|
|
1653
|
+
);
|
|
1654
|
+
}
|
|
1655
|
+
async maybeEnrollResolvedOrder(orderId, data) {
|
|
1656
|
+
if (data.enroll_in_link !== true) return false;
|
|
1657
|
+
let business = await safe(this.client.resolveBusinessId());
|
|
1658
|
+
if (!business.ok) return false;
|
|
1659
|
+
let address = data.address_info.street_address ? {
|
|
1660
|
+
label: "Default",
|
|
1661
|
+
street_address: data.address_info.street_address,
|
|
1662
|
+
apartment: data.address_info.apartment,
|
|
1663
|
+
city: data.address_info.city ?? "",
|
|
1664
|
+
region: data.address_info.region ?? "",
|
|
1665
|
+
postal_code: data.address_info.postal_code,
|
|
1666
|
+
country: data.address_info.country,
|
|
1667
|
+
delivery_instructions: data.address_info.delivery_instructions,
|
|
1668
|
+
phone_for_delivery: data.address_info.phone_for_delivery,
|
|
1669
|
+
latitude: data.address_info.latitude,
|
|
1670
|
+
longitude: data.address_info.longitude
|
|
1671
|
+
} : void 0;
|
|
1672
|
+
try {
|
|
1673
|
+
let saved = await this.client.link.saveDetails({
|
|
1674
|
+
order_id: orderId,
|
|
1675
|
+
business_id: business.value,
|
|
1676
|
+
address,
|
|
1677
|
+
consent: {
|
|
1678
|
+
copy_version: chunkGTJWQAGU_js.SAVE_DETAILS_CONSENT.COPY_VERSION,
|
|
1679
|
+
channel: chunkGTJWQAGU_js.SAVE_DETAILS_CONSENT.CHANNEL.LINK_ELEMENT
|
|
1680
|
+
}
|
|
1681
|
+
});
|
|
1682
|
+
return saved.ok && saved.value.saved;
|
|
1683
|
+
} catch {
|
|
1684
|
+
return false;
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
/** @deprecated Use `client.purchaseIntents.resolve()`. */
|
|
1688
|
+
async processAndResolve(data) {
|
|
1689
|
+
if (notifyCheckoutStatus(data.on_status_change, chunkGTJWQAGU_js.CHECKOUT_STATUS.PREPARING), !data.cart_id)
|
|
1690
|
+
return ok(
|
|
1691
|
+
toTerminalFailure(
|
|
1692
|
+
chunkUCR5HRYM_js.ErrorCode.INVALID_CART,
|
|
1693
|
+
"A valid cart is required before checkout can start.",
|
|
1694
|
+
false
|
|
1695
|
+
)
|
|
1696
|
+
);
|
|
1697
|
+
let cartResult = await this.client.cart.get();
|
|
1698
|
+
if (!cartResult.ok || !cartResult.value?.id)
|
|
1699
|
+
return ok(
|
|
1700
|
+
toTerminalFailure(
|
|
1701
|
+
chunkUCR5HRYM_js.ErrorCode.INVALID_CART,
|
|
1702
|
+
"Unable to load cart for checkout.",
|
|
1703
|
+
false
|
|
1704
|
+
)
|
|
1705
|
+
);
|
|
1706
|
+
let cart = cartResult.value;
|
|
1707
|
+
if (cart.id !== data.cart_id || cart.items.length === 0)
|
|
1708
|
+
return ok(
|
|
1709
|
+
toTerminalFailure(
|
|
1710
|
+
chunkUCR5HRYM_js.ErrorCode.INVALID_CART,
|
|
1711
|
+
"Cart is empty or no longer valid. Please refresh and try again.",
|
|
1712
|
+
false
|
|
1713
|
+
)
|
|
1714
|
+
);
|
|
1715
|
+
let checkoutData = {
|
|
1716
|
+
cart_id: data.cart_id,
|
|
1717
|
+
location_id: data.location_id,
|
|
1718
|
+
customer: data.customer,
|
|
1719
|
+
order_type: data.order_type,
|
|
1720
|
+
address_info: data.address_info,
|
|
1721
|
+
delivery_rate_id: data.delivery_rate_id,
|
|
1722
|
+
payment_method: data.payment_method,
|
|
1723
|
+
mobile_money_details: data.mobile_money_details,
|
|
1724
|
+
special_instructions: data.special_instructions,
|
|
1725
|
+
link_address_id: data.link_address_id,
|
|
1726
|
+
link_payment_method_id: data.link_payment_method_id,
|
|
1727
|
+
idempotency_key: data.idempotency_key,
|
|
1728
|
+
metadata: data.metadata,
|
|
1729
|
+
pay_currency: data.pay_currency,
|
|
1730
|
+
fx_quote_id: data.fx_quote_id,
|
|
1731
|
+
use_store_credit: data.use_store_credit,
|
|
1732
|
+
voucher_code: data.voucher_code,
|
|
1733
|
+
pay_deposit: data.pay_deposit
|
|
1734
|
+
}, rawBaseCurrency = typeof cart.pricing.currency == "string" ? cart.pricing.currency.trim().toUpperCase() : "";
|
|
1735
|
+
if (!chunkUCR5HRYM_js.isSupportedCurrency(rawBaseCurrency))
|
|
1736
|
+
return ok(
|
|
1737
|
+
toTerminalFailure(
|
|
1738
|
+
chunkUCR5HRYM_js.ErrorCode.UNSUPPORTED_CURRENCY,
|
|
1739
|
+
"Cart currency is missing or unsupported. Refresh the cart before checkout.",
|
|
1740
|
+
false
|
|
1741
|
+
)
|
|
1742
|
+
);
|
|
1743
|
+
let baseCurrency = rawBaseCurrency, payCurrency = data.pay_currency?.trim().toUpperCase();
|
|
1744
|
+
if (payCurrency && !chunkUCR5HRYM_js.isSupportedCurrency(payCurrency))
|
|
1745
|
+
return ok(
|
|
1746
|
+
toTerminalFailure(
|
|
1747
|
+
chunkUCR5HRYM_js.ErrorCode.UNSUPPORTED_CURRENCY,
|
|
1748
|
+
"Payment currency is unsupported for checkout.",
|
|
1749
|
+
false
|
|
1750
|
+
)
|
|
1751
|
+
);
|
|
1752
|
+
let payCurrencyCode = payCurrency && chunkUCR5HRYM_js.isSupportedCurrency(payCurrency) ? payCurrency : void 0, cartTotalSign = decimalSign(cart.pricing.total_price);
|
|
1753
|
+
if (cartTotalSign === null || cartTotalSign < 0)
|
|
1754
|
+
return ok(
|
|
1755
|
+
toTerminalFailure(
|
|
1756
|
+
chunkUCR5HRYM_js.ErrorCode.CHECKOUT_VALIDATION_FAILED,
|
|
1757
|
+
"Cart total is not a valid non-negative decimal amount.",
|
|
1758
|
+
false
|
|
1759
|
+
)
|
|
1760
|
+
);
|
|
1761
|
+
if (payCurrencyCode && payCurrencyCode !== baseCurrency && !checkoutData.fx_quote_id && cartTotalSign > 0) {
|
|
1762
|
+
let fxQuoteResult = await this.client.fx.lockQuote({
|
|
1763
|
+
from: baseCurrency,
|
|
1764
|
+
to: payCurrencyCode,
|
|
1765
|
+
amount: cart.pricing.total_price
|
|
1766
|
+
});
|
|
1767
|
+
if (!fxQuoteResult.ok)
|
|
1768
|
+
return ok(
|
|
1769
|
+
toTerminalFailure(
|
|
1770
|
+
chunkUCR5HRYM_js.ErrorCode.FX_QUOTE_FAILED,
|
|
1771
|
+
fxQuoteResult.error.message || "Unable to lock FX quote for checkout.",
|
|
1772
|
+
true
|
|
1773
|
+
)
|
|
1774
|
+
);
|
|
1775
|
+
checkoutData.pay_currency = payCurrencyCode, checkoutData.fx_quote_id = fxQuoteResult.value.id;
|
|
1776
|
+
}
|
|
1777
|
+
notifyCheckoutStatus(data.on_status_change, chunkGTJWQAGU_js.CHECKOUT_STATUS.PROCESSING);
|
|
1778
|
+
let started = await this.startIntentCheckout(checkoutData, { signal: data.signal });
|
|
1779
|
+
if (!started.ok)
|
|
1780
|
+
return ok(
|
|
1781
|
+
toTerminalFailure(
|
|
1782
|
+
started.error.code || chunkUCR5HRYM_js.ErrorCode.CHECKOUT_FAILED,
|
|
1783
|
+
started.error.message || "Unable to process checkout.",
|
|
1784
|
+
started.error.retryable ?? true
|
|
1785
|
+
)
|
|
1786
|
+
);
|
|
1787
|
+
let actionFailure;
|
|
1788
|
+
try {
|
|
1789
|
+
let resolved = await this.client.purchaseIntents.resolve(started.value.intentId, {
|
|
1790
|
+
confirmation: started.value.confirmation,
|
|
1791
|
+
initialResponse: started.value.initialResponse,
|
|
1792
|
+
pollIntervalMs: data.poll_interval_ms,
|
|
1793
|
+
maxPollAttempts: data.max_poll_attempts,
|
|
1794
|
+
signal: data.signal,
|
|
1795
|
+
onStatusChange: (status, response) => {
|
|
1796
|
+
let context = {};
|
|
1797
|
+
response && "order_id" in response && (context.order_id = response.order_id), response?.status === chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.TERMS_CHANGED && (context.replacement_terms = response.replacement, context.terms_deltas = response.deltas), response?.status === chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.SELECTION_UNAVAILABLE && (context.unavailable_lines = response.lines);
|
|
1798
|
+
let checkoutStatus = CHECKOUT_STATUS_BY_PURCHASE_INTENT_RESOLVE_STATUS[status];
|
|
1799
|
+
notifyCheckoutStatus(data.on_status_change, checkoutStatus, context);
|
|
1800
|
+
},
|
|
1801
|
+
onActionRequired: async (action) => {
|
|
1802
|
+
switch (action.status) {
|
|
1803
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.CARD_POPUP_REQUIRED: {
|
|
1804
|
+
if (!(data.allow_popups ?? typeof window < "u"))
|
|
1805
|
+
return actionFailure = {
|
|
1806
|
+
code: chunkUCR5HRYM_js.ErrorCode.PROVIDER_UNAVAILABLE,
|
|
1807
|
+
message: "Card authorization UI is unavailable in this environment.",
|
|
1808
|
+
recoverable: !1
|
|
1809
|
+
}, chunkUCR5HRYM_js.PURCHASE_INTENT_ACTION_DECISION.STOP;
|
|
1810
|
+
let outcome;
|
|
1811
|
+
try {
|
|
1812
|
+
notifyAuthorizationUi(data.on_authorization_ui_change, !0), outcome = await this.authorizeCardPopup(
|
|
1813
|
+
{
|
|
1814
|
+
type: chunkGTJWQAGU_js.CHECKOUT_NEXT_ACTION.CARD_POPUP,
|
|
1815
|
+
provider: action.provider,
|
|
1816
|
+
client_secret: action.client_secret,
|
|
1817
|
+
public_key: action.public_key,
|
|
1818
|
+
provider_account_id: action.provider_account_id ?? void 0
|
|
1819
|
+
},
|
|
1820
|
+
{
|
|
1821
|
+
email: checkoutData.customer.email,
|
|
1822
|
+
currency: started.value.terms.money.currency,
|
|
1823
|
+
returnUrl: data.return_url,
|
|
1824
|
+
signal: data.signal
|
|
1825
|
+
}
|
|
1826
|
+
);
|
|
1827
|
+
} finally {
|
|
1828
|
+
notifyAuthorizationUi(data.on_authorization_ui_change, !1);
|
|
1829
|
+
}
|
|
1830
|
+
return outcome.status === PAYMENT_AUTHORIZATION_OUTCOME_STATUS.SUBMITTED ? chunkUCR5HRYM_js.PURCHASE_INTENT_ACTION_DECISION.CONTINUE : (actionFailure = outcome.status === PAYMENT_AUTHORIZATION_OUTCOME_STATUS.CANCELLED ? {
|
|
1831
|
+
code: chunkUCR5HRYM_js.ErrorCode.PAYMENT_CANCELLED,
|
|
1832
|
+
message: "Card payment was cancelled before submission.",
|
|
1833
|
+
recoverable: !0
|
|
1834
|
+
} : {
|
|
1835
|
+
code: outcome.code,
|
|
1836
|
+
message: outcome.message,
|
|
1837
|
+
recoverable: outcome.recoverable
|
|
1838
|
+
}, chunkUCR5HRYM_js.PURCHASE_INTENT_ACTION_DECISION.STOP);
|
|
1839
|
+
}
|
|
1840
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.REDIRECT_REQUIRED: {
|
|
1841
|
+
let authorizationUrl = chunkDFZWHNRG_js.paymentAuthorizationUrl(action.authorization_url);
|
|
1842
|
+
if (!authorizationUrl)
|
|
1843
|
+
return actionFailure = {
|
|
1844
|
+
code: chunkUCR5HRYM_js.ErrorCode.AUTHORIZATION_FAILED,
|
|
1845
|
+
message: "The provider returned an invalid authorization URL.",
|
|
1846
|
+
recoverable: !1
|
|
1847
|
+
}, chunkUCR5HRYM_js.PURCHASE_INTENT_ACTION_DECISION.STOP;
|
|
1848
|
+
if (typeof window < "u")
|
|
1849
|
+
if (data.allow_popups === !1)
|
|
1850
|
+
window.location.assign(authorizationUrl);
|
|
1851
|
+
else {
|
|
1852
|
+
let popup = window.open(
|
|
1853
|
+
"",
|
|
1854
|
+
AUTHORIZATION_POPUP_NAME,
|
|
1855
|
+
AUTHORIZATION_POPUP_FEATURES
|
|
1856
|
+
);
|
|
1857
|
+
if (!popup)
|
|
1858
|
+
return actionFailure = {
|
|
1859
|
+
code: chunkUCR5HRYM_js.ErrorCode.POPUP_BLOCKED,
|
|
1860
|
+
message: "Authorization popup was blocked.",
|
|
1861
|
+
recoverable: !0
|
|
1862
|
+
}, chunkUCR5HRYM_js.PURCHASE_INTENT_ACTION_DECISION.STOP;
|
|
1863
|
+
popup.opener = null, popup.location.replace(authorizationUrl);
|
|
1864
|
+
}
|
|
1865
|
+
return actionFailure = {
|
|
1866
|
+
code: chunkUCR5HRYM_js.ErrorCode.REDIRECT_REQUIRED,
|
|
1867
|
+
message: "Complete authorization at the payment provider, then resume checkout.",
|
|
1868
|
+
recoverable: !0
|
|
1869
|
+
}, chunkUCR5HRYM_js.PURCHASE_INTENT_ACTION_DECISION.STOP;
|
|
1870
|
+
}
|
|
1871
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.AUTHORIZATION_REQUIRED: {
|
|
1872
|
+
let expected = authorizationKind(action.authorization_type);
|
|
1873
|
+
if (!expected || !data.on_authorization_required)
|
|
1874
|
+
return actionFailure = {
|
|
1875
|
+
code: chunkUCR5HRYM_js.ErrorCode.AUTHORIZATION_REQUIRED,
|
|
1876
|
+
message: "Additional payment authorization is required.",
|
|
1877
|
+
recoverable: !0
|
|
1878
|
+
}, chunkUCR5HRYM_js.PURCHASE_INTENT_ACTION_DECISION.STOP;
|
|
1879
|
+
let submission;
|
|
1880
|
+
return await data.on_authorization_required(expected, async (candidate) => {
|
|
1881
|
+
if (submission) throw new Error("Authorization was already submitted.");
|
|
1882
|
+
submission = normalizeAuthorizationSubmission(expected, candidate);
|
|
1883
|
+
}), submission ? {
|
|
1884
|
+
kind: chunkUCR5HRYM_js.PURCHASE_INTENT_ACTION_DECISION.SUBMIT,
|
|
1885
|
+
request: { authorization: submission }
|
|
1886
|
+
} : (actionFailure = {
|
|
1887
|
+
code: chunkUCR5HRYM_js.ErrorCode.AUTHORIZATION_REQUIRED,
|
|
1888
|
+
message: "Payment authorization was not submitted.",
|
|
1889
|
+
recoverable: !0
|
|
1890
|
+
}, chunkUCR5HRYM_js.PURCHASE_INTENT_ACTION_DECISION.STOP);
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
});
|
|
1895
|
+
if (!resolved.ok)
|
|
1896
|
+
return ok(
|
|
1897
|
+
toTerminalFailure(
|
|
1898
|
+
resolved.error.code || chunkUCR5HRYM_js.ErrorCode.CHECKOUT_FAILED,
|
|
1899
|
+
resolved.error.message || "Unable to resolve checkout.",
|
|
1900
|
+
resolved.error.retryable ?? !0
|
|
1901
|
+
)
|
|
1902
|
+
);
|
|
1903
|
+
switch (resolved.value.kind) {
|
|
1904
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_RESOLUTION_KIND.COMPLETED: {
|
|
1905
|
+
clearIntentIdempotencyKey(started.value.intentScope), clearIntentIdempotencyKey(started.value.confirmationScope);
|
|
1906
|
+
let response = resolved.value.response;
|
|
1907
|
+
notifyCheckoutStatus(data.on_status_change, chunkGTJWQAGU_js.CHECKOUT_STATUS.FINALIZING, {
|
|
1908
|
+
order_id: response.order_id
|
|
1909
|
+
});
|
|
1910
|
+
let enrolledInLink = await this.maybeEnrollResolvedOrder(response.order_id, data);
|
|
1911
|
+
return notifyCheckoutStatus(data.on_status_change, chunkGTJWQAGU_js.CHECKOUT_STATUS.SUCCESS, {
|
|
1912
|
+
order_id: response.order_id
|
|
1913
|
+
}), ok({
|
|
1914
|
+
success: !0,
|
|
1915
|
+
order: {
|
|
1916
|
+
id: response.order_id,
|
|
1917
|
+
order_number: response.order_number ?? response.order_id,
|
|
1918
|
+
status: chunkGTJWQAGU_js.CHECKOUT_ORDER_RESULT_STATUS.CONFIRMED,
|
|
1919
|
+
total: String(cart.pricing.total_price),
|
|
1920
|
+
currency: started.value.terms.money.currency
|
|
1921
|
+
},
|
|
1922
|
+
enrolled_in_link: enrolledInLink
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1925
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_RESOLUTION_KIND.FAILED:
|
|
1926
|
+
return clearIntentIdempotencyKey(started.value.confirmationScope), ok(
|
|
1927
|
+
toTerminalFailure(
|
|
1928
|
+
chunkUCR5HRYM_js.PURCHASE_INTENT_ERROR_CODE.PAYMENT_FAILED,
|
|
1929
|
+
"Payment failed. Choose another method or retry collection.",
|
|
1930
|
+
!0
|
|
1931
|
+
)
|
|
1932
|
+
);
|
|
1933
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_RESOLUTION_KIND.OUTCOME_UNKNOWN:
|
|
1934
|
+
return ok(
|
|
1935
|
+
toTerminalFailure(
|
|
1936
|
+
chunkUCR5HRYM_js.ErrorCode.PAYMENT_OUTCOME_UNKNOWN,
|
|
1937
|
+
"Payment outcome is still unknown. Resume this intent before retrying.",
|
|
1938
|
+
!0
|
|
1939
|
+
)
|
|
1940
|
+
);
|
|
1941
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_RESOLUTION_KIND.TIMED_OUT:
|
|
1942
|
+
return ok(
|
|
1943
|
+
toTerminalFailure(
|
|
1944
|
+
chunkUCR5HRYM_js.ErrorCode.TIMEOUT,
|
|
1945
|
+
"Payment is still processing. Resume this intent to continue polling.",
|
|
1946
|
+
!0
|
|
1947
|
+
)
|
|
1948
|
+
);
|
|
1949
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_RESOLUTION_KIND.ACTION_REQUIRED:
|
|
1950
|
+
return ok(
|
|
1951
|
+
toTerminalFailure(
|
|
1952
|
+
actionFailure?.code ?? chunkUCR5HRYM_js.ErrorCode.AUTHORIZATION_REQUIRED,
|
|
1953
|
+
actionFailure?.message ?? "Checkout requires additional authorization.",
|
|
1954
|
+
actionFailure?.recoverable ?? !0
|
|
1955
|
+
)
|
|
1956
|
+
);
|
|
1957
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_RESOLUTION_KIND.REVIEW_REQUIRED:
|
|
1958
|
+
switch (resolved.value.response.status) {
|
|
1959
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.TERMS_CHANGED:
|
|
1960
|
+
return ok(
|
|
1961
|
+
toTerminalFailure(
|
|
1962
|
+
chunkUCR5HRYM_js.PURCHASE_INTENT_ERROR_CODE.TERMS_CHANGED,
|
|
1963
|
+
"Checkout terms changed and require explicit review.",
|
|
1964
|
+
!0
|
|
1965
|
+
)
|
|
1966
|
+
);
|
|
1967
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.SELECTION_UNAVAILABLE:
|
|
1968
|
+
return ok(
|
|
1969
|
+
toTerminalFailure(
|
|
1970
|
+
chunkUCR5HRYM_js.PURCHASE_INTENT_ERROR_CODE.SELECTION_UNAVAILABLE,
|
|
1971
|
+
"One or more checkout selections are unavailable.",
|
|
1972
|
+
!0
|
|
1973
|
+
)
|
|
1974
|
+
);
|
|
1975
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.OFFER_ENDED:
|
|
1976
|
+
return ok(
|
|
1977
|
+
toTerminalFailure(
|
|
1978
|
+
chunkUCR5HRYM_js.PURCHASE_INTENT_ERROR_CODE.OFFER_ENDED,
|
|
1979
|
+
"This offer has ended.",
|
|
1980
|
+
!1
|
|
1981
|
+
)
|
|
1982
|
+
);
|
|
1983
|
+
case chunkUCR5HRYM_js.PURCHASE_INTENT_CONFIRM_STATUS.SOURCE_UNAVAILABLE:
|
|
1984
|
+
return ok(
|
|
1985
|
+
toTerminalFailure(
|
|
1986
|
+
chunkUCR5HRYM_js.PURCHASE_INTENT_ERROR_CODE.SOURCE_UNAVAILABLE,
|
|
1987
|
+
"This purchase source is unavailable.",
|
|
1988
|
+
!1
|
|
1989
|
+
)
|
|
1990
|
+
);
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
} catch (error) {
|
|
1994
|
+
let cancelled = data.signal?.aborted || error instanceof Error && error.name === ABORT_ERROR_NAME;
|
|
1995
|
+
return ok(
|
|
1996
|
+
toTerminalFailure(
|
|
1997
|
+
cancelled ? chunkUCR5HRYM_js.ErrorCode.CANCELLED : chunkUCR5HRYM_js.ErrorCode.AUTHORIZATION_FAILED,
|
|
1998
|
+
cancelled ? "Checkout was cancelled." : error instanceof Error ? error.message : "Checkout authorization failed.",
|
|
1999
|
+
true
|
|
2000
|
+
)
|
|
2001
|
+
);
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
};
|
|
2005
|
+
|
|
2006
|
+
// src/orders.ts
|
|
2007
|
+
var OrderQueries = class {
|
|
2008
|
+
constructor(client) {
|
|
2009
|
+
this.client = client;
|
|
2010
|
+
}
|
|
2011
|
+
orderTokenParam(orderId) {
|
|
2012
|
+
let token = this.client.getOrderToken(orderId);
|
|
2013
|
+
return token ? `?token=${encodeURIComponent(token)}` : "";
|
|
2014
|
+
}
|
|
2015
|
+
async list(options) {
|
|
2016
|
+
let params = new URLSearchParams();
|
|
2017
|
+
options?.status && params.set("status", options.status), options?.limit && params.set("limit", String(options.limit)), options?.offset && params.set("offset", String(options.offset));
|
|
2018
|
+
let path = params.toString() ? `/api/v1/orders?${params.toString()}` : "/api/v1/orders";
|
|
2019
|
+
return safe(this.client.get(path));
|
|
2020
|
+
}
|
|
2021
|
+
async get(orderId) {
|
|
2022
|
+
let encodedId = encodeURIComponent(orderId), tokenParam = this.orderTokenParam(orderId);
|
|
2023
|
+
return safe(this.client.get(`/api/v1/orders/${encodedId}${tokenParam}`));
|
|
2024
|
+
}
|
|
2025
|
+
/**
|
|
2026
|
+
* Same endpoint as `get`, typed as the enriched display contract
|
|
2027
|
+
* (product names, images, resolved selections, customer inputs, scheduling,
|
|
2028
|
+
* fulfillment). Feed the result through `toAccountOrderView`.
|
|
2029
|
+
*/
|
|
2030
|
+
async getDetail(orderId) {
|
|
2031
|
+
let encodedId = encodeURIComponent(orderId), tokenParam = this.orderTokenParam(orderId);
|
|
2032
|
+
return safe(this.client.get(`/api/v1/orders/${encodedId}${tokenParam}`));
|
|
2033
|
+
}
|
|
2034
|
+
async getRecent(limit = 5) {
|
|
2035
|
+
return this.list({ limit });
|
|
2036
|
+
}
|
|
2037
|
+
async getByStatus(status) {
|
|
2038
|
+
return this.list({ status });
|
|
2039
|
+
}
|
|
2040
|
+
async cancel(orderId, reason, opts) {
|
|
2041
|
+
let encodedId = encodeURIComponent(orderId), tokenParam = this.orderTokenParam(orderId), idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
2042
|
+
return safe(
|
|
2043
|
+
this.client.post(
|
|
2044
|
+
`/api/v1/orders/${encodedId}/cancel${tokenParam}`,
|
|
2045
|
+
{ reason },
|
|
2046
|
+
{ idempotencyKey }
|
|
2047
|
+
)
|
|
2048
|
+
);
|
|
2049
|
+
}
|
|
2050
|
+
};
|
|
2051
|
+
|
|
2052
|
+
// src/link.ts
|
|
2053
|
+
function encodePathSegment(value) {
|
|
2054
|
+
return encodeURIComponent(value);
|
|
2055
|
+
}
|
|
2056
|
+
var LinkService = class {
|
|
2057
|
+
constructor(client) {
|
|
2058
|
+
this.client = client;
|
|
2059
|
+
this.activationGeneration = 0;
|
|
2060
|
+
}
|
|
2061
|
+
beginActivation() {
|
|
2062
|
+
return {
|
|
2063
|
+
generation: ++this.activationGeneration,
|
|
2064
|
+
sessionEpoch: this.client.getSessionEpoch(),
|
|
2065
|
+
publicKeyEpoch: this.client.getPublicKeyEpoch()
|
|
2066
|
+
};
|
|
2067
|
+
}
|
|
2068
|
+
isActivationFenceCurrent(fence) {
|
|
2069
|
+
return fence.generation === this.activationGeneration && fence.sessionEpoch === this.client.getSessionEpoch() && fence.publicKeyEpoch === this.client.getPublicKeyEpoch();
|
|
2070
|
+
}
|
|
2071
|
+
supersededActivation() {
|
|
2072
|
+
return {
|
|
2073
|
+
ok: false,
|
|
2074
|
+
error: new chunkUCR5HRYM_js.CimplifyError(
|
|
2075
|
+
"session_superseded",
|
|
2076
|
+
"A newer authentication session replaced this one"
|
|
2077
|
+
)
|
|
2078
|
+
};
|
|
2079
|
+
}
|
|
2080
|
+
async activateAuthenticatedSession(result, fence) {
|
|
2081
|
+
if (!result.ok || !result.value.session_token) return result;
|
|
2082
|
+
if (!this.isActivationFenceCurrent(fence)) return this.supersededActivation();
|
|
2083
|
+
let accessToken = result.value.session_token;
|
|
2084
|
+
this.client.setAccessToken(accessToken);
|
|
2085
|
+
let installedSessionEpoch = this.client.getSessionEpoch();
|
|
2086
|
+
if (!this.client.getPublicKey().trim())
|
|
2087
|
+
return this.client.activity.refreshIdentity(), result;
|
|
2088
|
+
let claim = await this.client.session.claim();
|
|
2089
|
+
return fence.generation !== this.activationGeneration || fence.publicKeyEpoch !== this.client.getPublicKeyEpoch() || this.client.getAccessToken() !== accessToken ? this.supersededActivation() : !claim.ok && claim.error.code !== "already_claimed" ? this.client.getSessionEpoch() !== installedSessionEpoch ? this.supersededActivation() : (this.client.hasClaimedSessionAuthority() ? this.client.clearSession() : this.client.setAccessToken(null), claim) : (this.client.activity.refreshIdentity(), result);
|
|
2090
|
+
}
|
|
2091
|
+
async requestOtp(input, opts) {
|
|
2092
|
+
let idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
2093
|
+
return safe(
|
|
2094
|
+
this.client.linkPost("/v1/link/auth/request-otp", input, {
|
|
2095
|
+
idempotencyKey
|
|
2096
|
+
})
|
|
2097
|
+
);
|
|
2098
|
+
}
|
|
2099
|
+
async verifyOtp(input, opts) {
|
|
2100
|
+
let idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey(), activationFence = opts?.activateSession === false ? null : this.beginActivation(), { business_id: _ignoredBusinessId, ...body } = input, result = await safe(
|
|
2101
|
+
this.client.linkPost("/v1/link/auth/verify-otp", body, { idempotencyKey })
|
|
2102
|
+
);
|
|
2103
|
+
return activationFence ? this.activateAuthenticatedSession(result, activationFence) : result;
|
|
2104
|
+
}
|
|
2105
|
+
async refreshSession(sessionToken, opts) {
|
|
2106
|
+
let idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey(), activationFence = opts?.activateSession === false ? null : this.beginActivation(), body = sessionToken ? { session_token: sessionToken } : {}, result = await safe(
|
|
2107
|
+
this.client.linkPost("/v1/link/auth/refresh", body, { idempotencyKey })
|
|
2108
|
+
);
|
|
2109
|
+
return activationFence ? this.activateAuthenticatedSession(result, activationFence) : result;
|
|
2110
|
+
}
|
|
2111
|
+
async logout() {
|
|
2112
|
+
this.activationGeneration += 1;
|
|
2113
|
+
let request = safe(this.client.linkPost("/v1/link/auth/logout"));
|
|
2114
|
+
return this.client.clearSession(), request;
|
|
2115
|
+
}
|
|
2116
|
+
async checkStatus(contact) {
|
|
2117
|
+
return safe(this.client.linkPost("/v1/link/check-status", { contact }));
|
|
2118
|
+
}
|
|
2119
|
+
async getLinkData() {
|
|
2120
|
+
return safe(this.client.linkGet("/v1/link/data"));
|
|
2121
|
+
}
|
|
2122
|
+
async getAddresses() {
|
|
2123
|
+
return safe(this.client.linkGet("/v1/link/addresses"));
|
|
2124
|
+
}
|
|
2125
|
+
async getMobileMoney() {
|
|
2126
|
+
return safe(this.client.linkGet("/v1/link/mobile-money"));
|
|
2127
|
+
}
|
|
2128
|
+
async getPreferences() {
|
|
2129
|
+
return safe(this.client.linkGet("/v1/link/preferences"));
|
|
2130
|
+
}
|
|
2131
|
+
/**
|
|
2132
|
+
* Updates the profile name. An email or phone may only be echoed back
|
|
2133
|
+
* unchanged; a different one is refused with CONTACT_VERIFICATION_REQUIRED
|
|
2134
|
+
* and goes through `requestContactChange` and `confirmContactChange`.
|
|
2135
|
+
*/
|
|
2136
|
+
async updateProfile(input) {
|
|
2137
|
+
return safe(this.client.linkPost("/v1/link/profile", input));
|
|
2138
|
+
}
|
|
2139
|
+
async requestContactChange(input) {
|
|
2140
|
+
return safe(
|
|
2141
|
+
this.client.linkPost("/v1/link/profile/contact/request", input)
|
|
2142
|
+
);
|
|
2143
|
+
}
|
|
2144
|
+
async confirmContactChange(input) {
|
|
2145
|
+
return safe(this.client.linkPost("/v1/link/profile/contact/confirm", input));
|
|
2146
|
+
}
|
|
2147
|
+
async getOrders(options) {
|
|
2148
|
+
let params = new URLSearchParams();
|
|
2149
|
+
options?.status && params.set("status", options.status), options?.limit && params.set("limit", String(options.limit)), options?.offset && params.set("offset", String(options.offset)), options?.businessId && params.set("business_id", options.businessId);
|
|
2150
|
+
let query = params.toString(), path = query ? `/v1/link/orders?${query}` : "/v1/link/orders";
|
|
2151
|
+
return safe(this.client.linkGet(path));
|
|
2152
|
+
}
|
|
2153
|
+
async getOrder(orderId, options) {
|
|
2154
|
+
let params = new URLSearchParams();
|
|
2155
|
+
options?.businessId && params.set("business_id", options.businessId);
|
|
2156
|
+
let query = params.toString(), path = query ? `/v1/link/orders/${encodePathSegment(orderId)}?${query}` : `/v1/link/orders/${encodePathSegment(orderId)}`;
|
|
2157
|
+
return safe(this.client.linkGet(path));
|
|
2158
|
+
}
|
|
2159
|
+
async enroll(data, opts) {
|
|
2160
|
+
let idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
2161
|
+
return safe(
|
|
2162
|
+
this.client.linkPost("/v1/link/enroll", data, { idempotencyKey })
|
|
2163
|
+
);
|
|
2164
|
+
}
|
|
2165
|
+
/**
|
|
2166
|
+
* Save a paid order's details after the person ticked "Save my details with Cimplify".
|
|
2167
|
+
* Nothing is saved until the order's contact is proved; when it is not, the result names
|
|
2168
|
+
* the contact to send one code to. Never call this before payment completes.
|
|
2169
|
+
*/
|
|
2170
|
+
async saveDetails(data, opts) {
|
|
2171
|
+
let idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
2172
|
+
return safe(
|
|
2173
|
+
this.client.linkPost("/v1/link/save-details", data, {
|
|
2174
|
+
idempotencyKey
|
|
2175
|
+
})
|
|
2176
|
+
);
|
|
2177
|
+
}
|
|
2178
|
+
/**
|
|
2179
|
+
* After `saveDetails` asked for a code: checks the code the person received, which signs
|
|
2180
|
+
* them in to Link, then saves the order's details under their account.
|
|
2181
|
+
*/
|
|
2182
|
+
async confirmSaveDetails(data, code) {
|
|
2183
|
+
let verified = await this.verifyOtp(code);
|
|
2184
|
+
return verified.ok ? verified.value.success ? this.saveDetails(data) : err(new chunkUCR5HRYM_js.CimplifyError(chunkUCR5HRYM_js.ErrorCode.UNAUTHORIZED, verified.value.message, true)) : err(verified.error);
|
|
2185
|
+
}
|
|
2186
|
+
async updatePreferences(preferences) {
|
|
2187
|
+
return safe(this.client.linkPost("/v1/link/preferences", preferences));
|
|
2188
|
+
}
|
|
2189
|
+
async createAddress(input, opts) {
|
|
2190
|
+
let idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
2191
|
+
return safe(
|
|
2192
|
+
this.client.linkPost("/v1/link/addresses", input, { idempotencyKey })
|
|
2193
|
+
);
|
|
2194
|
+
}
|
|
2195
|
+
async updateAddress(input) {
|
|
2196
|
+
let { address_id, ...patch } = input;
|
|
2197
|
+
return safe(
|
|
2198
|
+
this.client.linkPost(
|
|
2199
|
+
`/v1/link/addresses/${encodePathSegment(address_id)}`,
|
|
2200
|
+
patch
|
|
2201
|
+
)
|
|
2202
|
+
);
|
|
2203
|
+
}
|
|
2204
|
+
async deleteAddress(addressId) {
|
|
2205
|
+
return safe(
|
|
2206
|
+
this.client.linkDelete(`/v1/link/addresses/${encodePathSegment(addressId)}`)
|
|
2207
|
+
);
|
|
2208
|
+
}
|
|
2209
|
+
async setDefaultAddress(addressId) {
|
|
2210
|
+
return safe(
|
|
2211
|
+
this.client.linkPost(
|
|
2212
|
+
`/v1/link/addresses/${encodePathSegment(addressId)}/default`
|
|
2213
|
+
)
|
|
2214
|
+
);
|
|
2215
|
+
}
|
|
2216
|
+
async trackAddressUsage(addressId) {
|
|
2217
|
+
return safe(
|
|
2218
|
+
this.client.linkPost(
|
|
2219
|
+
`/v1/link/addresses/${encodePathSegment(addressId)}/track-usage`
|
|
2220
|
+
)
|
|
2221
|
+
);
|
|
2222
|
+
}
|
|
2223
|
+
async createMobileMoney(input, opts) {
|
|
2224
|
+
let idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
2225
|
+
return safe(
|
|
2226
|
+
this.client.linkPost("/v1/link/mobile-money", input, { idempotencyKey })
|
|
2227
|
+
);
|
|
2228
|
+
}
|
|
2229
|
+
async deleteMobileMoney(mobileMoneyId) {
|
|
2230
|
+
return safe(
|
|
2231
|
+
this.client.linkDelete(
|
|
2232
|
+
`/v1/link/mobile-money/${encodePathSegment(mobileMoneyId)}`
|
|
2233
|
+
)
|
|
2234
|
+
);
|
|
2235
|
+
}
|
|
2236
|
+
async setDefaultMobileMoney(mobileMoneyId) {
|
|
2237
|
+
return safe(
|
|
2238
|
+
this.client.linkPost(
|
|
2239
|
+
`/v1/link/mobile-money/${encodePathSegment(mobileMoneyId)}/default`
|
|
2240
|
+
)
|
|
2241
|
+
);
|
|
2242
|
+
}
|
|
2243
|
+
async trackMobileMoneyUsage(mobileMoneyId) {
|
|
2244
|
+
return safe(
|
|
2245
|
+
this.client.linkPost(
|
|
2246
|
+
`/v1/link/mobile-money/${encodePathSegment(mobileMoneyId)}/track-usage`
|
|
2247
|
+
)
|
|
2248
|
+
);
|
|
2249
|
+
}
|
|
2250
|
+
/**
|
|
2251
|
+
* Reports whether a saved mobile money account is verified; it verifies nothing.
|
|
2252
|
+
* Verification comes only from a successful payment from the account; one not yet
|
|
2253
|
+
* verified fails with `CONCURRENCY_CONFLICT`.
|
|
2254
|
+
*/
|
|
2255
|
+
async checkMobileMoneyVerification(mobileMoneyId, opts) {
|
|
2256
|
+
let idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
2257
|
+
return safe(
|
|
2258
|
+
this.client.linkPost(
|
|
2259
|
+
`/v1/link/mobile-money/${encodePathSegment(mobileMoneyId)}/verify`,
|
|
2260
|
+
void 0,
|
|
2261
|
+
{ idempotencyKey }
|
|
2262
|
+
)
|
|
2263
|
+
);
|
|
2264
|
+
}
|
|
2265
|
+
/**
|
|
2266
|
+
* @deprecated Renamed to {@link LinkService.checkMobileMoneyVerification}: it only reports
|
|
2267
|
+
* whether the account is verified and never verifies it.
|
|
2268
|
+
*/
|
|
2269
|
+
async verifyMobileMoney(mobileMoneyId, opts) {
|
|
2270
|
+
return this.checkMobileMoneyVerification(mobileMoneyId, opts);
|
|
2271
|
+
}
|
|
2272
|
+
async getSessions() {
|
|
2273
|
+
return safe(this.client.linkGet("/v1/link/sessions"));
|
|
2274
|
+
}
|
|
2275
|
+
async revokeSession(sessionId) {
|
|
2276
|
+
return safe(this.client.linkDelete(`/v1/link/sessions/${sessionId}`));
|
|
2277
|
+
}
|
|
2278
|
+
async revokeAllSessions() {
|
|
2279
|
+
return safe(this.client.linkDelete("/v1/link/sessions"));
|
|
2280
|
+
}
|
|
2281
|
+
};
|
|
2282
|
+
|
|
2283
|
+
// src/auth.ts
|
|
2284
|
+
var AuthService = class {
|
|
2285
|
+
constructor(client) {
|
|
2286
|
+
this.client = client;
|
|
2287
|
+
}
|
|
2288
|
+
async getStatus() {
|
|
2289
|
+
return safe(this.client.get("/api/v1/auth/status"));
|
|
2290
|
+
}
|
|
2291
|
+
async getCurrentUser() {
|
|
2292
|
+
let result = await this.getStatus();
|
|
2293
|
+
return result.ok ? ok(result.value.customer || null) : result;
|
|
2294
|
+
}
|
|
2295
|
+
async isAuthenticated() {
|
|
2296
|
+
let result = await this.getStatus();
|
|
2297
|
+
return result.ok ? ok(result.value.is_authenticated) : result;
|
|
2298
|
+
}
|
|
2299
|
+
async requestOtp(contact, contactType, opts) {
|
|
2300
|
+
let idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
2301
|
+
return safe(
|
|
2302
|
+
this.client.post(
|
|
2303
|
+
"/api/v1/auth/request-otp",
|
|
2304
|
+
{ contact, contact_type: contactType },
|
|
2305
|
+
{ idempotencyKey }
|
|
2306
|
+
)
|
|
2307
|
+
);
|
|
2308
|
+
}
|
|
2309
|
+
async verifyOtp(code, contact, opts) {
|
|
2310
|
+
let idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey(), result = await safe(
|
|
2311
|
+
this.client.post(
|
|
2312
|
+
"/api/v1/auth/verify-otp",
|
|
2313
|
+
{ otp_code: code, contact },
|
|
2314
|
+
{ idempotencyKey }
|
|
2315
|
+
)
|
|
2316
|
+
);
|
|
2317
|
+
return result.ok && result.value.session_token && (this.client.setAccessToken(result.value.session_token), this.client.activity.refreshIdentity(), this.client.autoClaimSession()), result;
|
|
2318
|
+
}
|
|
2319
|
+
async logout() {
|
|
2320
|
+
let result = await safe(this.client.post("/api/v1/auth/logout"));
|
|
2321
|
+
return this.client.clearSession(), result;
|
|
2322
|
+
}
|
|
2323
|
+
async updateProfile(input) {
|
|
2324
|
+
return safe(this.client.post("/api/v1/auth/profile", input));
|
|
2325
|
+
}
|
|
2326
|
+
};
|
|
2327
|
+
|
|
2328
|
+
// src/business.ts
|
|
2329
|
+
var BusinessService = class {
|
|
2330
|
+
constructor(client) {
|
|
2331
|
+
this.client = client;
|
|
2332
|
+
}
|
|
2333
|
+
async getEmbeddingOrigins(opts) {
|
|
2334
|
+
return safe(this.client.get("/api/v1/elements/origins", opts));
|
|
2335
|
+
}
|
|
2336
|
+
async getInfo(opts) {
|
|
2337
|
+
return safe(this.client.get("/api/v1/business", opts));
|
|
2338
|
+
}
|
|
2339
|
+
async getByHandle(handle, opts) {
|
|
2340
|
+
let encodedHandle = encodeURIComponent(handle);
|
|
2341
|
+
return safe(this.client.get(`/api/v1/business/by-handle/${encodedHandle}`, opts));
|
|
2342
|
+
}
|
|
2343
|
+
async getByDomain(domain, opts) {
|
|
2344
|
+
let encodedDomain = encodeURIComponent(domain);
|
|
2345
|
+
return safe(this.client.get(`/api/v1/business/by-domain?domain=${encodedDomain}`, opts));
|
|
2346
|
+
}
|
|
2347
|
+
async getSettings(opts) {
|
|
2348
|
+
return safe(this.client.get("/api/v1/business/settings", opts));
|
|
2349
|
+
}
|
|
2350
|
+
async getLocations(opts) {
|
|
2351
|
+
return safe(this.client.get("/api/v1/business/locations", opts));
|
|
2352
|
+
}
|
|
2353
|
+
async getLocation(locationId, opts) {
|
|
2354
|
+
let result = await this.getLocations(opts);
|
|
2355
|
+
if (!result.ok) return err(result.error);
|
|
2356
|
+
let location = result.value.find((item) => item.id === locationId);
|
|
2357
|
+
return location ? ok(location) : err(new chunkUCR5HRYM_js.CimplifyError(chunkUCR5HRYM_js.ErrorCode.NOT_FOUND, `Location not found: ${locationId}`, false));
|
|
2358
|
+
}
|
|
2359
|
+
async getHours(opts) {
|
|
2360
|
+
return safe(this.client.get("/api/v1/business/hours", opts));
|
|
2361
|
+
}
|
|
2362
|
+
async getLocationHours(locationId, opts) {
|
|
2363
|
+
let result = await this.getHours(opts);
|
|
2364
|
+
return result.ok ? ok(result.value.filter((hour) => hour.location_id === locationId)) : result;
|
|
2365
|
+
}
|
|
2366
|
+
async getBootstrap(opts) {
|
|
2367
|
+
return safe(this.client.get("/api/v1/bootstrap", opts));
|
|
2368
|
+
}
|
|
2369
|
+
};
|
|
2370
|
+
|
|
2371
|
+
// src/inventory.ts
|
|
2372
|
+
var InventoryService = class {
|
|
2373
|
+
constructor(client) {
|
|
2374
|
+
this.client = client;
|
|
2375
|
+
}
|
|
2376
|
+
withQuery(path, params) {
|
|
2377
|
+
let searchParams = new URLSearchParams();
|
|
2378
|
+
for (let [key, value] of Object.entries(params))
|
|
2379
|
+
value !== void 0 && searchParams.set(key, String(value));
|
|
2380
|
+
let query = searchParams.toString();
|
|
2381
|
+
return query ? `${path}?${query}` : path;
|
|
2382
|
+
}
|
|
2383
|
+
async getProductStock(productId, locationId) {
|
|
2384
|
+
let encodedId = encodeURIComponent(productId), path = this.withQuery(`/api/v1/inventory/products/${encodedId}/stock`, {
|
|
2385
|
+
location_id: locationId
|
|
2386
|
+
});
|
|
2387
|
+
return safe(this.client.get(path));
|
|
2388
|
+
}
|
|
2389
|
+
async getVariantStock(variantId, locationId) {
|
|
2390
|
+
let encodedId = encodeURIComponent(variantId), path = this.withQuery(`/api/v1/inventory/variants/${encodedId}/stock`, {
|
|
2391
|
+
location_id: locationId
|
|
2392
|
+
});
|
|
2393
|
+
return safe(this.client.get(path));
|
|
2394
|
+
}
|
|
2395
|
+
async checkProductAvailability(productId, quantity, locationId) {
|
|
2396
|
+
let encodedId = encodeURIComponent(productId), path = this.withQuery(`/api/v1/inventory/products/${encodedId}/availability`, {
|
|
2397
|
+
quantity,
|
|
2398
|
+
location_id: locationId
|
|
2399
|
+
});
|
|
2400
|
+
return safe(this.client.get(path));
|
|
2401
|
+
}
|
|
2402
|
+
async checkVariantAvailability(variantId, quantity, locationId) {
|
|
2403
|
+
let encodedId = encodeURIComponent(variantId), path = this.withQuery(`/api/v1/inventory/variants/${encodedId}/availability`, {
|
|
2404
|
+
quantity,
|
|
2405
|
+
location_id: locationId
|
|
2406
|
+
});
|
|
2407
|
+
return safe(this.client.get(path));
|
|
2408
|
+
}
|
|
2409
|
+
async checkMultipleAvailability(items, locationId) {
|
|
2410
|
+
let results = await Promise.all(
|
|
2411
|
+
items.map(
|
|
2412
|
+
(item) => item.variant_id ? this.checkVariantAvailability(item.variant_id, item.quantity, locationId) : this.checkProductAvailability(item.product_id, item.quantity, locationId)
|
|
2413
|
+
)
|
|
2414
|
+
);
|
|
2415
|
+
for (let result of results)
|
|
2416
|
+
if (!result.ok) return result;
|
|
2417
|
+
return ok(results.map((r) => r.value));
|
|
2418
|
+
}
|
|
2419
|
+
async isInStock(productId, locationId) {
|
|
2420
|
+
let result = await this.checkProductAvailability(productId, 1, locationId);
|
|
2421
|
+
return result.ok ? ok(result.value.is_available) : result;
|
|
2422
|
+
}
|
|
2423
|
+
async getAvailableQuantity(productId, locationId) {
|
|
2424
|
+
let result = await this.getProductStock(productId, locationId);
|
|
2425
|
+
return result.ok ? ok(result.value.available_quantity ?? void 0) : result;
|
|
2426
|
+
}
|
|
2427
|
+
};
|
|
2428
|
+
|
|
2429
|
+
// src/scheduling.ts
|
|
2430
|
+
function withQuery2(path, params) {
|
|
2431
|
+
let searchParams = new URLSearchParams();
|
|
2432
|
+
for (let [key, value] of Object.entries(params))
|
|
2433
|
+
value !== void 0 && searchParams.set(key, String(value));
|
|
2434
|
+
let query = searchParams.toString();
|
|
2435
|
+
return query ? `${path}?${query}` : path;
|
|
2436
|
+
}
|
|
2437
|
+
function firstScheduledTime(booking) {
|
|
2438
|
+
return booking.service_items.find((item) => typeof item.scheduled_start == "string")?.scheduled_start || booking.created_at;
|
|
2439
|
+
}
|
|
2440
|
+
var SchedulingService = class {
|
|
2441
|
+
constructor(client) {
|
|
2442
|
+
this.client = client;
|
|
2443
|
+
}
|
|
2444
|
+
async getServices() {
|
|
2445
|
+
return safe(this.client.get("/api/v1/scheduling/services"));
|
|
2446
|
+
}
|
|
2447
|
+
async getService(serviceId) {
|
|
2448
|
+
let encodedId = encodeURIComponent(serviceId);
|
|
2449
|
+
return safe(this.client.get(`/api/v1/scheduling/services/${encodedId}`));
|
|
2450
|
+
}
|
|
2451
|
+
async getAvailableSlots(input) {
|
|
2452
|
+
let path = withQuery2("/api/v1/scheduling/slots", {
|
|
2453
|
+
service_id: input.service_id,
|
|
2454
|
+
date: input.date,
|
|
2455
|
+
participant_count: input.participant_count,
|
|
2456
|
+
units: input.units,
|
|
2457
|
+
variant_id: input.variant_id
|
|
2458
|
+
});
|
|
2459
|
+
return safe(this.client.get(path));
|
|
2460
|
+
}
|
|
2461
|
+
async checkSlotAvailability(input) {
|
|
2462
|
+
let path = withQuery2("/api/v1/scheduling/slots/check", {
|
|
2463
|
+
service_id: input.service_id,
|
|
2464
|
+
slot_time: input.slot_time,
|
|
2465
|
+
duration_minutes: input.duration_minutes,
|
|
2466
|
+
participant_count: input.participant_count
|
|
2467
|
+
});
|
|
2468
|
+
return safe(this.client.get(path));
|
|
2469
|
+
}
|
|
2470
|
+
async getServiceAvailability(params) {
|
|
2471
|
+
let path = withQuery2("/api/v1/scheduling/availability", {
|
|
2472
|
+
service_id: params.service_id,
|
|
2473
|
+
start_date: params.start_date,
|
|
2474
|
+
end_date: params.end_date,
|
|
2475
|
+
location_id: params.location_id,
|
|
2476
|
+
participant_count: params.participant_count,
|
|
2477
|
+
units: params.units,
|
|
2478
|
+
variant_id: params.variant_id
|
|
2479
|
+
});
|
|
2480
|
+
return safe(this.client.get(path));
|
|
2481
|
+
}
|
|
2482
|
+
async getBooking(bookingId) {
|
|
2483
|
+
let encodedId = encodeURIComponent(bookingId);
|
|
2484
|
+
return safe(this.client.get(`/api/v1/scheduling/bookings/${encodedId}`));
|
|
2485
|
+
}
|
|
2486
|
+
async getCustomerBookings(customerId) {
|
|
2487
|
+
let path = withQuery2("/api/v1/scheduling/bookings", {
|
|
2488
|
+
customer_id: customerId
|
|
2489
|
+
});
|
|
2490
|
+
return safe(this.client.get(path));
|
|
2491
|
+
}
|
|
2492
|
+
async getUpcomingBookings() {
|
|
2493
|
+
let result = await this.getCustomerBookings();
|
|
2494
|
+
if (!result.ok) return result;
|
|
2495
|
+
let upcoming = result.value.filter((booking) => {
|
|
2496
|
+
let status = String(booking.status).toLowerCase();
|
|
2497
|
+
return status !== "completed" && status !== "cancelled";
|
|
2498
|
+
}).sort((a, b) => firstScheduledTime(a).localeCompare(firstScheduledTime(b)));
|
|
2499
|
+
return ok(upcoming);
|
|
2500
|
+
}
|
|
2501
|
+
async getPastBookings(limit = 10) {
|
|
2502
|
+
let result = await this.getCustomerBookings();
|
|
2503
|
+
if (!result.ok) return result;
|
|
2504
|
+
let past = result.value.filter((booking) => String(booking.status).toLowerCase() === "completed").sort((a, b) => firstScheduledTime(b).localeCompare(firstScheduledTime(a))).slice(0, Math.max(0, limit));
|
|
2505
|
+
return ok(past);
|
|
2506
|
+
}
|
|
2507
|
+
async cancelBooking(input, opts) {
|
|
2508
|
+
let encodedId = encodeURIComponent(input.booking_id), idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
2509
|
+
return safe(
|
|
2510
|
+
this.client.post(
|
|
2511
|
+
`/api/v1/scheduling/bookings/${encodedId}/cancel`,
|
|
2512
|
+
{ reason: input.reason },
|
|
2513
|
+
{ idempotencyKey }
|
|
2514
|
+
)
|
|
2515
|
+
);
|
|
2516
|
+
}
|
|
2517
|
+
async rescheduleBooking(input, opts) {
|
|
2518
|
+
let idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
2519
|
+
return safe(
|
|
2520
|
+
this.client.post(
|
|
2521
|
+
"/api/v1/scheduling/bookings/reschedule",
|
|
2522
|
+
input,
|
|
2523
|
+
{ idempotencyKey }
|
|
2524
|
+
)
|
|
2525
|
+
);
|
|
2526
|
+
}
|
|
2527
|
+
async getNextAvailableSlot(serviceId, fromDate) {
|
|
2528
|
+
let date = fromDate || (/* @__PURE__ */ new Date()).toISOString().split("T")[0], result = await this.getAvailableSlots({
|
|
2529
|
+
service_id: serviceId,
|
|
2530
|
+
date
|
|
2531
|
+
});
|
|
2532
|
+
return result.ok ? ok(result.value[0] ?? null) : result;
|
|
2533
|
+
}
|
|
2534
|
+
async hasAvailabilityOn(serviceId, date) {
|
|
2535
|
+
let result = await this.getAvailableSlots({
|
|
2536
|
+
service_id: serviceId,
|
|
2537
|
+
date
|
|
2538
|
+
});
|
|
2539
|
+
return result.ok ? ok(result.value.length > 0) : result;
|
|
2540
|
+
}
|
|
2541
|
+
};
|
|
2542
|
+
|
|
2543
|
+
// src/lite.ts
|
|
2544
|
+
var LiteService = class {
|
|
2545
|
+
constructor(client) {
|
|
2546
|
+
this.client = client;
|
|
2547
|
+
}
|
|
2548
|
+
async getBootstrap() {
|
|
2549
|
+
return safe(this.client.get("/api/v1/lite/bootstrap"));
|
|
2550
|
+
}
|
|
2551
|
+
async getResource(resourceId) {
|
|
2552
|
+
let encodedId = encodeURIComponent(resourceId);
|
|
2553
|
+
return safe(this.client.get(`/api/v1/lite/resources/${encodedId}`));
|
|
2554
|
+
}
|
|
2555
|
+
async getMenu() {
|
|
2556
|
+
return safe(this.client.get("/api/v1/lite/menu"));
|
|
2557
|
+
}
|
|
2558
|
+
async getMenuByCategory(categoryId) {
|
|
2559
|
+
let encodedId = encodeURIComponent(categoryId);
|
|
2560
|
+
return safe(this.client.get(`/api/v1/lite/menu/categories/${encodedId}`));
|
|
2561
|
+
}
|
|
2562
|
+
};
|
|
2563
|
+
|
|
2564
|
+
// src/fx.ts
|
|
2565
|
+
var FxService = class {
|
|
2566
|
+
constructor(client) {
|
|
2567
|
+
this.client = client;
|
|
2568
|
+
}
|
|
2569
|
+
async getRate(from, to) {
|
|
2570
|
+
let path = `/api/v1/fx/rate?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`;
|
|
2571
|
+
return safe(this.client.get(path));
|
|
2572
|
+
}
|
|
2573
|
+
async lockQuote(request, opts) {
|
|
2574
|
+
let idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
|
|
2575
|
+
return safe(
|
|
2576
|
+
this.client.post("/api/v1/fx/quotes", request, { idempotencyKey })
|
|
2577
|
+
);
|
|
2578
|
+
}
|
|
2579
|
+
};
|
|
2580
|
+
|
|
2581
|
+
// src/types/elements.ts
|
|
2582
|
+
var ELEMENT_TYPES = {
|
|
2583
|
+
AUTH: "auth",
|
|
2584
|
+
ADDRESS: "address",
|
|
2585
|
+
PAYMENT: "payment",
|
|
2586
|
+
CHECKOUT: "checkout",
|
|
2587
|
+
ACCOUNT: "account"
|
|
2588
|
+
}, MESSAGE_TYPES = {
|
|
2589
|
+
INIT: "init",
|
|
2590
|
+
IDENTITY: "identity",
|
|
2591
|
+
SESSION_CLEARED: "session_cleared",
|
|
2592
|
+
SET_CART: "set_cart",
|
|
2593
|
+
GET_DATA: "get_data",
|
|
2594
|
+
LOGOUT: "logout",
|
|
2595
|
+
PROCESS_CHECKOUT: "process_checkout",
|
|
2596
|
+
ABORT_CHECKOUT: "abort_checkout",
|
|
2597
|
+
READY: "ready",
|
|
2598
|
+
HEIGHT_CHANGE: "height_change",
|
|
2599
|
+
ERROR: "error",
|
|
2600
|
+
ADDRESS_CHANGED: "address_changed",
|
|
2601
|
+
ADDRESS_SELECTED: "address_selected",
|
|
2602
|
+
PAYMENT_METHOD_SELECTED: "payment_method_selected",
|
|
2603
|
+
LOGOUT_COMPLETE: "logout_complete",
|
|
2604
|
+
AUTH_REQUESTED: "auth_requested",
|
|
2605
|
+
SESSION_ESTABLISHED: "session_established",
|
|
2606
|
+
CONTINUE_WITHOUT_SAVED_DETAILS: "continue_without_saved_details",
|
|
2607
|
+
CONTACT_PROVIDED: "contact_provided",
|
|
2608
|
+
CHECKOUT_STATUS: "checkout_status",
|
|
2609
|
+
CHECKOUT_COMPLETE: "checkout_complete",
|
|
2610
|
+
TERMS_CHANGED: "terms_changed",
|
|
2611
|
+
SELECTION_UNAVAILABLE: "selection_unavailable",
|
|
2612
|
+
ORDER_TYPE_CHANGED: "order_type_changed",
|
|
2613
|
+
REQUEST_SUBMIT: "request_submit"
|
|
2614
|
+
}, ELEMENTS_AUTH_CONTACT_TYPES = {
|
|
2615
|
+
EMAIL: "email",
|
|
2616
|
+
PHONE: "phone"
|
|
2617
|
+
}, ELEMENTS_AUTH_PROMPTS = {
|
|
2618
|
+
LOGIN: "login"
|
|
2619
|
+
}, ELEMENTS_AUTH_MODES = {
|
|
2620
|
+
CHECKOUT: "checkout",
|
|
2621
|
+
DEFAULT: "default"
|
|
2622
|
+
}, EVENT_TYPES = {
|
|
2623
|
+
READY: "ready",
|
|
2624
|
+
AUTHENTICATED: "authenticated",
|
|
2625
|
+
ERROR: "error",
|
|
2626
|
+
CHANGE: "change",
|
|
2627
|
+
BLUR: "blur",
|
|
2628
|
+
FOCUS: "focus",
|
|
2629
|
+
ORDER_TYPE_CHANGED: "order_type_changed",
|
|
2630
|
+
REQUEST_SUBMIT: "request_submit",
|
|
2631
|
+
CHECKOUT_STATUS: "checkout_status",
|
|
2632
|
+
CHECKOUT_COMPLETE: "checkout_complete"
|
|
2633
|
+
};
|
|
2634
|
+
|
|
2635
|
+
// src/internal/pkce.ts
|
|
2636
|
+
async function generatePkce() {
|
|
2637
|
+
let random = new Uint8Array(64);
|
|
2638
|
+
crypto.getRandomValues(random);
|
|
2639
|
+
let verifier = base64UrlEncode(random), digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier)), challenge = base64UrlEncode(new Uint8Array(digest));
|
|
2640
|
+
return { verifier, challenge, method: "S256" };
|
|
2641
|
+
}
|
|
2642
|
+
function generateState(byteLength = 16) {
|
|
2643
|
+
let buf = new Uint8Array(byteLength);
|
|
2644
|
+
return crypto.getRandomValues(buf), base64UrlEncode(buf);
|
|
2645
|
+
}
|
|
2646
|
+
function base64UrlEncode(bytes) {
|
|
2647
|
+
let str = "";
|
|
2648
|
+
for (let byte of bytes) str += String.fromCharCode(byte);
|
|
2649
|
+
return btoa(str).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
2650
|
+
}
|
|
2651
|
+
|
|
2652
|
+
// src/internal/pkce-cookie.ts
|
|
2653
|
+
var PKCE_COOKIE = "cimplify_pkce", PKCE_COOKIE_PATH = "/auth";
|
|
2654
|
+
function encodePkceState(state) {
|
|
2655
|
+
return encodeURIComponent(JSON.stringify(state));
|
|
2656
|
+
}
|
|
2657
|
+
function decodePkceState(raw) {
|
|
2658
|
+
try {
|
|
2659
|
+
let parsed = JSON.parse(decodeURIComponent(raw));
|
|
2660
|
+
if (typeof parsed?.verifier == "string" && typeof parsed.state == "string" && typeof parsed.returnTo == "string")
|
|
2661
|
+
return { verifier: parsed.verifier, state: parsed.state, returnTo: parsed.returnTo };
|
|
2662
|
+
} catch {
|
|
2663
|
+
}
|
|
2664
|
+
return null;
|
|
2665
|
+
}
|
|
2666
|
+
|
|
2667
|
+
// src/internal/discovery.ts
|
|
2668
|
+
var DEFAULT_ISSUER = "https://api.cimplify.io", DEFAULT_AUTHORIZATION_ENDPOINT = "https://auth.cimplify.io/oauth/authorize";
|
|
2669
|
+
function fallbackAuthorizationEndpoint(issuerBase) {
|
|
2670
|
+
if (issuerBase === DEFAULT_ISSUER) return DEFAULT_AUTHORIZATION_ENDPOINT;
|
|
2671
|
+
throw new Error(
|
|
2672
|
+
`OIDC discovery for "${issuerBase}" is unreachable and no fallback authorize endpoint is known for it. Make discovery reachable (enable CORS) or pass authUrl.`
|
|
2673
|
+
);
|
|
2674
|
+
}
|
|
2675
|
+
var cache = /* @__PURE__ */ new Map();
|
|
2676
|
+
function fetchDiscovery(issuer) {
|
|
2677
|
+
let base = issuer.replace(/\/$/, ""), pending = cache.get(base);
|
|
2678
|
+
return pending || (pending = fetch(`${base}/.well-known/openid-configuration`).then((res) => {
|
|
2679
|
+
if (!res.ok) throw new Error(`oidc discovery failed: ${res.status}`);
|
|
2680
|
+
return res.json();
|
|
2681
|
+
}), pending.catch(() => cache.delete(base)), cache.set(base, pending)), pending;
|
|
2682
|
+
}
|
|
2683
|
+
async function getAuthorizationEndpoint(issuer) {
|
|
2684
|
+
let base = issuer.replace(/\/$/, "");
|
|
2685
|
+
try {
|
|
2686
|
+
let doc = await fetchDiscovery(base);
|
|
2687
|
+
if (doc.authorization_endpoint) return doc.authorization_endpoint;
|
|
2688
|
+
} catch {
|
|
2689
|
+
}
|
|
2690
|
+
return fallbackAuthorizationEndpoint(base);
|
|
2691
|
+
}
|
|
2692
|
+
|
|
2693
|
+
// src/internal/modal-iframe.ts
|
|
2694
|
+
function openModalIframe(opts) {
|
|
2695
|
+
let overlay = document.createElement("div");
|
|
2696
|
+
overlay.dataset.cimplifyModal = "1", Object.assign(overlay.style, {
|
|
2697
|
+
position: "fixed",
|
|
2698
|
+
inset: "0",
|
|
2699
|
+
background: "rgba(15, 18, 24, 0.55)",
|
|
2700
|
+
zIndex: "2147483647",
|
|
2701
|
+
display: "grid",
|
|
2702
|
+
placeItems: "center",
|
|
2703
|
+
backdropFilter: "blur(2px)"
|
|
2704
|
+
});
|
|
2705
|
+
let card = document.createElement("div");
|
|
2706
|
+
Object.assign(card.style, {
|
|
2707
|
+
width: `${opts.width ?? 480}px`,
|
|
2708
|
+
maxWidth: "calc(100vw - 24px)",
|
|
2709
|
+
height: `${opts.height ?? 720}px`,
|
|
2710
|
+
maxHeight: "calc(100vh - 32px)"
|
|
2711
|
+
});
|
|
2712
|
+
let iframe = document.createElement("iframe");
|
|
2713
|
+
iframe.src = opts.src, iframe.style.width = "100%", iframe.style.height = "100%", iframe.style.border = "none", iframe.style.background = "transparent", iframe.setAttribute(
|
|
2714
|
+
"sandbox",
|
|
2715
|
+
opts.sandbox ?? "allow-scripts allow-same-origin allow-forms allow-popups"
|
|
2716
|
+
), iframe.setAttribute("allow", "publickey-credentials-get; publickey-credentials-create"), card.appendChild(iframe), overlay.appendChild(card), document.body.appendChild(overlay);
|
|
2717
|
+
let close = () => {
|
|
2718
|
+
overlay.remove(), document.removeEventListener("keydown", onKey), opts.onClose?.();
|
|
2719
|
+
}, onKey = (e) => {
|
|
2720
|
+
e.key === "Escape" && close();
|
|
2721
|
+
};
|
|
2722
|
+
return overlay.addEventListener("click", (e) => {
|
|
2723
|
+
e.target === overlay && close();
|
|
2724
|
+
}), document.addEventListener("keydown", onKey), { iframe, close };
|
|
2725
|
+
}
|
|
2726
|
+
|
|
2727
|
+
// src/sign-in.ts
|
|
2728
|
+
var DEFAULT_SCOPE = "openid email phone profile", DEFAULT_SILENT_TIMEOUT_MS = 900, RESPONSE_TYPE_CODE = "code", RESPONSE_MODE_WEB_MESSAGE = "web_message", RESPONSE_MODE_QUERY = "query", PROMPT_NONE = "none", AUTHORIZATION_RESPONSE_MESSAGE_TYPE = "authorization_response", ERROR_STATE_MISMATCH = "state_mismatch", ERROR_CALLBACK_FAILED = "callback_failed", ERROR_CALLBACK_EXCEPTION = "callback_exception", ERROR_CANCELLED = "cancelled", ERROR_LOGIN_REQUIRED = "login_required", ERROR_CONSENT_REQUIRED = "consent_required", ERROR_INTERACTION_REQUIRED = "interaction_required", INTERACTIVE_AUTH_ERRORS = /* @__PURE__ */ new Set([
|
|
2729
|
+
ERROR_LOGIN_REQUIRED,
|
|
2730
|
+
ERROR_CONSENT_REQUIRED,
|
|
2731
|
+
ERROR_INTERACTION_REQUIRED
|
|
2732
|
+
]);
|
|
2733
|
+
function buildAuthorizeUrl(opts, authorizeEndpoint, pkce, state, urlOpts) {
|
|
2734
|
+
let params = new URLSearchParams({
|
|
2735
|
+
response_type: RESPONSE_TYPE_CODE,
|
|
2736
|
+
response_mode: urlOpts.responseMode,
|
|
2737
|
+
client_id: opts.clientId,
|
|
2738
|
+
redirect_uri: opts.redirectUri,
|
|
2739
|
+
scope: opts.scope ?? DEFAULT_SCOPE,
|
|
2740
|
+
state,
|
|
2741
|
+
code_challenge: pkce.challenge,
|
|
2742
|
+
code_challenge_method: pkce.method
|
|
2743
|
+
});
|
|
2744
|
+
return opts.loginHint && params.set("login_hint", opts.loginHint), urlOpts.prompt && params.set("prompt", urlOpts.prompt), opts.uiMode && params.set("ui_mode", opts.uiMode), `${authorizeEndpoint}?${params.toString()}`;
|
|
2745
|
+
}
|
|
2746
|
+
async function exchangeAuthorizationCode(callbackUri, pkce, state, code) {
|
|
2747
|
+
let res = await fetch(callbackUri, {
|
|
2748
|
+
method: "POST",
|
|
2749
|
+
credentials: "include",
|
|
2750
|
+
headers: { "Content-Type": "application/json" },
|
|
2751
|
+
body: JSON.stringify({ code, codeVerifier: pkce.verifier, state })
|
|
2752
|
+
});
|
|
2753
|
+
if (!res.ok) {
|
|
2754
|
+
let body = await res.text().catch(() => "");
|
|
2755
|
+
throw { error: ERROR_CALLBACK_FAILED, description: body };
|
|
2756
|
+
}
|
|
2757
|
+
let payload = await res.json().catch(() => ({}));
|
|
2758
|
+
return {
|
|
2759
|
+
accessToken: payload.accessToken ?? payload.access_token,
|
|
2760
|
+
expiresIn: payload.expiresIn ?? payload.expires_in,
|
|
2761
|
+
scope: payload.scope
|
|
2762
|
+
};
|
|
2763
|
+
}
|
|
2764
|
+
async function trySilentModalSignIn(opts, authorizeEndpoint, callbackUri, pkce, state) {
|
|
2765
|
+
let expectedOrigin = new URL(authorizeEndpoint).origin, iframe = document.createElement("iframe");
|
|
2766
|
+
return iframe.style.display = "none", iframe.setAttribute("aria-hidden", "true"), iframe.setAttribute("sandbox", "allow-scripts allow-same-origin"), iframe.src = buildAuthorizeUrl(opts, authorizeEndpoint, pkce, state, {
|
|
2767
|
+
responseMode: RESPONSE_MODE_WEB_MESSAGE,
|
|
2768
|
+
prompt: PROMPT_NONE
|
|
2769
|
+
}), new Promise((resolve) => {
|
|
2770
|
+
let settled = false, handler = () => {
|
|
2771
|
+
}, timeout = setTimeout(() => finish(false), opts.silentTimeoutMs ?? (900)), cleanup = () => {
|
|
2772
|
+
window.removeEventListener("message", handler), iframe.remove(), clearTimeout(timeout);
|
|
2773
|
+
}, finish = (handled) => {
|
|
2774
|
+
settled || (settled = true, cleanup(), resolve(handled));
|
|
2775
|
+
};
|
|
2776
|
+
handler = async (event) => {
|
|
2777
|
+
if (event.origin !== expectedOrigin) return;
|
|
2778
|
+
let data = event.data;
|
|
2779
|
+
if (!data || typeof data != "object" || data.type !== AUTHORIZATION_RESPONSE_MESSAGE_TYPE) return;
|
|
2780
|
+
let response = data.response;
|
|
2781
|
+
if (response.error) {
|
|
2782
|
+
if (INTERACTIVE_AUTH_ERRORS.has(response.error)) {
|
|
2783
|
+
finish(false);
|
|
2784
|
+
return;
|
|
2785
|
+
}
|
|
2786
|
+
opts.onError?.({ error: response.error, description: response.error_description }), finish(true);
|
|
2787
|
+
return;
|
|
2788
|
+
}
|
|
2789
|
+
if (response.code) {
|
|
2790
|
+
if (response.state !== state) {
|
|
2791
|
+
opts.onError?.({ error: ERROR_STATE_MISMATCH }), finish(true);
|
|
2792
|
+
return;
|
|
2793
|
+
}
|
|
2794
|
+
try {
|
|
2795
|
+
opts.onSuccess?.(await exchangeAuthorizationCode(callbackUri, pkce, state, response.code));
|
|
2796
|
+
} catch (e) {
|
|
2797
|
+
let err2 = e;
|
|
2798
|
+
opts.onError?.({
|
|
2799
|
+
error: err2.error ?? ERROR_CALLBACK_EXCEPTION,
|
|
2800
|
+
description: err2.description ?? String(e)
|
|
2801
|
+
});
|
|
2802
|
+
}
|
|
2803
|
+
finish(true);
|
|
2804
|
+
}
|
|
2805
|
+
}, window.addEventListener("message", handler), document.body.appendChild(iframe);
|
|
2806
|
+
});
|
|
2807
|
+
}
|
|
2808
|
+
function resolveAuthorizeEndpoint(opts) {
|
|
2809
|
+
return opts.authUrl ? Promise.resolve(`${opts.authUrl.replace(/\/$/, "")}/oauth/authorize`) : getAuthorizationEndpoint(opts.issuer ?? DEFAULT_ISSUER);
|
|
2810
|
+
}
|
|
2811
|
+
async function startSignIn(opts) {
|
|
2812
|
+
let callbackUri = opts.callbackUri ?? "/auth/callback", pkce = await generatePkce(), state = generateState(), authorizeEndpoint = await resolveAuthorizeEndpoint(opts);
|
|
2813
|
+
if ((opts.mode ?? "redirect") === "redirect") {
|
|
2814
|
+
startRedirectSignIn(opts, authorizeEndpoint, pkce, state);
|
|
2815
|
+
return;
|
|
2816
|
+
}
|
|
2817
|
+
if (opts.silentFirst && !opts.prompt && await trySilentModalSignIn(opts, authorizeEndpoint, callbackUri, pkce, state))
|
|
2818
|
+
return;
|
|
2819
|
+
let src = buildAuthorizeUrl(opts, authorizeEndpoint, pkce, state, {
|
|
2820
|
+
responseMode: RESPONSE_MODE_WEB_MESSAGE,
|
|
2821
|
+
prompt: opts.prompt
|
|
2822
|
+
}), expectedOrigin = new URL(authorizeEndpoint).origin, completed = false, handler = () => {
|
|
2823
|
+
}, modal = openModalIframe({
|
|
2824
|
+
src,
|
|
2825
|
+
onClose: () => {
|
|
2826
|
+
window.removeEventListener("message", handler), completed || opts.onError?.({ error: ERROR_CANCELLED });
|
|
2827
|
+
}
|
|
2828
|
+
});
|
|
2829
|
+
handler = async (event) => {
|
|
2830
|
+
if (event.origin !== expectedOrigin) return;
|
|
2831
|
+
let data = event.data;
|
|
2832
|
+
if (!data || typeof data != "object" || data.type !== AUTHORIZATION_RESPONSE_MESSAGE_TYPE) return;
|
|
2833
|
+
let response = data.response;
|
|
2834
|
+
if (response.error) {
|
|
2835
|
+
completed = true, modal.close(), opts.onError?.({ error: response.error, description: response.error_description });
|
|
2836
|
+
return;
|
|
2837
|
+
}
|
|
2838
|
+
if (response.code) {
|
|
2839
|
+
if (response.state !== state) {
|
|
2840
|
+
completed = true, modal.close(), opts.onError?.({ error: ERROR_STATE_MISMATCH });
|
|
2841
|
+
return;
|
|
2842
|
+
}
|
|
2843
|
+
try {
|
|
2844
|
+
let result = await exchangeAuthorizationCode(callbackUri, pkce, state, response.code);
|
|
2845
|
+
completed = !0, modal.close(), opts.onSuccess?.(result);
|
|
2846
|
+
} catch (e) {
|
|
2847
|
+
let err2 = e;
|
|
2848
|
+
completed = true, opts.onError?.({
|
|
2849
|
+
error: err2.error ?? ERROR_CALLBACK_EXCEPTION,
|
|
2850
|
+
description: err2.description ?? String(e)
|
|
2851
|
+
}), modal.close();
|
|
2852
|
+
}
|
|
2853
|
+
}
|
|
2854
|
+
}, window.addEventListener("message", handler);
|
|
2855
|
+
}
|
|
2856
|
+
function startRedirectSignIn(opts, authorizeEndpoint, pkce, state) {
|
|
2857
|
+
let returnTo = opts.returnTo ?? window.location.pathname + window.location.search, cookieValue = encodePkceState({ verifier: pkce.verifier, state, returnTo }), secure = window.location.protocol === "https:" ? "; Secure" : "";
|
|
2858
|
+
document.cookie = `${PKCE_COOKIE}=${cookieValue}; Path=${PKCE_COOKIE_PATH}; Max-Age=${600}; SameSite=Lax${secure}`, window.location.assign(buildAuthorizeUrl(opts, authorizeEndpoint, pkce, state, {
|
|
2859
|
+
responseMode: RESPONSE_MODE_QUERY,
|
|
2860
|
+
prompt: opts.prompt
|
|
2861
|
+
}));
|
|
2862
|
+
}
|
|
2863
|
+
|
|
2864
|
+
// src/internal/events.ts
|
|
2865
|
+
var MUTATION_ERROR = "mutation:error";
|
|
2866
|
+
var AUTH_TOKEN_CHANGED = "auth:token-changed", SESSION_CLAIMED = "session:claimed", SESSION_CLEARED = "session:cleared";
|
|
2867
|
+
function createClientEvents() {
|
|
2868
|
+
let listeners = /* @__PURE__ */ new Map();
|
|
2869
|
+
return {
|
|
2870
|
+
on(name, listener) {
|
|
2871
|
+
let set = listeners.get(name);
|
|
2872
|
+
return set || (set = /* @__PURE__ */ new Set(), listeners.set(name, set)), set.add(listener), () => {
|
|
2873
|
+
set?.delete(listener);
|
|
2874
|
+
};
|
|
2875
|
+
},
|
|
2876
|
+
off(name, listener) {
|
|
2877
|
+
listeners.get(name)?.delete(listener);
|
|
2878
|
+
},
|
|
2879
|
+
emit(name, payload) {
|
|
2880
|
+
let set = listeners.get(name);
|
|
2881
|
+
if (!set) return;
|
|
2882
|
+
let snapshot = Array.from(set);
|
|
2883
|
+
for (let listener of snapshot)
|
|
2884
|
+
try {
|
|
2885
|
+
listener(payload);
|
|
2886
|
+
} catch (err2) {
|
|
2887
|
+
console.error(`[Cimplify] event listener for "${name}" threw:`, err2);
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
};
|
|
2891
|
+
}
|
|
2892
|
+
|
|
2893
|
+
// src/elements.ts
|
|
2894
|
+
function toCheckoutError(code, message, recoverable) {
|
|
2895
|
+
let hint = chunkUCR5HRYM_js.getErrorHint(code);
|
|
2896
|
+
return {
|
|
2897
|
+
success: false,
|
|
2898
|
+
error: {
|
|
2899
|
+
code,
|
|
2900
|
+
message,
|
|
2901
|
+
recoverable,
|
|
2902
|
+
docs_url: hint?.docs_url,
|
|
2903
|
+
suggestion: hint?.suggestion
|
|
2904
|
+
}
|
|
2905
|
+
};
|
|
2906
|
+
}
|
|
2907
|
+
var DEFAULT_LINK_URL = "https://link.cimplify.io", ELEMENT_IFRAME_PERMISSIONS = "geolocation; publickey-credentials-get; publickey-credentials-create", LEGACY_REFRESH_TOKEN_PREFIX = "cimplify.link.rt.", AUTH_CONTACT_TYPES = new Set(Object.values(ELEMENTS_AUTH_CONTACT_TYPES)), AUTH_MODES = new Set(Object.values(ELEMENTS_AUTH_MODES)), AUTH_PROMPTS = new Set(Object.values(ELEMENTS_AUTH_PROMPTS));
|
|
2908
|
+
function generateNonce() {
|
|
2909
|
+
return typeof crypto < "u" && crypto.randomUUID ? crypto.randomUUID().replace(/-/g, "").slice(0, 16) : Math.random().toString(36).slice(2) + Math.random().toString(36).slice(2);
|
|
2910
|
+
}
|
|
2911
|
+
function readPublicEnv(name) {
|
|
2912
|
+
try {
|
|
2913
|
+
let value = globalThis.process?.env?.[name];
|
|
2914
|
+
return value && value.trim() ? value : void 0;
|
|
2915
|
+
} catch {
|
|
2916
|
+
return;
|
|
2917
|
+
}
|
|
2918
|
+
}
|
|
2919
|
+
function decodeJwtSub(token) {
|
|
2920
|
+
let [, payload] = token.split(".");
|
|
2921
|
+
if (!payload || typeof atob > "u") return "";
|
|
2922
|
+
try {
|
|
2923
|
+
let base64 = payload.replace(/-/g, "+").replace(/_/g, "/"), padded = base64.padEnd(base64.length + (4 - base64.length % 4) % 4, "="), parsed = JSON.parse(atob(padded));
|
|
2924
|
+
return typeof parsed.sub == "string" ? parsed.sub : "";
|
|
2925
|
+
} catch {
|
|
2926
|
+
return "";
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
function isClaimedCustomer(value) {
|
|
2930
|
+
if (!value || typeof value != "object") return false;
|
|
2931
|
+
let record = value;
|
|
2932
|
+
return typeof record.id == "string" && typeof record.name == "string" && (record.email === null || typeof record.email == "string") && (record.phone === null || typeof record.phone == "string");
|
|
2933
|
+
}
|
|
2934
|
+
function isAllowedOrigin(origin) {
|
|
2935
|
+
try {
|
|
2936
|
+
let url = new URL(origin), hostname = url.hostname;
|
|
2937
|
+
return hostname === "localhost" || hostname === "127.0.0.1" ? !0 : url.protocol !== "https:" ? !1 : hostname === "cimplify.io" || hostname.endsWith(".cimplify.io");
|
|
2938
|
+
} catch {
|
|
2939
|
+
return false;
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
var KNOWN_IFRAME_TYPES = /* @__PURE__ */ new Set([
|
|
2943
|
+
MESSAGE_TYPES.READY,
|
|
2944
|
+
MESSAGE_TYPES.HEIGHT_CHANGE,
|
|
2945
|
+
MESSAGE_TYPES.AUTH_REQUESTED,
|
|
2946
|
+
MESSAGE_TYPES.SESSION_ESTABLISHED,
|
|
2947
|
+
MESSAGE_TYPES.CONTINUE_WITHOUT_SAVED_DETAILS,
|
|
2948
|
+
MESSAGE_TYPES.ERROR,
|
|
2949
|
+
MESSAGE_TYPES.ADDRESS_CHANGED,
|
|
2950
|
+
MESSAGE_TYPES.ADDRESS_SELECTED,
|
|
2951
|
+
MESSAGE_TYPES.PAYMENT_METHOD_SELECTED,
|
|
2952
|
+
MESSAGE_TYPES.CONTACT_PROVIDED,
|
|
2953
|
+
MESSAGE_TYPES.LOGOUT_COMPLETE,
|
|
2954
|
+
MESSAGE_TYPES.CHECKOUT_STATUS,
|
|
2955
|
+
MESSAGE_TYPES.CHECKOUT_COMPLETE,
|
|
2956
|
+
MESSAGE_TYPES.TERMS_CHANGED,
|
|
2957
|
+
MESSAGE_TYPES.SELECTION_UNAVAILABLE,
|
|
2958
|
+
MESSAGE_TYPES.ORDER_TYPE_CHANGED,
|
|
2959
|
+
MESSAGE_TYPES.REQUEST_SUBMIT
|
|
2960
|
+
]);
|
|
2961
|
+
function parseIframeMessage(data) {
|
|
2962
|
+
if (!data || typeof data != "object")
|
|
2963
|
+
return null;
|
|
2964
|
+
let record = data;
|
|
2965
|
+
if (typeof record.type != "string" || !KNOWN_IFRAME_TYPES.has(record.type))
|
|
2966
|
+
return null;
|
|
2967
|
+
switch (record.type) {
|
|
2968
|
+
case MESSAGE_TYPES.AUTH_REQUESTED:
|
|
2969
|
+
if (record.loginHint !== void 0 && typeof record.loginHint != "string" || record.contactType !== void 0 && (typeof record.contactType != "string" || !AUTH_CONTACT_TYPES.has(record.contactType)) || record.mode !== void 0 && (typeof record.mode != "string" || !AUTH_MODES.has(record.mode)) || record.prompt !== void 0 && (typeof record.prompt != "string" || !AUTH_PROMPTS.has(record.prompt)))
|
|
2970
|
+
return null;
|
|
2971
|
+
break;
|
|
2972
|
+
case MESSAGE_TYPES.SESSION_ESTABLISHED:
|
|
2973
|
+
return typeof record.sessionToken != "string" || !record.sessionToken.trim() || !isClaimedCustomer(record.customer) ? null : {
|
|
2974
|
+
type: MESSAGE_TYPES.SESSION_ESTABLISHED,
|
|
2975
|
+
sessionToken: record.sessionToken,
|
|
2976
|
+
customer: record.customer,
|
|
2977
|
+
...typeof record.nonce == "string" ? { nonce: record.nonce } : {}
|
|
2978
|
+
};
|
|
2979
|
+
case MESSAGE_TYPES.ADDRESS_CHANGED:
|
|
2980
|
+
case MESSAGE_TYPES.ADDRESS_SELECTED:
|
|
2981
|
+
if (!record.address || typeof record.address != "object") return null;
|
|
2982
|
+
break;
|
|
2983
|
+
case MESSAGE_TYPES.PAYMENT_METHOD_SELECTED:
|
|
2984
|
+
if (!record.method || typeof record.method != "object") return null;
|
|
2985
|
+
break;
|
|
2986
|
+
case MESSAGE_TYPES.CONTACT_PROVIDED:
|
|
2987
|
+
case MESSAGE_TYPES.CONTINUE_WITHOUT_SAVED_DETAILS:
|
|
2988
|
+
if (typeof record.contact != "string" || typeof record.contactType != "string") return null;
|
|
2989
|
+
break;
|
|
2990
|
+
case MESSAGE_TYPES.ERROR:
|
|
2991
|
+
if (typeof record.code != "string" || typeof record.message != "string") return null;
|
|
2992
|
+
break;
|
|
2993
|
+
case MESSAGE_TYPES.CHECKOUT_COMPLETE:
|
|
2994
|
+
if (typeof record.success != "boolean") return null;
|
|
2995
|
+
break;
|
|
2996
|
+
case MESSAGE_TYPES.CHECKOUT_STATUS:
|
|
2997
|
+
if (typeof record.status != "string" || !record.context || typeof record.context != "object")
|
|
2998
|
+
return null;
|
|
2999
|
+
break;
|
|
3000
|
+
case MESSAGE_TYPES.TERMS_CHANGED:
|
|
3001
|
+
if (typeof record.intent_id != "string" || !record.replacement || typeof record.replacement != "object" || !Array.isArray(record.deltas))
|
|
3002
|
+
return null;
|
|
3003
|
+
break;
|
|
3004
|
+
case MESSAGE_TYPES.SELECTION_UNAVAILABLE:
|
|
3005
|
+
if (typeof record.intent_id != "string" || !Array.isArray(record.lines)) return null;
|
|
3006
|
+
break;
|
|
3007
|
+
case MESSAGE_TYPES.READY:
|
|
3008
|
+
case MESSAGE_TYPES.HEIGHT_CHANGE:
|
|
3009
|
+
if (typeof record.height != "number") return null;
|
|
3010
|
+
break;
|
|
3011
|
+
case MESSAGE_TYPES.ORDER_TYPE_CHANGED:
|
|
3012
|
+
if (typeof record.orderType != "string") return null;
|
|
3013
|
+
break;
|
|
3014
|
+
}
|
|
3015
|
+
return data;
|
|
3016
|
+
}
|
|
3017
|
+
var CimplifyElements = class {
|
|
3018
|
+
constructor(client, businessId, options = {}) {
|
|
3019
|
+
this.elements = /* @__PURE__ */ new Map();
|
|
3020
|
+
this.accessToken = null;
|
|
3021
|
+
this.sessionAuthenticated = false;
|
|
3022
|
+
this.accountId = null;
|
|
3023
|
+
this.customerId = null;
|
|
3024
|
+
this.customerData = null;
|
|
3025
|
+
this.addressData = null;
|
|
3026
|
+
this.paymentData = null;
|
|
3027
|
+
this.checkoutInProgress = false;
|
|
3028
|
+
this.authInProgress = false;
|
|
3029
|
+
this.authGeneration = 0;
|
|
3030
|
+
this.activeCheckoutAbort = null;
|
|
3031
|
+
this.businessIdResolvePromise = null;
|
|
3032
|
+
this.stopSessionSync = () => {
|
|
3033
|
+
};
|
|
3034
|
+
this.client = client, this.businessId = businessId ?? null, this.linkUrl = options.linkUrl || DEFAULT_LINK_URL, this.options = options, this.boundHandleMessage = this.handleMessage.bind(this), typeof window < "u" && window.addEventListener("message", this.boundHandleMessage), this.stopSessionSync = client.events.on(SESSION_CLAIMED, () => {
|
|
3035
|
+
this.authInProgress || this._syncHostSession();
|
|
3036
|
+
}), this.restoreSession();
|
|
3037
|
+
}
|
|
3038
|
+
debug(...args) {
|
|
3039
|
+
this.client.isTestMode() && console.debug(...args);
|
|
3040
|
+
}
|
|
3041
|
+
_syncHostSession(element) {
|
|
3042
|
+
let sessionToken = this.client.getSessionToken();
|
|
3043
|
+
if (!sessionToken) return;
|
|
3044
|
+
let identity = {
|
|
3045
|
+
type: MESSAGE_TYPES.IDENTITY,
|
|
3046
|
+
sessionToken,
|
|
3047
|
+
accessToken: this.client.getAccessToken() ?? this.accessToken,
|
|
3048
|
+
customer: this.identityCustomer()
|
|
3049
|
+
}, targets = element ? [element] : Array.from(this.elements.values());
|
|
3050
|
+
for (let target of targets)
|
|
3051
|
+
target.sendMessage(identity);
|
|
3052
|
+
}
|
|
3053
|
+
identityCustomer() {
|
|
3054
|
+
return !this.isAuthenticated() || !this.customerId || !this.customerData ? null : { id: this.customerId, ...this.customerData };
|
|
3055
|
+
}
|
|
3056
|
+
forgetIdentity() {
|
|
3057
|
+
this.accessToken = null, this.sessionAuthenticated = false, this.accountId = null, this.customerId = null, this.customerData = null, this.addressData = null, this.paymentData = null;
|
|
3058
|
+
}
|
|
3059
|
+
create(type, options = {}) {
|
|
3060
|
+
let existing = this.elements.get(type);
|
|
3061
|
+
if (existing) return existing;
|
|
3062
|
+
let element = new CimplifyElement(type, this.businessId, this.linkUrl, options, this);
|
|
3063
|
+
return this.elements.set(type, element), element;
|
|
3064
|
+
}
|
|
3065
|
+
getElement(type) {
|
|
3066
|
+
return this.elements.get(type);
|
|
3067
|
+
}
|
|
3068
|
+
_removeElement(type, instance) {
|
|
3069
|
+
this.elements.get(type) === instance && this.elements.delete(type);
|
|
3070
|
+
}
|
|
3071
|
+
destroy() {
|
|
3072
|
+
this.authGeneration += 1, this.authInProgress = false, this.stopSessionSync(), this.stopSessionSync = () => {
|
|
3073
|
+
}, this.elements.forEach((element) => element.destroy()), this.elements.clear(), typeof window < "u" && window.removeEventListener("message", this.boundHandleMessage);
|
|
3074
|
+
}
|
|
3075
|
+
async submitCheckout(data) {
|
|
3076
|
+
let result = await this.processCheckout({
|
|
3077
|
+
cart_id: data.cart_id,
|
|
3078
|
+
intent_id: data.intent_id,
|
|
3079
|
+
hosted_session_id: data.hosted_session_id,
|
|
3080
|
+
initial_terms: data.initial_terms,
|
|
3081
|
+
order_type: data.order_type ?? chunkGTJWQAGU_js.ORDER_TYPE.DELIVERY,
|
|
3082
|
+
location_id: data.location_id,
|
|
3083
|
+
notes: data.notes,
|
|
3084
|
+
scheduled_time: data.scheduled_time,
|
|
3085
|
+
tip_amount: data.tip_amount,
|
|
3086
|
+
enroll_in_link: data.enroll_in_link
|
|
3087
|
+
});
|
|
3088
|
+
return result.success ? {
|
|
3089
|
+
success: true,
|
|
3090
|
+
order: {
|
|
3091
|
+
id: result.order?.id || "",
|
|
3092
|
+
status: result.order?.status || chunkGTJWQAGU_js.CHECKOUT_ORDER_RESULT_STATUS.UNKNOWN,
|
|
3093
|
+
total: result.order?.total || ""
|
|
3094
|
+
}
|
|
3095
|
+
} : {
|
|
3096
|
+
success: false,
|
|
3097
|
+
error: {
|
|
3098
|
+
code: result.error?.code || chunkUCR5HRYM_js.ErrorCode.CHECKOUT_FAILED,
|
|
3099
|
+
message: result.error?.message || "Checkout failed"
|
|
3100
|
+
}
|
|
3101
|
+
};
|
|
3102
|
+
}
|
|
3103
|
+
processCheckout(options) {
|
|
3104
|
+
let abortFn = null, abortable = (async () => {
|
|
3105
|
+
if (this.debug("[cimplify:checkout] processCheckout called", {
|
|
3106
|
+
cart_id: options.cart_id,
|
|
3107
|
+
intent_id: options.intent_id,
|
|
3108
|
+
hosted_session_id: options.hosted_session_id,
|
|
3109
|
+
order_type: options.order_type,
|
|
3110
|
+
location_id: options.location_id
|
|
3111
|
+
}), typeof options.tip_amount == "number" && options.tip_amount > 0)
|
|
3112
|
+
return toCheckoutError(
|
|
3113
|
+
chunkUCR5HRYM_js.ErrorCode.TIP_NOT_SUPPORTED,
|
|
3114
|
+
"Tips are not part of checkout. Remove the tip and try again.",
|
|
3115
|
+
false
|
|
3116
|
+
);
|
|
3117
|
+
if (this.checkoutInProgress)
|
|
3118
|
+
return this.debug("[cimplify:checkout] BLOCKED: already processing"), toCheckoutError(
|
|
3119
|
+
chunkUCR5HRYM_js.ErrorCode.ALREADY_PROCESSING,
|
|
3120
|
+
"Checkout is already in progress.",
|
|
3121
|
+
false
|
|
3122
|
+
);
|
|
3123
|
+
if (this.checkoutInProgress = true, !options.cart_id && !options.intent_id)
|
|
3124
|
+
return this.debug("[cimplify:checkout] BLOCKED: no cart_id or intent_id"), this.checkoutInProgress = false, toCheckoutError(
|
|
3125
|
+
chunkUCR5HRYM_js.ErrorCode.CHECKOUT_AUTHORITY_REQUIRED,
|
|
3126
|
+
"A cart or existing purchase intent is required before checkout can start.",
|
|
3127
|
+
false
|
|
3128
|
+
);
|
|
3129
|
+
if (!options.order_type)
|
|
3130
|
+
return this.debug("[cimplify:checkout] BLOCKED: no order_type"), this.checkoutInProgress = false, toCheckoutError(
|
|
3131
|
+
chunkUCR5HRYM_js.ErrorCode.ORDER_TYPE_REQUIRED,
|
|
3132
|
+
"Order type is required before checkout can start.",
|
|
3133
|
+
false
|
|
3134
|
+
);
|
|
3135
|
+
let checkoutElement = this.elements.get(ELEMENT_TYPES.CHECKOUT) || this.elements.get(ELEMENT_TYPES.PAYMENT);
|
|
3136
|
+
if (!checkoutElement)
|
|
3137
|
+
return this.debug("[cimplify:checkout] BLOCKED: no checkout element"), this.checkoutInProgress = false, toCheckoutError(
|
|
3138
|
+
chunkUCR5HRYM_js.ErrorCode.NO_PAYMENT_ELEMENT,
|
|
3139
|
+
"Checkout element must be mounted before checkout.",
|
|
3140
|
+
false
|
|
3141
|
+
);
|
|
3142
|
+
if (!checkoutElement.isMounted())
|
|
3143
|
+
return this.debug("[cimplify:checkout] BLOCKED: checkout element not mounted"), this.checkoutInProgress = false, toCheckoutError(
|
|
3144
|
+
chunkUCR5HRYM_js.ErrorCode.PAYMENT_NOT_MOUNTED,
|
|
3145
|
+
"Checkout element must be mounted before checkout.",
|
|
3146
|
+
false
|
|
3147
|
+
);
|
|
3148
|
+
let isUnifiedCheckout = this.elements.has(ELEMENT_TYPES.CHECKOUT);
|
|
3149
|
+
if (!isUnifiedCheckout) {
|
|
3150
|
+
if (this.elements.get(ELEMENT_TYPES.AUTH) && !this.isAuthenticated())
|
|
3151
|
+
return this.debug("[cimplify:checkout] BLOCKED: auth incomplete"), this.checkoutInProgress = false, toCheckoutError(
|
|
3152
|
+
chunkUCR5HRYM_js.ErrorCode.AUTH_INCOMPLETE,
|
|
3153
|
+
"Authentication must complete before checkout can start.",
|
|
3154
|
+
true
|
|
3155
|
+
);
|
|
3156
|
+
let addressElement = this.elements.get(ELEMENT_TYPES.ADDRESS);
|
|
3157
|
+
addressElement && (this.debug("[cimplify:checkout] getting address data..."), await addressElement.getData(), this.debug("[cimplify:checkout] address data resolved", this.addressData)), await this.hydrateCustomerData();
|
|
3158
|
+
}
|
|
3159
|
+
this.debug("[cimplify:checkout] customer data hydrated", {
|
|
3160
|
+
customerData: this.customerData,
|
|
3161
|
+
accountId: this.accountId,
|
|
3162
|
+
isUnifiedCheckout
|
|
3163
|
+
});
|
|
3164
|
+
let processMessage = {
|
|
3165
|
+
type: MESSAGE_TYPES.PROCESS_CHECKOUT,
|
|
3166
|
+
// Existing intent authority wins if a compatibility caller supplied
|
|
3167
|
+
// both values; the iframe must never mint a replacement.
|
|
3168
|
+
cart_id: options.intent_id ? void 0 : options.cart_id,
|
|
3169
|
+
intent_id: options.intent_id,
|
|
3170
|
+
hosted_session_id: options.hosted_session_id,
|
|
3171
|
+
initial_terms: options.intent_id ? options.initial_terms : void 0,
|
|
3172
|
+
order_type: options.order_type,
|
|
3173
|
+
location_id: options.location_id,
|
|
3174
|
+
notes: options.notes,
|
|
3175
|
+
scheduled_time: options.scheduled_time,
|
|
3176
|
+
pay_currency: options.pay_currency,
|
|
3177
|
+
enroll_in_link: options.enroll_in_link,
|
|
3178
|
+
address: isUnifiedCheckout ? void 0 : this.addressData ?? void 0,
|
|
3179
|
+
customer: isUnifiedCheckout ? void 0 : this.customerData ? {
|
|
3180
|
+
name: this.customerData.name,
|
|
3181
|
+
email: this.customerData.email,
|
|
3182
|
+
phone: this.customerData.phone
|
|
3183
|
+
} : null,
|
|
3184
|
+
account_id: this.accountId ?? void 0,
|
|
3185
|
+
customer_id: this.customerId ?? void 0
|
|
3186
|
+
}, inactivityTimeoutMs = options.timeout_ms ?? 18e4, shopperPendingStatuses = /* @__PURE__ */ new Set([
|
|
3187
|
+
chunkGTJWQAGU_js.CHECKOUT_STATUS.REVIEWING_TERMS,
|
|
3188
|
+
chunkGTJWQAGU_js.CHECKOUT_STATUS.AWAITING_AUTHORIZATION
|
|
3189
|
+
]);
|
|
3190
|
+
return new Promise((resolve) => {
|
|
3191
|
+
let settled = false, timeout, cleanup = () => {
|
|
3192
|
+
typeof window < "u" && window.removeEventListener("message", handleCheckoutMessage), clearTimeout(timeout), this.checkoutInProgress = false, this.activeCheckoutAbort = null;
|
|
3193
|
+
}, settle = (result) => {
|
|
3194
|
+
settled || (settled = true, cleanup(), resolve(result));
|
|
3195
|
+
}, armTimeout = () => {
|
|
3196
|
+
clearTimeout(timeout), timeout = setTimeout(() => {
|
|
3197
|
+
settle(
|
|
3198
|
+
toCheckoutError(
|
|
3199
|
+
chunkUCR5HRYM_js.ErrorCode.TIMEOUT,
|
|
3200
|
+
"Checkout timed out before receiving a terminal response.",
|
|
3201
|
+
true
|
|
3202
|
+
)
|
|
3203
|
+
);
|
|
3204
|
+
}, inactivityTimeoutMs);
|
|
3205
|
+
}, suspendTimeout = () => {
|
|
3206
|
+
clearTimeout(timeout), timeout = void 0;
|
|
3207
|
+
};
|
|
3208
|
+
armTimeout();
|
|
3209
|
+
let handleCheckoutMessage = (event) => {
|
|
3210
|
+
if (!isAllowedOrigin(event.origin))
|
|
3211
|
+
return;
|
|
3212
|
+
let message = parseIframeMessage(event.data);
|
|
3213
|
+
if (message && checkoutElement._acceptsMessageEvent(event, message)) {
|
|
3214
|
+
if (message.type === MESSAGE_TYPES.CHECKOUT_STATUS) {
|
|
3215
|
+
shopperPendingStatuses.has(message.status) ? suspendTimeout() : armTimeout(), options.on_status_change?.(message.status, message.context);
|
|
3216
|
+
return;
|
|
3217
|
+
}
|
|
3218
|
+
if (message.type === MESSAGE_TYPES.TERMS_CHANGED) {
|
|
3219
|
+
suspendTimeout(), options.on_status_change?.(chunkGTJWQAGU_js.CHECKOUT_STATUS.REVIEWING_TERMS, {
|
|
3220
|
+
intent_id: message.intent_id,
|
|
3221
|
+
replacement_terms: message.replacement,
|
|
3222
|
+
terms_deltas: message.deltas
|
|
3223
|
+
});
|
|
3224
|
+
return;
|
|
3225
|
+
}
|
|
3226
|
+
if (message.type === MESSAGE_TYPES.SELECTION_UNAVAILABLE) {
|
|
3227
|
+
suspendTimeout(), options.on_status_change?.(chunkGTJWQAGU_js.CHECKOUT_STATUS.REVIEWING_TERMS, {
|
|
3228
|
+
intent_id: message.intent_id,
|
|
3229
|
+
unavailable_lines: message.lines
|
|
3230
|
+
});
|
|
3231
|
+
return;
|
|
3232
|
+
}
|
|
3233
|
+
message.type === MESSAGE_TYPES.CHECKOUT_COMPLETE && (this.debug("[cimplify:checkout] received checkout_complete", {
|
|
3234
|
+
success: message.success,
|
|
3235
|
+
error: message.error
|
|
3236
|
+
}), settle({
|
|
3237
|
+
success: message.success,
|
|
3238
|
+
order: message.order,
|
|
3239
|
+
error: message.error,
|
|
3240
|
+
enrolled_in_link: message.enrolled_in_link
|
|
3241
|
+
})), message.type === MESSAGE_TYPES.LOGOUT_COMPLETE && (checkoutElement.sendMessage({ type: MESSAGE_TYPES.ABORT_CHECKOUT }), settle(
|
|
3242
|
+
toCheckoutError(
|
|
3243
|
+
chunkUCR5HRYM_js.ErrorCode.AUTH_LOST,
|
|
3244
|
+
"Authentication was cleared during checkout.",
|
|
3245
|
+
true
|
|
3246
|
+
)
|
|
3247
|
+
));
|
|
3248
|
+
}
|
|
3249
|
+
};
|
|
3250
|
+
typeof window < "u" && window.addEventListener("message", handleCheckoutMessage), abortFn = () => {
|
|
3251
|
+
checkoutElement.sendMessage({ type: MESSAGE_TYPES.ABORT_CHECKOUT }), settle(toCheckoutError(chunkUCR5HRYM_js.ErrorCode.CANCELLED, "Checkout was cancelled.", true));
|
|
3252
|
+
}, this.activeCheckoutAbort = abortFn, this.debug("[cimplify:checkout] sending process_checkout to checkout iframe", {
|
|
3253
|
+
cart_id: processMessage.cart_id,
|
|
3254
|
+
intent_id: processMessage.intent_id,
|
|
3255
|
+
hosted_session_id: processMessage.hosted_session_id,
|
|
3256
|
+
order_type: processMessage.order_type,
|
|
3257
|
+
hasCustomer: !!processMessage.customer,
|
|
3258
|
+
hasAddress: !!processMessage.address,
|
|
3259
|
+
isUnifiedCheckout
|
|
3260
|
+
}), this._syncHostSession(checkoutElement), checkoutElement.sendMessage(processMessage), this.debug("[cimplify:checkout] postMessage sent, waiting for checkout_complete...");
|
|
3261
|
+
});
|
|
3262
|
+
})();
|
|
3263
|
+
return abortable.abort = () => {
|
|
3264
|
+
abortFn && abortFn();
|
|
3265
|
+
}, abortable;
|
|
3266
|
+
}
|
|
3267
|
+
isAuthenticated() {
|
|
3268
|
+
return this.accessToken !== null || this.sessionAuthenticated;
|
|
3269
|
+
}
|
|
3270
|
+
getAccessToken() {
|
|
3271
|
+
return this.accessToken;
|
|
3272
|
+
}
|
|
3273
|
+
getPublicKey() {
|
|
3274
|
+
return this.client.getPublicKey();
|
|
3275
|
+
}
|
|
3276
|
+
getSessionToken() {
|
|
3277
|
+
return this.client.getSessionToken();
|
|
3278
|
+
}
|
|
3279
|
+
getBusinessId() {
|
|
3280
|
+
return this.businessId;
|
|
3281
|
+
}
|
|
3282
|
+
async resolveBusinessId() {
|
|
3283
|
+
return this.businessId ? this.businessId : this.businessIdResolvePromise ? this.businessIdResolvePromise : (this.businessIdResolvePromise = this.client.resolveBusinessId().then((resolvedBusinessId) => (this.businessId = resolvedBusinessId, resolvedBusinessId)).catch(() => null).finally(() => {
|
|
3284
|
+
this.businessIdResolvePromise = null;
|
|
3285
|
+
}), this.businessIdResolvePromise);
|
|
3286
|
+
}
|
|
3287
|
+
/** @internal Whether a `processCheckout` call is waiting on the checkout element. */
|
|
3288
|
+
_isCheckoutInProgress() {
|
|
3289
|
+
return this.checkoutInProgress;
|
|
3290
|
+
}
|
|
3291
|
+
getAppearance() {
|
|
3292
|
+
return this.options.appearance;
|
|
3293
|
+
}
|
|
3294
|
+
isAuthGenerationCurrent(generation, token) {
|
|
3295
|
+
return this.authGeneration === generation && this.client.getAccessToken() === token;
|
|
3296
|
+
}
|
|
3297
|
+
async hydrateCustomerData(generation = this.authGeneration, token = this.accessToken, force = false) {
|
|
3298
|
+
if (!token || !this.isAuthGenerationCurrent(generation, token)) return false;
|
|
3299
|
+
if (this.customerData && !force) return true;
|
|
3300
|
+
let linkDataResult = await this.client.link.getLinkData();
|
|
3301
|
+
if (!this.isAuthGenerationCurrent(generation, token)) return false;
|
|
3302
|
+
if (!linkDataResult.ok || !linkDataResult.value?.customer)
|
|
3303
|
+
return true;
|
|
3304
|
+
let customer = linkDataResult.value.customer;
|
|
3305
|
+
return this.customerData = {
|
|
3306
|
+
name: customer.name || "",
|
|
3307
|
+
email: customer.email || null,
|
|
3308
|
+
phone: customer.phone || null
|
|
3309
|
+
}, this.customerId = customer.id, true;
|
|
3310
|
+
}
|
|
3311
|
+
sourceElementFor(event, message) {
|
|
3312
|
+
for (let element of this.elements.values())
|
|
3313
|
+
if (element._acceptsMessageEvent(event, message))
|
|
3314
|
+
return element;
|
|
3315
|
+
return null;
|
|
3316
|
+
}
|
|
3317
|
+
/** Earlier SDK versions kept the account-wide Link refresh token here. It
|
|
3318
|
+
* is removed on sight and never read. */
|
|
3319
|
+
dropLegacyRefreshToken() {
|
|
3320
|
+
if (typeof window > "u") return;
|
|
3321
|
+
let key = this.client.getPublicKey().trim();
|
|
3322
|
+
if (key)
|
|
3323
|
+
try {
|
|
3324
|
+
window.localStorage.removeItem(`${LEGACY_REFRESH_TOKEN_PREFIX}${key}`);
|
|
3325
|
+
} catch {
|
|
3326
|
+
return;
|
|
3327
|
+
}
|
|
3328
|
+
}
|
|
3329
|
+
sessionAuthenticatedData() {
|
|
3330
|
+
let sessionToken = this.client.getSessionToken();
|
|
3331
|
+
return !sessionToken || !this.customerId || !this.customerData ? null : {
|
|
3332
|
+
accountId: "",
|
|
3333
|
+
customerId: this.customerId,
|
|
3334
|
+
token: sessionToken,
|
|
3335
|
+
customer: this.customerData
|
|
3336
|
+
};
|
|
3337
|
+
}
|
|
3338
|
+
/**
|
|
3339
|
+
* A reload keeps the shopper signed in through the storefront session the
|
|
3340
|
+
* element claimed for this business. The page asks the storefront API who
|
|
3341
|
+
* that session belongs to; no Link credential is involved.
|
|
3342
|
+
*/
|
|
3343
|
+
async restoreSession() {
|
|
3344
|
+
if (this.dropLegacyRefreshToken(), typeof window > "u" || this.isAuthenticated() || !this.client.hasClaimedSessionAuthority()) return;
|
|
3345
|
+
let generation = ++this.authGeneration, sessionEpoch = this.client.getSessionEpoch(), status = await this.client.auth.getStatus();
|
|
3346
|
+
if (this.authGeneration !== generation || this.client.getSessionEpoch() !== sessionEpoch || !status.ok) return;
|
|
3347
|
+
let customer = status.value.customer;
|
|
3348
|
+
if (!status.value.is_authenticated || !customer?.id) {
|
|
3349
|
+
this.forgetIdentity(), this.client.clearSession(), this.broadcastClearedSession();
|
|
3350
|
+
return;
|
|
3351
|
+
}
|
|
3352
|
+
this.sessionAuthenticated = true, this.customerId = customer.id, this.customerData = {
|
|
3353
|
+
name: customer.name || "",
|
|
3354
|
+
email: customer.email || null,
|
|
3355
|
+
phone: customer.phone || null
|
|
3356
|
+
};
|
|
3357
|
+
let data = this.sessionAuthenticatedData();
|
|
3358
|
+
this._syncHostSession(), data && this.elements.forEach((element) => element._emitAuthenticated(data));
|
|
3359
|
+
}
|
|
3360
|
+
async applyAccessToken(token, generation) {
|
|
3361
|
+
if (this.authGeneration !== generation) return { kind: "incomplete" };
|
|
3362
|
+
this.forgetIdentity(), this.client.setAccessToken(token);
|
|
3363
|
+
let claim = await this.client.session.claim();
|
|
3364
|
+
return this.isAuthGenerationCurrent(generation, token) ? !claim.ok && claim.error.code !== "already_claimed" ? (this.client.hasClaimedSessionAuthority() ? this.client.clearSession() : this.client.setAccessToken(null), {
|
|
3365
|
+
kind: "claim_failed",
|
|
3366
|
+
code: claim.error.code,
|
|
3367
|
+
message: claim.error.userMessage
|
|
3368
|
+
}) : (this.accessToken = token, this.accountId = decodeJwtSub(token), await this.hydrateCustomerData(generation, token, true) ? this.isAuthGenerationCurrent(generation, token) ? {
|
|
3369
|
+
kind: "authenticated",
|
|
3370
|
+
data: {
|
|
3371
|
+
accountId: this.accountId ?? "",
|
|
3372
|
+
customerId: this.customerId ?? "",
|
|
3373
|
+
token,
|
|
3374
|
+
customer: this.customerData ?? { name: "", email: null, phone: null }
|
|
3375
|
+
}
|
|
3376
|
+
} : { kind: "incomplete" } : { kind: "incomplete" }) : { kind: "incomplete" };
|
|
3377
|
+
}
|
|
3378
|
+
adoptEstablishedSession(sourceElement, session) {
|
|
3379
|
+
this.authGeneration += 1, this.authInProgress = false;
|
|
3380
|
+
let { id, ...customer } = session.customer;
|
|
3381
|
+
this.forgetIdentity(), this.client.getAccessToken() && this.client.setAccessToken(null), this.sessionAuthenticated = true, this.customerId = id, this.customerData = customer, this.client.session.adopt(null, {
|
|
3382
|
+
sessionToken: session.sessionToken,
|
|
3383
|
+
customerName: session.customer.name,
|
|
3384
|
+
customer: session.customer,
|
|
3385
|
+
cart: null
|
|
3386
|
+
}), sourceElement._emitAuthenticated({
|
|
3387
|
+
accountId: "",
|
|
3388
|
+
customerId: id,
|
|
3389
|
+
token: session.sessionToken,
|
|
3390
|
+
customer
|
|
3391
|
+
});
|
|
3392
|
+
}
|
|
3393
|
+
broadcastClearedSession() {
|
|
3394
|
+
let sessionToken = this.client.getSessionToken();
|
|
3395
|
+
return sessionToken ? (this.elements.forEach((element) => {
|
|
3396
|
+
element.sendMessage({ type: MESSAGE_TYPES.SESSION_CLEARED, sessionToken });
|
|
3397
|
+
}), sessionToken) : null;
|
|
3398
|
+
}
|
|
3399
|
+
startEmbeddedAuth(sourceElement, request) {
|
|
3400
|
+
if (this.authInProgress) return;
|
|
3401
|
+
let auth = this.options.auth ?? {}, clientId = auth.clientId ?? readPublicEnv("NEXT_PUBLIC_CIMPLIFY_CLIENT_ID"), redirectUri = auth.redirectUri ?? readPublicEnv("NEXT_PUBLIC_CIMPLIFY_REDIRECT_URI");
|
|
3402
|
+
if (!clientId || !redirectUri) {
|
|
3403
|
+
sourceElement._emitError({
|
|
3404
|
+
code: chunkUCR5HRYM_js.ErrorCode.AUTH_CONFIG_REQUIRED,
|
|
3405
|
+
message: "Cimplify OAuth clientId and redirectUri are required."
|
|
3406
|
+
});
|
|
3407
|
+
return;
|
|
3408
|
+
}
|
|
3409
|
+
let generation = ++this.authGeneration;
|
|
3410
|
+
this.authInProgress = true, startSignIn({
|
|
3411
|
+
clientId,
|
|
3412
|
+
redirectUri,
|
|
3413
|
+
callbackUri: auth.callbackUri,
|
|
3414
|
+
scope: auth.scope,
|
|
3415
|
+
issuer: auth.issuer,
|
|
3416
|
+
authUrl: auth.authUrl,
|
|
3417
|
+
loginHint: request.loginHint,
|
|
3418
|
+
prompt: request.prompt,
|
|
3419
|
+
uiMode: request.mode,
|
|
3420
|
+
mode: "modal",
|
|
3421
|
+
silentFirst: request.mode === ELEMENTS_AUTH_MODES.CHECKOUT && request.prompt !== ELEMENTS_AUTH_PROMPTS.LOGIN,
|
|
3422
|
+
onSuccess: async ({ accessToken }) => {
|
|
3423
|
+
if (this.authGeneration !== generation) return;
|
|
3424
|
+
if (this.authInProgress = false, !accessToken) {
|
|
3425
|
+
sourceElement._emitError({
|
|
3426
|
+
code: chunkUCR5HRYM_js.ErrorCode.AUTH_CALLBACK_MISSING_TOKEN,
|
|
3427
|
+
message: "Sign-in callback did not return an access token."
|
|
3428
|
+
});
|
|
3429
|
+
return;
|
|
3430
|
+
}
|
|
3431
|
+
let application = await this.applyAccessToken(accessToken, generation);
|
|
3432
|
+
application.kind === "authenticated" ? (this._syncHostSession(), sourceElement._emitAuthenticated(application.data)) : application.kind === "claim_failed" && sourceElement._emitError({
|
|
3433
|
+
code: application.code,
|
|
3434
|
+
message: application.message
|
|
3435
|
+
});
|
|
3436
|
+
},
|
|
3437
|
+
onError: (err2) => {
|
|
3438
|
+
this.authGeneration === generation && (this.authInProgress = false, sourceElement._emitError({
|
|
3439
|
+
code: err2.error,
|
|
3440
|
+
message: err2.description ?? err2.error
|
|
3441
|
+
}));
|
|
3442
|
+
}
|
|
3443
|
+
}).catch((error) => {
|
|
3444
|
+
this.authGeneration === generation && (this.authInProgress = false, sourceElement._emitError({
|
|
3445
|
+
code: chunkUCR5HRYM_js.ErrorCode.AUTH_START_FAILED,
|
|
3446
|
+
message: error instanceof Error ? error.message : "Unable to start sign-in."
|
|
3447
|
+
}));
|
|
3448
|
+
});
|
|
3449
|
+
}
|
|
3450
|
+
handleMessage(event) {
|
|
3451
|
+
if (!isAllowedOrigin(event.origin))
|
|
3452
|
+
return;
|
|
3453
|
+
let message = parseIframeMessage(event.data);
|
|
3454
|
+
if (!message) return;
|
|
3455
|
+
let sourceElement = this.sourceElementFor(event, message);
|
|
3456
|
+
if (sourceElement)
|
|
3457
|
+
switch (message.type) {
|
|
3458
|
+
case MESSAGE_TYPES.AUTH_REQUESTED:
|
|
3459
|
+
this.startEmbeddedAuth(sourceElement, message);
|
|
3460
|
+
break;
|
|
3461
|
+
case MESSAGE_TYPES.SESSION_ESTABLISHED:
|
|
3462
|
+
this.adoptEstablishedSession(sourceElement, message);
|
|
3463
|
+
break;
|
|
3464
|
+
case MESSAGE_TYPES.ADDRESS_CHANGED:
|
|
3465
|
+
case MESSAGE_TYPES.ADDRESS_SELECTED:
|
|
3466
|
+
this.addressData = message.address;
|
|
3467
|
+
break;
|
|
3468
|
+
case MESSAGE_TYPES.PAYMENT_METHOD_SELECTED:
|
|
3469
|
+
this.paymentData = message.method;
|
|
3470
|
+
break;
|
|
3471
|
+
case MESSAGE_TYPES.CONTACT_PROVIDED:
|
|
3472
|
+
this.customerData || (this.customerData = { name: "", email: null, phone: null }), message.contactType === ELEMENTS_AUTH_CONTACT_TYPES.EMAIL ? this.customerData.email = message.contact : this.customerData.phone = message.contact;
|
|
3473
|
+
break;
|
|
3474
|
+
case MESSAGE_TYPES.CONTINUE_WITHOUT_SAVED_DETAILS: {
|
|
3475
|
+
this.authGeneration += 1, this.authInProgress = false;
|
|
3476
|
+
let carriedIdentityAuthority = !!this.client.getAccessToken() || this.client.hasClaimedSessionAuthority();
|
|
3477
|
+
this.forgetIdentity(), this.customerData = { name: "", email: null, phone: null }, carriedIdentityAuthority ? this.client.clearSession() : this.client.setAccessToken(null), this.broadcastClearedSession(), message.contactType === ELEMENTS_AUTH_CONTACT_TYPES.EMAIL ? this.customerData.email = message.contact : this.customerData.phone = message.contact;
|
|
3478
|
+
break;
|
|
3479
|
+
}
|
|
3480
|
+
case MESSAGE_TYPES.LOGOUT_COMPLETE:
|
|
3481
|
+
this.authGeneration += 1, this.authInProgress = false, this.checkoutInProgress && this.activeCheckoutAbort && this.activeCheckoutAbort(), this.forgetIdentity(), this.client.clearSession(), this.broadcastClearedSession();
|
|
3482
|
+
break;
|
|
3483
|
+
}
|
|
3484
|
+
}
|
|
3485
|
+
_setAddressData(data) {
|
|
3486
|
+
this.addressData = data;
|
|
3487
|
+
}
|
|
3488
|
+
_setPaymentData(data) {
|
|
3489
|
+
this.paymentData = data;
|
|
3490
|
+
}
|
|
3491
|
+
_setGuestContact(contact, contactType) {
|
|
3492
|
+
this.customerData || (this.customerData = { name: "", email: null, phone: null }), contactType === ELEMENTS_AUTH_CONTACT_TYPES.EMAIL ? this.customerData.email = contact : this.customerData.phone = contact;
|
|
3493
|
+
}
|
|
3494
|
+
};
|
|
3495
|
+
function createEventHandlers() {
|
|
3496
|
+
return {
|
|
3497
|
+
[EVENT_TYPES.READY]: /* @__PURE__ */ new Set(),
|
|
3498
|
+
[EVENT_TYPES.AUTHENTICATED]: /* @__PURE__ */ new Set(),
|
|
3499
|
+
[EVENT_TYPES.ERROR]: /* @__PURE__ */ new Set(),
|
|
3500
|
+
[EVENT_TYPES.CHANGE]: /* @__PURE__ */ new Set(),
|
|
3501
|
+
[EVENT_TYPES.BLUR]: /* @__PURE__ */ new Set(),
|
|
3502
|
+
[EVENT_TYPES.FOCUS]: /* @__PURE__ */ new Set(),
|
|
3503
|
+
[EVENT_TYPES.ORDER_TYPE_CHANGED]: /* @__PURE__ */ new Set(),
|
|
3504
|
+
[EVENT_TYPES.REQUEST_SUBMIT]: /* @__PURE__ */ new Set(),
|
|
3505
|
+
[EVENT_TYPES.CHECKOUT_STATUS]: /* @__PURE__ */ new Set(),
|
|
3506
|
+
[EVENT_TYPES.CHECKOUT_COMPLETE]: /* @__PURE__ */ new Set()
|
|
3507
|
+
};
|
|
3508
|
+
}
|
|
3509
|
+
var CimplifyElement = class {
|
|
3510
|
+
constructor(type, businessId, linkUrl, options, parent) {
|
|
3511
|
+
this.iframe = null;
|
|
3512
|
+
this.container = null;
|
|
3513
|
+
this.mounted = false;
|
|
3514
|
+
this.ready = false;
|
|
3515
|
+
this.pendingMessages = [];
|
|
3516
|
+
this.pendingInit = null;
|
|
3517
|
+
this.destroyed = false;
|
|
3518
|
+
this.eventHandlers = createEventHandlers();
|
|
3519
|
+
this.resolvers = /* @__PURE__ */ new Map();
|
|
3520
|
+
this.lastReportedHeight = 0;
|
|
3521
|
+
this.listening = false;
|
|
3522
|
+
this.type = type, this.businessId = businessId, this.linkUrl = linkUrl, this.options = options, this.parent = parent, this.nonce = generateNonce(), this.boundHandleMessage = this.handleMessage.bind(this), this.boundHandleResize = () => this.applyHeight(), typeof window < "u" && (window.addEventListener("message", this.boundHandleMessage), window.addEventListener("resize", this.boundHandleResize), this.listening = true);
|
|
3523
|
+
}
|
|
3524
|
+
/**
|
|
3525
|
+
* Size the iframe to the element's reported content height (in pixels). We do
|
|
3526
|
+
* NOT cap checkout at the viewport: capping forced a tall checkout to scroll
|
|
3527
|
+
* *inside* a viewport-height iframe — a nested scroll-within-scroll. Sizing to
|
|
3528
|
+
* content lets the iframe grow and the host page scroll naturally as one
|
|
3529
|
+
* surface, which is the standard embedded-checkout behaviour.
|
|
3530
|
+
*/
|
|
3531
|
+
applyHeight(reportedHeight) {
|
|
3532
|
+
if (!this.iframe) return;
|
|
3533
|
+
typeof reportedHeight == "number" && reportedHeight > 0 && (this.lastReportedHeight = reportedHeight);
|
|
3534
|
+
let content = this.lastReportedHeight;
|
|
3535
|
+
content && (this.iframe.style.height = `${Math.max(320, content)}px`);
|
|
3536
|
+
}
|
|
3537
|
+
mount(container) {
|
|
3538
|
+
if (this.mounted) {
|
|
3539
|
+
console.warn(`Element ${this.type} is already mounted`);
|
|
3540
|
+
return;
|
|
3541
|
+
}
|
|
3542
|
+
let target = typeof container == "string" ? document.querySelector(container) : container;
|
|
3543
|
+
if (!target) {
|
|
3544
|
+
console.error(`Container not found: ${container}`);
|
|
3545
|
+
return;
|
|
3546
|
+
}
|
|
3547
|
+
this.container = target, this.mounted = true, !this.listening && typeof window < "u" && (window.addEventListener("message", this.boundHandleMessage), this.listening = true), this.createIframe();
|
|
3548
|
+
}
|
|
3549
|
+
destroy() {
|
|
3550
|
+
this.iframe && (this.iframe.remove(), this.iframe = null), this.container = null, this.mounted = false, this.ready = false, this.destroyed = true, this.pendingMessages = [], this.eventHandlers = createEventHandlers(), this.resolvers.forEach((entry) => clearTimeout(entry.timeoutId)), this.resolvers.clear(), this.listening && typeof window < "u" && (window.removeEventListener("message", this.boundHandleMessage), window.removeEventListener("resize", this.boundHandleResize), this.listening = false), this.parent._removeElement(this.type, this);
|
|
3551
|
+
}
|
|
3552
|
+
on(event, handler) {
|
|
3553
|
+
this.eventHandlers[event].add(handler);
|
|
3554
|
+
}
|
|
3555
|
+
off(event, handler) {
|
|
3556
|
+
this.eventHandlers[event].delete(handler);
|
|
3557
|
+
}
|
|
3558
|
+
async getData() {
|
|
3559
|
+
return this.isMounted() ? new Promise((resolve) => {
|
|
3560
|
+
let id = Math.random().toString(36).slice(2), timeoutId = setTimeout(() => {
|
|
3561
|
+
let entry = this.resolvers.get(id);
|
|
3562
|
+
entry && (this.resolvers.delete(id), entry.resolve(null));
|
|
3563
|
+
}, 5e3);
|
|
3564
|
+
this.resolvers.set(id, { resolve, timeoutId }), this.sendMessage({ type: MESSAGE_TYPES.GET_DATA });
|
|
3565
|
+
}) : null;
|
|
3566
|
+
}
|
|
3567
|
+
setCart(cart) {
|
|
3568
|
+
this.sendMessage({ type: MESSAGE_TYPES.SET_CART, cart });
|
|
3569
|
+
}
|
|
3570
|
+
/**
|
|
3571
|
+
* Posts to the element. Until its iframe exists and reports READY (before
|
|
3572
|
+
* `mount`, while the business id resolves, or while the iframe loads) the
|
|
3573
|
+
* message is queued and sent on READY; a newer cart replaces a queued one.
|
|
3574
|
+
* A destroyed element, or one whose iframe was removed from the page, drops it.
|
|
3575
|
+
*/
|
|
3576
|
+
sendMessage(message) {
|
|
3577
|
+
if (this.destroyed) return;
|
|
3578
|
+
let iframe = this.iframe;
|
|
3579
|
+
if (iframe && !iframe.isConnected) {
|
|
3580
|
+
console.warn("[cimplify:checkout] sendMessage DROPPED \u2014 iframe detached", {
|
|
3581
|
+
type: message.type
|
|
3582
|
+
});
|
|
3583
|
+
return;
|
|
3584
|
+
}
|
|
3585
|
+
if (!iframe || !this.ready || !iframe.contentWindow) {
|
|
3586
|
+
this.queue(message);
|
|
3587
|
+
return;
|
|
3588
|
+
}
|
|
3589
|
+
iframe.contentWindow.postMessage(message, this.linkUrl);
|
|
3590
|
+
}
|
|
3591
|
+
queue(message) {
|
|
3592
|
+
message.type === MESSAGE_TYPES.SET_CART && (this.pendingMessages = this.pendingMessages.filter(
|
|
3593
|
+
(queued) => queued.type !== MESSAGE_TYPES.SET_CART
|
|
3594
|
+
)), this.pendingMessages.push(message);
|
|
3595
|
+
}
|
|
3596
|
+
flushPending() {
|
|
3597
|
+
if (!this.ready || !this.iframe?.contentWindow) return;
|
|
3598
|
+
let queue = this.pendingMessages;
|
|
3599
|
+
this.pendingMessages = [];
|
|
3600
|
+
for (let message of queue)
|
|
3601
|
+
this.iframe.contentWindow.postMessage(message, this.linkUrl);
|
|
3602
|
+
}
|
|
3603
|
+
getContentWindow() {
|
|
3604
|
+
return this.iframe?.contentWindow ?? null;
|
|
3605
|
+
}
|
|
3606
|
+
isMounted() {
|
|
3607
|
+
return this.mounted && !!this.iframe && this.iframe?.isConnected === true;
|
|
3608
|
+
}
|
|
3609
|
+
_acceptsMessageEvent(event, message) {
|
|
3610
|
+
let iframeWindow = this.iframe?.contentWindow;
|
|
3611
|
+
return !iframeWindow || event.source !== iframeWindow ? false : message.nonce === this.nonce;
|
|
3612
|
+
}
|
|
3613
|
+
_emitAuthenticated(data) {
|
|
3614
|
+
this.emit(EVENT_TYPES.AUTHENTICATED, data);
|
|
3615
|
+
}
|
|
3616
|
+
_emitError(error) {
|
|
3617
|
+
this.emit(EVENT_TYPES.ERROR, error);
|
|
3618
|
+
}
|
|
3619
|
+
async createIframe() {
|
|
3620
|
+
if (!this.container) return;
|
|
3621
|
+
let resolvedBusinessId = this.businessId ?? await this.parent.resolveBusinessId();
|
|
3622
|
+
if (!resolvedBusinessId || !this.container || !this.mounted) {
|
|
3623
|
+
console.error("Unable to mount element without a resolved business ID"), this.emit(EVENT_TYPES.ERROR, {
|
|
3624
|
+
code: chunkUCR5HRYM_js.ErrorCode.BUSINESS_ID_REQUIRED,
|
|
3625
|
+
message: "Unable to initialize checkout without a business ID."
|
|
3626
|
+
});
|
|
3627
|
+
return;
|
|
3628
|
+
}
|
|
3629
|
+
this.businessId = resolvedBusinessId;
|
|
3630
|
+
let iframe = document.createElement("iframe"), url = new URL(`${this.linkUrl}/elements/${this.type}`);
|
|
3631
|
+
url.searchParams.set("businessId", resolvedBusinessId), url.searchParams.set("nonce", this.nonce);
|
|
3632
|
+
let publicKey = this.parent.getPublicKey().trim();
|
|
3633
|
+
publicKey && url.searchParams.set("publicKey", publicKey), this.options.prefillEmail && url.searchParams.set("email", this.options.prefillEmail), this.options.mode && url.searchParams.set("mode", this.options.mode), iframe.src = url.toString(), iframe.style.border = "none", iframe.style.width = "100%", iframe.style.minHeight = "200px", iframe.style.display = "block", iframe.style.overflow = "hidden", iframe.style.background = "transparent", iframe.setAttribute("allowtransparency", "true"), iframe.setAttribute("frameborder", "0"), iframe.setAttribute("allow", ELEMENT_IFRAME_PERMISSIONS), iframe.setAttribute(
|
|
3634
|
+
"sandbox",
|
|
3635
|
+
"allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox"
|
|
3636
|
+
), this.iframe = iframe, this.container.appendChild(iframe), this.pendingInit = {
|
|
3637
|
+
businessId: resolvedBusinessId,
|
|
3638
|
+
publicKey: this.parent.getPublicKey()
|
|
3639
|
+
};
|
|
3640
|
+
}
|
|
3641
|
+
handleMessage(event) {
|
|
3642
|
+
if (!isAllowedOrigin(event.origin))
|
|
3643
|
+
return;
|
|
3644
|
+
let message = parseIframeMessage(event.data);
|
|
3645
|
+
if (message && this._acceptsMessageEvent(event, message))
|
|
3646
|
+
switch (message.type) {
|
|
3647
|
+
case MESSAGE_TYPES.READY:
|
|
3648
|
+
if (this.ready = true, message.height && this.applyHeight(message.height), this.pendingInit) {
|
|
3649
|
+
let { publicKey } = this.pendingInit;
|
|
3650
|
+
this.sendMessage({
|
|
3651
|
+
type: MESSAGE_TYPES.INIT,
|
|
3652
|
+
businessId: this.pendingInit.businessId,
|
|
3653
|
+
publicKey,
|
|
3654
|
+
prefillEmail: this.options.prefillEmail,
|
|
3655
|
+
appearance: this.parent.getAppearance(),
|
|
3656
|
+
orderTypes: this.options.orderTypes,
|
|
3657
|
+
defaultOrderType: this.options.defaultOrderType,
|
|
3658
|
+
renderSubmitButton: true,
|
|
3659
|
+
submitLabel: this.options.submitLabel,
|
|
3660
|
+
intentId: this.options.intentId,
|
|
3661
|
+
hostedSessionId: this.options.hostedSessionId,
|
|
3662
|
+
initialTerms: this.options.initialTerms,
|
|
3663
|
+
offerSaveDetails: this.options.offerSaveDetails ?? false
|
|
3664
|
+
}), this.parent._syncHostSession(this), this.pendingInit = null;
|
|
3665
|
+
}
|
|
3666
|
+
this.flushPending(), this.emit(EVENT_TYPES.READY, { height: message.height });
|
|
3667
|
+
break;
|
|
3668
|
+
case MESSAGE_TYPES.HEIGHT_CHANGE:
|
|
3669
|
+
this.applyHeight(message.height);
|
|
3670
|
+
break;
|
|
3671
|
+
case MESSAGE_TYPES.ERROR:
|
|
3672
|
+
this.emit(EVENT_TYPES.ERROR, { code: message.code, message: message.message });
|
|
3673
|
+
break;
|
|
3674
|
+
case MESSAGE_TYPES.ADDRESS_CHANGED:
|
|
3675
|
+
case MESSAGE_TYPES.ADDRESS_SELECTED:
|
|
3676
|
+
this.parent._setAddressData(message.address), this.emit(EVENT_TYPES.CHANGE, { address: message.address }), this.resolveData(message.address);
|
|
3677
|
+
break;
|
|
3678
|
+
case MESSAGE_TYPES.PAYMENT_METHOD_SELECTED:
|
|
3679
|
+
this.parent._setPaymentData(message.method), this.emit(EVENT_TYPES.CHANGE, { paymentMethod: message.method }), this.resolveData(message.method);
|
|
3680
|
+
break;
|
|
3681
|
+
case MESSAGE_TYPES.CONTACT_PROVIDED:
|
|
3682
|
+
this.parent._setGuestContact(message.contact, message.contactType);
|
|
3683
|
+
break;
|
|
3684
|
+
case MESSAGE_TYPES.ORDER_TYPE_CHANGED:
|
|
3685
|
+
this.emit(EVENT_TYPES.ORDER_TYPE_CHANGED, { orderType: message.orderType });
|
|
3686
|
+
break;
|
|
3687
|
+
case MESSAGE_TYPES.REQUEST_SUBMIT:
|
|
3688
|
+
this.emit(EVENT_TYPES.REQUEST_SUBMIT, {});
|
|
3689
|
+
break;
|
|
3690
|
+
case MESSAGE_TYPES.CHECKOUT_STATUS:
|
|
3691
|
+
this.parent._isCheckoutInProgress() || this.emit(EVENT_TYPES.CHECKOUT_STATUS, {
|
|
3692
|
+
status: message.status,
|
|
3693
|
+
context: message.context
|
|
3694
|
+
});
|
|
3695
|
+
break;
|
|
3696
|
+
case MESSAGE_TYPES.CHECKOUT_COMPLETE:
|
|
3697
|
+
this.parent._isCheckoutInProgress() || this.emit(EVENT_TYPES.CHECKOUT_COMPLETE, {
|
|
3698
|
+
success: message.success,
|
|
3699
|
+
order: message.order,
|
|
3700
|
+
error: message.error,
|
|
3701
|
+
enrolled_in_link: message.enrolled_in_link
|
|
3702
|
+
});
|
|
3703
|
+
break;
|
|
3704
|
+
}
|
|
3705
|
+
}
|
|
3706
|
+
emit(event, data) {
|
|
3707
|
+
this.eventHandlers[event].forEach((handler) => handler(data));
|
|
3708
|
+
}
|
|
3709
|
+
resolveData(data) {
|
|
3710
|
+
this.resolvers.forEach((entry) => {
|
|
3711
|
+
clearTimeout(entry.timeoutId), entry.resolve(data);
|
|
3712
|
+
}), this.resolvers.clear();
|
|
3713
|
+
}
|
|
3714
|
+
};
|
|
3715
|
+
function createElements(client, businessId, options) {
|
|
3716
|
+
return new CimplifyElements(client, businessId, options);
|
|
3717
|
+
}
|
|
3718
|
+
|
|
3719
|
+
exports.AUTH_TOKEN_CHANGED = AUTH_TOKEN_CHANGED;
|
|
3720
|
+
exports.AuthService = AuthService;
|
|
3721
|
+
exports.BusinessService = BusinessService;
|
|
3722
|
+
exports.CartOperations = CartOperations;
|
|
3723
|
+
exports.CatalogueQueries = CatalogueQueries;
|
|
3724
|
+
exports.CheckoutService = CheckoutService;
|
|
3725
|
+
exports.CimplifyElement = CimplifyElement;
|
|
3726
|
+
exports.CimplifyElements = CimplifyElements;
|
|
3727
|
+
exports.DEFAULT_ISSUER = DEFAULT_ISSUER;
|
|
3728
|
+
exports.ELEMENTS_AUTH_CONTACT_TYPES = ELEMENTS_AUTH_CONTACT_TYPES;
|
|
3729
|
+
exports.ELEMENTS_AUTH_MODES = ELEMENTS_AUTH_MODES;
|
|
3730
|
+
exports.ELEMENTS_AUTH_PROMPTS = ELEMENTS_AUTH_PROMPTS;
|
|
3731
|
+
exports.ELEMENT_TYPES = ELEMENT_TYPES;
|
|
3732
|
+
exports.EVENT_TYPES = EVENT_TYPES;
|
|
3733
|
+
exports.FxService = FxService;
|
|
3734
|
+
exports.InventoryService = InventoryService;
|
|
3735
|
+
exports.LinkService = LinkService;
|
|
3736
|
+
exports.LiteService = LiteService;
|
|
3737
|
+
exports.MESSAGE_TYPES = MESSAGE_TYPES;
|
|
3738
|
+
exports.MUTATION_ERROR = MUTATION_ERROR;
|
|
3739
|
+
exports.OrderQueries = OrderQueries;
|
|
3740
|
+
exports.PAYMENT_AUTHORIZATION_OUTCOME_STATUS = PAYMENT_AUTHORIZATION_OUTCOME_STATUS;
|
|
3741
|
+
exports.PAYMENT_AUTHORIZATION_PROVIDER = PAYMENT_AUTHORIZATION_PROVIDER;
|
|
3742
|
+
exports.PKCE_COOKIE = PKCE_COOKIE;
|
|
3743
|
+
exports.PKCE_COOKIE_PATH = PKCE_COOKIE_PATH;
|
|
3744
|
+
exports.PaymentAuthorizationAdapterRegistry = PaymentAuthorizationAdapterRegistry;
|
|
3745
|
+
exports.PaystackAuthorizationAdapter = PaystackAuthorizationAdapter;
|
|
3746
|
+
exports.SESSION_CLAIMED = SESSION_CLAIMED;
|
|
3747
|
+
exports.SESSION_CLEARED = SESSION_CLEARED;
|
|
3748
|
+
exports.SchedulingService = SchedulingService;
|
|
3749
|
+
exports.StripeAuthorizationAdapter = StripeAuthorizationAdapter;
|
|
3750
|
+
exports.clearIntentIdempotencyKey = clearIntentIdempotencyKey;
|
|
3751
|
+
exports.combine = combine;
|
|
3752
|
+
exports.combineObject = combineObject;
|
|
3753
|
+
exports.confirmationForUnchangedReplacement = confirmationForUnchangedReplacement;
|
|
3754
|
+
exports.createClientEvents = createClientEvents;
|
|
3755
|
+
exports.createDefaultPaymentAuthorizationAdapterRegistry = createDefaultPaymentAuthorizationAdapterRegistry;
|
|
3756
|
+
exports.createElements = createElements;
|
|
3757
|
+
exports.createPurchaseIntentConfirmation = createPurchaseIntentConfirmation;
|
|
3758
|
+
exports.decodePkceState = decodePkceState;
|
|
3759
|
+
exports.err = err;
|
|
3760
|
+
exports.flatMap = flatMap;
|
|
3761
|
+
exports.fromPromise = fromPromise;
|
|
3762
|
+
exports.generateIdempotencyKey = generateIdempotencyKey;
|
|
3763
|
+
exports.generatePkce = generatePkce;
|
|
3764
|
+
exports.generateState = generateState;
|
|
3765
|
+
exports.getAuthorizationEndpoint = getAuthorizationEndpoint;
|
|
3766
|
+
exports.getOrElse = getOrElse;
|
|
3767
|
+
exports.intentIdempotencyKey = intentIdempotencyKey;
|
|
3768
|
+
exports.isErr = isErr;
|
|
3769
|
+
exports.isOk = isOk;
|
|
3770
|
+
exports.mapError = mapError;
|
|
3771
|
+
exports.mapResult = mapResult;
|
|
3772
|
+
exports.ok = ok;
|
|
3773
|
+
exports.purchaseIntentRequiresPaymentOption = purchaseIntentRequiresPaymentOption;
|
|
3774
|
+
exports.safe = safe;
|
|
3775
|
+
exports.selectPurchaseIntentPaymentOption = selectPurchaseIntentPaymentOption;
|
|
3776
|
+
exports.startSignIn = startSignIn;
|
|
3777
|
+
exports.toNullable = toNullable;
|
|
3778
|
+
exports.tryCatch = tryCatch;
|
|
3779
|
+
exports.unwrap = unwrap;
|