@goplusvn/core 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (591) hide show
  1. package/package.json +31 -175
  2. package/src/assets/erp_wallpaper.png +0 -0
  3. package/src/assets/goeat_logo.png +0 -0
  4. package/src/audit/audit-manager.ts +139 -0
  5. package/src/audit/index.ts +11 -0
  6. package/src/audit/memory-audit-logger.ts +86 -0
  7. package/src/audit/types.ts +50 -0
  8. package/src/auth/auth-service.ts +97 -0
  9. package/src/auth/index.ts +266 -0
  10. package/src/code-generation/index.ts +69 -0
  11. package/src/configs/auth-routes.ts +17 -0
  12. package/src/configs/crud.ts +136 -0
  13. package/src/configs/data/navigations.ts +781 -0
  14. package/src/configs/data/oauth-links.ts +10 -0
  15. package/src/configs/entities/material-categories.config.ts +125 -0
  16. package/src/configs/i18n.ts +12 -0
  17. package/src/configs/index.ts +26 -0
  18. package/src/configs/status.ts +25 -0
  19. package/src/configs/themes.ts +100 -0
  20. package/src/crud/components/crud-bulk-actions.tsx +91 -0
  21. package/src/crud/components/crud-card-view.tsx +241 -0
  22. package/src/crud/components/crud-context.tsx +122 -0
  23. package/src/crud/components/crud-delete-dialog.tsx +145 -0
  24. package/src/crud/components/crud-dialog.tsx +406 -0
  25. package/src/crud/components/crud-empty-state.tsx +104 -0
  26. package/src/crud/components/crud-export-button.tsx +170 -0
  27. package/src/crud/components/crud-field-renderer.tsx +653 -0
  28. package/src/crud/components/crud-filter-chips.tsx +102 -0
  29. package/src/crud/components/crud-filters/checkbox-filter.tsx +97 -0
  30. package/src/crud/components/crud-filters/datetime-filter.tsx +83 -0
  31. package/src/crud/components/crud-filters/filter-builder.tsx +66 -0
  32. package/src/crud/components/crud-filters/index.tsx +76 -0
  33. package/src/crud/components/crud-filters/radio-filter.tsx +86 -0
  34. package/src/crud/components/crud-filters/select-filter.tsx +141 -0
  35. package/src/crud/components/crud-filters/text-filter.tsx +86 -0
  36. package/src/crud/components/crud-form.tsx +642 -0
  37. package/src/crud/components/crud-import-dialog.tsx +440 -0
  38. package/src/crud/components/crud-infinite-scroll.tsx +116 -0
  39. package/src/crud/components/crud-page.tsx +1017 -0
  40. package/src/crud/components/crud-provider.tsx +277 -0
  41. package/src/crud/components/crud-row-actions.tsx +189 -0
  42. package/src/crud/components/crud-search.tsx +82 -0
  43. package/src/crud/components/crud-sheet.tsx +336 -0
  44. package/src/crud/components/crud-table-skeleton.tsx +26 -0
  45. package/src/crud/components/crud-table-toolbar.tsx +91 -0
  46. package/src/crud/components/crud-table.tsx +352 -0
  47. package/src/crud/components/crud-virtual-table.tsx +55 -0
  48. package/src/crud/components/index.tsx +20 -0
  49. package/src/crud/crud-filters/checkbox-filter.tsx +87 -0
  50. package/src/crud/crud-filters/datetime-filter.tsx +82 -0
  51. package/src/crud/crud-filters/filter-builder.tsx +64 -0
  52. package/src/crud/crud-filters/index.tsx +78 -0
  53. package/src/crud/crud-filters/radio-filter.tsx +79 -0
  54. package/src/crud/crud-filters/select-filter.tsx +148 -0
  55. package/src/crud/crud-filters/text-filter.tsx +81 -0
  56. package/src/crud/index.ts +43 -0
  57. package/src/crud/lib/crud-service.test.ts +334 -0
  58. package/src/crud/lib/crud-service.ts +358 -0
  59. package/src/crud/lib/crud-utils.test.ts +354 -0
  60. package/src/crud/lib/crud-utils.ts +299 -0
  61. package/src/crud/lib/crud-validator.ts +247 -0
  62. package/src/crud/lib/data-loader.ts +234 -0
  63. package/src/crud/lib/field-calculator.ts +241 -0
  64. package/src/crud/lib/field-formatter.ts +240 -0
  65. package/src/crud/lib/import-export-service.test.ts +290 -0
  66. package/src/crud/lib/import-export-service.ts +352 -0
  67. package/src/crud/lib/import-server-utils.ts +109 -0
  68. package/src/crud/lib/lazy-loader.ts +241 -0
  69. package/src/crud/lib/parse-filters.ts +85 -0
  70. package/src/crud/lib/permissions.ts +52 -0
  71. package/src/crud/lib/serialize-config.ts +60 -0
  72. package/src/crud/lib/stream-loader.ts +145 -0
  73. package/src/crud/lib/translate-config.ts +335 -0
  74. package/src/crud/lib/types.ts +11 -0
  75. package/src/crud/pages/entity-crud-page.tsx +144 -0
  76. package/src/crud/server.ts +8 -0
  77. package/src/home/constants.tsx +142 -0
  78. package/src/home/feature-showcase.tsx +171 -0
  79. package/src/home/home-page.tsx +191 -0
  80. package/src/home/hooks/index.ts +1 -0
  81. package/src/home/hooks/useWidgetPreferences.ts +167 -0
  82. package/src/home/index.ts +33 -0
  83. package/src/home/quick-access-dialog.tsx +271 -0
  84. package/src/home/quick-access-menu.tsx +267 -0
  85. package/src/home/types.ts +140 -0
  86. package/src/home/welcome-card.tsx +92 -0
  87. package/src/home/widget-container.tsx +258 -0
  88. package/src/home/widgets/base-widget.tsx +200 -0
  89. package/src/home/widgets/customers-widget.tsx +74 -0
  90. package/src/home/widgets/index.ts +6 -0
  91. package/src/home/widgets/orders-widget.tsx +87 -0
  92. package/src/home/widgets/revenue-widget.tsx +71 -0
  93. package/src/home/widgets/stock-widget.tsx +109 -0
  94. package/src/hooks/index.tsx +598 -0
  95. package/src/hooks/use-tenant.test.tsx +30 -0
  96. package/src/hooks/use-tenant.ts +5 -0
  97. package/src/index.ts +17 -0
  98. package/src/infrastructure/__tests__/architecture-verification.spec.ts +103 -0
  99. package/src/infrastructure/api-service.ts +317 -0
  100. package/src/infrastructure/cache/cache-manager.ts +107 -0
  101. package/src/infrastructure/cache/cache.ts +120 -0
  102. package/src/infrastructure/cache/index.ts +8 -0
  103. package/src/infrastructure/cache/types.ts +48 -0
  104. package/src/infrastructure/cron/cron-manager.ts +239 -0
  105. package/src/infrastructure/cron/index.ts +6 -0
  106. package/src/infrastructure/cron/types.ts +41 -0
  107. package/src/infrastructure/event-bus/event-bus.ts +145 -0
  108. package/src/infrastructure/event-bus/index.ts +2 -0
  109. package/src/infrastructure/event-bus/types.ts +22 -0
  110. package/src/infrastructure/index.ts +32 -0
  111. package/src/infrastructure/lock/decorators.ts +67 -0
  112. package/src/infrastructure/lock/index.ts +2 -0
  113. package/src/infrastructure/lock/lock-manager.ts +33 -0
  114. package/src/infrastructure/logger/index.ts +2 -0
  115. package/src/infrastructure/logger/logger.ts +96 -0
  116. package/src/infrastructure/logger/types.ts +25 -0
  117. package/src/layout/index.tsx +185 -0
  118. package/src/navigation/index.ts +91 -0
  119. package/src/notification/index.ts +14 -0
  120. package/src/notification/notification-service.ts +120 -0
  121. package/src/notification/storage/in-memory.ts +56 -0
  122. package/src/notification/storage/index.ts +1 -0
  123. package/src/notification/types.ts +51 -0
  124. package/src/organization/branch-service.ts +299 -0
  125. package/src/organization/branches.config.ts +154 -0
  126. package/src/organization/index.ts +5 -0
  127. package/src/plugin/apps-registry.ts +97 -0
  128. package/src/plugin/index.ts +5 -0
  129. package/src/plugin/types.ts +41 -0
  130. package/src/providers/index.tsx +109 -0
  131. package/src/providers/tenant-provider.tsx +45 -0
  132. package/src/rbac/components/roles/role-card.tsx +158 -0
  133. package/src/rbac/components/roles/role-stats-cards.tsx +29 -0
  134. package/src/rbac/components/roles/role-toolbar.tsx +123 -0
  135. package/src/rbac/hooks/use-role-operations.ts +159 -0
  136. package/src/rbac/hooks/use-roles-data.ts +59 -0
  137. package/src/rbac/index.ts +297 -0
  138. package/src/rbac/lib/permission-helpers.ts +63 -0
  139. package/src/rbac/pages/action-list-page.tsx +25 -0
  140. package/src/rbac/pages/resource-list-page.tsx +25 -0
  141. package/src/rbac/pages/role-list-page.tsx +378 -0
  142. package/src/rbac/permission-service.ts +140 -0
  143. package/src/rbac/permissions.ts +135 -0
  144. package/src/rbac/resource-service.ts +115 -0
  145. package/src/rbac/resource-validator.ts +119 -0
  146. package/src/rbac/role-service.ts +165 -0
  147. package/src/rbac/server.ts +16 -0
  148. package/src/rbac/types.ts +38 -0
  149. package/src/schemas/action.schema.ts +66 -0
  150. package/src/schemas/branch.schema.ts +52 -0
  151. package/src/schemas/coming-soon-schema.ts +9 -0
  152. package/src/schemas/company.schema.ts +44 -0
  153. package/src/schemas/forgot-passward-schema.ts +9 -0
  154. package/src/schemas/index.ts +30 -0
  155. package/src/schemas/material-category.schema.ts +43 -0
  156. package/src/schemas/material-pricing.schema.ts +74 -0
  157. package/src/schemas/material.schema.ts +76 -0
  158. package/src/schemas/materials.ts +52 -0
  159. package/src/schemas/new-passward-schema.ts +15 -0
  160. package/src/schemas/partner-company.schema.ts +149 -0
  161. package/src/schemas/register-schema.ts +36 -0
  162. package/src/schemas/resource.schema.ts +133 -0
  163. package/src/schemas/role.schema.ts +11 -0
  164. package/src/schemas/sign-in-schema.ts +24 -0
  165. package/src/schemas/supplier-pricing.schema.ts +15 -0
  166. package/src/schemas/supplier.schema.ts +120 -0
  167. package/src/schemas/system-category-group.schema.ts +67 -0
  168. package/src/schemas/system-category.schema.ts +77 -0
  169. package/src/schemas/system-config.schema.ts +118 -0
  170. package/src/schemas/uom.schema.ts +75 -0
  171. package/src/schemas/user-supplier.schema.ts +179 -0
  172. package/src/schemas/user.schema.ts +18 -0
  173. package/src/schemas/verify-email-schema.ts +9 -0
  174. package/src/schemas/warehouse.schema.ts +49 -0
  175. package/src/system/components/categories/category-list.tsx +529 -0
  176. package/src/system/components/categories/category-manager.tsx +89 -0
  177. package/src/system/components/categories/group-sidebar.tsx +308 -0
  178. package/src/system/components/settings/setting-dialogs.tsx +197 -0
  179. package/src/system/components/settings/setting-field.tsx +291 -0
  180. package/src/system/components/settings/setting-form-dialog.tsx +308 -0
  181. package/src/system/components/settings/settings-groups.ts +80 -0
  182. package/src/system/components/settings/settings-search.tsx +71 -0
  183. package/src/system/components/settings/settings-section.tsx +74 -0
  184. package/src/system/components/settings/settings-sidebar.tsx +81 -0
  185. package/src/system/constants.ts +3 -0
  186. package/src/system/index.ts +150 -0
  187. package/src/system/job-manager.ts +176 -0
  188. package/src/system/pages/components/categories/category-list.tsx +537 -0
  189. package/src/system/pages/components/categories/category-manager.tsx +90 -0
  190. package/src/system/pages/components/categories/group-sidebar.tsx +311 -0
  191. package/src/system/pages/components/settings/sales-rules-settings.tsx +222 -0
  192. package/src/system/pages/components/settings/setting-dialogs.tsx +197 -0
  193. package/src/system/pages/components/settings/setting-field.tsx +292 -0
  194. package/src/system/pages/components/settings/setting-form-dialog.tsx +308 -0
  195. package/src/system/pages/components/settings/settings-groups.ts +87 -0
  196. package/src/system/pages/components/settings/settings-page.tsx +372 -0
  197. package/src/system/pages/components/settings/settings-search.tsx +71 -0
  198. package/src/system/pages/components/settings/settings-section.tsx +74 -0
  199. package/src/system/pages/components/settings/settings-sidebar.tsx +81 -0
  200. package/src/system/pages/components/settings/system-settings.tsx +244 -0
  201. package/src/system/pages/system-category-page.tsx +15 -0
  202. package/src/system/pages/system-settings-page.tsx +380 -0
  203. package/src/system/schemas/system-category-group.schema.ts +46 -0
  204. package/src/system/schemas/system-category.schema.ts +56 -0
  205. package/src/system/services/settings-service.ts +127 -0
  206. package/src/system/services/system-category-service.ts +63 -0
  207. package/src/system/types.ts +45 -0
  208. package/src/types/index.ts +703 -0
  209. package/src/ui/auth/auth-layout.tsx +135 -0
  210. package/src/ui/auth/forgot-password-form.tsx +98 -0
  211. package/src/ui/auth/index.tsx +7 -0
  212. package/src/ui/auth/new-password-form.tsx +107 -0
  213. package/src/ui/auth/oauth-links.tsx +30 -0
  214. package/src/ui/auth/register-form.tsx +202 -0
  215. package/src/ui/auth/sign-in-form.tsx +238 -0
  216. package/src/ui/auth/verify-email-form.tsx +104 -0
  217. package/src/ui/crud/index.tsx +10 -0
  218. package/src/ui/data-display/accordion.tsx +65 -0
  219. package/src/ui/data-display/aspect-ratio.tsx +11 -0
  220. package/src/ui/data-display/avatar.tsx +163 -0
  221. package/src/ui/data-display/bento-grid.tsx +77 -0
  222. package/src/ui/data-display/carousel.tsx +249 -0
  223. package/src/ui/data-display/chart.tsx +363 -0
  224. package/src/ui/data-display/code-block-highlight.tsx +54 -0
  225. package/src/ui/data-display/collapsible.tsx +42 -0
  226. package/src/ui/data-display/compact-stat-bar.tsx +149 -0
  227. package/src/ui/data-display/data-table/data-table-context.tsx +255 -0
  228. package/src/ui/data-display/data-table/data-table-empty-state.tsx +133 -0
  229. package/src/ui/data-display/data-table/data-table-skeleton.tsx +145 -0
  230. package/src/ui/data-display/data-table/data-table-toolbar.tsx +353 -0
  231. package/src/ui/data-display/data-table/data-table.tsx +597 -0
  232. package/src/ui/data-display/data-table/index.ts +44 -0
  233. package/src/ui/data-display/data-table-column-header.tsx +75 -0
  234. package/src/ui/data-display/data-table-pagination.tsx +130 -0
  235. package/src/ui/data-display/data-table-view-options.tsx +59 -0
  236. package/src/ui/data-display/formatted-number-input.tsx +210 -0
  237. package/src/ui/data-display/highlight.tsx +20 -0
  238. package/src/ui/data-display/hover-card.tsx +48 -0
  239. package/src/ui/data-display/index.tsx +50 -0
  240. package/src/ui/data-display/iphone-15-pro.tsx +114 -0
  241. package/src/ui/data-display/kanban/index.ts +4 -0
  242. package/src/ui/data-display/kanban/kanban-board.tsx +192 -0
  243. package/src/ui/data-display/kanban/kanban-column.tsx +74 -0
  244. package/src/ui/data-display/kanban/kanban-item.tsx +50 -0
  245. package/src/ui/data-display/kanban/kanban-types.ts +21 -0
  246. package/src/ui/data-display/kpi-card.tsx +68 -0
  247. package/src/ui/data-display/media-grid.tsx +110 -0
  248. package/src/ui/data-display/safari.tsx +175 -0
  249. package/src/ui/data-display/show-more-text.tsx +55 -0
  250. package/src/ui/data-display/tabs.tsx +68 -0
  251. package/src/ui/data-display/timeline.tsx +256 -0
  252. package/src/ui/feedback/alert.tsx +60 -0
  253. package/src/ui/feedback/context-menu.tsx +245 -0
  254. package/src/ui/feedback/drawer.tsx +132 -0
  255. package/src/ui/feedback/error-dialog.tsx +273 -0
  256. package/src/ui/feedback/index.tsx +183 -0
  257. package/src/ui/feedback/progress.tsx +32 -0
  258. package/src/ui/feedback/sheet.tsx +148 -0
  259. package/src/ui/feedback/sonner.tsx +36 -0
  260. package/src/ui/forms/command.tsx +157 -0
  261. package/src/ui/forms/date-picker.tsx +73 -0
  262. package/src/ui/forms/date-range-picker.tsx +76 -0
  263. package/src/ui/forms/date-time-picker.tsx +109 -0
  264. package/src/ui/forms/editor/editor-menu-bar.tsx +394 -0
  265. package/src/ui/forms/editor/index.tsx +130 -0
  266. package/src/ui/forms/editor/multi-select-example.tsx +1234 -0
  267. package/src/ui/forms/emoji-picker.tsx +109 -0
  268. package/src/ui/forms/file-dropzone.tsx +169 -0
  269. package/src/ui/forms/file-thumbnail.tsx +29 -0
  270. package/src/ui/forms/index.tsx +201 -0
  271. package/src/ui/forms/input-file.tsx +99 -0
  272. package/src/ui/forms/input-group.tsx +46 -0
  273. package/src/ui/forms/input-otp.tsx +81 -0
  274. package/src/ui/forms/input-phone.tsx +172 -0
  275. package/src/ui/forms/input-spin.tsx +116 -0
  276. package/src/ui/forms/input-tags.tsx +219 -0
  277. package/src/ui/forms/input-time.tsx +42 -0
  278. package/src/ui/forms/multi-select.tsx +629 -0
  279. package/src/ui/forms/multiple-date-picker.tsx +74 -0
  280. package/src/ui/forms/radio-group.tsx +42 -0
  281. package/src/ui/forms/rating.tsx +158 -0
  282. package/src/ui/forms/time-picker.tsx +57 -0
  283. package/src/ui/index.tsx +17 -0
  284. package/src/ui/layout/animated-list.tsx +77 -0
  285. package/src/ui/layout/animated-sidebar.tsx +294 -0
  286. package/src/ui/layout/command-menu.tsx +355 -0
  287. package/src/ui/layout/customizer.tsx +324 -0
  288. package/src/ui/layout/footer.tsx +43 -0
  289. package/src/ui/layout/full-screen-toggle.tsx +52 -0
  290. package/src/ui/layout/header-breadcrumb.tsx +77 -0
  291. package/src/ui/layout/horizontal-layout-header.tsx +83 -0
  292. package/src/ui/layout/horizontal-layout.tsx +50 -0
  293. package/src/ui/layout/index.tsx +25 -0
  294. package/src/ui/layout/language-dropdown.tsx +103 -0
  295. package/src/ui/layout/logo.tsx +63 -0
  296. package/src/ui/layout/main-layout.tsx +57 -0
  297. package/src/ui/layout/mode-dropdown.tsx +58 -0
  298. package/src/ui/layout/notification-dropdown.tsx +127 -0
  299. package/src/ui/layout/page-tabs.tsx +306 -0
  300. package/src/ui/layout/route-cache.tsx +214 -0
  301. package/src/ui/layout/sidebar-group-icon-menu.tsx +195 -0
  302. package/src/ui/layout/sidebar.tsx +279 -0
  303. package/src/ui/layout/tab-content-cache.tsx +201 -0
  304. package/src/ui/layout/tab-navigation-provider.tsx +536 -0
  305. package/src/ui/layout/toggle-mobile-sidebar.tsx +33 -0
  306. package/src/ui/layout/top-bar-header-menubar.tsx +412 -0
  307. package/src/ui/layout/user-dropdown.tsx +188 -0
  308. package/src/ui/layout/vertical-layout-header.tsx +65 -0
  309. package/src/ui/layout/vertical-layout.tsx +47 -0
  310. package/src/ui/management/audit-log-page.tsx +209 -0
  311. package/src/ui/management/cache-management.tsx +349 -0
  312. package/src/ui/management/index.ts +3 -0
  313. package/src/ui/management/job-management.tsx +308 -0
  314. package/src/ui/pages/not-found.tsx +30 -0
  315. package/src/ui/primitives/badge.tsx +66 -0
  316. package/src/ui/primitives/breadcrumb.tsx +103 -0
  317. package/src/ui/primitives/button.tsx +129 -0
  318. package/src/ui/primitives/calendar.tsx +74 -0
  319. package/src/ui/primitives/card.tsx +86 -0
  320. package/src/ui/primitives/checkbox.tsx +31 -0
  321. package/src/ui/primitives/client.ts +30 -0
  322. package/src/ui/primitives/combobox.tsx +290 -0
  323. package/src/ui/primitives/dialog.tsx +121 -0
  324. package/src/ui/primitives/dropdown-menu.tsx +239 -0
  325. package/src/ui/primitives/dynamic-icon.tsx +24 -0
  326. package/src/ui/primitives/index.tsx +134 -0
  327. package/src/ui/primitives/input-number.tsx +131 -0
  328. package/src/ui/primitives/input.tsx +22 -0
  329. package/src/ui/primitives/keyboard.tsx +23 -0
  330. package/src/ui/primitives/label.tsx +24 -0
  331. package/src/ui/primitives/menubar.tsx +262 -0
  332. package/src/ui/primitives/navigation-menu.tsx +157 -0
  333. package/src/ui/primitives/pagination.tsx +118 -0
  334. package/src/ui/primitives/popover.tsx +56 -0
  335. package/src/ui/primitives/prefetch-link.tsx +60 -0
  336. package/src/ui/primitives/resizable.tsx +59 -0
  337. package/src/ui/primitives/scroll-area.tsx +63 -0
  338. package/src/ui/primitives/select.tsx +172 -0
  339. package/src/ui/primitives/separator.tsx +51 -0
  340. package/src/ui/primitives/sidebar.tsx +844 -0
  341. package/src/ui/primitives/slider.tsx +27 -0
  342. package/src/ui/primitives/status-badge.tsx +47 -0
  343. package/src/ui/primitives/sticky-layout.tsx +50 -0
  344. package/src/ui/primitives/switch.tsx +29 -0
  345. package/src/ui/primitives/table.tsx +116 -0
  346. package/src/ui/primitives/tabs.tsx +55 -0
  347. package/src/ui/primitives/toggle-group.tsx +70 -0
  348. package/src/ui/primitives/toggle.tsx +47 -0
  349. package/src/ui/primitives/tooltip.tsx +59 -0
  350. package/src/user/components/dangerous-zone.tsx +34 -0
  351. package/src/user/components/delete-account-form.tsx +40 -0
  352. package/src/user/components/index.ts +4 -0
  353. package/src/user/components/profile-info-form.tsx +390 -0
  354. package/src/user/components/profile-info.tsx +32 -0
  355. package/src/user/components/unified-profile-dialog.tsx +1019 -0
  356. package/src/user/components/user-stats.tsx +27 -0
  357. package/src/user/components/user-toolbar.tsx +137 -0
  358. package/src/user/components/users-card-view.tsx +253 -0
  359. package/src/user/index.ts +11 -0
  360. package/src/user/pages/user-list-page.tsx +234 -0
  361. package/src/user/pages/users-client-page.tsx +385 -0
  362. package/src/user/profile-page.tsx +19 -0
  363. package/src/user/schemas.ts +68 -0
  364. package/src/user/types.ts +34 -0
  365. package/src/user/user-service.ts +538 -0
  366. package/src/utils/index.ts +906 -0
  367. package/src/workflow/activity-timeline.tsx +412 -0
  368. package/src/workflow/approval-workflow.tsx +31 -0
  369. package/src/workflow/index.ts +2 -0
  370. package/dist/audit/index.d.mts +0 -115
  371. package/dist/audit/index.d.ts +0 -115
  372. package/dist/audit/index.js +0 -204
  373. package/dist/audit/index.js.map +0 -1
  374. package/dist/audit/index.mjs +0 -200
  375. package/dist/audit/index.mjs.map +0 -1
  376. package/dist/auth/index.d.mts +0 -86
  377. package/dist/auth/index.d.ts +0 -86
  378. package/dist/auth/index.js +0 -210
  379. package/dist/auth/index.js.map +0 -1
  380. package/dist/auth/index.mjs +0 -198
  381. package/dist/auth/index.mjs.map +0 -1
  382. package/dist/button-1dWvP9Ib.d.mts +0 -30
  383. package/dist/button-1dWvP9Ib.d.ts +0 -30
  384. package/dist/calendar-2QzdEo1z.d.mts +0 -20
  385. package/dist/calendar-2QzdEo1z.d.ts +0 -20
  386. package/dist/code-generation/index.d.mts +0 -30
  387. package/dist/code-generation/index.d.ts +0 -30
  388. package/dist/code-generation/index.js +0 -31
  389. package/dist/code-generation/index.js.map +0 -1
  390. package/dist/code-generation/index.mjs +0 -28
  391. package/dist/code-generation/index.mjs.map +0 -1
  392. package/dist/configs/index.d.mts +0 -175
  393. package/dist/configs/index.d.ts +0 -175
  394. package/dist/configs/index.js +0 -254
  395. package/dist/configs/index.js.map +0 -1
  396. package/dist/configs/index.mjs +0 -233
  397. package/dist/configs/index.mjs.map +0 -1
  398. package/dist/crud/index.d.mts +0 -646
  399. package/dist/crud/index.d.ts +0 -646
  400. package/dist/crud/index.js +0 -11772
  401. package/dist/crud/index.js.map +0 -1
  402. package/dist/crud/index.mjs +0 -11665
  403. package/dist/crud/index.mjs.map +0 -1
  404. package/dist/crud/server.d.mts +0 -20
  405. package/dist/crud/server.d.ts +0 -20
  406. package/dist/crud/server.js +0 -123
  407. package/dist/crud/server.js.map +0 -1
  408. package/dist/crud/server.mjs +0 -120
  409. package/dist/crud/server.mjs.map +0 -1
  410. package/dist/data-table-skeleton-12NA8Mjx.d.mts +0 -39
  411. package/dist/data-table-skeleton-12NA8Mjx.d.ts +0 -39
  412. package/dist/dialog-bKfjZMTd.d.mts +0 -22
  413. package/dist/dialog-bKfjZMTd.d.ts +0 -22
  414. package/dist/dynamic-icon-DrGIiu2N.d.mts +0 -10
  415. package/dist/dynamic-icon-DrGIiu2N.d.ts +0 -10
  416. package/dist/home/index.d.mts +0 -269
  417. package/dist/home/index.d.ts +0 -269
  418. package/dist/home/index.js +0 -1678
  419. package/dist/home/index.js.map +0 -1
  420. package/dist/home/index.mjs +0 -1635
  421. package/dist/home/index.mjs.map +0 -1
  422. package/dist/hooks/index.d.mts +0 -7
  423. package/dist/hooks/index.d.ts +0 -7
  424. package/dist/hooks/index.js +0 -8316
  425. package/dist/hooks/index.js.map +0 -1
  426. package/dist/hooks/index.mjs +0 -8255
  427. package/dist/hooks/index.mjs.map +0 -1
  428. package/dist/index-50hpiPrV.d.ts +0 -116
  429. package/dist/index-B9zQVEVi.d.mts +0 -116
  430. package/dist/index.d.mts +0 -5
  431. package/dist/index.d.ts +0 -5
  432. package/dist/index.js +0 -123
  433. package/dist/index.js.map +0 -1
  434. package/dist/index.mjs +0 -118
  435. package/dist/index.mjs.map +0 -1
  436. package/dist/infrastructure/index.d.mts +0 -423
  437. package/dist/infrastructure/index.d.ts +0 -423
  438. package/dist/infrastructure/index.js +0 -633
  439. package/dist/infrastructure/index.js.map +0 -1
  440. package/dist/infrastructure/index.mjs +0 -619
  441. package/dist/infrastructure/index.mjs.map +0 -1
  442. package/dist/label-DWTEkNPo.d.ts +0 -226
  443. package/dist/label-LPpdcoBx.d.mts +0 -226
  444. package/dist/layout/index.d.mts +0 -48
  445. package/dist/layout/index.d.ts +0 -48
  446. package/dist/layout/index.js +0 -117
  447. package/dist/layout/index.js.map +0 -1
  448. package/dist/layout/index.mjs +0 -90
  449. package/dist/layout/index.mjs.map +0 -1
  450. package/dist/navigation/index.d.mts +0 -16
  451. package/dist/navigation/index.d.ts +0 -16
  452. package/dist/navigation/index.js +0 -53
  453. package/dist/navigation/index.js.map +0 -1
  454. package/dist/navigation/index.mjs +0 -50
  455. package/dist/navigation/index.mjs.map +0 -1
  456. package/dist/notification/index.d.mts +0 -105
  457. package/dist/notification/index.d.ts +0 -105
  458. package/dist/notification/index.js +0 -278
  459. package/dist/notification/index.js.map +0 -1
  460. package/dist/notification/index.mjs +0 -274
  461. package/dist/notification/index.mjs.map +0 -1
  462. package/dist/organization/index.d.mts +0 -99
  463. package/dist/organization/index.d.ts +0 -99
  464. package/dist/organization/index.js +0 -360
  465. package/dist/organization/index.js.map +0 -1
  466. package/dist/organization/index.mjs +0 -352
  467. package/dist/organization/index.mjs.map +0 -1
  468. package/dist/plugin/index.d.mts +0 -83
  469. package/dist/plugin/index.d.ts +0 -83
  470. package/dist/plugin/index.js +0 -86
  471. package/dist/plugin/index.js.map +0 -1
  472. package/dist/plugin/index.mjs +0 -84
  473. package/dist/plugin/index.mjs.map +0 -1
  474. package/dist/providers/index.d.mts +0 -25
  475. package/dist/providers/index.d.ts +0 -25
  476. package/dist/providers/index.js +0 -84
  477. package/dist/providers/index.js.map +0 -1
  478. package/dist/providers/index.mjs +0 -77
  479. package/dist/providers/index.mjs.map +0 -1
  480. package/dist/rbac/index.d.mts +0 -226
  481. package/dist/rbac/index.d.ts +0 -226
  482. package/dist/rbac/index.js +0 -4784
  483. package/dist/rbac/index.js.map +0 -1
  484. package/dist/rbac/index.mjs +0 -4722
  485. package/dist/rbac/index.mjs.map +0 -1
  486. package/dist/rbac/permissions.d.mts +0 -26
  487. package/dist/rbac/permissions.d.ts +0 -26
  488. package/dist/rbac/permissions.js +0 -94
  489. package/dist/rbac/permissions.js.map +0 -1
  490. package/dist/rbac/permissions.mjs +0 -90
  491. package/dist/rbac/permissions.mjs.map +0 -1
  492. package/dist/rbac/server.d.mts +0 -1
  493. package/dist/rbac/server.d.ts +0 -1
  494. package/dist/rbac/server.js +0 -128
  495. package/dist/rbac/server.js.map +0 -1
  496. package/dist/rbac/server.mjs +0 -124
  497. package/dist/rbac/server.mjs.map +0 -1
  498. package/dist/schemas/index.d.mts +0 -1257
  499. package/dist/schemas/index.d.ts +0 -1257
  500. package/dist/schemas/index.js +0 -572
  501. package/dist/schemas/index.js.map +0 -1
  502. package/dist/schemas/index.mjs +0 -523
  503. package/dist/schemas/index.mjs.map +0 -1
  504. package/dist/server-QuYCTa89.d.mts +0 -83
  505. package/dist/server-QuYCTa89.d.ts +0 -83
  506. package/dist/sonner-C74GlRDQ.d.mts +0 -71
  507. package/dist/sonner-C74GlRDQ.d.ts +0 -71
  508. package/dist/status-BOXZgIqX.d.mts +0 -12
  509. package/dist/status-BOXZgIqX.d.ts +0 -12
  510. package/dist/system/index.d.mts +0 -77
  511. package/dist/system/index.d.ts +0 -77
  512. package/dist/system/index.js +0 -102
  513. package/dist/system/index.js.map +0 -1
  514. package/dist/system/index.mjs +0 -100
  515. package/dist/system/index.mjs.map +0 -1
  516. package/dist/tabs-C6FfBwPY.d.mts +0 -18
  517. package/dist/tabs-C6FfBwPY.d.ts +0 -18
  518. package/dist/tenant-provider-B8eC_Wpb.d.mts +0 -27
  519. package/dist/tenant-provider-B8eC_Wpb.d.ts +0 -27
  520. package/dist/types/index.d.mts +0 -469
  521. package/dist/types/index.d.ts +0 -469
  522. package/dist/types/index.js +0 -25
  523. package/dist/types/index.js.map +0 -1
  524. package/dist/types/index.mjs +0 -21
  525. package/dist/types/index.mjs.map +0 -1
  526. package/dist/ui/auth.d.mts +0 -39
  527. package/dist/ui/auth.d.ts +0 -39
  528. package/dist/ui/auth.js +0 -4941
  529. package/dist/ui/auth.js.map +0 -1
  530. package/dist/ui/auth.mjs +0 -4896
  531. package/dist/ui/auth.mjs.map +0 -1
  532. package/dist/ui/crud.d.mts +0 -2
  533. package/dist/ui/crud.d.ts +0 -2
  534. package/dist/ui/crud.js +0 -4
  535. package/dist/ui/crud.js.map +0 -1
  536. package/dist/ui/crud.mjs +0 -3
  537. package/dist/ui/crud.mjs.map +0 -1
  538. package/dist/ui/data-display.d.mts +0 -596
  539. package/dist/ui/data-display.d.ts +0 -596
  540. package/dist/ui/data-display.js +0 -5307
  541. package/dist/ui/data-display.js.map +0 -1
  542. package/dist/ui/data-display.mjs +0 -5212
  543. package/dist/ui/data-display.mjs.map +0 -1
  544. package/dist/ui/feedback.d.mts +0 -55
  545. package/dist/ui/feedback.d.ts +0 -55
  546. package/dist/ui/feedback.js +0 -2608
  547. package/dist/ui/feedback.js.map +0 -1
  548. package/dist/ui/feedback.mjs +0 -2526
  549. package/dist/ui/feedback.mjs.map +0 -1
  550. package/dist/ui/forms.d.mts +0 -309
  551. package/dist/ui/forms.d.ts +0 -309
  552. package/dist/ui/forms.js +0 -4656
  553. package/dist/ui/forms.js.map +0 -1
  554. package/dist/ui/forms.mjs +0 -4571
  555. package/dist/ui/forms.mjs.map +0 -1
  556. package/dist/ui/index.d.mts +0 -331
  557. package/dist/ui/index.d.ts +0 -331
  558. package/dist/ui/index.js +0 -16953
  559. package/dist/ui/index.js.map +0 -1
  560. package/dist/ui/index.mjs +0 -16598
  561. package/dist/ui/index.mjs.map +0 -1
  562. package/dist/ui/primitives/client.d.mts +0 -61
  563. package/dist/ui/primitives/client.d.ts +0 -61
  564. package/dist/ui/primitives/client.js +0 -3408
  565. package/dist/ui/primitives/client.js.map +0 -1
  566. package/dist/ui/primitives/client.mjs +0 -3256
  567. package/dist/ui/primitives/client.mjs.map +0 -1
  568. package/dist/ui/primitives.d.mts +0 -113
  569. package/dist/ui/primitives.d.ts +0 -113
  570. package/dist/ui/primitives.js +0 -3356
  571. package/dist/ui/primitives.js.map +0 -1
  572. package/dist/ui/primitives.mjs +0 -3227
  573. package/dist/ui/primitives.mjs.map +0 -1
  574. package/dist/user/index.d.mts +0 -228
  575. package/dist/user/index.d.ts +0 -228
  576. package/dist/user/index.js +0 -4306
  577. package/dist/user/index.js.map +0 -1
  578. package/dist/user/index.mjs +0 -4260
  579. package/dist/user/index.mjs.map +0 -1
  580. package/dist/utils/index.d.mts +0 -205
  581. package/dist/utils/index.d.ts +0 -205
  582. package/dist/utils/index.js +0 -574
  583. package/dist/utils/index.js.map +0 -1
  584. package/dist/utils/index.mjs +0 -514
  585. package/dist/utils/index.mjs.map +0 -1
  586. package/dist/workflow/index.d.mts +0 -40
  587. package/dist/workflow/index.d.ts +0 -40
  588. package/dist/workflow/index.js +0 -3710
  589. package/dist/workflow/index.js.map +0 -1
  590. package/dist/workflow/index.mjs +0 -3677
  591. package/dist/workflow/index.mjs.map +0 -1
