@saolabs/client 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (378) hide show
  1. package/README.md +52 -195
  2. package/dist/index.d.ts +20 -5
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +14 -3
  5. package/dist/index.js.map +1 -1
  6. package/dist/plugins.d.ts +2 -2
  7. package/dist/plugins.js +2 -2
  8. package/dist/src/core/app/Application.d.ts +17 -15
  9. package/dist/src/core/app/Application.d.ts.map +1 -1
  10. package/dist/src/core/app/Application.js +41 -18
  11. package/dist/src/core/app/Application.js.map +1 -1
  12. package/dist/src/core/bootstrap/app.d.ts +1 -1
  13. package/dist/src/core/bootstrap/app.d.ts.map +1 -1
  14. package/dist/src/core/bootstrap/app.js +74 -4
  15. package/dist/src/core/bootstrap/app.js.map +1 -1
  16. package/dist/src/core/bootstrap/bundle.d.ts +41 -0
  17. package/dist/src/core/bootstrap/bundle.d.ts.map +1 -0
  18. package/dist/src/core/bootstrap/bundle.js +98 -0
  19. package/dist/src/core/bootstrap/bundle.js.map +1 -0
  20. package/dist/src/core/bootstrap/providers/ApiServiceProvider.d.ts +1 -1
  21. package/dist/src/core/bootstrap/providers/ApiServiceProvider.d.ts.map +1 -1
  22. package/dist/src/core/bootstrap/providers/ApiServiceProvider.js +3 -3
  23. package/dist/src/core/bootstrap/providers/ApiServiceProvider.js.map +1 -1
  24. package/dist/src/core/bootstrap/providers/CoreServiceProvider.d.ts +1 -1
  25. package/dist/src/core/bootstrap/providers/CoreServiceProvider.d.ts.map +1 -1
  26. package/dist/src/core/bootstrap/providers/CoreServiceProvider.js +11 -8
  27. package/dist/src/core/bootstrap/providers/CoreServiceProvider.js.map +1 -1
  28. package/dist/src/core/bootstrap/providers/HelperServiceProvider.d.ts +3 -1
  29. package/dist/src/core/bootstrap/providers/HelperServiceProvider.d.ts.map +1 -1
  30. package/dist/src/core/bootstrap/providers/HelperServiceProvider.js +8 -3
  31. package/dist/src/core/bootstrap/providers/HelperServiceProvider.js.map +1 -1
  32. package/dist/src/core/bootstrap/providers/RouteServiceProvider.d.ts +2 -1
  33. package/dist/src/core/bootstrap/providers/RouteServiceProvider.d.ts.map +1 -1
  34. package/dist/src/core/bootstrap/providers/RouteServiceProvider.js +14 -4
  35. package/dist/src/core/bootstrap/providers/RouteServiceProvider.js.map +1 -1
  36. package/dist/src/core/bootstrap/providers/ServiceProvider.d.ts +4 -4
  37. package/dist/src/core/bootstrap/providers/ServiceProvider.d.ts.map +1 -1
  38. package/dist/src/core/bootstrap/providers/ServiceProvider.js +5 -5
  39. package/dist/src/core/bootstrap/providers/ServiceProvider.js.map +1 -1
  40. package/dist/src/core/bootstrap/providers/ViewServiceProvider.d.ts +1 -1
  41. package/dist/src/core/bootstrap/providers/ViewServiceProvider.d.ts.map +1 -1
  42. package/dist/src/core/bootstrap/providers/ViewServiceProvider.js +3 -3
  43. package/dist/src/core/bootstrap/providers/ViewServiceProvider.js.map +1 -1
  44. package/dist/src/core/bootstrap/providers/default-providers.d.ts +1 -1
  45. package/dist/src/core/bootstrap/providers/default-providers.d.ts.map +1 -1
  46. package/dist/src/core/bootstrap/providers/default-providers.js +44 -11
  47. package/dist/src/core/bootstrap/providers/default-providers.js.map +1 -1
  48. package/dist/src/core/bootstrap/providers/index.d.ts +9 -9
  49. package/dist/src/core/bootstrap/providers/index.d.ts.map +1 -1
  50. package/dist/src/core/bootstrap/providers/index.js +8 -8
  51. package/dist/src/core/bootstrap/providers/index.js.map +1 -1
  52. package/dist/src/core/bootstrap/providers/provider-order.d.ts +1 -1
  53. package/dist/src/core/bootstrap/providers/provider-order.d.ts.map +1 -1
  54. package/dist/src/core/bootstrap/ssr.d.ts +47 -0
  55. package/dist/src/core/bootstrap/ssr.d.ts.map +1 -0
  56. package/dist/src/core/bootstrap/ssr.js +125 -0
  57. package/dist/src/core/bootstrap/ssr.js.map +1 -0
  58. package/dist/src/core/cache/ViewCache.d.ts +1 -1
  59. package/dist/src/core/cache/ViewCache.d.ts.map +1 -1
  60. package/dist/src/core/cache/index.d.ts +1 -1
  61. package/dist/src/core/cache/index.d.ts.map +1 -1
  62. package/dist/src/core/cache/index.js +1 -1
  63. package/dist/src/core/cache/index.js.map +1 -1
  64. package/dist/src/core/contracts/ApplicationInterface.d.ts +13 -11
  65. package/dist/src/core/contracts/ApplicationInterface.d.ts.map +1 -1
  66. package/dist/src/core/contracts/BlockInterface.d.ts +10 -10
  67. package/dist/src/core/contracts/BlockInterface.d.ts.map +1 -1
  68. package/dist/src/core/contracts/BundleInterface.d.ts +38 -0
  69. package/dist/src/core/contracts/BundleInterface.d.ts.map +1 -0
  70. package/dist/src/core/contracts/BundleInterface.js +2 -0
  71. package/dist/src/core/contracts/BundleInterface.js.map +1 -0
  72. package/dist/src/core/contracts/ComponentInterface.d.ts +7 -6
  73. package/dist/src/core/contracts/ComponentInterface.d.ts.map +1 -1
  74. package/dist/src/core/contracts/ElementInterface.d.ts +91 -27
  75. package/dist/src/core/contracts/ElementInterface.d.ts.map +1 -1
  76. package/dist/src/core/contracts/HeadServiceInterface.d.ts +37 -0
  77. package/dist/src/core/contracts/HeadServiceInterface.d.ts.map +1 -0
  78. package/dist/src/core/contracts/HeadServiceInterface.js +3 -0
  79. package/dist/src/core/contracts/HeadServiceInterface.js.map +1 -0
  80. package/dist/src/core/contracts/HelperInterface.d.ts +9 -1
  81. package/dist/src/core/contracts/HelperInterface.d.ts.map +1 -1
  82. package/dist/src/core/contracts/HttpServiceInterface.d.ts +3 -0
  83. package/dist/src/core/contracts/HttpServiceInterface.d.ts.map +1 -1
  84. package/dist/src/core/contracts/MarkerInterface.d.ts +29 -44
  85. package/dist/src/core/contracts/MarkerInterface.d.ts.map +1 -1
  86. package/dist/src/core/contracts/ReactiveInterface.d.ts +9 -9
  87. package/dist/src/core/contracts/ReactiveInterface.d.ts.map +1 -1
  88. package/dist/src/core/contracts/RouterInterface.d.ts +5 -2
  89. package/dist/src/core/contracts/RouterInterface.d.ts.map +1 -1
  90. package/dist/src/core/contracts/SectionInterface.d.ts +48 -0
  91. package/dist/src/core/contracts/SectionInterface.d.ts.map +1 -0
  92. package/dist/src/core/contracts/SectionInterface.js +2 -0
  93. package/dist/src/core/contracts/SectionInterface.js.map +1 -0
  94. package/dist/src/core/contracts/ServiceProviderInterface.d.ts +3 -3
  95. package/dist/src/core/contracts/ServiceProviderInterface.d.ts.map +1 -1
  96. package/dist/src/core/contracts/ViewControllerInterface.d.ts +116 -15
  97. package/dist/src/core/contracts/ViewControllerInterface.d.ts.map +1 -1
  98. package/dist/src/core/contracts/ViewInterface.d.ts +31 -5
  99. package/dist/src/core/contracts/ViewInterface.d.ts.map +1 -1
  100. package/dist/src/core/contracts/ViewManagerInterface.d.ts +47 -5
  101. package/dist/src/core/contracts/ViewManagerInterface.d.ts.map +1 -1
  102. package/dist/src/core/contracts/ViewStateInterface.d.ts +39 -2
  103. package/dist/src/core/contracts/ViewStateInterface.d.ts.map +1 -1
  104. package/dist/src/core/contracts/common.d.ts +3 -3
  105. package/dist/src/core/contracts/common.js +3 -3
  106. package/dist/src/core/contracts/utils.d.ts +19 -19
  107. package/dist/src/core/contracts/utils.d.ts.map +1 -1
  108. package/dist/src/core/contracts/views.d.ts +1 -22
  109. package/dist/src/core/contracts/views.d.ts.map +1 -1
  110. package/dist/src/core/devtools/hook.d.ts +66 -0
  111. package/dist/src/core/devtools/hook.d.ts.map +1 -0
  112. package/dist/src/core/devtools/hook.js +114 -0
  113. package/dist/src/core/devtools/hook.js.map +1 -0
  114. package/dist/src/core/devtools/index.d.ts +34 -0
  115. package/dist/src/core/devtools/index.d.ts.map +1 -0
  116. package/dist/src/core/devtools/index.js +33 -0
  117. package/dist/src/core/devtools/index.js.map +1 -0
  118. package/dist/src/core/devtools/inspector.d.ts +31 -0
  119. package/dist/src/core/devtools/inspector.d.ts.map +1 -0
  120. package/dist/src/core/devtools/inspector.js +249 -0
  121. package/dist/src/core/devtools/inspector.js.map +1 -0
  122. package/dist/src/core/elements/Block.d.ts +9 -7
  123. package/dist/src/core/elements/Block.d.ts.map +1 -1
  124. package/dist/src/core/elements/Block.js +33 -9
  125. package/dist/src/core/elements/Block.js.map +1 -1
  126. package/dist/src/core/elements/BlockOutlet.d.ts +19 -8
  127. package/dist/src/core/elements/BlockOutlet.d.ts.map +1 -1
  128. package/dist/src/core/elements/BlockOutlet.js +57 -13
  129. package/dist/src/core/elements/BlockOutlet.js.map +1 -1
  130. package/dist/src/core/elements/Component.d.ts +83 -11
  131. package/dist/src/core/elements/Component.d.ts.map +1 -1
  132. package/dist/src/core/elements/Component.js +334 -13
  133. package/dist/src/core/elements/Component.js.map +1 -1
  134. package/dist/src/core/elements/ForeachSlotCache.d.ts +95 -0
  135. package/dist/src/core/elements/ForeachSlotCache.d.ts.map +1 -0
  136. package/dist/src/core/elements/ForeachSlotCache.js +149 -0
  137. package/dist/src/core/elements/ForeachSlotCache.js.map +1 -0
  138. package/dist/src/core/elements/Fragment.d.ts +19 -13
  139. package/dist/src/core/elements/Fragment.d.ts.map +1 -1
  140. package/dist/src/core/elements/Fragment.js +43 -20
  141. package/dist/src/core/elements/Fragment.js.map +1 -1
  142. package/dist/src/core/elements/Html.d.ts +89 -12
  143. package/dist/src/core/elements/Html.d.ts.map +1 -1
  144. package/dist/src/core/elements/Html.js +707 -106
  145. package/dist/src/core/elements/Html.js.map +1 -1
  146. package/dist/src/core/elements/Output.d.ts +34 -10
  147. package/dist/src/core/elements/Output.d.ts.map +1 -1
  148. package/dist/src/core/elements/Output.js +141 -26
  149. package/dist/src/core/elements/Output.js.map +1 -1
  150. package/dist/src/core/elements/Reactive.d.ts +85 -14
  151. package/dist/src/core/elements/Reactive.d.ts.map +1 -1
  152. package/dist/src/core/elements/Reactive.js +315 -41
  153. package/dist/src/core/elements/Reactive.js.map +1 -1
  154. package/dist/src/core/elements/TextElement.d.ts +11 -7
  155. package/dist/src/core/elements/TextElement.d.ts.map +1 -1
  156. package/dist/src/core/elements/TextElement.js +18 -11
  157. package/dist/src/core/elements/TextElement.js.map +1 -1
  158. package/dist/src/core/elements/Wrapper.d.ts +24 -13
  159. package/dist/src/core/elements/Wrapper.d.ts.map +1 -1
  160. package/dist/src/core/elements/Wrapper.js +65 -8
  161. package/dist/src/core/elements/Wrapper.js.map +1 -1
  162. package/dist/src/core/elements/Yield.d.ts +10 -9
  163. package/dist/src/core/elements/Yield.d.ts.map +1 -1
  164. package/dist/src/core/elements/Yield.js +31 -19
  165. package/dist/src/core/elements/Yield.js.map +1 -1
  166. package/dist/src/core/elements/helpers.d.ts +7 -7
  167. package/dist/src/core/elements/helpers.d.ts.map +1 -1
  168. package/dist/src/core/elements/helpers.js +4 -4
  169. package/dist/src/core/elements/index.d.ts +12 -11
  170. package/dist/src/core/elements/index.d.ts.map +1 -1
  171. package/dist/src/core/elements/index.js +12 -11
  172. package/dist/src/core/elements/index.js.map +1 -1
  173. package/dist/src/core/elements/reconcileChildren.d.ts +7 -0
  174. package/dist/src/core/elements/reconcileChildren.d.ts.map +1 -0
  175. package/dist/src/core/elements/reconcileChildren.js +74 -0
  176. package/dist/src/core/elements/reconcileChildren.js.map +1 -0
  177. package/dist/src/core/hellpers/utils.d.ts +2 -2
  178. package/dist/src/core/hellpers/utils.js +4 -4
  179. package/dist/src/core/helpers/ApiClient.d.ts +58 -0
  180. package/dist/src/core/helpers/ApiClient.d.ts.map +1 -0
  181. package/dist/src/core/helpers/ApiClient.js +131 -0
  182. package/dist/src/core/helpers/ApiClient.js.map +1 -0
  183. package/dist/src/core/helpers/app.d.ts +3 -0
  184. package/dist/src/core/helpers/app.d.ts.map +1 -0
  185. package/dist/src/core/helpers/app.js +63 -0
  186. package/dist/src/core/helpers/app.js.map +1 -0
  187. package/dist/src/core/helpers/transition.d.ts +34 -0
  188. package/dist/src/core/helpers/transition.d.ts.map +1 -0
  189. package/dist/src/core/helpers/transition.js +118 -0
  190. package/dist/src/core/helpers/transition.js.map +1 -0
  191. package/dist/src/core/helpers/utils.d.ts +26 -0
  192. package/dist/src/core/helpers/utils.d.ts.map +1 -0
  193. package/dist/src/core/helpers/utils.js +96 -0
  194. package/dist/src/core/helpers/utils.js.map +1 -0
  195. package/dist/src/core/helpers/view.d.ts +39 -0
  196. package/dist/src/core/helpers/view.d.ts.map +1 -0
  197. package/dist/src/core/helpers/view.js +286 -0
  198. package/dist/src/core/helpers/view.js.map +1 -0
  199. package/dist/src/core/routers/Router.d.ts +108 -7
  200. package/dist/src/core/routers/Router.d.ts.map +1 -1
  201. package/dist/src/core/routers/Router.js +444 -68
  202. package/dist/src/core/routers/Router.js.map +1 -1
  203. package/dist/src/core/routers/index.d.ts +2 -2
  204. package/dist/src/core/routers/index.d.ts.map +1 -1
  205. package/dist/src/core/routers/index.js +1 -1
  206. package/dist/src/core/routers/index.js.map +1 -1
  207. package/dist/src/core/services/AssetManager.d.ts +112 -0
  208. package/dist/src/core/services/AssetManager.d.ts.map +1 -0
  209. package/dist/src/core/services/AssetManager.js +361 -0
  210. package/dist/src/core/services/AssetManager.js.map +1 -0
  211. package/dist/src/core/services/BlockManager.d.ts +73 -2
  212. package/dist/src/core/services/BlockManager.d.ts.map +1 -1
  213. package/dist/src/core/services/BlockManager.js +270 -48
  214. package/dist/src/core/services/BlockManager.js.map +1 -1
  215. package/dist/src/core/services/DomService.js +3 -3
  216. package/dist/src/core/services/DomService.js.map +1 -1
  217. package/dist/src/core/services/HeadService.d.ts +24 -0
  218. package/dist/src/core/services/HeadService.d.ts.map +1 -0
  219. package/dist/src/core/services/HeadService.js +120 -0
  220. package/dist/src/core/services/HeadService.js.map +1 -0
  221. package/dist/src/core/services/HelperService.d.ts +14 -3
  222. package/dist/src/core/services/HelperService.d.ts.map +1 -1
  223. package/dist/src/core/services/HelperService.js +32 -2
  224. package/dist/src/core/services/HelperService.js.map +1 -1
  225. package/dist/src/core/services/HttpService.d.ts +8 -0
  226. package/dist/src/core/services/HttpService.d.ts.map +1 -1
  227. package/dist/src/core/services/HttpService.js +121 -47
  228. package/dist/src/core/services/HttpService.js.map +1 -1
  229. package/dist/src/core/services/MarkerRegistry.d.ts +51 -8
  230. package/dist/src/core/services/MarkerRegistry.d.ts.map +1 -1
  231. package/dist/src/core/services/MarkerRegistry.js +135 -14
  232. package/dist/src/core/services/MarkerRegistry.js.map +1 -1
  233. package/dist/src/core/services/PageCache.d.ts +101 -0
  234. package/dist/src/core/services/PageCache.d.ts.map +1 -0
  235. package/dist/src/core/services/PageCache.js +184 -0
  236. package/dist/src/core/services/PageCache.js.map +1 -0
  237. package/dist/src/core/services/SectionManager.d.ts +100 -0
  238. package/dist/src/core/services/SectionManager.d.ts.map +1 -0
  239. package/dist/src/core/services/SectionManager.js +408 -0
  240. package/dist/src/core/services/SectionManager.js.map +1 -0
  241. package/dist/src/core/services/StorageService.js +1 -1
  242. package/dist/src/core/services/TranslationService.d.ts +21 -0
  243. package/dist/src/core/services/TranslationService.d.ts.map +1 -0
  244. package/dist/src/core/services/TranslationService.js +95 -0
  245. package/dist/src/core/services/TranslationService.js.map +1 -0
  246. package/dist/src/core/services/index.d.ts +11 -8
  247. package/dist/src/core/services/index.d.ts.map +1 -1
  248. package/dist/src/core/services/index.js +11 -8
  249. package/dist/src/core/services/index.js.map +1 -1
  250. package/dist/src/core/types/utils.d.ts +8 -8
  251. package/dist/src/core/types/utils.d.ts.map +1 -1
  252. package/dist/src/core/view/LoopContext.d.ts +21 -1
  253. package/dist/src/core/view/LoopContext.d.ts.map +1 -1
  254. package/dist/src/core/view/LoopContext.js +36 -0
  255. package/dist/src/core/view/LoopContext.js.map +1 -1
  256. package/dist/src/core/view/ResourceScope.d.ts +38 -0
  257. package/dist/src/core/view/ResourceScope.d.ts.map +1 -0
  258. package/dist/src/core/view/ResourceScope.js +167 -0
  259. package/dist/src/core/view/ResourceScope.js.map +1 -0
  260. package/dist/src/core/view/Section.d.ts +17 -32
  261. package/dist/src/core/view/Section.d.ts.map +1 -1
  262. package/dist/src/core/view/Section.js +14 -55
  263. package/dist/src/core/view/Section.js.map +1 -1
  264. package/dist/src/core/view/View.d.ts +43 -7
  265. package/dist/src/core/view/View.d.ts.map +1 -1
  266. package/dist/src/core/view/View.js +22 -4
  267. package/dist/src/core/view/View.js.map +1 -1
  268. package/dist/src/core/view/ViewController.d.ts +313 -40
  269. package/dist/src/core/view/ViewController.d.ts.map +1 -1
  270. package/dist/src/core/view/ViewController.js +1002 -147
  271. package/dist/src/core/view/ViewController.js.map +1 -1
  272. package/dist/src/core/view/ViewManager.d.ts +318 -27
  273. package/dist/src/core/view/ViewManager.d.ts.map +1 -1
  274. package/dist/src/core/view/ViewManager.js +1199 -258
  275. package/dist/src/core/view/ViewManager.js.map +1 -1
  276. package/dist/src/core/view/ViewState.d.ts +185 -6
  277. package/dist/src/core/view/ViewState.d.ts.map +1 -1
  278. package/dist/src/core/view/ViewState.js +851 -123
  279. package/dist/src/core/view/ViewState.js.map +1 -1
  280. package/dist/src/core/view/index.d.ts +5 -5
  281. package/dist/src/core/view/index.d.ts.map +1 -1
  282. package/dist/src/core/view/index.js +5 -5
  283. package/dist/src/core/view/index.js.map +1 -1
  284. package/dist/src/testing/index.d.ts +69 -0
  285. package/dist/src/testing/index.d.ts.map +1 -0
  286. package/dist/src/testing/index.js +140 -0
  287. package/dist/src/testing/index.js.map +1 -0
  288. package/index.ts +29 -5
  289. package/package.json +30 -21
  290. package/plugins.ts +2 -2
  291. package/src/core/app/Application.ts +58 -31
  292. package/src/core/bootstrap/app.ts +80 -6
  293. package/src/core/bootstrap/bundle.ts +101 -0
  294. package/src/core/bootstrap/providers/ApiServiceProvider.ts +4 -4
  295. package/src/core/bootstrap/providers/CoreServiceProvider.ts +14 -8
  296. package/src/core/bootstrap/providers/HelperServiceProvider.ts +8 -3
  297. package/src/core/bootstrap/providers/RouteServiceProvider.ts +15 -4
  298. package/src/core/bootstrap/providers/ServiceProvider.ts +8 -8
  299. package/src/core/bootstrap/providers/ViewServiceProvider.ts +3 -3
  300. package/src/core/bootstrap/providers/default-providers.ts +51 -16
  301. package/src/core/bootstrap/providers/index.ts +9 -9
  302. package/src/core/bootstrap/providers/provider-order.test.ts +16 -27
  303. package/src/core/bootstrap/providers/provider-order.ts +1 -1
  304. package/src/core/bootstrap/ssr.ts +136 -0
  305. package/src/core/cache/ViewCache.ts +1 -1
  306. package/src/core/cache/index.ts +1 -1
  307. package/src/core/contracts/ApplicationInterface.ts +13 -11
  308. package/src/core/contracts/BlockInterface.ts +18 -18
  309. package/src/core/contracts/BundleInterface.ts +40 -0
  310. package/src/core/contracts/ComponentInterface.ts +7 -6
  311. package/src/core/contracts/ElementInterface.ts +95 -27
  312. package/src/core/contracts/HeadServiceInterface.ts +41 -0
  313. package/src/core/contracts/HelperInterface.ts +9 -1
  314. package/src/core/contracts/HttpServiceInterface.ts +3 -0
  315. package/src/core/contracts/MarkerInterface.ts +22 -49
  316. package/src/core/contracts/ReactiveInterface.ts +9 -9
  317. package/src/core/contracts/RouterInterface.ts +5 -2
  318. package/src/core/contracts/SectionInterface.ts +49 -0
  319. package/src/core/contracts/ServiceProviderInterface.ts +3 -3
  320. package/src/core/contracts/ViewControllerInterface.ts +124 -16
  321. package/src/core/contracts/ViewInterface.ts +34 -5
  322. package/src/core/contracts/ViewManagerInterface.ts +40 -5
  323. package/src/core/contracts/ViewStateInterface.ts +39 -2
  324. package/src/core/contracts/common.ts +3 -3
  325. package/src/core/contracts/utils.ts +19 -19
  326. package/src/core/contracts/views.ts +2 -22
  327. package/src/core/devtools/hook.ts +142 -0
  328. package/src/core/devtools/index.ts +38 -0
  329. package/src/core/devtools/inspector.ts +270 -0
  330. package/src/core/elements/Block.ts +43 -21
  331. package/src/core/elements/BlockOutlet.ts +61 -21
  332. package/src/core/elements/Component.ts +352 -18
  333. package/src/core/elements/ElementManager.ts +9 -9
  334. package/src/core/elements/ForeachSlotCache.ts +170 -0
  335. package/src/core/elements/Fragment.ts +50 -32
  336. package/src/core/elements/Html.ts +696 -117
  337. package/src/core/elements/Output.ts +147 -30
  338. package/src/core/elements/Reactive.ts +329 -52
  339. package/src/core/elements/TextElement.ts +25 -16
  340. package/src/core/elements/Wrapper.ts +84 -18
  341. package/src/core/elements/Yield.ts +35 -24
  342. package/src/core/elements/helpers.ts +12 -12
  343. package/src/core/elements/index.ts +25 -24
  344. package/src/core/elements/reconcileChildren.ts +70 -0
  345. package/src/core/{hellpers → helpers}/ApiClient.ts +8 -1
  346. package/src/core/{hellpers → helpers}/app.ts +13 -2
  347. package/src/core/helpers/transition.ts +127 -0
  348. package/src/core/{hellpers → helpers}/utils.ts +4 -4
  349. package/src/core/helpers/view.ts +283 -0
  350. package/src/core/routers/Router.ts +458 -64
  351. package/src/core/routers/index.ts +2 -2
  352. package/src/core/services/AssetManager.ts +387 -0
  353. package/src/core/services/BlockManager.ts +272 -50
  354. package/src/core/services/DomService.ts +3 -3
  355. package/src/core/services/HeadService.ts +124 -0
  356. package/src/core/services/HelperService.ts +34 -4
  357. package/src/core/services/HttpService.ts +116 -55
  358. package/src/core/services/MarkerRegistry.ts +142 -16
  359. package/src/core/services/PageCache.ts +239 -0
  360. package/src/core/services/SectionManager.ts +387 -0
  361. package/src/core/services/StorageService.ts +1 -1
  362. package/src/core/services/TranslationService.ts +91 -0
  363. package/src/core/services/index.ts +11 -8
  364. package/src/core/types/utils.ts +8 -8
  365. package/src/core/view/LoopContext.ts +38 -1
  366. package/src/core/view/ResourceScope.ts +174 -0
  367. package/src/core/view/Section.ts +21 -68
  368. package/src/core/view/View.ts +57 -8
  369. package/src/core/view/ViewController.ts +1070 -186
  370. package/src/core/view/ViewManager.ts +1346 -272
  371. package/src/core/view/ViewState.ts +834 -116
  372. package/src/core/view/index.ts +5 -5
  373. package/src/testing/index.ts +184 -0
  374. package/dist/src/core/services/MarkerService.d.ts +0 -299
  375. package/dist/src/core/services/MarkerService.d.ts.map +0 -1
  376. package/dist/src/core/services/MarkerService.js +0 -723
  377. package/dist/src/core/services/MarkerService.js.map +0 -1
  378. package/src/core/services/MarkerService.ts +0 -923
