@saolabs/client 1.0.0 → 1.1.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 (383) 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 +25 -15
  9. package/dist/src/core/app/Application.d.ts.map +1 -1
  10. package/dist/src/core/app/Application.js +55 -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 +77 -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 +129 -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 +15 -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/helpers/ApiClient.d.ts.map +1 -0
  178. package/dist/src/core/{hellpers → helpers}/ApiClient.js +10 -1
  179. package/dist/src/core/helpers/ApiClient.js.map +1 -0
  180. package/dist/src/core/helpers/app.d.ts +3 -0
  181. package/dist/src/core/helpers/app.d.ts.map +1 -0
  182. package/dist/src/core/{hellpers → helpers}/app.js +11 -1
  183. package/dist/src/core/helpers/app.js.map +1 -0
  184. package/dist/src/core/helpers/transition.d.ts +34 -0
  185. package/dist/src/core/helpers/transition.d.ts.map +1 -0
  186. package/dist/src/core/helpers/transition.js +118 -0
  187. package/dist/src/core/helpers/transition.js.map +1 -0
  188. package/dist/src/core/{hellpers → helpers}/utils.d.ts +2 -2
  189. package/dist/src/core/helpers/utils.d.ts.map +1 -0
  190. package/dist/src/core/{hellpers → helpers}/utils.js +4 -4
  191. package/dist/src/core/helpers/utils.js.map +1 -0
  192. package/dist/src/core/helpers/view.d.ts +39 -0
  193. package/dist/src/core/helpers/view.d.ts.map +1 -0
  194. package/dist/src/core/helpers/view.js +286 -0
  195. package/dist/src/core/helpers/view.js.map +1 -0
  196. package/dist/src/core/routers/Router.d.ts +108 -7
  197. package/dist/src/core/routers/Router.d.ts.map +1 -1
  198. package/dist/src/core/routers/Router.js +444 -68
  199. package/dist/src/core/routers/Router.js.map +1 -1
  200. package/dist/src/core/routers/index.d.ts +2 -2
  201. package/dist/src/core/routers/index.d.ts.map +1 -1
  202. package/dist/src/core/routers/index.js +1 -1
  203. package/dist/src/core/routers/index.js.map +1 -1
  204. package/dist/src/core/services/AssetManager.d.ts +112 -0
  205. package/dist/src/core/services/AssetManager.d.ts.map +1 -0
  206. package/dist/src/core/services/AssetManager.js +361 -0
  207. package/dist/src/core/services/AssetManager.js.map +1 -0
  208. package/dist/src/core/services/BlockManager.d.ts +73 -2
  209. package/dist/src/core/services/BlockManager.d.ts.map +1 -1
  210. package/dist/src/core/services/BlockManager.js +270 -48
  211. package/dist/src/core/services/BlockManager.js.map +1 -1
  212. package/dist/src/core/services/DomService.js +3 -3
  213. package/dist/src/core/services/DomService.js.map +1 -1
  214. package/dist/src/core/services/HeadService.d.ts +24 -0
  215. package/dist/src/core/services/HeadService.d.ts.map +1 -0
  216. package/dist/src/core/services/HeadService.js +120 -0
  217. package/dist/src/core/services/HeadService.js.map +1 -0
  218. package/dist/src/core/services/HelperService.d.ts +14 -3
  219. package/dist/src/core/services/HelperService.d.ts.map +1 -1
  220. package/dist/src/core/services/HelperService.js +32 -2
  221. package/dist/src/core/services/HelperService.js.map +1 -1
  222. package/dist/src/core/services/HttpService.d.ts +8 -0
  223. package/dist/src/core/services/HttpService.d.ts.map +1 -1
  224. package/dist/src/core/services/HttpService.js +121 -47
  225. package/dist/src/core/services/HttpService.js.map +1 -1
  226. package/dist/src/core/services/MarkerRegistry.d.ts +51 -8
  227. package/dist/src/core/services/MarkerRegistry.d.ts.map +1 -1
  228. package/dist/src/core/services/MarkerRegistry.js +135 -14
  229. package/dist/src/core/services/MarkerRegistry.js.map +1 -1
  230. package/dist/src/core/services/PageCache.d.ts +101 -0
  231. package/dist/src/core/services/PageCache.d.ts.map +1 -0
  232. package/dist/src/core/services/PageCache.js +184 -0
  233. package/dist/src/core/services/PageCache.js.map +1 -0
  234. package/dist/src/core/services/SectionManager.d.ts +100 -0
  235. package/dist/src/core/services/SectionManager.d.ts.map +1 -0
  236. package/dist/src/core/services/SectionManager.js +408 -0
  237. package/dist/src/core/services/SectionManager.js.map +1 -0
  238. package/dist/src/core/services/StorageService.js +1 -1
  239. package/dist/src/core/services/TranslationService.d.ts +21 -0
  240. package/dist/src/core/services/TranslationService.d.ts.map +1 -0
  241. package/dist/src/core/services/TranslationService.js +95 -0
  242. package/dist/src/core/services/TranslationService.js.map +1 -0
  243. package/dist/src/core/services/index.d.ts +11 -8
  244. package/dist/src/core/services/index.d.ts.map +1 -1
  245. package/dist/src/core/services/index.js +11 -8
  246. package/dist/src/core/services/index.js.map +1 -1
  247. package/dist/src/core/types/utils.d.ts +8 -8
  248. package/dist/src/core/types/utils.d.ts.map +1 -1
  249. package/dist/src/core/view/LoopContext.d.ts +21 -1
  250. package/dist/src/core/view/LoopContext.d.ts.map +1 -1
  251. package/dist/src/core/view/LoopContext.js +36 -0
  252. package/dist/src/core/view/LoopContext.js.map +1 -1
  253. package/dist/src/core/view/ResourceScope.d.ts +38 -0
  254. package/dist/src/core/view/ResourceScope.d.ts.map +1 -0
  255. package/dist/src/core/view/ResourceScope.js +167 -0
  256. package/dist/src/core/view/ResourceScope.js.map +1 -0
  257. package/dist/src/core/view/Section.d.ts +17 -32
  258. package/dist/src/core/view/Section.d.ts.map +1 -1
  259. package/dist/src/core/view/Section.js +14 -55
  260. package/dist/src/core/view/Section.js.map +1 -1
  261. package/dist/src/core/view/View.d.ts +43 -7
  262. package/dist/src/core/view/View.d.ts.map +1 -1
  263. package/dist/src/core/view/View.js +22 -4
  264. package/dist/src/core/view/View.js.map +1 -1
  265. package/dist/src/core/view/ViewController.d.ts +313 -40
  266. package/dist/src/core/view/ViewController.d.ts.map +1 -1
  267. package/dist/src/core/view/ViewController.js +1002 -147
  268. package/dist/src/core/view/ViewController.js.map +1 -1
  269. package/dist/src/core/view/ViewManager.d.ts +318 -27
  270. package/dist/src/core/view/ViewManager.d.ts.map +1 -1
  271. package/dist/src/core/view/ViewManager.js +1199 -258
  272. package/dist/src/core/view/ViewManager.js.map +1 -1
  273. package/dist/src/core/view/ViewState.d.ts +185 -6
  274. package/dist/src/core/view/ViewState.d.ts.map +1 -1
  275. package/dist/src/core/view/ViewState.js +851 -123
  276. package/dist/src/core/view/ViewState.js.map +1 -1
  277. package/dist/src/core/view/index.d.ts +5 -5
  278. package/dist/src/core/view/index.d.ts.map +1 -1
  279. package/dist/src/core/view/index.js +5 -5
  280. package/dist/src/core/view/index.js.map +1 -1
  281. package/dist/src/testing/index.d.ts +69 -0
  282. package/dist/src/testing/index.d.ts.map +1 -0
  283. package/dist/src/testing/index.js +140 -0
  284. package/dist/src/testing/index.js.map +1 -0
  285. package/index.ts +29 -5
  286. package/package.json +30 -21
  287. package/plugins.ts +2 -2
  288. package/src/core/app/Application.ts +72 -31
  289. package/src/core/bootstrap/app.ts +84 -6
  290. package/src/core/bootstrap/bundle.ts +101 -0
  291. package/src/core/bootstrap/providers/ApiServiceProvider.ts +4 -4
  292. package/src/core/bootstrap/providers/CoreServiceProvider.ts +14 -8
  293. package/src/core/bootstrap/providers/HelperServiceProvider.ts +8 -3
  294. package/src/core/bootstrap/providers/RouteServiceProvider.ts +15 -4
  295. package/src/core/bootstrap/providers/ServiceProvider.ts +8 -8
  296. package/src/core/bootstrap/providers/ViewServiceProvider.ts +3 -3
  297. package/src/core/bootstrap/providers/default-providers.ts +51 -16
  298. package/src/core/bootstrap/providers/index.ts +9 -9
  299. package/src/core/bootstrap/providers/provider-order.test.ts +16 -27
  300. package/src/core/bootstrap/providers/provider-order.ts +1 -1
  301. package/src/core/bootstrap/ssr.ts +141 -0
  302. package/src/core/cache/ViewCache.ts +1 -1
  303. package/src/core/cache/index.ts +1 -1
  304. package/src/core/contracts/ApplicationInterface.ts +15 -11
  305. package/src/core/contracts/BlockInterface.ts +18 -18
  306. package/src/core/contracts/BundleInterface.ts +40 -0
  307. package/src/core/contracts/ComponentInterface.ts +7 -6
  308. package/src/core/contracts/ElementInterface.ts +95 -27
  309. package/src/core/contracts/HeadServiceInterface.ts +41 -0
  310. package/src/core/contracts/HelperInterface.ts +9 -1
  311. package/src/core/contracts/HttpServiceInterface.ts +3 -0
  312. package/src/core/contracts/MarkerInterface.ts +22 -49
  313. package/src/core/contracts/ReactiveInterface.ts +9 -9
  314. package/src/core/contracts/RouterInterface.ts +5 -2
  315. package/src/core/contracts/SectionInterface.ts +49 -0
  316. package/src/core/contracts/ServiceProviderInterface.ts +3 -3
  317. package/src/core/contracts/ViewControllerInterface.ts +124 -16
  318. package/src/core/contracts/ViewInterface.ts +34 -5
  319. package/src/core/contracts/ViewManagerInterface.ts +40 -5
  320. package/src/core/contracts/ViewStateInterface.ts +39 -2
  321. package/src/core/contracts/common.ts +3 -3
  322. package/src/core/contracts/utils.ts +19 -19
  323. package/src/core/contracts/views.ts +2 -22
  324. package/src/core/devtools/hook.ts +142 -0
  325. package/src/core/devtools/index.ts +38 -0
  326. package/src/core/devtools/inspector.ts +270 -0
  327. package/src/core/elements/Block.ts +43 -21
  328. package/src/core/elements/BlockOutlet.ts +61 -21
  329. package/src/core/elements/Component.ts +352 -18
  330. package/src/core/elements/ElementManager.ts +9 -9
  331. package/src/core/elements/ForeachSlotCache.ts +170 -0
  332. package/src/core/elements/Fragment.ts +50 -32
  333. package/src/core/elements/Html.ts +696 -117
  334. package/src/core/elements/Output.ts +147 -30
  335. package/src/core/elements/Reactive.ts +329 -52
  336. package/src/core/elements/TextElement.ts +25 -16
  337. package/src/core/elements/Wrapper.ts +84 -18
  338. package/src/core/elements/Yield.ts +35 -24
  339. package/src/core/elements/helpers.ts +12 -12
  340. package/src/core/elements/index.ts +25 -24
  341. package/src/core/elements/reconcileChildren.ts +70 -0
  342. package/src/core/{hellpers → helpers}/ApiClient.ts +8 -1
  343. package/src/core/{hellpers → helpers}/app.ts +13 -2
  344. package/src/core/helpers/transition.ts +127 -0
  345. package/src/core/{hellpers → helpers}/utils.ts +4 -4
  346. package/src/core/helpers/view.ts +283 -0
  347. package/src/core/routers/Router.ts +458 -64
  348. package/src/core/routers/index.ts +2 -2
  349. package/src/core/services/AssetManager.ts +387 -0
  350. package/src/core/services/BlockManager.ts +272 -50
  351. package/src/core/services/DomService.ts +3 -3
  352. package/src/core/services/HeadService.ts +124 -0
  353. package/src/core/services/HelperService.ts +34 -4
  354. package/src/core/services/HttpService.ts +116 -55
  355. package/src/core/services/MarkerRegistry.ts +142 -16
  356. package/src/core/services/PageCache.ts +239 -0
  357. package/src/core/services/SectionManager.ts +387 -0
  358. package/src/core/services/StorageService.ts +1 -1
  359. package/src/core/services/TranslationService.ts +91 -0
  360. package/src/core/services/index.ts +11 -8
  361. package/src/core/types/utils.ts +8 -8
  362. package/src/core/view/LoopContext.ts +38 -1
  363. package/src/core/view/ResourceScope.ts +174 -0
  364. package/src/core/view/Section.ts +21 -68
  365. package/src/core/view/View.ts +57 -8
  366. package/src/core/view/ViewController.ts +1070 -186
  367. package/src/core/view/ViewManager.ts +1346 -272
  368. package/src/core/view/ViewState.ts +834 -116
  369. package/src/core/view/index.ts +5 -5
  370. package/src/testing/index.ts +184 -0
  371. package/dist/src/core/hellpers/ApiClient.d.ts.map +0 -1
  372. package/dist/src/core/hellpers/ApiClient.js.map +0 -1
  373. package/dist/src/core/hellpers/app.d.ts +0 -3
  374. package/dist/src/core/hellpers/app.d.ts.map +0 -1
  375. package/dist/src/core/hellpers/app.js.map +0 -1
  376. package/dist/src/core/hellpers/utils.d.ts.map +0 -1
  377. package/dist/src/core/hellpers/utils.js.map +0 -1
  378. package/dist/src/core/services/MarkerService.d.ts +0 -299
  379. package/dist/src/core/services/MarkerService.d.ts.map +0 -1
  380. package/dist/src/core/services/MarkerService.js +0 -723
  381. package/dist/src/core/services/MarkerService.js.map +0 -1
  382. package/src/core/services/MarkerService.ts +0 -923
  383. /package/dist/src/core/{hellpers → helpers}/ApiClient.d.ts +0 -0
