@everysk/apps-sdk 0.2.0 → 0.3.0-beta-20261016180126

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 (349) hide show
  1. package/README.md +298 -12
  2. package/dist/EveryskApp.d.ts +34 -2
  3. package/dist/EveryskApp.d.ts.map +1 -1
  4. package/dist/EveryskApp.js +35 -2
  5. package/dist/EveryskApp.js.map +1 -1
  6. package/dist/agGrid/handleRowsScrollEnd.d.ts +53 -0
  7. package/dist/agGrid/handleRowsScrollEnd.d.ts.map +1 -0
  8. package/dist/agGrid/handleRowsScrollEnd.js +47 -0
  9. package/dist/agGrid/handleRowsScrollEnd.js.map +1 -0
  10. package/dist/agGrid/index.d.ts +2 -0
  11. package/dist/agGrid/index.d.ts.map +1 -1
  12. package/dist/agGrid/index.js +2 -1
  13. package/dist/api/datastore.d.ts +10 -8
  14. package/dist/api/datastore.d.ts.map +1 -1
  15. package/dist/api/datastore.js +24 -55
  16. package/dist/api/datastore.js.map +1 -1
  17. package/dist/api/entityQuery.d.ts +46 -41
  18. package/dist/api/entityQuery.d.ts.map +1 -1
  19. package/dist/api/entityQuery.js +55 -14
  20. package/dist/api/entityQuery.js.map +1 -1
  21. package/dist/api/file.d.ts +26 -9
  22. package/dist/api/file.d.ts.map +1 -1
  23. package/dist/api/file.js +45 -55
  24. package/dist/api/file.js.map +1 -1
  25. package/dist/api/portfolio.d.ts +11 -8
  26. package/dist/api/portfolio.d.ts.map +1 -1
  27. package/dist/api/portfolio.js +24 -55
  28. package/dist/api/portfolio.js.map +1 -1
  29. package/dist/api/profile.d.ts +3 -2
  30. package/dist/api/profile.d.ts.map +1 -1
  31. package/dist/api/profile.js +4 -9
  32. package/dist/api/profile.js.map +1 -1
  33. package/dist/api/request.d.ts +106 -0
  34. package/dist/api/request.d.ts.map +1 -0
  35. package/dist/api/request.js +132 -0
  36. package/dist/api/request.js.map +1 -0
  37. package/dist/api/websocketsConfig.d.ts +7 -2
  38. package/dist/api/websocketsConfig.d.ts.map +1 -1
  39. package/dist/api/websocketsConfig.js +2 -10
  40. package/dist/api/websocketsConfig.js.map +1 -1
  41. package/dist/api/workflow.d.ts +84 -89
  42. package/dist/api/workflow.d.ts.map +1 -1
  43. package/dist/api/workflow.js +121 -208
  44. package/dist/api/workflow.js.map +1 -1
  45. package/dist/api/workspace.d.ts +18 -8
  46. package/dist/api/workspace.d.ts.map +1 -1
  47. package/dist/api/workspace.js +21 -26
  48. package/dist/api/workspace.js.map +1 -1
  49. package/dist/components/ui/Footer/index.d.ts.map +1 -1
  50. package/dist/components/ui/Footer/index.js.map +1 -1
  51. package/dist/components/ui/GlobalLoading/index.d.ts.map +1 -1
  52. package/dist/components/ui/GlobalLoading/index.js.map +1 -1
  53. package/dist/components/ui/PageContainer/index.d.ts +1 -1
  54. package/dist/components/ui/PageContainer/index.d.ts.map +1 -1
  55. package/dist/components/ui/PageContainer/index.js.map +1 -1
  56. package/dist/components/ui/Toolbar/index.d.ts +40 -3
  57. package/dist/components/ui/Toolbar/index.d.ts.map +1 -1
  58. package/dist/components/ui/Toolbar/index.js +42 -15
  59. package/dist/components/ui/Toolbar/index.js.map +1 -1
  60. package/dist/contexts/appAlertContext/provider.js.map +1 -1
  61. package/dist/contexts/appAlertContext/types.d.ts.map +1 -1
  62. package/dist/contexts/appConfigContext/index.d.ts.map +1 -1
  63. package/dist/contexts/appConfigContext/index.js.map +1 -1
  64. package/dist/contexts/appConfigContext/provider.d.ts.map +1 -1
  65. package/dist/contexts/appConfigContext/provider.js.map +1 -1
  66. package/dist/contexts/webSocketContext/handler.d.ts +3 -2
  67. package/dist/contexts/webSocketContext/handler.d.ts.map +1 -1
  68. package/dist/contexts/webSocketContext/handler.js.map +1 -1
  69. package/dist/contexts/webSocketContext/hooks/useWebSocket/index.d.ts +1 -1
  70. package/dist/contexts/webSocketContext/hooks/useWebSocket/index.js +1 -1
  71. package/dist/contexts/webSocketContext/hooks/useWebSocket/index.js.map +1 -1
  72. package/dist/contexts/webSocketContext/provider.d.ts +6 -3
  73. package/dist/contexts/webSocketContext/provider.d.ts.map +1 -1
  74. package/dist/contexts/webSocketContext/provider.js +42 -7
  75. package/dist/contexts/webSocketContext/provider.js.map +1 -1
  76. package/dist/contexts/webSocketContext/types.d.ts +7 -5
  77. package/dist/contexts/webSocketContext/types.d.ts.map +1 -1
  78. package/dist/file/index.d.ts +2 -0
  79. package/dist/file/index.d.ts.map +1 -1
  80. package/dist/hooks/datastore/useDatastoreMutations.d.ts +4 -4
  81. package/dist/hooks/datastore/useDatastoreMutations.d.ts.map +1 -1
  82. package/dist/hooks/datastore/useDatastoreMutations.js +17 -55
  83. package/dist/hooks/datastore/useDatastoreMutations.js.map +1 -1
  84. package/dist/hooks/datastore/useFetchDatastore.d.ts +30 -41
  85. package/dist/hooks/datastore/useFetchDatastore.d.ts.map +1 -1
  86. package/dist/hooks/datastore/useFetchDatastore.js +25 -59
  87. package/dist/hooks/datastore/useFetchDatastore.js.map +1 -1
  88. package/dist/hooks/datastore/useFetchDatastores.d.ts +47 -52
  89. package/dist/hooks/datastore/useFetchDatastores.d.ts.map +1 -1
  90. package/dist/hooks/datastore/useFetchDatastores.js +55 -70
  91. package/dist/hooks/datastore/useFetchDatastores.js.map +1 -1
  92. package/dist/hooks/file/fileData.d.ts +17 -0
  93. package/dist/hooks/file/fileData.d.ts.map +1 -0
  94. package/dist/hooks/file/fileData.js +10 -0
  95. package/dist/hooks/file/fileData.js.map +1 -0
  96. package/dist/hooks/file/useFetchFile.d.ts +38 -58
  97. package/dist/hooks/file/useFetchFile.d.ts.map +1 -1
  98. package/dist/hooks/file/useFetchFile.js +26 -66
  99. package/dist/hooks/file/useFetchFile.js.map +1 -1
  100. package/dist/hooks/file/useFetchFiles.d.ts +18 -52
  101. package/dist/hooks/file/useFetchFiles.d.ts.map +1 -1
  102. package/dist/hooks/file/useFetchFiles.js +53 -69
  103. package/dist/hooks/file/useFetchFiles.js.map +1 -1
  104. package/dist/hooks/file/useFileMutations.d.ts +9 -8
  105. package/dist/hooks/file/useFileMutations.d.ts.map +1 -1
  106. package/dist/hooks/file/useFileMutations.js +23 -60
  107. package/dist/hooks/file/useFileMutations.js.map +1 -1
  108. package/dist/hooks/portfolio/useFetchPortfolio.d.ts +16 -50
  109. package/dist/hooks/portfolio/useFetchPortfolio.d.ts.map +1 -1
  110. package/dist/hooks/portfolio/useFetchPortfolio.js +15 -63
  111. package/dist/hooks/portfolio/useFetchPortfolio.js.map +1 -1
  112. package/dist/hooks/portfolio/useFetchPortfolios.d.ts +13 -52
  113. package/dist/hooks/portfolio/useFetchPortfolios.d.ts.map +1 -1
  114. package/dist/hooks/portfolio/useFetchPortfolios.js +29 -71
  115. package/dist/hooks/portfolio/useFetchPortfolios.js.map +1 -1
  116. package/dist/hooks/portfolio/usePortfolioMutations.d.ts +8 -8
  117. package/dist/hooks/portfolio/usePortfolioMutations.d.ts.map +1 -1
  118. package/dist/hooks/portfolio/usePortfolioMutations.js +20 -58
  119. package/dist/hooks/portfolio/usePortfolioMutations.js.map +1 -1
  120. package/dist/hooks/profile/useFetchProfile.d.ts +18 -44
  121. package/dist/hooks/profile/useFetchProfile.d.ts.map +1 -1
  122. package/dist/hooks/profile/useFetchProfile.js +16 -48
  123. package/dist/hooks/profile/useFetchProfile.js.map +1 -1
  124. package/dist/hooks/useAxios.js.map +1 -1
  125. package/dist/hooks/useEntityInfiniteQuery.d.ts +88 -0
  126. package/dist/hooks/useEntityInfiniteQuery.d.ts.map +1 -0
  127. package/dist/hooks/useEntityInfiniteQuery.js +111 -0
  128. package/dist/hooks/useEntityInfiniteQuery.js.map +1 -0
  129. package/dist/hooks/useEntityMutation.d.ts +47 -0
  130. package/dist/hooks/useEntityMutation.d.ts.map +1 -0
  131. package/dist/hooks/useEntityMutation.js +58 -0
  132. package/dist/hooks/useEntityMutation.js.map +1 -0
  133. package/dist/hooks/useEntityQuery.d.ts +68 -0
  134. package/dist/hooks/useEntityQuery.d.ts.map +1 -0
  135. package/dist/hooks/useEntityQuery.js +75 -0
  136. package/dist/hooks/useEntityQuery.js.map +1 -0
  137. package/dist/hooks/workflow/useFetchWorkerExecution.d.ts +17 -34
  138. package/dist/hooks/workflow/useFetchWorkerExecution.d.ts.map +1 -1
  139. package/dist/hooks/workflow/useFetchWorkerExecution.js +16 -46
  140. package/dist/hooks/workflow/useFetchWorkerExecution.js.map +1 -1
  141. package/dist/hooks/workflow/useFetchWorkerExecutions.d.ts +179 -41
  142. package/dist/hooks/workflow/useFetchWorkerExecutions.d.ts.map +1 -1
  143. package/dist/hooks/workflow/useFetchWorkerExecutions.js +29 -62
  144. package/dist/hooks/workflow/useFetchWorkerExecutions.js.map +1 -1
  145. package/dist/hooks/workflow/useFetchWorkflow.d.ts +16 -35
  146. package/dist/hooks/workflow/useFetchWorkflow.d.ts.map +1 -1
  147. package/dist/hooks/workflow/useFetchWorkflow.js +15 -48
  148. package/dist/hooks/workflow/useFetchWorkflow.js.map +1 -1
  149. package/dist/hooks/workflow/useFetchWorkflowExecution.d.ts +17 -34
  150. package/dist/hooks/workflow/useFetchWorkflowExecution.d.ts.map +1 -1
  151. package/dist/hooks/workflow/useFetchWorkflowExecution.js +16 -46
  152. package/dist/hooks/workflow/useFetchWorkflowExecution.js.map +1 -1
  153. package/dist/hooks/workflow/useFetchWorkflowExecutions.d.ts +22 -36
  154. package/dist/hooks/workflow/useFetchWorkflowExecutions.d.ts.map +1 -1
  155. package/dist/hooks/workflow/useFetchWorkflowExecutions.js +43 -56
  156. package/dist/hooks/workflow/useFetchWorkflowExecutions.js.map +1 -1
  157. package/dist/hooks/workflow/useFetchWorkflows.d.ts +20 -37
  158. package/dist/hooks/workflow/useFetchWorkflows.d.ts.map +1 -1
  159. package/dist/hooks/workflow/useFetchWorkflows.js +32 -47
  160. package/dist/hooks/workflow/useFetchWorkflows.js.map +1 -1
  161. package/dist/hooks/workflow/useRunWorkflow.d.ts +21 -16
  162. package/dist/hooks/workflow/useRunWorkflow.d.ts.map +1 -1
  163. package/dist/hooks/workflow/useRunWorkflow.js +66 -29
  164. package/dist/hooks/workflow/useRunWorkflow.js.map +1 -1
  165. package/dist/hooks/workflow/useTriggerWorkflow.d.ts +20 -0
  166. package/dist/hooks/workflow/useTriggerWorkflow.d.ts.map +1 -0
  167. package/dist/hooks/workflow/useTriggerWorkflow.js +32 -0
  168. package/dist/hooks/workflow/useTriggerWorkflow.js.map +1 -0
  169. package/dist/hooks/workspace/useFetchWorkspace.d.ts +19 -34
  170. package/dist/hooks/workspace/useFetchWorkspace.d.ts.map +1 -1
  171. package/dist/hooks/workspace/useFetchWorkspace.js +16 -46
  172. package/dist/hooks/workspace/useFetchWorkspace.js.map +1 -1
  173. package/dist/hooks/workspace/useFetchWorkspaces.d.ts +17 -37
  174. package/dist/hooks/workspace/useFetchWorkspaces.d.ts.map +1 -1
  175. package/dist/hooks/workspace/useFetchWorkspaces.js +25 -47
  176. package/dist/hooks/workspace/useFetchWorkspaces.js.map +1 -1
  177. package/dist/index.d.ts +13 -10
  178. package/dist/index.d.ts.map +1 -1
  179. package/dist/index.js +13 -11
  180. package/dist/lib/abort.d.ts +58 -0
  181. package/dist/lib/abort.d.ts.map +1 -0
  182. package/dist/lib/abort.js +112 -0
  183. package/dist/lib/abort.js.map +1 -0
  184. package/dist/lib/datastoreTable.d.ts +59 -54
  185. package/dist/lib/datastoreTable.d.ts.map +1 -1
  186. package/dist/lib/datastoreTable.js +58 -62
  187. package/dist/lib/datastoreTable.js.map +1 -1
  188. package/dist/lib/file.d.ts +34 -0
  189. package/dist/lib/file.d.ts.map +1 -0
  190. package/dist/lib/file.js +63 -0
  191. package/dist/lib/file.js.map +1 -0
  192. package/dist/lib/queryClient.d.ts.map +1 -1
  193. package/dist/lib/queryClient.js.map +1 -1
  194. package/dist/lib/workflowRun.d.ts +91 -0
  195. package/dist/lib/workflowRun.d.ts.map +1 -0
  196. package/dist/lib/workflowRun.js +224 -0
  197. package/dist/lib/workflowRun.js.map +1 -0
  198. package/dist/socket/index.d.ts +1 -3
  199. package/dist/socket/index.d.ts.map +1 -1
  200. package/dist/socket/index.js +3 -5
  201. package/dist/test/mocks/index.d.ts +1 -1
  202. package/dist/test/mocks/index.d.ts.map +1 -1
  203. package/dist/test/renderWithProviders.d.ts +2 -2
  204. package/dist/test/renderWithProviders.d.ts.map +1 -1
  205. package/dist/test/renderWithProviders.js.map +1 -1
  206. package/dist/test/setup.js.map +1 -1
  207. package/dist/theme/index.d.ts +1 -1
  208. package/dist/theme/index.d.ts.map +1 -1
  209. package/dist/theme/overrides/index.d.ts +4 -2
  210. package/dist/theme/overrides/index.d.ts.map +1 -1
  211. package/dist/theme/overrides/index.js +5 -3
  212. package/dist/theme/overrides/index.js.map +1 -1
  213. package/dist/theme/overrides/muiButton.d.ts +2 -2
  214. package/dist/theme/overrides/muiButton.js.map +1 -1
  215. package/dist/theme/overrides/muiCssBaseline.d.ts.map +1 -1
  216. package/dist/theme/overrides/muiCssBaseline.js.map +1 -1
  217. package/dist/theme/overrides/muiDatePicker.js.map +1 -1
  218. package/dist/theme/overrides/muiFormControl.js.map +1 -1
  219. package/dist/theme/overrides/muiIconButton.d.ts +2 -2
  220. package/dist/theme/overrides/muiIconButton.js.map +1 -1
  221. package/dist/theme/overrides/muiSelect.d.ts.map +1 -1
  222. package/dist/theme/overrides/muiSelect.js.map +1 -1
  223. package/dist/theme/overrides/muiSvgIcon.d.ts.map +1 -1
  224. package/dist/theme/overrides/muiSvgIcon.js.map +1 -1
  225. package/dist/theme/overrides/muiTextField.js.map +1 -1
  226. package/dist/theme/overrides/muiToggleButton.d.ts +2 -2
  227. package/dist/theme/overrides/muiToggleButton.js.map +1 -1
  228. package/dist/theme/overrides/muiToggleButtonGroup.d.ts +2 -2
  229. package/dist/theme/overrides/muiToggleButtonGroup.js.map +1 -1
  230. package/dist/theme/themes/DefaultDark.js +2 -2
  231. package/dist/theme/themes/DefaultDark.js.map +1 -1
  232. package/dist/theme/themes/DefaultLight.js +2 -2
  233. package/dist/theme/themes/DefaultLight.js.map +1 -1
  234. package/dist/theme/themes/EveryskDark.js +2 -2
  235. package/dist/theme/themes/EveryskDark.js.map +1 -1
  236. package/dist/theme/themes/EveryskLight.js +2 -2
  237. package/dist/theme/themes/EveryskLight.js.map +1 -1
  238. package/dist/theme/themes/MidnightEmber.js +2 -2
  239. package/dist/theme/themes/MidnightEmber.js.map +1 -1
  240. package/dist/types/anyRecord.d.ts.map +1 -1
  241. package/dist/types/datastore.d.ts +35 -5
  242. package/dist/types/datastore.d.ts.map +1 -1
  243. package/dist/types/datastoreDataFormat.d.ts +13 -0
  244. package/dist/types/datastoreDataFormat.d.ts.map +1 -0
  245. package/dist/types/entityQuery.d.ts +86 -16
  246. package/dist/types/entityQuery.d.ts.map +1 -1
  247. package/dist/types/file.d.ts +7 -3
  248. package/dist/types/file.d.ts.map +1 -1
  249. package/dist/types/portfolio.d.ts +1 -3
  250. package/dist/types/portfolio.d.ts.map +1 -1
  251. package/dist/types/profile.d.ts +0 -10
  252. package/dist/types/profile.d.ts.map +1 -1
  253. package/dist/types/workflow.d.ts +35 -6
  254. package/dist/types/workflow.d.ts.map +1 -1
  255. package/dist/types/workspace.d.ts +1 -2
  256. package/dist/types/workspace.d.ts.map +1 -1
  257. package/dist/ui/index.d.ts +1 -1
  258. package/dist/ui/index.d.ts.map +1 -1
  259. package/dist/workflow/index.d.ts +2 -0
  260. package/dist/workflow/index.d.ts.map +1 -1
  261. package/package.json +1 -1
  262. package/src/EveryskApp.tsx +53 -2
  263. package/src/agGrid/handleRowsScrollEnd.ts +71 -0
  264. package/src/agGrid/index.ts +5 -1
  265. package/src/api/datastore.ts +79 -107
  266. package/src/api/entityQuery.ts +86 -17
  267. package/src/api/file.ts +110 -103
  268. package/src/api/portfolio.ts +82 -125
  269. package/src/api/profile.ts +25 -18
  270. package/src/api/request.ts +168 -0
  271. package/src/api/websocketsConfig.ts +11 -19
  272. package/src/api/workflow.ts +232 -334
  273. package/src/api/workspace.ts +43 -43
  274. package/src/components/ui/Footer/index.tsx +8 -7
  275. package/src/components/ui/GlobalLoading/index.tsx +13 -3
  276. package/src/components/ui/PageContainer/index.tsx +9 -2
  277. package/src/components/ui/Toolbar/index.tsx +105 -30
  278. package/src/contexts/appAlertContext/provider.tsx +1 -1
  279. package/src/contexts/appAlertContext/types.ts +3 -3
  280. package/src/contexts/appConfigContext/index.tsx +1 -1
  281. package/src/contexts/appConfigContext/provider.tsx +1 -5
  282. package/src/contexts/webSocketContext/handler.ts +8 -2
  283. package/src/contexts/webSocketContext/hooks/useWebSocket/index.ts +1 -1
  284. package/src/contexts/webSocketContext/provider.tsx +64 -14
  285. package/src/contexts/webSocketContext/types.ts +7 -6
  286. package/src/file/index.ts +2 -0
  287. package/src/hooks/datastore/useDatastoreMutations.ts +19 -60
  288. package/src/hooks/datastore/useFetchDatastore.ts +45 -73
  289. package/src/hooks/datastore/useFetchDatastores.ts +106 -131
  290. package/src/hooks/file/fileData.ts +19 -0
  291. package/src/hooks/file/useFetchFile.ts +41 -76
  292. package/src/hooks/file/useFetchFiles.ts +92 -87
  293. package/src/hooks/file/useFileMutations.ts +23 -73
  294. package/src/hooks/portfolio/useFetchPortfolio.ts +26 -78
  295. package/src/hooks/portfolio/useFetchPortfolios.ts +50 -93
  296. package/src/hooks/portfolio/usePortfolioMutations.ts +22 -72
  297. package/src/hooks/profile/useFetchProfile.ts +24 -65
  298. package/src/hooks/useAxios.ts +5 -5
  299. package/src/hooks/useEntityInfiniteQuery.ts +193 -0
  300. package/src/hooks/useEntityMutation.ts +70 -0
  301. package/src/hooks/useEntityQuery.ts +117 -0
  302. package/src/hooks/workflow/useFetchWorkerExecution.ts +27 -56
  303. package/src/hooks/workflow/useFetchWorkerExecutions.ts +54 -79
  304. package/src/hooks/workflow/useFetchWorkflow.ts +24 -58
  305. package/src/hooks/workflow/useFetchWorkflowExecution.ts +27 -57
  306. package/src/hooks/workflow/useFetchWorkflowExecutions.ts +64 -73
  307. package/src/hooks/workflow/useFetchWorkflows.ts +48 -64
  308. package/src/hooks/workflow/useRunWorkflow.ts +82 -36
  309. package/src/hooks/workflow/useTriggerWorkflow.ts +36 -0
  310. package/src/hooks/workspace/useFetchWorkspace.ts +25 -58
  311. package/src/hooks/workspace/useFetchWorkspaces.ts +38 -69
  312. package/src/index.ts +34 -19
  313. package/src/lib/abort.ts +131 -0
  314. package/src/lib/datastoreTable.ts +127 -74
  315. package/src/lib/file.ts +67 -0
  316. package/src/lib/queryClient.ts +11 -13
  317. package/src/lib/workflowRun.ts +329 -0
  318. package/src/socket/index.ts +1 -3
  319. package/src/test/mocks/index.ts +1 -5
  320. package/src/test/renderWithProviders.tsx +8 -3
  321. package/src/test/setup.ts +16 -16
  322. package/src/theme/index.ts +1 -1
  323. package/src/theme/overrides/index.ts +5 -3
  324. package/src/theme/overrides/muiButton.ts +3 -3
  325. package/src/theme/overrides/muiCssBaseline.ts +11 -12
  326. package/src/theme/overrides/muiDatePicker.ts +2 -2
  327. package/src/theme/overrides/muiFormControl.ts +2 -2
  328. package/src/theme/overrides/muiIconButton.ts +3 -3
  329. package/src/theme/overrides/muiSelect.ts +2 -2
  330. package/src/theme/overrides/muiSvgIcon.ts +2 -2
  331. package/src/theme/overrides/muiTextField.ts +1 -1
  332. package/src/theme/overrides/muiToggleButton.ts +4 -4
  333. package/src/theme/overrides/muiToggleButtonGroup.ts +4 -4
  334. package/src/theme/themes/DefaultDark.ts +2 -2
  335. package/src/theme/themes/DefaultLight.ts +2 -2
  336. package/src/theme/themes/EveryskDark.ts +2 -2
  337. package/src/theme/themes/EveryskLight.ts +2 -2
  338. package/src/theme/themes/MidnightEmber.ts +15 -15
  339. package/src/types/anyRecord.ts +2 -2
  340. package/src/types/datastore.ts +56 -22
  341. package/src/types/datastoreDataFormat.ts +12 -0
  342. package/src/types/entityQuery.ts +122 -38
  343. package/src/types/file.ts +8 -6
  344. package/src/types/portfolio.ts +70 -74
  345. package/src/types/profile.ts +0 -11
  346. package/src/types/workflow.ts +38 -9
  347. package/src/types/workspace.ts +2 -4
  348. package/src/ui/index.ts +1 -1
  349. package/src/workflow/index.ts +5 -0
