catalyst-core 0.1.0-beta.2 → 0.1.0-beta.4

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 (103) hide show
  1. package/README.md +1 -1
  2. package/bin/catalyst.js +8 -1
  3. package/changelog.md +6 -0
  4. package/dist/native/androidProject/app/build.gradle.kts +9 -0
  5. package/dist/native/androidProject/app/src/main/AndroidManifest.xml +2 -1
  6. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/BridgeMessageValidator.kt +1 -1
  7. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/CustomWebview.kt +17 -1
  8. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/MainActivity.kt +31 -3
  9. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/NativeBridge.kt +148 -0
  10. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/NativeCameraManager.kt +337 -0
  11. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/TransitionManager.kt +202 -0
  12. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/WebCacheManager.kt +3 -3
  13. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/BarcodeDetector.kt +123 -0
  14. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/CameraSessionManager.kt +244 -0
  15. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/HoldController.kt +70 -0
  16. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/TorchController.kt +57 -0
  17. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/VideoStreamState.kt +41 -0
  18. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/VideoStreamStateMachine.kt +40 -0
  19. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/ViewfinderMapper.kt +75 -0
  20. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/camera/ZoomController.kt +156 -0
  21. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/plugins/CatalystPlugin.kt +7 -0
  22. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/plugins/GeneratedPluginIndex.kt +6 -0
  23. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/plugins/PluginBridge.kt +253 -0
  24. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/security/FridaDetector.kt +16 -5
  25. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/BridgeUtils.kt +42 -5
  26. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/FrameworkServerUtils.kt +7 -3
  27. package/dist/native/androidProject/app/src/main/res/drawable/debug_viewfinder_border.xml +8 -0
  28. package/dist/native/androidProject/app/src/main/res/layout/activity_main.xml +37 -0
  29. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/plugins/PluginBridgeTest.kt +139 -0
  30. package/dist/native/androidSetup.js +1 -1
  31. package/dist/native/bridge/WebBridge.js +5 -5
  32. package/dist/native/bridge/constants/NativeInterfaces.js +9 -5
  33. package/dist/native/bridge/hooks/index.js +1 -0
  34. package/dist/native/bridge/hooks/useCamera.js +9 -0
  35. package/dist/native/bridge/hooks/useDataProtection.js +2 -0
  36. package/dist/native/bridge/hooks/useDeviceInfo.js +2 -0
  37. package/dist/native/bridge/hooks/useFilePicker.js +2 -0
  38. package/dist/native/bridge/hooks/useGoogleSignIn.js +1 -0
  39. package/dist/native/bridge/hooks/useHapticFeedback.js +1 -0
  40. package/dist/native/bridge/hooks/useIntent.js +1 -0
  41. package/dist/native/bridge/hooks/useNativeTransition.js +43 -0
  42. package/dist/native/bridge/hooks/useNetworkStatus.js +3 -0
  43. package/dist/native/bridge/hooks/useNotification.js +2 -0
  44. package/dist/native/bridge/hooks/useSafeArea.js +2 -0
  45. package/dist/native/bridge/hooks/useVideoStream.js +6 -0
  46. package/dist/native/bridge/hooks/utils.js +1 -0
  47. package/dist/native/bridge/hooks.js +1 -137
  48. package/dist/native/bridge/useBaseHook.js +12 -7
  49. package/dist/native/bridge/utils/NativeBridge.js +41 -6
  50. package/dist/native/buildAppAndroid.js +7 -9
  51. package/dist/native/buildAppIos.js +14 -22
  52. package/dist/native/internalPluginUtils.js +1 -0
  53. package/dist/native/iosnativeWebView/Package.resolved +36 -0
  54. package/dist/native/iosnativeWebView/Sources/Core/Camera/BarcodeDetector.swift +116 -0
  55. package/dist/native/iosnativeWebView/Sources/Core/Camera/CameraPreviewView.swift +58 -0
  56. package/dist/native/iosnativeWebView/Sources/Core/Camera/CameraSessionManager.swift +308 -0
  57. package/dist/native/iosnativeWebView/Sources/Core/Camera/HoldController.swift +63 -0
  58. package/dist/native/iosnativeWebView/Sources/Core/Camera/NativeCameraManager.swift +194 -0
  59. package/dist/native/iosnativeWebView/Sources/Core/Camera/TorchController.swift +60 -0
  60. package/dist/native/iosnativeWebView/Sources/Core/Camera/VideoStreamState.swift +44 -0
  61. package/dist/native/iosnativeWebView/Sources/Core/Camera/VideoStreamStateMachine.swift +60 -0
  62. package/dist/native/iosnativeWebView/Sources/Core/Camera/ZoomController.swift +130 -0
  63. package/dist/native/iosnativeWebView/Sources/Core/Constants/CatalystConstants.swift +11 -1
  64. package/dist/native/iosnativeWebView/Sources/Core/Plugins/CatalystPlugin.swift +5 -0
  65. package/dist/native/iosnativeWebView/Sources/Core/Plugins/GeneratedPluginIndex.swift +6 -0
  66. package/dist/native/iosnativeWebView/Sources/Core/Plugins/PluginBridge.swift +364 -0
  67. package/dist/native/iosnativeWebView/Sources/Core/WebView/BridgeMessageValidator.swift +4 -1
  68. package/dist/native/iosnativeWebView/Sources/Core/WebView/NativeBridge.swift +227 -4
  69. package/dist/native/iosnativeWebView/Sources/Core/WebView/TransitionManager.swift +169 -0
  70. package/dist/native/iosnativeWebView/Sources/Core/WebView/WeakScriptMessageHandler.swift +14 -0
  71. package/dist/native/iosnativeWebView/Sources/Core/WebView/WebView.swift +38 -7
  72. package/dist/native/iosnativeWebView/Sources/Core/WebView/WebViewNavigationDelegate.swift +6 -2
  73. package/dist/native/iosnativeWebView/iosnativeWebView/ContentView.swift +15 -4
  74. package/dist/native/iosnativeWebView/iosnativeWebView/Info.plist +11 -17
  75. package/dist/native/iosnativeWebView/iosnativeWebView.xcodeproj/project.pbxproj +8 -2
  76. package/dist/native/iosnativeWebView/iosnativeWebViewTests/PluginBridgeTests.swift +160 -0
  77. package/dist/native/plugin-bridge/PluginBridge.js +1 -0
  78. package/dist/native/pluginComposerAndroid.js +9 -0
  79. package/dist/native/pluginComposerIos.js +7 -0
  80. package/dist/native/renameAndroidProject.js +3 -3
  81. package/dist/native/setupServer.js +2 -3
  82. package/dist/native/utils.js +4 -1
  83. package/dist/otel.js +70 -2
  84. package/dist/scripts/devServe.js +1 -1
  85. package/dist/scripts/plugins.js +1 -0
  86. package/dist/scripts/registerAliases.js +6 -2
  87. package/dist/scripts/scriptUtils.js +2 -1
  88. package/dist/scripts/serve.js +2 -1
  89. package/dist/scripts/start.js +4 -1
  90. package/dist/server/renderer/extract.js +5 -5
  91. package/dist/server/renderer/handler.js +15 -14
  92. package/dist/server/utils/validator.js +1 -1
  93. package/dist/webpack/base.babel.js +2 -1
  94. package/dist/webpack/development.client.babel.js +6 -2
  95. package/dist/webpack/production.ssr.babel.js +5 -1
  96. package/mcp_v2/knowledge-base.json +1564 -1067
  97. package/mcp_v2/lib/helpers.js +19 -7
  98. package/mcp_v2/tools/build.js +1 -1
  99. package/mcp_v2/tools/config.js +16 -4
  100. package/mcp_v2/tools/conversion.js +11 -11
  101. package/mcp_v2/tools/knowledge.js +16 -3
  102. package/mcp_v2/tools/tasks.js +13 -4
  103. package/package.json +2 -2