@@ -27,22 +27,23 @@
27
27
  * const router = app.make('router');
28
28
  */
29
29
 
30
- import type { ApplicationInterface, ServiceKey, ServiceFactory, ServiceBinding } from '../contracts/ApplicationInterface';
31
- import type { ServiceProviderInterface } from '../contracts/ServiceProviderInterface';
32
- import type { ViewManagerInterface, RouterInterface } from '../contracts/utils';
33
- import type { HelperInterface } from '../contracts/HelperInterface';
34
- import type { EventServiceInterface } from '../contracts/EventServiceInterface';
35
- import type { HttpServiceInterface } from '../contracts/HttpServiceInterface';
36
- import type { StoreServiceInterface } from '../contracts/StoreServiceInterface';
37
- import type { StorageServiceInterface } from '../contracts/StorageServiceInterface';
38
- import type { LoggerServiceInterface } from '../contracts/LoggerServiceInterface';
39
- import { APIClientInterface } from '../contracts/ApiInterface';
40
- import { OneObjectType, OOTEnum } from '../types/utils';
30
+ import type { ApplicationInterface, ServiceKey, ServiceFactory, ServiceBinding } from '../contracts/ApplicationInterface.js';
31
+ import type { ServiceProviderInterface } from '../contracts/ServiceProviderInterface.js';
32
+ import type { ViewManagerInterface, RouterInterface } from '../contracts/utils.js';
33
+ import type { HelperInterface } from '../contracts/HelperInterface.js';
34
+ import type { EventServiceInterface } from '../contracts/EventServiceInterface.js';
35
+ import type { HttpServiceInterface } from '../contracts/HttpServiceInterface.js';
36
+ import type { StoreServiceInterface } from '../contracts/StoreServiceInterface.js';
37
+ import type { StorageServiceInterface } from '../contracts/StorageServiceInterface.js';
38
+ import type { LoggerServiceInterface } from '../contracts/LoggerServiceInterface.js';
39
+ import type { HeadServiceInterface } from '../contracts/HeadServiceInterface.js';
40
+ import { APIClientInterface } from '../contracts/ApiInterface.js';
41
+ import { SaoObjectType, OOTEnum } from '../types/utils.js';
41
42
 
