@geode/opengeodeweb-front 10.34.0-rc.9 → 10.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (282) hide show
  1. package/{server → .build/server}/utils/app_config.js +10 -9
  2. package/{server → .build/server}/utils/cleanup.js +31 -17
  3. package/{server → .build/server}/utils/cloud.js +1 -4
  4. package/{server → .build/server}/utils/microservices.js +21 -9
  5. package/{server → .build/server}/utils/path.js +4 -4
  6. package/{server → .build/server}/utils/scripts.js +9 -9
  7. package/.build/server/utils/server_config.js +51 -0
  8. package/.build/server/utils/stream.js +6 -0
  9. package/{server → .build/server}/utils/ws_client.js +18 -3
  10. package/{shared → .build/shared}/scripts.js +10 -10
  11. package/.build/shared/utils/call_raw.js +31 -0
  12. package/{shared → .build/shared}/utils/call_schema.js +2 -2
  13. package/.build/shared/utils/fetch_raw.js +52 -0
  14. package/{shared → .build/shared}/utils/fetch_schema.js +2 -2
  15. package/{shared → .build/shared}/utils/file.js +3 -1
  16. package/{shared → .build/shared}/utils/response_handlers/load.js +10 -7
  17. package/{shared → .build/shared}/utils/validate_schema.js +1 -1
  18. package/app/components/ActionButton.vue +6 -6
  19. package/app/components/CameraManager/List.vue +5 -5
  20. package/app/components/CameraManager/Saver.vue +3 -5
  21. package/app/components/CameraManager.vue +6 -4
  22. package/app/components/CameraOrientation.vue +12 -12
  23. package/app/components/ClippingPlaneCard.vue +4 -2
  24. package/app/components/ClippingPlanes.vue +8 -8
  25. package/app/components/CrsSelector.vue +9 -10
  26. package/app/components/DeleteDialog.vue +4 -2
  27. package/app/components/DragAndDrop.vue +10 -12
  28. package/app/components/DragAndDropInternal/DragAndDropInline.vue +4 -2
  29. package/app/components/ExtensionSelector.vue +4 -4
  30. package/app/components/FeedBack/ErrorBanner.vue +3 -1
  31. package/app/components/FeedBack/Snackers.vue +4 -3
  32. package/app/components/FileSelector.vue +10 -8
  33. package/app/components/FileUploader.vue +11 -11
  34. package/app/components/GlassCard.vue +1 -1
  35. package/app/components/HybridRenderingView.vue +7 -5
  36. package/app/components/HybridViewerTooltip.vue +7 -7
  37. package/app/components/Launcher.vue +1 -1
  38. package/app/components/Loading/EcoMessages.vue +9 -3
  39. package/app/components/Loading.vue +2 -2
  40. package/app/components/MissingFilesSelector.vue +12 -10
  41. package/app/components/ObjectSelector.vue +10 -9
  42. package/app/components/PackagesVersions.vue +6 -5
  43. package/app/components/Recaptcha.vue +3 -3
  44. package/app/components/RemoteRenderingView.vue +6 -7
  45. package/app/components/Ruler.vue +3 -3
  46. package/app/components/Screenshot.vue +6 -6
  47. package/app/components/SearchBar.vue +4 -2
  48. package/app/components/ShrinkFilter.vue +7 -7
  49. package/app/components/Step.vue +6 -5
  50. package/app/components/Stepper.vue +4 -3
  51. package/app/components/ToolPanel.vue +6 -3
  52. package/app/components/ViewToolbar.vue +25 -28
  53. package/app/components/Viewer/ContextMenu/CenterButton.vue +7 -5
  54. package/app/components/Viewer/ContextMenu/CircularItems.vue +3 -3
  55. package/app/components/Viewer/ContextMenu/ContextMenu.vue +22 -19
  56. package/app/components/Viewer/ContextMenu/ContextMenuItem.vue +10 -8
  57. package/app/components/Viewer/ContextMenu/InfoCard.vue +11 -12
  58. package/app/components/Viewer/EdgedCurve/SpecificEdgesOptions.vue +13 -17
  59. package/app/components/Viewer/Generic/Mesh/CellsOptions.vue +11 -15
  60. package/app/components/Viewer/Generic/Mesh/EdgesOptions.vue +12 -16
  61. package/app/components/Viewer/Generic/Mesh/PointsOptions.vue +8 -12
  62. package/app/components/Viewer/Generic/Mesh/PolygonsOptions.vue +11 -15
  63. package/app/components/Viewer/Generic/Mesh/PolyhedraOptions.vue +11 -15
  64. package/app/components/Viewer/Generic/Model/BlocksOptions.vue +67 -38
  65. package/app/components/Viewer/Generic/Model/CornersOptions.vue +53 -23
  66. package/app/components/Viewer/Generic/Model/EdgesOptions.vue +1 -3
  67. package/app/components/Viewer/Generic/Model/LinesOptions.vue +67 -38
  68. package/app/components/Viewer/Generic/Model/ModelStyleCard.vue +31 -15
  69. package/app/components/Viewer/Generic/Model/ModelStyleOptions.vue +2 -3
  70. package/app/components/Viewer/Generic/Model/PointsOptions.vue +6 -6
  71. package/app/components/Viewer/Generic/Model/SurfacesOptions.vue +69 -38
  72. package/app/components/Viewer/ObjectTree/Base/CommonTreeView.vue +64 -46
  73. package/app/components/Viewer/ObjectTree/Base/Controls.vue +5 -5
  74. package/app/components/Viewer/ObjectTree/Base/ItemLabel.vue +13 -9
  75. package/app/components/Viewer/ObjectTree/Base/StickyHeader.vue +5 -5
  76. package/app/components/Viewer/ObjectTree/Base/TreeRow.vue +10 -10
  77. package/app/components/Viewer/ObjectTree/Box.vue +6 -4
  78. package/app/components/Viewer/ObjectTree/Layout.vue +23 -21
  79. package/app/components/Viewer/ObjectTree/Views/GlobalObjects.vue +14 -14
  80. package/app/components/Viewer/ObjectTree/Views/{ModelCollections.vue → ModelTree.vue} +59 -24
  81. package/app/components/Viewer/Options/AttributeColorBar.vue +4 -2
  82. package/app/components/Viewer/Options/AttributeRangeSelector.vue +4 -2
  83. package/app/components/Viewer/Options/AttributeSelector.vue +7 -9
  84. package/app/components/Viewer/Options/ColorMapList.vue +15 -13
  85. package/app/components/Viewer/Options/ColorMapPicker.vue +4 -4
  86. package/app/components/Viewer/Options/ColorPicker.vue +223 -41
  87. package/app/components/Viewer/Options/ColoringTypeSelector.vue +16 -16
  88. package/app/components/Viewer/Options/ColormapQuickPicker.vue +7 -5
  89. package/app/components/Viewer/Options/OptionsSection.vue +1 -1
  90. package/app/components/Viewer/Options/TextureItem.vue +8 -6
  91. package/app/components/Viewer/Options/TexturesSelector.vue +1 -1
  92. package/app/components/Viewer/OverlappingObjectsPicker.vue +8 -9
  93. package/app/components/Viewer/PointSet/SpecificPointsOptions.vue +2 -6
  94. package/app/components/Viewer/Solid/SpecificPolyhedraOptions.vue +12 -16
  95. package/app/components/Viewer/Surface/PolygonsOptions.vue +12 -16
  96. package/app/components/Viewer/Ui.vue +2 -2
  97. package/app/components/Wrapper.vue +1 -4
  98. package/app/components/ZScaling.vue +5 -3
  99. package/app/components/csv-preview/CsvPreviewer.vue +38 -37
  100. package/app/components/csv-preview/CsvSettings.vue +6 -4
  101. package/app/components/csv-preview/CsvTable.vue +1 -1
  102. package/app/composables/batch_style.ts +5 -6
  103. package/app/composables/clipping_planes_widget.ts +73 -181
  104. package/app/composables/clipping_planes_widget_entries.ts +189 -0
  105. package/app/composables/copy_to_clipboard.ts +7 -0
  106. package/app/composables/global_attribute_style.ts +163 -83
  107. package/app/composables/hover_highlight.ts +46 -14
  108. package/app/composables/model_collections.ts +26 -13
  109. package/app/composables/model_components.ts +26 -13
  110. package/app/composables/project_manager.ts +76 -19
  111. package/app/composables/responsive_middle_truncate.ts +13 -13
  112. package/app/composables/stepper_tree.ts +34 -11
  113. package/app/composables/tree_filter.ts +66 -44
  114. package/app/composables/tree_keyboard_nav.ts +25 -11
  115. package/app/composables/tree_scroll.ts +44 -14
  116. package/app/composables/use_adaptive_styles.ts +66 -23
  117. package/app/composables/use_overlapping_picker.ts +66 -16
  118. package/app/composables/use_quick_colormap.ts +16 -5
  119. package/app/composables/virtual_tree.ts +75 -43
  120. package/app/composables/vtk_implicit_plane_widget.d.ts +2 -0
  121. package/app/plugins/auto_store_register.ts +2 -7
  122. package/app/plugins/click_outside_ignore_snackbars.client.ts +39 -0
  123. package/app/stores/app.ts +57 -192
  124. package/app/stores/app_helpers/extension.ts +179 -0
  125. package/app/stores/back.ts +37 -21
  126. package/app/stores/camera_manager.ts +22 -20
  127. package/app/stores/cloud.ts +17 -13
  128. package/app/stores/data.ts +88 -47
  129. package/app/stores/data_helpers/collections.ts +36 -38
  130. package/app/stores/data_helpers/mesh.ts +45 -36
  131. package/app/stores/data_style.ts +50 -28
  132. package/app/stores/feedback.ts +6 -6
  133. package/app/stores/hybrid_viewer.ts +41 -52
  134. package/app/stores/infra.ts +39 -37
  135. package/app/stores/menu.ts +23 -14
  136. package/app/stores/treeview.ts +72 -42
  137. package/app/stores/viewer.ts +39 -27
  138. package/app/utils/attributes.ts +3 -3
  139. package/app/utils/clipping_planes.ts +111 -14
  140. package/app/utils/color_picker.ts +57 -0
  141. package/app/utils/colormap.ts +58 -35
  142. package/app/utils/default_styles/index.ts +2 -2
  143. package/app/utils/default_styles/meshes.ts +107 -13
  144. package/app/utils/default_styles/models.ts +83 -14
  145. package/app/utils/extension.ts +47 -20
  146. package/app/utils/import_workflow.ts +21 -13
  147. package/app/utils/name_cleaner.ts +1 -1
  148. package/app/utils/string.ts +1 -1
  149. package/app/utils/treeview.ts +2 -2
  150. package/internal/database/base_database.ts +7 -3
  151. package/internal/database/database.ts +36 -26
  152. package/internal/database/extended_database.ts +1 -1
  153. package/internal/stores/data_style/mesh/cells/cell.ts +70 -34
  154. package/internal/stores/data_style/mesh/cells/color.ts +12 -6
  155. package/internal/stores/data_style/mesh/cells/common.ts +18 -8
  156. package/internal/stores/data_style/mesh/cells/index.ts +122 -42
  157. package/internal/stores/data_style/mesh/cells/textures.ts +12 -6
  158. package/internal/stores/data_style/mesh/cells/vertex.ts +75 -34
  159. package/internal/stores/data_style/mesh/cells/visibility.ts +15 -4
  160. package/internal/stores/data_style/mesh/edges/color.ts +12 -6
  161. package/internal/stores/data_style/mesh/edges/common.ts +14 -6
  162. package/internal/stores/data_style/mesh/edges/edge.ts +71 -39
  163. package/internal/stores/data_style/mesh/edges/index.ts +117 -42
  164. package/internal/stores/data_style/mesh/edges/vertex.ts +76 -39
  165. package/internal/stores/data_style/mesh/edges/visibility.ts +15 -4
  166. package/internal/stores/data_style/mesh/edges/width.ts +12 -4
  167. package/internal/stores/data_style/mesh/index.ts +30 -11
  168. package/internal/stores/data_style/mesh/points/color.ts +12 -6
  169. package/internal/stores/data_style/mesh/points/common.ts +21 -8
  170. package/internal/stores/data_style/mesh/points/index.ts +101 -50
  171. package/internal/stores/data_style/mesh/points/size.ts +12 -4
  172. package/internal/stores/data_style/mesh/points/vertex.ts +75 -34
  173. package/internal/stores/data_style/mesh/points/visibility.ts +17 -7
  174. package/internal/stores/data_style/mesh/polygons/color.ts +12 -6
  175. package/internal/stores/data_style/mesh/polygons/common.ts +23 -6
  176. package/internal/stores/data_style/mesh/polygons/index.ts +130 -70
  177. package/internal/stores/data_style/mesh/polygons/polygon.ts +77 -43
  178. package/internal/stores/data_style/mesh/polygons/textures.ts +12 -6
  179. package/internal/stores/data_style/mesh/polygons/vertex.ts +79 -39
  180. package/internal/stores/data_style/mesh/polygons/visibility.ts +16 -6
  181. package/internal/stores/data_style/mesh/polyhedra/color.ts +12 -6
  182. package/internal/stores/data_style/mesh/polyhedra/common.ts +14 -6
  183. package/internal/stores/data_style/mesh/polyhedra/index.ts +115 -56
  184. package/internal/stores/data_style/mesh/polyhedra/polyhedron.ts +80 -39
  185. package/internal/stores/data_style/mesh/polyhedra/vertex.ts +79 -39
  186. package/internal/stores/data_style/mesh/polyhedra/visibility.ts +16 -6
  187. package/internal/stores/data_style/model/blocks/color.ts +43 -13
  188. package/internal/stores/data_style/model/blocks/common.ts +21 -6
  189. package/internal/stores/data_style/model/blocks/index.ts +89 -59
  190. package/internal/stores/data_style/model/blocks/polyhedron.ts +101 -44
  191. package/internal/stores/data_style/model/blocks/vertex.ts +107 -42
  192. package/internal/stores/data_style/model/blocks/visibility.ts +17 -4
  193. package/internal/stores/data_style/model/color.ts +171 -83
  194. package/internal/stores/data_style/model/common.ts +70 -21
  195. package/internal/stores/data_style/model/corners/color.ts +43 -11
  196. package/internal/stores/data_style/model/corners/common.ts +25 -6
  197. package/internal/stores/data_style/model/corners/index.ts +66 -41
  198. package/internal/stores/data_style/model/corners/vertex.ts +105 -74
  199. package/internal/stores/data_style/model/corners/visibility.ts +19 -4
  200. package/internal/stores/data_style/model/edges/common.ts +12 -4
  201. package/internal/stores/data_style/model/edges/index.ts +2 -1
  202. package/internal/stores/data_style/model/edges/visibility.ts +24 -7
  203. package/internal/stores/data_style/model/index.ts +24 -11
  204. package/internal/stores/data_style/model/lines/color.ts +41 -11
  205. package/internal/stores/data_style/model/lines/common.ts +17 -6
  206. package/internal/stores/data_style/model/lines/edge.ts +105 -42
  207. package/internal/stores/data_style/model/lines/index.ts +86 -59
  208. package/internal/stores/data_style/model/lines/vertex.ts +105 -42
  209. package/internal/stores/data_style/model/lines/visibility.ts +17 -4
  210. package/internal/stores/data_style/model/points/common.ts +8 -4
  211. package/internal/stores/data_style/model/points/index.ts +10 -3
  212. package/internal/stores/data_style/model/points/size.ts +12 -4
  213. package/internal/stores/data_style/model/points/visibility.ts +16 -6
  214. package/internal/stores/data_style/model/selection.ts +80 -58
  215. package/internal/stores/data_style/model/surfaces/color.ts +41 -11
  216. package/internal/stores/data_style/model/surfaces/common.ts +23 -6
  217. package/internal/stores/data_style/model/surfaces/index.ts +89 -59
  218. package/internal/stores/data_style/model/surfaces/polygon.ts +107 -67
  219. package/internal/stores/data_style/model/surfaces/vertex.ts +111 -67
  220. package/internal/stores/data_style/model/surfaces/visibility.ts +18 -5
  221. package/internal/stores/data_style/model/visibility.ts +82 -20
  222. package/internal/stores/data_style/state.ts +77 -65
  223. package/internal/stores/hybrid_viewer/brightness.ts +49 -31
  224. package/internal/stores/hybrid_viewer/camera.ts +191 -177
  225. package/internal/stores/hybrid_viewer/camera_animation.ts +11 -10
  226. package/internal/stores/hybrid_viewer/core.ts +64 -0
  227. package/internal/stores/hybrid_viewer/filters.ts +10 -16
  228. package/internal/stores/hybrid_viewer/highlight.ts +91 -130
  229. package/internal/stores/hybrid_viewer/ruler.ts +24 -15
  230. package/internal/stores/hybrid_viewer/scene.ts +96 -117
  231. package/internal/stores/hybrid_viewer/viewport.ts +74 -65
  232. package/internal/stores/hybrid_viewer/vtk_types.ts +13 -29
  233. package/internal/utils/api_fetch.ts +54 -23
  234. package/internal/utils/upload_file.ts +74 -53
  235. package/internal/utils/viewer_call.ts +22 -13
  236. package/internal/utils/ws_client.ts +24 -13
  237. package/nuxt.config.ts +58 -1
  238. package/package.json +20 -8
  239. package/server/api/cloud/extensions/run.post.ts +6 -10
  240. package/server/api/local/app/project_folder_path.post.ts +4 -4
  241. package/server/api/local/app/run_back.post.ts +5 -7
  242. package/server/api/local/app/run_viewer.post.ts +5 -7
  243. package/server/api/local/extensions/kill.post.ts +4 -3
  244. package/server/api/local/extensions/run.post.ts +7 -10
  245. package/server/api/local/extensions/upload.put.ts +44 -54
  246. package/server/api/microservice/app/get_is_app_ready.get.ts +4 -5
  247. package/server/api/microservice/app/set_app_base_url.post.ts +5 -6
  248. package/server/api/microservice/app/set_back_base_url.post.ts +5 -6
  249. package/server/api/microservice/app/set_is_app_ready.post.ts +5 -6
  250. package/server/api/microservice/app/set_viewer_base_url.post.ts +5 -6
  251. package/server/api/microservice/extensions/download.post.ts +5 -4
  252. package/server/api/serverless/run_cloud.post.ts +53 -11
  253. package/server/utils/app_config.ts +29 -22
  254. package/server/utils/cleanup.ts +60 -30
  255. package/server/utils/cloud.ts +9 -8
  256. package/server/utils/extension.ts +23 -9
  257. package/server/utils/microservices.ts +33 -24
  258. package/server/utils/path.ts +4 -4
  259. package/server/utils/scripts.ts +26 -23
  260. package/server/utils/server.ts +2 -2
  261. package/server/utils/server_config.ts +41 -27
  262. package/server/utils/stream.ts +6 -0
  263. package/server/utils/ws_client.ts +42 -8
  264. package/shared/scripts.ts +15 -10
  265. package/shared/utils/call_raw.ts +23 -16
  266. package/shared/utils/call_schema.ts +5 -8
  267. package/shared/utils/fetch_raw.ts +87 -47
  268. package/shared/utils/fetch_schema.ts +6 -9
  269. package/shared/utils/file.ts +8 -2
  270. package/shared/utils/response_handlers/load.ts +26 -11
  271. package/shared/utils/types.ts +9 -9
  272. package/shared/utils/validate_schema.ts +1 -1
  273. package/app/components/Viewer/ObjectTree/Views/ModelComponents.vue +0 -276
  274. package/server/types/vendor.d.ts +0 -64
  275. package/server/utils/server_config.js +0 -43
  276. package/shared/utils/call_raw.js +0 -30
  277. package/shared/utils/fetch_raw.js +0 -40
  278. /package/{opengeodeweb_front_schemas.js → .build/opengeodeweb_front_schemas.js} +0 -0
  279. /package/{server → .build/server}/utils/server.js +0 -0
  280. /package/{shared → .build/shared}/app_mode.js +0 -0
  281. /package/{shared → .build/shared}/utils/parse_boolean.js +0 -0
  282. /package/{shared → .build/shared}/utils/types.js +0 -0
