@hkdigital/lib-core 0.3.9 → 0.3.11

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 (428) hide show
  1. package/README.md +149 -149
  2. package/dist/assets/autospuiten/car-paint-picker.d.ts +7 -7
  3. package/dist/assets/autospuiten/car-paint-picker.js +41 -41
  4. package/dist/assets/autospuiten/labels.js +7 -7
  5. package/dist/classes/data/IterableTree.d.ts +15 -24
  6. package/dist/classes/data/IterableTree.js +242 -243
  7. package/dist/classes/data/Selector.js +190 -190
  8. package/dist/classes/data/index.js +2 -2
  9. package/dist/classes/data/typedef.d.ts +8 -0
  10. package/dist/classes/data/typedef.js +9 -0
  11. package/dist/classes/event-emitter/EventEmitter.js +273 -275
  12. package/dist/classes/event-emitter/index.js +2 -2
  13. package/dist/classes/index.js +4 -4
  14. package/dist/classes/promise/HkPromise.d.ts +18 -17
  15. package/dist/classes/promise/HkPromise.js +384 -377
  16. package/dist/classes/promise/index.js +1 -1
  17. package/dist/classes/stores/SubscribersCount.js +107 -107
  18. package/dist/classes/stores/index.js +1 -1
  19. package/dist/classes/streams/LogTransformStream.js +19 -19
  20. package/dist/classes/streams/ServerEventsStore.d.ts +2 -3
  21. package/dist/classes/streams/ServerEventsStore.js +111 -110
  22. package/dist/classes/streams/TimeStampSource.js +26 -26
  23. package/dist/classes/streams/index.js +3 -3
  24. package/dist/classes/svelte/finite-state-machine/FiniteStateMachine.svelte.js +133 -133
  25. package/dist/classes/svelte/finite-state-machine/index.js +1 -1
  26. package/dist/classes/svelte/index.d.ts +0 -8
  27. package/dist/classes/svelte/index.js +11 -14
  28. package/dist/classes/svelte/loading-state-machine/LoadingStateMachine.svelte.js +109 -109
  29. package/dist/classes/svelte/loading-state-machine/constants.js +16 -16
  30. package/dist/classes/svelte/loading-state-machine/index.js +3 -3
  31. package/dist/config/README.md +196 -0
  32. package/dist/config/{imagetools-config.js → generators/imagetools.js} +189 -189
  33. package/dist/config/generators/vite.d.ts +47 -0
  34. package/dist/config/generators/vite.js +142 -0
  35. package/dist/config/imagetools.d.ts +72 -72
  36. package/dist/config/vite.d.ts +1 -0
  37. package/dist/config/vite.js +5 -0
  38. package/dist/constants/bases/index.js +13 -13
  39. package/dist/constants/http/headers.js +6 -6
  40. package/dist/constants/http/index.js +2 -2
  41. package/dist/constants/http/methods.js +14 -14
  42. package/dist/constants/index.js +6 -6
  43. package/dist/constants/mime/application.js +5 -5
  44. package/dist/constants/mime/audio.js +13 -13
  45. package/dist/constants/mime/image.js +3 -3
  46. package/dist/constants/mime/index.js +4 -4
  47. package/dist/constants/mime/text.js +2 -2
  48. package/dist/constants/regexp/README.md +95 -0
  49. package/dist/constants/regexp/index.d.ts +1 -1
  50. package/dist/constants/regexp/index.js +31 -31
  51. package/dist/constants/regexp/inspiratie.js__ +95 -95
  52. package/dist/constants/regexp/text.d.ts +3 -3
  53. package/dist/constants/regexp/text.js +49 -49
  54. package/dist/constants/regexp/url.d.ts +1 -0
  55. package/dist/constants/regexp/url.js +3 -0
  56. package/dist/constants/regexp/user.d.ts +0 -1
  57. package/dist/constants/regexp/user.js +29 -33
  58. package/dist/constants/states/drag.js +6 -6
  59. package/dist/constants/states/drop.js +6 -6
  60. package/dist/constants/states/index.js +4 -4
  61. package/dist/constants/states/input.js +11 -11
  62. package/dist/constants/states/submit.js +4 -4
  63. package/dist/constants/time/index.js +28 -28
  64. package/dist/css/utilities.css +43 -43
  65. package/dist/design/README.md +405 -0
  66. package/dist/design/{design-config.js → config/design-config.js} +73 -73
  67. package/dist/{util/design-system/tailwind.js → design/generators/index.js} +288 -288
  68. package/dist/design/index.d.ts +8 -0
  69. package/dist/design/index.js +97 -0
  70. package/dist/{util/design-system → design/plugins}/skeleton.js +208 -208
  71. package/dist/design/tailwind-theme-extend.js +158 -158
  72. package/dist/design/themes/README.md +103 -0
  73. package/dist/{themes → design/themes}/hkdev/components/blocks/text-block.css +34 -34
  74. package/dist/{themes → design/themes}/hkdev/components/boxes/game-box.css +11 -11
  75. package/dist/{themes → design/themes}/hkdev/components/buttons/button-icon-steeze.css +22 -22
  76. package/dist/{themes → design/themes}/hkdev/components/buttons/button-text.css +32 -32
  77. package/dist/{themes → design/themes}/hkdev/components/buttons/button.css +146 -146
  78. package/dist/{themes → design/themes}/hkdev/components/buttons/skip-button.css +5 -5
  79. package/dist/{themes → design/themes}/hkdev/components/drag-drop/draggable.css +73 -73
  80. package/dist/{themes → design/themes}/hkdev/components/drag-drop/drop-zone.css +58 -58
  81. package/dist/{themes → design/themes}/hkdev/components/icons/icon-steeze.css +15 -15
  82. package/dist/{themes → design/themes}/hkdev/components/inputs/text-input.css +102 -102
  83. package/dist/{themes → design/themes}/hkdev/components/panels/panel.css +25 -25
  84. package/dist/{themes → design/themes}/hkdev/components/rows/panel-grid-row.css +4 -4
  85. package/dist/{themes → design/themes}/hkdev/components/rows/panel-row-2.css +5 -5
  86. package/dist/{themes → design/themes}/hkdev/components.css +29 -29
  87. package/dist/design/themes/hkdev/debug.css +2 -0
  88. package/dist/{themes → design/themes}/hkdev/global/layout.css +32 -32
  89. package/dist/{themes → design/themes}/hkdev/global/on-colors.css +32 -32
  90. package/dist/{themes → design/themes}/hkdev/globals.css +3 -3
  91. package/dist/{themes → design/themes}/hkdev/responsive.css +12 -12
  92. package/dist/{themes → design/themes}/hkdev/theme-ext.js +12 -12
  93. package/dist/{themes → design/themes}/hkdev/theme.css +218 -218
  94. package/dist/{util/design-system/css → design/utils}/clamp.js +66 -66
  95. package/dist/{util/design-system/css/root-design-vars.d.ts → design/utils/root-vars.d.ts} +2 -2
  96. package/dist/{util/design-system/css/root-design-vars.js → design/utils/root-vars.js} +102 -102
  97. package/dist/{util/design-system/layout → design/utils}/scaling.js +228 -228
  98. package/dist/{util/design-system/components → design/utils}/states.js +22 -22
  99. package/dist/errors/api.js +9 -9
  100. package/dist/errors/generic.js +20 -20
  101. package/dist/errors/http.js +16 -16
  102. package/dist/errors/index.d.ts +1 -0
  103. package/dist/errors/index.js +5 -4
  104. package/dist/errors/jwt.js +5 -5
  105. package/dist/errors/promise.d.ts +27 -0
  106. package/dist/errors/promise.js +26 -0
  107. package/dist/logging/index.js +7 -7
  108. package/dist/logging/internal/adapters/console.js +114 -114
  109. package/dist/logging/internal/adapters/index.js +2 -2
  110. package/dist/logging/internal/adapters/pino.d.ts +1 -0
  111. package/dist/logging/internal/adapters/pino.js +142 -115
  112. package/dist/logging/internal/adapters/typedef.d.ts +24 -0
  113. package/dist/logging/internal/adapters/typedef.js +10 -0
  114. package/dist/logging/internal/factories/client.js +21 -21
  115. package/dist/logging/internal/factories/server.js +22 -22
  116. package/dist/logging/internal/factories/universal.js +22 -22
  117. package/dist/logging/internal/unified-logger/Logger.js +217 -217
  118. package/dist/logging/internal/unified-logger/constants.js +22 -22
  119. package/dist/logging/internal/unified-logger/index.js +6 -6
  120. package/dist/logging/internal/unified-logger/typedef.js +17 -17
  121. package/dist/network/README.md +173 -0
  122. package/dist/{classes → network}/cache/IndexedDbCache.js +1407 -1407
  123. package/dist/{classes → network}/cache/MemoryResponseCache.js +138 -138
  124. package/dist/{classes → network}/cache/index.js +5 -5
  125. package/dist/{classes → network}/cache/typedef.js +41 -41
  126. package/dist/network/cache.d.ts +3 -0
  127. package/dist/network/cache.js +4 -0
  128. package/dist/{util → network}/http/caching.js +261 -263
  129. package/dist/{util → network}/http/errors.js +97 -97
  130. package/dist/{util → network}/http/headers.js +75 -75
  131. package/dist/{util → network}/http/http-request.js +578 -578
  132. package/dist/{util → network}/http/index.js +22 -22
  133. package/dist/{util → network}/http/json-request.js +224 -224
  134. package/dist/{util → network}/http/mocks.js +65 -65
  135. package/dist/{util → network}/http/response.js +318 -318
  136. package/dist/{util → network}/http/typedef.js +93 -93
  137. package/dist/{util → network}/http/url.js +52 -52
  138. package/dist/network/http.d.ts +6 -0
  139. package/dist/network/http.js +6 -0
  140. package/dist/network/loaders/README.md +255 -0
  141. package/dist/{classes/svelte → network/loaders}/audio/AudioLoader.svelte.d.ts +1 -1
  142. package/dist/{classes/svelte → network/loaders}/audio/AudioLoader.svelte.js +58 -58
  143. package/dist/{classes/svelte → network/loaders}/audio/AudioScene.svelte.js +324 -324
  144. package/dist/{classes/svelte → network/loaders}/audio/mocks.js +35 -35
  145. package/dist/network/loaders/audio.d.ts +2 -0
  146. package/dist/network/loaders/audio.js +2 -0
  147. package/dist/{classes/svelte → network/loaders}/image/ImageLoader.svelte.d.ts +3 -6
  148. package/dist/{classes/svelte → network/loaders}/image/ImageLoader.svelte.js +44 -45
  149. package/dist/{classes/svelte → network/loaders}/image/ImageScene.svelte.d.ts +5 -7
  150. package/dist/{classes/svelte → network/loaders}/image/ImageScene.svelte.js +248 -249
  151. package/dist/{classes/svelte → network/loaders}/image/ImageVariantsLoader.svelte.d.ts +4 -4
  152. package/dist/{classes/svelte → network/loaders}/image/ImageVariantsLoader.svelte.js +150 -152
  153. package/dist/{classes/svelte → network/loaders}/image/index.js +4 -4
  154. package/dist/{classes/svelte → network/loaders}/image/mocks.js +35 -35
  155. package/dist/{classes/svelte → network/loaders}/image/typedef.js +8 -8
  156. package/dist/{util/image → network/loaders/image/utils}/index.d.ts +2 -2
  157. package/dist/{util/image → network/loaders/image/utils}/index.js +86 -86
  158. package/dist/network/loaders/image.d.ts +5 -0
  159. package/dist/network/loaders/image.js +8 -0
  160. package/dist/{typedef/image.js → network/loaders/typedef.js} +38 -38
  161. package/dist/network/loaders.d.ts +2 -0
  162. package/dist/network/loaders.js +2 -0
  163. package/dist/{classes/svelte/network-loader → network/states}/NetworkLoader.svelte.d.ts +1 -1
  164. package/dist/{classes/svelte/network-loader → network/states}/NetworkLoader.svelte.js +338 -338
  165. package/dist/{classes/svelte/network-loader → network/states}/constants.js +3 -3
  166. package/dist/{classes/svelte/network-loader → network/states}/index.js +3 -3
  167. package/dist/{classes/svelte/network-loader → network/states}/mocks.js +30 -30
  168. package/dist/{classes/svelte/network-loader → network/states}/typedef.js +8 -8
  169. package/dist/network/typedef.d.ts +4 -0
  170. package/dist/network/typedef.js +10 -0
  171. package/dist/services/index.js +1 -1
  172. package/dist/services/internal/index.js +8 -8
  173. package/dist/services/internal/service-base/ServiceBase.js +462 -462
  174. package/dist/services/internal/service-base/constants.js +110 -110
  175. package/dist/services/internal/service-base/index.js +3 -3
  176. package/dist/services/internal/service-base/typedef.js +101 -101
  177. package/dist/services/internal/service-manager/ServiceManager.d.ts +2 -35
  178. package/dist/services/internal/service-manager/ServiceManager.js +608 -614
  179. package/dist/services/internal/service-manager/constants.js +6 -6
  180. package/dist/services/internal/service-manager/typedef.js +90 -90
  181. package/dist/states/index.js +1 -1
  182. package/dist/states/navigation.svelte.js +55 -55
  183. package/dist/stores/index.js +1 -1
  184. package/dist/stores/theme.js +80 -80
  185. package/dist/typedef/context.js +6 -6
  186. package/dist/typedef/drag.js +25 -25
  187. package/dist/typedef/drop.js +12 -12
  188. package/dist/typedef/index.d.ts +0 -1
  189. package/dist/typedef/index.js +4 -4
  190. package/dist/{components → ui/components}/button-group/ButtonGroup.svelte +82 -82
  191. package/dist/{components → ui/components}/button-group/typedef.js +10 -10
  192. package/dist/{components → ui/components}/compare-left-right/CompareLeftRight.svelte +179 -179
  193. package/dist/{components → ui/components}/compare-left-right/index.js +1 -1
  194. package/dist/{components → ui/components}/game-box/GameBox.svelte +577 -577
  195. package/dist/{components → ui/components}/game-box/gamebox.util.js +83 -83
  196. package/dist/ui/components/hk-app-layout/HkAppLayout.state.svelte.d.ts +6 -0
  197. package/dist/{components → ui/components}/hk-app-layout/HkAppLayout.state.svelte.js +25 -25
  198. package/dist/{components → ui/components}/hk-app-layout/HkAppLayout.svelte +251 -251
  199. package/dist/{components → ui/components}/image-box/ImageBox.svelte +210 -210
  200. package/dist/{components → ui/components}/image-box/ImageBox.svelte.d.ts +6 -6
  201. package/dist/ui/components/image-box/index.js +5 -0
  202. package/dist/{components → ui/components}/image-box/typedef.js +32 -32
  203. package/dist/{components → ui/components}/index.js +23 -23
  204. package/dist/{components → ui/components}/presenter/ImageSlide.svelte +64 -64
  205. package/dist/{components → ui/components}/presenter/ImageSlide.svelte.d.ts +2 -2
  206. package/dist/{components → ui/components}/presenter/Presenter.state.svelte.d.ts +1 -1
  207. package/dist/{components → ui/components}/presenter/Presenter.state.svelte.js +638 -638
  208. package/dist/{components → ui/components}/presenter/Presenter.svelte +142 -142
  209. package/dist/{components → ui/components}/presenter/constants.js +7 -7
  210. package/dist/{components → ui/components}/presenter/index.js +10 -10
  211. package/dist/{components → ui/components}/presenter/typedef.js +106 -106
  212. package/dist/{components → ui/components}/presenter/util.js +210 -210
  213. package/dist/{components → ui/components}/virtual-viewport/VirtualViewport.svelte +196 -196
  214. package/dist/{primitives → ui/primitives}/area/HkArea.svelte +49 -49
  215. package/dist/{primitives → ui/primitives}/area/HkGridArea.svelte +77 -77
  216. package/dist/{primitives → ui/primitives}/area/index.js +2 -2
  217. package/dist/{primitives → ui/primitives}/buttons/button/Button.svelte +82 -82
  218. package/dist/{primitives → ui/primitives}/buttons/button/Button.svelte.d.ts +1 -1
  219. package/dist/{primitives → ui/primitives}/buttons/button-icon-steeze/SteezeIconButton.svelte +30 -30
  220. package/dist/{primitives → ui/primitives}/buttons/button-text/TextButton.svelte +21 -21
  221. package/dist/{primitives → ui/primitives}/buttons/index.js +3 -3
  222. package/dist/{primitives → ui/primitives}/debug/debug-panel-design-scaling/DebugPanelDesignScaling.svelte +146 -146
  223. package/dist/{primitives → ui/primitives}/debug/index.js +1 -1
  224. package/dist/{primitives → ui/primitives}/drag-drop/DragController.js +44 -44
  225. package/dist/{primitives → ui/primitives}/drag-drop/DragDropContext.svelte +111 -111
  226. package/dist/{primitives → ui/primitives}/drag-drop/DragDropContext.svelte.d.ts +1 -1
  227. package/dist/{primitives → ui/primitives}/drag-drop/Draggable.svelte +519 -519
  228. package/dist/{primitives → ui/primitives}/drag-drop/Draggable.svelte.d.ts +1 -1
  229. package/dist/{primitives → ui/primitives}/drag-drop/DropZone.svelte +258 -258
  230. package/dist/{primitives → ui/primitives}/drag-drop/DropZone.svelte.d.ts +3 -3
  231. package/dist/{primitives → ui/primitives}/drag-drop/DropZoneArea.svelte +119 -119
  232. package/dist/{primitives → ui/primitives}/drag-drop/DropZoneArea.svelte.d.ts +3 -3
  233. package/dist/{primitives → ui/primitives}/drag-drop/DropZoneList.svelte +125 -125
  234. package/dist/{primitives → ui/primitives}/drag-drop/DropZoneList.svelte.d.ts +3 -3
  235. package/dist/{primitives → ui/primitives}/drag-drop/actions.js +26 -26
  236. package/dist/{primitives → ui/primitives}/drag-drop/drag-state.svelte.d.ts +11 -11
  237. package/dist/{primitives → ui/primitives}/drag-drop/drag-state.svelte.js +322 -322
  238. package/dist/{primitives → ui/primitives}/drag-drop/index.js +7 -7
  239. package/dist/{primitives → ui/primitives}/drag-drop/util.js +85 -85
  240. package/dist/{primitives → ui/primitives}/hkdev/blocks/TextBlock.svelte +46 -46
  241. package/dist/{primitives → ui/primitives}/hkdev/buttons/CheckButton.svelte +62 -62
  242. package/dist/{primitives → ui/primitives}/icons/HkIcon.svelte +86 -86
  243. package/dist/{primitives → ui/primitives}/icons/HkTabIcon.svelte +116 -116
  244. package/dist/{primitives → ui/primitives}/icons/SteezeIcon.svelte +97 -97
  245. package/dist/{primitives → ui/primitives}/icons/index.js +6 -6
  246. package/dist/{primitives → ui/primitives}/icons/typedef.js +16 -16
  247. package/dist/{primitives → ui/primitives}/index.js +2 -2
  248. package/dist/{primitives → ui/primitives}/inputs/index.js +1 -1
  249. package/dist/{primitives → ui/primitives}/inputs/text-input/TextInput.svelte +223 -223
  250. package/dist/{primitives → ui/primitives}/inputs/text-input/assets/IconInvalid.svelte +14 -14
  251. package/dist/{primitives → ui/primitives}/inputs/text-input/assets/IconValid.svelte +12 -12
  252. package/dist/{primitives → ui/primitives}/layout/grid-layers/GridLayers.svelte +63 -63
  253. package/dist/{primitives → ui/primitives}/layout/grid-layers/util.js +74 -74
  254. package/dist/{primitives → ui/primitives}/layout/index.js +1 -1
  255. package/dist/{primitives → ui/primitives}/panels/index.js +1 -1
  256. package/dist/{primitives → ui/primitives}/panels/panel/Panel.svelte +43 -43
  257. package/dist/{primitives → ui/primitives}/rows/index.js +3 -3
  258. package/dist/{primitives → ui/primitives}/rows/panel-grid-row/PanelGridRow.svelte +104 -104
  259. package/dist/{primitives → ui/primitives}/rows/panel-row-2/PanelRow2.svelte +40 -40
  260. package/dist/{primitives → ui/primitives}/tab-bar/HkTabBar.state.svelte.d.ts +3 -3
  261. package/dist/{primitives → ui/primitives}/tab-bar/HkTabBar.state.svelte.js +149 -149
  262. package/dist/{primitives → ui/primitives}/tab-bar/HkTabBar.svelte +74 -74
  263. package/dist/{primitives → ui/primitives}/tab-bar/HkTabBarSelector.state.svelte.d.ts +3 -3
  264. package/dist/{primitives → ui/primitives}/tab-bar/HkTabBarSelector.state.svelte.js +93 -93
  265. package/dist/{primitives → ui/primitives}/tab-bar/HkTabBarSelector.svelte +49 -49
  266. package/dist/{primitives → ui/primitives}/tab-bar/index.js +17 -17
  267. package/dist/{primitives → ui/primitives}/tab-bar/typedef.js +11 -11
  268. package/dist/util/array/index.js +436 -436
  269. package/dist/util/bases/base58.js +262 -262
  270. package/dist/util/bases/index.js +1 -1
  271. package/dist/util/compare/index.js +247 -247
  272. package/dist/util/css/css-vars.js +83 -83
  273. package/dist/util/css/index.js +1 -1
  274. package/dist/util/env/index.js +9 -9
  275. package/dist/util/exceptions/index.js +23 -23
  276. package/dist/util/expect/arrays.js +47 -47
  277. package/dist/util/expect/index.js +259 -259
  278. package/dist/util/expect/primitives.js +55 -55
  279. package/dist/util/expect/url.d.ts +6 -6
  280. package/dist/util/expect/url.js +60 -60
  281. package/dist/util/function/index.js +218 -218
  282. package/dist/util/geo/index.js +26 -26
  283. package/dist/util/index.d.ts +3 -1
  284. package/dist/util/index.js +7 -3
  285. package/dist/util/is/index.d.ts +15 -14
  286. package/dist/util/is/index.js +147 -140
  287. package/dist/util/iterate/index.d.ts +37 -69
  288. package/dist/util/iterate/index.js +204 -234
  289. package/dist/util/object/index.d.ts +38 -57
  290. package/dist/util/object/index.js +1345 -1361
  291. package/dist/util/singleton/index.js +97 -97
  292. package/dist/util/string/array-path.js +75 -75
  293. package/dist/util/string/convert.js +54 -54
  294. package/dist/util/string/fs.js +226 -226
  295. package/dist/util/string/index.js +5 -5
  296. package/dist/util/string/interpolate.js +61 -61
  297. package/dist/util/string/pad.js +10 -10
  298. package/dist/util/svelte/index.js +4 -4
  299. package/dist/util/svelte/loading/loading-tracker.svelte.js +108 -108
  300. package/dist/util/svelte/observe/index.js +49 -49
  301. package/dist/util/svelte/state-context/index.js +117 -117
  302. package/dist/util/svelte/wait/index.js +38 -38
  303. package/dist/util/sveltekit/index.js +1 -1
  304. package/dist/util/sveltekit/route-folders/index.js +101 -101
  305. package/dist/util/time/index.js +328 -323
  306. package/dist/util/unique/index.js +231 -249
  307. package/dist/valibot/README.md +50 -0
  308. package/dist/valibot/index.d.ts +4 -4
  309. package/dist/valibot/index.js +8 -9
  310. package/dist/valibot/{url.d.ts → parsers/url.d.ts} +13 -5
  311. package/dist/valibot/{url.js → parsers/url.js} +111 -95
  312. package/dist/valibot/{user.js → parsers/user.js} +23 -23
  313. package/dist/valibot/parsers.d.ts +2 -0
  314. package/dist/valibot/parsers.js +4 -0
  315. package/package.json +131 -133
  316. package/dist/components/hk-app-layout/HkAppLayout.state.svelte.d.ts +0 -6
  317. package/dist/components/image-box/index.js +0 -5
  318. package/dist/constants/regexp/web.d.ts +0 -1
  319. package/dist/constants/regexp/web.js +0 -3
  320. package/dist/primitives/inputs/text-input/TestTextInput.svelte__ +0 -102
  321. package/dist/primitives/inputs/text-input/TextInput.svelte___ +0 -83
  322. package/dist/primitives/layout/grid-layers/GridLayers.svelte__heightFrom__ +0 -372
  323. package/dist/schemas/index.d.ts +0 -1
  324. package/dist/schemas/index.js +0 -1
  325. package/dist/schemas/validate-url.d.ts +0 -30
  326. package/dist/schemas/validate-url.js +0 -180
  327. package/dist/themes/hkdev/debug.css +0 -2
  328. package/dist/themes/index.d.ts +0 -1
  329. package/dist/themes/index.js +0 -1
  330. package/dist/util/design-system/index.d.ts +0 -5
  331. package/dist/util/design-system/index.js +0 -5
  332. package/dist/util/http/test-data__/content-length-test-hkdigital-small.V4HfZyBQ.avif +0 -0
  333. package/dist/valibot/date.js__ +0 -10
  334. package/dist/zod/all.d.ts +0 -6
  335. package/dist/zod/all.js +0 -33
  336. package/dist/zod/generic.d.ts +0 -6
  337. package/dist/zod/generic.js +0 -11
  338. package/dist/zod/javascript.d.ts +0 -8
  339. package/dist/zod/javascript.js +0 -32
  340. package/dist/zod/user.d.ts +0 -9
  341. package/dist/zod/user.js +0 -16
  342. package/dist/zod/web.d.ts +0 -21
  343. package/dist/zod/web.js +0 -52
  344. /package/dist/config/{imagetools-config.d.ts → generators/imagetools.d.ts} +0 -0
  345. /package/dist/design/{design-config.d.ts → config/design-config.d.ts} +0 -0
  346. /package/dist/{util/design-system/tailwind.d.ts → design/generators/index.d.ts} +0 -0
  347. /package/dist/{util/design-system → design/plugins}/skeleton.d.ts +0 -0
  348. /package/dist/{themes → design/themes}/hkdev/theme-ext.d.ts +0 -0
  349. /package/dist/{util/design-system/css → design/utils}/clamp.d.ts +0 -0
  350. /package/dist/{util/design-system/layout → design/utils}/scaling.d.ts +0 -0
  351. /package/dist/{util/design-system/components → design/utils}/states.d.ts +0 -0
  352. /package/dist/{classes → network}/cache/IndexedDbCache.d.ts +0 -0
  353. /package/dist/{classes → network}/cache/MemoryResponseCache.d.ts +0 -0
  354. /package/dist/{classes → network}/cache/index.d.ts +0 -0
  355. /package/dist/{classes → network}/cache/typedef.d.ts +0 -0
  356. /package/dist/{util → network}/http/caching.d.ts +0 -0
  357. /package/dist/{util → network}/http/errors.d.ts +0 -0
  358. /package/dist/{util → network}/http/headers.d.ts +0 -0
  359. /package/dist/{util → network}/http/http-request.d.ts +0 -0
  360. /package/dist/{util → network}/http/index.d.ts +0 -0
  361. /package/dist/{util → network}/http/json-request.d.ts +0 -0
  362. /package/dist/{util → network}/http/mocks.d.ts +0 -0
  363. /package/dist/{util → network}/http/response.d.ts +0 -0
  364. /package/dist/{util → network}/http/typedef.d.ts +0 -0
  365. /package/dist/{util → network}/http/url.d.ts +0 -0
  366. /package/dist/{classes/svelte → network/loaders}/audio/AudioScene.svelte.d.ts +0 -0
  367. /package/dist/{classes/svelte → network/loaders}/audio/mocks.d.ts +0 -0
  368. /package/dist/{classes/svelte → network/loaders}/image/index.d.ts +0 -0
  369. /package/dist/{classes/svelte → network/loaders}/image/mocks.d.ts +0 -0
  370. /package/dist/{classes/svelte → network/loaders}/image/typedef.d.ts +0 -0
  371. /package/dist/{typedef/image.d.ts → network/loaders/typedef.d.ts} +0 -0
  372. /package/dist/{classes/svelte/network-loader → network/states}/constants.d.ts +0 -0
  373. /package/dist/{classes/svelte/network-loader → network/states}/index.d.ts +0 -0
  374. /package/dist/{classes/svelte/network-loader → network/states}/mocks.d.ts +0 -0
  375. /package/dist/{classes/svelte/network-loader → network/states}/typedef.d.ts +0 -0
  376. /package/dist/{components → ui/components}/button-group/ButtonGroup.svelte.d.ts +0 -0
  377. /package/dist/{components → ui/components}/button-group/typedef.d.ts +0 -0
  378. /package/dist/{components → ui/components}/compare-left-right/CompareLeftRight.svelte.d.ts +0 -0
  379. /package/dist/{components → ui/components}/compare-left-right/index.d.ts +0 -0
  380. /package/dist/{components → ui/components}/game-box/GameBox.svelte.d.ts +0 -0
  381. /package/dist/{components → ui/components}/game-box/gamebox.util.d.ts +0 -0
  382. /package/dist/{components → ui/components}/hk-app-layout/HkAppLayout.svelte.d.ts +0 -0
  383. /package/dist/{components → ui/components}/image-box/index.d.ts +0 -0
  384. /package/dist/{components → ui/components}/image-box/typedef.d.ts +0 -0
  385. /package/dist/{components → ui/components}/index.d.ts +0 -0
  386. /package/dist/{components → ui/components}/presenter/Presenter.svelte.d.ts +0 -0
  387. /package/dist/{components → ui/components}/presenter/constants.d.ts +0 -0
  388. /package/dist/{components → ui/components}/presenter/index.d.ts +0 -0
  389. /package/dist/{components → ui/components}/presenter/typedef.d.ts +0 -0
  390. /package/dist/{components → ui/components}/presenter/util.d.ts +0 -0
  391. /package/dist/{components → ui/components}/virtual-viewport/VirtualViewport.svelte.d.ts +0 -0
  392. /package/dist/{primitives → ui/primitives}/area/HkArea.svelte.d.ts +0 -0
  393. /package/dist/{primitives → ui/primitives}/area/HkGridArea.svelte.d.ts +0 -0
  394. /package/dist/{primitives → ui/primitives}/area/index.d.ts +0 -0
  395. /package/dist/{primitives → ui/primitives}/buttons/button-icon-steeze/SteezeIconButton.svelte.d.ts +0 -0
  396. /package/dist/{primitives → ui/primitives}/buttons/button-text/TextButton.svelte.d.ts +0 -0
  397. /package/dist/{primitives → ui/primitives}/buttons/index.d.ts +0 -0
  398. /package/dist/{primitives → ui/primitives}/debug/debug-panel-design-scaling/DebugPanelDesignScaling.svelte.d.ts +0 -0
  399. /package/dist/{primitives → ui/primitives}/debug/index.d.ts +0 -0
  400. /package/dist/{primitives → ui/primitives}/drag-drop/DragController.d.ts +0 -0
  401. /package/dist/{primitives → ui/primitives}/drag-drop/actions.d.ts +0 -0
  402. /package/dist/{primitives → ui/primitives}/drag-drop/index.d.ts +0 -0
  403. /package/dist/{primitives → ui/primitives}/drag-drop/util.d.ts +0 -0
  404. /package/dist/{primitives → ui/primitives}/hkdev/blocks/TextBlock.svelte.d.ts +0 -0
  405. /package/dist/{primitives → ui/primitives}/hkdev/buttons/CheckButton.svelte.d.ts +0 -0
  406. /package/dist/{primitives → ui/primitives}/icons/HkIcon.svelte.d.ts +0 -0
  407. /package/dist/{primitives → ui/primitives}/icons/HkTabIcon.svelte.d.ts +0 -0
  408. /package/dist/{primitives → ui/primitives}/icons/SteezeIcon.svelte.d.ts +0 -0
  409. /package/dist/{primitives → ui/primitives}/icons/index.d.ts +0 -0
  410. /package/dist/{primitives → ui/primitives}/icons/typedef.d.ts +0 -0
  411. /package/dist/{primitives → ui/primitives}/index.d.ts +0 -0
  412. /package/dist/{primitives → ui/primitives}/inputs/index.d.ts +0 -0
  413. /package/dist/{primitives → ui/primitives}/inputs/text-input/TextInput.svelte.d.ts +0 -0
  414. /package/dist/{primitives → ui/primitives}/inputs/text-input/assets/IconInvalid.svelte.d.ts +0 -0
  415. /package/dist/{primitives → ui/primitives}/inputs/text-input/assets/IconValid.svelte.d.ts +0 -0
  416. /package/dist/{primitives → ui/primitives}/layout/grid-layers/GridLayers.svelte.d.ts +0 -0
  417. /package/dist/{primitives → ui/primitives}/layout/grid-layers/util.d.ts +0 -0
  418. /package/dist/{primitives → ui/primitives}/layout/index.d.ts +0 -0
  419. /package/dist/{primitives → ui/primitives}/panels/index.d.ts +0 -0
  420. /package/dist/{primitives → ui/primitives}/panels/panel/Panel.svelte.d.ts +0 -0
  421. /package/dist/{primitives → ui/primitives}/rows/index.d.ts +0 -0
  422. /package/dist/{primitives → ui/primitives}/rows/panel-grid-row/PanelGridRow.svelte.d.ts +0 -0
  423. /package/dist/{primitives → ui/primitives}/rows/panel-row-2/PanelRow2.svelte.d.ts +0 -0
  424. /package/dist/{primitives → ui/primitives}/tab-bar/HkTabBar.svelte.d.ts +0 -0
  425. /package/dist/{primitives → ui/primitives}/tab-bar/HkTabBarSelector.svelte.d.ts +0 -0
  426. /package/dist/{primitives → ui/primitives}/tab-bar/index.d.ts +0 -0
  427. /package/dist/{primitives → ui/primitives}/tab-bar/typedef.d.ts +0 -0
  428. /package/dist/valibot/{user.d.ts → parsers/user.d.ts} +0 -0