@@ -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>>();
@@ -94,10 +96,11 @@ export class Application implements ApplicationInterface {
94
96
  'destroy',
95
97
  'getBindings',
96
98
  'getSingletons',
99
+ 'shared',
97
100
  '__store',
98
101
  ]; // Để track dynamic properties nếu cần
99
102
 
100
- __store: Map<string, { isOverridable: boolean, value: any }> = new Map(); // Store cho dynamic properties nếu cần
103
+ __store: Map<any, { isOverridable: boolean, value: any }> = new Map(); // Store cho dynamic properties nếu cần
101
104
 
102
105
  [key: string]: any; // Cho phép dynamic properties nếu cần
103
106
 
@@ -179,6 +182,18 @@ export class Application implements ApplicationInterface {
179
182
  */
180
183
  instance<T>(key: ServiceKey<T>, value: T): this {
181
184
  this.singletons.set(key, value);
185
+ if (typeof key === 'string' && !this.ownProperties.includes(key)) {
186
+ this.__store.set(key, { value, isOverridable: true });
187
+ Object.defineProperty(this, key, {
188
+ get: () => this.__store.get(key)?.value,
189
+ set: (newValue) => {
190
+ this.__store.set(key, { value: newValue, isOverridable: true });
191
+ this.singletons.set(key, newValue);
192
+ },
193
+ configurable: true,
194
+ enumerable: false,
195
+ });
196
+ }
182
197
  return this;
183
198
  }
184
199
 
@@ -289,6 +304,15 @@ export class Application implements ApplicationInterface {
289
304
  (provider as any).initApplication();
290
305
  }
291
306
  provider.register();
307
+
308
+ // Đăng ký SAU khi app đã boot — plugin nạp muộn qua App.push(), hoặc
309
+ // provider của theme cắm vào giữa phiên. boot() vòng lặp chính đã chạy
310
+ // xong và có cờ chặn, nên nếu không gọi ở đây thì provider chỉ chạy nửa
311
+ // vòng đời: register() có, boot() không, và KHÔNG có lỗi nào phát ra.
312
+ if (this.booted && typeof provider.boot === 'function') {
313
+ provider.boot();
314
+ }
315
+
292
316
  return this;
293
317
  }