@@ -1,86 +1,55 @@
1
- import { useMemo } from "react";
2
- import { useInfiniteQuery, type UseInfiniteQueryOptions, type QueryKey } from "@tanstack/react-query";
3
-
4
1
  import { useAxios } from "@/hooks/useAxios";
2
+ import { useEntityInfiniteQuery } from "@/hooks/useEntityInfiniteQuery";
5
3
  import { listWorkspaces } from "@/api/workspace";
4
+ import { buildQueryKey } from "@/api/entityQuery";
6
5
  import type { Workspace, WorkspaceListResponse } from "@/types/workspace";
7
-
8
- type PageToken = string | null;
9
-
10
- type InfiniteOptions<TData> = Omit<
11
- UseInfiniteQueryOptions<WorkspaceListResponse, Error, TData, QueryKey, PageToken>,
12
- "queryKey" | "queryFn" | "initialPageParam" | "getNextPageParam"
13
- >;
14
-
15
- export type FetchInfiniteWorkspaceProps = {
16
- workspace?: string;
17
- pageSize?: number;
18
- queryOptions?: InfiniteOptions<Workspace[]>;
19
- };
20
-
21
- const defaultQueryOptions: InfiniteOptions<Workspace[]> = {
22
- refetchOnMount: "always",
23
- staleTime: 0,
24
- gcTime: 0,
6
+ import type { FetchEntitiesProps, ListCache } from "@/types/entityQuery";
7
+
8
+ /** The query cache of `useFetchWorkspaces`, for typing `setQueryData`. */
9
+ export type WorkspacesCache = ListCache<WorkspaceListResponse>;
10
+
11
+ export type FetchWorkspacesProps<TData = Workspace[]> = FetchEntitiesProps<
12
+ Workspace,
13
+ TData,
14
+ WorkspaceListResponse
15
+ > & {
16
+ /** A name prefix. */
17
+ search?: string;
25
18
  };
26
19
 
27
20
  /**
28
21
  * useFetchWorkspaces
29
22
  *
30
- * Data-fetching hook built on TanStack Query's `useInfiniteQuery` to retrieve
31
- * workspaces with cursor-based pagination.
32
- *
33
- * It also:
34
- * - flattens all pages into a single `Workspace[]` via `select`
35
- *
36
- * Important notes:
37
- * - `query.data` returns a flat `Workspace[]` (all pages merged).
38
- * - `workspace` is required by some API configurations to avoid being blocked.
23
+ * Lists workspaces with cursor pagination; `query.data` is every loaded page merged, or
24
+ * whatever `select` makes of it. `select` and `fetchAllPages` behave as in
25
+ * `useFetchDatastores`. This endpoint lists the account's workspaces: it takes a name `search`,
26
+ * and no workspace — the docs exempt it, and the endpoint ignores one, which this hook used to
27
+ * send.
39
28
  *
40
- * @param props - FetchInfiniteWorkspaceProps
41
- * - `workspace`: Current workspace name sent as a query param.
42
- * - `pageSize`: Number of workspaces to fetch per page.
43
- * - `queryOptions`: TanStack Query options passed through to `useInfiniteQuery`.
44
- *
45
- * Returns:
46
- * @returns {object}
47
- * - `query`: the full `useInfiniteQuery` result (data, isLoading, hasNextPage, fetchNextPage, etc.)
48
- * - `queryKey`: the cache key used by React Query
49
- *
50
- * Example:
51
- * ```ts
52
- * const { query } = useFetchWorkspaces({ workspace: "main", pageSize: 20 });
53
- *
54
- * // Flat list of all fetched workspaces
55
- * const workspaces = query.data ?? [];
56
- * ```
29
+ * @param {FetchWorkspacesProps} props - Search, page size, `select`, `fetchAllPages` and
30
+ * TanStack `queryOptions`.
31
+ * @returns {object} `query` (the `useInfiniteQuery` result) and `queryKey`.
57
32
  */
58
- export function useFetchWorkspaces({ workspace, pageSize = 10, queryOptions }: FetchInfiniteWorkspaceProps) {
33
+ export function useFetchWorkspaces<TData = Workspace[]>({
34
+ search,
35
+ pageSize = 10,
36
+ select,
37
+ fetchAllPages = false,
38
+ queryOptions,
39
+ }: FetchWorkspacesProps<TData>) {
59
40
  const { api } = useAxios();
60
41
 
61
- const queryKey: QueryKey = ["workspaces", workspace ?? null];
62
-
63
- const mergedQueryOptions = useMemo<InfiniteOptions<Workspace[]>>(() => ({
64
- ...defaultQueryOptions,
65
- ...(queryOptions ?? {}),
66
- }), [queryOptions]);
42
+ const queryKey = buildQueryKey(["workspaces", search ?? null], [], { pageSize, fetchAllPages });
67
43
 
68
- const query = useInfiniteQuery<WorkspaceListResponse, Error, Workspace[], QueryKey, PageToken>({
44
+ const query = useEntityInfiniteQuery<WorkspaceListResponse, "workspaces", TData>({
69
45
  queryKey,
70
- initialPageParam: null,
71
- getNextPageParam: (lastPage) => lastPage.next_page_token ?? undefined,
72
-
73
- queryFn: async ({ pageParam }) => {
74
- return await listWorkspaces(api, workspace, pageSize, pageParam ?? undefined);
75
- },
76
-
77
- select: (data) => data.pages.flatMap((p) => p.workspaces),
78
-
79
- ...mergedQueryOptions,
46
+ itemsKey: "workspaces",
47
+ fetchPage: (pageToken, signal) =>
48
+ listWorkspaces(api, { search, pageSize, pageToken: pageToken ?? undefined }, signal),
49
+ select,
50
+ fetchAllPages,
51
+ queryOptions,
80
52
  });
81
53
 
82
- return {
83
- query,
84
- queryKey,
85
- };
54
+ return { query, queryKey };
86
55
  }
package/src/index.ts CHANGED
@@ -10,21 +10,19 @@
10
10
  // before it can tree-shake it, so re-exporting the AG Grid layer from here would fail to build
11
11
  // in an app that never installed ag-grid — even one importing nothing but createQueryClient.
12
12
 
13
- export { EveryskApp } from "./EveryskApp";
14
- export type { EveryskAppProps, ProviderComponent } from "./EveryskApp";
13
+ export { EveryskApp, withProps } from "./EveryskApp";
14
+ export type {
15
+ ConfiguredProvider,
16
+ EveryskAppProps,
17
+ ProviderComponent,
18
+ ProviderEntry,
19
+ } from "./EveryskApp";
15
20
 
16
- // Contexts — app configuration
17
- export { AppConfigContext } from "./contexts/appConfigContext";
18
- export { AppConfigProvider } from "./contexts/appConfigContext/provider";
21
+ // Contexts. `EveryskApp` mounts both providers, so only the hooks and the types are public: a
22
+ // second provider would give part of the tree a context of its own.
19
23
  export { useAppConfig } from "./contexts/appConfigContext/useAppConfig";
20
- export type {
21
- AppConfigContextType,
22
- AppConfigProviderProps,
23
- } from "./contexts/appConfigContext/types";
24
+ export type { AppConfigContextType } from "./contexts/appConfigContext/types";
24
25
 
25
- // Contexts — alerts
26
- export { AppAlertContext } from "./contexts/appAlertContext";
27
- export { AppAlertProvider } from "./contexts/appAlertContext/provider";
28
26
  export { useAppAlert } from "./contexts/appAlertContext/useAppAlert";
29
27
  export type {
30
28
  AppAlertContextType,
@@ -34,29 +32,46 @@ export type {
34
32
 
35
33
  // Hooks
36
34
  export { useAxios } from "./hooks/useAxios";
35
+ // The hooks the entity slices are built on, public for an endpoint the SDK does not cover.
36
+ export { useEntityQuery } from "./hooks/useEntityQuery";
37
+ export type { EntityQueryProps } from "./hooks/useEntityQuery";
38
+ export { useEntityMutation } from "./hooks/useEntityMutation";
39
+ export type { EntityMutationProps } from "./hooks/useEntityMutation";
40
+ export { useEntityInfiniteQuery, FETCH_ALL_PAGES_LIMIT } from "./hooks/useEntityInfiniteQuery";
41
+ export type { EntityInfiniteQueryProps, ItemOf } from "./hooks/useEntityInfiniteQuery";
37
42
 
38
43
  // API helpers
39
- export { toFilterTuple, buildQueryObject, buildQueryKey } from "./api/entityQuery";
44
+ export {
45
+ buildQueryObject,
46
+ buildQueryKey,
47
+ hasWorkspaceFilter,
48
+ missingWorkspaceError,
49
+ } from "./api/entityQuery";
50
+ export type { QueryKeyParams } from "./api/entityQuery";
40
51
 
41
52
  // Query client
42
- export { createQueryClient, getQueryFn } from "./lib/queryClient";
53
+ export { createQueryClient } from "./lib/queryClient";
43
54
 
44
55
  // Types
45
56
  export type { AnyRecord } from "./types/anyRecord";
46
57
  export type {
47
- BaseQueryParams,
48
- DeleteEntityDefaultResponse,
58
+ DeletedEntity,
49
59
  DeleteEntityResponse,
50
- EntityDefaultResponse,
60
+ EntityInfiniteQueryOptions,
51
61
  EntityListResponse,
52
62
  EntityQueryOptions,
53
63
  EntityQueryParams,
54
64
  EntitySingleResponse,
55
- FetchEntitiesParams,
56
- FetchEntityParams,
65
+ FetchEntitiesProps,
66
+ FetchEntityByIdProps,
67
+ FetchEntityProps,
57
68
  FilterClause,
58
69
  FilterExpression,
59
70
  FilterOperator,
71
+ ListCache,
72
+ ListQueryProps,
73
+ PagedResponse,
74
+ PageToken,
60
75
  QueryObject,
61
76
  } from "./types/entityQuery";
62
77
 
@@ -0,0 +1,131 @@
1
+ /**
2
+ * abortable
3
+ *
4
+ * The one shape every abortable wait here takes: a promise that `start` settles, or that rejects
5
+ * with the signal's reason as soon as it aborts. `start` returns its cleanup, which runs either
6
+ * way, so a timer or a listener never outlives the promise.
7
+ *
8
+ * @param signal - Aborts the wait.
9
+ * @param start - Begins the work and returns what undoes it.
10
+ * @returns The work's result, unless the signal aborts first.
11
+ */
12
+ export const abortable = <T>(
13
+ signal: AbortSignal,
14
+ start: (resolve: (value: T) => void, reject: (error: unknown) => void) => () => void,
15
+ ): Promise<T> =>
16
+ new Promise<T>((resolve, reject) => {
17
+ if (signal.aborted) return reject(signal.reason);
18
+
19
+ let cleanup = () => {};
20
+ const finish = () => {
21
+ cleanup();
22
+ signal.removeEventListener("abort", onAbort);
23
+ };
24
+ const onAbort = () => {
25
+ finish();
26
+ reject(signal.reason);
27
+ };
28
+
29
+ signal.addEventListener("abort", onAbort, { once: true });
30
+ cleanup = start(
31
+ (value) => {
32
+ finish();
33
+ resolve(value);
34
+ },
35
+ (error) => {
36
+ finish();
37
+ reject(error);
38
+ },
39
+ );
40
+ });
41
+
42
+ /**
43
+ * Settles as `promise` does, or rejects with the signal's reason once it aborts first — for work
44
+ * that may not honour the signal itself.
45
+ */
46
+ export const unlessAborted = <T>(promise: Promise<T>, signal: AbortSignal): Promise<T> =>
47
+ abortable(signal, (resolve, reject) => {
48
+ promise.then(resolve, reject);
49
+ return () => {};
50
+ });
51
+
52
+ /**
53
+ * createDeadline
54
+ *
55
+ * A signal that aborts after `timeoutMs`, or as soon as `signal` does, each with its own error.
56
+ * `dispose` stops the timer and the listener once the work is done.
57
+ *
58
+ * @param options - The timeout, the outer signal, and the error each abort carries. The errors
59
+ * are built when the abort happens, so they can describe the state at that moment.
60
+ * @returns The signal, and `dispose`.
61
+ */
62
+ export const createDeadline = ({
63
+ timeoutMs,
64
+ signal,
65
+ timeoutError,
66
+ abortError,
67
+ }: {
68
+ timeoutMs: number;
69
+ signal?: AbortSignal;
70
+ timeoutError: () => Error;
71
+ abortError: () => Error;
72
+ }) => {
73
+ const controller = new AbortController();
74
+ const timer = setTimeout(() => controller.abort(timeoutError()), timeoutMs);
75
+ const abort = () => controller.abort(abortError());
76
+
77
+ if (signal?.aborted) abort();
78
+ else signal?.addEventListener("abort", abort, { once: true });
79
+
80
+ return {
81
+ signal: controller.signal,
82
+ dispose() {
83
+ clearTimeout(timer);
84
+ signal?.removeEventListener("abort", abort);
85
+ },
86
+ };
87
+ };
88
+
89
+ /**
90
+ * anySignal
91
+ *
92
+ * A signal that aborts as soon as any of `signals` does, with that one's reason. It is
93
+ * `AbortSignal.any`, written out because that arrived in Chrome 116, Firefox 124 and Safari 17.4,
94
+ * after the browsers a Vite 8 app targets by default (Chrome 111, Firefox 114, Safari 16.4).
95
+ * What it uses instead — `abort(reason)`, `signal.reason` and `addEventListener`'s `once` —
96
+ * predates them all. Source: MDN browser-compat-data, `api/AbortSignal.json` and
97
+ * `api/AbortController.json` (2026-10-14).
98
+ *
99
+ * Missing signals are skipped, so an optional one can be passed as is. It stops listening to the
100
+ * others once one aborts, or when `dispose` is called: a run that ends normally aborts nothing,
101
+ * and a long-lived signal would otherwise keep one listener per run.
102
+ *
103
+ * @param signals - The signals to follow; `undefined` entries are ignored.
104
+ * @returns The signal that aborts with the first of them, and `dispose`.
105
+ */
106
+ export const anySignal = (
107
+ signals: (AbortSignal | undefined)[],
108
+ ): { signal: AbortSignal; dispose: () => void } => {
109
+ const controller = new AbortController();
110
+ const present = signals.filter((signal): signal is AbortSignal => signal !== undefined);
111
+
112
+ const already = present.find((signal) => signal.aborted);
113
+ if (already) {
114
+ controller.abort(already.reason);
115
+ return { signal: controller.signal, dispose: () => {} };
116
+ }
117
+
118
+ const dispose = () => {
119
+ for (const [signal, listener] of listeners) signal.removeEventListener("abort", listener);
120
+ };
121
+ const listeners = present.map((signal) => {
122
+ const listener = () => {
123
+ dispose();
124
+ controller.abort(signal.reason);
125
+ };
126
+ signal.addEventListener("abort", listener, { once: true });
127
+ return [signal, listener] as const;
128
+ });
129
+
130
+ return { signal: controller.signal, dispose };
131
+ };
@@ -1,4 +1,5 @@
1
- import type { Datastore } from "@/types/datastore";
1
+ import type { Datastore, ParsedDatastore, JsonDatastore } from "@/types/datastore";
2
+ import type { DatastoreDataFormat } from "@/types/datastoreDataFormat";
2
3
  import type { AnyRecord } from "@/types/anyRecord";
3
4
 
4
5
  type Cell = string | number | null;
@@ -34,30 +35,103 @@ type DatastoreData = Cell[][];
34
35
  * ["Alice", 30],
35
36
  * ["Bob", null],
36
37
  * ];
37
- * const rows = tableToObjects("ds_123", headers, data);
38
+ * const rows = matrixToObjects("ds_123", headers, data);
38
39
  * // [
39
40
  * // { datastoreId: "ds_123", name: "Alice", age: 30 },
40
41
  * // { datastoreId: "ds_123", name: "Bob", age: null }
41
42
  * // ]
42
43
  */
43
- export const tableToObjects = <T extends Record<string, Cell>>(datastoreId: string, headers: string[], data: DatastoreData): T[] => {
44
- const result: T[] = [];
44
+ export const matrixToObjects = <T extends Record<string, Cell>>(
45
+ datastoreId: string,
46
+ headers: string[],
47
+ data: DatastoreData,
48
+ ): T[] => {
49
+ const result: T[] = [];
45
50
 
46
- for (let i = 1; i < data?.length; i++) {
47
- const item: Record<string, Cell> = {};
51
+ for (let i = 1; i < data?.length; i++) {
52
+ const item: Record<string, Cell> = {};
48
53
 
49
- item.datastoreId = datastoreId;
54
+ item.datastoreId = datastoreId;
50
55
 
51
- headers.forEach((header: string, index: number) => {
52
- item[header] = data[i][index];
53
- });
56
+ headers.forEach((header: string, index: number) => {
57
+ item[header] = data[i][index];
58
+ });
54
59
 
55
- result.push(item as T);
56
- }
60
+ result.push(item as T);
61
+ }
57
62
 
58
- return result;
63
+ return result;
59
64
  };
60
65
 
66
+ /** A tabular datastore's `data`: an array of rows. An empty array counts, as an empty table. */
67
+ const isMatrix = (data: unknown): data is DatastoreData =>
68
+ Array.isArray(data) && data.every(Array.isArray);
69
+
70
+ /**
71
+ * Converts a datastore as the API returns it into the shape the datastore hooks return.
72
+ *
73
+ * A datastore is tabular or JSON, and the API does not say which. `data` is a matrix, an object,
74
+ * or an array of objects, so only an array whose every element is an array is read as a table.
75
+ * "Any array" is not enough: the API has returned `[{ … }]` for a JSON datastore, which read as a
76
+ * matrix lost its content with one element and threw with two. A table's matrix becomes row
77
+ * objects, with the header row kept as `fields` so that saving back can restore the column
78
+ * order. JSON passes through untouched.
79
+ *
80
+ * A read without its data (`projection: "-data"`) carries nothing to tell the kinds apart and
81
+ * comes back as an empty table.
82
+ *
83
+ * The hooks convert in the request rather than in `select`, so the cache holds objects and an
84
+ * app patches a row as `{ ...row, ...patch }` rather than by column index. It is exported for an
85
+ * app that seeds that cache itself.
86
+ *
87
+ * With `dataFormat: "matrix"` a table keeps its matrix unconverted, header row included, and still
88
+ * gets `fields`. JSON is untouched either way.
89
+ *
90
+ * @param datastore The datastore as the API returned it.
91
+ * @param dataFormat `"object"` (default) or `"matrix"`.
92
+ * @returns A tabular or a `JsonDatastore`, told apart by `format`.
93
+ */
94
+ export function parseDatastore(datastore: Datastore): ParsedDatastore;
95
+ export function parseDatastore<F extends DatastoreDataFormat>(
96
+ datastore: Datastore,
97
+ dataFormat: F,
98
+ ): ParsedDatastore<F>;
99
+ export function parseDatastore(
100
+ datastore: Datastore,
101
+ dataFormat: DatastoreDataFormat = "object",
102
+ ): ParsedDatastore<DatastoreDataFormat> {
103
+ const { data } = datastore;
104
+
105
+ if (data && !isMatrix(data)) {
106
+ return { ...datastore, format: "json", data: data as JsonDatastore["data"] };
107
+ }
108
+
109
+ const matrix = (data ?? []) as DatastoreData;
110
+ const fields = (matrix[0] ?? []) as string[];
111
+
112
+ if (dataFormat === "matrix") {
113
+ return { ...datastore, format: "table", fields, data: matrix };
114
+ }
115
+
116
+ return {
117
+ ...datastore,
118
+ format: "table",
119
+ fields,
120
+ data: matrixToObjects(datastore.id, fields, matrix),
121
+ };
122
+ }
123
+
124
+ /**
125
+ * Narrows a datastore to a tabular one, whose `data` is rows. For a `select` over a list that
126
+ * may mix kinds: `datastores.filter(isTableDatastore).flatMap((d) => d.data)`.
127
+ *
128
+ * @param datastore A datastore as the hooks return it.
129
+ * @returns True for a tabular datastore.
130
+ */
131
+ export const isTableDatastore = <D extends ParsedDatastore<DatastoreDataFormat>>(
132
+ datastore: D,
133
+ ): datastore is Extract<D, { format: "table" }> => datastore.format === "table";
134
+
61
135
  /**
62
136
  * Converts an array of objects into a datastore table (2D array).
63
137
  *
@@ -66,7 +140,8 @@ export const tableToObjects = <T extends Record<string, Cell>>(datastoreId: stri
66
140
  * - For each object in `data`, creates a row by mapping `headers` to values in the object.
67
141
  * - If a header is missing in an object, the corresponding cell is set to `null`.
68
142
  *
69
- * @template T A record type whose values are compatible with `Cell` (string | number | null).
143
+ * Takes rows as the datastore hooks hand them over (`AnyRecord`): a value that is not a cell is
144
+ * written as it is, since the row came from a matrix in the first place.
70
145
  *
71
146
  * @param headers Column names (and output table header row).
72
147
  * @param data Array of objects to convert into rows.
@@ -77,7 +152,7 @@ export const tableToObjects = <T extends Record<string, Cell>>(datastoreId: stri
77
152
  *
78
153
  * @example
79
154
  * const headers = ["name", "age"];
80
- * const rows = objectsToTable(headers, [
155
+ * const rows = objectsToMatrix(headers, [
81
156
  * { name: "Alice", age: 30 },
82
157
  * { name: "Bob" }, // age missing -> null
83
158
  * ]);
@@ -87,73 +162,51 @@ export const tableToObjects = <T extends Record<string, Cell>>(datastoreId: stri
87
162
  * // ["Bob", null]
88
163
  * // ]
89
164
  */
90
- export const objectsToTable = <T extends Record<string, Cell>>(headers: string[] ,data: T[]): DatastoreData => {
91
- const rows: DatastoreData = data.map((d) => headers.map<Cell>((h) => d[h as string] ?? null));
165
+ export const objectsToMatrix = <T extends AnyRecord = AnyRecord>(
166
+ headers: string[],
167
+ data: T[],
168
+ ): DatastoreData => {
169
+ // Built into one array: mapping the rows and then spreading them after the header copied the
170
+ // whole list a second time. The header is copied: a caller's `headers` is often a datastore's
171
+ // `fields`, held in the query cache, and renaming a column in the matrix renamed it there too.
172
+ const matrix: DatastoreData = [headers.slice()];
92
173
 
93
- return [headers, ...rows];
174
+ for (const row of data)
175
+ matrix.push(headers.map<Cell>((header) => (row[header] ?? null) as Cell));
176
+
177
+ return matrix;
94
178
  };
95
179
 
96
180
  /**
97
- * Flattens multiple datastore row arrays into a single array.
98
- *
99
- * This is typically used after fetching multiple datastores, where each datastore is
100
- * represented as `AnyRecord[]` (i.e., an array of row objects).
181
+ * The matrix of a tabular datastore, however the hook read it. Code that saves or exports a
182
+ * datastore calls this without knowing the `dataFormat` it was read with: a matrix read is
183
+ * copied, an object read is rebuilt in the datastore's own column order (`fields`), without the
184
+ * `datastoreId` the SDK adds to each row, and with any patch applied to the rows.
101
185
  *
102
- * @param datastores A list of datastores, each represented as an array of row objects.
186
+ * Either way the result is a new matrix the caller owns and may edit before saving. A matrix
187
+ * read's `data` is the matrix in the query cache, and handing that back made an edit change what
188
+ * every screen reading the entry sees.
103
189
  *
104
- * @returns A single array containing all rows from all datastores, in the same order.
190
+ * Do not save the result of a read that projected `data` away (`projection: "-data"`): it comes
191
+ * back as an empty table, indistinguishable from a real one, and saving it would empty the
192
+ * datastore.
105
193
  *
106
- * @example
107
- * const merged = mergeDatastores([
108
- * [{ datastoreId: "a", x: 1 }],
109
- * [{ datastoreId: "b", x: 2 }, { datastoreId: "b", x: 3 }],
110
- * ]);
111
- * // [{...}, {...}, {...}]
194
+ * @param datastore A tabular datastore as the hooks return it (narrow with `isTableDatastore`).
195
+ * @returns The matrix, header row first.
112
196
  */
113
- export const mergeDatastores = (datastores: AnyRecord[][]): AnyRecord[] => {
114
- const result: AnyRecord[] = [];
197
+ export const toDatastoreMatrix = (
198
+ datastore: Extract<ParsedDatastore<DatastoreDataFormat>, { format: "table" }>,
199
+ ): DatastoreData => {
200
+ const { data, fields } = datastore;
115
201
 
116
- datastores.forEach((datastore: AnyRecord[]) => {
117
- result.push(...datastore);
118
- });
202
+ if (data.length === 0) return fields.length > 0 ? [fields.slice()] : [];
119
203
 
120
- return result;
204
+ // The first row is enough: the SDK built this `data`, so it is all rows or all objects. The
205
+ // full `isMatrix` scan guards the API's data, and here it would only walk every row for nothing.
206
+ // A row-by-row copy is a full copy: a matrix is two levels deep and its cells are primitives.
207
+ // `structuredClone` would do the same about 8 times slower (147 ms against 18 ms for 100,000
208
+ // rows of 10 cells), paying for cycles and special types a datastore matrix never holds.
209
+ return Array.isArray(data[0])
210
+ ? (data as DatastoreData).map((row) => row.slice())
211
+ : objectsToMatrix(fields, data as AnyRecord[]);
121
212
  };
122
-
123
- /**
124
- * buildDatastoreProps
125
- *
126
- * Extracts and maps the metadata properties of a `Datastore` into a plain object
127
- * for UI usage, discarding raw data rows.
128
- *
129
- * - `header` is derived from `datastore.data?.[0]` (the first row of the data matrix),
130
- * which is expected to contain the column names. Falls back to `[]` if not present.
131
- *
132
- * @param {Datastore} datastore - The source datastore object.
133
- * @returns Metadata object with the datastore's descriptive properties and header.
134
- *
135
- * @example
136
- * const meta = buildDatastoreProps(datastore);
137
- * // {
138
- * // name: "my-datastore",
139
- * // workspace: "ws-1",
140
- * // header: ["col1", "col2"],
141
- * // ...
142
- * // }
143
- */
144
- export const buildDatastoreProps = (datastore: Datastore) => {
145
- return {
146
- name: datastore.name,
147
- date: datastore.date,
148
- version: datastore.version,
149
- description: datastore.description,
150
- tags: datastore.tags,
151
- link_uid: datastore.link_uid,
152
- workspace: datastore.workspace,
153
- date_time: datastore.date_time,
154
- created: datastore.created,
155
- updated: datastore.updated,
156
- level: datastore.level,
157
- header: datastore.data?.[0] || [],
158
- };
159
- };
@@ -0,0 +1,67 @@
1
+ /**
2
+ * fileToBase64
3
+ *
4
+ * The raw base64 `createFile` and `updateFile` take as `data`, from a `File` an `<input
5
+ * type="file">` gives or any `Blob`. The API stores `data` as given, so the `data:<type>;base64,`
6
+ * prefix `FileReader` puts in front would be stored as part of the content.
7
+ *
8
+ * Read through `FileReader` rather than by encoding the bytes in a loop: the browser encodes
9
+ * natively, with no binary string built byte by byte for `btoa`. An empty file reads as `data:`
10
+ * with no comma in Chromium, so a missing comma is empty content — for an empty file only, as
11
+ * a file with content read that way would otherwise be uploaded empty.
12
+ *
13
+ * @param blob - The file.
14
+ * @returns The content as base64, without a prefix.
15
+ */
16
+ export const fileToBase64 = (blob: Blob): Promise<string> =>
17
+ new Promise((resolve, reject) => {
18
+ const reader = new FileReader();
19
+ reader.onload = () => {
20
+ const dataUrl = String(reader.result);
21
+ const comma = dataUrl.indexOf(",");
22
+ if (comma !== -1) {
23
+ resolve(dataUrl.slice(comma + 1));
24
+ } else if (blob.size === 0) {
25
+ resolve("");
26
+ } else {
27
+ reject(new Error("Unable to read the file: it read as a data URL with no content"));
28
+ }
29
+ };
30
+ reader.onerror = () => reject(reader.error ?? new Error("Unable to read the file"));
31
+ reader.readAsDataURL(blob);
32
+ });
33
+
34
+ /**
35
+ * base64ToBlob
36
+ *
37
+ * A file's content, as the API returns it in `data`, decoded into a `Blob` byte for byte: to work
38
+ * on the bytes in code, such as parsing a CSV or unzipping. Not to show the file — the app page's
39
+ * CSP blocks a `blob:` frame, image or media; use the file's own `url` — and it decodes
40
+ * synchronously, a byte at a time, so a file of several megabytes is better read through it.
41
+ *
42
+ * Without content — a file read without `withData: true` — it warns and gives an empty blob:
43
+ * `atob(null)` decodes the text "null", three bytes of garbage that would pass for the file.
44
+ *
45
+ * @param data - The content as base64, as the hooks return it with `withData: true`.
46
+ * @param contentType - The file's `content_type`, which becomes the blob's `type`.
47
+ * @returns The content.
48
+ * @throws {Error} If `data` is not raw base64.
49
+ */
50
+ export const base64ToBlob = (data: string | null | undefined, contentType: string): Blob => {
51
+ if (data == null) {
52
+ console.warn(
53
+ "[apps-sdk] base64ToBlob: the file came without its content; read it with withData: true.",
54
+ );
55
+ return new Blob([], { type: contentType });
56
+ }
57
+
58
+ let binary: string;
59
+ try {
60
+ binary = atob(data);
61
+ } catch (error) {
62
+ throw new Error("The file's data is not raw base64", { cause: error });
63
+ }
64
+ const bytes = new Uint8Array(binary.length);
65
+ for (let index = 0; index < binary.length; index++) bytes[index] = binary.charCodeAt(index);
66
+ return new Blob([bytes], { type: contentType });
67
+ };