@wix/himalaya-cli 0.1573.0 → 0.1575.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/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/app-config.d.ts +16 -5
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/define-app.d.ts +6 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/message-format.d.ts +59 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/telemetry/wix-bi/src/index.d.ts +15 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/telemetry/wix-bi/src/oneapp.d.ts +90 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core.mjs +3 -3
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/l10n.mjs +8 -3
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdui.mjs +3 -3
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-bi.mjs +165 -5
- package/dist/cli.mjs +5261 -2937
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/designing-himi-screens.md +7 -1
- package/guides/hhp.md +2 -2
- package/guides/himi-json-output.md +53 -2
- package/guides/himi-mcp.md +1 -1
- package/guides/himi-test.md +3 -2
- package/guides/iap-products.md +1 -1
- package/guides/importing-oneapp-translations.md +115 -0
- package/guides/index.json +6 -0
- package/guides/one-app-section-mappings.md +16 -4
- package/guides/one-app-to-himi-app.md +167 -10
- package/guides/push-cli-onboarding.md +10 -0
- package/guides/qa-builds.md +21 -1
- package/guides/templates.md +3 -2
- package/guides/testing-himi-apps.md +1 -1
- package/package.json +3 -3
- package/templates/beauty-salon/dev/index.ts +96 -133
- package/templates/beauty-salon/tier5-src/_shared/exclusive-writes.ts +66 -0
- package/templates/beauty-salon/tier5-src/himi-branded-lite-cart/index.ts +18 -5
- package/templates/beauty-salon-owner/dev/index.ts +27 -6
- package/templates/beauty-salon-owner/tier5-src/_shared/exclusive-writes.ts +66 -0
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-post-form/index.ts +5 -1
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-product-form/index.ts +5 -1
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-service-form/index.ts +5 -1
- package/templates/branded-lite/dev/index.ts +136 -142
- package/templates/branded-lite/l10n/en.json +570 -0
- package/templates/branded-lite/l10n/he.json +200 -0
- package/templates/branded-lite/tier5-src/_shared/business-chat-copy.ts +40 -0
- package/templates/branded-lite/tier5-src/_shared/business-chat-message-model.ts +1 -1
- package/templates/branded-lite/tier5-src/_shared/business-chat-model.ts +3 -2
- package/templates/branded-lite/tier5-src/_shared/business-chat-presenter.ts +26 -21
- package/templates/branded-lite/tier5-src/_shared/exclusive-writes.ts +66 -0
- package/templates/branded-lite/tier5-src/business-chat/index.ts +184 -63
- package/templates/branded-lite/tier5-src/himi-branded-lite-cart/index.ts +18 -5
- package/templates/community-club/dev/index.ts +22 -6
- package/templates/community-club-owner/dev/index.ts +27 -6
- package/templates/community-club-owner/tier5-src/_shared/exclusive-writes.ts +66 -0
- package/templates/community-club-owner/tier5-src/himi-owner-lite-event-form/index.ts +5 -1
- package/templates/community-club-owner/tier5-src/himi-owner-lite-post-form/index.ts +5 -1
- package/templates/community-club-owner/tier5-src/himi-owner-lite-product-form/index.ts +5 -1
- package/templates/events-meetups/dev/index.ts +22 -6
- package/templates/events-meetups-owner/dev/index.ts +25 -6
- package/templates/events-meetups-owner/tier5-src/_shared/exclusive-writes.ts +66 -0
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-event-form/index.ts +5 -1
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-post-form/index.ts +5 -1
- package/templates/gym-fitness/dev/index.ts +96 -133
- package/templates/gym-fitness/tier5-src/_shared/exclusive-writes.ts +66 -0
- package/templates/gym-fitness/tier5-src/himi-branded-lite-cart/index.ts +18 -5
- package/templates/gym-fitness-owner/dev/index.ts +28 -6
- package/templates/gym-fitness-owner/tier5-src/_shared/exclusive-writes.ts +66 -0
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-event-form/index.ts +5 -1
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-post-form/index.ts +5 -1
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-product-form/index.ts +5 -1
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-service-form/index.ts +5 -1
- package/templates/himi-chat/dev/index.ts +22 -6
- package/templates/nonprofit-cause/dev/index.ts +22 -6
- package/templates/nonprofit-cause-owner/dev/index.ts +26 -6
- package/templates/nonprofit-cause-owner/tier5-src/_shared/exclusive-writes.ts +66 -0
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-event-form/index.ts +5 -1
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-post-form/index.ts +5 -1
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-service-form/index.ts +5 -1
- package/templates/owner-lite/dev/index.ts +28 -6
- package/templates/owner-lite/tier5-src/_shared/exclusive-writes.ts +66 -0
- package/templates/owner-lite/tier5-src/himi-owner-lite-event-form/index.ts +5 -1
- package/templates/owner-lite/tier5-src/himi-owner-lite-post-form/index.ts +5 -1
- package/templates/owner-lite/tier5-src/himi-owner-lite-product-form/index.ts +5 -1
- package/templates/owner-lite/tier5-src/himi-owner-lite-service-form/index.ts +5 -1
- package/templates/podcast-creator/dev/index.ts +22 -6
- package/templates/podcast-creator-owner/dev/index.ts +27 -6
- package/templates/podcast-creator-owner/tier5-src/_shared/exclusive-writes.ts +66 -0
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-event-form/index.ts +5 -1
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-post-form/index.ts +5 -1
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-product-form/index.ts +5 -1
- package/templates/portfolio-creative/dev/index.ts +96 -133
- package/templates/portfolio-creative/tier5-src/_shared/exclusive-writes.ts +66 -0
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-cart/index.ts +18 -5
- package/templates/portfolio-creative-owner/dev/index.ts +27 -6
- package/templates/portfolio-creative-owner/tier5-src/_shared/exclusive-writes.ts +66 -0
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-post-form/index.ts +5 -1
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-product-form/index.ts +5 -1
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-service-form/index.ts +5 -1
- package/templates/restaurant/dev/index.ts +22 -6
- package/templates/restaurant-owner/dev/index.ts +28 -6
- package/templates/restaurant-owner/tier5-src/_shared/exclusive-writes.ts +66 -0
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-event-form/index.ts +5 -1
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-post-form/index.ts +5 -1
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-product-form/index.ts +5 -1
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-service-form/index.ts +5 -1
- package/templates/retail-store/dev/index.ts +96 -133
- package/templates/retail-store/tier5-src/_shared/exclusive-writes.ts +66 -0
- package/templates/retail-store/tier5-src/himi-branded-lite-cart/index.ts +18 -5
- package/templates/retail-store-owner/dev/index.ts +26 -6
- package/templates/retail-store-owner/tier5-src/_shared/exclusive-writes.ts +66 -0
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-post-form/index.ts +5 -1
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-product-form/index.ts +5 -1
- package/templates/surface-showcase/dev/index.ts +22 -6
- package/templates/yoga-studio/dev/index.ts +22 -6
- package/templates/yoga-studio-owner/dev/index.ts +26 -6
- package/templates/yoga-studio-owner/tier5-src/_shared/exclusive-writes.ts +66 -0
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-event-form/index.ts +5 -1
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-post-form/index.ts +5 -1
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-service-form/index.ts +5 -1
|
@@ -15759,39 +15759,28 @@ const SCREENS = runtimeSetting({
|
|
|
15759
15759
|
"id": "himi_cart.qty_minus",
|
|
15760
15760
|
"body": {
|
|
15761
15761
|
"package": "himalaya",
|
|
15762
|
-
"type": "
|
|
15762
|
+
"type": "Button",
|
|
15763
15763
|
"props": {
|
|
15764
|
-
"
|
|
15765
|
-
"
|
|
15766
|
-
|
|
15767
|
-
|
|
15768
|
-
"
|
|
15769
|
-
"package": "himalaya",
|
|
15770
|
-
"type": "Icon",
|
|
15771
|
-
"props": {
|
|
15772
|
-
"name": "minus",
|
|
15773
|
-
"size": 24,
|
|
15774
|
-
"tint": "textPrimary"
|
|
15775
|
-
}
|
|
15776
|
-
},
|
|
15777
|
-
"modifiers": {
|
|
15778
|
-
"accessibilityRole": "decorative"
|
|
15779
|
-
}
|
|
15764
|
+
"title": "Decrease quantity",
|
|
15765
|
+
"action": {
|
|
15766
|
+
"actionId": "tier5.himiStoreCart.decrement",
|
|
15767
|
+
"params": {
|
|
15768
|
+
"id": "$item.id"
|
|
15780
15769
|
}
|
|
15781
|
-
|
|
15770
|
+
},
|
|
15771
|
+
"style": "tertiary",
|
|
15772
|
+
"iconOnly": true,
|
|
15773
|
+
"leadingIcon": "minus",
|
|
15774
|
+
"cornerRadius": 22,
|
|
15775
|
+
"minHeight": 44,
|
|
15776
|
+
"disabledPath": "$service:himiStoreCart.writeBusy"
|
|
15782
15777
|
}
|
|
15783
15778
|
},
|
|
15784
15779
|
"modifiers": {
|
|
15785
15780
|
"width": 44,
|
|
15786
15781
|
"height": 44,
|
|
15787
|
-
"onTap": {
|
|
15788
|
-
"actionId": "tier5.himiStoreCart.decrement",
|
|
15789
|
-
"params": {
|
|
15790
|
-
"id": "$item.id"
|
|
15791
|
-
}
|
|
15792
|
-
},
|
|
15793
|
-
"accessibilityRole": "button",
|
|
15794
15782
|
"accessibilityLabel": "Decrease quantity",
|
|
15783
|
+
"accessibilityRole": "button",
|
|
15795
15784
|
"haptic": "light"
|
|
15796
15785
|
}
|
|
15797
15786
|
},
|
|
@@ -15814,39 +15803,28 @@ const SCREENS = runtimeSetting({
|
|
|
15814
15803
|
"id": "himi_cart.qty_plus",
|
|
15815
15804
|
"body": {
|
|
15816
15805
|
"package": "himalaya",
|
|
15817
|
-
"type": "
|
|
15806
|
+
"type": "Button",
|
|
15818
15807
|
"props": {
|
|
15819
|
-
"
|
|
15820
|
-
"
|
|
15821
|
-
|
|
15822
|
-
|
|
15823
|
-
"
|
|
15824
|
-
"package": "himalaya",
|
|
15825
|
-
"type": "Icon",
|
|
15826
|
-
"props": {
|
|
15827
|
-
"name": "plus",
|
|
15828
|
-
"size": 24,
|
|
15829
|
-
"tint": "textPrimary"
|
|
15830
|
-
}
|
|
15831
|
-
},
|
|
15832
|
-
"modifiers": {
|
|
15833
|
-
"accessibilityRole": "decorative"
|
|
15834
|
-
}
|
|
15808
|
+
"title": "Increase quantity",
|
|
15809
|
+
"action": {
|
|
15810
|
+
"actionId": "tier5.himiStoreCart.increment",
|
|
15811
|
+
"params": {
|
|
15812
|
+
"id": "$item.id"
|
|
15835
15813
|
}
|
|
15836
|
-
|
|
15814
|
+
},
|
|
15815
|
+
"style": "tertiary",
|
|
15816
|
+
"iconOnly": true,
|
|
15817
|
+
"leadingIcon": "plus",
|
|
15818
|
+
"cornerRadius": 22,
|
|
15819
|
+
"minHeight": 44,
|
|
15820
|
+
"disabledPath": "$service:himiStoreCart.writeBusy"
|
|
15837
15821
|
}
|
|
15838
15822
|
},
|
|
15839
15823
|
"modifiers": {
|
|
15840
15824
|
"width": 44,
|
|
15841
15825
|
"height": 44,
|
|
15842
|
-
"onTap": {
|
|
15843
|
-
"actionId": "tier5.himiStoreCart.increment",
|
|
15844
|
-
"params": {
|
|
15845
|
-
"id": "$item.id"
|
|
15846
|
-
}
|
|
15847
|
-
},
|
|
15848
|
-
"accessibilityRole": "button",
|
|
15849
15826
|
"accessibilityLabel": "Increase quantity",
|
|
15827
|
+
"accessibilityRole": "button",
|
|
15850
15828
|
"haptic": "light"
|
|
15851
15829
|
}
|
|
15852
15830
|
},
|
|
@@ -15862,39 +15840,28 @@ const SCREENS = runtimeSetting({
|
|
|
15862
15840
|
"id": "himi_cart.save_filled",
|
|
15863
15841
|
"body": {
|
|
15864
15842
|
"package": "himalaya",
|
|
15865
|
-
"type": "
|
|
15843
|
+
"type": "Button",
|
|
15866
15844
|
"props": {
|
|
15867
|
-
"
|
|
15868
|
-
"
|
|
15869
|
-
|
|
15870
|
-
|
|
15871
|
-
"
|
|
15872
|
-
"package": "himalaya",
|
|
15873
|
-
"type": "Icon",
|
|
15874
|
-
"props": {
|
|
15875
|
-
"name": "heart_fill",
|
|
15876
|
-
"size": 24,
|
|
15877
|
-
"tint": "textPrimary"
|
|
15878
|
-
}
|
|
15879
|
-
},
|
|
15880
|
-
"modifiers": {
|
|
15881
|
-
"accessibilityRole": "decorative"
|
|
15882
|
-
}
|
|
15845
|
+
"title": "Remove from wishlist",
|
|
15846
|
+
"action": {
|
|
15847
|
+
"actionId": "tier5.himiStoreCart.save",
|
|
15848
|
+
"params": {
|
|
15849
|
+
"id": "$item.id"
|
|
15883
15850
|
}
|
|
15884
|
-
|
|
15851
|
+
},
|
|
15852
|
+
"style": "tertiary",
|
|
15853
|
+
"iconOnly": true,
|
|
15854
|
+
"leadingIcon": "heart_fill",
|
|
15855
|
+
"cornerRadius": 22,
|
|
15856
|
+
"minHeight": 44,
|
|
15857
|
+
"disabledPath": "$service:himiStoreCart.writeBusy"
|
|
15885
15858
|
}
|
|
15886
15859
|
},
|
|
15887
15860
|
"modifiers": {
|
|
15888
15861
|
"width": 44,
|
|
15889
15862
|
"height": 44,
|
|
15890
|
-
"onTap": {
|
|
15891
|
-
"actionId": "tier5.himiStoreCart.save",
|
|
15892
|
-
"params": {
|
|
15893
|
-
"id": "$item.id"
|
|
15894
|
-
}
|
|
15895
|
-
},
|
|
15896
|
-
"accessibilityRole": "button",
|
|
15897
15863
|
"accessibilityLabel": "Remove from wishlist",
|
|
15864
|
+
"accessibilityRole": "button",
|
|
15898
15865
|
"haptic": "light",
|
|
15899
15866
|
"hiddenPath": "$item.notSaved"
|
|
15900
15867
|
}
|
|
@@ -15903,39 +15870,28 @@ const SCREENS = runtimeSetting({
|
|
|
15903
15870
|
"id": "himi_cart.save",
|
|
15904
15871
|
"body": {
|
|
15905
15872
|
"package": "himalaya",
|
|
15906
|
-
"type": "
|
|
15873
|
+
"type": "Button",
|
|
15907
15874
|
"props": {
|
|
15908
|
-
"
|
|
15909
|
-
"
|
|
15910
|
-
|
|
15911
|
-
|
|
15912
|
-
"
|
|
15913
|
-
"package": "himalaya",
|
|
15914
|
-
"type": "Icon",
|
|
15915
|
-
"props": {
|
|
15916
|
-
"name": "heart",
|
|
15917
|
-
"size": 24,
|
|
15918
|
-
"tint": "textPrimary"
|
|
15919
|
-
}
|
|
15920
|
-
},
|
|
15921
|
-
"modifiers": {
|
|
15922
|
-
"accessibilityRole": "decorative"
|
|
15923
|
-
}
|
|
15875
|
+
"title": "Add to wishlist",
|
|
15876
|
+
"action": {
|
|
15877
|
+
"actionId": "tier5.himiStoreCart.save",
|
|
15878
|
+
"params": {
|
|
15879
|
+
"id": "$item.id"
|
|
15924
15880
|
}
|
|
15925
|
-
|
|
15881
|
+
},
|
|
15882
|
+
"style": "tertiary",
|
|
15883
|
+
"iconOnly": true,
|
|
15884
|
+
"leadingIcon": "heart",
|
|
15885
|
+
"cornerRadius": 22,
|
|
15886
|
+
"minHeight": 44,
|
|
15887
|
+
"disabledPath": "$service:himiStoreCart.writeBusy"
|
|
15926
15888
|
}
|
|
15927
15889
|
},
|
|
15928
15890
|
"modifiers": {
|
|
15929
15891
|
"width": 44,
|
|
15930
15892
|
"height": 44,
|
|
15931
|
-
"onTap": {
|
|
15932
|
-
"actionId": "tier5.himiStoreCart.save",
|
|
15933
|
-
"params": {
|
|
15934
|
-
"id": "$item.id"
|
|
15935
|
-
}
|
|
15936
|
-
},
|
|
15937
|
-
"accessibilityRole": "button",
|
|
15938
15893
|
"accessibilityLabel": "Add to wishlist",
|
|
15894
|
+
"accessibilityRole": "button",
|
|
15939
15895
|
"haptic": "light",
|
|
15940
15896
|
"hiddenPath": "$item.saved"
|
|
15941
15897
|
}
|
|
@@ -15944,39 +15900,28 @@ const SCREENS = runtimeSetting({
|
|
|
15944
15900
|
"id": "himi_cart.remove",
|
|
15945
15901
|
"body": {
|
|
15946
15902
|
"package": "himalaya",
|
|
15947
|
-
"type": "
|
|
15903
|
+
"type": "Button",
|
|
15948
15904
|
"props": {
|
|
15949
|
-
"
|
|
15950
|
-
"
|
|
15951
|
-
|
|
15952
|
-
|
|
15953
|
-
"
|
|
15954
|
-
"package": "himalaya",
|
|
15955
|
-
"type": "Icon",
|
|
15956
|
-
"props": {
|
|
15957
|
-
"name": "trash",
|
|
15958
|
-
"size": 24,
|
|
15959
|
-
"tint": "textPrimary"
|
|
15960
|
-
}
|
|
15961
|
-
},
|
|
15962
|
-
"modifiers": {
|
|
15963
|
-
"accessibilityRole": "decorative"
|
|
15964
|
-
}
|
|
15905
|
+
"title": "Remove from cart",
|
|
15906
|
+
"action": {
|
|
15907
|
+
"actionId": "tier5.himiStoreCart.remove",
|
|
15908
|
+
"params": {
|
|
15909
|
+
"id": "$item.id"
|
|
15965
15910
|
}
|
|
15966
|
-
|
|
15911
|
+
},
|
|
15912
|
+
"style": "tertiary",
|
|
15913
|
+
"iconOnly": true,
|
|
15914
|
+
"leadingIcon": "trash",
|
|
15915
|
+
"cornerRadius": 22,
|
|
15916
|
+
"minHeight": 44,
|
|
15917
|
+
"disabledPath": "$service:himiStoreCart.writeBusy"
|
|
15967
15918
|
}
|
|
15968
15919
|
},
|
|
15969
15920
|
"modifiers": {
|
|
15970
15921
|
"width": 44,
|
|
15971
15922
|
"height": 44,
|
|
15972
|
-
"onTap": {
|
|
15973
|
-
"actionId": "tier5.himiStoreCart.remove",
|
|
15974
|
-
"params": {
|
|
15975
|
-
"id": "$item.id"
|
|
15976
|
-
}
|
|
15977
|
-
},
|
|
15978
|
-
"accessibilityRole": "button",
|
|
15979
15923
|
"accessibilityLabel": "Remove from cart",
|
|
15924
|
+
"accessibilityRole": "button",
|
|
15980
15925
|
"haptic": "light"
|
|
15981
15926
|
}
|
|
15982
15927
|
}
|
|
@@ -16225,7 +16170,7 @@ const SCREENS = runtimeSetting({
|
|
|
16225
16170
|
"action": {
|
|
16226
16171
|
"actionId": "tier5.himiStoreCart.applyPromo"
|
|
16227
16172
|
},
|
|
16228
|
-
"disabledPath": "$service:himiStoreCart.
|
|
16173
|
+
"disabledPath": "$service:himiStoreCart.writeBusy"
|
|
16229
16174
|
}
|
|
16230
16175
|
},
|
|
16231
16176
|
"modifiers": {
|
|
@@ -16282,7 +16227,8 @@ const SCREENS = runtimeSetting({
|
|
|
16282
16227
|
"iconOnly": true,
|
|
16283
16228
|
"leadingIcon": "close",
|
|
16284
16229
|
"cornerRadius": 22,
|
|
16285
|
-
"minHeight": 44
|
|
16230
|
+
"minHeight": 44,
|
|
16231
|
+
"disabledPath": "$service:himiStoreCart.writeBusy"
|
|
16286
16232
|
}
|
|
16287
16233
|
},
|
|
16288
16234
|
"modifiers": {
|
|
@@ -16416,6 +16362,7 @@ const SCREENS = runtimeSetting({
|
|
|
16416
16362
|
"title": "Checkout",
|
|
16417
16363
|
"style": "primary",
|
|
16418
16364
|
"fullWidth": true,
|
|
16365
|
+
"disabledPath": "$service:himiStoreCart.writeBusy",
|
|
16419
16366
|
"action": {
|
|
16420
16367
|
"actionId": "tier5.himiStoreCart.checkout"
|
|
16421
16368
|
}
|
|
@@ -49075,15 +49022,31 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
49075
49022
|
|
|
49076
49023
|
// Live seed-id enumeration: a published release serves only EXACT screens, so
|
|
49077
49024
|
// `himi push` bakes each templated detail route's CURRENT catalog ids as exact
|
|
49078
|
-
// screens via `seedIds`. Anonymous visitor rung against this app's own clientId
|
|
49079
|
-
//
|
|
49025
|
+
// screens via `seedIds`. Anonymous visitor rung against this app's own clientId — or,
|
|
49026
|
+
// for an app bound through the One App visitor identity (`visitorSource: "one-app"`,
|
|
49027
|
+
// no client), that site's One App visitor instance. Best-effort (offline build → no
|
|
49028
|
+
// baked details, preview still live-resolves).
|
|
49029
|
+
async function liveSeedToken(WIX: string): Promise<string | undefined> {
|
|
49030
|
+
const auth = (config as { auth?: { config?: { clientId?: string; visitorSource?: string; metaSiteId?: string } } }).auth?.config;
|
|
49031
|
+
// A One App binding boots as the site's One App visitor, so the seed reads as that visitor too —
|
|
49032
|
+
// even beside a member-login clientId, and never repointed by a stray local WIX_CLIENT_ID.
|
|
49033
|
+
const oneApp = auth?.visitorSource === "one-app";
|
|
49034
|
+
const clientId = oneApp ? "" : process.env.WIX_CLIENT_ID ?? auth?.clientId ?? "";
|
|
49035
|
+
if (clientId && !clientId.startsWith("YOUR_")) {
|
|
49036
|
+
const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
|
|
49037
|
+
return ((await mint.json()) as { access_token?: string }).access_token;
|
|
49038
|
+
}
|
|
49039
|
+
const msid = oneApp ? auth?.metaSiteId ?? "" : "";
|
|
49040
|
+
if (!/^[0-9a-fA-F-]{10,64}$/.test(msid)) return undefined;
|
|
49041
|
+
const mint = await fetch(`https://apps.wix.com/_api/one-app-session-web/v3/businesses/${msid}/signed-instance?signed_instance_type=Visitor`, { headers: { Accept: "application/json" }, redirect: "error" });
|
|
49042
|
+
const visitor = (await mint.json()) as { signedInstance?: string; signedInstanceType?: string };
|
|
49043
|
+
return visitor.signedInstanceType === "Visitor" ? visitor.signedInstance : undefined;
|
|
49044
|
+
}
|
|
49045
|
+
|
|
49080
49046
|
async function liveSeedIds(spec: LiveSeed): Promise<string[]> {
|
|
49081
49047
|
try {
|
|
49082
49048
|
const WIX = "https://www.wixapis.com";
|
|
49083
|
-
const
|
|
49084
|
-
if (!clientId || clientId.startsWith("YOUR_")) return [];
|
|
49085
|
-
const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
|
|
49086
|
-
const token = ((await mint.json()) as { access_token?: string }).access_token;
|
|
49049
|
+
const token = await liveSeedToken(WIX);
|
|
49087
49050
|
if (!token) return [];
|
|
49088
49051
|
const res = await fetch(WIX + spec.path, { method: "POST", headers: { Authorization: token, "Content-Type": "application/json" }, body: JSON.stringify(spec.body) });
|
|
49089
49052
|
const json = (await res.json()) as Record<string, unknown>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { defineService as register, type ServiceDefinition } from '@himalaya/state';
|
|
2
|
+
|
|
3
|
+
/** Reject repeated taps until the accepted write's result is committed. A promise
|
|
4
|
+
* queue alone releases before the host applies the reducer result, so the next
|
|
5
|
+
* write can still read an old revision/id. The private synchronous reducer below
|
|
6
|
+
* publishes busy and commits completion through the ordinary service handle;
|
|
7
|
+
* awaiting that handle guarantees the host has stored the result before unlock.
|
|
8
|
+
* Skipped actions return undefined, so they cannot roll back the accepted write.
|
|
9
|
+
*/
|
|
10
|
+
export function withExclusiveWrites<S extends object = Record<string, unknown>>(
|
|
11
|
+
registerService: typeof register, names: readonly string[],
|
|
12
|
+
options: { prepare?: (action: string, args: readonly unknown[]) => void; coalesce?: readonly string[]; settle?: (before: S, next: S, live: S) => S } = {},
|
|
13
|
+
): typeof register {
|
|
14
|
+
return ((name: string, definition: ServiceDefinition<Record<string, unknown>>) => {
|
|
15
|
+
let busy = false;
|
|
16
|
+
let activeAction = "";
|
|
17
|
+
let completion = Promise.resolve();
|
|
18
|
+
let complete = () => {};
|
|
19
|
+
let handle: { getState(): Record<string, unknown>; exclusiveWriteState(next: Record<string, unknown>): Promise<unknown> };
|
|
20
|
+
const wrapped: ServiceDefinition<Record<string, unknown>> = {
|
|
21
|
+
...definition,
|
|
22
|
+
state: { ...definition.state, writeBusy: false },
|
|
23
|
+
notHydrated: [...(definition.notHydrated ?? []), 'writeBusy'],
|
|
24
|
+
actions: {
|
|
25
|
+
...Object.fromEntries(Object.entries(definition.actions ?? {}).map(([action, reduce]) => [action,
|
|
26
|
+
names.includes(action) ? async (state: Record<string, unknown>, ...args: never[]) => {
|
|
27
|
+
// Intake request metadata even when its state replacement is skipped.
|
|
28
|
+
options.prepare?.(action, args);
|
|
29
|
+
if (busy) {
|
|
30
|
+
// Repeated initial loads must await the accepted load, so callers
|
|
31
|
+
// observe its committed rows rather than the initial skeleton.
|
|
32
|
+
if (activeAction === action && options.coalesce?.includes(action)) await completion;
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
busy = true;
|
|
36
|
+
activeAction = action;
|
|
37
|
+
completion = new Promise<void>(resolve => { complete = resolve; });
|
|
38
|
+
try {
|
|
39
|
+
await handle.exclusiveWriteState({ ...handle.getState(), writeBusy: true });
|
|
40
|
+
const next = await reduce(state, ...args);
|
|
41
|
+
const live = handle.getState();
|
|
42
|
+
// Non-write actions (for example editing a draft field) can still run
|
|
43
|
+
// during I/O. Let the owning service preserve those newer edits.
|
|
44
|
+
const settled = options.settle ? options.settle(state as S, (next ?? live) as S, live as S) : next ?? live;
|
|
45
|
+
await handle.exclusiveWriteState({ ...settled, writeBusy: false });
|
|
46
|
+
} catch (error) {
|
|
47
|
+
await handle.exclusiveWriteState({ ...handle.getState(), writeBusy: false });
|
|
48
|
+
throw error;
|
|
49
|
+
} finally {
|
|
50
|
+
busy = false;
|
|
51
|
+
complete();
|
|
52
|
+
}
|
|
53
|
+
} : reduce,
|
|
54
|
+
])),
|
|
55
|
+
exclusiveWriteState: (_state, next: Record<string, unknown>) => next,
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
const registered = registerService(name, wrapped);
|
|
59
|
+
// Registration preserves this private action, but the dynamic action map
|
|
60
|
+
// cannot express its payload to the generic service handle.
|
|
61
|
+
handle = registered as unknown as typeof handle;
|
|
62
|
+
// Older hosts ignore notHydrated. A fresh worker has no pending write.
|
|
63
|
+
handle.getState().writeBusy = false;
|
|
64
|
+
return registered;
|
|
65
|
+
}) as typeof register;
|
|
66
|
+
}
|
|
@@ -115,6 +115,7 @@ interface State {
|
|
|
115
115
|
checkoutHint: string;
|
|
116
116
|
itemCount: number;
|
|
117
117
|
promoCode: string;
|
|
118
|
+
promoEditRevision: number;
|
|
118
119
|
appliedCode: string;
|
|
119
120
|
appliedLabel: string;
|
|
120
121
|
couponId: string;
|
|
@@ -380,11 +381,24 @@ function couponDetails(result: unknown): { id: string; code: string } {
|
|
|
380
381
|
return { id: coupon?.coupon?.id ?? coupon?.id ?? "", code: coupon?.coupon?.code ?? coupon?.code ?? "" };
|
|
381
382
|
}
|
|
382
383
|
|
|
384
|
+
import { withExclusiveWrites } from "../_shared/exclusive-writes.js";
|
|
385
|
+
|
|
383
386
|
let cartPricing: IapCommerce;
|
|
384
387
|
const defineService = withIapPresentation<State>({
|
|
385
|
-
register: withOnlineWrites(registerState, ["remove", "increment", "decrement", "checkout", "beginPromo", "applyPromo", "removePromo"], { derive, messageFields: action => action.includes("Promo") ? ["promoError"] : ["checkoutHint"] }),
|
|
388
|
+
register: withExclusiveWrites<State>(withOnlineWrites(registerState, ["remove", "increment", "decrement", "checkout", "beginPromo", "applyPromo", "removePromo"], { derive, messageFields: action => action.includes("Promo") ? ["promoError"] : ["checkoutHint"] }), ["load", "remove", "increment", "decrement", "checkout", "applyPromo", "removePromo", "save"], {
|
|
389
|
+
prepare: (action, args) => { if (action === "load") stashCopy(args[0]); },
|
|
390
|
+
coalesce: ["load"],
|
|
391
|
+
// Full cart reloads share the transaction, since they also replace rows and
|
|
392
|
+
// reset promo fields. Only setPromo increments the edit revision: beginPromo's internal error reset
|
|
393
|
+
// must not masquerade as a user edit when a rejected code is retried.
|
|
394
|
+
settle: (before, next, live) => {
|
|
395
|
+
if ((before.promoEditRevision ?? 0) === (live.promoEditRevision ?? 0)) return next;
|
|
396
|
+
return derive({ ...next, promoEditRevision: live.promoEditRevision,
|
|
397
|
+
...(next.items.length ? { promoCode: live.promoCode, promoError: live.promoError } : {}) });
|
|
398
|
+
},
|
|
399
|
+
}),
|
|
386
400
|
onCreate: commerce => { cartPricing = commerce; },
|
|
387
|
-
prefix: "cart", transientKeys: ["items", "subtotal", "promoBusy"], contentActions: ["load", "remove", "increment", "decrement"],
|
|
401
|
+
prefix: "cart", transientKeys: ["items", "subtotal", "promoBusy", "promoEditRevision"], contentActions: ["load", "remove", "increment", "decrement"],
|
|
388
402
|
items: state => state.items.flatMap(row => row.catalogReference?.catalogItemId ? [{ reference: { kind: "storesProduct", id: row.catalogReference.catalogItemId }, commerceDisplayPrice: row.commerceTotal ?? row.total }] : []),
|
|
389
403
|
present: (state, price, allowed) => ({ ...state,
|
|
390
404
|
items: state.items.map(row => ({ ...row, total: row.catalogReference?.catalogItemId ? price(row.catalogReference.catalogItemId, row.commerceTotal ?? row.total) : row.total })),
|
|
@@ -404,10 +418,9 @@ const svc = defineService<State, {
|
|
|
404
418
|
decrement: (state: State, arg?: unknown) => Promise<State>;
|
|
405
419
|
checkout: (state: State) => Promise<State>;
|
|
406
420
|
}>("himiStoreCart", {
|
|
407
|
-
state: derive({ status: "loading", errorKind: "", items: [], subtotal: "", subtotalLabel: "", emptyText: "", checkoutHint: "", showPaidToast: false, noPaidToast: true, itemCount: 0, promoCode: "", appliedCode: "", appliedLabel: "", couponId: "", promoError: "", promoBusy: false, noPromoError: true, hasCoupon: false, discount: "", noDiscount: true, noCheckoutHint: true, noCoupon: true, isLoading: true, notLoading: false, isErrored: false, notErrored: true, noOfflineError: true, noServerError: true, hideContent: true, noEmpty: true, noItems: true }),
|
|
421
|
+
state: derive({ status: "loading", errorKind: "", items: [], subtotal: "", subtotalLabel: "", emptyText: "", checkoutHint: "", showPaidToast: false, noPaidToast: true, itemCount: 0, promoCode: "", promoEditRevision: 0, appliedCode: "", appliedLabel: "", couponId: "", promoError: "", promoBusy: false, noPromoError: true, hasCoupon: false, discount: "", noDiscount: true, noCheckoutHint: true, noCoupon: true, isLoading: true, notLoading: false, isErrored: false, notErrored: true, noOfflineError: true, noServerError: true, hideContent: true, noEmpty: true, noItems: true }),
|
|
408
422
|
actions: {
|
|
409
423
|
load: async (state, arg) => {
|
|
410
|
-
stashCopy(arg);
|
|
411
424
|
// 1) Instant paint from the on-device cache (offline-safe; empty on first-ever run).
|
|
412
425
|
const cached = await readCachedItems();
|
|
413
426
|
const base = cached.length
|
|
@@ -423,7 +436,7 @@ const svc = defineService<State, {
|
|
|
423
436
|
: derive({ ...state, status: "error", errorKind: isOfflineFailure(error) ? "offline" : "server", items: [], subtotal: "", emptyText: copyParam("cart.loadErrorText", "Cart could not load."), checkoutHint: "" });
|
|
424
437
|
}
|
|
425
438
|
},
|
|
426
|
-
setPromo: (state, arg) => derive({ ...state, promoCode: (typeof arg === "string" ? arg : String((arg as { value?: unknown } | undefined)?.value ?? "")).slice(0, 100), promoError: "" }),
|
|
439
|
+
setPromo: (state, arg) => derive({ ...state, promoEditRevision: (state.promoEditRevision ?? 0) + 1, promoCode: (typeof arg === "string" ? arg : String((arg as { value?: unknown } | undefined)?.value ?? "")).slice(0, 100), promoError: "" }),
|
|
427
440
|
beginPromo: state => derive({ ...state, promoBusy: true, promoError: "" }),
|
|
428
441
|
applyPromo: async (state): Promise<State> => {
|
|
429
442
|
const code = state.promoCode.trim();
|
|
@@ -82378,6 +82378,7 @@ const SCREENS = runtimeSetting({
|
|
|
82378
82378
|
"title": "Create product",
|
|
82379
82379
|
"style": "primary",
|
|
82380
82380
|
"fullWidth": true,
|
|
82381
|
+
"disabledPath": "$service:himiOwnerLiteProductForm.writeBusy",
|
|
82381
82382
|
"action": {
|
|
82382
82383
|
"actionId": "tier5.himiOwnerLiteProductForm.submit"
|
|
82383
82384
|
}
|
|
@@ -82697,6 +82698,7 @@ const SCREENS = runtimeSetting({
|
|
|
82697
82698
|
"title": "Create post",
|
|
82698
82699
|
"style": "primary",
|
|
82699
82700
|
"fullWidth": true,
|
|
82701
|
+
"disabledPath": "$service:himiOwnerLitePostForm.writeBusy",
|
|
82700
82702
|
"action": {
|
|
82701
82703
|
"actionId": "tier5.himiOwnerLitePostForm.submit"
|
|
82702
82704
|
}
|
|
@@ -83212,6 +83214,7 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
83212
83214
|
"title": "Save changes",
|
|
83213
83215
|
"style": "primary",
|
|
83214
83216
|
"fullWidth": true,
|
|
83217
|
+
"disabledPath": "$service:himiOwnerLiteProductForm.writeBusy",
|
|
83215
83218
|
"action": {
|
|
83216
83219
|
"actionId": "tier5.himiOwnerLiteProductForm.submit"
|
|
83217
83220
|
}
|
|
@@ -83459,6 +83462,7 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
83459
83462
|
"title": "Save changes",
|
|
83460
83463
|
"style": "primary",
|
|
83461
83464
|
"fullWidth": true,
|
|
83465
|
+
"disabledPath": "$service:himiOwnerLiteServiceForm.writeBusy",
|
|
83462
83466
|
"action": {
|
|
83463
83467
|
"actionId": "tier5.himiOwnerLiteServiceForm.submit"
|
|
83464
83468
|
}
|
|
@@ -83821,6 +83825,7 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
83821
83825
|
"title": "Save changes",
|
|
83822
83826
|
"style": "primary",
|
|
83823
83827
|
"fullWidth": true,
|
|
83828
|
+
"disabledPath": "$service:himiOwnerLiteEventForm.writeBusy",
|
|
83824
83829
|
"action": {
|
|
83825
83830
|
"actionId": "tier5.himiOwnerLiteEventForm.submit"
|
|
83826
83831
|
}
|
|
@@ -84144,6 +84149,7 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
84144
84149
|
"title": "Save changes",
|
|
84145
84150
|
"style": "primary",
|
|
84146
84151
|
"fullWidth": true,
|
|
84152
|
+
"disabledPath": "$service:himiOwnerLitePostForm.writeBusy",
|
|
84147
84153
|
"action": {
|
|
84148
84154
|
"actionId": "tier5.himiOwnerLitePostForm.submit"
|
|
84149
84155
|
}
|
|
@@ -90716,15 +90722,31 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
90716
90722
|
|
|
90717
90723
|
// Live seed-id enumeration: a published release serves only EXACT screens, so
|
|
90718
90724
|
// `himi push` bakes each templated detail route's CURRENT catalog ids as exact
|
|
90719
|
-
// screens via `seedIds`. Anonymous visitor rung against this app's own clientId
|
|
90720
|
-
//
|
|
90725
|
+
// screens via `seedIds`. Anonymous visitor rung against this app's own clientId — or,
|
|
90726
|
+
// for an app bound through the One App visitor identity (`visitorSource: "one-app"`,
|
|
90727
|
+
// no client), that site's One App visitor instance. Best-effort (offline build → no
|
|
90728
|
+
// baked details, preview still live-resolves).
|
|
90729
|
+
async function liveSeedToken(WIX: string): Promise<string | undefined> {
|
|
90730
|
+
const auth = (config as { auth?: { config?: { clientId?: string; visitorSource?: string; metaSiteId?: string } } }).auth?.config;
|
|
90731
|
+
// A One App binding boots as the site's One App visitor, so the seed reads as that visitor too —
|
|
90732
|
+
// even beside a member-login clientId, and never repointed by a stray local WIX_CLIENT_ID.
|
|
90733
|
+
const oneApp = auth?.visitorSource === "one-app";
|
|
90734
|
+
const clientId = oneApp ? "" : process.env.WIX_CLIENT_ID ?? auth?.clientId ?? "";
|
|
90735
|
+
if (clientId && !clientId.startsWith("YOUR_")) {
|
|
90736
|
+
const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
|
|
90737
|
+
return ((await mint.json()) as { access_token?: string }).access_token;
|
|
90738
|
+
}
|
|
90739
|
+
const msid = oneApp ? auth?.metaSiteId ?? "" : "";
|
|
90740
|
+
if (!/^[0-9a-fA-F-]{10,64}$/.test(msid)) return undefined;
|
|
90741
|
+
const mint = await fetch(`https://apps.wix.com/_api/one-app-session-web/v3/businesses/${msid}/signed-instance?signed_instance_type=Visitor`, { headers: { Accept: "application/json" }, redirect: "error" });
|
|
90742
|
+
const visitor = (await mint.json()) as { signedInstance?: string; signedInstanceType?: string };
|
|
90743
|
+
return visitor.signedInstanceType === "Visitor" ? visitor.signedInstance : undefined;
|
|
90744
|
+
}
|
|
90745
|
+
|
|
90721
90746
|
async function liveSeedIds(spec: LiveSeed): Promise<string[]> {
|
|
90722
90747
|
try {
|
|
90723
90748
|
const WIX = "https://www.wixapis.com";
|
|
90724
|
-
const
|
|
90725
|
-
if (!clientId || clientId.startsWith("YOUR_")) return [];
|
|
90726
|
-
const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
|
|
90727
|
-
const token = ((await mint.json()) as { access_token?: string }).access_token;
|
|
90749
|
+
const token = await liveSeedToken(WIX);
|
|
90728
90750
|
if (!token) return [];
|
|
90729
90751
|
const res = await fetch(WIX + spec.path, { method: "POST", headers: { Authorization: token, "Content-Type": "application/json" }, body: JSON.stringify(spec.body) });
|
|
90730
90752
|
const json = (await res.json()) as Record<string, unknown>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { defineService as register, type ServiceDefinition } from '@himalaya/state';
|
|
2
|
+
|
|
3
|
+
/** Reject repeated taps until the accepted write's result is committed. A promise
|
|
4
|
+
* queue alone releases before the host applies the reducer result, so the next
|
|
5
|
+
* write can still read an old revision/id. The private synchronous reducer below
|
|
6
|
+
* publishes busy and commits completion through the ordinary service handle;
|
|
7
|
+
* awaiting that handle guarantees the host has stored the result before unlock.
|
|
8
|
+
* Skipped actions return undefined, so they cannot roll back the accepted write.
|
|
9
|
+
*/
|
|
10
|
+
export function withExclusiveWrites<S extends object = Record<string, unknown>>(
|
|
11
|
+
registerService: typeof register, names: readonly string[],
|
|
12
|
+
options: { prepare?: (action: string, args: readonly unknown[]) => void; coalesce?: readonly string[]; settle?: (before: S, next: S, live: S) => S } = {},
|
|
13
|
+
): typeof register {
|
|
14
|
+
return ((name: string, definition: ServiceDefinition<Record<string, unknown>>) => {
|
|
15
|
+
let busy = false;
|
|
16
|
+
let activeAction = "";
|
|
17
|
+
let completion = Promise.resolve();
|
|
18
|
+
let complete = () => {};
|
|
19
|
+
let handle: { getState(): Record<string, unknown>; exclusiveWriteState(next: Record<string, unknown>): Promise<unknown> };
|
|
20
|
+
const wrapped: ServiceDefinition<Record<string, unknown>> = {
|
|
21
|
+
...definition,
|
|
22
|
+
state: { ...definition.state, writeBusy: false },
|
|
23
|
+
notHydrated: [...(definition.notHydrated ?? []), 'writeBusy'],
|
|
24
|
+
actions: {
|
|
25
|
+
...Object.fromEntries(Object.entries(definition.actions ?? {}).map(([action, reduce]) => [action,
|
|
26
|
+
names.includes(action) ? async (state: Record<string, unknown>, ...args: never[]) => {
|
|
27
|
+
// Intake request metadata even when its state replacement is skipped.
|
|
28
|
+
options.prepare?.(action, args);
|
|
29
|
+
if (busy) {
|
|
30
|
+
// Repeated initial loads must await the accepted load, so callers
|
|
31
|
+
// observe its committed rows rather than the initial skeleton.
|
|
32
|
+
if (activeAction === action && options.coalesce?.includes(action)) await completion;
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
busy = true;
|
|
36
|
+
activeAction = action;
|
|
37
|
+
completion = new Promise<void>(resolve => { complete = resolve; });
|
|
38
|
+
try {
|
|
39
|
+
await handle.exclusiveWriteState({ ...handle.getState(), writeBusy: true });
|
|
40
|
+
const next = await reduce(state, ...args);
|
|
41
|
+
const live = handle.getState();
|
|
42
|
+
// Non-write actions (for example editing a draft field) can still run
|
|
43
|
+
// during I/O. Let the owning service preserve those newer edits.
|
|
44
|
+
const settled = options.settle ? options.settle(state as S, (next ?? live) as S, live as S) : next ?? live;
|
|
45
|
+
await handle.exclusiveWriteState({ ...settled, writeBusy: false });
|
|
46
|
+
} catch (error) {
|
|
47
|
+
await handle.exclusiveWriteState({ ...handle.getState(), writeBusy: false });
|
|
48
|
+
throw error;
|
|
49
|
+
} finally {
|
|
50
|
+
busy = false;
|
|
51
|
+
complete();
|
|
52
|
+
}
|
|
53
|
+
} : reduce,
|
|
54
|
+
])),
|
|
55
|
+
exclusiveWriteState: (_state, next: Record<string, unknown>) => next,
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
const registered = registerService(name, wrapped);
|
|
59
|
+
// Registration preserves this private action, but the dynamic action map
|
|
60
|
+
// cannot express its payload to the generic service handle.
|
|
61
|
+
handle = registered as unknown as typeof handle;
|
|
62
|
+
// Older hosts ignore notHydrated. A fresh worker has no pending write.
|
|
63
|
+
handle.getState().writeBusy = false;
|
|
64
|
+
return registered;
|
|
65
|
+
}) as typeof register;
|
|
66
|
+
}
|