@@ -1,11 +1,9 @@
1
- // Not auto-fixable (eslint's sort-imports core rule has no autofixer) and this file's import order doesn't match its syntax-kind-then-alphabetical requirement - left as-is rather than manually reordered across the codebase for a purely cosmetic rule.
2
- // oxlint-disable eslint/sort-imports
1
+ import type { JsonRpcSchema, RequestHandlersWithValidation } from "@ogw_shared/utils/types.js";
3
2
  import { endRequestLog, startRequestLog } from "@ogw_front/utils/log";
3
+ import type { Microservice } from "./api_fetch.js";
4
+ import type { RpcClient } from "@ogw_shared/utils/call_raw.js";
4
5
  import { callSchema } from "@ogw_shared/utils/call_schema";
5
6
  import { useFeedbackStore } from "@ogw_front/stores/feedback";
6
- import type { JsonRpcSchema, RequestHandlersWithValidation } from "@ogw_shared/utils/types.js";
7
- import type { RpcClient } from "@ogw_shared/utils/call_raw.js";
8
- import type { Microservice } from "./api_fetch.js";
9
7
 
10
8
  interface ViewerMicroservice extends Microservice {
11
9
  client: RpcClient;
@@ -23,7 +21,17 @@ interface RpcErrorLike {
23
21
  message?: string;
24
22
  }
25
23
 
26
- function viewer_call(
24
+ function toRpcErrorLike(value: unknown): RpcErrorLike {
25
+ if (typeof value !== "object" || value === null) {
26
+ return {};
27
+ }
28
+ return {
29
+ code: "code" in value && typeof value.code === "number" ? value.code : undefined,
30
+ message: "message" in value && typeof value.message === "string" ? value.message : undefined,
31
+ };
32
+ }
33
+
34
+ async function viewer_call(
27
35
  microservice: ViewerMicroservice,
28
36
  { schema, params = {}, timeout }: ViewerCallParams,
29
37
  {
@@ -31,12 +39,13 @@ function viewer_call(
31
39
  response_function,
32
40
  response_error_function,
33
41
  }: RequestHandlersWithValidation = {},
34
- ) {
42
+ ): Promise<unknown> {
35
43
  const feedbackStore = useFeedbackStore();
36
44
  const { client } = microservice;
45
+ microservice.start_request();
37
46
 
38
47
  const requestStartingTime = startRequestLog(microservice, schema);
39
- return callSchema(
48
+ const result = await callSchema(
40
49
  {
41
50
  schema,
42
51
  params,
@@ -46,7 +55,7 @@ function viewer_call(
46
55
  {
47
56
  request_error_function(error: unknown) {
48
57
  microservice.stop_request();
49
- const typedError = error as RpcErrorLike;
58
+ const typedError = toRpcErrorLike(error);
50
59
  feedbackStore.add_error(
51
60
  typedError.code ?? 0,
52
61
  schema.$id,
@@ -54,7 +63,7 @@ function viewer_call(
54
63
  typedError.message ?? "",
55
64
  );
56
65
  if (request_error_function) {
57
- request_error_function(error);
66
+ void request_error_function(error);
58
67
  }
59
68
  },
60
69
  response_function(data: unknown) {
@@ -66,8 +75,7 @@ function viewer_call(
66
75
  },
67
76
  response_error_function(response: unknown) {
68
77
  microservice.stop_request();
69
- // Pre-existing bug: this used an undefined `error` identifier (ReferenceError at runtime); fixed to use `response`, mirroring request_error_function above.
70
- const typedResponse = response as RpcErrorLike;
78
+ const typedResponse = toRpcErrorLike(response);
71
79
  feedbackStore.add_error(
72
80
  typedResponse.code ?? 0,
73
81
  schema.$id,
@@ -75,7 +83,7 @@ function viewer_call(
75
83
  typedResponse.message ?? "",
76
84
  );
77
85
  if (response_error_function) {
78
- response_error_function(response);
86
+ void response_error_function(response);
79
87
  }
80
88
  },
81
89
  validation_error_function({ code, name, error }) {
@@ -84,6 +92,7 @@ function viewer_call(
84
92
  },
85
93
  },
86
94
  );
95
+ return result;
87
96
  }
88
97
 
89
98
  export { viewer_call };
@@ -1,32 +1,43 @@
1
- // Not auto-fixable (eslint's sort-imports core rule has no autofixer) and this file's import order doesn't match its syntax-kind-then-alphabetical requirement - left as-is rather than manually reordered across the codebase for a purely cosmetic rule.
2
- // oxlint-disable eslint/sort-imports
3
1
  // Third party imports
4
- import vtkWSLinkClient, { newInstance } from "@kitware/vtk.js/IO/Core/WSLinkClient";
5
- // oxlint-disable-next-line eslint/no-duplicate-imports
6
- import type { vtkWSLinkClient as VtkWSLinkClient } from "@kitware/vtk.js/IO/Core/WSLinkClient";
2
+ import vtkWSLinkClient, {
3
+ type vtkWSLinkClient as VtkWSLinkClient,
4
+ newInstance,
5
+ } from "@kitware/vtk.js/IO/Core/WSLinkClient";
7
6
  import SmartConnect from "wslink/src/SmartConnect";
8
- import _ from "lodash";
9
7
 
10
8
  interface WsClientCallbacks {
11
9
  onConnectionClose?: () => void;
12
10
  }
13
11
 
12
+ // Wslink's connection event shape is untyped upstream; this describes the fields we read.
13
+ interface WsConnectionEvent {
14
+ response?: { error?: string };
15
+ }
16
+
17
+ function isVtkWSLinkClient(value: unknown): value is VtkWSLinkClient {
18
+ return (
19
+ typeof value === "object" &&
20
+ value !== null &&
21
+ "connect" in value &&
22
+ "onConnectionError" in value &&
23
+ "onConnectionClose" in value
24
+ );
25
+ }
26
+
14
27
  async function initWebSocketClient(
15
28
  baseUrl: string,
16
29
  initialClient: unknown = {},
17
30
  { onConnectionClose }: WsClientCallbacks = {},
18
31
  ): Promise<VtkWSLinkClient> {
19
32
  vtkWSLinkClient.setSmartConnectClass(SmartConnect);
20
- const client = (_.isEmpty(initialClient) ? newInstance() : initialClient) as VtkWSLinkClient;
33
+ const client = isVtkWSLinkClient(initialClient) ? initialClient : newInstance();
21
34
 
22
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- wslink's httpReq shape is untyped upstream.
23
- client.onConnectionError((httpReq: any) => {
24
- const message = httpReq?.response?.error || `Connection error`;
35
+ client.onConnectionError((httpReq: WsConnectionEvent) => {
36
+ const message = httpReq.response?.error ?? "Connection error";
25
37
  console.error(message);
26
38
  });
27
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- wslink's httpReq shape is untyped upstream.
28
- client.onConnectionClose((httpReq: any) => {
29
- const message = httpReq?.response?.error || `Connection close`;
39
+ client.onConnectionClose((httpReq: WsConnectionEvent) => {
40
+ const message = httpReq.response?.error ?? "Connection close";
30
41
  onConnectionClose?.();
31
42
  console.error(message);
32
43
  });
package/nuxt.config.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  // Node imports
2
+ import fs from "node:fs";
2
3
  import path from "node:path";
3
4
 
4
5
  // Third party imports
@@ -9,6 +10,28 @@ import package_json from "./package.json";
9
10
 
10
11
  const __dirname = import.meta.dirname;
11
12
 
13
+ // Oxlint's type-aware linter auto-discovers each file's nearest tsconfig.json
14
+ // By walking up directories, and any "extends" on that discovered file makes
15
+ // Its whole type-aware resolution collapse: every symbol coming through the
16
+ // Aliases normally only defined in .nuxt/tsconfig.json (@ogw_shared, etc.,
17
+ // But also Nuxt's own #app/#imports/defineStore auto-imports) becomes an
18
+ // `error` type, even though tsc/vue-tsc resolve the exact same "extends"
19
+ // Chain correctly (oxc-project/oxc#22345). The only fix is for the root
20
+ // Tsconfig.json to be fully self-contained: no "extends", with its own copy
21
+ // Of .nuxt/tsconfig.json's compilerOptions.paths (re-relativized here, since
22
+ // They're written relative to .nuxt/) and a deliberately project-wide
23
+ // "include" (unlike .nuxt/tsconfig.json's own include, which only covers
24
+ // Nuxt's conventional folders and would otherwise silently drop internal/,
25
+ // Tests/, etc. from the program). Regenerated on every Nuxt prepare so it
26
+ // Can never drift from what Nuxt actually resolves.
27
+ function remap_path_to_root(target: string, build_dir: string): string {
28
+ const relative = path
29
+ .relative(__dirname, path.resolve(build_dir, target))
30
+ .split(path.sep)
31
+ .join("/");
32
+ return relative.startsWith("./") || relative.startsWith("../") ? relative : `./${relative}`;
33
+ }
34
+
12
35
  // Nuxt requires this file's config object as the default export; the shared org lint config's no-default-export override only lists *.config.js, not *.config.ts, since this file predates the TypeScript migration.
13
36
  // oxlint-disable-next-line import/no-default-export
14
37
  export default defineNuxtConfig({
@@ -17,7 +40,7 @@ export default defineNuxtConfig({
17
40
  COMMAND_BACK: "opengeodeweb-back",
18
41
  COMMAND_VIEWER: "opengeodeweb-viewer",
19
42
  NUXT_ROOT_PATH: __dirname,
20
- MODE: process.env.MODE || "CLOUD",
43
+ MODE: process.env.MODE ?? "CLOUD",
21
44
  PROJECT: package_json.name,
22
45
  },
23
46
  },
@@ -108,4 +131,38 @@ export default defineNuxtConfig({
108
131
  ],
109
132
  },
110
133
  },
134
+ typescript: {
135
+ tsConfig: {
136
+ compilerOptions: {
137
+ types: ["node", "ws", "busboy"],
138
+ },
139
+ },
140
+ },
141
+
142
+ hooks: {
143
+ "prepare:types": ({ tsConfig }) => {
144
+ const paths = tsConfig.compilerOptions?.paths;
145
+ if (!paths) {
146
+ return;
147
+ }
148
+ const build_dir = path.resolve(__dirname, ".nuxt");
149
+ const root_paths = Object.fromEntries(
150
+ Object.entries(paths).map(([alias, targets]) => [
151
+ alias,
152
+ targets.map((target) => remap_path_to_root(target, build_dir)),
153
+ ]),
154
+ );
155
+ fs.writeFileSync(
156
+ path.resolve(__dirname, "tsconfig.json"),
157
+ `${JSON.stringify(
158
+ {
159
+ compilerOptions: { ...tsConfig.compilerOptions, paths: root_paths },
160
+ include: ["**/*", "./.nuxt/nuxt.d.ts"],
161
+ },
162
+ undefined,
163
+ 2,
164
+ )}\n`,
165
+ );
166
+ },
167
+ },
111
168
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geode/opengeodeweb-front",
3
- "version": "10.34.0-rc.9",
3
+ "version": "10.34.0",
4
4
  "description": "OpenSource Vue/Nuxt/Pinia/Vuetify framework for web applications",
5
5
  "homepage": "https://github.com/Geode-solutions/OpenGeodeWeb-Front",
6
6
  "bugs": {
@@ -21,6 +21,7 @@
21
21
  "internal",
22
22
  "server",
23
23
  "shared",
24
+ ".build",
24
25
  "nuxt.config.ts",
25
26
  "opengeodeweb_front_schemas.json",
26
27
  "opengeodeweb_front_schemas.js",
@@ -32,6 +33,14 @@
32
33
  "main": "./nuxt.config.ts",
33
34
  "exports": {
34
35
  ".": "./nuxt.config.ts",
36
+ "./server/utils/*.js": {
37
+ "types": "./server/utils/*.ts",
38
+ "default": "./.build/server/utils/*.js"
39
+ },
40
+ "./shared/*.js": {
41
+ "types": "./shared/*.ts",
42
+ "default": "./.build/shared/*.js"
43
+ },
35
44
  "./*": "./*"
36
45
  },
37
46
  "publishConfig": {
@@ -53,13 +62,15 @@
53
62
  "prepublishOnly": "npm run build"
54
63
  },
55
64
  "dependencies": {
56
- "@geode/opengeodeweb-back": "next",
57
- "@geode/opengeodeweb-viewer": "next",
58
- "@google-cloud/run": "3.2.0",
65
+ "@geode/opengeodeweb-back": "latest",
66
+ "@geode/opengeodeweb-viewer": "latest",
67
+ "@google-cloud/run": "4.1.0",
59
68
  "@kitware/vtk.js": "33.3.0",
60
69
  "@mdi/font": "7.4.47",
61
70
  "@pinia/nuxt": "1.0.1",
62
- "@types/node": "22.15.3",
71
+ "@types/busboy": "1.5.4",
72
+ "@types/node": "22.20.3",
73
+ "@types/ws": "8.18.1",
63
74
  "@vueuse/components": "13.1.0",
64
75
  "@vueuse/core": "13.1.0",
65
76
  "@vueuse/nuxt": "13.1.0",
@@ -69,8 +80,8 @@
69
80
  "conf": "15.1.0",
70
81
  "dexie": "4.2.1",
71
82
  "get-port-please": "3.2.0",
72
- "google-auth-library": "10.6.1",
73
- "googleapis": "171.4.0",
83
+ "google-auth-library": "11.0.2",
84
+ "googleapis": "181.0.0",
74
85
  "js-file-download": "0.4.12",
75
86
  "jszip": "3.10.1",
76
87
  "lodash": "4.18.1",
@@ -89,7 +100,8 @@
89
100
  "vuetify": "4.2.0",
90
101
  "vuetify-nuxt-module": "1.0.0-rc.5",
91
102
  "ws": "8.21.2",
92
- "wslink": "1.12.4"
103
+ "wslink": "1.12.4",
104
+ "zod": "4.4.3"
93
105
  },
94
106
  "devDependencies": {
95
107
  "@nuxt/test-utils": "4.1.0",
@@ -2,7 +2,7 @@
2
2
  import fs from "node:fs";
3
3
 
4
4
  // Third party imports
5
- import { createError, defineEventHandler, readBody } from "h3";
5
+ import { type H3Event, createError, defineEventHandler, readBody } from "h3";
6
6
 
7
7
  // Local imports
8
8
  import {
@@ -25,15 +25,13 @@ interface RunExtensionsBody {
25
25
  projectName: string;
26
26
  }
27
27
 
28
- export default defineEventHandler(async (event) => {
28
+ export default defineEventHandler(async (event: H3Event) => {
29
29
  try {
30
30
  console.log("NITRO: runExtensions", event);
31
31
  const { projectFolderPath, projectName } = await readBody<RunExtensionsBody>(event);
32
32
  const extensionsConfig = extensionsConf(projectName);
33
33
  const extensionsArray = await Promise.all(
34
- Object.keys(extensionsConfig).map(async (extensionId) => {
35
- // Safe: extensionId comes from Object.keys(extensionsConfig) itself.
36
- const extensionPath = extensionsConfig[extensionId]!.path;
34
+ Object.entries(extensionsConfig).map(async ([extensionId, { path: extensionPath }]) => {
37
35
  const unzippedExtensionPath = await unzipFile(
38
36
  extensionPath,
39
37
  extensionFolderPath(projectFolderPath, extensionId),
@@ -49,12 +47,10 @@ export default defineEventHandler(async (event) => {
49
47
  const port = await runExtension(id, backendExecutable, unzippedExtensionPath, {
50
48
  projectFolderPath,
51
49
  });
52
- await addMicroserviceMetadatas(projectFolderPath, {
50
+ addMicroserviceMetadatas(projectFolderPath, {
53
51
  type: "back",
54
52
  name,
55
- // RunExtension can exhaust its port-conflict retries and return undefined
56
- // (pre-existing bug: addMicroserviceMetadatas/URLs then embed "undefined").
57
- port: port as number,
53
+ port,
58
54
  });
59
55
  return {
60
56
  id,
@@ -74,7 +70,7 @@ export default defineEventHandler(async (event) => {
74
70
  console.error("Error running extensions:", error);
75
71
  throw createError({
76
72
  statusCode: 500,
77
- statusMessage: (error as Error).message,
73
+ statusMessage: error instanceof Error ? error.message : String(error),
78
74
  });
79
75
  }
80
76
  });
@@ -1,7 +1,7 @@
1
1
  // Node imports
2
2
 
3
3
  // Third party imports
4
- import { createError, defineEventHandler, readBody } from "h3";
4
+ import { type H3Event, createError, defineEventHandler, readBody } from "h3";
5
5
 
6
6
  // Local imports
7
7
  import {
@@ -13,11 +13,11 @@ interface ProjectFolderPathBody {
13
13
  PROJECT: string;
14
14
  }
15
15
 
16
- export default defineEventHandler(async (event) => {
16
+ export default defineEventHandler(async (event: H3Event) => {
17
17
  try {
18
18
  const { PROJECT } = await readBody<ProjectFolderPathBody>(event);
19
19
  const projectFolderPath = generateProjectFolderPath(PROJECT);
20
- await createPath(projectFolderPath);
20
+ createPath(projectFolderPath);
21
21
 
22
22
  return {
23
23
  statusCode: 200,
@@ -27,7 +27,7 @@ export default defineEventHandler(async (event) => {
27
27
  console.log(error);
28
28
  throw createError({
29
29
  statusCode: 500,
30
- statusMessage: (error as Error).message,
30
+ statusMessage: error instanceof Error ? error.message : String(error),
31
31
  });
32
32
  }
33
33
  });
@@ -1,7 +1,7 @@
1
1
  // Node imports
2
2
 
3
3
  // Third party imports
4
- import { createError, defineEventHandler, readBody } from "h3";
4
+ import { type H3Event, createError, defineEventHandler, readBody } from "h3";
5
5
 
6
6
  // Local imports
7
7
  import {
@@ -15,16 +15,14 @@ interface RunBackBody {
15
15
  args: { projectFolderPath: string; [key: string]: unknown };
16
16
  }
17
17
 
18
- export default defineEventHandler(async (event) => {
18
+ export default defineEventHandler(async (event: H3Event) => {
19
19
  try {
20
20
  const { COMMAND_BACK, NUXT_ROOT_PATH, args } = await readBody<RunBackBody>(event);
21
21
  const port = await runBack(COMMAND_BACK, NUXT_ROOT_PATH, args);
22
- await addMicroserviceMetadatas(args.projectFolderPath, {
22
+ addMicroserviceMetadatas(args.projectFolderPath, {
23
23
  type: "back",
24
24
  name: COMMAND_BACK,
25
- // RunBack can exhaust its port-conflict retries and return undefined
26
- // (pre-existing bug: addMicroserviceMetadatas/URLs then embed "undefined").
27
- port: port as number,
25
+ port,
28
26
  });
29
27
 
30
28
  return {
@@ -35,7 +33,7 @@ export default defineEventHandler(async (event) => {
35
33
  console.log(error);
36
34
  throw createError({
37
35
  statusCode: 500,
38
- statusMessage: (error as Error).message,
36
+ statusMessage: error instanceof Error ? error.message : String(error),
39
37
  });
40
38
  }
41
39
  });
@@ -1,7 +1,7 @@
1
1
  // Node imports
2
2
 
3
3
  // Third party imports
4
- import { createError, defineEventHandler, readBody } from "h3";
4
+ import { type H3Event, createError, defineEventHandler, readBody } from "h3";
5
5
 
6
6
  // Local imports
7
7
  import {
@@ -15,16 +15,14 @@ interface RunViewerBody {
15
15
  args: { projectFolderPath: string; [key: string]: unknown };
16
16
  }
17
17
 
18
- export default defineEventHandler(async (event) => {
18
+ export default defineEventHandler(async (event: H3Event) => {
19
19
  try {
20
20
  const { COMMAND_VIEWER, NUXT_ROOT_PATH, args } = await readBody<RunViewerBody>(event);
21
21
  const port = await runViewer(COMMAND_VIEWER, NUXT_ROOT_PATH, args);
22
- await addMicroserviceMetadatas(args.projectFolderPath, {
22
+ addMicroserviceMetadatas(args.projectFolderPath, {
23
23
  type: "viewer",
24
24
  name: COMMAND_VIEWER,
25
- // RunViewer can exhaust its port-conflict retries and return undefined
26
- // (pre-existing bug: addMicroserviceMetadatas/URLs then embed "undefined").
27
- port: port as number,
25
+ port,
28
26
  });
29
27
 
30
28
  return {
@@ -35,7 +33,7 @@ export default defineEventHandler(async (event) => {
35
33
  console.log(error);
36
34
  throw createError({
37
35
  statusCode: 500,
38
- statusMessage: (error as Error).message,
36
+ statusMessage: error instanceof Error ? error.message : String(error),
39
37
  });
40
38
  }
41
39
  });
@@ -1,7 +1,7 @@
1
1
  // Node imports
2
2
 
3
3
  // Third party imports
4
- import { createError, defineEventHandler, readBody } from "h3";
4
+ import { type H3Event, createError, defineEventHandler, readBody } from "h3";
5
5
 
6
6
  // Local imports
7
7
  import {
@@ -19,7 +19,7 @@ interface KillExtensionBody {
19
19
  extensionId: string;
20
20
  }
21
21
 
22
- export default defineEventHandler(async (event) => {
22
+ export default defineEventHandler(async (event: H3Event) => {
23
23
  try {
24
24
  const body = await readBody<KillExtensionBody>(event);
25
25
  const { projectFolderPath, projectName, extensionId } = body;
@@ -43,7 +43,8 @@ export default defineEventHandler(async (event) => {
43
43
  console.error("Error killing extension:", error);
44
44
  throw createError({
45
45
  statusCode: 500,
46
- statusMessage: (error as Error).message,
46
+
47
+ statusMessage: error instanceof Error ? error.message : String(error),
47
48
  });
48
49
  }
49
50
  });
@@ -2,7 +2,7 @@
2
2
  import fs from "node:fs";
3
3
 
4
4
  // Third party imports
5
- import { createError, defineEventHandler, readBody } from "h3";
5
+ import { type H3Event, createError, defineEventHandler, readBody } from "h3";
6
6
 
7
7
  // Local imports
8
8
  import {
@@ -25,15 +25,13 @@ interface RunExtensionsBody {
25
25
  projectName: string;
26
26
  }
27
27
 
28
- export default defineEventHandler(async (event) => {
28
+ export default defineEventHandler(async (event: H3Event) => {
29
29
  try {
30
30
  console.log("NITRO: runExtensions", event);
31
31
  const { projectFolderPath, projectName } = await readBody<RunExtensionsBody>(event);
32
32
  const extensionsConfig = extensionsConf(projectName);
33
33
  const extensionsArray = await Promise.all(
34
- Object.keys(extensionsConfig).map(async (extensionId) => {
35
- // Safe: extensionId comes from Object.keys(extensionsConfig) itself.
36
- const extensionPath = extensionsConfig[extensionId]!.path;
34
+ Object.entries(extensionsConfig).map(async ([extensionId, { path: extensionPath }]) => {
37
35
  const unzippedExtensionPath = await unzipFile(
38
36
  extensionPath,
39
37
  extensionFolderPath(projectFolderPath, extensionId),
@@ -49,12 +47,10 @@ export default defineEventHandler(async (event) => {
49
47
  const port = await runBack(backendExecutable, unzippedExtensionPath, {
50
48
  projectFolderPath,
51
49
  });
52
- await addMicroserviceMetadatas(projectFolderPath, {
50
+ addMicroserviceMetadatas(projectFolderPath, {
53
51
  type: "back",
54
52
  name,
55
- // RunBack can exhaust its port-conflict retries and return undefined
56
- // (pre-existing bug: addMicroserviceMetadatas/URLs then embed "undefined").
57
- port: port as number,
53
+ port,
58
54
  });
59
55
  return {
60
56
  id,
@@ -74,7 +70,8 @@ export default defineEventHandler(async (event) => {
74
70
  console.error("Error running extensions:", error);
75
71
  throw createError({
76
72
  statusCode: 500,
77
- statusMessage: (error as Error).message,
73
+
74
+ statusMessage: error instanceof Error ? error.message : String(error),
78
75
  });
79
76
  }
80
77
  });
@@ -1,81 +1,71 @@
1
- // Not auto-fixable (eslint's sort-imports core rule has no autofixer) and this file's import order doesn't match its syntax-kind-then-alphabetical requirement - left as-is rather than manually reordered across the codebase for a purely cosmetic rule.
2
- // oxlint-disable eslint/sort-imports
3
- /// <reference path="../../../types/vendor.d.ts" />
4
1
  // Node imports
5
- import { finished, pipeline } from "node:stream/promises";
6
2
  import { Readable } from "node:stream";
7
- import type { ReadableStream as NodeReadableStream } from "node:stream/web";
8
3
  import fs from "node:fs";
4
+ import { pipeline } from "node:stream/promises";
9
5
 
10
6
  // Third party imports
11
- import { createError, defineEventHandler, getRequestHeaders, getRequestWebStream } from "h3";
12
- import busboy from "busboy";
7
+ import { type H3Event, createError, defineEventHandler, getQuery, getRequestWebStream } from "h3";
13
8
 
14
9
  // Local imports
15
10
  import {
16
11
  registerExtensionFile,
17
12
  targetExtensionFilePath,
18
13
  } from "@geode/opengeodeweb-front/server/utils/app_config.ts";
14
+ import { BYTES_PER_KIBIBYTE } from "@ogw_shared/utils/file.js";
15
+ import { toNodeWebStream } from "@geode/opengeodeweb-front/server/utils/stream.ts";
19
16
 
17
+ const CODE_200 = 200;
20
18
  const CODE_201 = 201;
21
- const BYTES_PER_KIBIBYTE = 1024;
22
19
  const MAX_FILE_MEGABYTES = 500;
23
20
  const FILE_SIZE_LIMIT = MAX_FILE_MEGABYTES * BYTES_PER_KIBIBYTE * BYTES_PER_KIBIBYTE;
24
21
 
25
- export default defineEventHandler(async (event) => {
26
- const writePromises: Promise<void>[] = [];
27
- const savedFiles: string[] = [];
28
-
29
- const busboyInstance = busboy({
30
- headers: getRequestHeaders(event),
31
- limits: {
32
- fileSize: FILE_SIZE_LIMIT,
33
- files: 1,
34
- },
35
- });
36
- let projectName = "";
37
- busboyInstance.on("field", (name, value) => {
38
- console.log(`Field ${name}: ${value}`);
39
- if (name === "projectName") {
40
- projectName = value;
41
- }
42
- });
22
+ function requiredQueryString(event: H3Event, key: string): string {
23
+ const value = getQuery(event)[key];
24
+ if (typeof value !== "string" || value.length === 0) {
25
+ throw createError({ statusCode: 400, message: `Missing "${key}" query parameter` });
26
+ }
27
+ return value;
28
+ }
43
29
 
44
- busboyInstance.on("file", (fieldname, fileStream, info) => {
45
- if (fieldname !== "file") {
46
- // Drain & ignore unwanted fields
47
- fileStream.resume();
48
- return;
49
- }
50
- const targetPath = targetExtensionFilePath(projectName, info.filename);
51
- const writePromise = (async () => {
52
- const writeStream = fs.createWriteStream(targetPath);
53
- await pipeline(fileStream, writeStream);
54
- savedFiles.push(targetPath);
55
- console.log("File written:", targetPath);
56
- })();
57
- writePromises.push(writePromise);
58
- fileStream.on("limit", () => busboyInstance.destroy(new Error("File too large")));
59
- });
30
+ function requiredQueryInt(event: H3Event, key: string): number {
31
+ const parsed = Math.trunc(Number(requiredQueryString(event, key)));
32
+ if (!Number.isInteger(parsed) || parsed < 0) {
33
+ throw createError({ statusCode: 400, message: `Invalid "${key}" query parameter` });
34
+ }
35
+ return parsed;
36
+ }
60
37
 
61
- busboyInstance.on("filesLimit", () => busboyInstance.destroy(new Error("Too many files")));
62
- busboyInstance.on("partsLimit", () => busboyInstance.destroy(new Error("Too many parts")));
38
+ // The file is sent as a raw (non-multipart) body, split into sequential chunks the client uploads in order (see OpenGeodeWeb-Front's upload_file.ts and OpenGeodeWeb-Back's upload_file route, which use the same protocol). Each chunk is appended to a `.part` file; the last one triggers the existing zip-metadata registration.
39
+ export default defineEventHandler(async (event: H3Event) => {
40
+ const projectName = requiredQueryString(event, "projectName");
41
+ const filename = requiredQueryString(event, "filename");
42
+ const totalChunks = requiredQueryInt(event, "total_chunks");
43
+ const chunkIndex = requiredQueryInt(event, "chunk_index");
44
+ if (chunkIndex >= totalChunks) {
45
+ throw createError({ statusCode: 400, message: "chunk_index must be less than total_chunks" });
46
+ }
63
47
 
64
48
  const webStream = getRequestWebStream(event);
65
49
  if (!webStream) {
66
50
  throw createError({ statusCode: 400, message: "No request body received" });
67
51
  }
68
- // H3's ReadableStream (lib.dom) and Node's stream/web ReadableStream are structurally
69
- // The same at runtime but the two ambient type declarations aren't nominally compatible.
70
- Readable.fromWeb(webStream as unknown as NodeReadableStream).pipe(busboyInstance);
71
- await finished(busboyInstance);
72
- if (writePromises.length > 0) {
73
- await Promise.all(writePromises);
74
- console.log("All disk writes completed");
52
+
53
+ const targetPath = targetExtensionFilePath(projectName, filename);
54
+ const partPath = `${targetPath}.part`;
55
+ const writeStream = fs.createWriteStream(partPath, { flags: chunkIndex === 0 ? "w" : "a" });
56
+ await pipeline(Readable.fromWeb(toNodeWebStream(webStream)), writeStream);
57
+
58
+ const { size } = await fs.promises.stat(partPath);
59
+ if (size > FILE_SIZE_LIMIT) {
60
+ await fs.promises.unlink(partPath);
61
+ throw createError({ statusCode: 400, message: "File too large" });
75
62
  }
76
- if (savedFiles.length === 0) {
77
- throw createError({ statusCode: 400, message: "No file received" });
63
+
64
+ if (chunkIndex < totalChunks - 1) {
65
+ return { statusCode: CODE_200 };
78
66
  }
79
- await Promise.all(savedFiles.map(async (file) => await registerExtensionFile(projectName, file)));
67
+
68
+ await fs.promises.rename(partPath, targetPath);
69
+ await registerExtensionFile(projectName, targetPath);
80
70
  return { statusCode: CODE_201 };
81
71
  });