@shopify/ui-extensions-server-kit 5.2.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.
Files changed (367) hide show
  1. package/CHANGELOG.md +121 -0
  2. package/README.md +74 -0
  3. package/dist/ExtensionServerClient/ExtensionServerClient.cjs.js +1 -0
  4. package/dist/ExtensionServerClient/ExtensionServerClient.d.ts +28 -0
  5. package/dist/ExtensionServerClient/ExtensionServerClient.es.js +133 -0
  6. package/dist/ExtensionServerClient/ExtensionServerClient.test.d.ts +1 -0
  7. package/dist/ExtensionServerClient/index.d.ts +2 -0
  8. package/dist/ExtensionServerClient/types.cjs.js +1 -0
  9. package/dist/ExtensionServerClient/types.d.ts +124 -0
  10. package/dist/ExtensionServerClient/types.es.js +4 -0
  11. package/dist/context/ExtensionServerProvider.cjs.js +1 -0
  12. package/dist/context/ExtensionServerProvider.d.ts +2 -0
  13. package/dist/context/ExtensionServerProvider.es.js +29 -0
  14. package/dist/context/ExtensionServerProvider.test.d.ts +1 -0
  15. package/dist/context/constants.cjs.js +1 -0
  16. package/dist/context/constants.d.ts +3 -0
  17. package/dist/context/constants.es.js +14 -0
  18. package/dist/context/index.d.ts +3 -0
  19. package/dist/context/types.d.ts +11 -0
  20. package/dist/hooks/index.d.ts +5 -0
  21. package/dist/hooks/useExtensionClient.cjs.js +1 -0
  22. package/dist/hooks/useExtensionClient.d.ts +1 -0
  23. package/dist/hooks/useExtensionClient.es.js +8 -0
  24. package/dist/hooks/useExtensionServerContext.cjs.js +1 -0
  25. package/dist/hooks/useExtensionServerContext.d.ts +1 -0
  26. package/dist/hooks/useExtensionServerContext.es.js +6 -0
  27. package/dist/hooks/useExtensionServerEvent.cjs.js +1 -0
  28. package/dist/hooks/useExtensionServerEvent.d.ts +1 -0
  29. package/dist/hooks/useExtensionServerEvent.es.js +9 -0
  30. package/dist/hooks/useExtensionServerState.cjs.js +1 -0
  31. package/dist/hooks/useExtensionServerState.d.ts +1 -0
  32. package/dist/hooks/useExtensionServerState.es.js +9 -0
  33. package/dist/hooks/useIsomorphicLayoutEffect.cjs.js +1 -0
  34. package/dist/hooks/useIsomorphicLayoutEffect.d.ts +2 -0
  35. package/dist/hooks/useIsomorphicLayoutEffect.es.js +5 -0
  36. package/dist/i18n.cjs.js +1 -0
  37. package/dist/i18n.d.ts +93 -0
  38. package/dist/i18n.es.js +61 -0
  39. package/dist/i18n.test.d.ts +1 -0
  40. package/dist/index.cjs.js +1 -0
  41. package/dist/index.cjs2.js +1 -0
  42. package/dist/index.d.ts +7 -0
  43. package/dist/index.es.js +54 -0
  44. package/dist/index.es2.js +8 -0
  45. package/dist/state/actions/actions.cjs.js +1 -0
  46. package/dist/state/actions/actions.d.ts +6 -0
  47. package/dist/state/actions/actions.es.js +37 -0
  48. package/dist/state/actions/index.d.ts +2 -0
  49. package/dist/state/actions/types.d.ts +21 -0
  50. package/dist/state/index.d.ts +2 -0
  51. package/dist/state/reducers/constants.cjs.js +1 -0
  52. package/dist/state/reducers/constants.d.ts +2 -0
  53. package/dist/state/reducers/constants.es.js +7 -0
  54. package/dist/state/reducers/extensionServerReducer.cjs.js +1 -0
  55. package/dist/state/reducers/extensionServerReducer.d.ts +3 -0
  56. package/dist/state/reducers/extensionServerReducer.es.js +57 -0
  57. package/dist/state/reducers/extensionServerReducer.test.d.ts +1 -0
  58. package/dist/state/reducers/index.d.ts +3 -0
  59. package/dist/state/reducers/types.d.ts +6 -0
  60. package/dist/testing/MockExtensionServerProvider.cjs.js +1 -0
  61. package/dist/testing/MockExtensionServerProvider.d.ts +7 -0
  62. package/dist/testing/MockExtensionServerProvider.es.js +24 -0
  63. package/dist/testing/app.cjs.js +1 -0
  64. package/dist/testing/app.d.ts +2 -0
  65. package/dist/testing/app.es.js +16 -0
  66. package/dist/testing/extensions.cjs.js +1 -0
  67. package/dist/testing/extensions.d.ts +6 -0
  68. package/dist/testing/extensions.es.js +65 -0
  69. package/dist/testing/index.d.ts +3 -0
  70. package/dist/types.cjs.js +1 -0
  71. package/dist/types.d.ts +169 -0
  72. package/dist/types.es.js +4 -0
  73. package/dist/utilities/assetToString.cjs.js +1 -0
  74. package/dist/utilities/assetToString.d.ts +2 -0
  75. package/dist/utilities/assetToString.es.js +7 -0
  76. package/dist/utilities/assetToString.test.d.ts +1 -0
  77. package/dist/utilities/groupByKey.cjs.js +1 -0
  78. package/dist/utilities/groupByKey.d.ts +3 -0
  79. package/dist/utilities/groupByKey.es.js +6 -0
  80. package/dist/utilities/index.d.ts +7 -0
  81. package/dist/utilities/isUIExtension.cjs.js +1 -0
  82. package/dist/utilities/isUIExtension.d.ts +1 -0
  83. package/dist/utilities/isUIExtension.es.js +6 -0
  84. package/dist/utilities/isValidSurface.cjs.js +1 -0
  85. package/dist/utilities/isValidSurface.d.ts +2 -0
  86. package/dist/utilities/isValidSurface.es.js +7 -0
  87. package/dist/utilities/noop.cjs.js +1 -0
  88. package/dist/utilities/noop.d.ts +1 -0
  89. package/dist/utilities/noop.es.js +5 -0
  90. package/dist/utilities/replaceUpdated.cjs.js +1 -0
  91. package/dist/utilities/replaceUpdated.d.ts +1 -0
  92. package/dist/utilities/replaceUpdated.es.js +14 -0
  93. package/dist/utilities/replaceUpdated.test.d.ts +1 -0
  94. package/dist/utilities/set.cjs.js +1 -0
  95. package/dist/utilities/set.d.ts +4 -0
  96. package/dist/utilities/set.es.js +18 -0
  97. package/dist/utilities/set.test.d.ts +1 -0
  98. package/index.d.ts +1 -0
  99. package/index.js +1 -0
  100. package/index.mjs +1 -0
  101. package/node_modules/@shopify/react-testing/LICENSE.md +21 -0
  102. package/node_modules/@shopify/react-testing/README.md +711 -0
  103. package/node_modules/@shopify/react-testing/build/cjs/TestWrapper.js +52 -0
  104. package/node_modules/@shopify/react-testing/build/cjs/_virtual/_rollupPluginBabelHelpers.js +47 -0
  105. package/node_modules/@shopify/react-testing/build/cjs/compat.js +14 -0
  106. package/node_modules/@shopify/react-testing/build/cjs/destroy.js +13 -0
  107. package/node_modules/@shopify/react-testing/build/cjs/element.js +225 -0
  108. package/node_modules/@shopify/react-testing/build/cjs/index.js +21 -0
  109. package/node_modules/@shopify/react-testing/build/cjs/matchers/components.js +46 -0
  110. package/node_modules/@shopify/react-testing/build/cjs/matchers/context.js +25 -0
  111. package/node_modules/@shopify/react-testing/build/cjs/matchers/index.js +16 -0
  112. package/node_modules/@shopify/react-testing/build/cjs/matchers/props.js +38 -0
  113. package/node_modules/@shopify/react-testing/build/cjs/matchers/strings.js +42 -0
  114. package/node_modules/@shopify/react-testing/build/cjs/matchers/utilities.js +110 -0
  115. package/node_modules/@shopify/react-testing/build/cjs/mount.js +76 -0
  116. package/node_modules/@shopify/react-testing/build/cjs/root.js +284 -0
  117. package/node_modules/@shopify/react-testing/build/cjs/toReactString.js +86 -0
  118. package/node_modules/@shopify/react-testing/build/cjs/types.js +28 -0
  119. package/node_modules/@shopify/react-testing/build/esm/TestWrapper.mjs +44 -0
  120. package/node_modules/@shopify/react-testing/build/esm/_virtual/_rollupPluginBabelHelpers.mjs +42 -0
  121. package/node_modules/@shopify/react-testing/build/esm/compat.mjs +10 -0
  122. package/node_modules/@shopify/react-testing/build/esm/destroy.mjs +9 -0
  123. package/node_modules/@shopify/react-testing/build/esm/element.mjs +221 -0
  124. package/node_modules/@shopify/react-testing/build/esm/index.mjs +5 -0
  125. package/node_modules/@shopify/react-testing/build/esm/matchers/components.mjs +41 -0
  126. package/node_modules/@shopify/react-testing/build/esm/matchers/context.mjs +21 -0
  127. package/node_modules/@shopify/react-testing/build/esm/matchers/index.mjs +14 -0
  128. package/node_modules/@shopify/react-testing/build/esm/matchers/props.mjs +33 -0
  129. package/node_modules/@shopify/react-testing/build/esm/matchers/strings.mjs +37 -0
  130. package/node_modules/@shopify/react-testing/build/esm/matchers/utilities.mjs +101 -0
  131. package/node_modules/@shopify/react-testing/build/esm/mount.mjs +70 -0
  132. package/node_modules/@shopify/react-testing/build/esm/root.mjs +275 -0
  133. package/node_modules/@shopify/react-testing/build/esm/toReactString.mjs +80 -0
  134. package/node_modules/@shopify/react-testing/build/esm/types.mjs +26 -0
  135. package/node_modules/@shopify/react-testing/build/esnext/TestWrapper.esnext +44 -0
  136. package/node_modules/@shopify/react-testing/build/esnext/compat.esnext +10 -0
  137. package/node_modules/@shopify/react-testing/build/esnext/destroy.esnext +9 -0
  138. package/node_modules/@shopify/react-testing/build/esnext/element.esnext +221 -0
  139. package/node_modules/@shopify/react-testing/build/esnext/index.esnext +5 -0
  140. package/node_modules/@shopify/react-testing/build/esnext/matchers/components.esnext +41 -0
  141. package/node_modules/@shopify/react-testing/build/esnext/matchers/context.esnext +21 -0
  142. package/node_modules/@shopify/react-testing/build/esnext/matchers/index.esnext +14 -0
  143. package/node_modules/@shopify/react-testing/build/esnext/matchers/props.esnext +33 -0
  144. package/node_modules/@shopify/react-testing/build/esnext/matchers/strings.esnext +37 -0
  145. package/node_modules/@shopify/react-testing/build/esnext/matchers/utilities.esnext +99 -0
  146. package/node_modules/@shopify/react-testing/build/esnext/mount.esnext +71 -0
  147. package/node_modules/@shopify/react-testing/build/esnext/root.esnext +275 -0
  148. package/node_modules/@shopify/react-testing/build/esnext/toReactString.esnext +80 -0
  149. package/node_modules/@shopify/react-testing/build/esnext/types.esnext +26 -0
  150. package/node_modules/@shopify/react-testing/build/ts/TestWrapper.d.ts +17 -0
  151. package/node_modules/@shopify/react-testing/build/ts/TestWrapper.d.ts.map +1 -0
  152. package/node_modules/@shopify/react-testing/build/ts/compat.d.ts +3 -0
  153. package/node_modules/@shopify/react-testing/build/ts/compat.d.ts.map +1 -0
  154. package/node_modules/@shopify/react-testing/build/ts/destroy.d.ts +2 -0
  155. package/node_modules/@shopify/react-testing/build/ts/destroy.d.ts.map +1 -0
  156. package/node_modules/@shopify/react-testing/build/ts/element.d.ts +42 -0
  157. package/node_modules/@shopify/react-testing/build/ts/element.d.ts.map +1 -0
  158. package/node_modules/@shopify/react-testing/build/ts/index.d.ts +7 -0
  159. package/node_modules/@shopify/react-testing/build/ts/index.d.ts.map +1 -0
  160. package/node_modules/@shopify/react-testing/build/ts/matchers/components.d.ts +12 -0
  161. package/node_modules/@shopify/react-testing/build/ts/matchers/components.d.ts.map +1 -0
  162. package/node_modules/@shopify/react-testing/build/ts/matchers/context.d.ts +8 -0
  163. package/node_modules/@shopify/react-testing/build/ts/matchers/context.d.ts.map +1 -0
  164. package/node_modules/@shopify/react-testing/build/ts/matchers/index.d.ts +20 -0
  165. package/node_modules/@shopify/react-testing/build/ts/matchers/index.d.ts.map +1 -0
  166. package/node_modules/@shopify/react-testing/build/ts/matchers/props.d.ts +10 -0
  167. package/node_modules/@shopify/react-testing/build/ts/matchers/props.d.ts.map +1 -0
  168. package/node_modules/@shopify/react-testing/build/ts/matchers/strings.d.ts +11 -0
  169. package/node_modules/@shopify/react-testing/build/ts/matchers/strings.d.ts.map +1 -0
  170. package/node_modules/@shopify/react-testing/build/ts/matchers/utilities.d.ts +17 -0
  171. package/node_modules/@shopify/react-testing/build/ts/matchers/utilities.d.ts.map +1 -0
  172. package/node_modules/@shopify/react-testing/build/ts/mount.d.ts +39 -0
  173. package/node_modules/@shopify/react-testing/build/ts/mount.d.ts.map +1 -0
  174. package/node_modules/@shopify/react-testing/build/ts/root.d.ts +55 -0
  175. package/node_modules/@shopify/react-testing/build/ts/root.d.ts.map +1 -0
  176. package/node_modules/@shopify/react-testing/build/ts/toReactString.d.ts +5 -0
  177. package/node_modules/@shopify/react-testing/build/ts/toReactString.d.ts.map +1 -0
  178. package/node_modules/@shopify/react-testing/build/ts/types.d.ts +89 -0
  179. package/node_modules/@shopify/react-testing/build/ts/types.d.ts.map +1 -0
  180. package/node_modules/@shopify/react-testing/index.esnext +1 -0
  181. package/node_modules/@shopify/react-testing/index.js +1 -0
  182. package/node_modules/@shopify/react-testing/index.mjs +1 -0
  183. package/node_modules/@shopify/react-testing/matchers.esnext +1 -0
  184. package/node_modules/@shopify/react-testing/matchers.js +1 -0
  185. package/node_modules/@shopify/react-testing/matchers.mjs +1 -0
  186. package/node_modules/@shopify/react-testing/package.json +69 -0
  187. package/node_modules/@shopify/ui-extensions-test-utils/CHANGELOG.md +66 -0
  188. package/node_modules/@shopify/ui-extensions-test-utils/dist/index.js +3 -0
  189. package/node_modules/@shopify/ui-extensions-test-utils/dist/render.js +5 -0
  190. package/node_modules/@shopify/ui-extensions-test-utils/dist/renderHook.js +20 -0
  191. package/node_modules/@shopify/ui-extensions-test-utils/dist/withProviders.js +6 -0
  192. package/node_modules/@shopify/ui-extensions-test-utils/package.json +41 -0
  193. package/node_modules/@shopify/ui-extensions-test-utils/project.json +39 -0
  194. package/node_modules/@types/node/LICENSE +21 -0
  195. package/node_modules/@types/node/README.md +15 -0
  196. package/node_modules/@types/node/assert/strict.d.ts +8 -0
  197. package/node_modules/@types/node/assert.d.ts +985 -0
  198. package/node_modules/@types/node/async_hooks.d.ts +522 -0
  199. package/node_modules/@types/node/buffer.d.ts +2321 -0
  200. package/node_modules/@types/node/child_process.d.ts +1544 -0
  201. package/node_modules/@types/node/cluster.d.ts +432 -0
  202. package/node_modules/@types/node/console.d.ts +412 -0
  203. package/node_modules/@types/node/constants.d.ts +19 -0
  204. package/node_modules/@types/node/crypto.d.ts +4451 -0
  205. package/node_modules/@types/node/dgram.d.ts +586 -0
  206. package/node_modules/@types/node/diagnostics_channel.d.ts +192 -0
  207. package/node_modules/@types/node/dns/promises.d.ts +381 -0
  208. package/node_modules/@types/node/dns.d.ts +809 -0
  209. package/node_modules/@types/node/dom-events.d.ts +122 -0
  210. package/node_modules/@types/node/domain.d.ts +170 -0
  211. package/node_modules/@types/node/events.d.ts +803 -0
  212. package/node_modules/@types/node/fs/promises.d.ts +1205 -0
  213. package/node_modules/@types/node/fs.d.ts +4211 -0
  214. package/node_modules/@types/node/globals.d.ts +377 -0
  215. package/node_modules/@types/node/globals.global.d.ts +1 -0
  216. package/node_modules/@types/node/http.d.ts +1801 -0
  217. package/node_modules/@types/node/http2.d.ts +2386 -0
  218. package/node_modules/@types/node/https.d.ts +544 -0
  219. package/node_modules/@types/node/index.d.ts +88 -0
  220. package/node_modules/@types/node/inspector.d.ts +2739 -0
  221. package/node_modules/@types/node/module.d.ts +298 -0
  222. package/node_modules/@types/node/net.d.ts +913 -0
  223. package/node_modules/@types/node/os.d.ts +473 -0
  224. package/node_modules/@types/node/package.json +235 -0
  225. package/node_modules/@types/node/path.d.ts +191 -0
  226. package/node_modules/@types/node/perf_hooks.d.ts +626 -0
  227. package/node_modules/@types/node/process.d.ts +1531 -0
  228. package/node_modules/@types/node/punycode.d.ts +117 -0
  229. package/node_modules/@types/node/querystring.d.ts +141 -0
  230. package/node_modules/@types/node/readline/promises.d.ts +143 -0
  231. package/node_modules/@types/node/readline.d.ts +666 -0
  232. package/node_modules/@types/node/repl.d.ts +430 -0
  233. package/node_modules/@types/node/stream/consumers.d.ts +12 -0
  234. package/node_modules/@types/node/stream/promises.d.ts +83 -0
  235. package/node_modules/@types/node/stream/web.d.ts +336 -0
  236. package/node_modules/@types/node/stream.d.ts +1731 -0
  237. package/node_modules/@types/node/string_decoder.d.ts +67 -0
  238. package/node_modules/@types/node/test.d.ts +1113 -0
  239. package/node_modules/@types/node/timers/promises.d.ts +93 -0
  240. package/node_modules/@types/node/timers.d.ts +126 -0
  241. package/node_modules/@types/node/tls.d.ts +1203 -0
  242. package/node_modules/@types/node/trace_events.d.ts +171 -0
  243. package/node_modules/@types/node/ts4.8/assert/strict.d.ts +8 -0
  244. package/node_modules/@types/node/ts4.8/assert.d.ts +985 -0
  245. package/node_modules/@types/node/ts4.8/async_hooks.d.ts +522 -0
  246. package/node_modules/@types/node/ts4.8/buffer.d.ts +2321 -0
  247. package/node_modules/@types/node/ts4.8/child_process.d.ts +1544 -0
  248. package/node_modules/@types/node/ts4.8/cluster.d.ts +432 -0
  249. package/node_modules/@types/node/ts4.8/console.d.ts +412 -0
  250. package/node_modules/@types/node/ts4.8/constants.d.ts +19 -0
  251. package/node_modules/@types/node/ts4.8/crypto.d.ts +4450 -0
  252. package/node_modules/@types/node/ts4.8/dgram.d.ts +586 -0
  253. package/node_modules/@types/node/ts4.8/diagnostics_channel.d.ts +192 -0
  254. package/node_modules/@types/node/ts4.8/dns/promises.d.ts +381 -0
  255. package/node_modules/@types/node/ts4.8/dns.d.ts +809 -0
  256. package/node_modules/@types/node/ts4.8/dom-events.d.ts +122 -0
  257. package/node_modules/@types/node/ts4.8/domain.d.ts +170 -0
  258. package/node_modules/@types/node/ts4.8/events.d.ts +754 -0
  259. package/node_modules/@types/node/ts4.8/fs/promises.d.ts +1205 -0
  260. package/node_modules/@types/node/ts4.8/fs.d.ts +4211 -0
  261. package/node_modules/@types/node/ts4.8/globals.d.ts +377 -0
  262. package/node_modules/@types/node/ts4.8/globals.global.d.ts +1 -0
  263. package/node_modules/@types/node/ts4.8/http.d.ts +1801 -0
  264. package/node_modules/@types/node/ts4.8/http2.d.ts +2386 -0
  265. package/node_modules/@types/node/ts4.8/https.d.ts +544 -0
  266. package/node_modules/@types/node/ts4.8/index.d.ts +88 -0
  267. package/node_modules/@types/node/ts4.8/inspector.d.ts +2739 -0
  268. package/node_modules/@types/node/ts4.8/module.d.ts +298 -0
  269. package/node_modules/@types/node/ts4.8/net.d.ts +913 -0
  270. package/node_modules/@types/node/ts4.8/os.d.ts +473 -0
  271. package/node_modules/@types/node/ts4.8/path.d.ts +191 -0
  272. package/node_modules/@types/node/ts4.8/perf_hooks.d.ts +626 -0
  273. package/node_modules/@types/node/ts4.8/process.d.ts +1531 -0
  274. package/node_modules/@types/node/ts4.8/punycode.d.ts +117 -0
  275. package/node_modules/@types/node/ts4.8/querystring.d.ts +141 -0
  276. package/node_modules/@types/node/ts4.8/readline/promises.d.ts +143 -0
  277. package/node_modules/@types/node/ts4.8/readline.d.ts +666 -0
  278. package/node_modules/@types/node/ts4.8/repl.d.ts +430 -0
  279. package/node_modules/@types/node/ts4.8/stream/consumers.d.ts +12 -0
  280. package/node_modules/@types/node/ts4.8/stream/promises.d.ts +83 -0
  281. package/node_modules/@types/node/ts4.8/stream/web.d.ts +336 -0
  282. package/node_modules/@types/node/ts4.8/stream.d.ts +1731 -0
  283. package/node_modules/@types/node/ts4.8/string_decoder.d.ts +67 -0
  284. package/node_modules/@types/node/ts4.8/test.d.ts +1113 -0
  285. package/node_modules/@types/node/ts4.8/timers/promises.d.ts +93 -0
  286. package/node_modules/@types/node/ts4.8/timers.d.ts +126 -0
  287. package/node_modules/@types/node/ts4.8/tls.d.ts +1203 -0
  288. package/node_modules/@types/node/ts4.8/trace_events.d.ts +171 -0
  289. package/node_modules/@types/node/ts4.8/tty.d.ts +206 -0
  290. package/node_modules/@types/node/ts4.8/url.d.ts +937 -0
  291. package/node_modules/@types/node/ts4.8/util.d.ts +2075 -0
  292. package/node_modules/@types/node/ts4.8/v8.d.ts +541 -0
  293. package/node_modules/@types/node/ts4.8/vm.d.ts +667 -0
  294. package/node_modules/@types/node/ts4.8/wasi.d.ts +158 -0
  295. package/node_modules/@types/node/ts4.8/worker_threads.d.ts +692 -0
  296. package/node_modules/@types/node/ts4.8/zlib.d.ts +517 -0
  297. package/node_modules/@types/node/tty.d.ts +206 -0
  298. package/node_modules/@types/node/url.d.ts +937 -0
  299. package/node_modules/@types/node/util.d.ts +2075 -0
  300. package/node_modules/@types/node/v8.d.ts +541 -0
  301. package/node_modules/@types/node/vm.d.ts +667 -0
  302. package/node_modules/@types/node/wasi.d.ts +158 -0
  303. package/node_modules/@types/node/worker_threads.d.ts +692 -0
  304. package/node_modules/@types/node/zlib.d.ts +517 -0
  305. package/node_modules/@types/react/LICENSE +21 -0
  306. package/node_modules/@types/react/README.md +16 -0
  307. package/node_modules/@types/react/experimental.d.ts +192 -0
  308. package/node_modules/@types/react/global.d.ts +151 -0
  309. package/node_modules/@types/react/index.d.ts +3175 -0
  310. package/node_modules/@types/react/jsx-dev-runtime.d.ts +2 -0
  311. package/node_modules/@types/react/jsx-runtime.d.ts +2 -0
  312. package/node_modules/@types/react/package.json +149 -0
  313. package/node_modules/@vitejs/plugin-react-refresh/LICENSE +21 -0
  314. package/node_modules/@vitejs/plugin-react-refresh/README.md +73 -0
  315. package/node_modules/@vitejs/plugin-react-refresh/index.d.ts +14 -0
  316. package/node_modules/@vitejs/plugin-react-refresh/index.js +239 -0
  317. package/node_modules/@vitejs/plugin-react-refresh/package.json +35 -0
  318. package/package.json +65 -0
  319. package/project.json +74 -0
  320. package/scripts/create-entry-files.ts +44 -0
  321. package/src/ExtensionServerClient/ExtensionServerClient.test.ts +730 -0
  322. package/src/ExtensionServerClient/ExtensionServerClient.ts +310 -0
  323. package/src/ExtensionServerClient/index.ts +2 -0
  324. package/src/ExtensionServerClient/types.ts +159 -0
  325. package/src/context/ExtensionServerProvider.test.tsx +173 -0
  326. package/src/context/ExtensionServerProvider.tsx +46 -0
  327. package/src/context/constants.ts +15 -0
  328. package/src/context/index.ts +3 -0
  329. package/src/context/types.ts +13 -0
  330. package/src/hooks/index.ts +5 -0
  331. package/src/hooks/useExtensionClient.ts +6 -0
  332. package/src/hooks/useExtensionServerContext.ts +4 -0
  333. package/src/hooks/useExtensionServerEvent.ts +11 -0
  334. package/src/hooks/useExtensionServerState.ts +6 -0
  335. package/src/hooks/useIsomorphicLayoutEffect.ts +6 -0
  336. package/src/i18n.test.ts +417 -0
  337. package/src/i18n.ts +208 -0
  338. package/src/index.ts +7 -0
  339. package/src/state/actions/actions.ts +36 -0
  340. package/src/state/actions/index.ts +2 -0
  341. package/src/state/actions/types.ts +26 -0
  342. package/src/state/index.ts +2 -0
  343. package/src/state/reducers/constants.ts +6 -0
  344. package/src/state/reducers/extensionServerReducer.test.ts +160 -0
  345. package/src/state/reducers/extensionServerReducer.ts +87 -0
  346. package/src/state/reducers/index.ts +3 -0
  347. package/src/state/reducers/types.ts +7 -0
  348. package/src/testing/MockExtensionServerProvider.tsx +36 -0
  349. package/src/testing/app.ts +15 -0
  350. package/src/testing/extensions.ts +70 -0
  351. package/src/testing/index.ts +3 -0
  352. package/src/types.ts +172 -0
  353. package/src/utilities/assetToString.test.ts +16 -0
  354. package/src/utilities/assetToString.ts +8 -0
  355. package/src/utilities/groupByKey.ts +3 -0
  356. package/src/utilities/index.ts +7 -0
  357. package/src/utilities/isUIExtension.ts +7 -0
  358. package/src/utilities/isValidSurface.ts +7 -0
  359. package/src/utilities/noop.ts +1 -0
  360. package/src/utilities/replaceUpdated.test.ts +26 -0
  361. package/src/utilities/replaceUpdated.ts +16 -0
  362. package/src/utilities/set.test.ts +19 -0
  363. package/src/utilities/set.ts +29 -0
  364. package/testing.d.ts +1 -0
  365. package/testing.js +1 -0
  366. package/testing.mjs +1 -0
  367. package/tests/setup.ts +6 -0
