@ordergroove/smi-serve 1.9.24 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,20 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [1.10.0](https://github.com/ordergroove/plush-toys/compare/@ordergroove/smi-serve@1.9.24...@ordergroove/smi-serve@1.10.0) (2026-01-30)
7
+
8
+
9
+ ### Features
10
+
11
+ * add --auto-cancel-flow flag ([98b8972](https://github.com/ordergroove/plush-toys/commit/98b8972db35726725861d92f6d004cadf2ea5622))
12
+ * add select-customer command ([65bf439](https://github.com/ordergroove/plush-toys/commit/65bf4397dc9bfffcf961532a055618c7d01613f9))
13
+ * implement CSS-only refresh for cancel-flow ([9de945b](https://github.com/ordergroove/plush-toys/commit/9de945b7c3bd0156816278b0d85064d37a9efb7e))
14
+ * smi-serve builds smi-core and cancel-flow when --local-assets ([b74d3e1](https://github.com/ordergroove/plush-toys/commit/b74d3e1066e867e18bd6332ee111d9d626180b08))
15
+
16
+
17
+
18
+
19
+
6
20
  ## [1.9.24](https://github.com/ordergroove/plush-toys/compare/@ordergroove/smi-serve@1.9.23...@ordergroove/smi-serve@1.9.24) (2026-01-12)
7
21
 
8
22
  **Note:** Version bump only for package @ordergroove/smi-serve
@@ -1,11 +1,11 @@
1
1
  <?xml version="1.0" ?>
2
2
  <!DOCTYPE coverage SYSTEM "http://cobertura.sourceforge.net/xml/coverage-04.dtd">
3
- <coverage lines-valid="488" lines-covered="210" line-rate="0.4303" branches-valid="165" branches-covered="45" branch-rate="0.2727" timestamp="1768237253459" complexity="0" version="0.1">
3
+ <coverage lines-valid="564" lines-covered="218" line-rate="0.3865" branches-valid="216" branches-covered="45" branch-rate="0.20829999999999999" timestamp="1769792457293" complexity="0" version="0.1">
4
4
  <sources>
5
5
  <source>/home/jenkins/agent/workspace/Ordergroove_plush-toys_master/plush-toys/packages/smi-serve</source>
6
6
  </sources>
7
7
  <packages>
8
- <package name="smi-serve" line-rate="0.4535" branch-rate="0.3061">
8
+ <package name="smi-serve" line-rate="0.4113" branch-rate="0.23929999999999998">
9
9
  <classes>
10
10
  <class name="auth.js" filename="src/auth.js" line-rate="0.9333" branch-rate="0.8332999999999999">
11
11
  <methods>
@@ -33,31 +33,56 @@
33
33
  <line number="30" hits="2" branch="false"/>
34
34
  </lines>
35
35
  </class>
36
- <class name="impersonate.js" filename="src/impersonate.js" line-rate="0.20679999999999998" branch-rate="0">
36
+ <class name="impersonate.js" filename="src/impersonate.js" line-rate="0.1666" branch-rate="0">
37
37
  <methods>
38
- <method name="impersonate" hits="0" signature="()V">
38
+ <method name="tryToLoadSelectedCustomer" hits="0" signature="()V">
39
39
  <lines>
40
- <line number="8" hits="0"/>
40
+ <line number="9" hits="0"/>
41
41
  </lines>
42
42
  </method>
43
- <method name="(anonymous_1)" hits="0" signature="()V">
43
+ <method name="impersonate" hits="0" signature="()V">
44
44
  <lines>
45
- <line number="14" hits="0"/>
45
+ <line number="21" hits="0"/>
46
46
  </lines>
47
47
  </method>
48
48
  <method name="(anonymous_2)" hits="0" signature="()V">
49
49
  <lines>
50
- <line number="36" hits="0"/>
50
+ <line number="27" hits="0"/>
51
51
  </lines>
52
52
  </method>
53
53
  <method name="(anonymous_3)" hits="0" signature="()V">
54
54
  <lines>
55
- <line number="55" hits="0"/>
55
+ <line number="49" hits="0"/>
56
56
  </lines>
57
57
  </method>
58
58
  <method name="(anonymous_4)" hits="0" signature="()V">
59
59
  <lines>
60
- <line number="58" hits="0"/>
60
+ <line number="59" hits="0"/>
61
+ </lines>
62
+ </method>
63
+ <method name="(anonymous_5)" hits="0" signature="()V">
64
+ <lines>
65
+ <line number="83" hits="0"/>
66
+ </lines>
67
+ </method>
68
+ <method name="(anonymous_6)" hits="0" signature="()V">
69
+ <lines>
70
+ <line number="86" hits="0"/>
71
+ </lines>
72
+ </method>
73
+ <method name="saveSelectedCustomer" hits="0" signature="()V">
74
+ <lines>
75
+ <line number="95" hits="0"/>
76
+ </lines>
77
+ </method>
78
+ <method name="loadSelectedCustomer" hits="0" signature="()V">
79
+ <lines>
80
+ <line number="104" hits="0"/>
81
+ </lines>
82
+ </method>
83
+ <method name="cliCallSelectCustomer" hits="0" signature="()V">
84
+ <lines>
85
+ <line number="116" hits="0"/>
61
86
  </lines>
62
87
  </method>
63
88
  </methods>
@@ -66,31 +91,62 @@
66
91
  <line number="2" hits="1" branch="false"/>
67
92
  <line number="3" hits="1" branch="false"/>
68
93
  <line number="4" hits="1" branch="false"/>
69
- <line number="6" hits="1" branch="false"/>
70
- <line number="9" hits="0" branch="false"/>
94
+ <line number="5" hits="1" branch="false"/>
95
+ <line number="7" hits="1" branch="false"/>
96
+ <line number="10" hits="0" branch="false"/>
97
+ <line number="12" hits="0" branch="true" condition-coverage="0% (0/2)"/>
71
98
  <line number="13" hits="0" branch="false"/>
72
- <line number="14" hits="0" branch="false"/>
73
- <line number="15" hits="0" branch="false"/>
74
99
  <line number="16" hits="0" branch="false"/>
75
- <line number="17" hits="0" branch="true" condition-coverage="0% (0/2)"/>
76
- <line number="18" hits="0" branch="false"/>
77
- <line number="31" hits="0" branch="true" condition-coverage="0% (0/2)"/>
78
- <line number="33" hits="0" branch="false"/>
79
- <line number="35" hits="0" branch="true" condition-coverage="0% (0/2)"/>
80
- <line number="36" hits="0" branch="false"/>
81
- <line number="38" hits="0" branch="false"/>
82
- <line number="42" hits="0" branch="true" condition-coverage="0% (0/2)"/>
83
- <line number="43" hits="0" branch="false"/>
100
+ <line number="17" hits="0" branch="false"/>
101
+ <line number="22" hits="0" branch="false"/>
102
+ <line number="26" hits="0" branch="false"/>
103
+ <line number="27" hits="0" branch="false"/>
104
+ <line number="28" hits="0" branch="false"/>
105
+ <line number="29" hits="0" branch="false"/>
106
+ <line number="30" hits="0" branch="true" condition-coverage="0% (0/2)"/>
107
+ <line number="31" hits="0" branch="false"/>
84
108
  <line number="44" hits="0" branch="true" condition-coverage="0% (0/2)"/>
85
- <line number="45" hits="0" branch="false"/>
109
+ <line number="46" hits="0" branch="false"/>
86
110
  <line number="48" hits="0" branch="true" condition-coverage="0% (0/2)"/>
87
111
  <line number="49" hits="0" branch="false"/>
112
+ <line number="51" hits="0" branch="false"/>
88
113
  <line number="55" hits="0" branch="true" condition-coverage="0% (0/2)"/>
114
+ <line number="56" hits="0" branch="false"/>
115
+ <line number="57" hits="0" branch="true" condition-coverage="0% (0/2)"/>
116
+ <line number="58" hits="0" branch="false"/>
89
117
  <line number="59" hits="0" branch="false"/>
118
+ <line number="60" hits="0" branch="true" condition-coverage="0% (0/2)"/>
90
119
  <line number="61" hits="0" branch="false"/>
91
- <line number="64" hits="0" branch="false"/>
92
- <line number="78" hits="0" branch="false"/>
93
- <line number="81" hits="1" branch="false"/>
120
+ <line number="63" hits="0" branch="false"/>
121
+ <line number="69" hits="0" branch="true" condition-coverage="0% (0/5)"/>
122
+ <line number="70" hits="0" branch="false"/>
123
+ <line number="71" hits="0" branch="true" condition-coverage="0% (0/2)"/>
124
+ <line number="72" hits="0" branch="false"/>
125
+ <line number="76" hits="0" branch="true" condition-coverage="0% (0/2)"/>
126
+ <line number="77" hits="0" branch="false"/>
127
+ <line number="83" hits="0" branch="true" condition-coverage="0% (0/2)"/>
128
+ <line number="87" hits="0" branch="false"/>
129
+ <line number="89" hits="0" branch="false"/>
130
+ <line number="92" hits="0" branch="false"/>
131
+ <line number="96" hits="0" branch="false"/>
132
+ <line number="105" hits="0" branch="false"/>
133
+ <line number="106" hits="0" branch="false"/>
134
+ <line number="109" hits="0" branch="true" condition-coverage="0% (0/5)"/>
135
+ <line number="110" hits="0" branch="false"/>
136
+ <line number="113" hits="0" branch="false"/>
137
+ <line number="118" hits="0" branch="true" condition-coverage="0% (0/2)"/>
138
+ <line number="119" hits="0" branch="false"/>
139
+ <line number="120" hits="0" branch="true" condition-coverage="0% (0/4)"/>
140
+ <line number="121" hits="0" branch="false"/>
141
+ <line number="124" hits="0" branch="false"/>
142
+ <line number="127" hits="0" branch="false"/>
143
+ <line number="128" hits="0" branch="false"/>
144
+ <line number="130" hits="0" branch="false"/>
145
+ <line number="139" hits="0" branch="false"/>
146
+ <line number="142" hits="1" branch="false"/>
147
+ <line number="143" hits="1" branch="false"/>
148
+ <line number="144" hits="1" branch="false"/>
149
+ <line number="145" hits="1" branch="false"/>
94
150
  </lines>
95
151
  </class>
96
152
  <class name="init.js" filename="src/init.js" line-rate="0.875" branch-rate="0.375">
@@ -667,56 +723,86 @@
667
723
  <line number="84" hits="2" branch="false"/>
668
724
  </lines>
669
725
  </class>
670
- <class name="serve.js" filename="src/serve.js" line-rate="0.1929" branch-rate="0">
726
+ <class name="serve.js" filename="src/serve.js" line-rate="0.1521" branch-rate="0">
671
727
  <methods>
672
728
  <method name="getGlobals" hits="0" signature="()V">
673
729
  <lines>
674
- <line number="12" hits="0"/>
730
+ <line number="13" hits="0"/>
675
731
  </lines>
676
732
  </method>
677
733
  <method name="(anonymous_1)" hits="0" signature="()V">
678
734
  <lines>
679
- <line number="36" hits="0"/>
735
+ <line number="51" hits="0"/>
680
736
  </lines>
681
737
  </method>
682
738
  <method name="(anonymous_2)" hits="0" signature="()V">
683
739
  <lines>
684
- <line number="41" hits="0"/>
740
+ <line number="54" hits="0"/>
685
741
  </lines>
686
742
  </method>
687
743
  <method name="(anonymous_3)" hits="0" signature="()V">
688
744
  <lines>
689
- <line number="42" hits="0"/>
745
+ <line number="67" hits="0"/>
690
746
  </lines>
691
747
  </method>
692
748
  <method name="(anonymous_4)" hits="0" signature="()V">
693
749
  <lines>
694
- <line number="49" hits="0"/>
750
+ <line number="72" hits="0"/>
695
751
  </lines>
696
752
  </method>
697
753
  <method name="(anonymous_5)" hits="0" signature="()V">
698
754
  <lines>
699
- <line number="51" hits="0"/>
755
+ <line number="73" hits="0"/>
700
756
  </lines>
701
757
  </method>
702
758
  <method name="(anonymous_6)" hits="0" signature="()V">
703
759
  <lines>
704
- <line number="78" hits="0"/>
760
+ <line number="80" hits="0"/>
705
761
  </lines>
706
762
  </method>
707
763
  <method name="(anonymous_7)" hits="0" signature="()V">
708
764
  <lines>
709
- <line number="84" hits="0"/>
765
+ <line number="83" hits="0"/>
710
766
  </lines>
711
767
  </method>
712
768
  <method name="(anonymous_8)" hits="0" signature="()V">
713
769
  <lines>
714
- <line number="92" hits="0"/>
770
+ <line number="116" hits="0"/>
771
+ </lines>
772
+ </method>
773
+ <method name="(anonymous_9)" hits="0" signature="()V">
774
+ <lines>
775
+ <line number="122" hits="0"/>
776
+ </lines>
777
+ </method>
778
+ <method name="(anonymous_10)" hits="0" signature="()V">
779
+ <lines>
780
+ <line number="130" hits="0"/>
781
+ </lines>
782
+ </method>
783
+ <method name="(anonymous_11)" hits="0" signature="()V">
784
+ <lines>
785
+ <line number="141" hits="0"/>
786
+ </lines>
787
+ </method>
788
+ <method name="(anonymous_12)" hits="0" signature="()V">
789
+ <lines>
790
+ <line number="169" hits="0"/>
791
+ </lines>
792
+ </method>
793
+ <method name="(anonymous_13)" hits="0" signature="()V">
794
+ <lines>
795
+ <line number="172" hits="0"/>
796
+ </lines>
797
+ </method>
798
+ <method name="(anonymous_14)" hits="0" signature="()V">
799
+ <lines>
800
+ <line number="173" hits="0"/>
715
801
  </lines>
716
802
  </method>
717
803
  <method name="serve" hits="0" signature="()V">
718
804
  <lines>
719
- <line number="103" hits="0"/>
805
+ <line number="187" hits="0"/>
720
806
  </lines>
721
807
  </method>
722
808
  </methods>
@@ -728,59 +814,94 @@
728
814
  <line number="5" hits="1" branch="false"/>
729
815
  <line number="6" hits="1" branch="false"/>
730
816
  <line number="7" hits="1" branch="false"/>
731
- <line number="9" hits="1" branch="false"/>
817
+ <line number="8" hits="1" branch="false"/>
732
818
  <line number="10" hits="1" branch="false"/>
733
- <line number="13" hits="0" branch="false"/>
734
- <line number="18" hits="0" branch="true" condition-coverage="0% (0/2)"/>
735
- <line number="19" hits="0" branch="false"/>
736
- <line number="21" hits="0" branch="true" condition-coverage="0% (0/2)"/>
819
+ <line number="11" hits="1" branch="false"/>
820
+ <line number="14" hits="0" branch="false"/>
821
+ <line number="19" hits="0" branch="true" condition-coverage="0% (0/2)"/>
822
+ <line number="20" hits="0" branch="false"/>
823
+ <line number="22" hits="0" branch="true" condition-coverage="0% (0/2)"/>
737
824
  <line number="24" hits="0" branch="false"/>
738
- <line number="25" hits="0" branch="true" condition-coverage="0% (0/2)"/>
739
- <line number="27" hits="0" branch="false"/>
740
- <line number="36" hits="1" branch="false"/>
741
- <line number="37" hits="0" branch="false"/>
742
825
  <line number="39" hits="0" branch="false"/>
826
+ <line number="40" hits="0" branch="true" condition-coverage="0% (0/2)"/>
743
827
  <line number="42" hits="0" branch="false"/>
744
- <line number="44" hits="0" branch="false"/>
745
- <line number="48" hits="0" branch="false"/>
746
- <line number="49" hits="0" branch="false"/>
747
- <line number="51" hits="0" branch="false"/>
748
- <line number="55" hits="0" branch="false"/>
828
+ <line number="51" hits="1" branch="false"/>
829
+ <line number="52" hits="0" branch="true" condition-coverage="0% (0/4)"/>
830
+ <line number="54" hits="0" branch="false"/>
749
831
  <line number="56" hits="0" branch="false"/>
750
- <line number="57" hits="0" branch="false"/>
751
- <line number="63" hits="0" branch="false"/>
752
- <line number="77" hits="0" branch="false"/>
753
- <line number="78" hits="0" branch="false"/>
832
+ <line number="57" hits="0" branch="true" condition-coverage="0% (0/2)"/>
833
+ <line number="58" hits="0" branch="false"/>
834
+ <line number="60" hits="0" branch="false"/>
835
+ <line number="62" hits="0" branch="false"/>
836
+ <line number="64" hits="0" branch="false"/>
837
+ <line number="67" hits="1" branch="false"/>
838
+ <line number="68" hits="0" branch="false"/>
839
+ <line number="70" hits="0" branch="false"/>
840
+ <line number="73" hits="0" branch="false"/>
841
+ <line number="75" hits="0" branch="false"/>
754
842
  <line number="79" hits="0" branch="false"/>
755
- <line number="84" hits="0" branch="false"/>
756
- <line number="85" hits="0" branch="false"/>
757
- <line number="92" hits="0" branch="false"/>
843
+ <line number="81" hits="0" branch="false"/>
844
+ <line number="83" hits="0" branch="false"/>
845
+ <line number="86" hits="0" branch="true" condition-coverage="0% (0/2)"/>
846
+ <line number="87" hits="0" branch="false"/>
847
+ <line number="89" hits="0" branch="false"/>
758
848
  <line number="93" hits="0" branch="false"/>
759
- <line number="100" hits="0" branch="false"/>
760
- <line number="104" hits="0" branch="false"/>
761
- <line number="105" hits="0" branch="false"/>
762
- <line number="107" hits="0" branch="false"/>
763
- <line number="108" hits="0" branch="false"/>
764
- <line number="109" hits="0" branch="false"/>
765
- <line number="111" hits="0" branch="true" condition-coverage="0% (0/2)"/>
766
- <line number="112" hits="0" branch="false"/>
849
+ <line number="94" hits="0" branch="false"/>
850
+ <line number="95" hits="0" branch="false"/>
851
+ <line number="101" hits="0" branch="false"/>
767
852
  <line number="115" hits="0" branch="false"/>
853
+ <line number="116" hits="0" branch="false"/>
768
854
  <line number="117" hits="0" branch="false"/>
769
- <line number="118" hits="0" branch="false"/>
770
- <line number="119" hits="0" branch="false"/>
771
- <line number="121" hits="0" branch="false"/>
772
- <line number="124" hits="0" branch="false"/>
773
- <line number="148" hits="0" branch="true" condition-coverage="0% (0/2)"/>
774
- <line number="149" hits="0" branch="false"/>
775
- <line number="152" hits="0" branch="false"/>
855
+ <line number="122" hits="0" branch="false"/>
856
+ <line number="123" hits="0" branch="false"/>
857
+ <line number="130" hits="0" branch="false"/>
858
+ <line number="131" hits="0" branch="false"/>
859
+ <line number="138" hits="0" branch="false"/>
860
+ <line number="141" hits="1" branch="false"/>
861
+ <line number="142" hits="0" branch="false"/>
862
+ <line number="144" hits="0" branch="false"/>
863
+ <line number="145" hits="0" branch="false"/>
864
+ <line number="146" hits="0" branch="false"/>
865
+ <line number="150" hits="0" branch="true" condition-coverage="0% (0/2)"/>
776
866
  <line number="154" hits="0" branch="false"/>
777
- <line number="156" hits="0" branch="false"/>
778
- <line number="161" hits="0" branch="false"/>
779
- <line number="162" hits="0" branch="false"/>
780
- <line number="164" hits="1" branch="false"/>
867
+ <line number="155" hits="0" branch="false"/>
868
+ <line number="157" hits="0" branch="false"/>
869
+ <line number="159" hits="0" branch="false"/>
870
+ <line number="170" hits="0" branch="false"/>
871
+ <line number="171" hits="0" branch="false"/>
872
+ <line number="173" hits="0" branch="false"/>
873
+ <line number="175" hits="0" branch="true" condition-coverage="0% (0/4)"/>
874
+ <line number="176" hits="0" branch="false"/>
875
+ <line number="184" hits="0" branch="false"/>
876
+ <line number="188" hits="0" branch="false"/>
877
+ <line number="189" hits="0" branch="false"/>
878
+ <line number="191" hits="0" branch="false"/>
879
+ <line number="192" hits="0" branch="false"/>
880
+ <line number="193" hits="0" branch="false"/>
881
+ <line number="195" hits="0" branch="true" condition-coverage="0% (0/2)"/>
882
+ <line number="196" hits="0" branch="false"/>
883
+ <line number="199" hits="0" branch="false"/>
884
+ <line number="201" hits="0" branch="false"/>
885
+ <line number="202" hits="0" branch="false"/>
886
+ <line number="203" hits="0" branch="false"/>
887
+ <line number="205" hits="0" branch="false"/>
888
+ <line number="208" hits="0" branch="false"/>
889
+ <line number="239" hits="0" branch="true" condition-coverage="0% (0/2)"/>
890
+ <line number="240" hits="0" branch="false"/>
891
+ <line number="243" hits="0" branch="false"/>
892
+ <line number="245" hits="0" branch="false"/>
893
+ <line number="247" hits="0" branch="false"/>
894
+ <line number="252" hits="0" branch="false"/>
895
+ <line number="253" hits="0" branch="true" condition-coverage="0% (0/2)"/>
896
+ <line number="254" hits="0" branch="false"/>
897
+ <line number="255" hits="0" branch="false"/>
898
+ <line number="256" hits="0" branch="false"/>
899
+ <line number="257" hits="0" branch="false"/>
900
+ <line number="259" hits="0" branch="false"/>
901
+ <line number="261" hits="1" branch="false"/>
781
902
  </lines>
782
903
  </class>
783
- <class name="utils.js" filename="src/utils.js" line-rate="0.4838" branch-rate="0.44439999999999996">
904
+ <class name="utils.js" filename="src/utils.js" line-rate="0.4893" branch-rate="0.44439999999999996">
784
905
  <methods>
785
906
  <method name="getcwd" hits="0" signature="()V">
786
907
  <lines>
@@ -837,14 +958,14 @@
837
958
  <line number="80" hits="0"/>
838
959
  </lines>
839
960
  </method>
840
- <method name="readRc" hits="23" signature="()V">
961
+ <method name="readRc" hits="35" signature="()V">
841
962
  <lines>
842
- <line number="97" hits="23"/>
963
+ <line number="97" hits="35"/>
843
964
  </lines>
844
965
  </method>
845
- <method name="readRcEnv" hits="11" signature="()V">
966
+ <method name="readRcEnv" hits="23" signature="()V">
846
967
  <lines>
847
- <line number="110" hits="11"/>
968
+ <line number="110" hits="23"/>
848
969
  </lines>
849
970
  </method>
850
971
  <method name="writeRc" hits="12" signature="()V">
@@ -859,22 +980,22 @@
859
980
  </method>
860
981
  <method name="readPackageJson" hits="0" signature="()V">
861
982
  <lines>
862
- <line number="139" hits="0"/>
983
+ <line number="140" hits="0"/>
863
984
  </lines>
864
985
  </method>
865
986
  <method name="isValidToken" hits="10" signature="()V">
866
987
  <lines>
867
- <line number="150" hits="10"/>
988
+ <line number="151" hits="10"/>
868
989
  </lines>
869
990
  </method>
870
991
  <method name="getAuthorNameFromToken" hits="1" signature="()V">
871
992
  <lines>
872
- <line number="165" hits="1"/>
993
+ <line number="166" hits="1"/>
873
994
  </lines>
874
995
  </method>
875
996
  <method name="getMerchantTemplatesVersion" hits="1" signature="()V">
876
997
  <lines>
877
- <line number="180" hits="1"/>
998
+ <line number="181" hits="1"/>
878
999
  </lines>
879
1000
  </method>
880
1001
  </methods>
@@ -924,54 +1045,55 @@
924
1045
  <line number="90" hits="0" branch="false"/>
925
1046
  <line number="93" hits="0" branch="false"/>
926
1047
  <line number="94" hits="0" branch="false"/>
927
- <line number="98" hits="23" branch="false"/>
928
- <line number="99" hits="23" branch="true" condition-coverage="100% (2/2)"/>
929
- <line number="100" hits="21" branch="false"/>
930
- <line number="101" hits="21" branch="false"/>
931
- <line number="102" hits="21" branch="false"/>
1048
+ <line number="98" hits="35" branch="false"/>
1049
+ <line number="99" hits="35" branch="true" condition-coverage="100% (2/2)"/>
1050
+ <line number="100" hits="32" branch="false"/>
1051
+ <line number="101" hits="32" branch="false"/>
1052
+ <line number="102" hits="32" branch="false"/>
932
1053
  <line number="104" hits="0" branch="false"/>
933
- <line number="107" hits="2" branch="false"/>
934
- <line number="111" hits="11" branch="false"/>
935
- <line number="112" hits="11" branch="true" condition-coverage="100% (2/2)"/>
1054
+ <line number="107" hits="3" branch="false"/>
1055
+ <line number="111" hits="23" branch="false"/>
1056
+ <line number="112" hits="23" branch="true" condition-coverage="100% (2/2)"/>
936
1057
  <line number="115" hits="2" branch="false"/>
937
1058
  <line number="118" hits="12" branch="false"/>
938
1059
  <line number="133" hits="12" branch="false"/>
939
1060
  <line number="134" hits="12" branch="false"/>
940
- <line number="137" hits="2" branch="false"/>
941
- <line number="140" hits="0" branch="false"/>
1061
+ <line number="135" hits="12" branch="false"/>
1062
+ <line number="138" hits="2" branch="false"/>
942
1063
  <line number="141" hits="0" branch="false"/>
943
1064
  <line number="142" hits="0" branch="false"/>
944
- <line number="144" hits="0" branch="false"/>
945
- <line number="148" hits="2" branch="false"/>
946
- <line number="151" hits="10" branch="false"/>
947
- <line number="152" hits="10" branch="true" condition-coverage="50% (1/2)"/>
948
- <line number="153" hits="0" branch="false"/>
1065
+ <line number="143" hits="0" branch="false"/>
1066
+ <line number="145" hits="0" branch="false"/>
1067
+ <line number="149" hits="2" branch="false"/>
1068
+ <line number="152" hits="10" branch="false"/>
1069
+ <line number="153" hits="10" branch="true" condition-coverage="50% (1/2)"/>
949
1070
  <line number="154" hits="0" branch="false"/>
950
1071
  <line number="155" hits="0" branch="false"/>
951
- <line number="156" hits="0" branch="true" condition-coverage="0% (0/2)"/>
952
- <line number="157" hits="0" branch="false"/>
953
- <line number="160" hits="10" branch="false"/>
954
- <line number="163" hits="2" branch="false"/>
955
- <line number="166" hits="1" branch="false"/>
956
- <line number="167" hits="1" branch="true" condition-coverage="50% (1/2)"/>
957
- <line number="168" hits="0" branch="false"/>
1072
+ <line number="156" hits="0" branch="false"/>
1073
+ <line number="157" hits="0" branch="true" condition-coverage="0% (0/2)"/>
1074
+ <line number="158" hits="0" branch="false"/>
1075
+ <line number="161" hits="10" branch="false"/>
1076
+ <line number="164" hits="2" branch="false"/>
1077
+ <line number="167" hits="1" branch="false"/>
1078
+ <line number="168" hits="1" branch="true" condition-coverage="50% (1/2)"/>
958
1079
  <line number="169" hits="0" branch="false"/>
959
- <line number="172" hits="0" branch="false"/>
1080
+ <line number="170" hits="0" branch="false"/>
960
1081
  <line number="173" hits="0" branch="false"/>
961
- <line number="175" hits="1" branch="false"/>
962
- <line number="178" hits="2" branch="false"/>
963
- <line number="182" hits="1" branch="false"/>
1082
+ <line number="174" hits="0" branch="false"/>
1083
+ <line number="176" hits="1" branch="false"/>
1084
+ <line number="179" hits="2" branch="false"/>
964
1085
  <line number="183" hits="1" branch="false"/>
965
- <line number="185" hits="1" branch="true" condition-coverage="50% (1/2)"/>
966
- <line number="186" hits="1" branch="false"/>
1086
+ <line number="184" hits="1" branch="false"/>
1087
+ <line number="186" hits="1" branch="true" condition-coverage="50% (1/2)"/>
967
1088
  <line number="187" hits="1" branch="false"/>
968
- <line number="190" hits="1" branch="true" condition-coverage="50% (1/2)"/>
969
- <line number="191" hits="1" branch="false"/>
970
- <line number="193" hits="0" branch="false"/>
1089
+ <line number="188" hits="1" branch="false"/>
1090
+ <line number="191" hits="1" branch="true" condition-coverage="50% (1/2)"/>
1091
+ <line number="192" hits="1" branch="false"/>
971
1092
  <line number="194" hits="0" branch="false"/>
972
1093
  <line number="195" hits="0" branch="false"/>
973
- <line number="199" hits="2" branch="false"/>
974
- <line number="201" hits="2" branch="false"/>
1094
+ <line number="196" hits="0" branch="false"/>
1095
+ <line number="200" hits="2" branch="false"/>
1096
+ <line number="202" hits="2" branch="false"/>
975
1097
  </lines>
976
1098
  </class>
977
1099
  </classes>
@@ -994,7 +1116,7 @@
994
1116
  <methods>
995
1117
  <method name="(anonymous_0)" hits="0" signature="()V">
996
1118
  <lines>
997
- <line number="20" hits="0"/>
1119
+ <line number="26" hits="0"/>
998
1120
  </lines>
999
1121
  </method>
1000
1122
  <method name="(anonymous_1)" hits="0" signature="()V">
@@ -1002,42 +1124,61 @@
1002
1124
  <line number="37" hits="0"/>
1003
1125
  </lines>
1004
1126
  </method>
1005
- <method name="waitForScriptToLoad" hits="0" signature="()V">
1127
+ <method name="(anonymous_2)" hits="0" signature="()V">
1006
1128
  <lines>
1007
- <line number="48" hits="0"/>
1129
+ <line number="58" hits="0"/>
1008
1130
  </lines>
1009
1131
  </method>
1010
1132
  <method name="(anonymous_3)" hits="0" signature="()V">
1011
1133
  <lines>
1012
- <line number="49" hits="0"/>
1134
+ <line number="60" hits="0"/>
1013
1135
  </lines>
1014
1136
  </method>
1015
- <method name="(anonymous_4)" hits="0" signature="()V">
1137
+ <method name="waitForScriptToLoad" hits="0" signature="()V">
1016
1138
  <lines>
1017
- <line number="52" hits="0"/>
1139
+ <line number="76" hits="0"/>
1140
+ </lines>
1141
+ </method>
1142
+ <method name="(anonymous_5)" hits="0" signature="()V">
1143
+ <lines>
1144
+ <line number="77" hits="0"/>
1145
+ </lines>
1146
+ </method>
1147
+ <method name="(anonymous_6)" hits="0" signature="()V">
1148
+ <lines>
1149
+ <line number="80" hits="0"/>
1018
1150
  </lines>
1019
1151
  </method>
1020
1152
  </methods>
1021
1153
  <lines>
1022
1154
  <line number="6" hits="0" branch="true" condition-coverage="0% (0/2)"/>
1023
1155
  <line number="10" hits="0" branch="true" condition-coverage="0% (0/2)"/>
1024
- <line number="15" hits="0" branch="false"/>
1025
- <line number="18" hits="0" branch="true" condition-coverage="0% (0/2)"/>
1026
- <line number="19" hits="0" branch="true" condition-coverage="0% (0/4)"/>
1027
- <line number="20" hits="0" branch="false"/>
1028
- <line number="21" hits="0" branch="false"/>
1156
+ <line number="15" hits="0" branch="true" condition-coverage="0% (0/2)"/>
1157
+ <line number="20" hits="0" branch="true" condition-coverage="0% (0/2)"/>
1158
+ <line number="21" hits="0" branch="true" condition-coverage="0% (0/2)"/>
1159
+ <line number="22" hits="0" branch="true" condition-coverage="0% (0/4)"/>
1160
+ <line number="24" hits="0" branch="true" condition-coverage="0% (0/2)"/>
1161
+ <line number="26" hits="0" branch="false"/>
1162
+ <line number="27" hits="0" branch="false"/>
1163
+ <line number="34" hits="0" branch="false"/>
1029
1164
  <line number="37" hits="0" branch="false"/>
1030
1165
  <line number="38" hits="0" branch="false"/>
1031
- <line number="39" hits="0" branch="false"/>
1032
- <line number="40" hits="0" branch="false"/>
1033
- <line number="41" hits="0" branch="false"/>
1034
- <line number="45" hits="0" branch="false"/>
1035
- <line number="49" hits="0" branch="false"/>
1036
- <line number="50" hits="0" branch="false"/>
1037
- <line number="51" hits="0" branch="false"/>
1038
- <line number="52" hits="0" branch="false"/>
1039
- <line number="53" hits="0" branch="false"/>
1040
- <line number="55" hits="0" branch="false"/>
1166
+ <line number="54" hits="0" branch="true" condition-coverage="0% (0/2)"/>
1167
+ <line number="56" hits="0" branch="false"/>
1168
+ <line number="58" hits="0" branch="false"/>
1169
+ <line number="60" hits="0" branch="false"/>
1170
+ <line number="61" hits="0" branch="false"/>
1171
+ <line number="62" hits="0" branch="false"/>
1172
+ <line number="63" hits="0" branch="false"/>
1173
+ <line number="67" hits="0" branch="true" condition-coverage="0% (0/2)"/>
1174
+ <line number="69" hits="0" branch="false"/>
1175
+ <line number="72" hits="0" branch="false"/>
1176
+ <line number="77" hits="0" branch="false"/>
1177
+ <line number="78" hits="0" branch="false"/>
1178
+ <line number="79" hits="0" branch="false"/>
1179
+ <line number="80" hits="0" branch="false"/>
1180
+ <line number="81" hits="0" branch="false"/>
1181
+ <line number="83" hits="0" branch="false"/>
1041
1182
  </lines>
1042
1183
  </class>
1043
1184
  </classes>
@@ -1,18 +1,18 @@
1
1
  ---------------------|---------|----------|---------|---------|-------------------------------------------------------------------------
2
2
  File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
3
3
  ---------------------|---------|----------|---------|---------|-------------------------------------------------------------------------
4
- All files | 42.43 | 27.27 | 34.73 | 43.03 |
5
- src | 44.62 | 30.61 | 36.66 | 45.35 |
4
+ All files | 38.09 | 20.83 | 30.55 | 38.65 |
5
+ src | 40.5 | 23.93 | 32.67 | 41.13 |
6
6
  auth.js | 93.33 | 83.33 | 100 | 93.33 | 14
7
- impersonate.js | 19.35 | 0 | 0 | 20.68 | 9-78
7
+ impersonate.js | 15.87 | 0 | 0 | 16.66 | 10-139
8
8
  init.js | 84.09 | 37.5 | 87.5 | 87.5 | 38,53-54,64,83
9
9
  login.js | 13.46 | 16.66 | 6.66 | 14 | 6-87
10
10
  pull-theme.js | 77.77 | 56.25 | 93.75 | 76.84 | 25-28,37-38,69-70,77,94,102-103,117,130,145,156-157,163-166,178,234-239
11
11
  push-theme.js | 0 | 0 | 0 | 0 | 1-130
12
12
  select-merchant.js | 50 | 35.29 | 22.22 | 55.88 | 19,31,38,43-81
13
- serve.js | 19.29 | 0 | 0 | 19.29 | 13-27,37-162
14
- utils.js | 47.36 | 44.44 | 36.84 | 48.38 | 13,23-31,40,53-70,81-94,104,140-144,153-157,168-173,193-195
13
+ serve.js | 15.05 | 0 | 0 | 15.21 | 14-42,52-64,68-138,142-259
14
+ utils.js | 47.91 | 44.44 | 36.84 | 48.93 | 13,23-31,40,53-70,81-94,104,141-145,154-158,169-174,194-196
15
15
  src/partials | 0 | 0 | 0 | 0 |
16
16
  devmode.js | 0 | 0 | 100 | 0 | 4-21
17
- entrypoint.js | 0 | 0 | 0 | 0 | 6-55
17
+ entrypoint.js | 0 | 0 | 0 | 0 | 6-83
18
18
  ---------------------|---------|----------|---------|---------|-------------------------------------------------------------------------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ordergroove/smi-serve",
3
- "version": "1.9.24",
3
+ "version": "1.10.0",
4
4
  "description": "Utility to serve a Subscription Manager template locally",
5
5
  "keywords": [],
6
6
  "author": "Eugenio Lattanzio <eugenio.lattanzio@ordergroove.com>",
@@ -34,5 +34,5 @@
34
34
  "devDependencies": {
35
35
  "memfs": "^4.8.2"
36
36
  },
37
- "gitHead": "1a562611e5b0a8f8385ea949aabc1ce6b2cd241e"
37
+ "gitHead": "c8ea88c5a752ba4dcd5079dc26753fc85928b02d"
38
38
  }
package/smi-serve.js CHANGED
@@ -9,6 +9,7 @@ const figures = require('figures');
9
9
 
10
10
  const { getcwd, getNetFreePort, readRcEnv } = require('./src/utils');
11
11
  const { cliCallSelectMerchant } = require('./src/select-merchant');
12
+ const { cliCallSelectCustomer } = require('./src/impersonate');
12
13
  const { cliPullTheme, getMerchantThemes } = require('./src/pull-theme');
13
14
  const { cliPushTheme } = require('./src/push-theme');
14
15
  const { init, DirNotEmpty, OG_RC_FILE } = require('./src/init');
@@ -130,6 +131,17 @@ async function program() {
130
131
  }),
131
132
  handler: wrapHandler(cliPushTheme)
132
133
  })
134
+ .command({
135
+ command: 'select-customer [search]',
136
+ describe: 'Select a customer to impersonate for local development',
137
+ builder: y =>
138
+ y.positional('search', {
139
+ type: 'string',
140
+ description: 'Pre-fill customer search with this value'
141
+ }),
142
+ handler: wrapHandler(cliCallSelectCustomer)
143
+ })
144
+ .hide('select-customer')
133
145
  .option('verbose', {
134
146
  alias: 'v',
135
147
  type: 'boolean',
@@ -162,6 +174,10 @@ async function program() {
162
174
  .option('impersonate', {
163
175
  alias: 'i',
164
176
  type: 'string'
177
+ // Usage:
178
+ // --impersonate=selected Use previously selected customer (via select-customer command)
179
+ // --impersonate=<search> Pre-fill customer search and auto-select if only one match
180
+ // --impersonate (no value) Prompt for customer selection interactively
165
181
  })
166
182
  // impersonate only works for superusers; hide it from help for now
167
183
  .hide('impersonate')
@@ -177,6 +193,11 @@ async function program() {
177
193
  description: 'Use local SM packages'
178
194
  })
179
195
  .hide('local-assets')
196
+ .option('auto-cancel-flow', {
197
+ type: 'boolean',
198
+ description: 'Replace cancel subscription buttons with new cancel flow handler'
199
+ })
200
+ .hide('auto-cancel-flow')
180
201
  .parse()
181
202
  );
182
203
  }
@@ -2,10 +2,23 @@ const inquirer = require('inquirer');
2
2
  const inquirerPrompt = require('inquirer-autocomplete-prompt');
3
3
  const { getRC3Url } = require('./auth');
4
4
  const { getValidSettings } = require('./select-merchant');
5
+ const { writeRcEnv, readRcEnv } = require('./utils');
5
6
 
6
7
  inquirer.registerPrompt('autocomplete', inquirerPrompt);
7
8
 
8
- async function impersonate(args) {
9
+ async function tryToLoadSelectedCustomer(args) {
10
+ const selectedCustomer = await loadSelectedCustomer(args);
11
+
12
+ if (selectedCustomer) {
13
+ return selectedCustomer;
14
+ } else {
15
+ // No selected customer found, fall back to interactive prompt
16
+ console.log('No selected customer found. Please select a customer to impersonate.\n');
17
+ return null;
18
+ }
19
+ }
20
+
21
+ async function impersonate(args, autoSelectSingleResult = true) {
9
22
  const { token, merchant } = await getValidSettings(args);
10
23
 
11
24
  let customersResponse, az;
@@ -39,12 +52,27 @@ async function impersonate(args) {
39
52
  };
40
53
 
41
54
  let customer;
42
- if (impersonateInput) {
55
+ if (args.impersonate === 'selected') {
56
+ const selectedCustomer = await tryToLoadSelectedCustomer(args);
57
+ if (selectedCustomer) {
58
+ await search(selectedCustomer.email);
59
+ customer = customersResponse.customers.find(c => c.merchant_user_id === selectedCustomer.merchant_user_id);
60
+ if (customer) {
61
+ return [token, merchant, { ...customer, ts: customersResponse.hmac_timestamp }];
62
+ }
63
+ console.log(
64
+ `The previously selected customer (${selectedCustomer.email}) was not found. Please select a customer to impersonate.\n`
65
+ );
66
+ }
67
+ }
68
+
69
+ if (autoSelectSingleResult && impersonateInput && impersonateInput !== 'selected') {
43
70
  const s = await search(impersonateInput);
44
71
  if (s.length === 1) {
45
72
  customer = customersResponse.customers[0];
46
73
  }
47
74
  }
75
+
48
76
  if (!customer)
49
77
  customer = await inquirer
50
78
  .prompt([
@@ -61,21 +89,57 @@ async function impersonate(args) {
61
89
  return result;
62
90
  });
63
91
 
64
- console.log(`\
92
+ return [token, merchant, { ...customer, ts: customersResponse.hmac_timestamp }];
93
+ }
94
+
95
+ async function saveSelectedCustomer(args, customer) {
96
+ await writeRcEnv(args, {
97
+ selectedCustomer: {
98
+ merchant_user_id: customer.merchant_user_id,
99
+ email: customer.email
100
+ }
101
+ });
102
+ }
103
+
104
+ async function loadSelectedCustomer(args) {
105
+ const settings = await readRcEnv(args);
106
+ const customer = settings.selectedCustomer;
107
+
108
+ // Validate required fields
109
+ if (customer && customer.merchant_user_id && customer.email) {
110
+ return customer;
111
+ }
112
+
113
+ return null;
114
+ }
115
+
116
+ async function cliCallSelectCustomer(args) {
117
+ // Pre-fill search with currently selected customer's email if no search term provided
118
+ if (!args.search) {
119
+ const selectedCustomer = await loadSelectedCustomer(args);
120
+ if (selectedCustomer && selectedCustomer.email) {
121
+ args.impersonate = selectedCustomer.email;
122
+ }
123
+ } else {
124
+ args.impersonate = args.search;
125
+ }
126
+
127
+ const [token, merchant, customer] = await impersonate(args, false);
128
+ await saveSelectedCustomer(args, customer);
65
129
 
66
- -------------------------------------------------------------------------------
67
- Browsing Subscription Manager for customer: ${customer.first_name} ${customer.last_name} (${customer.email})
130
+ console.log(`
131
+ Successfully saved customer selection: ${customer.first_name} ${customer.last_name}.
68
132
 
69
- Please note:
70
- This tool browses the live Subscription Manager of the customer you are impersonating.
71
- Do not make any changes to orders/subscriptions as they will actually
72
- take effect. This tool is intended for troubleshooting and previewing
73
- only. Please use the CSA to edit order/subscription data.
133
+ You can now run: smi-serve --impersonate=selected
74
134
 
75
- -------------------------------------------------------------------------------
135
+ The selected customer data will be used automatically without prompting.
136
+ To change the customer, run: smi-serve select-customer
76
137
  `);
77
138
 
78
- return [token, merchant, { ...customer, ts: customersResponse.hmac_timestamp }];
139
+ return { token, merchant, customer };
79
140
  }
80
141
 
81
142
  exports.impersonate = impersonate;
143
+ exports.saveSelectedCustomer = saveSelectedCustomer;
144
+ exports.loadSelectedCustomer = loadSelectedCustomer;
145
+ exports.cliCallSelectCustomer = cliCallSelectCustomer;
@@ -4,27 +4,43 @@ import mainTemplate from '~/views/main.liquid';
4
4
  import { merchant_id, auth_config, smi_core_version, use_local_assets } from './devmode';
5
5
 
6
6
  const smiCoreUrl = use_local_assets
7
- ? `http://${window.location.hostname}:8080`
7
+ ? `http://${window.location.hostname}:${window.location.port}/smi-core`
8
8
  : `https://static.ordergroove.com/@ordergroove/smi-core/${smi_core_version}/dist`;
9
9
 
10
10
  const smiPreviewUrl = use_local_assets
11
- ? `http://${window.location.hostname}:8080`
11
+ ? `http://${window.location.hostname}:${window.location.port}/smi-preview`
12
12
  : `https://static.ordergroove.com/@ordergroove/smi-preview/latest/dist`;
13
13
 
14
- // TODO this should eventually load from SOS
15
- const cancelFlowsUrl = `http://${window.location.hostname}:4002`;
14
+ // Load cancel-flow from same port when using local assets
15
+ const cancelFlowsUrl = use_local_assets
16
+ ? `http://${window.location.hostname}:${window.location.port}/cancel-flow`
17
+ : `https://static.ordergroove.com/@ordergroove/cancel-flow/latest/dist`;
16
18
 
17
19
  // only run on initial load, not hot reload
18
20
  if (!window.og?.smi) {
21
+ window.og = window.og || {};
19
22
  if (auth_config && merchant_id) {
20
- waitForScriptToLoad(`${smiCoreUrl}/smi.js`).then(() => {
23
+ let smiCorePromise;
24
+ if (use_local_assets) {
25
+ // When using local assets, smi-serve builds smi-core as an ES Module
26
+ smiCorePromise = import(`${smiCoreUrl}/smi.js`).then(smiModule => {
27
+ window.og.smi = {
28
+ ...smiModule, // Spread all named exports
29
+ bootstrap: smiModule.default // bootstrap is the default export
30
+ };
31
+ });
32
+ } else {
33
+ // When loaded from SOS, smi-core is an IIFE bundle that sets window.og.smi directly
34
+ smiCorePromise = waitForScriptToLoad(`${smiCoreUrl}/smi.js`);
35
+ }
36
+
37
+ smiCorePromise.then(() => {
21
38
  window.og.smi.bootstrap(
22
39
  {
23
40
  merchant_id,
24
41
  ...auth_config,
25
42
  core_settings: {
26
- // enable discount codes so they're fetching when the SM starts up
27
- // when deployed, this value is automatically read from theme-settings.json, but in smi-serve we need to set it directly
43
+ // when deployed, discount_codes_enabled is automatically read from theme-settings.json, but in smi-serve we need to set it directly
28
44
  discount_codes_enabled: true,
29
45
  cancel_flow_discount_enabled: true,
30
46
  sm_tracking_enabled: true
@@ -34,15 +50,27 @@ if (!window.og?.smi) {
34
50
  );
35
51
  });
36
52
  } else {
37
- waitForScriptToLoad(`${smiPreviewUrl}/smi-preview.js`).then(() => {
38
- const smiPreview = window.og['smi-preview'];
53
+ let smiPreviewPromise;
54
+ if (use_local_assets) {
55
+ // When using local assets, smi-serve builds smi-preview as an ES Module
56
+ smiPreviewPromise = import(`${smiPreviewUrl}/smi-preview.js`);
57
+ } else {
58
+ smiPreviewPromise = waitForScriptToLoad(`${smiPreviewUrl}/smi-preview.js`).then(() => window.og['smi-preview']);
59
+ }
60
+ smiPreviewPromise.then(smiPreview => {
39
61
  const preview = smiPreview.createPreview(document.body, smi_core_version);
40
62
  preview.template = mainTemplate;
41
63
  preview.locale = 'en-US';
42
64
  });
43
65
  }
44
66
 
45
- waitForScriptToLoad(`${cancelFlowsUrl}/cancel-flow.js`);
67
+ if (use_local_assets) {
68
+ // smi-serve builds cancel-flow as an ES Module
69
+ import(`${cancelFlowsUrl}/cancel-flow.js`);
70
+ } else {
71
+ // When loaded from SOS, cancel-flow is an IIFE bundle
72
+ waitForScriptToLoad(`${cancelFlowsUrl}/cancel-flow.js`);
73
+ }
46
74
  }
47
75
 
48
76
  async function waitForScriptToLoad(src) {
@@ -6,12 +6,18 @@
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1" />
7
7
  <link rel="stylesheet" href="/main.css" />
8
8
  <script>
9
- new EventSource('/esbuild').addEventListener('change', ev => {
9
+ // Track last applied cancel-flow CSS for hot reload comparison
10
+ let lastCancelFlowCss;
11
+ let initialCancelFlowCssPromise = fetch(`/cancel-flow/styles.css`).then(r => r.text());
12
+
13
+ new EventSource('/esbuild').addEventListener('change', async ev => {
10
14
  console.log('File changed, running hot reload');
11
15
  let stylesheet = document.querySelector('link[rel="stylesheet"]');
12
16
  try {
13
17
  const { updated, added } = JSON.parse(ev.data);
14
18
  const ts = new Date().getTime();
19
+
20
+ // SM template CSS updated
15
21
  if (updated.includes('/main.css') || added.includes('/main.css')) {
16
22
  // https://esbuild.github.io/api/#hot-reloading-css
17
23
  const newStylesheet = document.createElement('link');
@@ -21,14 +27,54 @@
21
27
  newStylesheet.onload = () => stylesheet.remove();
22
28
  document.head.appendChild(newStylesheet);
23
29
  }
30
+
31
+ // other SM template files changed
24
32
  if (updated.includes('/entrypoint.js')) {
25
33
  import('./entrypoint.js?_=' + ts).then(({ mainTemplate }) => {
26
34
  const smi = window.og.smi;
27
35
  smi.HTMLSmiElement.template = mainTemplate(smi.html, smi.repeat);
28
36
  });
29
37
  }
38
+
39
+ // Handle smi-core changes
40
+ if (updated.some(file => file.includes('/smi-core/smi.js'))) {
41
+ console.log('smi-core changed, reloading page...');
42
+ window.location.reload();
43
+ }
44
+
45
+ // Handle cancel-flow changes
46
+ if (updated.includes('/cancel-flow/cancel-flow.js')) {
47
+ if (!lastCancelFlowCss) {
48
+ // for the initial update, wait for the CSS to be fetched
49
+ lastCancelFlowCss = await initialCancelFlowCssPromise;
50
+ }
51
+ const css = await fetch(`/cancel-flow/styles.css?_=${ts}`).then(r => r.text());
52
+
53
+ if (css !== lastCancelFlowCss) {
54
+ // styles are changed, only replace the styles without reloading the module
55
+ window.og.cancelFlow.DEV__updateStyles(css);
56
+ lastCancelFlowCss = css;
57
+ console.log('✓ Cancel-flow styles updated');
58
+ } else {
59
+ // styles are the same, reload the module
60
+ console.log('Cancel-flow JS changed, running hot reload');
61
+ const wasOpen = window.og.cancelFlow.isOpen();
62
+
63
+ window.og.cancelFlow.closeCancelFlow();
64
+ delete window.og.cancelFlow;
65
+
66
+ await import(`/cancel-flow/cancel-flow.js?_=${ts}`);
67
+ console.log('Cancel-flow reloaded successfully');
68
+
69
+ if (wasOpen) {
70
+ window.og.cancelFlow.DEV__reopenCancelFlow();
71
+ }
72
+ }
73
+
74
+ lastCancelFlowCss = css;
75
+ }
30
76
  } catch (err) {
31
- console.error(err);
77
+ console.error('Hot reload error:', err);
32
78
  }
33
79
  });
34
80
  </script>
@@ -76,7 +76,7 @@ async function selectMerchant(args, callFromCLI = false) {
76
76
  return merchants[merchantsList.findIndex(it => it === merchantText)];
77
77
  });
78
78
 
79
- await writeRcEnv(args, { merchant, token });
79
+ await writeRcEnv(args, { merchant, token, selectedCustomer: undefined });
80
80
 
81
81
  return merchant;
82
82
  }
package/src/serve.js CHANGED
@@ -1,5 +1,6 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
+ const { createRequire } = require('module');
3
4
  const esbuild = require('esbuild');
4
5
  const { lessLoader } = require('esbuild-plugin-less');
5
6
  const precompile = require('@ordergroove/smi-precompile');
@@ -19,6 +20,20 @@ async function getGlobals(argv) {
19
20
  [_token, merchant, customer] = await impersonate(argv);
20
21
 
21
22
  hmacAuth = customer && [customer.merchant_user_id, customer.ts, customer.hash].join('|');
23
+
24
+ console.log(`\
25
+
26
+ -------------------------------------------------------------------------------
27
+ Browsing Subscription Manager for customer: ${customer.first_name} ${customer.last_name} (${customer.email})
28
+
29
+ Please note:
30
+ This tool browses the live Subscription Manager of the customer you are impersonating.
31
+ Do not make any changes to orders/subscriptions as they will actually
32
+ take effect. This tool is intended for troubleshooting and previewing
33
+ only. Please use the CSA to edit order/subscription data.
34
+
35
+ -------------------------------------------------------------------------------
36
+ `);
22
37
  }
23
38
 
24
39
  const packageJson = readPackageJson(getcwd(argv));
@@ -33,6 +48,22 @@ async function getGlobals(argv) {
33
48
  };
34
49
  }
35
50
 
51
+ const replaceCancelFlowClickHandlers = file => {
52
+ if (file.name.endsWith('/more-options-dropdown.liquid') || file.name.endsWith('/order-item-buttons.liquid')) {
53
+ // Replace @click handlers on cancel buttons with new cancel flow handler
54
+ const modifiedContent = file.content.replace(/@click="[^"]*"/g, (match, offset) => {
55
+ // Check if this is a cancel button by looking at the context
56
+ const contextBefore = file.content.substring(Math.max(0, offset - 200), offset);
57
+ if (contextBefore.includes('cancel')) {
58
+ return `onclick="window.og?.cancelFlow?.openCancelFlow({ subscriptionId: '{{ subscription.public_id }}' });"`;
59
+ }
60
+ return match;
61
+ });
62
+ return { ...file, content: modifiedContent };
63
+ }
64
+ return file;
65
+ };
66
+
36
67
  const smiDevModePlugin = (globals, args) => {
37
68
  const cwd = getcwd(args);
38
69
  /** @type {import('esbuild').Plugin} */
@@ -45,11 +76,18 @@ const smiDevModePlugin = (globals, args) => {
45
76
  ignore: ['**/node_modules/**', 'node_modules/**']
46
77
  });
47
78
 
48
- const fileList = await Promise.all(
49
- files.map(async file => ({
50
- name: file.substring(cwd.length),
51
- content: await fs.promises.readFile(file, 'utf8').catch(() => '')
52
- }))
79
+ let fileList = await Promise.all(
80
+ files.map(async rawFile => {
81
+ const file = {
82
+ name: rawFile.substring(cwd.length),
83
+ content: await fs.promises.readFile(rawFile, 'utf8').catch(() => '')
84
+ };
85
+ // If auto-cancel-flow is enabled, replace cancel button handlers
86
+ if (args.autoCancelFlow) {
87
+ return replaceCancelFlowClickHandlers(file);
88
+ }
89
+ return file;
90
+ })
53
91
  );
54
92
 
55
93
  try {
@@ -100,6 +138,52 @@ const smiDevModePlugin = (globals, args) => {
100
138
  return plugin;
101
139
  };
102
140
 
141
+ const getPlugins = async argv => {
142
+ const { cwd, outdir } = argv;
143
+
144
+ const globals = await getGlobals(argv);
145
+ const devModePlugin = smiDevModePlugin(globals, argv);
146
+ const less = lessLoader({
147
+ plugins: [new VariableExtractorPlugin()]
148
+ });
149
+
150
+ if (argv.localAssets) {
151
+ // when --local-assets is enabled, smi-serve builds smi-core and cancel-flow locally
152
+ // we need to copy over their build plugins for consistency
153
+
154
+ const { createResolveSmiCoreModulesPlugin } = require('../../smi-core/build.js');
155
+ const { createLessInjectorPlugin } = require('../../cancel-flow/build.js');
156
+
157
+ const smiCoreRequire = createRequire(path.join(__dirname, '../../smi-core', 'package.json'));
158
+
159
+ return [
160
+ // the cancel-flow less plugin should run before the main less plugin, since we want to handle those files differently
161
+ createLessInjectorPlugin({
162
+ pathFilter: /cancel-flow/,
163
+ cssOutputPath: path.join(cwd, outdir, 'cancel-flow', 'styles.css')
164
+ }),
165
+ devModePlugin,
166
+ less,
167
+ {
168
+ name: 'resolve_smi_core_modules_local_filtered',
169
+ setup(build) {
170
+ const basePlugin = createResolveSmiCoreModulesPlugin(smiCoreRequire);
171
+ basePlugin.setup({
172
+ onResolve(options, callback) {
173
+ build.onResolve(options, args => {
174
+ // Only apply to smi-core files
175
+ if (!args.importer || !args.importer.includes('smi-core')) return;
176
+ return callback(args);
177
+ });
178
+ }
179
+ });
180
+ }
181
+ }
182
+ ];
183
+ }
184
+ return [devModePlugin, less];
185
+ };
186
+
103
187
  async function serve(argv) {
104
188
  await getValidLoginAndCurrentMerchant(argv);
105
189
  const { port, outdir, verbose } = argv;
@@ -118,12 +202,24 @@ async function serve(argv) {
118
202
  const smiIndexSource = fs.readFileSync(`${__dirname}/partials/index.html`, 'utf8');
119
203
  fs.writeFileSync(smiIndexFile, smiIndexSource, { encoding: 'utf8' });
120
204
 
121
- const globals = await getGlobals(argv);
205
+ const plugins = await getPlugins(argv);
122
206
 
123
207
  /** @type {import('esbuild').BuildOptions} */
124
208
  const buildConf = {
125
- entryPoints: [path.join(__dirname, 'partials', 'entrypoint.js'), path.join(cwd, mainLess)],
126
- entryNames: '[name]',
209
+ entryPoints: {
210
+ entrypoint: path.join(__dirname, 'partials', 'entrypoint.js'),
211
+ main: path.join(cwd, mainLess),
212
+ // when --local-assets, also build smi-core and cancel-flow packages and serve from the same dev server
213
+ // note: this means that smi-core and cancel-flow are being built as ESM modules here, instead of IIFE bundles as when built normally
214
+ ...(argv.localAssets
215
+ ? {
216
+ 'smi-core/smi': path.join(__dirname, '../../smi-core', 'src/index.ts'),
217
+ 'cancel-flow/cancel-flow': path.join(__dirname, '../../cancel-flow', 'src/index.ts'),
218
+ 'smi-preview/smi-preview': path.join(__dirname, '../../smi-preview', 'src/smi-preview.js')
219
+ }
220
+ : {})
221
+ },
222
+ entryNames: '[dir]/[name]',
127
223
 
128
224
  logLevel: verbose ? 'verbose' : 'error',
129
225
  nodePaths: [path.join(cwd, 'node_modules')],
@@ -137,12 +233,7 @@ async function serve(argv) {
137
233
  sourcemap: true,
138
234
 
139
235
  outdir: path.join(cwd, outdir),
140
- plugins: [
141
- smiDevModePlugin(globals, argv),
142
- lessLoader({
143
- plugins: [new VariableExtractorPlugin()]
144
- })
145
- ]
236
+ plugins
146
237
  };
147
238
 
148
239
  if (!mainLess) {
@@ -159,6 +250,12 @@ async function serve(argv) {
159
250
  });
160
251
 
161
252
  console.log(`Dev server listening on http://${actualHost}:${actualPort}`);
253
+ if (argv.localAssets) {
254
+ console.log('Serving local packages:');
255
+ console.log(` smi-core: /smi-core/smi.js`);
256
+ console.log(` cancel-flow: /cancel-flow/cancel-flow.js`);
257
+ console.log(` smi-preview: /smi-preview/smi-preview.js`);
258
+ }
162
259
  open(`http://${actualHost}:${actualPort}`);
163
260
  }
164
261
  exports.serve = serve;
package/src/utils.js CHANGED
@@ -131,7 +131,8 @@ async function writeRc(args, settings) {
131
131
 
132
132
  async function writeRcEnv(args, settings) {
133
133
  const { env } = args;
134
- await writeRc(args, { [env]: settings });
134
+ const existingEnvSettings = await readRcEnv(args);
135
+ await writeRc(args, { [env]: { ...existingEnvSettings, ...settings } });
135
136
  }
136
137
 
137
138
  exports.writeRcEnv = writeRcEnv;