@@ -0,0 +1,334 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { crudService } from "./crud-service";
3
+
4
+ // Mock crudConfig
5
+ vi.mock("@/configs/crud", () => ({
6
+ crudConfig: {
7
+ service: {
8
+ cacheEnabled: false,
9
+ cacheBusterEnabled: false,
10
+ },
11
+ },
12
+ }));
13
+
14
+ // Mock logger
15
+ vi.mock("@/lib/logger", () => ({
16
+ logger: {
17
+ debug: vi.fn(),
18
+ error: vi.fn(),
19
+ },
20
+ }));
21
+
22
+ // Save original fetch
23
+ const originalFetch = global.fetch;
24
+
25
+ describe("CrudService", () => {
26
+ const mockEndpoint = "/api/test";
27
+
28
+ beforeEach(() => {
29
+ global.fetch = vi.fn();
30
+ });
31
+
32
+ afterEach(() => {
33
+ global.fetch = originalFetch;
34
+ vi.clearAllMocks();
35
+ });
36
+
37
+ describe("fetch", () => {
38
+ it("should fetch data with correct query params", async () => {
39
+ const mockData = { data: [], total: 0, page: 1, pageSize: 10 };
40
+ const mockResponse = {
41
+ ok: true,
42
+ headers: { get: () => "application/json" },
43
+ json: () => Promise.resolve(mockData),
44
+ };
45
+ vi.mocked(global.fetch).mockResolvedValue(mockResponse as any);
46
+
47
+ const params = { page: 1, pageSize: 10, search: "test" };
48
+ const result = await crudService.fetch(mockEndpoint, params);
49
+
50
+ expect(global.fetch).toHaveBeenCalledWith(
51
+ expect.stringContaining("/api/test?page=1&pageSize=10&search=test"),
52
+ expect.any(Object),
53
+ );
54
+ expect(result).toEqual(mockData);
55
+ });
56
+
57
+ it("should handle API errors", async () => {
58
+ const mockResponse = {
59
+ ok: false,
60
+ status: 500,
61
+ statusText: "Internal Server Error",
62
+ text: () => Promise.resolve("Error details"),
63
+ headers: { get: () => "text/plain" },
64
+ };
65
+ vi.mocked(global.fetch).mockResolvedValue(mockResponse as any);
66
+
67
+ await expect(
68
+ crudService.fetch(mockEndpoint, { page: 1, pageSize: 10 }),
69
+ ).rejects.toThrow("Failed to fetch: Internal Server Error");
70
+ });
71
+
72
+ it("should throw error for invalid content type", async () => {
73
+ const mockResponse = {
74
+ ok: true,
75
+ headers: { get: () => "text/html" },
76
+ text: () => Promise.resolve("<html>Error</html>"),
77
+ };
78
+ vi.mocked(global.fetch).mockResolvedValue(mockResponse as any);
79
+
80
+ await expect(
81
+ crudService.fetch(mockEndpoint, { page: 1, pageSize: 10 }),
82
+ ).rejects.toThrow("Invalid response format");
83
+ });
84
+
85
+ it("should handle cache buster when enabled", async () => {
86
+ // Re-mock config for this test
87
+ vi.resetModules();
88
+ vi.doMock("@/configs/crud", () => ({
89
+ crudConfig: {
90
+ service: {
91
+ cacheEnabled: false,
92
+ cacheBusterEnabled: true,
93
+ },
94
+ },
95
+ }));
96
+
97
+ const { crudService: freshService } = await import("./crud-service");
98
+
99
+ const mockResponse = {
100
+ ok: true,
101
+ headers: { get: () => "application/json" },
102
+ json: () => Promise.resolve({ data: [] }),
103
+ };
104
+ vi.mocked(global.fetch).mockResolvedValue(mockResponse as any);
105
+
106
+ await freshService.fetch(mockEndpoint, { page: 1, pageSize: 10 });
107
+
108
+ expect(global.fetch).toHaveBeenCalledWith(
109
+ expect.stringMatching(/_t=\d+/),
110
+ expect.any(Object),
111
+ );
112
+ });
113
+ });
114
+
115
+ describe("create", () => {
116
+ it("should create a record successfully", async () => {
117
+ const mockData = { id: 1, name: "Test" };
118
+ const mockResponse = {
119
+ ok: true,
120
+ headers: { get: () => "application/json" },
121
+ json: () => Promise.resolve(mockData),
122
+ };
123
+ vi.mocked(global.fetch).mockResolvedValue(mockResponse as any);
124
+
125
+ const payload = { name: "Test" };
126
+ const result = await crudService.create(mockEndpoint, payload);
127
+
128
+ expect(global.fetch).toHaveBeenCalledWith(
129
+ mockEndpoint,
130
+ expect.objectContaining({
131
+ method: "POST",
132
+ body: JSON.stringify(payload),
133
+ }),
134
+ );
135
+ expect(result).toEqual(mockData);
136
+ });
137
+
138
+ it("should handle creation errors with JSON response", async () => {
139
+ const errorResponse = {
140
+ ok: false,
141
+ status: 400,
142
+ statusText: "Bad Request",
143
+ headers: { get: () => "application/json" },
144
+ json: () =>
145
+ Promise.resolve({ message: "Validation failed", field: "name" }),
146
+ };
147
+ vi.mocked(global.fetch).mockResolvedValue(errorResponse as any);
148
+
149
+ try {
150
+ await crudService.create(mockEndpoint, { name: "" });
151
+ } catch (e: any) {
152
+ expect(e.message).toBe("Validation failed");
153
+ expect(e.field).toBe("name");
154
+ }
155
+ });
156
+
157
+ it("should handle creation errors with non-JSON response", async () => {
158
+ const errorResponse = {
159
+ ok: false,
160
+ status: 500,
161
+ statusText: "Error",
162
+ headers: { get: () => "text/plain" },
163
+ text: () => Promise.resolve("Server Error"),
164
+ };
165
+ vi.mocked(global.fetch).mockResolvedValue(errorResponse as any);
166
+
167
+ await expect(crudService.create(mockEndpoint, {})).rejects.toThrow(
168
+ "Server Error",
169
+ );
170
+ });
171
+
172
+ it("should throw for invalid response content type", async () => {
173
+ const mockResponse = {
174
+ ok: true,
175
+ headers: { get: () => "text/html" },
176
+ text: () => Promise.resolve("<html></html>"),
177
+ };
178
+ vi.mocked(global.fetch).mockResolvedValue(mockResponse as any);
179
+
180
+ await expect(crudService.create(mockEndpoint, {})).rejects.toThrow(
181
+ "Invalid response format",
182
+ );
183
+ });
184
+ });
185
+
186
+ describe("update", () => {
187
+ it("should update a record successfully", async () => {
188
+ const mockData = { id: "123", name: "Updated" };
189
+ const mockResponse = {
190
+ ok: true,
191
+ headers: { get: () => "application/json" },
192
+ json: () => Promise.resolve(mockData),
193
+ };
194
+ vi.mocked(global.fetch).mockResolvedValue(mockResponse as any);
195
+
196
+ const payload = { name: "Updated" };
197
+ const result = await crudService.update(mockEndpoint, "123", payload);
198
+
199
+ expect(global.fetch).toHaveBeenCalledWith(
200
+ `${mockEndpoint}/123`,
201
+ expect.objectContaining({
202
+ method: "PUT",
203
+ body: JSON.stringify(payload),
204
+ }),
205
+ );
206
+ expect(result).toEqual(mockData);
207
+ });
208
+
209
+ it("should handle update errors", async () => {
210
+ const errorResponse = {
211
+ ok: false,
212
+ status: 400,
213
+ headers: { get: () => "application/json" },
214
+ json: () => Promise.resolve({ error: "Update failed" }),
215
+ };
216
+ vi.mocked(global.fetch).mockResolvedValue(errorResponse as any);
217
+
218
+ await expect(crudService.update(mockEndpoint, "123", {})).rejects.toThrow(
219
+ "Update failed",
220
+ );
221
+ });
222
+
223
+ it("should handle non-JSON error response", async () => {
224
+ const errorResponse = {
225
+ ok: false,
226
+ status: 500,
227
+ headers: { get: () => "text/html" },
228
+ text: () => Promise.resolve("<html>Error</html>"),
229
+ url: "/api/test",
230
+ };
231
+ vi.mocked(global.fetch).mockResolvedValue(errorResponse as any);
232
+
233
+ await expect(crudService.update(mockEndpoint, "123", {})).rejects.toThrow(
234
+ "API endpoint returned HTML",
235
+ );
236
+ });
237
+
238
+ it("should throw if success response is not JSON", async () => {
239
+ const mockResponse = {
240
+ ok: true,
241
+ headers: { get: () => "text/plain" },
242
+ text: () => Promise.resolve("ok"),
243
+ };
244
+ vi.mocked(global.fetch).mockResolvedValue(mockResponse as any);
245
+
246
+ await expect(crudService.update(mockEndpoint, "123", {})).rejects.toThrow(
247
+ "Invalid response format",
248
+ );
249
+ });
250
+ });
251
+
252
+ describe("delete", () => {
253
+ it("should delete a record successfully", async () => {
254
+ const mockResponse = {
255
+ ok: true,
256
+ };
257
+ vi.mocked(global.fetch).mockResolvedValue(mockResponse as any);
258
+
259
+ await crudService.delete(mockEndpoint, "123");
260
+
261
+ expect(global.fetch).toHaveBeenCalledWith(
262
+ `${mockEndpoint}/123`,
263
+ expect.objectContaining({
264
+ method: "DELETE",
265
+ }),
266
+ );
267
+ });
268
+
269
+ it("should handle delete errors", async () => {
270
+ const errorResponse = {
271
+ ok: false,
272
+ status: 404,
273
+ statusText: "Not Found",
274
+ headers: { get: () => "application/json" },
275
+ text: () => Promise.resolve("Not Found"),
276
+ json: () => Promise.resolve({ message: "Not Found" }),
277
+ };
278
+ vi.mocked(global.fetch).mockResolvedValue(errorResponse as any);
279
+
280
+ await expect(crudService.delete(mockEndpoint, "999")).rejects.toThrow(
281
+ "Not Found",
282
+ );
283
+ });
284
+
285
+ it("should handle non-JSON delete errors", async () => {
286
+ const errorResponse = {
287
+ ok: false,
288
+ headers: { get: () => "text/plain" },
289
+ text: () => Promise.resolve("Error"),
290
+ statusText: "Error",
291
+ };
292
+ vi.mocked(global.fetch).mockResolvedValue(errorResponse as any);
293
+
294
+ await expect(crudService.delete(mockEndpoint, "999")).rejects.toThrow(
295
+ "Error",
296
+ );
297
+ });
298
+ });
299
+
300
+ describe("deleteMany", () => {
301
+ it("should delete multiple records successfully", async () => {
302
+ const mockResponse = {
303
+ ok: true,
304
+ };
305
+ vi.mocked(global.fetch).mockResolvedValue(mockResponse as any);
306
+
307
+ const ids = ["1", "2", "3"];
308
+ await crudService.deleteMany(mockEndpoint, ids);
309
+
310
+ expect(global.fetch).toHaveBeenCalledWith(
311
+ `${mockEndpoint}/bulk`,
312
+ expect.objectContaining({
313
+ method: "DELETE",
314
+ body: JSON.stringify({ ids }),
315
+ }),
316
+ );
317
+ });
318
+
319
+ it("should handle bulk delete errors", async () => {
320
+ const errorResponse = {
321
+ ok: false,
322
+ status: 500,
323
+ statusText: "Error",
324
+ headers: { get: () => "application/json" },
325
+ json: () => Promise.resolve({ error: "Bulk delete failed" }),
326
+ };
327
+ vi.mocked(global.fetch).mockResolvedValue(errorResponse as any);
328
+
329
+ await expect(crudService.deleteMany(mockEndpoint, ["1"])).rejects.toThrow(
330
+ "Bulk delete failed",
331
+ );
332
+ });
333
+ });
334
+ });
@@ -0,0 +1,358 @@
1
+ import type { CrudQueryParams, CrudResponse } from "../../types";
2
+
3
+ import { crudConfig } from "../../configs";
4
+
5
+ import { buildQueryString } from "./crud-utils";
6
+ import { logger } from "../../utils";
7
+
8
+ class CrudService {
9
+ /**
10
+ * Fetch list of records
11
+ */
12
+ async fetch<T = Record<string, unknown>>(
13
+ endpoint: string,
14
+ params: CrudQueryParams,
15
+ signal?: AbortSignal,
16
+ ): Promise<CrudResponse<T>> {
17
+ const queryString = buildQueryString(params);
18
+ // Add cache buster if enabled (configure via CRUD_SERVICE_CACHE_BUSTER_ENABLED)
19
+ const cacheBuster = crudConfig.service.cacheBusterEnabled
20
+ ? `_t=${Date.now()}`
21
+ : "";
22
+ const url = queryString
23
+ ? cacheBuster
24
+ ? `${endpoint}?${queryString}&${cacheBuster}`
25
+ : `${endpoint}?${queryString}`
26
+ : cacheBuster
27
+ ? `${endpoint}?${cacheBuster}`
28
+ : endpoint;
29
+
30
+ logger.debug("Fetching from: " + url);
31
+ logger.debug("Query params:", { params });
32
+
33
+ // Configure cache based on CRUD_SERVICE_CACHE_ENABLED env variable
34
+ const fetchOptions: RequestInit = {
35
+ cache: crudConfig.service.cacheEnabled ? "default" : "no-store",
36
+ headers: crudConfig.service.cacheEnabled
37
+ ? {}
38
+ : {
39
+ "Cache-Control": "no-cache, no-store, must-revalidate",
40
+ Pragma: "no-cache",
41
+ Expires: "0",
42
+ },
43
+ };
44
+
45
+ const response = await fetch(url, { ...fetchOptions, signal });
46
+
47
+ // Check Content-Type first
48
+ const contentType = response.headers.get("content-type");
49
+ const isJSON = contentType && contentType.includes("application/json");
50
+
51
+ if (!response.ok) {
52
+ const errorText = await response.text();
53
+ logger.error("API Error", undefined, {
54
+ status: response.status,
55
+ errorText: errorText.substring(0, 200),
56
+ });
57
+ throw new Error(`Failed to fetch: ${response.statusText}`);
58
+ }
59
+
60
+ // Check Content-Type to ensure it's JSON
61
+ if (!isJSON) {
62
+ const text = await response.text();
63
+ logger.error("Invalid Content-Type", undefined, { contentType });
64
+ logger.error("Response text", undefined, {
65
+ text: text.substring(0, 200),
66
+ });
67
+ throw new Error(
68
+ `Invalid response format. Expected JSON but got ${contentType || "unknown"}. The endpoint might not exist or returned an error page.`,
69
+ );
70
+ }
71
+
72
+ const jsonData = await response.json();
73
+ logger.debug("API Response", { jsonData });
74
+
75
+ // Ensure response matches CrudResponse format
76
+ if (jsonData.items && !jsonData.data) {
77
+ // Map items to data if needed
78
+ return {
79
+ data: jsonData.items,
80
+ total: jsonData.total ?? 0,
81
+ page: jsonData.page ?? 1,
82
+ pageSize: jsonData.pageSize ?? 10,
83
+ };
84
+ }
85
+
86
+ return jsonData;
87
+ }
88
+
89
+ /**
90
+ * Create a new record
91
+ */
92
+ async create(
93
+ endpoint: string,
94
+ data: Record<string, unknown>,
95
+ ): Promise<Record<string, unknown>> {
96
+ const method = "POST";
97
+
98
+ // Debug log for user-suppliers
99
+ if (endpoint.includes("user-suppliers")) {
100
+ logger.debug("CrudService.create - Sending data", {
101
+ endpoint,
102
+ data,
103
+ userId: data.userId,
104
+ supplierId: data.supplierId,
105
+ userIdType: typeof data.userId,
106
+ supplierIdType: typeof data.supplierId,
107
+ userIdValue: data.userId,
108
+ supplierIdValue: data.supplierId,
109
+ });
110
+ }
111
+
112
+ const response = await fetch(endpoint, {
113
+ method,
114
+ headers: {
115
+ "Content-Type": "application/json",
116
+ },
117
+ body: JSON.stringify(data),
118
+ });
119
+
120
+ if (!response.ok) {
121
+ const contentType = response.headers.get("content-type");
122
+ let error: {
123
+ message?: string;
124
+ error?: string;
125
+ field?: string;
126
+ details?: unknown[];
127
+ } = { message: response.statusText };
128
+
129
+ if (contentType && contentType.includes("application/json")) {
130
+ try {
131
+ error = await response.json();
132
+ } catch {
133
+ const errorText = await response.text();
134
+ logger.error("Failed to parse error response", undefined, {
135
+ errorText: errorText.substring(0, 200),
136
+ });
137
+ throw new Error(
138
+ errorText.substring(0, 200) ||
139
+ `Failed to ${method}: ${response.statusText}`,
140
+ );
141
+ }
142
+ } else {
143
+ const errorText = await response.text();
144
+ logger.error("Non-JSON error response", undefined, {
145
+ errorText: errorText.substring(0, 200),
146
+ });
147
+ throw new Error(
148
+ errorText.substring(0, 200) ||
149
+ `Failed to ${method}: ${response.statusText}`,
150
+ );
151
+ }
152
+
153
+ const errorMessage =
154
+ error?.error ||
155
+ error?.message ||
156
+ `Failed to ${method}: ${response.statusText}`;
157
+ const apiError = new Error(errorMessage);
158
+ // Attach additional error information for better error handling
159
+ if (error.field) {
160
+ (apiError as Error & { field?: string }).field = error.field;
161
+ }
162
+ if (error.details) {
163
+ (apiError as Error & { details?: unknown[] }).details = error.details;
164
+ }
165
+ throw apiError;
166
+ }
167
+
168
+ const contentType = response.headers.get("content-type");
169
+ if (!contentType || !contentType.includes("application/json")) {
170
+ const text = await response.text();
171
+ logger.error("Invalid Content-Type", undefined, { contentType });
172
+ throw new Error(
173
+ `Invalid response format. Expected JSON but got ${contentType || "unknown"}`,
174
+ );
175
+ }
176
+
177
+ return response.json();
178
+ }
179
+
180
+ /**
181
+ * Update an existing record
182
+ */
183
+ async update(
184
+ endpoint: string,
185
+ id: string,
186
+ data: Record<string, unknown>,
187
+ ): Promise<Record<string, unknown>> {
188
+ const url = `${endpoint}/${id}`;
189
+ logger.debug("Updating record", { url, id, data });
190
+
191
+ const response = await fetch(url, {
192
+ method: "PUT",
193
+ headers: {
194
+ "Content-Type": "application/json",
195
+ },
196
+ body: JSON.stringify(data),
197
+ });
198
+
199
+ // Check Content-Type first
200
+ const contentType = response.headers.get("content-type");
201
+ const isJSON = contentType && contentType.includes("application/json");
202
+
203
+ if (!response.ok) {
204
+ let error: {
205
+ message?: string;
206
+ error?: string;
207
+ field?: string;
208
+ details?: unknown[];
209
+ } = { message: response.statusText };
210
+
211
+ if (isJSON) {
212
+ try {
213
+ error = await response.json();
214
+ } catch {
215
+ const errorText = await response.text();
216
+ logger.error("Failed to parse error response", undefined, {
217
+ errorText: errorText.substring(0, 200),
218
+ });
219
+ }
220
+ } else {
221
+ const errorText = await response.text();
222
+ logger.error("Non-JSON error response", undefined, {
223
+ status: response.status,
224
+ statusText: response.statusText,
225
+ contentType,
226
+ url: response.url,
227
+ text: errorText.substring(0, 500),
228
+ });
229
+
230
+ // Check if it's HTML (likely redirect or error page)
231
+ if (errorText.includes("<!DOCTYPE") || errorText.includes("<html")) {
232
+ throw new Error(
233
+ `API endpoint returned HTML instead of JSON. This might be a redirect to login page or an error page. Status: ${response.status}, URL: ${response.url}`,
234
+ );
235
+ }
236
+ }
237
+
238
+ const errorMessage =
239
+ error?.error ||
240
+ error?.message ||
241
+ `Failed to update: ${response.status} ${response.statusText}`;
242
+ const apiError = new Error(errorMessage);
243
+ // Attach additional error information for better error handling
244
+ if (error.field) {
245
+ (apiError as Error & { field?: string }).field = error.field;
246
+ }
247
+ if (error.details) {
248
+ (apiError as Error & { details?: unknown[] }).details = error.details;
249
+ }
250
+ throw apiError;
251
+ }
252
+
253
+ if (!isJSON) {
254
+ const text = await response.text();
255
+ logger.error("Invalid Content-Type for successful response", undefined, {
256
+ contentType,
257
+ status: response.status,
258
+ url: response.url,
259
+ text: text.substring(0, 500),
260
+ });
261
+
262
+ // Check if it's HTML
263
+ if (text.includes("<!DOCTYPE") || text.includes("<html")) {
264
+ throw new Error(
265
+ `API endpoint returned HTML instead of JSON. This might be a redirect or error page. Status: ${response.status}, URL: ${response.url}`,
266
+ );
267
+ }
268
+
269
+ throw new Error(
270
+ `Invalid response format. Expected JSON but got ${contentType || "unknown"}`,
271
+ );
272
+ }
273
+
274
+ return response.json();
275
+ }
276
+
277
+ /**
278
+ * Delete a record
279
+ */
280
+ async delete(endpoint: string, id: string): Promise<void> {
281
+ const response = await fetch(`${endpoint}/${id}`, {
282
+ method: "DELETE",
283
+ });
284
+
285
+ if (!response.ok) {
286
+ const contentType = response.headers.get("content-type");
287
+ let error: { message?: string; error?: string } = {
288
+ message: response.statusText,
289
+ };
290
+
291
+ if (contentType && contentType.includes("application/json")) {
292
+ try {
293
+ error = await response.json();
294
+ } catch {
295
+ const errorText = await response.text();
296
+ logger.error("Failed to parse error response", undefined, {
297
+ errorText: errorText.substring(0, 200),
298
+ });
299
+ }
300
+ } else {
301
+ const errorText = await response.text();
302
+ logger.error("Non-JSON error response", undefined, {
303
+ errorText: errorText.substring(0, 200),
304
+ });
305
+ }
306
+
307
+ const errorMessage =
308
+ error?.error ||
309
+ error?.message ||
310
+ `Failed to delete: ${response.statusText}`;
311
+ throw new Error(errorMessage);
312
+ }
313
+ }
314
+
315
+ /**
316
+ * Delete multiple records
317
+ */
318
+ async deleteMany(endpoint: string, ids: string[]): Promise<void> {
319
+ const response = await fetch(`${endpoint}/bulk`, {
320
+ method: "DELETE",
321
+ headers: {
322
+ "Content-Type": "application/json",
323
+ },
324
+ body: JSON.stringify({ ids }),
325
+ });
326
+
327
+ if (!response.ok) {
328
+ const contentType = response.headers.get("content-type");
329
+ let error: { message?: string; error?: string } = {
330
+ message: response.statusText,
331
+ };
332
+
333
+ if (contentType && contentType.includes("application/json")) {
334
+ try {
335
+ error = await response.json();
336
+ } catch {
337
+ const errorText = await response.text();
338
+ logger.error("Failed to parse error response", undefined, {
339
+ errorText: errorText.substring(0, 200),
340
+ });
341
+ }
342
+ } else {
343
+ const errorText = await response.text();
344
+ logger.error("Non-JSON error response", undefined, {
345
+ errorText: errorText.substring(0, 200),
346
+ });
347
+ }
348
+
349
+ const errorMessage =
350
+ error?.error ||
351
+ error?.message ||
352
+ `Failed to delete: ${response.statusText}`;
353
+ throw new Error(errorMessage);
354
+ }
355
+ }
356
+ }
357
+
358
+ export const crudService = new CrudService();