@@ -0,0 +1,310 @@
1
+ /* eslint-disable no-console */
2
+ import {Surface} from './types.js'
3
+ import {
4
+ FlattenedLocalization,
5
+ Localization,
6
+ TRANSLATED_KEYS,
7
+ getFlattenedLocalization,
8
+ isFlattenedTranslations,
9
+ } from '../i18n'
10
+ import {isUIExtension, isValidSurface} from '../utilities'
11
+ import {DeepPartial, ExtensionPayload, ExtensionPoint} from '../types'
12
+
13
+ export class ExtensionServerClient implements ExtensionServer.Client {
14
+ public id: string
15
+
16
+ public connection!: WebSocket
17
+
18
+ public options: ExtensionServer.Options
19
+
20
+ protected EVENT_THAT_WILL_MUTATE_THE_SERVER = ['update']
21
+
22
+ protected listeners: {[key: string]: Set<any>} = {}
23
+ protected connectionListeners: {close: Set<any>; open: Set<any>} = {close: new Set(), open: new Set()}
24
+
25
+ protected connected = false
26
+
27
+ private uiExtensionsByUuid: {[key: string]: ExtensionServer.UIExtension} = {}
28
+
29
+ constructor(options: DeepPartial<ExtensionServer.Options> = {}) {
30
+ this.id = (Math.random() + 1).toString(36).substring(7)
31
+ this.options = getValidatedOptions({
32
+ ...options,
33
+ connection: {
34
+ automaticConnect: true,
35
+ protocols: [],
36
+ ...(options.connection ?? {}),
37
+ },
38
+ }) as ExtensionServer.Options
39
+
40
+ this.setupConnection(this.options.connection.automaticConnect)
41
+ }
42
+
43
+ public connect(options: ExtensionServer.Options = {connection: {}}) {
44
+ const newOptions = mergeOptions(this.options, options)
45
+ const optionsChanged = JSON.stringify(newOptions) !== JSON.stringify(this.options)
46
+
47
+ if (optionsChanged) {
48
+ this.options = newOptions
49
+ this.setupConnection(true)
50
+ }
51
+
52
+ return () => {
53
+ this.closeConnection()
54
+ }
55
+ }
56
+
57
+ public on<TEvent extends keyof ExtensionServer.InboundEvents>(
58
+ event: TEvent,
59
+ listener: (payload: ExtensionServer.InboundEvents[TEvent]) => void,
60
+ ): () => void {
61
+ if (!this.listeners[event]) {
62
+ this.listeners[event] = new Set()
63
+ }
64
+
65
+ this.listeners[event].add(listener)
66
+ return () => this.listeners[event].delete(listener)
67
+ }
68
+
69
+ public persist<TEvent extends keyof ExtensionServer.OutboundPersistEvents>(
70
+ event: TEvent,
71
+ data: ExtensionServer.OutboundPersistEvents[TEvent],
72
+ ): void {
73
+ if (this.EVENT_THAT_WILL_MUTATE_THE_SERVER.includes(event)) {
74
+ if (!this.options.locales) {
75
+ return this.connection?.send(JSON.stringify({event, data}))
76
+ }
77
+
78
+ /**
79
+ * Since each websocket connection will have its own translated values
80
+ * we need to strip out all translated properties to prevent
81
+ * mutating the Dev Server's data
82
+ * Before:
83
+ * ```
84
+ * {
85
+ * name: 'en name'
86
+ * localization: {...},
87
+ * extensionPoints: [{
88
+ * target: 'admin.product.item.action'
89
+ * name: 'en name'
90
+ * description: 'en description'
91
+ * localization: {...}
92
+ * }],
93
+ * }
94
+ * ```
95
+ * After:
96
+ * ```
97
+ * extensionPoints: [{
98
+ * target: 'admin.product.item.action'
99
+ * }],
100
+ * }
101
+ * ```
102
+ */
103
+ data.extensions?.forEach((extension) => {
104
+ TRANSLATED_KEYS.forEach((key) => {
105
+ if (isUIExtension(extension)) {
106
+ extension.extensionPoints?.forEach((extensionPoint) => {
107
+ delete extensionPoint[key as keyof ExtensionPoint]
108
+ })
109
+ }
110
+ delete extension[key as keyof ExtensionPayload]
111
+ })
112
+ })
113
+ return this.connection?.send(JSON.stringify({event, data}))
114
+ }
115
+
116
+ console.warn(`You tried to use "persist" with a dispatch event. Please use the "emit" method instead.`)
117
+ }
118
+
119
+ public emit<TEvent extends keyof ExtensionServer.DispatchEvents>(...args: ExtensionServer.EmitArgs<TEvent>): void {
120
+ const [event, data] = args
121
+
122
+ if (this.EVENT_THAT_WILL_MUTATE_THE_SERVER.includes(event)) {
123
+ return console.warn(
124
+ `You tried to use "emit" with a the "${event}" event. Please use the "persist" method instead to persist changes to the server.`,
125
+ )
126
+ }
127
+
128
+ this.connection?.send(JSON.stringify({event: 'dispatch', data: {type: event, payload: data}}))
129
+ }
130
+
131
+ public onConnection<TEvent extends keyof typeof this.connectionListeners>(
132
+ event: TEvent,
133
+ listener: (event: Event) => void,
134
+ ): () => void {
135
+ this.connectionListeners[event].add(listener)
136
+ return () => this.connectionListeners[event].delete(listener)
137
+ }
138
+
139
+ protected initializeConnection() {
140
+ if (!this.connection) {
141
+ return
142
+ }
143
+
144
+ this.connection.addEventListener('open', (event) => {
145
+ this.connected = true
146
+ this.connectionListeners.open.forEach((listener) => listener(event))
147
+ })
148
+
149
+ this.connection.addEventListener('close', (event) => {
150
+ this.connected = false
151
+ this.connectionListeners.close.forEach((listener) => listener(event))
152
+ })
153
+
154
+ this.connection?.addEventListener('message', (message) => {
155
+ try {
156
+ const {event, data} = JSON.parse(message.data) as ExtensionServer.ServerEvents
157
+
158
+ if (event === 'dispatch') {
159
+ const {type, payload} = data
160
+ this.listeners[type]?.forEach((listener) => listener(payload))
161
+ return
162
+ }
163
+
164
+ const filteredExtensions = data.extensions
165
+ ? filterExtensionsBySurface(data.extensions, this.options.surface)
166
+ : data.extensions
167
+
168
+ this.listeners[event]?.forEach((listener) => {
169
+ listener({...data, extensions: this._getLocalizedExtensions(filteredExtensions)})
170
+ })
171
+ // eslint-disable-next-line no-catch-all/no-catch-all
172
+ } catch (err) {
173
+ console.error(
174
+ `[ExtensionServer] Something went wrong while parsing a server message:`,
175
+ err instanceof Error ? err.message : err,
176
+ )
177
+ }
178
+ })
179
+ }
180
+
181
+ protected setupConnection(connectWebsocket = true) {
182
+ if (!this.options.connection.url) {
183
+ return
184
+ }
185
+
186
+ if (!connectWebsocket) {
187
+ return
188
+ }
189
+
190
+ this.closeConnection()
191
+
192
+ this.connection = new WebSocket(this.options.connection.url, this.options.connection.protocols)
193
+
194
+ this.initializeConnection()
195
+ }
196
+
197
+ protected closeConnection() {
198
+ if (this.connected) {
199
+ this.connection?.close()
200
+ }
201
+ }
202
+
203
+ private _getLocalizedExtensions(extensions?: ExtensionPayload[]) {
204
+ return extensions?.map((extension) => {
205
+ if (!this.options.locales || !isUIExtension(extension)) {
206
+ return extension
207
+ }
208
+
209
+ const shouldUpdateTranslations =
210
+ this.uiExtensionsByUuid[extension.uuid]?.localization?.lastUpdated !== extension.localization?.lastUpdated
211
+
212
+ const localization = shouldUpdateTranslations
213
+ ? getFlattenedLocalization(extension.localization, this.options.locales)
214
+ : this.uiExtensionsByUuid[extension.uuid]?.localization || extension.localization
215
+
216
+ const parsedTranslation: {[key: string]: string} =
217
+ localization && isFlattenedTranslations(localization) ? JSON.parse(localization.translations) : localization
218
+
219
+ const localizedExtension = {
220
+ ...extension,
221
+ localization,
222
+ name:
223
+ parsedTranslation && extension.name.startsWith('t:')
224
+ ? this._getLocalizedValue(parsedTranslation, extension.name)
225
+ : extension.name,
226
+ ...(extension.description && {
227
+ description:
228
+ parsedTranslation && extension.description?.startsWith('t:')
229
+ ? this._getLocalizedValue(parsedTranslation, extension.description)
230
+ : extension.description,
231
+ }),
232
+ }
233
+
234
+ this.uiExtensionsByUuid[extension.uuid] = {
235
+ ...localizedExtension,
236
+ extensionPoints: this._getLocalizedExtensionPoints(localization, localizedExtension),
237
+ }
238
+
239
+ return this.uiExtensionsByUuid[extension.uuid]
240
+ })
241
+ }
242
+
243
+ private _getLocalizedExtensionPoints(
244
+ localization: FlattenedLocalization | Localization | null | undefined,
245
+ {extensionPoints, name, description}: ExtensionServer.UIExtension,
246
+ ): ExtensionPoint[] {
247
+ if (!localization || !isFlattenedTranslations(localization)) {
248
+ return extensionPoints
249
+ }
250
+
251
+ return extensionPoints?.map((extensionPoint) => {
252
+ return {
253
+ ...extensionPoint,
254
+ localization,
255
+ name,
256
+ ...(description && {description}),
257
+ }
258
+ })
259
+ }
260
+
261
+ private _getLocalizedValue(translations: {[x: string]: string}, value: string): string {
262
+ const translationKey = value.replace('t:', '')
263
+ return translations[translationKey] || value
264
+ }
265
+ }
266
+
267
+ function mergeOptions(options: ExtensionServer.Options, newOptions: ExtensionServer.Options) {
268
+ return getValidatedOptions({
269
+ ...options,
270
+ ...newOptions,
271
+ connection: {
272
+ ...options.connection,
273
+ ...newOptions.connection,
274
+ },
275
+ })
276
+ }
277
+
278
+ function getValidatedOptions<TOptions extends DeepPartial<ExtensionServer.Options>>(options: TOptions): TOptions {
279
+ if (!isValidSurface(options.surface)) {
280
+ delete options.surface
281
+ }
282
+ return options
283
+ }
284
+
285
+ function filterExtensionsBySurface(extensions: ExtensionPayload[], surface: Surface | undefined): ExtensionPayload[] {
286
+ if (!surface) {
287
+ return extensions
288
+ }
289
+
290
+ return extensions.filter((extension) => {
291
+ if (extension.surface === surface) {
292
+ return true
293
+ }
294
+
295
+ if (Array.isArray(extension.extensionPoints)) {
296
+ const extensionPoints: (string | {surface: Surface; [key: string]: any})[] = extension.extensionPoints
297
+ const extensionPointMatchingSurface = extensionPoints.filter((extensionPoint) => {
298
+ if (typeof extensionPoint === 'string') {
299
+ return false
300
+ }
301
+
302
+ return extensionPoint.surface === surface
303
+ })
304
+
305
+ return extensionPointMatchingSurface.length > 0
306
+ }
307
+
308
+ return false
309
+ })
310
+ }
@@ -0,0 +1,2 @@
1
+ export * from './ExtensionServerClient'
2
+ export * from './types'
@@ -0,0 +1,159 @@
1
+ import type {LocalesOptions} from '../i18n'
2
+
3
+ declare global {
4
+ namespace ExtensionServer {
5
+ /**
6
+ * Events being received by the extension server where the keys are the event names
7
+ * and the values are the payload of the given action. In case no payload is
8
+ * required, a value of void should be used.
9
+ */
10
+ interface InboundEvents {
11
+ //
12
+ }
13
+
14
+ /**
15
+ * Events being sent to the extension server where the keys are the event names
16
+ * and the values are the payload of the given action. In case no payload is
17
+ * required, a value of void should be used.
18
+ *
19
+ * Persist events are those that will generate changes on the server, like
20
+ * update and connected events. Dispatch events are those that will
21
+ * simply be proxied to the clients connected to the server.
22
+ */
23
+ interface OutboundPersistEvents {
24
+ //
25
+ }
26
+
27
+ interface DispatchEvents {
28
+ //
29
+ }
30
+
31
+ /**
32
+ * Extension server client class options. These are used to configure
33
+ * the client class.
34
+ */
35
+ interface Options {
36
+ connection: {
37
+ /**
38
+ * The absolute URL of the WebSocket.
39
+ */
40
+ url?: string
41
+
42
+ /**
43
+ * This defines if we should automatically attempt to connect when the
44
+ * class is instantiated.
45
+ *
46
+ * @defaultValue true
47
+ */
48
+ automaticConnect?: boolean
49
+
50
+ /**
51
+ * The sub-protocol selected by the server.
52
+ *
53
+ * @defaultValue []
54
+ */
55
+ protocols?: string | string[]
56
+ }
57
+ /**
58
+ * If provided the extension server will only return extensions that matches the specified surface
59
+ */
60
+ surface?: Surface
61
+
62
+ /**
63
+ * If provided the extension server will return a requested translations object with flattened
64
+ * translations for each extension matching the requested locales
65
+ */
66
+ locales?: LocalesOptions
67
+ }
68
+
69
+ /**
70
+ * Extension server client class. This class will be used to connect and
71
+ * communicate with the extension server.
72
+ */
73
+ interface Client {
74
+ /**
75
+ * Connection options
76
+ */
77
+ options: Options
78
+
79
+ /**
80
+ * Reconnecting WebSocket Client
81
+ */
82
+ connection: WebSocket
83
+
84
+ /**
85
+ * Function to add an event listener to messages coming from
86
+ * the extension server connection.
87
+ */
88
+ on<TEvent extends keyof ExtensionServer.InboundEvents>(
89
+ event: TEvent,
90
+ cb: EventListener<TEvent>,
91
+ ): EventUnsubscriber
92
+
93
+ /**
94
+ * Function to emit an event that will persist changes to the extension server.
95
+ */
96
+ persist<TEvent extends keyof OutboundPersistEvents>(event: TEvent, payload: OutboundPersistEvents[TEvent]): void
97
+
98
+ /**
99
+ * Function to emit an event to the extension server.
100
+ */
101
+ emit<TEvent extends keyof DispatchEvents>(...args: EmitArgs<TEvent>): void
102
+
103
+ /**
104
+ * Function that opens a connection with the extensions server.
105
+ */
106
+ connect(options?: Options): () => void
107
+ }
108
+
109
+ /**
110
+ * This defines how the ExtensionServer client's static class is defined and the constructor
111
+ * arguments it requires.
112
+ *
113
+ * @example
114
+ * ```
115
+ * const client = new ExtensionServer({ url: 'wss://localhost:1234' });
116
+ * ```
117
+ */
118
+ type StaticClient = Static<ExtensionServer.Client, [option?: ExtensionServer.Options]>
119
+
120
+ // Utilities
121
+
122
+ /**
123
+ * This helper type allows us to account for nullish payloads on the emit function.
124
+ * In practice, this will allow TypeScript to type-check the event being emitted
125
+ * and, if the payload isn't required, the second argument won't be necessary.
126
+ */
127
+ type EmitArgs<TEvent extends keyof ExtensionServer.DispatchEvents> =
128
+ ExtensionServer.DispatchEvents[TEvent] extends void
129
+ ? [event: TEvent]
130
+ : [event: TEvent, payload: ExtensionServer.DispatchEvents[TEvent]]
131
+
132
+ /**
133
+ * This is a helper interface that allows us to define the static methods of a given
134
+ * class. This is useful to define static methods, static properties
135
+ * and constructor variables.
136
+ */
137
+ interface Static<T = unknown, TArgs extends unknown[] = unknown[]> {
138
+ prototype: T
139
+ new (...args: TArgs): T
140
+ }
141
+
142
+ /**
143
+ * This helper creates a partial interface with exception to the defined key values.
144
+ */
145
+ type PartialExcept<TOject, TKey extends keyof TOject> = Partial<Omit<TOject, TKey>> & Pick<TOject, TKey>
146
+
147
+ type EventListener<TEvent extends keyof ExtensionServer.InboundEvents> = (
148
+ payload: ExtensionServer.InboundEvents[TEvent],
149
+ ) => void
150
+
151
+ type EventUnsubscriber = () => void
152
+ }
153
+ }
154
+
155
+ export const AVAILABLE_SURFACES = ['admin', 'checkout', 'post_purchase', 'point_of_sale', 'customer-accounts'] as const
156
+
157
+ export type Surface = (typeof AVAILABLE_SURFACES)[number]
158
+
159
+ export {}
@@ -0,0 +1,173 @@
1
+ import {ExtensionServerProvider} from './ExtensionServerProvider'
2
+ import {mockApp, mockExtension} from '../testing'
3
+ import {useExtensionServerContext} from '../hooks'
4
+ import {createConnectedAction} from '../state'
5
+ import WS from 'jest-websocket-mock'
6
+ import {renderHook, withProviders} from '@shopify/ui-extensions-test-utils'
7
+
8
+ describe('ExtensionServerProvider tests', () => {
9
+ describe('client tests', () => {
10
+ test('creates a new ExtensionServerClient instance', async () => {
11
+ const options = {connection: {url: 'ws://example-host.com:8000/extensions/'}}
12
+
13
+ const wrapper = renderHook(useExtensionServerContext, withProviders(ExtensionServerProvider), {options})
14
+
15
+ expect(wrapper.result.client).toBeDefined()
16
+ })
17
+
18
+ test('does not start a new connection if an empty url is passed', async () => {
19
+ const options = {connection: {}}
20
+
21
+ const wrapper = renderHook(useExtensionServerContext, withProviders(ExtensionServerProvider), {options})
22
+
23
+ expect(wrapper.result.client.connection).toBeUndefined()
24
+ })
25
+ })
26
+
27
+ describe('connect tests', () => {
28
+ test('starts a new connection by calling connect', async () => {
29
+ const options = {connection: {url: 'ws://example-host.com:8000/extensions/'}}
30
+ const socket = new WS(options.connection.url, {jsonProtocol: true})
31
+ const wrapper = renderHook(useExtensionServerContext, withProviders(ExtensionServerProvider), {
32
+ options: {
33
+ connection: {url: ''},
34
+ },
35
+ })
36
+
37
+ expect(socket.server.clients()).toHaveLength(0)
38
+
39
+ wrapper.act(({connect}) => connect(options))
40
+
41
+ expect(wrapper.result.client.connection).toBeDefined()
42
+ expect(socket.server.clients()).toHaveLength(1)
43
+ socket.close()
44
+ })
45
+ })
46
+
47
+ describe('dispatch tests', () => {
48
+ test('updates the state', async () => {
49
+ const options = {connection: {url: 'ws://example-host.com:8000/extensions/'}}
50
+ const app = mockApp()
51
+ const extension = mockExtension()
52
+ const payload = {app, extensions: [extension], store: 'test-store.com'}
53
+ const wrapper = renderHook(useExtensionServerContext, withProviders(ExtensionServerProvider), {options})
54
+
55
+ wrapper.act(({dispatch}) => {
56
+ dispatch({type: 'connected', payload})
57
+ })
58
+
59
+ expect(wrapper.result.state).toStrictEqual({
60
+ app,
61
+ extensions: [extension],
62
+ store: 'test-store.com',
63
+ })
64
+ })
65
+ })
66
+
67
+ describe('state tests', () => {
68
+ let socket: WS
69
+ const options = {connection: {url: 'ws://example-host.com:8000/extensions/'}}
70
+
71
+ beforeEach(() => {
72
+ socket = new WS(options.connection.url, {jsonProtocol: true})
73
+ })
74
+
75
+ afterEach(() => {
76
+ socket.close()
77
+ })
78
+
79
+ test('persists connection data to the state', async () => {
80
+ const app = mockApp()
81
+ const extension = mockExtension()
82
+ const data = {app, store: 'test-store.com', extensions: [extension]}
83
+ const wrapper = renderHook(useExtensionServerContext, withProviders(ExtensionServerProvider), {options})
84
+
85
+ wrapper.act(() => socket.send({event: 'connected', data}))
86
+
87
+ expect(wrapper.result.state).toEqual({
88
+ app,
89
+ extensions: [extension],
90
+ store: 'test-store.com',
91
+ })
92
+ })
93
+
94
+ test('persists update data to the state', async () => {
95
+ const app = mockApp()
96
+ const extension = mockExtension()
97
+ const update = {...extension, version: 'v2'}
98
+ const data = {app, store: 'test-store.com', extensions: [extension]}
99
+ const wrapper = renderHook(useExtensionServerContext, withProviders(ExtensionServerProvider), {options})
100
+
101
+ wrapper.act(({dispatch}) => {
102
+ dispatch(createConnectedAction(data))
103
+
104
+ socket.send({event: 'update', data: {...data, extensions: [update]}})
105
+ })
106
+
107
+ expect(wrapper.result.state).toEqual({
108
+ app,
109
+ extensions: [update],
110
+ store: 'test-store.com',
111
+ })
112
+ })
113
+
114
+ // eslint-disable-next-line vitest/no-disabled-tests
115
+ test.skip('persists refresh data to the state', async () => {
116
+ const app = mockApp()
117
+ const extension = mockExtension()
118
+ const data = {app, store: 'test-store.com', extensions: [extension]}
119
+ const wrapper = renderHook(useExtensionServerContext, withProviders(ExtensionServerProvider), {options})
120
+
121
+ wrapper.act(({dispatch}) => {
122
+ dispatch(createConnectedAction(data))
123
+
124
+ socket.send({
125
+ event: 'dispatch',
126
+ data: {type: 'refresh', payload: [{uuid: extension.uuid}]},
127
+ })
128
+ })
129
+
130
+ const [updatedExtension] = wrapper.result.state.extensions
131
+ expect(updatedExtension.assets.main.url).not.toEqual(extension.assets.main.url)
132
+ })
133
+
134
+ test('persists focus data to the state', async () => {
135
+ const app = mockApp()
136
+ const extension = mockExtension()
137
+ const data = {app, store: 'test-store.com', extensions: [extension]}
138
+ const wrapper = renderHook(useExtensionServerContext, withProviders(ExtensionServerProvider), {options})
139
+
140
+ wrapper.act(({dispatch}) => {
141
+ dispatch(createConnectedAction(data))
142
+
143
+ socket.send({
144
+ event: 'dispatch',
145
+ data: {type: 'focus', payload: [{uuid: extension.uuid}]},
146
+ })
147
+ })
148
+
149
+ const [updatedExtension] = wrapper.result.state.extensions
150
+ expect(updatedExtension.development.focused).toBe(true)
151
+ })
152
+
153
+ test('persists unfocus data to the state', async () => {
154
+ const app = mockApp()
155
+ const extension = mockExtension()
156
+ extension.development.focused = true
157
+ const data = {app, store: 'test-store.com', extensions: [extension]}
158
+ const wrapper = renderHook(useExtensionServerContext, withProviders(ExtensionServerProvider), {options})
159
+
160
+ wrapper.act(({dispatch}) => {
161
+ dispatch(createConnectedAction(data))
162
+
163
+ socket.send({
164
+ event: 'dispatch',
165
+ data: {type: 'unfocus'},
166
+ })
167
+ })
168
+
169
+ const [updatedExtension] = wrapper.result.state.extensions
170
+ expect(updatedExtension.development.focused).toBe(false)
171
+ })
172
+ })
173
+ })
@@ -0,0 +1,46 @@
1
+ import {extensionServerContext} from './constants'
2
+ import {
3
+ createConnectedAction,
4
+ createUpdateAction,
5
+ createRefreshAction,
6
+ createFocusAction,
7
+ createUnfocusAction,
8
+ } from '../state'
9
+
10
+ import {ExtensionServerClient} from '../ExtensionServerClient'
11
+ import {useIsomorphicLayoutEffect} from '../hooks/useIsomorphicLayoutEffect'
12
+ import {useExtensionServerState} from '../hooks/useExtensionServerState'
13
+ import React, {useCallback, useMemo, useState} from 'react'
14
+
15
+ import type {ExtensionServerProviderProps} from './types'
16
+
17
+ export function ExtensionServerProvider({children, options: defaultOptions}: ExtensionServerProviderProps) {
18
+ const [state, dispatch] = useExtensionServerState()
19
+ const [options, setOptions] = useState(defaultOptions)
20
+ const [client] = useState<ExtensionServer.Client>(() => new ExtensionServerClient())
21
+
22
+ const connect = useCallback(
23
+ (newOptions: ExtensionServer.Options = options) => {
24
+ setOptions(newOptions)
25
+ },
26
+ [options],
27
+ )
28
+
29
+ useIsomorphicLayoutEffect(() => client.connect(options), [client, options])
30
+
31
+ useIsomorphicLayoutEffect(() => {
32
+ const listeners = [
33
+ client.on('update', (payload) => dispatch(createUpdateAction(payload))),
34
+ client.on('connected', (payload) => dispatch(createConnectedAction(payload))),
35
+ client.on('refresh', (payload) => dispatch(createRefreshAction(payload))),
36
+ client.on('focus', (payload) => dispatch(createFocusAction(payload))),
37
+ client.on('unfocus', (payload) => dispatch(createUnfocusAction(payload))),
38
+ ]
39
+
40
+ return () => listeners.forEach((unsubscribe) => unsubscribe())
41
+ }, [dispatch])
42
+
43
+ const context = useMemo(() => ({dispatch, state, connect, client}), [dispatch, connect, state, client])
44
+
45
+ return <extensionServerContext.Provider value={context}>{children}</extensionServerContext.Provider>
46
+ }