@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
|
@@ -15063,39 +15063,28 @@ const SCREENS = runtimeSetting({
|
|
|
15063
15063
|
"id": "himi_cart.qty_minus",
|
|
15064
15064
|
"body": {
|
|
15065
15065
|
"package": "himalaya",
|
|
15066
|
-
"type": "
|
|
15066
|
+
"type": "Button",
|
|
15067
15067
|
"props": {
|
|
15068
|
-
"
|
|
15069
|
-
"
|
|
15070
|
-
|
|
15071
|
-
|
|
15072
|
-
"
|
|
15073
|
-
"package": "himalaya",
|
|
15074
|
-
"type": "Icon",
|
|
15075
|
-
"props": {
|
|
15076
|
-
"name": "minus",
|
|
15077
|
-
"size": 24,
|
|
15078
|
-
"tint": "textPrimary"
|
|
15079
|
-
}
|
|
15080
|
-
},
|
|
15081
|
-
"modifiers": {
|
|
15082
|
-
"accessibilityRole": "decorative"
|
|
15083
|
-
}
|
|
15068
|
+
"title": "Decrease quantity",
|
|
15069
|
+
"action": {
|
|
15070
|
+
"actionId": "tier5.himiStoreCart.decrement",
|
|
15071
|
+
"params": {
|
|
15072
|
+
"id": "$item.id"
|
|
15084
15073
|
}
|
|
15085
|
-
|
|
15074
|
+
},
|
|
15075
|
+
"style": "tertiary",
|
|
15076
|
+
"iconOnly": true,
|
|
15077
|
+
"leadingIcon": "minus",
|
|
15078
|
+
"cornerRadius": 22,
|
|
15079
|
+
"minHeight": 44,
|
|
15080
|
+
"disabledPath": "$service:himiStoreCart.writeBusy"
|
|
15086
15081
|
}
|
|
15087
15082
|
},
|
|
15088
15083
|
"modifiers": {
|
|
15089
15084
|
"width": 44,
|
|
15090
15085
|
"height": 44,
|
|
15091
|
-
"onTap": {
|
|
15092
|
-
"actionId": "tier5.himiStoreCart.decrement",
|
|
15093
|
-
"params": {
|
|
15094
|
-
"id": "$item.id"
|
|
15095
|
-
}
|
|
15096
|
-
},
|
|
15097
|
-
"accessibilityRole": "button",
|
|
15098
15086
|
"accessibilityLabel": "Decrease quantity",
|
|
15087
|
+
"accessibilityRole": "button",
|
|
15099
15088
|
"haptic": "light"
|
|
15100
15089
|
}
|
|
15101
15090
|
},
|
|
@@ -15118,39 +15107,28 @@ const SCREENS = runtimeSetting({
|
|
|
15118
15107
|
"id": "himi_cart.qty_plus",
|
|
15119
15108
|
"body": {
|
|
15120
15109
|
"package": "himalaya",
|
|
15121
|
-
"type": "
|
|
15110
|
+
"type": "Button",
|
|
15122
15111
|
"props": {
|
|
15123
|
-
"
|
|
15124
|
-
"
|
|
15125
|
-
|
|
15126
|
-
|
|
15127
|
-
"
|
|
15128
|
-
"package": "himalaya",
|
|
15129
|
-
"type": "Icon",
|
|
15130
|
-
"props": {
|
|
15131
|
-
"name": "plus",
|
|
15132
|
-
"size": 24,
|
|
15133
|
-
"tint": "textPrimary"
|
|
15134
|
-
}
|
|
15135
|
-
},
|
|
15136
|
-
"modifiers": {
|
|
15137
|
-
"accessibilityRole": "decorative"
|
|
15138
|
-
}
|
|
15112
|
+
"title": "Increase quantity",
|
|
15113
|
+
"action": {
|
|
15114
|
+
"actionId": "tier5.himiStoreCart.increment",
|
|
15115
|
+
"params": {
|
|
15116
|
+
"id": "$item.id"
|
|
15139
15117
|
}
|
|
15140
|
-
|
|
15118
|
+
},
|
|
15119
|
+
"style": "tertiary",
|
|
15120
|
+
"iconOnly": true,
|
|
15121
|
+
"leadingIcon": "plus",
|
|
15122
|
+
"cornerRadius": 22,
|
|
15123
|
+
"minHeight": 44,
|
|
15124
|
+
"disabledPath": "$service:himiStoreCart.writeBusy"
|
|
15141
15125
|
}
|
|
15142
15126
|
},
|
|
15143
15127
|
"modifiers": {
|
|
15144
15128
|
"width": 44,
|
|
15145
15129
|
"height": 44,
|
|
15146
|
-
"onTap": {
|
|
15147
|
-
"actionId": "tier5.himiStoreCart.increment",
|
|
15148
|
-
"params": {
|
|
15149
|
-
"id": "$item.id"
|
|
15150
|
-
}
|
|
15151
|
-
},
|
|
15152
|
-
"accessibilityRole": "button",
|
|
15153
15130
|
"accessibilityLabel": "Increase quantity",
|
|
15131
|
+
"accessibilityRole": "button",
|
|
15154
15132
|
"haptic": "light"
|
|
15155
15133
|
}
|
|
15156
15134
|
},
|
|
@@ -15166,39 +15144,28 @@ const SCREENS = runtimeSetting({
|
|
|
15166
15144
|
"id": "himi_cart.save_filled",
|
|
15167
15145
|
"body": {
|
|
15168
15146
|
"package": "himalaya",
|
|
15169
|
-
"type": "
|
|
15147
|
+
"type": "Button",
|
|
15170
15148
|
"props": {
|
|
15171
|
-
"
|
|
15172
|
-
"
|
|
15173
|
-
|
|
15174
|
-
|
|
15175
|
-
"
|
|
15176
|
-
"package": "himalaya",
|
|
15177
|
-
"type": "Icon",
|
|
15178
|
-
"props": {
|
|
15179
|
-
"name": "heart_fill",
|
|
15180
|
-
"size": 24,
|
|
15181
|
-
"tint": "textPrimary"
|
|
15182
|
-
}
|
|
15183
|
-
},
|
|
15184
|
-
"modifiers": {
|
|
15185
|
-
"accessibilityRole": "decorative"
|
|
15186
|
-
}
|
|
15149
|
+
"title": "Remove from wishlist",
|
|
15150
|
+
"action": {
|
|
15151
|
+
"actionId": "tier5.himiStoreCart.save",
|
|
15152
|
+
"params": {
|
|
15153
|
+
"id": "$item.id"
|
|
15187
15154
|
}
|
|
15188
|
-
|
|
15155
|
+
},
|
|
15156
|
+
"style": "tertiary",
|
|
15157
|
+
"iconOnly": true,
|
|
15158
|
+
"leadingIcon": "heart_fill",
|
|
15159
|
+
"cornerRadius": 22,
|
|
15160
|
+
"minHeight": 44,
|
|
15161
|
+
"disabledPath": "$service:himiStoreCart.writeBusy"
|
|
15189
15162
|
}
|
|
15190
15163
|
},
|
|
15191
15164
|
"modifiers": {
|
|
15192
15165
|
"width": 44,
|
|
15193
15166
|
"height": 44,
|
|
15194
|
-
"onTap": {
|
|
15195
|
-
"actionId": "tier5.himiStoreCart.save",
|
|
15196
|
-
"params": {
|
|
15197
|
-
"id": "$item.id"
|
|
15198
|
-
}
|
|
15199
|
-
},
|
|
15200
|
-
"accessibilityRole": "button",
|
|
15201
15167
|
"accessibilityLabel": "Remove from wishlist",
|
|
15168
|
+
"accessibilityRole": "button",
|
|
15202
15169
|
"haptic": "light",
|
|
15203
15170
|
"hiddenPath": "$item.notSaved"
|
|
15204
15171
|
}
|
|
@@ -15207,39 +15174,28 @@ const SCREENS = runtimeSetting({
|
|
|
15207
15174
|
"id": "himi_cart.save",
|
|
15208
15175
|
"body": {
|
|
15209
15176
|
"package": "himalaya",
|
|
15210
|
-
"type": "
|
|
15177
|
+
"type": "Button",
|
|
15211
15178
|
"props": {
|
|
15212
|
-
"
|
|
15213
|
-
"
|
|
15214
|
-
|
|
15215
|
-
|
|
15216
|
-
"
|
|
15217
|
-
"package": "himalaya",
|
|
15218
|
-
"type": "Icon",
|
|
15219
|
-
"props": {
|
|
15220
|
-
"name": "heart",
|
|
15221
|
-
"size": 24,
|
|
15222
|
-
"tint": "textPrimary"
|
|
15223
|
-
}
|
|
15224
|
-
},
|
|
15225
|
-
"modifiers": {
|
|
15226
|
-
"accessibilityRole": "decorative"
|
|
15227
|
-
}
|
|
15179
|
+
"title": "Add to wishlist",
|
|
15180
|
+
"action": {
|
|
15181
|
+
"actionId": "tier5.himiStoreCart.save",
|
|
15182
|
+
"params": {
|
|
15183
|
+
"id": "$item.id"
|
|
15228
15184
|
}
|
|
15229
|
-
|
|
15185
|
+
},
|
|
15186
|
+
"style": "tertiary",
|
|
15187
|
+
"iconOnly": true,
|
|
15188
|
+
"leadingIcon": "heart",
|
|
15189
|
+
"cornerRadius": 22,
|
|
15190
|
+
"minHeight": 44,
|
|
15191
|
+
"disabledPath": "$service:himiStoreCart.writeBusy"
|
|
15230
15192
|
}
|
|
15231
15193
|
},
|
|
15232
15194
|
"modifiers": {
|
|
15233
15195
|
"width": 44,
|
|
15234
15196
|
"height": 44,
|
|
15235
|
-
"onTap": {
|
|
15236
|
-
"actionId": "tier5.himiStoreCart.save",
|
|
15237
|
-
"params": {
|
|
15238
|
-
"id": "$item.id"
|
|
15239
|
-
}
|
|
15240
|
-
},
|
|
15241
|
-
"accessibilityRole": "button",
|
|
15242
15197
|
"accessibilityLabel": "Add to wishlist",
|
|
15198
|
+
"accessibilityRole": "button",
|
|
15243
15199
|
"haptic": "light",
|
|
15244
15200
|
"hiddenPath": "$item.saved"
|
|
15245
15201
|
}
|
|
@@ -15248,39 +15204,28 @@ const SCREENS = runtimeSetting({
|
|
|
15248
15204
|
"id": "himi_cart.remove",
|
|
15249
15205
|
"body": {
|
|
15250
15206
|
"package": "himalaya",
|
|
15251
|
-
"type": "
|
|
15207
|
+
"type": "Button",
|
|
15252
15208
|
"props": {
|
|
15253
|
-
"
|
|
15254
|
-
"
|
|
15255
|
-
|
|
15256
|
-
|
|
15257
|
-
"
|
|
15258
|
-
"package": "himalaya",
|
|
15259
|
-
"type": "Icon",
|
|
15260
|
-
"props": {
|
|
15261
|
-
"name": "trash",
|
|
15262
|
-
"size": 24,
|
|
15263
|
-
"tint": "textPrimary"
|
|
15264
|
-
}
|
|
15265
|
-
},
|
|
15266
|
-
"modifiers": {
|
|
15267
|
-
"accessibilityRole": "decorative"
|
|
15268
|
-
}
|
|
15209
|
+
"title": "Remove from cart",
|
|
15210
|
+
"action": {
|
|
15211
|
+
"actionId": "tier5.himiStoreCart.remove",
|
|
15212
|
+
"params": {
|
|
15213
|
+
"id": "$item.id"
|
|
15269
15214
|
}
|
|
15270
|
-
|
|
15215
|
+
},
|
|
15216
|
+
"style": "tertiary",
|
|
15217
|
+
"iconOnly": true,
|
|
15218
|
+
"leadingIcon": "trash",
|
|
15219
|
+
"cornerRadius": 22,
|
|
15220
|
+
"minHeight": 44,
|
|
15221
|
+
"disabledPath": "$service:himiStoreCart.writeBusy"
|
|
15271
15222
|
}
|
|
15272
15223
|
},
|
|
15273
15224
|
"modifiers": {
|
|
15274
15225
|
"width": 44,
|
|
15275
15226
|
"height": 44,
|
|
15276
|
-
"onTap": {
|
|
15277
|
-
"actionId": "tier5.himiStoreCart.remove",
|
|
15278
|
-
"params": {
|
|
15279
|
-
"id": "$item.id"
|
|
15280
|
-
}
|
|
15281
|
-
},
|
|
15282
|
-
"accessibilityRole": "button",
|
|
15283
15227
|
"accessibilityLabel": "Remove from cart",
|
|
15228
|
+
"accessibilityRole": "button",
|
|
15284
15229
|
"haptic": "light"
|
|
15285
15230
|
}
|
|
15286
15231
|
}
|
|
@@ -15529,7 +15474,7 @@ const SCREENS = runtimeSetting({
|
|
|
15529
15474
|
"action": {
|
|
15530
15475
|
"actionId": "tier5.himiStoreCart.applyPromo"
|
|
15531
15476
|
},
|
|
15532
|
-
"disabledPath": "$service:himiStoreCart.
|
|
15477
|
+
"disabledPath": "$service:himiStoreCart.writeBusy"
|
|
15533
15478
|
}
|
|
15534
15479
|
},
|
|
15535
15480
|
"modifiers": {
|
|
@@ -15586,7 +15531,8 @@ const SCREENS = runtimeSetting({
|
|
|
15586
15531
|
"iconOnly": true,
|
|
15587
15532
|
"leadingIcon": "close",
|
|
15588
15533
|
"cornerRadius": 22,
|
|
15589
|
-
"minHeight": 44
|
|
15534
|
+
"minHeight": 44,
|
|
15535
|
+
"disabledPath": "$service:himiStoreCart.writeBusy"
|
|
15590
15536
|
}
|
|
15591
15537
|
},
|
|
15592
15538
|
"modifiers": {
|
|
@@ -15720,6 +15666,7 @@ const SCREENS = runtimeSetting({
|
|
|
15720
15666
|
"title": "Checkout",
|
|
15721
15667
|
"style": "primary",
|
|
15722
15668
|
"fullWidth": true,
|
|
15669
|
+
"disabledPath": "$service:himiStoreCart.writeBusy",
|
|
15723
15670
|
"action": {
|
|
15724
15671
|
"actionId": "tier5.himiStoreCart.checkout"
|
|
15725
15672
|
}
|
|
@@ -36114,15 +36061,31 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
36114
36061
|
|
|
36115
36062
|
// Live seed-id enumeration: a published release serves only EXACT screens, so
|
|
36116
36063
|
// `himi push` bakes each templated detail route's CURRENT catalog ids as exact
|
|
36117
|
-
// screens via `seedIds`. Anonymous visitor rung against this app's own clientId
|
|
36118
|
-
//
|
|
36064
|
+
// screens via `seedIds`. Anonymous visitor rung against this app's own clientId — or,
|
|
36065
|
+
// for an app bound through the One App visitor identity (`visitorSource: "one-app"`,
|
|
36066
|
+
// no client), that site's One App visitor instance. Best-effort (offline build → no
|
|
36067
|
+
// baked details, preview still live-resolves).
|
|
36068
|
+
async function liveSeedToken(WIX: string): Promise<string | undefined> {
|
|
36069
|
+
const auth = (config as { auth?: { config?: { clientId?: string; visitorSource?: string; metaSiteId?: string } } }).auth?.config;
|
|
36070
|
+
// A One App binding boots as the site's One App visitor, so the seed reads as that visitor too —
|
|
36071
|
+
// even beside a member-login clientId, and never repointed by a stray local WIX_CLIENT_ID.
|
|
36072
|
+
const oneApp = auth?.visitorSource === "one-app";
|
|
36073
|
+
const clientId = oneApp ? "" : process.env.WIX_CLIENT_ID ?? auth?.clientId ?? "";
|
|
36074
|
+
if (clientId && !clientId.startsWith("YOUR_")) {
|
|
36075
|
+
const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
|
|
36076
|
+
return ((await mint.json()) as { access_token?: string }).access_token;
|
|
36077
|
+
}
|
|
36078
|
+
const msid = oneApp ? auth?.metaSiteId ?? "" : "";
|
|
36079
|
+
if (!/^[0-9a-fA-F-]{10,64}$/.test(msid)) return undefined;
|
|
36080
|
+
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" });
|
|
36081
|
+
const visitor = (await mint.json()) as { signedInstance?: string; signedInstanceType?: string };
|
|
36082
|
+
return visitor.signedInstanceType === "Visitor" ? visitor.signedInstance : undefined;
|
|
36083
|
+
}
|
|
36084
|
+
|
|
36119
36085
|
async function liveSeedIds(spec: LiveSeed): Promise<string[]> {
|
|
36120
36086
|
try {
|
|
36121
36087
|
const WIX = "https://www.wixapis.com";
|
|
36122
|
-
const
|
|
36123
|
-
if (!clientId || clientId.startsWith("YOUR_")) return [];
|
|
36124
|
-
const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
|
|
36125
|
-
const token = ((await mint.json()) as { access_token?: string }).access_token;
|
|
36088
|
+
const token = await liveSeedToken(WIX);
|
|
36126
36089
|
if (!token) return [];
|
|
36127
36090
|
const res = await fetch(WIX + spec.path, { method: "POST", headers: { Authorization: token, "Content-Type": "application/json" }, body: JSON.stringify(spec.body) });
|
|
36128
36091
|
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();
|
|
@@ -79742,6 +79742,7 @@ const SCREENS = runtimeSetting({
|
|
|
79742
79742
|
"title": "Create product",
|
|
79743
79743
|
"style": "primary",
|
|
79744
79744
|
"fullWidth": true,
|
|
79745
|
+
"disabledPath": "$service:himiOwnerLiteProductForm.writeBusy",
|
|
79745
79746
|
"action": {
|
|
79746
79747
|
"actionId": "tier5.himiOwnerLiteProductForm.submit"
|
|
79747
79748
|
}
|
|
@@ -80061,6 +80062,7 @@ const SCREENS = runtimeSetting({
|
|
|
80061
80062
|
"title": "Create post",
|
|
80062
80063
|
"style": "primary",
|
|
80063
80064
|
"fullWidth": true,
|
|
80065
|
+
"disabledPath": "$service:himiOwnerLitePostForm.writeBusy",
|
|
80064
80066
|
"action": {
|
|
80065
80067
|
"actionId": "tier5.himiOwnerLitePostForm.submit"
|
|
80066
80068
|
}
|
|
@@ -80576,6 +80578,7 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
80576
80578
|
"title": "Save changes",
|
|
80577
80579
|
"style": "primary",
|
|
80578
80580
|
"fullWidth": true,
|
|
80581
|
+
"disabledPath": "$service:himiOwnerLiteProductForm.writeBusy",
|
|
80579
80582
|
"action": {
|
|
80580
80583
|
"actionId": "tier5.himiOwnerLiteProductForm.submit"
|
|
80581
80584
|
}
|
|
@@ -80823,6 +80826,7 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
80823
80826
|
"title": "Save changes",
|
|
80824
80827
|
"style": "primary",
|
|
80825
80828
|
"fullWidth": true,
|
|
80829
|
+
"disabledPath": "$service:himiOwnerLiteServiceForm.writeBusy",
|
|
80826
80830
|
"action": {
|
|
80827
80831
|
"actionId": "tier5.himiOwnerLiteServiceForm.submit"
|
|
80828
80832
|
}
|
|
@@ -81146,6 +81150,7 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
81146
81150
|
"title": "Save changes",
|
|
81147
81151
|
"style": "primary",
|
|
81148
81152
|
"fullWidth": true,
|
|
81153
|
+
"disabledPath": "$service:himiOwnerLitePostForm.writeBusy",
|
|
81149
81154
|
"action": {
|
|
81150
81155
|
"actionId": "tier5.himiOwnerLitePostForm.submit"
|
|
81151
81156
|
}
|
|
@@ -86711,15 +86716,31 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
86711
86716
|
|
|
86712
86717
|
// Live seed-id enumeration: a published release serves only EXACT screens, so
|
|
86713
86718
|
// `himi push` bakes each templated detail route's CURRENT catalog ids as exact
|
|
86714
|
-
// screens via `seedIds`. Anonymous visitor rung against this app's own clientId
|
|
86715
|
-
//
|
|
86719
|
+
// screens via `seedIds`. Anonymous visitor rung against this app's own clientId — or,
|
|
86720
|
+
// for an app bound through the One App visitor identity (`visitorSource: "one-app"`,
|
|
86721
|
+
// no client), that site's One App visitor instance. Best-effort (offline build → no
|
|
86722
|
+
// baked details, preview still live-resolves).
|
|
86723
|
+
async function liveSeedToken(WIX: string): Promise<string | undefined> {
|
|
86724
|
+
const auth = (config as { auth?: { config?: { clientId?: string; visitorSource?: string; metaSiteId?: string } } }).auth?.config;
|
|
86725
|
+
// A One App binding boots as the site's One App visitor, so the seed reads as that visitor too —
|
|
86726
|
+
// even beside a member-login clientId, and never repointed by a stray local WIX_CLIENT_ID.
|
|
86727
|
+
const oneApp = auth?.visitorSource === "one-app";
|
|
86728
|
+
const clientId = oneApp ? "" : process.env.WIX_CLIENT_ID ?? auth?.clientId ?? "";
|
|
86729
|
+
if (clientId && !clientId.startsWith("YOUR_")) {
|
|
86730
|
+
const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
|
|
86731
|
+
return ((await mint.json()) as { access_token?: string }).access_token;
|
|
86732
|
+
}
|
|
86733
|
+
const msid = oneApp ? auth?.metaSiteId ?? "" : "";
|
|
86734
|
+
if (!/^[0-9a-fA-F-]{10,64}$/.test(msid)) return undefined;
|
|
86735
|
+
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" });
|
|
86736
|
+
const visitor = (await mint.json()) as { signedInstance?: string; signedInstanceType?: string };
|
|
86737
|
+
return visitor.signedInstanceType === "Visitor" ? visitor.signedInstance : undefined;
|
|
86738
|
+
}
|
|
86739
|
+
|
|
86716
86740
|
async function liveSeedIds(spec: LiveSeed): Promise<string[]> {
|
|
86717
86741
|
try {
|
|
86718
86742
|
const WIX = "https://www.wixapis.com";
|
|
86719
|
-
const
|
|
86720
|
-
if (!clientId || clientId.startsWith("YOUR_")) return [];
|
|
86721
|
-
const mint = await fetch(WIX + "/oauth2/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId, grantType: "anonymous" }) });
|
|
86722
|
-
const token = ((await mint.json()) as { access_token?: string }).access_token;
|
|
86743
|
+
const token = await liveSeedToken(WIX);
|
|
86723
86744
|
if (!token) return [];
|
|
86724
86745
|
const res = await fetch(WIX + spec.path, { method: "POST", headers: { Authorization: token, "Content-Type": "application/json" }, body: JSON.stringify(spec.body) });
|
|
86725
86746
|
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
|
+
}
|