@@ -1,614 +1,608 @@
1
- /**
2
- * @fileoverview Service Manager for coordinating service lifecycle,
3
- * dependencies, and health monitoring.
4
- *
5
- * The ServiceManager handles registration, dependency resolution, startup
6
- * orchestration, and coordinated shutdown of services. It provides centralized
7
- * logging control and health monitoring for all registered services.
8
- *
9
- * @example
10
- * // Basic usage
11
- * import { ServiceManager } from './ServiceManager.js';
12
- * import DatabaseService from './services/DatabaseService.js';
13
- * import AuthService from './services/AuthService.js';
14
- *
15
- * const manager = new ServiceManager({
16
- * debug: true,
17
- * stopTimeout: 10000
18
- * });
19
- *
20
- * // Register services with dependencies
21
- * manager.register('database', DatabaseService, {
22
- * connectionString: 'postgres://localhost/myapp'
23
- * });
24
- *
25
- * manager.register('auth', AuthService, {
26
- * secret: process.env.JWT_SECRET
27
- * }, {
28
- * dependencies: ['database'] // auth depends on database
29
- * });
30
- *
31
- * // Start all services
32
- * await manager.startAll();
33
- *
34
- * @example
35
- * // Advanced usage with health monitoring
36
- * manager.on('service:healthChanged', ({ service, healthy }) => {
37
- * if (!healthy) {
38
- * console.error(`Service ${service} became unhealthy`);
39
- * }
40
- * });
41
- *
42
- * // Check health of all services
43
- * const health = await manager.checkHealth();
44
- * console.log('System health:', health);
45
- *
46
- * // Recover failed service
47
- * manager.on('service:error', async ({ service }) => {
48
- * console.log(`Attempting to recover ${service}`);
49
- * await manager.recoverService(service);
50
- * });
51
- *
52
- * @example
53
- * // Logging control
54
- * // Set global log level
55
- * manager.setLogLevel('*', 'DEBUG');
56
- *
57
- * // Set specific service log level
58
- * manager.setLogLevel('database', 'ERROR');
59
- *
60
- * // Listen to all service logs
61
- * manager.on('service:log', (logEvent) => {
62
- * writeToLogFile(logEvent);
63
- * });
64
- */
65
-
66
- import { EventEmitter } from '../../../classes/event-emitter';
67
- import { Logger, DEBUG, INFO, WARN } from '../../../logging/index.js';
68
-
69
- import {
70
- NOT_CREATED,
71
- CREATED,
72
- RUNNING,
73
- DESTROYED
74
- } from '../service-base/constants.js';
75
-
76
- /**
77
- * @typedef {import('./typedef.js').ServiceConstructor} ServiceConstructor
78
- * @typedef {import('./typedef.js').ServiceRegistrationOptions} ServiceRegistrationOptions
79
- * @typedef {import('./typedef.js').ServiceManagerConfig} ServiceManagerConfig
80
- * @typedef {import('./typedef.js').ServiceEntry} ServiceEntry
81
- * @typedef {import('./typedef.js').HealthCheckResult} HealthCheckResult
82
- *
83
- * @typedef {import('../service-base/typedef.js').StopOptions} StopOptions
84
- */
85
-
86
- /**
87
- * Service Manager for lifecycle and dependency management
88
- * @extends EventEmitter
89
- */
90
- export class ServiceManager extends EventEmitter {
91
- /**
92
- * Create a new ServiceManager instance
93
- *
94
- * @param {ServiceManagerConfig} [config={}] - Manager configuration
95
- */
96
- constructor(config = {}) {
97
- super();
98
-
99
- /** @type {Map<string, ServiceEntry>} */
100
- this.services = new Map();
101
-
102
- /** @type {Logger} */
103
- this.logger = new Logger('ServiceManager', config.logLevel || INFO);
104
-
105
- /** @type {ServiceManagerConfig} */
106
- this.config = {
107
- debug: config.debug ?? false,
108
- autoStart: config.autoStart ?? false,
109
- stopTimeout: config.stopTimeout || 10000,
110
- logConfig: config.logConfig || {}
111
- };
112
-
113
- this._setupLogging();
114
- }
115
-
116
- /**
117
- * Register a service class with the manager
118
- *
119
- * @param {string} name - Unique service identifier
120
- * @param {ServiceConstructor} ServiceClass - Service class constructor
121
- * @param {*} [config={}] - Service configuration
122
- * @param {ServiceRegistrationOptions} [options={}] - Registration options
123
- *
124
- * @throws {Error} If service name is already registered
125
- */
126
- register(name, ServiceClass, config = {}, options = {}) {
127
- if (this.services.has(name)) {
128
- throw new Error(`Service '${name}' already registered`);
129
- }
130
-
131
- /** @type {ServiceEntry} */
132
- const entry = {
133
- ServiceClass,
134
- instance: null,
135
- config,
136
- dependencies: options.dependencies || [],
137
- dependents: new Set(),
138
- tags: options.tags || [],
139
- priority: options.priority || 0
140
- };
141
-
142
- // Track dependents
143
- entry.dependencies.forEach(dep => {
144
- const depEntry = this.services.get(dep);
145
- if (depEntry) {
146
- depEntry.dependents.add(name);
147
- }
148
- });
149
-
150
- this.services.set(name, entry);
151
-
152
- this.logger.debug(`Registered service '${name}'`, {
153
- dependencies: entry.dependencies,
154
- tags: entry.tags
155
- });
156
- }
157
-
158
- /**
159
- * Get or create a service instance
160
- *
161
- * @param {string} name - Service name
162
- *
163
- * @returns {import('./typedef.js').ServiceInstance|null}
164
- * Service instance or null if not found
165
- */
166
- get(name) {
167
- const entry = this.services.get(name);
168
- if (!entry) {
169
- this.logger.warn(`Service '${name}' not found`);
170
- return null;
171
- }
172
-
173
- if (!entry.instance) {
174
- try {
175
- entry.instance = new entry.ServiceClass(name);
176
-
177
- // Apply log level
178
- const logLevel = this._getServiceLogLevel(name);
179
- if (logLevel) {
180
- entry.instance.setLogLevel(logLevel);
181
- }
182
-
183
- // Forward events
184
- this._attachServiceEvents(name, entry.instance);
185
-
186
- this.logger.debug(`Created instance for '${name}'`);
187
- } catch (error) {
188
- this.logger.error(`Failed to create instance for '${name}'`, error);
189
- return null;
190
- }
191
- }
192
-
193
- return entry.instance;
194
- }
195
-
196
- /**
197
- * Initialize a service
198
- *
199
- * @param {string} name - Service name
200
- *
201
- * @returns {Promise<boolean>} True if initialization succeeded
202
- */
203
- async initService(name) {
204
- const instance = this.get(name);
205
- if (!instance) return false;
206
-
207
- const entry = this.services.get(name);
208
- return await instance.initialize(entry.config);
209
- }
210
-
211
- /**
212
- * Start a service and its dependencies
213
- *
214
- * @param {string} name - Service name
215
- *
216
- * @returns {Promise<boolean>} True if service started successfully
217
- */
218
- async startService(name) {
219
- const entry = this.services.get(name);
220
- if (!entry) {
221
- this.logger.warn(`Cannot start unregistered service '${name}'`);
222
- return false;
223
- }
224
-
225
- // Start dependencies first
226
- for (const dep of entry.dependencies) {
227
- if (!await this.isRunning(dep)) {
228
-
229
- this.logger.debug(`Starting dependency '${dep}' for '${name}'`);
230
-
231
- const started = await this.startService(dep);
232
- if (!started) {
233
- this.logger.error(
234
- `Failed to start dependency '${dep}' for '${name}'`
235
- );
236
- return false;
237
- }
238
- }
239
- }
240
-
241
- const instance = this.get(name);
242
- if (!instance) return false;
243
-
244
- // Initialize if needed
245
- if (instance.state === CREATED || instance.state === DESTROYED) {
246
- const initialized = await this.initService(name);
247
- if (!initialized) return false;
248
- }
249
-
250
- return await instance.start();
251
- }
252
-
253
- /**
254
- * Stop a service
255
- *
256
- * @param {string} name - Service name
257
- * @param {StopOptions} [options={}] - Stop options
258
- *
259
- * @returns {Promise<boolean>} True if service stopped successfully
260
- */
261
- async stopService(name, options = {}) {
262
- const instance = this.get(name);
263
- if (!instance) {
264
- this.logger.warn(`Cannot stop unregistered service '${name}'`);
265
- return true; // Already stopped
266
- }
267
-
268
- // Check dependents
269
- const entry = this.services.get(name);
270
- if (!options.force && entry && entry.dependents.size > 0) {
271
- const runningDependents = [];
272
- for (const dep of entry.dependents) {
273
- if (await this.isRunning(dep)) {
274
- runningDependents.push(dep);
275
- }
276
- }
277
-
278
- if (runningDependents.length > 0) {
279
- this.logger.warn(
280
- `Cannot stop '${name}' - required by: ${runningDependents.join(', ')}`
281
- );
282
- return false;
283
- }
284
- }
285
-
286
- return await instance.stop(options);
287
- }
288
-
289
- /**
290
- * Recover a service from error state
291
- *
292
- * @param {string} name - Service name
293
- *
294
- * @returns {Promise<boolean>} True if recovery succeeded
295
- */
296
- async recoverService(name) {
297
- const instance = this.get(name);
298
- if (!instance) return false;
299
-
300
- return await instance.recover();
301
- }
302
-
303
- /**
304
- * Start all registered services in dependency order
305
- *
306
- * @returns {Promise<Object<string, boolean>>} Map of service results
307
- */
308
- async startAll() {
309
- this.logger.info('Starting all services');
310
-
311
- // Sort by priority and dependencies
312
- const sorted = this._topologicalSort();
313
- const results = new Map();
314
-
315
- for (const name of sorted) {
316
- const success = await this.startService(name);
317
- results.set(name, success);
318
-
319
- if (!success) {
320
- this.logger.error(`Failed to start '${name}', stopping`);
321
- // Mark remaining services as not started
322
- for (const remaining of sorted) {
323
- if (!results.has(remaining)) {
324
- results.set(remaining, false);
325
- }
326
- }
327
- break;
328
- }
329
- }
330
-
331
- return Object.fromEntries(results);
332
- }
333
-
334
- /**
335
- * Stop all services in reverse dependency order
336
- *
337
- * @param {StopOptions} [options={}] - Stop options
338
- *
339
- * @returns {Promise<Object<string, boolean>>} Map of service results
340
- */
341
- async stopAll(options = {}) {
342
- this.logger.info('Stopping all services');
343
-
344
- const stopOptions = {
345
- timeout: options.timeout || this.config.stopTimeout,
346
- force: options.force || false
347
- };
348
-
349
- // Stop in reverse order
350
- const sorted = this._topologicalSort().reverse();
351
- const results = new Map();
352
-
353
- // Handle global timeout if specified
354
- if (stopOptions.timeout > 0) {
355
- const timeoutPromise = new Promise((_, reject) =>
356
- setTimeout(
357
- () => reject(new Error('Global shutdown timeout')),
358
- stopOptions.timeout
359
- )
360
- );
361
-
362
- try {
363
- // Race between stopping all services and timeout
364
- await Promise.race([
365
- this._stopAllSequentially(sorted, results, stopOptions),
366
- timeoutPromise
367
- ]);
368
- } catch (error) {
369
- if (error.message === 'Global shutdown timeout') {
370
- this.logger.error('Global shutdown timeout reached');
371
- // Mark any remaining services as failed
372
- for (const name of sorted) {
373
- if (!results.has(name)) {
374
- results.set(name, false);
375
- }
376
- }
377
- } else {
378
- throw error;
379
- }
380
- }
381
- } else {
382
- // No timeout, just stop sequentially
383
- await this._stopAllSequentially(sorted, results, stopOptions);
384
- }
385
-
386
- return Object.fromEntries(results);
387
- }
388
-
389
- /**
390
- * Stop services sequentially
391
- *
392
- * @private
393
- * @param {string[]} serviceNames - Ordered list of service names
394
- * @param {Map<string, boolean>} results - Results map to populate
395
- * @param {StopOptions} options - Stop options
396
- */
397
- async _stopAllSequentially(serviceNames, results, options) {
398
- for (const name of serviceNames) {
399
- try {
400
- const success = await this.stopService(name, options);
401
- results.set(name, success);
402
- } catch (error) {
403
- this.logger.error(`Error stopping '${name}'`, error);
404
- results.set(name, false);
405
- }
406
- }
407
- }
408
-
409
- /**
410
- * Get health status for all services
411
- *
412
- * @returns {Promise<HealthCheckResult>} Health status for all services
413
- */
414
- async checkHealth() {
415
- /** @type {HealthCheckResult} */
416
- const health = {};
417
-
418
- for (const [name, entry] of this.services) {
419
- if (entry.instance) {
420
- health[name] = await entry.instance.getHealth();
421
- } else {
422
- health[name] = {
423
- name,
424
- state: NOT_CREATED,
425
- healthy: false
426
- };
427
- }
428
- }
429
-
430
- return health;
431
- }
432
-
433
- /**
434
- * Check if a service is currently running
435
- *
436
- * @param {string} name - Service name
437
- *
438
- * @returns {Promise<boolean>} True if service is running
439
- */
440
- async isRunning(name) {
441
- const instance = this.get(name);
442
- return instance ? instance.state === RUNNING : false;
443
- }
444
-
445
- /**
446
- * Set log level for a service or globally
447
- *
448
- * @param {string} name - Service name or '*' for global
449
- * @param {string} level - Log level to set
450
- */
451
- setLogLevel(name, level) {
452
- if (name === '*') {
453
- // Global level
454
- this.config.logConfig.globalLevel = level;
455
-
456
- // Apply to all existing services
457
- // eslint-disable-next-line no-unused-vars
458
- for (const [_, entry] of this.services) {
459
- if (entry.instance) {
460
- entry.instance.setLogLevel(level);
461
- }
462
- }
463
- } else {
464
- // Service-specific level
465
- if (!this.config.logConfig.serviceLevels) {
466
- this.config.logConfig.serviceLevels = {};
467
- }
468
- this.config.logConfig.serviceLevels[name] = level;
469
-
470
- // Apply to existing instance
471
- const instance = this.get(name);
472
- if (instance) {
473
- instance.setLogLevel(level);
474
- }
475
- }
476
- }
477
-
478
- /**
479
- * Get all services with a specific tag
480
- *
481
- * @param {string} tag - Tag to filter by
482
- *
483
- * @returns {string[]} Array of service names
484
- */
485
- getServicesByTag(tag) {
486
- const services = [];
487
- for (const [name, entry] of this.services) {
488
- if (entry.tags.includes(tag)) {
489
- services.push(name);
490
- }
491
- }
492
- return services;
493
- }
494
-
495
- // Private methods
496
-
497
- /**
498
- * Setup logging configuration based on config.dev
499
- *
500
- * @private
501
- */
502
- _setupLogging() {
503
- // Set default log levels based on config.debug flag
504
- if (this.config.debug) {
505
- this.config.logConfig.defaultLevel = DEBUG;
506
- } else {
507
- this.config.logConfig.defaultLevel = WARN;
508
- }
509
-
510
- // Apply config
511
- if (this.config.logConfig.globalLevel) {
512
- this.logger.setLevel(this.config.logConfig.globalLevel);
513
- }
514
- }
515
-
516
- /**
517
- * Get the appropriate log level for a service
518
- *
519
- * @private
520
- * @param {string} name - Service name
521
- *
522
- * @returns {string|undefined} Log level or undefined
523
- */
524
- _getServiceLogLevel(name) {
525
- const config = this.config.logConfig;
526
-
527
- // Check in order of precedence:
528
- // 1. Global level (overrides everything)
529
- if (config.globalLevel) {
530
- return config.globalLevel;
531
- }
532
-
533
- // 2. Service-specific level
534
- if (config.serviceLevels?.[name]) {
535
- return config.serviceLevels[name];
536
- }
537
-
538
- // 3. Don't use defaultLevel as it might be too restrictive
539
- // Return undefined to let the service use its own default
540
- return undefined;
541
- }
542
-
543
- /**
544
- * Attach event listeners to forward service events
545
- *
546
- * @private
547
- * @param {string} name - Service name
548
- * @param {import('../service-base/typedef.js').ServiceInstance} instance
549
- * Service instance
550
- */
551
- _attachServiceEvents(name, instance) {
552
- // Forward service events
553
- instance.on('stateChanged', (data) => {
554
- this.emit('service:stateChanged', { service: name, data });
555
- });
556
-
557
- instance.on('healthChanged', (data) => {
558
- this.emit('service:healthChanged', { service: name, data });
559
- });
560
-
561
- instance.on('error', (data) => {
562
- this.emit('service:error', { service: name, data });
563
- });
564
-
565
- // Forward log events
566
-
567
- instance.logger.on('log', (logEvent) => {
568
- this.emit('service:log', logEvent);
569
- });
570
- }
571
-
572
- /**
573
- * Sort services by dependencies using topological sort
574
- *
575
- * @private
576
- *
577
- * @returns {string[]} Service names in dependency order
578
- * @throws {Error} If circular dependencies are detected
579
- */
580
- _topologicalSort() {
581
- const sorted = [];
582
- const visited = new Set();
583
- const visiting = new Set();
584
-
585
- const visit = (name) => {
586
- if (visited.has(name)) return;
587
- if (visiting.has(name)) {
588
- throw new Error(`Circular dependency detected involving '${name}'`);
589
- }
590
-
591
- visiting.add(name);
592
-
593
- const entry = this.services.get(name);
594
- if (entry) {
595
- for (const dep of entry.dependencies) {
596
- visit(dep);
597
- }
598
- }
599
-
600
- visiting.delete(name);
601
- visited.add(name);
602
- sorted.push(name);
603
- };
604
-
605
- // Visit all services
606
- for (const name of this.services.keys()) {
607
- visit(name);
608
- }
609
-
610
- return sorted;
611
- }
612
- }
613
-
614
- export default ServiceManager;
1
+ /**
2
+ * @fileoverview Service Manager for coordinating service lifecycle,
3
+ * dependencies, and health monitoring.
4
+ *
5
+ * The ServiceManager handles registration, dependency resolution, startup
6
+ * orchestration, and coordinated shutdown of services. It provides centralized
7
+ * logging control and health monitoring for all registered services.
8
+ *
9
+ * @example
10
+ * // Basic usage
11
+ * import { ServiceManager } from './ServiceManager.js';
12
+ * import DatabaseService from './services/DatabaseService.js';
13
+ * import AuthService from './services/AuthService.js';
14
+ *
15
+ * const manager = new ServiceManager({
16
+ * debug: true,
17
+ * stopTimeout: 10000
18
+ * });
19
+ *
20
+ * // Register services with dependencies
21
+ * manager.register('database', DatabaseService, {
22
+ * connectionString: 'postgres://localhost/myapp'
23
+ * });
24
+ *
25
+ * manager.register('auth', AuthService, {
26
+ * secret: process.env.JWT_SECRET
27
+ * }, {
28
+ * dependencies: ['database'] // auth depends on database
29
+ * });
30
+ *
31
+ * // Start all services
32
+ * await manager.startAll();
33
+ *
34
+ * @example
35
+ * // Advanced usage with health monitoring
36
+ * manager.on('service:healthChanged', ({ service, healthy }) => {
37
+ * if (!healthy) {
38
+ * console.error(`Service ${service} became unhealthy`);
39
+ * }
40
+ * });
41
+ *
42
+ * // Check health of all services
43
+ * const health = await manager.checkHealth();
44
+ * console.log('System health:', health);
45
+ *
46
+ * // Recover failed service
47
+ * manager.on('service:error', async ({ service }) => {
48
+ * console.log(`Attempting to recover ${service}`);
49
+ * await manager.recoverService(service);
50
+ * });
51
+ *
52
+ * @example
53
+ * // Logging control
54
+ * // Set global log level
55
+ * manager.setLogLevel('*', 'DEBUG');
56
+ *
57
+ * // Set specific service log level
58
+ * manager.setLogLevel('database', 'ERROR');
59
+ *
60
+ * // Listen to all service logs
61
+ * manager.on('service:log', (logEvent) => {
62
+ * writeToLogFile(logEvent);
63
+ * });
64
+ */
65
+
66
+ import { EventEmitter } from '../../../classes/event-emitter';
67
+ import { Logger, DEBUG, INFO, WARN } from '../../../logging/index.js';
68
+
69
+ import {
70
+ NOT_CREATED,
71
+ CREATED,
72
+ RUNNING,
73
+ DESTROYED
74
+ } from '../service-base/constants.js';
75
+
76
+ /**
77
+ * @typedef {import('./typedef.js').ServiceConstructor} ServiceConstructor
78
+ * @typedef {import('./typedef.js').ServiceRegistrationOptions} ServiceRegistrationOptions
79
+ * @typedef {import('./typedef.js').ServiceManagerConfig} ServiceManagerConfig
80
+ * @typedef {import('./typedef.js').ServiceEntry} ServiceEntry
81
+ * @typedef {import('./typedef.js').HealthCheckResult} HealthCheckResult
82
+ *
83
+ * @typedef {import('../service-base/typedef.js').StopOptions} StopOptions
84
+ */
85
+
86
+ /**
87
+ * Service Manager for lifecycle and dependency management
88
+ * @extends EventEmitter
89
+ */
90
+ export class ServiceManager extends EventEmitter {
91
+ /**
92
+ * Create a new ServiceManager instance
93
+ *
94
+ * @param {ServiceManagerConfig} [config={}] - Manager configuration
95
+ */
96
+ constructor(config = {}) {
97
+ super();
98
+
99
+ /** @type {Map<string, ServiceEntry>} */
100
+ this.services = new Map();
101
+
102
+ /** @type {Logger} */
103
+ this.logger = new Logger('ServiceManager', config.logLevel || INFO);
104
+
105
+ /** @type {ServiceManagerConfig} */
106
+ this.config = {
107
+ debug: config.debug ?? false,
108
+ autoStart: config.autoStart ?? false,
109
+ stopTimeout: config.stopTimeout || 10000,
110
+ logConfig: config.logConfig || {}
111
+ };
112
+
113
+ this.#setupLogging();
114
+ }
115
+
116
+ /**
117
+ * Register a service class with the manager
118
+ *
119
+ * @param {string} name - Unique service identifier
120
+ * @param {ServiceConstructor} ServiceClass - Service class constructor
121
+ * @param {*} [config={}] - Service configuration
122
+ * @param {ServiceRegistrationOptions} [options={}] - Registration options
123
+ *
124
+ * @throws {Error} If service name is already registered
125
+ */
126
+ register(name, ServiceClass, config = {}, options = {}) {
127
+ if (this.services.has(name)) {
128
+ throw new Error(`Service '${name}' already registered`);
129
+ }
130
+
131
+ /** @type {ServiceEntry} */
132
+ const entry = {
133
+ ServiceClass,
134
+ instance: null,
135
+ config,
136
+ dependencies: options.dependencies || [],
137
+ dependents: new Set(),
138
+ tags: options.tags || [],
139
+ priority: options.priority || 0
140
+ };
141
+
142
+ // Track dependents
143
+ entry.dependencies.forEach((dep) => {
144
+ const depEntry = this.services.get(dep);
145
+ if (depEntry) {
146
+ depEntry.dependents.add(name);
147
+ }
148
+ });
149
+
150
+ this.services.set(name, entry);
151
+
152
+ this.logger.debug(`Registered service '${name}'`, {
153
+ dependencies: entry.dependencies,
154
+ tags: entry.tags
155
+ });
156
+ }
157
+
158
+ /**
159
+ * Get or create a service instance
160
+ *
161
+ * @param {string} name - Service name
162
+ *
163
+ * @returns {import('./typedef.js').ServiceInstance|null}
164
+ * Service instance or null if not found
165
+ */
166
+ get(name) {
167
+ const entry = this.services.get(name);
168
+ if (!entry) {
169
+ this.logger.warn(`Service '${name}' not found`);
170
+ return null;
171
+ }
172
+
173
+ if (!entry.instance) {
174
+ try {
175
+ entry.instance = new entry.ServiceClass(name);
176
+
177
+ // Apply log level
178
+ const logLevel = this.#getServiceLogLevel(name);
179
+ if (logLevel) {
180
+ entry.instance.setLogLevel(logLevel);
181
+ }
182
+
183
+ // Forward events
184
+ this._attachServiceEvents(name, entry.instance);
185
+
186
+ this.logger.debug(`Created instance for '${name}'`);
187
+ } catch (error) {
188
+ this.logger.error(`Failed to create instance for '${name}'`, error);
189
+ return null;
190
+ }
191
+ }
192
+
193
+ return entry.instance;
194
+ }
195
+
196
+ /**
197
+ * Initialize a service
198
+ *
199
+ * @param {string} name - Service name
200
+ *
201
+ * @returns {Promise<boolean>} True if initialization succeeded
202
+ */
203
+ async initService(name) {
204
+ const instance = this.get(name);
205
+ if (!instance) return false;
206
+
207
+ const entry = this.services.get(name);
208
+ return await instance.initialize(entry.config);
209
+ }
210
+
211
+ /**
212
+ * Start a service and its dependencies
213
+ *
214
+ * @param {string} name - Service name
215
+ *
216
+ * @returns {Promise<boolean>} True if service started successfully
217
+ */
218
+ async startService(name) {
219
+ const entry = this.services.get(name);
220
+ if (!entry) {
221
+ this.logger.warn(`Cannot start unregistered service '${name}'`);
222
+ return false;
223
+ }
224
+
225
+ // Start dependencies first
226
+ for (const dep of entry.dependencies) {
227
+ if (!(await this.isRunning(dep))) {
228
+ this.logger.debug(`Starting dependency '${dep}' for '${name}'`);
229
+
230
+ const started = await this.startService(dep);
231
+ if (!started) {
232
+ this.logger.error(
233
+ `Failed to start dependency '${dep}' for '${name}'`
234
+ );
235
+ return false;
236
+ }
237
+ }
238
+ }
239
+
240
+ const instance = this.get(name);
241
+ if (!instance) return false;
242
+
243
+ // Initialize if needed
244
+ if (instance.state === CREATED || instance.state === DESTROYED) {
245
+ const initialized = await this.initService(name);
246
+ if (!initialized) return false;
247
+ }
248
+
249
+ return await instance.start();
250
+ }
251
+
252
+ /**
253
+ * Stop a service
254
+ *
255
+ * @param {string} name - Service name
256
+ * @param {StopOptions} [options={}] - Stop options
257
+ *
258
+ * @returns {Promise<boolean>} True if service stopped successfully
259
+ */
260
+ async stopService(name, options = {}) {
261
+ const instance = this.get(name);
262
+ if (!instance) {
263
+ this.logger.warn(`Cannot stop unregistered service '${name}'`);
264
+ return true; // Already stopped
265
+ }
266
+
267
+ // Check dependents
268
+ const entry = this.services.get(name);
269
+ if (!options.force && entry && entry.dependents.size > 0) {
270
+ const runningDependents = [];
271
+ for (const dep of entry.dependents) {
272
+ if (await this.isRunning(dep)) {
273
+ runningDependents.push(dep);
274
+ }
275
+ }
276
+
277
+ if (runningDependents.length > 0) {
278
+ this.logger.warn(
279
+ `Cannot stop '${name}' - required by: ${runningDependents.join(', ')}`
280
+ );
281
+ return false;
282
+ }
283
+ }
284
+
285
+ return await instance.stop(options);
286
+ }
287
+
288
+ /**
289
+ * Recover a service from error state
290
+ *
291
+ * @param {string} name - Service name
292
+ *
293
+ * @returns {Promise<boolean>} True if recovery succeeded
294
+ */
295
+ async recoverService(name) {
296
+ const instance = this.get(name);
297
+ if (!instance) return false;
298
+
299
+ return await instance.recover();
300
+ }
301
+
302
+ /**
303
+ * Start all registered services in dependency order
304
+ *
305
+ * @returns {Promise<Object<string, boolean>>} Map of service results
306
+ */
307
+ async startAll() {
308
+ this.logger.info('Starting all services');
309
+
310
+ // Sort by priority and dependencies
311
+ const sorted = this.#topologicalSort();
312
+ const results = new Map();
313
+
314
+ for (const name of sorted) {
315
+ const success = await this.startService(name);
316
+ results.set(name, success);
317
+
318
+ if (!success) {
319
+ this.logger.error(`Failed to start '${name}', stopping`);
320
+ // Mark remaining services as not started
321
+ for (const remaining of sorted) {
322
+ if (!results.has(remaining)) {
323
+ results.set(remaining, false);
324
+ }
325
+ }
326
+ break;
327
+ }
328
+ }
329
+
330
+ return Object.fromEntries(results);
331
+ }
332
+
333
+ /**
334
+ * Stop all services in reverse dependency order
335
+ *
336
+ * @param {StopOptions} [options={}] - Stop options
337
+ *
338
+ * @returns {Promise<Object<string, boolean>>} Map of service results
339
+ */
340
+ async stopAll(options = {}) {
341
+ this.logger.info('Stopping all services');
342
+
343
+ const stopOptions = {
344
+ timeout: options.timeout || this.config.stopTimeout,
345
+ force: options.force || false
346
+ };
347
+
348
+ // Stop in reverse order
349
+ const sorted = this.#topologicalSort().reverse();
350
+ const results = new Map();
351
+
352
+ // Handle global timeout if specified
353
+ if (stopOptions.timeout > 0) {
354
+ const timeoutPromise = new Promise((_, reject) =>
355
+ setTimeout(
356
+ () => reject(new Error('Global shutdown timeout')),
357
+ stopOptions.timeout
358
+ )
359
+ );
360
+
361
+ try {
362
+ // Race between stopping all services and timeout
363
+ await Promise.race([
364
+ this.#stopAllSequentially(sorted, results, stopOptions),
365
+ timeoutPromise
366
+ ]);
367
+ } catch (error) {
368
+ if (error.message === 'Global shutdown timeout') {
369
+ this.logger.error('Global shutdown timeout reached');
370
+ // Mark any remaining services as failed
371
+ for (const name of sorted) {
372
+ if (!results.has(name)) {
373
+ results.set(name, false);
374
+ }
375
+ }
376
+ } else {
377
+ throw error;
378
+ }
379
+ }
380
+ } else {
381
+ // No timeout, just stop sequentially
382
+ await this.#stopAllSequentially(sorted, results, stopOptions);
383
+ }
384
+
385
+ return Object.fromEntries(results);
386
+ }
387
+
388
+
389
+ /**
390
+ * Get health status for all services
391
+ *
392
+ * @returns {Promise<HealthCheckResult>} Health status for all services
393
+ */
394
+ async checkHealth() {
395
+ /** @type {HealthCheckResult} */
396
+ const health = {};
397
+
398
+ for (const [name, entry] of this.services) {
399
+ if (entry.instance) {
400
+ health[name] = await entry.instance.getHealth();
401
+ } else {
402
+ health[name] = {
403
+ name,
404
+ state: NOT_CREATED,
405
+ healthy: false
406
+ };
407
+ }
408
+ }
409
+
410
+ return health;
411
+ }
412
+
413
+ /**
414
+ * Check if a service is currently running
415
+ *
416
+ * @param {string} name - Service name
417
+ *
418
+ * @returns {Promise<boolean>} True if service is running
419
+ */
420
+ async isRunning(name) {
421
+ const instance = this.get(name);
422
+ return instance ? instance.state === RUNNING : false;
423
+ }
424
+
425
+ /**
426
+ * Set log level for a service or globally
427
+ *
428
+ * @param {string} name - Service name or '*' for global
429
+ * @param {string} level - Log level to set
430
+ */
431
+ setLogLevel(name, level) {
432
+ if (name === '*') {
433
+ // Global level
434
+ this.config.logConfig.globalLevel = level;
435
+
436
+ // Apply to all existing services
437
+ // eslint-disable-next-line no-unused-vars
438
+ for (const [_, entry] of this.services) {
439
+ if (entry.instance) {
440
+ entry.instance.setLogLevel(level);
441
+ }
442
+ }
443
+ } else {
444
+ // Service-specific level
445
+ if (!this.config.logConfig.serviceLevels) {
446
+ this.config.logConfig.serviceLevels = {};
447
+ }
448
+ this.config.logConfig.serviceLevels[name] = level;
449
+
450
+ // Apply to existing instance
451
+ const instance = this.get(name);
452
+ if (instance) {
453
+ instance.setLogLevel(level);
454
+ }
455
+ }
456
+ }
457
+
458
+ /**
459
+ * Get all services with a specific tag
460
+ *
461
+ * @param {string} tag - Tag to filter by
462
+ *
463
+ * @returns {string[]} Array of service names
464
+ */
465
+ getServicesByTag(tag) {
466
+ const services = [];
467
+ for (const [name, entry] of this.services) {
468
+ if (entry.tags.includes(tag)) {
469
+ services.push(name);
470
+ }
471
+ }
472
+ return services;
473
+ }
474
+
475
+
476
+ /**
477
+ * Attach event listeners to forward service events
478
+ *
479
+ * @param {string} name - Service name
480
+ * @param {import('../service-base/typedef.js').ServiceInstance} instance
481
+ * Service instance
482
+ */
483
+ _attachServiceEvents(name, instance) {
484
+ // Forward service events
485
+ instance.on('stateChanged', (data) => {
486
+ this.emit('service:stateChanged', { service: name, data });
487
+ });
488
+
489
+ instance.on('healthChanged', (data) => {
490
+ this.emit('service:healthChanged', { service: name, data });
491
+ });
492
+
493
+ instance.on('error', (data) => {
494
+ this.emit('service:error', { service: name, data });
495
+ });
496
+
497
+ // Forward log events
498
+
499
+ instance.logger.on('log', (logEvent) => {
500
+ this.emit('service:log', logEvent);
501
+ });
502
+ }
503
+
504
+ // Internal methods
505
+
506
+ /**
507
+ * Setup logging configuration based on config.dev
508
+ */
509
+ #setupLogging() {
510
+ // Set default log levels based on config.debug flag
511
+ if (this.config.debug) {
512
+ this.config.logConfig.defaultLevel = DEBUG;
513
+ } else {
514
+ this.config.logConfig.defaultLevel = WARN;
515
+ }
516
+
517
+ // Apply config
518
+ if (this.config.logConfig.globalLevel) {
519
+ this.logger.setLevel(this.config.logConfig.globalLevel);
520
+ }
521
+ }
522
+
523
+ /**
524
+ * Get the appropriate log level for a service
525
+ *
526
+ * @param {string} name - Service name
527
+ *
528
+ * @returns {string|undefined} Log level or undefined
529
+ */
530
+ #getServiceLogLevel(name) {
531
+ const config = this.config.logConfig;
532
+
533
+ // Check in order of precedence:
534
+ // 1. Global level (overrides everything)
535
+ if (config.globalLevel) {
536
+ return config.globalLevel;
537
+ }
538
+
539
+ // 2. Service-specific level
540
+ if (config.serviceLevels?.[name]) {
541
+ return config.serviceLevels[name];
542
+ }
543
+
544
+ // 3. Don't use defaultLevel as it might be too restrictive
545
+ // Return undefined to let the service use its own default
546
+ return undefined;
547
+ }
548
+
549
+ /**
550
+ * Stop services sequentially
551
+ *
552
+ * @param {string[]} serviceNames - Ordered list of service names
553
+ * @param {Map<string, boolean>} results - Results map to populate
554
+ * @param {StopOptions} options - Stop options
555
+ */
556
+ async #stopAllSequentially(serviceNames, results, options) {
557
+ for (const name of serviceNames) {
558
+ try {
559
+ const success = await this.stopService(name, options);
560
+ results.set(name, success);
561
+ } catch (error) {
562
+ this.logger.error(`Error stopping '${name}'`, error);
563
+ results.set(name, false);
564
+ }
565
+ }
566
+ }
567
+
568
+ /**
569
+ * Sort services by dependencies using topological sort
570
+ *
571
+ * @returns {string[]} Service names in dependency order
572
+ * @throws {Error} If circular dependencies are detected
573
+ */
574
+ #topologicalSort() {
575
+ const sorted = [];
576
+ const visited = new Set();
577
+ const visiting = new Set();
578
+
579
+ const visit = (name) => {
580
+ if (visited.has(name)) return;
581
+ if (visiting.has(name)) {
582
+ throw new Error(`Circular dependency detected involving '${name}'`);
583
+ }
584
+
585
+ visiting.add(name);
586
+
587
+ const entry = this.services.get(name);
588
+ if (entry) {
589
+ for (const dep of entry.dependencies) {
590
+ visit(dep);
591
+ }
592
+ }
593
+
594
+ visiting.delete(name);
595
+ visited.add(name);
596
+ sorted.push(name);
597
+ };
598
+
599
+ // Visit all services
600
+ for (const name of this.services.keys()) {
601
+ visit(name);
602
+ }
603
+
604
+ return sorted;
605
+ }
606
+ }
607
+
608
+ export default ServiceManager;