42
43
  // ─── Application ────────────────────────────────────────────────
43
44
 
44
45
  export class Application implements ApplicationInterface {
45
- readonly oneType: OneObjectType = OOTEnum.APPLICATION;
46
+ readonly saoType: SaoObjectType = OOTEnum.APPLICATION;
46
47
  // Service properties — set during bootstrap via App.set()
47
48
  declare isInitialized: boolean;
48
49
  declare isStarted: boolean;
@@ -55,6 +56,7 @@ export class Application implements ApplicationInterface {
55
56
  declare Store: StoreServiceInterface;
56
57
  declare Storage: StorageServiceInterface;
57
58
  declare Logger: LoggerServiceInterface;
59
+ declare Head: HeadServiceInterface;
58
60
 
59
61
  /** Factory bindings — mỗi lần make() gọi factory tạo instance mới */
60
62
  private bindings = new Map<ServiceKey, ServiceFactory<any>>();
@@ -97,7 +99,7 @@ export class Application implements ApplicationInterface {
97
99
  '__store',
98
100
  ]; // Để track dynamic properties nếu cần
99
101
 
100
- __store: Map<string, { isOverridable: boolean, value: any }> = new Map(); // Store cho dynamic properties nếu cần
102
+ __store: Map<any, { isOverridable: boolean, value: any }> = new Map(); // Store cho dynamic properties nếu cần
101
103
 
102
104
  [key: string]: any; // Cho phép dynamic properties nếu cần
103
105
 
@@ -179,6 +181,18 @@ export class Application implements ApplicationInterface {
179
181
  */
180
182
  instance<T>(key: ServiceKey<T>, value: T): this {
181
183
  this.singletons.set(key, value);
184
+ if (typeof key === 'string' && !this.ownProperties.includes(key)) {
185
+ this.__store.set(key, { value, isOverridable: true });
186
+ Object.defineProperty(this, key, {
187
+ get: () => this.__store.get(key)?.value,
188
+ set: (newValue) => {
189
+ this.__store.set(key, { value: newValue, isOverridable: true });
190
+ this.singletons.set(key, newValue);
191
+ },
192
+ configurable: true,
193
+ enumerable: false,
194
+ });
195
+ }
182
196
  return this;
183
197
  }
184
198
 
@@ -289,6 +303,15 @@ export class Application implements ApplicationInterface {
289
303
  (provider as any).initApplication();
290
304
  }
291
305
  provider.register();
306
+
307
+ // Đăng ký SAU khi app đã boot — plugin nạp muộn qua App.push(), hoặc
308
+ // provider của theme cắm vào giữa phiên. boot() vòng lặp chính đã chạy
309
+ // xong và có cờ chặn, nên nếu không gọi ở đây thì provider chỉ chạy nửa
310
+ // vòng đời: register() có, boot() không, và KHÔNG có lỗi nào phát ra.
311
+ if (this.booted && typeof provider.boot === 'function') {
312
+ provider.boot();
313
+ }
314
+
292
315
  return this;
293
316
  }
294
317
 
@@ -342,31 +365,35 @@ export class Application implements ApplicationInterface {
342
365
  }
343
366
 
344
367
 
345
- set<T = any>(name: string, value: T, isOne: boolean = false): void {
346
- if (this.ownProperties.includes(name)) {
347
- return; // Không cho ghi đè lên thuộc tính có sẵn
348
- }
368
+ set<T = any>(name: any, value: T, isOne: boolean = false): void {
349
369
  if (this.__store.has(name) && this.__store.get(name)?.isOverridable === false) {
350
370
  return; // Không cho ghi đè lên thuộc tính không thể override
351
371
  }
372
+ const isString = typeof name === 'string';
373
+ if (isString && this.ownProperties.includes(name)) {
374
+ return; // Không cho ghi đè lên thuộc tính có sẵn
375
+ }
352
376
  this.__store.set(name, { value, isOverridable: !isOne });
353
377
  this.singletons.set(name, value); // Sync → DI container
354
- Object.defineProperty(this, name, {
355
- get: () => this.__store.get(name)?.value,
356
- set: (newValue) => {
357
- if (this.__store.has(name) && this.__store.get(name)?.isOverridable === false) {
358
- return; // Không cho ghi đè nếu isOverridable là false
359
- }
360
- this.__store.set(name, { value: newValue, isOverridable: !isOne });
361
- this.singletons.set(name, newValue); // Sync → DI container
362
- },
363
- configurable: isOne ? false : true,
364
- enumerable: false,
365
- });
378
+ if (isString) {
379
+ Object.defineProperty(this, name, {
380
+ get: () => this.__store.get(name)?.value,
381
+ set: (newValue) => {
382
+ if (this.__store.has(name) && this.__store.get(name)?.isOverridable === false) {
383
+ return; // Không cho ghi đè nếu isOverridable là false
384
+ }
385
+ this.__store.set(name, { value: newValue, isOverridable: !isOne });
386
+ this.singletons.set(name, newValue); // Sync → DI container
387
+ },
388
+ configurable: isOne ? false : true,
389
+ enumerable: false,
390
+ });
391
+ }
366
392
  }
367
393
 
368
- get<T = any>(name: string): T {
369
- if (this.ownProperties.includes(name)) {
394
+ get<T = any>(name: any): T {
395
+ const isString = typeof name === 'string';
396
+ if (isString && this.ownProperties.includes(name)) {
370
397
  return (this as any)[name]; // Trả về thuộc tính có sẵn
371
398
  }
372
399
  // Check __store first (registered via set())
@@ -1,7 +1,10 @@
1
- import { ApplicationInterface } from "../contracts/ApplicationInterface";
2
- import { app } from "../hellpers/app";
3
- import { Router } from "../routers";
4
- import { buildDefaultProviders, resolveProviderOrder } from "./providers";
1
+ import { ApplicationInterface } from "../contracts/ApplicationInterface.js";
2
+ import { app } from "../helpers/app.js";
3
+ import { Router } from "../routers/index.js";
4
+ import { buildDefaultProviders, resolveProviderOrder } from "./providers/index.js";
5
+ import { readSSRBoot, readBootConfig, mergeBootConfig } from "./ssr.js";
6
+ import { bootBundles, loadBundles } from "./bundle.js";
7
+ import type { MergedBundles } from "../contracts/BundleInterface.js";
5
8
 
6
9
  const App: ApplicationInterface = app<ApplicationInterface>();
7
10
 
@@ -9,6 +12,41 @@ const App: ApplicationInterface = app<ApplicationInterface>();
9
12
  App.set<boolean>('isInitialized', false);
10
13
  App.set<boolean>('isStarted', false);
11
14
 
15
+ /**
16
+ * Hàng đợi `App.push(fn)` — cửa cho mã KHÔNG đi qua bundler (snippet trong
17
+ * layout, plugin bên thứ ba, thư viện nạp bất đồng bộ).
18
+ *
19
+ * Mẫu `dataLayer.push`: trước khi file này chạy, `window.App` là một MẢNG và
20
+ * `.push(fn)` chỉ xếp hàng. Ở đây ta rút hàng đợi rồi thay bằng App thật, và
21
+ * gắn `App.push` = chạy NGAY. Nhờ vậy CÙNG MỘT dòng gọi
22
+ *
23
+ * (window.App = window.App || []).push(fn)
24
+ *
25
+ * hoạt động ở cả ba mốc: trước khi app.js tải, trong lúc parse, và sau khi app
26
+ * đã boot. Tác giả plugin không phải biết mình chạy lúc nào.
27
+ *
28
+ * ⚠️ Hệ quả: `window.App` là MẢNG cho tới lúc boot. Đọc App phải đọc TRONG
29
+ * callback, đừng đọc ở tầng module.
30
+ */
31
+ function drainPushQueue(): void {
32
+ if (typeof window === 'undefined') return;
33
+ const w = window as any;
34
+
35
+ const pending: unknown[] = Array.isArray(w.App) ? w.App : [];
36
+
37
+ (App as any).push = (fn: (app: ApplicationInterface) => void): void => {
38
+ if (typeof fn !== 'function') return;
39
+ try {
40
+ fn(App);
41
+ } catch (err) {
42
+ console.error('[App.push] callback ném lỗi:', err);
43
+ }
44
+ };
45
+ w.App = App;
46
+
47
+ for (const fn of pending) (App as any).push(fn);
48
+ }
49
+
12
50
  /**
13
51
  * Khởi tạo app — đăng ký + boot tất cả providers theo dependency order.
14
52
  *
@@ -38,19 +76,55 @@ App.setMethod('init', function (config: Record<string, any> = {}) {
38
76
  /**
39
77
  * Start app — init nếu chưa, rồi start Router.
40
78
  *
79
+ * Nếu phát hiện SSR boot (script saola-ssr), inject vào config.view.ssr để
80
+ * ViewManager + Router hydrate route đầu tiên thay vì mount mới.
81
+ *
41
82
  * @example
42
83
  * App.start(); // init với config mặc định
43
84
  * App.start({ view: { container: '#app' } }); // init với config tùy chỉnh
44
85
  */
45
- App.setMethod('start', function (config?: Record<string, any>) {
86
+ App.setMethod('start', async function (config?: Record<string, any>) {
46
87
  if (App.isStarted) {
47
88
  console.warn('[Bootstrap] App already started.');
48
89
  return;
49
90
  }
91
+ let bundles: MergedBundles | null = null;
50
92
  if (!App.isInitialized) {
51
- App.init(config || {});
93
+ // Config app truyền có ưu tiên hơn boot config (window.APP_CONFIGS:
94
+ // routes + container từ server). Thiếu APP_CONFIGS → chỉ dùng config app.
95
+ const boot = readBootConfig() || {};
96
+ const cfg = mergeBootConfig(boot, config || {});
97
+
98
+ // SSR boot (script saola-ssr) → ssr + container cho hydrate route đầu.
99
+ const ssr = readSSRBoot();
100
+ if (ssr) {
101
+ cfg.view = {
102
+ ...(cfg.view || {}),
103
+ ssr: { view: ssr.view, viewId: ssr.viewId },
104
+ container: (cfg.view && cfg.view.container) || ssr.container,
105
+ };
106
+ }
107
+ // Bundle nạp rời (theme…): server phát danh sách URL trong
108
+ // APP_CONFIGS.bundles. Phải await TRƯỚC init để view/service/provider
109
+ // của chúng có mặt lúc provider boot và lúc render route đầu.
110
+ bundles = await loadBundles(cfg.bundles);
111
+ cfg.view = {
112
+ ...(cfg.view || {}),
113
+ // Bundle nạp sau ĐÈ registry của app — đúng ngữ nghĩa overlay theme.
114
+ registry: { ...(cfg.view?.registry || {}), ...bundles.views },
115
+ };
116
+ cfg.services = { ...(cfg.services || {}), ...bundles.services };
117
+ cfg.helpers = { ...(cfg.helpers || {}), ...bundles.helpers };
118
+ cfg.providers = [...(cfg.providers || []), ...bundles.providers];
119
+
120
+ App.init(cfg);
121
+ bootBundles(bundles, App);
52
122
  }
53
123
 
124
+ // Sau init (View/Router/Helper đã có), TRƯỚC khi render: chỗ duy nhất mà
125
+ // mã ngoài cắm vào được mà chắc chắn kịp.
126
+ drainPushQueue();
127
+
54
128
  App.get<Router>('Router').start();
55
129
  App.isStarted = true;
56
130
  }, true);
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Bundle nạp rời — hợp đồng + loader.
3
+ *
4
+ * Bài toán: một gói build ĐỘC LẬP (theme) phải cắm được view / service /
5
+ * helper / provider vào app đang chạy, mà không chia sẻ module graph với app.
6
+ * Cầu nối là import map: `@saolabs/client` của gói đó resolve về đúng file
7
+ * entry của app, nên hai bên dùng CHUNG một instance runtime. Xem
8
+ * docs/EXTENSION_ARCHITECTURE.md §7.
9
+ */
10
+
11
+ import type { ApplicationInterface } from "../contracts/ApplicationInterface.js";
12
+ import type { MergedBundles, SaolaBundle } from "../contracts/BundleInterface.js";
13
+ import logger from "../services/LoggerService.js";
14
+
15
+ /**
16
+ * Khai báo một bundle. Chỉ là identity + kiểu — nó tồn tại để tên khoá là HỢP
17
+ * ĐỒNG chứ không phải quy ước truyền miệng, và để IDE gợi ý được.
18
+ *
19
+ * @example
20
+ * export default defineBundle({
21
+ * name: 'theme:aurora',
22
+ * views: { 'themes.aurora.modules.ping.index': factory },
23
+ * });
24
+ */
25
+ export function defineBundle(bundle: SaolaBundle): SaolaBundle {
26
+ return bundle;
27
+ }
28
+
29
+ function emptyMerged(): MergedBundles {
30
+ return { providers: [], services: {}, helpers: {}, views: {}, boots: [], loaded: [], failed: [] };
31
+ }
32
+
33
+ /**
34
+ * Gộp nhiều manifest theo ĐÚNG THỨ TỰ mảng — không theo thứ tự resolve của
35
+ * mạng. Bundle sau ĐÈ bundle trước ở `views`/`services`/`helpers`; `providers`
36
+ * thì CỘNG THÊM chứ không thay, để một bundle không gỡ được provider của app.
37
+ */
38
+ export function mergeBundles(bundles: Array<SaolaBundle | null | undefined>): MergedBundles {
39
+ const out = emptyMerged();
40
+
41
+ for (const bundle of bundles) {
42
+ if (!bundle || typeof bundle !== 'object') continue;
43
+ out.loaded.push(bundle.name ?? '(không tên)');
44
+ if (Array.isArray(bundle.providers)) out.providers.push(...bundle.providers);
45
+ if (bundle.services) Object.assign(out.services, bundle.services);
46
+ if (bundle.helpers) Object.assign(out.helpers, bundle.helpers);
47
+ if (bundle.views) Object.assign(out.views, bundle.views);
48
+ if (typeof bundle.boot === 'function') out.boots.push(bundle.boot.bind(bundle));
49
+ }
50
+
51
+ return out;
52
+ }
53
+
54
+ /**
55
+ * Nạp danh sách URL bundle rồi gộp lại.
56
+ *
57
+ * Tải SONG SONG nhưng gộp theo thứ tự mảng — thứ tự URL là thứ tự ưu tiên do
58
+ * server quyết định (`APP_CONFIGS.bundles`), không phải do mạng.
59
+ *
60
+ * Một URL hỏng KHÔNG làm sập boot: ghi vào `failed` rồi đi tiếp. Theme lỗi thì
61
+ * site chạy bằng view gốc, còn hơn trắng trang.
62
+ */
63
+ export async function loadBundles(urls: string[] | null | undefined): Promise<MergedBundles> {
64
+ if (!Array.isArray(urls) || urls.length === 0) return emptyMerged();
65
+
66
+ const results = await Promise.all(urls.map(async (url): Promise<[string, SaolaBundle | null, string | null]> => {
67
+ try {
68
+ // URL đến từ runtime nên bundler không phân tích tĩnh được — đúng ý
69
+ // đồ. Viết literal ở đây sẽ làm GÃY build của app (rollup cố resolve
70
+ // một đường dẫn không có trong module graph).
71
+ const mod: any = await import(/* @vite-ignore */ /* webpackIgnore: true */ url);
72
+ // Bundle có thể khai manifest (export default) HOẶC tự đăng ký ngay
73
+ // trong thân module qua App.View/App.set — import đã await xong nên
74
+ // cả hai đều kịp trước khi render.
75
+ return [url, (mod?.default ?? null) as SaolaBundle | null, null];
76
+ } catch (err) {
77
+ return [url, null, String(err)];
78
+ }
79
+ }));
80
+
81
+ const merged = mergeBundles(results.map(([, bundle]) => bundle));
82
+ for (const [url, , error] of results) {
83
+ if (error) {
84
+ merged.failed.push([url, error]);
85
+ logger.error(`[Bundle] Không nạp được "${url}": ${error}`);
86
+ }
87
+ }
88
+
89
+ return merged;
90
+ }
91
+
92
+ /** Chạy `boot()` của các bundle, sau khi App đã init. Lỗi một cái không chặn cái sau. */
93
+ export function bootBundles(merged: MergedBundles, app: ApplicationInterface): void {
94
+ for (const boot of merged.boots) {
95
+ try {
96
+ boot(app);
97
+ } catch (err) {
98
+ logger.error('[Bundle] boot() ném lỗi:', err);
99
+ }
100
+ }
101
+ }
@@ -1,7 +1,7 @@
1
- import { APIClientInterface } from "../../contracts/ApiInterface";
2
- import { ApiClient } from "../../hellpers/ApiClient";
3
- import { PROVIDER_NAMES } from "./provider-order";
4
- import { ServiceProvider } from "./ServiceProvider";
1
+ import { APIClientInterface } from "../../contracts/ApiInterface.js";
2
+ import { ApiClient } from "../../helpers/ApiClient.js";
3
+ import { PROVIDER_NAMES } from "./provider-order.js";
4
+ import { ServiceProvider } from "./ServiceProvider.js";
5
5
 
6
6
  export class ApiServiceProvider extends ServiceProvider {
7
7
  readonly name = PROVIDER_NAMES.API;
@@ -1,19 +1,25 @@
1
- import { app } from "../../hellpers/app";
2
- import { EventService } from "../../services/EventService";
3
- import { HttpService } from "../../services/HttpService";
4
- import { MarkerService } from "../../services/MarkerService";
5
- import { StoreService } from "../../services/StoreService";
6
- import { PROVIDER_NAMES } from "./provider-order";
7
- import { ServiceProvider } from "./ServiceProvider";
1
+ import { MarkerRegistryInterface } from "../../contracts/MarkerInterface.js";
2
+ import { app } from "../../helpers/app.js";
3
+ import { MarkerRegistry, MarkerRegistryService } from "../../services/index.js";
4
+ import { EventService } from "../../services/EventService.js";
5
+ import { HttpService } from "../../services/HttpService.js";
6
+ import { StoreService } from "../../services/StoreService.js";
7
+ import HeadService from "../../services/HeadService.js";
8
+ import { Devtools } from "../../devtools/index.js";
9
+ import type { HeadServiceInterface } from "../../contracts/HeadServiceInterface.js";
10
+ import { PROVIDER_NAMES } from "./provider-order.js";
11
+ import { ServiceProvider } from "./ServiceProvider.js";
8
12
 
9
13
  export class CoreServiceProvider extends ServiceProvider {
10
14
  readonly name = PROVIDER_NAMES.CORE;
11
15
 
12
16
  register(): void {
13
- this.app.set<MarkerService>("Marker", app<MarkerService>(MarkerService), true);
14
17
  this.app.set<StoreService>("Store", StoreService.instance(), true);
15
18
  this.app.set<StoreService>("Storage", StoreService.instance(), true);
16
19
  this.app.set<EventService>("Event", EventService.instance(), true);
17
20
  this.app.set<HttpService>("Http", HttpService.instance(), true);
21
+ this.app.set<MarkerRegistryInterface>("Registry", MarkerRegistry, true);
22
+ this.app.set<HeadServiceInterface>("Head", HeadService, true);
23
+ this.app.set("Devtools", Devtools, true);
18
24
  }
19
25
  }
@@ -1,12 +1,17 @@
1
- import { HelperService } from "../../services/HelperService";
2
- import { PROVIDER_NAMES } from "./provider-order";
3
- import { ServiceProvider } from "./ServiceProvider";
1
+ import { HelperService } from "../../services/HelperService.js";
2
+ import { PROVIDER_NAMES } from "./provider-order.js";
3
+ import { ServiceProvider } from "./ServiceProvider.js";
4
4
 
5
5
  export class HelperServiceProvider extends ServiceProvider {
6
6
  readonly name = PROVIDER_NAMES.HELPER;
7
7
  readonly dependsOn = [PROVIDER_NAMES.CORE, PROVIDER_NAMES.ROUTER, PROVIDER_NAMES.VIEW];
8
8
 
9
+ static config: Record<string, any> = {};
10
+
9
11
  register(): void {
10
12
  this.app.set<HelperService>("Helper", new HelperService(this.app), true);
11
13
  }
14
+ boot(): void {
15
+ if (HelperServiceProvider.config.i18n) this.app.get<HelperService>("Helper").initTranslations(HelperServiceProvider.config.i18n);
16
+ }
12
17
  }
@@ -1,9 +1,11 @@
1
- import { Router } from "../../routers";
2
- import { PROVIDER_NAMES } from "./provider-order";
3
- import { ServiceProvider } from "./ServiceProvider";
1
+ import { Router } from "../../routers/index.js";
2
+ import { ViewManager } from "../../view/index.js";
3
+ import { PROVIDER_NAMES } from "./provider-order.js";
4
+ import { ServiceProvider } from "./ServiceProvider.js";
4
5
 
5
6
  export class RouteServiceProvider extends ServiceProvider {
6
7
  readonly name = PROVIDER_NAMES.ROUTER;
8
+ /** ROUTER phải boot SAU VIEW để ViewManager đã sẵn sàng */
7
9
  readonly dependsOn = [PROVIDER_NAMES.VIEW];
8
10
  static config: Record<string, any> = {};
9
11
 
@@ -12,6 +14,15 @@ export class RouteServiceProvider extends ServiceProvider {
12
14
  }
13
15
 
14
16
  boot(): void {
15
- this.app.get<Router>("Router").init(RouteServiceProvider.config);
17
+ const router = this.app.get<Router>("Router");
18
+
19
+ // Wire ViewManager → Router (Router cần để mountView khi navigate)
20
+ try {
21
+ const vm = this.app.get<ViewManager>("View");
22
+ if (vm) router.setViewManager(vm);
23
+ } catch (_) { /* View chưa register — Router sẽ fallback qua App.View */ }
24
+
25
+ // init: load routes config + auto-wire
26
+ router.init(RouteServiceProvider.config);
16
27
  }
17
28
  }
@@ -1,8 +1,8 @@
1
- import { ApplicationInterface } from "../../contracts/ApplicationInterface";
2
- import { ServiceProviderInterface } from "../../contracts/utils";
3
- import { app } from "../../hellpers/app";
4
- import { OneObjectType, OOTEnum } from "../../types/utils";
5
- import { NamedServiceProvider } from "./provider-order";
1
+ import { ApplicationInterface } from "../../contracts/ApplicationInterface.js";
2
+ import { ServiceProviderInterface } from "../../contracts/utils.js";
3
+ import { app } from "../../helpers/app.js";
4
+ import { SaoObjectType, OOTEnum } from "../../types/utils.js";
5
+ import { NamedServiceProvider } from "./provider-order.js";
6
6
 
7
7
  /**
8
8
  * Base class cho Service Provider — API giống Laravel.
@@ -27,7 +27,7 @@ import { NamedServiceProvider } from "./provider-order";
27
27
  * }
28
28
  */
29
29
  export abstract class ServiceProvider implements ServiceProviderInterface {
30
- readonly oneType: OneObjectType = OOTEnum.SERVICE_PROVIDER;
30
+ readonly saoType: SaoObjectType = OOTEnum.SERVICE_PROVIDER;
31
31
  abstract readonly name: string;
32
32
  readonly dependsOn?: string[];
33
33
  protected app: ApplicationInterface;
@@ -38,8 +38,8 @@ export abstract class ServiceProvider implements ServiceProviderInterface {
38
38
  }
39
39
 
40
40
  initApplication(App?: ApplicationInterface): void {
41
- if (!this.app || typeof this.app !== 'object' || this.app.oneType !== OOTEnum.APPLICATION) {
42
- this.app = (App && App.oneType === OOTEnum.APPLICATION) ? App : app<ApplicationInterface>();
41
+ if (!this.app || typeof this.app !== 'object' || this.app.saoType !== OOTEnum.APPLICATION) {
42
+ this.app = (App && App.saoType === OOTEnum.APPLICATION) ? App : app<ApplicationInterface>();
43
43
  }
44
44
  }
45
45
 
@@ -1,6 +1,6 @@
1
- import { ViewManager } from "../../view";
2
- import { PROVIDER_NAMES } from "./provider-order";
3
- import { ServiceProvider } from "./ServiceProvider";
1
+ import { ViewManager } from "../../view/index.js";
2
+ import { PROVIDER_NAMES } from "./provider-order.js";
3
+ import { ServiceProvider } from "./ServiceProvider.js";
4
4
 
5
5
  export class ViewServiceProvider extends ServiceProvider {
6
6
  readonly name = PROVIDER_NAMES.VIEW;
@@ -1,14 +1,14 @@
1
- import { ApplicationInterface } from "../../contracts/ApplicationInterface";
2
- import { app } from "../../hellpers/app";
3
- import { NamedServiceProvider, PROVIDER_NAMES } from "./provider-order";
4
- import { ApiServiceProvider } from "./ApiServiceProvider";
5
- import { CoreServiceProvider } from "./CoreServiceProvider";
6
- import { HelperServiceProvider } from "./HelperServiceProvider";
7
- import { RouteServiceProvider } from "./RouteServiceProvider";
8
- import { ServiceProvider } from "./ServiceProvider";
9
- import { ViewServiceProvider } from "./ViewServiceProvider";
10
- import { ServiceProviderInterface } from "../../contracts/ServiceProviderInterface";
11
- import { OOTEnum } from "../../types/utils";
1
+ import { ApplicationInterface } from "../../contracts/ApplicationInterface.js";
2
+ import { app } from "../../helpers/app.js";
3
+ import { NamedServiceProvider, PROVIDER_NAMES } from "./provider-order.js";
4
+ import { ApiServiceProvider } from "./ApiServiceProvider.js";
5
+ import { CoreServiceProvider } from "./CoreServiceProvider.js";
6
+ import { HelperServiceProvider } from "./HelperServiceProvider.js";
7
+ import { RouteServiceProvider } from "./RouteServiceProvider.js";
8
+ import { ServiceProvider } from "./ServiceProvider.js";
9
+ import { ViewServiceProvider } from "./ViewServiceProvider.js";
10
+ import { ServiceProviderInterface } from "../../contracts/ServiceProviderInterface.js";
11
+ import { OOTEnum } from "../../types/utils.js";
12
12
 
13
13
  /** Provider class type — constructor nhận optional app */
14
14
  type ProviderClass = new (app?: ApplicationInterface) => ServiceProvider;
@@ -17,7 +17,7 @@ type ProviderClass = new (app?: ApplicationInterface) => ServiceProvider;
17
17
  const SYSTEM_PROVIDER_NAMES = new Set(Object.values(PROVIDER_NAMES));
18
18
 
19
19
  /** Tên system services — không cho phép ghi đè qua config.services */
20
- const SYSTEM_SERVICE_KEYS = new Set(['Marker', 'Store', 'Storage', 'Event', 'Http', 'View', 'Router', 'Helper', 'API']);
20
+ const SYSTEM_SERVICE_KEYS = new Set(['Store', 'Storage', 'Event', 'Http', 'View', 'Router', 'Helper', 'API']);
21
21
 
22
22
  /**
23
23
  * Chuyển `config.services` dạng { name: Class } thành NamedServiceProvider[].
@@ -26,7 +26,7 @@ const SYSTEM_SERVICE_KEYS = new Set(['Marker', 'Store', 'Storage', 'Event', 'Htt
26
26
  * services: { Auth: AuthService, Toast: ToastService }
27
27
  * → 2 providers, mỗi cái dependsOn ['core'], register = app.set(name, new Class(app))
28
28
  */
29
- function servicesFromMap(map: Record<string, new (app: ApplicationInterface) => any>): ServiceProviderInterface[] {
29
+ function servicesFromMap(map: Record<string, any>): ServiceProviderInterface[] {
30
30
  const appInstance = app<ApplicationInterface>();
31
31
  return Object.entries(map)
32
32
  .filter(([name]) => {
@@ -36,15 +36,44 @@ function servicesFromMap(map: Record<string, new (app: ApplicationInterface) =>
36
36
  }
37
37
  return true;
38
38
  })
39
- .map(([name, ServiceClass]) => ({
39
+ .map(([name, value]) => ({
40
40
  name,
41
41
  dependsOn: [PROVIDER_NAMES.CORE],
42
42
  register() {
43
- appInstance.set(name, new ServiceClass(appInstance));
43
+ // Bundle nạp rời (theme) hay gửi INSTANCE hoặc object thuần chứ
44
+ // không phải class — `new` vô điều kiện sẽ ném "is not a
45
+ // constructor". Chỉ dựng khi thật sự là class.
46
+ const isClass = typeof value === 'function' && value.prototype;
47
+ appInstance.set(name, isClass ? new value(appInstance) : value);
44
48
  }
45
49
  }));
46
50
  }
47
51
 
52
+ /**
53
+ * `config.helpers` = { tên: fn } → MỘT provider gộp, phụ thuộc `helper`.
54
+ *
55
+ * Không gán tay sau `init()`: `App.Helper` chỉ tồn tại sau khi
56
+ * HelperServiceProvider register, nên phải để resolveProviderOrder xếp chỗ.
57
+ * Gán tay thì provider nào đọc helper trong boot() của mình sẽ nhận undefined.
58
+ */
59
+ function helpersFromMap(map: Record<string, any>): ServiceProviderInterface[] {
60
+ const appInstance = app<ApplicationInterface>();
61
+ if (!map || Object.keys(map).length === 0) return [];
62
+
63
+ return [{
64
+ name: 'bundle.helpers',
65
+ dependsOn: [PROVIDER_NAMES.HELPER],
66
+ register() {
67
+ const helper = appInstance.get<Record<string, any>>('Helper');
68
+ if (!helper) {
69
+ console.warn('[Bootstrap] Helper chưa sẵn sàng, bỏ qua config.helpers.');
70
+ return;
71
+ }
72
+ Object.assign(helper, map);
73
+ }
74
+ }];
75
+ }
76
+
48
77
  /**
49
78
  * Tạo danh sách providers mặc định.
50
79
  *
@@ -60,6 +89,7 @@ export function buildDefaultProviders(config: Record<string, any> = {}): NamedSe
60
89
  // Set static config cho default providers trước khi tạo instance
61
90
  ViewServiceProvider.config = config.view || {};
62
91
  RouteServiceProvider.config = config.router || {};
92
+ HelperServiceProvider.config = { i18n: config.i18n };
63
93
  ApiServiceProvider.config = config.api || {};
64
94
  const App = app<ApplicationInterface>();
65
95
  const defaults: NamedServiceProvider[] = [
@@ -75,6 +105,11 @@ export function buildDefaultProviders(config: Record<string, any> = {}): NamedSe
75
105
  ? servicesFromMap(config.services)
76
106
  : [];
77
107
 
108
+ // config.helpers: { tên: fn } → một provider phụ thuộc `helper`
109
+ const helperProviders = config.helpers
110
+ ? helpersFromMap(config.helpers)
111
+ : [];
112
+
78
113
  // config.providers: (ProviderClass | NamedServiceProvider)[] → instantiate classes
79
114
  const customProviders: NamedServiceProvider[] = Array.isArray(config.providers)
80
115
  ? config.providers
@@ -90,5 +125,5 @@ export function buildDefaultProviders(config: Record<string, any> = {}): NamedSe
90
125
  })
91
126
  : [];
92
127
 
93
- return [...defaults, ...serviceProviders, ...customProviders];
128
+ return [...defaults, ...serviceProviders, ...helperProviders, ...customProviders];
94
129
  }
@@ -1,9 +1,9 @@
1
- export { NamedServiceProvider, resolveProviderOrder, PROVIDER_NAMES } from './provider-order';
2
- export type { ProviderName } from './provider-order';
3
- export { ServiceProvider } from './ServiceProvider';
4
- export { buildDefaultProviders } from './default-providers';
5
- export { CoreServiceProvider } from './CoreServiceProvider';
6
- export { ViewServiceProvider } from './ViewServiceProvider';
7
- export { RouteServiceProvider } from './RouteServiceProvider';
8
- export { HelperServiceProvider } from './HelperServiceProvider';
9
- export { ApiServiceProvider } from './ApiServiceProvider';
1
+ export { NamedServiceProvider, resolveProviderOrder, PROVIDER_NAMES } from './provider-order.js';
2
+ export type { ProviderName } from './provider-order.js';
3
+ export { ServiceProvider } from './ServiceProvider.js';
4
+ export { buildDefaultProviders } from './default-providers.js';
5
+ export { CoreServiceProvider } from './CoreServiceProvider.js';
6
+ export { ViewServiceProvider } from './ViewServiceProvider.js';
7
+ export { RouteServiceProvider } from './RouteServiceProvider.js';
8
+ export { HelperServiceProvider } from './HelperServiceProvider.js';
9
+ export { ApiServiceProvider } from './ApiServiceProvider.js';