@@ -101,21 +101,33 @@ function findCatalystRoot() {
101
101
  * File-system helpers scoped to a project root.
102
102
  */
103
103
  function makeProjectHelpers(root) {
104
+ function safeProjectPath(rel) {
105
+ if (typeof rel !== "string" || path.isAbsolute(rel)) return null
106
+ const normalized = path.normalize(rel)
107
+ if (normalized === ".." || normalized.startsWith(`..${path.sep}`)) return null
108
+ return `${root}${path.sep}${normalized}`
109
+ }
110
+
104
111
  function fileExists(rel) {
105
- return fs.existsSync(path.join(root, rel))
112
+ const filePath = safeProjectPath(rel)
113
+ return Boolean(filePath && fs.existsSync(filePath))
106
114
  }
107
115
 
108
116
  function readJson(rel) {
117
+ const filePath = safeProjectPath(rel)
118
+ if (!filePath) return null
109
119
  try {
110
- return JSON.parse(fs.readFileSync(path.join(root, rel), "utf8"))
120
+ return JSON.parse(fs.readFileSync(filePath, "utf8"))
111
121
  } catch {
112
122
  return null
113
123
  }
114
124
  }
115
125
 
116
126
  function readText(rel) {
127
+ const filePath = safeProjectPath(rel)
128
+ if (!filePath) return null
117
129
  try {
118
- return fs.readFileSync(path.join(root, rel), "utf8")
130
+ return fs.readFileSync(filePath, "utf8")
119
131
  } catch {
120
132
  return null
121
133
  }
@@ -125,7 +137,6 @@ function makeProjectHelpers(root) {
125
137
  * Walk src/**\/*.{js,jsx,ts,tsx} and return relative paths that match pattern.
126
138
  */
127
139
  function grepSrc(pattern) {
128
- const re = new RegExp(pattern)
129
140
  const matches = []
130
141
  function walk(dir) {
131
142
  let entries
@@ -136,12 +147,13 @@ function makeProjectHelpers(root) {
136
147
  }
137
148
  for (const e of entries) {
138
149
  if (e.name === "node_modules" || e.name === ".git") continue
139
- const full = path.join(dir, e.name)
150
+ const full = `${dir}${path.sep}${e.name}`
140
151
  if (e.isDirectory()) {
141
152
  walk(full)
142
153
  } else if (/\.(js|jsx|ts|tsx)$/.test(e.name)) {
143
154
  try {
144
- if (re.test(fs.readFileSync(full, "utf8"))) {
155
+ const content = fs.readFileSync(full, "utf8")
156
+ if (pattern.test(content)) {
145
157
  matches.push(path.relative(root, full))
146
158
  }
147
159
  } catch {
@@ -150,7 +162,7 @@ function makeProjectHelpers(root) {
150
162
  }
151
163
  }
152
164
  }
153
- walk(path.join(root, "src"))
165
+ walk(`${root}${path.sep}src`)
154
166
  return matches
155
167
  }
156
168
 
@@ -658,7 +658,7 @@ function handle_get_architecture_diagram({ feature, symptom } = {}) {
658
658
 
659
659
  if (diagram_key === "routing") {
660
660
  const { grepSrc } = makeProjectHelpers(catalystRoot.dir)
661
- const routeFiles = grepSrc("RouterDataProvider|createBrowserRouter|<Route")
661
+ const routeFiles = grepSrc(/RouterDataProvider|createBrowserRouter|<Route/)
662
662
  project_context.push(
663
663
  `RouterDataProvider found in: ${routeFiles.length ? routeFiles.slice(0, 3).join(", ") : "not detected"}`
664
664
  )
@@ -8,6 +8,14 @@ function init(projectInfo) {
8
8
  _projectInfo = projectInfo
9
9
  }
10
10
 
11
+ function projectPath(root, rel) {
12
+ const normalized = path.normalize(rel)
13
+ if (path.isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${path.sep}`)) {
14
+ return null
15
+ }
16
+ return `${root}${path.sep}${normalized}`
17
+ }
18
+
11
19
  function handle_check_config({ project_path, platform = "both" } = {}) {
12
20
  const root = project_path || _projectInfo.dir
13
21
  const configPath = path.join(root, "config", "config.json")
@@ -390,7 +398,10 @@ function handle_check_config({ project_path, platform = "both" } = {}) {
390
398
  })
391
399
  } else {
392
400
  const missingSplash = ["public/android/splashscreen.png", "public/ios/splashscreen.png"].filter(
393
- (f) => !fs.existsSync(path.join(root, f))
401
+ (f) => {
402
+ const filePath = projectPath(root, f)
403
+ return !filePath || !fs.existsSync(filePath)
404
+ }
394
405
  )
395
406
  if (missingSplash.length) {
396
407
  issues.push({
@@ -405,9 +416,10 @@ function handle_check_config({ project_path, platform = "both" } = {}) {
405
416
 
406
417
  // ── notifications (optional, validate if present) ─────────────────────────
407
418
  if (wc.notifications && wc.notifications.enabled) {
408
- const missingFirebase = ["google-services.json", "GoogleService-Info.plist"].filter(
409
- (f) => !fs.existsSync(path.join(root, f))
410
- )
419
+ const missingFirebase = ["google-services.json", "GoogleService-Info.plist"].filter((f) => {
420
+ const filePath = projectPath(root, f)
421
+ return !filePath || !fs.existsSync(filePath)
422
+ })
411
423
  if (missingFirebase.length) {
412
424
  issues.push({
413
425
  field: "WEBVIEW_CONFIG.notifications",
@@ -113,9 +113,9 @@ function handle_get_conversion_status({ project_path, include_not_applicable = f
113
113
 
114
114
  T4_DATA_FETCHING: () => {
115
115
  const useEffectFiles = grepSrc(
116
- "useEffect.*fetch|useEffect.*axios|useEffect.*\\.get\\(|useEffect.*\\.post\\("
116
+ /useEffect.*fetch|useEffect.*axios|useEffect.*\.get\(|useEffect.*\.post\(/
117
117
  )
118
- const fetcherFiles = grepSrc("\\.serverFetcher\\s*=|\\.clientFetcher\\s*=")
118
+ const fetcherFiles = grepSrc(/\.serverFetcher\s*=|\.clientFetcher\s*=/)
119
119
  if (useEffectFiles.length === 0) return { status: "completed" }
120
120
  return {
121
121
  status: "needs_review",
@@ -368,13 +368,13 @@ function handle_get_conversion_status({ project_path, include_not_applicable = f
368
368
  // ── Tier 3: Enhancements (feature-presence gated) ───────────────────────
369
369
 
370
370
  T17a_USE_FILEPICKER: () => {
371
- const oldPatternFiles = grepSrc("<input[^>]*type=['\"]file['\"]")
371
+ const oldPatternFiles = grepSrc(/<input[^>]*type=['"]file['"]/)
372
372
  if (oldPatternFiles.length === 0)
373
373
  return {
374
374
  status: "not_applicable",
375
375
  reason: 'No <input type="file"> found in project — file upload feature not used.',
376
376
  }
377
- const hookUsageFiles = grepSrc("useFilePicker")
377
+ const hookUsageFiles = grepSrc(/useFilePicker/)
378
378
  return {
379
379
  status: "needs_review",
380
380
  native_risk:
@@ -396,13 +396,13 @@ function handle_get_conversion_status({ project_path, include_not_applicable = f
396
396
  },
397
397
 
398
398
  T17b_USE_CAMERA: () => {
399
- const oldPatternFiles = grepSrc("accept=['\"]image[^>]*capture|<input[^>]+capture")
399
+ const oldPatternFiles = grepSrc(/accept=['"]image[^>]*capture|<input[^>]+capture/)
400
400
  if (oldPatternFiles.length === 0)
401
401
  return {
402
402
  status: "not_applicable",
403
403
  reason: "No camera capture inputs (<input capture>) found — camera feature not used.",
404
404
  }
405
- const hookUsageFiles = grepSrc("useCamera")
405
+ const hookUsageFiles = grepSrc(/useCamera/)
406
406
  return {
407
407
  status: "needs_review",
408
408
  native_risk:
@@ -424,13 +424,13 @@ function handle_get_conversion_status({ project_path, include_not_applicable = f
424
424
  },
425
425
 
426
426
  T18_USE_HAPTIC: () => {
427
- const oldPatternFiles = grepSrc("navigator\\.vibrate")
427
+ const oldPatternFiles = grepSrc(/navigator\.vibrate/)
428
428
  if (oldPatternFiles.length === 0)
429
429
  return {
430
430
  status: "not_applicable",
431
431
  reason: "No navigator.vibrate() calls found — haptic feedback not used.",
432
432
  }
433
- const hookUsageFiles = grepSrc("useHapticFeedback")
433
+ const hookUsageFiles = grepSrc(/useHapticFeedback/)
434
434
  return {
435
435
  status: "needs_review",
436
436
  native_risk:
@@ -453,7 +453,7 @@ function handle_get_conversion_status({ project_path, include_not_applicable = f
453
453
 
454
454
  T19_USE_NOTIFICATIONS: () => {
455
455
  if (!webviewConfig || !webviewConfig.notifications || !webviewConfig.notifications.enabled) {
456
- const pushFiles = grepSrc("firebase|FCM|pushNotif|useNotification")
456
+ const pushFiles = grepSrc(/firebase|FCM|pushNotif|useNotification/)
457
457
  if (pushFiles.length === 0)
458
458
  return {
459
459
  status: "not_applicable",
@@ -480,7 +480,7 @@ function handle_get_conversion_status({ project_path, include_not_applicable = f
480
480
 
481
481
  T20_USE_DEVICE_INFO: () => {
482
482
  const oldPatternFiles = grepSrc(
483
- "navigator\\.userAgent|/Android/i\\.test|/iPhone/i\\.test|/iPad/i\\.test"
483
+ /navigator\.userAgent|\/Android\/i\.test|\/iPhone\/i\.test|\/iPad\/i\.test/
484
484
  )
485
485
  if (oldPatternFiles.length === 0)
486
486
  return {
@@ -488,7 +488,7 @@ function handle_get_conversion_status({ project_path, include_not_applicable = f
488
488
  reason: "No navigator.userAgent / UA-sniffing found — platform detection not used.",
489
489
  }
490
490
  const correctPatternFiles = grepSrc(
491
- "isNative|window\\.NativeBridge|nativeBridge\\.isAndroid|nativeBridge\\.isIOS"
491
+ /isNative|window\.NativeBridge|nativeBridge\.isAndroid|nativeBridge\.isIOS/
492
492
  )
493
493
  return {
494
494
  status: "needs_review",
@@ -55,11 +55,20 @@ function fetchRaw(url) {
55
55
  })
56
56
  }
57
57
 
58
+ // Only allow known tag shapes or "main" — guards against a tampered/malformed
59
+ // installed version string being interpolated into the GitHub fetch URL.
60
+ // Covers all observed formats:
61
+ // v0.1.0, v0.1.0-canary.8, v0.0.3-canary-18, v0.1.0-beta.2
62
+ function sanitizeGithubTag(version) {
63
+ if (!version) return "main"
64
+ return /^v\d+\.\d+\.\d+(-[a-zA-Z0-9]+([.\-]\d+)?)?$/.test(version) ? version : "main"
65
+ }
66
+
58
67
  // Fetch first available file — used for KB-miss GitHub fallback
59
68
  async function fetchFromGithub(files, installedVersion) {
60
69
  if (!files || files.length === 0) return null
61
70
 
62
- const tag = installedVersion || "main"
71
+ const tag = sanitizeGithubTag(installedVersion)
63
72
  const base = `https://raw.githubusercontent.com/tata1mg/catalyst-core/${tag}`
64
73
 
65
74
  for (const file of files) {
@@ -88,9 +97,13 @@ async function fetchFromGithub(files, installedVersion) {
88
97
  return null
89
98
  }
90
99
 
91
- // Build FTS5 query string from keywords array — each term ORed, quoted for safety
100
+ // Build FTS5 query string from keywords array — each term ORed, quoted for safety.
101
+ // Strip all FTS5 special characters before quoting so keywords are treated as literals.
92
102
  function buildFtsQuery(keywords) {
93
- return keywords.map((k) => `"${k.replace(/"/g, "")}"`).join(" OR ")
103
+ return keywords
104
+ .map((k) => `"${k.replace(/[^a-zA-Z0-9 _\-]/g, " ").trim()}"`)
105
+ .filter((k) => k.length > 2) // drop empty/whitespace-only terms after stripping
106
+ .join(" OR ")
94
107
  }
95
108
 
96
109
  function stripGithubFiles(rows) {
@@ -26,6 +26,14 @@ function now() {
26
26
  return new Date().toISOString().replace("T", " ").slice(0, 19)
27
27
  }
28
28
 
29
+ function projectPath(projectRoot, rel) {
30
+ const normalized = path.normalize(rel)
31
+ if (path.isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${path.sep}`)) {
32
+ return null
33
+ }
34
+ return `${projectRoot}${path.sep}${normalized}`
35
+ }
36
+
29
37
  // ─── Improvement 1: Resolve needs_review inline before plan write ─────────────
30
38
  //
31
39
  // Reads signal_files from disk for each needs_review task.
@@ -67,7 +75,8 @@ function resolveNeedsReview(task, projectRoot) {
67
75
  let nativeBranchFound = false
68
76
  for (const f of samplesToCheck) {
69
77
  try {
70
- const absPath = path.isAbsolute(f) ? f : path.join(projectRoot, f)
78
+ const absPath = path.isAbsolute(f) ? f : projectPath(projectRoot, f)
79
+ if (!absPath) continue
71
80
  const content = fs.readFileSync(absPath, "utf8")
72
81
  if (hookRegex && hookRegex.test(content)) {
73
82
  nativeBranchFound = true
@@ -411,12 +420,12 @@ function summarisePlan(plan) {
411
420
  // ─── MD file helpers ─────────────────────────────────────────────────────────
412
421
 
413
422
  function getMdPath(projectRoot, slug) {
414
- return path.join(projectRoot, ".mcp_tasks", `${slug}.md`)
423
+ return `${projectRoot}${path.sep}.mcp_tasks${path.sep}${slug}.md`
415
424
  }
416
425
 
417
426
  function buildUserReviewWarnings(projectRoot) {
418
427
  const warnings = []
419
- const configPath = path.join(projectRoot, "config", "config.json")
428
+ const configPath = `${projectRoot}${path.sep}config${path.sep}config.json`
420
429
  let config = null
421
430
  try {
422
431
  config = JSON.parse(fs.readFileSync(configPath, "utf8"))
@@ -463,7 +472,7 @@ function buildUserReviewWarnings(projectRoot) {
463
472
  }
464
473
 
465
474
  function writeMdFile(projectRoot, slug, goal, steps, bareMinimum, userReviewWarnings) {
466
- const dir = path.join(projectRoot, ".mcp_tasks")
475
+ const dir = `${projectRoot}${path.sep}.mcp_tasks`
467
476
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })
468
477
 
469
478
  const mdPath = getMdPath(projectRoot, slug)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "catalyst-core",
3
- "version": "0.1.0-beta.2",
3
+ "version": "0.1.0-beta.4",
4
4
  "main": "dist/index.js",
5
5
  "description": "Web framework that provides great performance out of the box",
6
6
  "bin": {
@@ -97,7 +97,7 @@
97
97
  "webpack": "^5.88.2",
98
98
  "webpack-bundle-analyzer": "^4.9.1",
99
99
  "webpack-cli": "^5.1.4",
100
- "webpack-dev-server": "^4.15.2",
100
+ "webpack-dev-server": "^5.2.4",
101
101
  "webpack-merge": "^5.9.0",
102
102
  "webpack-node-externals": "^3.0.0",
103
103
  "winston": "^3.11.0",