294
318
 
@@ -342,31 +366,35 @@ export class Application implements ApplicationInterface {
342
366
  }
343
367
 
344
368
 
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
- }
369
+ set<T = any>(name: any, value: T, isOne: boolean = false): void {
349
370
  if (this.__store.has(name) && this.__store.get(name)?.isOverridable === false) {
350
371
  return; // Không cho ghi đè lên thuộc tính không thể override
351
372
  }
373
+ const isString = typeof name === 'string';
374
+ if (isString && this.ownProperties.includes(name)) {
375
+ return; // Không cho ghi đè lên thuộc tính có sẵn
376
+ }
352
377
  this.__store.set(name, { value, isOverridable: !isOne });
353
378
  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
- });
379
+ if (isString) {
380
+ Object.defineProperty(this, name, {
381
+ get: () => this.__store.get(name)?.value,
382
+ set: (newValue) => {
383
+ if (this.__store.has(name) && this.__store.get(name)?.isOverridable === false) {
384
+ return; // Không cho ghi đè nếu isOverridable là false
385
+ }
386
+ this.__store.set(name, { value: newValue, isOverridable: !isOne });
387
+ this.singletons.set(name, newValue); // Sync → DI container
388
+ },
389
+ configurable: isOne ? false : true,
390
+ enumerable: false,
391
+ });
392
+ }
366
393
  }
367
394
 
368
- get<T = any>(name: string): T {
369
- if (this.ownProperties.includes(name)) {
395
+ get<T = any>(name: any): T {
396
+ const isString = typeof name === 'string';
397
+ if (isString && this.ownProperties.includes(name)) {
370
398
  return (this as any)[name]; // Trả về thuộc tính có sẵn
371
399
  }
372
400
  // Check __store first (registered via set())
@@ -380,6 +408,19 @@ export class Application implements ApplicationInterface {
380
408
  return undefined as T;
381
409
  }
382
410
 
411
+ /**
412
+ * Dữ liệu package PHP chia sẻ cho client theo từng request (`Saola::share()`
413
+ * → `APP_CONFIGS.shared` → `App.init({ shared })`). Helper JS của package đọc
414
+ * ở đây thay vì tự đọc `window`, để test truyền được qua config.
415
+ *
416
+ * @example App.shared('permission', { routes: [] }).routes
417
+ */
418
+ shared<T = any>(key?: string, fallback?: T): T {
419
+ const all = (this.__store.get('SharedData')?.value ?? {}) as Record<string, any>;
420
+ if (key === undefined) return all as T;
421
+ return (Object.prototype.hasOwnProperty.call(all, key) ? all[key] : fallback) as T;
422
+ }
423
+
383
424
  setMethod(name: string, method: Function, isOne: boolean = false): void {
384
425
  if (this.ownProperties.includes(name)) {
385
426
  return; // Không cho ghi đè lên thuộc tính có sẵn
@@ -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
  *
@@ -26,6 +64,10 @@ App.setMethod('init', function (config: Record<string, any> = {}) {
26
64
  return;
27
65
  }
28
66
 
67
+ if (config.shared && typeof config.shared === 'object') {
68
+ App.set<Record<string, any>>('SharedData', { ...config.shared });
69
+ }
70
+
29
71
  const providers = resolveProviderOrder(buildDefaultProviders(config));
30
72
  for (const provider of providers) {
31
73
  App.register(provider);
@@ -38,19 +80,55 @@ App.setMethod('init', function (config: Record<string, any> = {}) {
38
80
  /**
39
81
  * Start app — init nếu chưa, rồi start Router.
40
82
  *
83
+ * Nếu phát hiện SSR boot (script saola-ssr), inject vào config.view.ssr để
84
+ * ViewManager + Router hydrate route đầu tiên thay vì mount mới.
85
+ *
41
86
  * @example
42
87
  * App.start(); // init với config mặc định
43
88
  * App.start({ view: { container: '#app' } }); // init với config tùy chỉnh
44
89
  */
45
- App.setMethod('start', function (config?: Record<string, any>) {
90
+ App.setMethod('start', async function (config?: Record<string, any>) {
46
91
  if (App.isStarted) {
47
92
  console.warn('[Bootstrap] App already started.');
48
93
  return;
49
94
  }
95
+ let bundles: MergedBundles | null = null;
50
96
  if (!App.isInitialized) {
51
- App.init(config || {});
97
+ // Config app truyền có ưu tiên hơn boot config (window.APP_CONFIGS:
98
+ // routes + container từ server). Thiếu APP_CONFIGS → chỉ dùng config app.
99
+ const boot = readBootConfig() || {};
100
+ const cfg = mergeBootConfig(boot, config || {});
101
+
102
+ // SSR boot (script saola-ssr) → ssr + container cho hydrate route đầu.
103
+ const ssr = readSSRBoot();
104
+ if (ssr) {
105
+ cfg.view = {
106
+ ...(cfg.view || {}),
107
+ ssr: { view: ssr.view, viewId: ssr.viewId },
108
+ container: (cfg.view && cfg.view.container) || ssr.container,
109
+ };
110
+ }
111
+ // Bundle nạp rời (theme…): server phát danh sách URL trong
112
+ // APP_CONFIGS.bundles. Phải await TRƯỚC init để view/service/provider
113
+ // của chúng có mặt lúc provider boot và lúc render route đầu.
114
+ bundles = await loadBundles(cfg.bundles);
115
+ cfg.view = {
116
+ ...(cfg.view || {}),
117
+ // Bundle nạp sau ĐÈ registry của app — đúng ngữ nghĩa overlay theme.
118
+ registry: { ...(cfg.view?.registry || {}), ...bundles.views },
119
+ };
120
+ cfg.services = { ...(cfg.services || {}), ...bundles.services };
121
+ cfg.helpers = { ...(cfg.helpers || {}), ...bundles.helpers };
122
+ cfg.providers = [...(cfg.providers || []), ...bundles.providers];
123
+
124
+ App.init(cfg);
125
+ bootBundles(bundles, App);
52
126
  }
53
127
 
128
+ // Sau init (View/Router/Helper đã có), TRƯỚC khi render: chỗ duy nhất mà
129
+ // mã ngoài cắm vào được mà chắc chắn kịp.
130
+ drainPushQueue();
131
+
54
132
  App.get<Router>('Router').start();
55
133
  App.isStarted = true;
56
134
  }, 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
  }