Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughMonorepo-wide dependency upgrades (Lerna v9, Jest v30, rimraf v6, TypeScript/tooling bumps), removal of Yarn-specific CI/cache config, TypeScript target/module updates, and selective migration from Koa v2/koa-router to Koa v3/@koa/router with corresponding route and type adjustments. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
shared/packages/worker/src/worker/accessorHandlers/lib/FTPClient/FTPClient.ts (2)
31-45:⚠️ Potential issue | 🟠 MajorAdd
cdto themethodsToOverridelist to serialize all FTP operations.The queue wraps certain FTP methods for exclusive execution, but
cdis missing from the list. This leaves directthis.client.cd('/')calls at lines 96, 199, 218, and 322 running outside the queue, allowing them to interleave with queued operations likeensureDirandremove. For example,ensureDir(queued) →cd(unqueued) →remove(queued) can race if another queued operation is waiting. This breaks the one-at-a-time guarantee.Suggested fix
const methodsToOverride: (keyof FTP.Client)[] = [ 'access', + 'cd', // 'close', // 'closed', 'downloadTo',🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@shared/packages/worker/src/worker/accessorHandlers/lib/FTPClient/FTPClient.ts` around lines 31 - 45, The FTPClient currently lists methods to wrap in methodsToOverride but omits 'cd', so direct calls to this.client.cd bypass the queue; add 'cd' to the methodsToOverride array (alongside 'downloadTo', 'ensureDir', etc.) so the wrapper/serialization logic in the FTPClient class will queue and serialize calls to this.client.cd (thereby ensuring calls like this.client.cd('/') used elsewhere are routed through the same exclusive execution mechanism).
52-54:⚠️ Potential issue | 🔴 CriticalUnsafe
JSON.stringify(args)breaks upload/download operations before execution.The queue wrapper serializes
argson line 53 for error context. SinceuploadFromanddownloadTomethods receive stream objects (Readable, PassThrough) as arguments,JSON.stringify()throws on circular references and crashes the queued operation beforeorgMethod.apply()runs. This prevents legitimate file transfers from executing.Suggested fix
- const orgError = new Error(`Error executing ${method}: ${JSON.stringify(args)}`) // Used later + let serializedArgs = '[unserializable args]' + try { + serializedArgs = JSON.stringify(args) + } catch { + // keep fallback + } + const orgError = new Error(`Error executing ${String(method)}: ${serializedArgs}`) // Used later🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@shared/packages/worker/src/worker/accessorHandlers/lib/FTPClient/FTPClient.ts` around lines 52 - 54, The current queue wrapper creates orgError using JSON.stringify(args), which throws when args contain stream objects (e.g., for uploadFrom/downloadTo) and aborts the operation; replace that unsafe serialization with a safe representation: detect stream-like objects (Readable, PassThrough) or otherwise wrap JSON.stringify in a try/catch and fall back to a placeholder (e.g., "<stream>" or "<unserializable>") per argument so that creating orgError never throws; update the code around queue.add and the orgError creation (referencing method, args, and orgMethod.apply) to use this safe stringify logic before entering the try block.
🧹 Nitpick comments (3)
shared/packages/api/package.json (1)
20-20: Remove deprecated@types/winstonstub.Line 20 adds a legacy stub package while
winstonv3 already provides its own typings. Version mismatch between the@types/winstonv2.4.4 stubs andwinstonv3.19.0 runtime can cause type conflicts.♻️ Proposed cleanup
- "@types/winston": "^2.4.4",🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@shared/packages/api/package.json` at line 20, Remove the legacy TypeScript stub "@types/winston" from package.json to avoid conflicts with winston v3's built-in typings; locate the entry "@types/winston": "^2.4.4" and delete it from dependencies/devDependencies, then run the package manager to update the lockfile (npm install / yarn install / pnpm install) so the change is reflected in package-lock.json/yarn.lock and rebuild types to confirm no remaining type errors.jest.config.base.js (1)
1-1: Consider usingnode:pathfor explicit built-in module identification.While
require('path')is standard and always valid, thenode:prefix makes it explicit that this is a built-in module. This is an optional stylistic convention in modern Node.js.Optional cleanup
-const path = require('path') +const path = require('node:path')🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@jest.config.base.js` at line 1, Update the built-in module import to use the explicit node: prefix by replacing the top-level require('path') with require('node:path') in jest.config.base.js (the symbol to change is the const path = require('path') declaration), keeping the rest of the file unchanged so it still uses the same `path` variable for path resolution.apps/quantel-http-transformer-proxy/packages/generic/package.json (1)
14-14: Duplicate@koa/corsin dependencies and devDependencies.
@koa/corsis listed in bothdependencies(line 14) anddevDependencies(line 29) with the same version. This is redundant—it only needs to be independenciessince it's used at runtime.🧹 Proposed fix to remove duplicate
"devDependencies": { - "@koa/cors": "^5.0.0", "@types/koa": "^3.0.1",Also applies to: 29-29
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/quantel-http-transformer-proxy/packages/generic/package.json` at line 14, The package.json currently lists the same runtime package "@koa/cors" in both dependencies and devDependencies; remove the duplicate entry from devDependencies so "@koa/cors" remains only in dependencies to avoid redundancy and ensure it's available at runtime; update the devDependencies block to delete the "@koa/cors" entry and ensure package.json remains valid JSON after the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/http-server/app/package.json`:
- Line 15: The package.json currently lists "rimraf" in dependencies but it's
only used by the build script ("build": "yarn rimraf dist ..."); remove the
"rimraf" entry from the dependencies object and add the same version string to
devDependencies instead (mirroring packages/generic), then update the lockfile
by running your package manager install (yarn or npm) so the move is reflected;
also ensure you remove the duplicate occurrence noted elsewhere and run the
build script to verify nothing breaks.
In `@apps/http-server/packages/generic/src/lib.ts`:
- Around line 1-5: The exported CTX and CTXPost types currently alias
RouterContext<any, any>, which erases context/state typing; update their
definitions to use Koa's DefaultState and DefaultContext so compile-time types
are preserved: replace occurrences of RouterContext<any, any> for the CTX and
CTXPost exports with RouterContext<DefaultState, DefaultContext> (import
DefaultState and DefaultContext from 'koa') and keep the same export names (CTX,
CTXPost).
In `@apps/http-server/packages/generic/src/server.ts`:
- Around line 98-105: The route patterns using the older wildcard syntax (e.g.
'/package/*path' and '/uploadForm/*path') won't match under `@koa/router` v15+;
update the router calls in server.ts (the router.get/ head/ post handlers that
call handleStorage and storage.getPackage/headPackage, and the routes around the
uploadForm handlers) to use the new named wildcard syntax '/package/{/*path}'
and '/uploadForm/{/*path}' so Koa will correctly bind ctx.params.path for the
existing handleStorage, storage.getPackage, storage.headPackage and the upload
form handlers.
In `@apps/quantel-http-transformer-proxy/packages/generic/src/server.ts`:
- Line 123: Update the Koa route pattern: replace the incorrect catch-all string
"{/*path}" with the correct "/{/*path}" wherever it's used (e.g., the
this.router.get('{/*path}', async (ctx, next) => { ... }) route in server.ts);
also make the same replacement for the other occurrence in the http-server app
so the root "/" is properly matched.
---
Outside diff comments:
In
`@shared/packages/worker/src/worker/accessorHandlers/lib/FTPClient/FTPClient.ts`:
- Around line 31-45: The FTPClient currently lists methods to wrap in
methodsToOverride but omits 'cd', so direct calls to this.client.cd bypass the
queue; add 'cd' to the methodsToOverride array (alongside 'downloadTo',
'ensureDir', etc.) so the wrapper/serialization logic in the FTPClient class
will queue and serialize calls to this.client.cd (thereby ensuring calls like
this.client.cd('/') used elsewhere are routed through the same exclusive
execution mechanism).
- Around line 52-54: The current queue wrapper creates orgError using
JSON.stringify(args), which throws when args contain stream objects (e.g., for
uploadFrom/downloadTo) and aborts the operation; replace that unsafe
serialization with a safe representation: detect stream-like objects (Readable,
PassThrough) or otherwise wrap JSON.stringify in a try/catch and fall back to a
placeholder (e.g., "<stream>" or "<unserializable>") per argument so that
creating orgError never throws; update the code around queue.add and the
orgError creation (referencing method, args, and orgMethod.apply) to use this
safe stringify logic before entering the try block.
---
Nitpick comments:
In `@apps/quantel-http-transformer-proxy/packages/generic/package.json`:
- Line 14: The package.json currently lists the same runtime package "@koa/cors"
in both dependencies and devDependencies; remove the duplicate entry from
devDependencies so "@koa/cors" remains only in dependencies to avoid redundancy
and ensure it's available at runtime; update the devDependencies block to delete
the "@koa/cors" entry and ensure package.json remains valid JSON after the
change.
In `@jest.config.base.js`:
- Line 1: Update the built-in module import to use the explicit node: prefix by
replacing the top-level require('path') with require('node:path') in
jest.config.base.js (the symbol to change is the const path = require('path')
declaration), keeping the rest of the file unchanged so it still uses the same
`path` variable for path resolution.
In `@shared/packages/api/package.json`:
- Line 20: Remove the legacy TypeScript stub "@types/winston" from package.json
to avoid conflicts with winston v3's built-in typings; locate the entry
"@types/winston": "^2.4.4" and delete it from dependencies/devDependencies, then
run the package manager to update the lockfile (npm install / yarn install /
pnpm install) so the change is reflected in package-lock.json/yarn.lock and
rebuild types to confirm no remaining type errors.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6ef0909d-6fbc-4183-9de2-224b4afd99e5
⛔ Files ignored due to path filters (2)
.yarn/releases/yarn-4.1.1.cjsis excluded by!**/.yarn/**yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (39)
.github/workflows/build-windows.yaml.github/workflows/lint-and-test.yaml.github/workflows/publish-prerelease.yaml.yarnrc.ymlapps/_boilerplate/app/package.jsonapps/_boilerplate/packages/generic/package.jsonapps/appcontainer-node/app/package.jsonapps/appcontainer-node/packages/generic/package.jsonapps/html-renderer/app/package.jsonapps/html-renderer/packages/generic/package.jsonapps/http-server/app/package.jsonapps/http-server/packages/generic/package.jsonapps/http-server/packages/generic/src/lib.tsapps/http-server/packages/generic/src/server.tsapps/package-manager/app/package.jsonapps/package-manager/packages/generic/package.jsonapps/quantel-http-transformer-proxy/app/package.jsonapps/quantel-http-transformer-proxy/packages/generic/package.jsonapps/quantel-http-transformer-proxy/packages/generic/src/server.tsapps/single-app/app/package.jsonapps/worker/app/package.jsonapps/worker/packages/generic/package.jsonapps/workforce/app/package.jsonapps/workforce/packages/generic/package.jsonjest.config.base.jslerna.jsonpackage.jsonshared/packages/api/package.jsonshared/packages/api/src/websocketServer.tsshared/packages/expectationManager/package.jsonshared/packages/worker/package.jsonshared/packages/worker/src/worker/accessorHandlers/__tests__/fileShare.spec.tsshared/packages/worker/src/worker/accessorHandlers/__tests__/localFolder.spec.tsshared/packages/worker/src/worker/accessorHandlers/lib/FTPClient/FTPClient.tsshared/packages/worker/src/worker/accessorHandlers/lib/fetch.tsshared/packages/workforce/package.jsontests/internal-tests/package.jsontsconfig.build.jsontsconfig.jest.json
💤 Files with no reviewable changes (5)
- .yarnrc.yml
- .github/workflows/publish-prerelease.yaml
- .github/workflows/lint-and-test.yaml
- .github/workflows/build-windows.yaml
- shared/packages/worker/src/worker/accessorHandlers/lib/fetch.ts
| "dependencies": { | ||
| "@http-server/generic": "1.53.0", | ||
| "rimraf": "^5.0.5" | ||
| "rimraf": "^6.1.3" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "1) Search runtime code for rimraf imports/usages:"
rg -nP -C2 '\b(from\s+["'\'']rimraf["'\'']|require\(\s*["'\'']rimraf["'\'']\s*\)|\brimraf\s*\()' apps/http-server || true
echo
echo "2) Inspect package manifests in http-server workspace for rimraf placement:"
fd -a package.json apps/http-server -x sh -c 'echo "### $1"; rg -n "\"rimraf\"" "$1" || true' sh {}Repository: Sofie-Automation/sofie-package-manager
Length of output: 389
🏁 Script executed:
cat -n apps/http-server/app/package.json | head -40Repository: Sofie-Automation/sofie-package-manager
Length of output: 1201
🏁 Script executed:
cat -n apps/http-server/packages/generic/package.json | grep -A 5 -B 5 "rimraf"Repository: Sofie-Automation/sofie-package-manager
Length of output: 828
Move rimraf from dependencies to devDependencies.
Line 15 places rimraf in dependencies, but it is used only in the build script (line 7: "build": "yarn rimraf dist ..."), not at runtime. The sibling package (packages/generic) correctly places the same tool in devDependencies. This unnecessarily adds rimraf to the production install surface.
Adjustment
"dependencies": {
- "@http-server/generic": "1.53.0",
- "rimraf": "^6.1.3"
+ "@http-server/generic": "1.53.0"
},
@@
"devDependencies": {
- "lerna": "^9.0.7"
+ "lerna": "^9.0.7",
+ "rimraf": "^6.1.3"
}Also applies to: 30-30
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/http-server/app/package.json` at line 15, The package.json currently
lists "rimraf" in dependencies but it's only used by the build script ("build":
"yarn rimraf dist ..."); remove the "rimraf" entry from the dependencies object
and add the same version string to devDependencies instead (mirroring
packages/generic), then update the lockfile by running your package manager
install (yarn or npm) so the move is reflected; also ensure you remove the
duplicate occurrence noted elsewhere and run the build script to verify nothing
breaks.
| import type { RouterContext } from '@koa/router' | ||
| import { Readable, Writable } from 'stream' | ||
|
|
||
| export type CTX = Koa.ParameterizedContext<any, Router.IRouterParamContext<any, any>> | ||
| export type CTXPost = Koa.ParameterizedContext<any, Router.IRouterParamContext<any, any>> | ||
| export type CTX = RouterContext<any, any> | ||
| export type CTXPost = RouterContext<any, any> |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
For @koa/router15.x with koa 3.x, what is the recommended RouterContext generic typing for route handlers (state/context/params) to avoidany?
💡 Result:
In @koa/router 15.x (koajs/router) the exported RouterContext only has generics for:
RouterContext<StateT = DefaultState, ContextT = DefaultContext, BodyT = unknown>and route params are not generic—they’re typed as Record<string, string> via RouterParameterContext/RouterContext (params and request.params). [1]
Recommended typing (avoid any): put your app-level types on the Router, then (optionally) annotate handlers with the matching RouterContext<StateT, ContextT, BodyT>.
import Router, { type RouterContext } from '@koa/router';
type AppState = { user?: { id: string } };
type AppContext = { requestId: string }; // whatever you add via declaration merging, etc.
const router = new Router<AppState, AppContext>();
router.get('/users/:id', async (ctx: RouterContext<AppState, AppContext>) => {
// ctx.state is AppState
// ctx is AppContext & router additions
// ctx.params.id is string (Record<string, string>)
const id = ctx.params.id;
});If you need strongly-typed param keys (e.g. { id: string } instead of Record<string,string>), you must refine it yourself (e.g. an intersection/cast), because @koa/router 15.x doesn’t provide a params generic. [1]
Sources:
[1] @koa/router RouterContext / RouterParameterContext type definitions (koajs/router src/types.ts) (raw.githubusercontent.com)
Citations:
🏁 Script executed:
# First, check the package.json for version info
find . -name "package.json" -path "*/http-server/*" | head -5Repository: Sofie-Automation/sofie-package-manager
Length of output: 166
🏁 Script executed:
# Search for usage of CTX and CTXPost in the codebase
rg "CTX|CTXPost" --type ts --type tsx -B 2 -A 2Repository: Sofie-Automation/sofie-package-manager
Length of output: 109
🏁 Script executed:
# Look for any custom context or state type definitions
rg "type.*Context|type.*State" --type ts --type tsx | head -20Repository: Sofie-Automation/sofie-package-manager
Length of output: 109
🏁 Script executed:
# Check package.json for koa and `@koa/router` versions
cat apps/http-server/packages/generic/package.json | grep -A 2 -B 2 "koa\|router"Repository: Sofie-Automation/sofie-package-manager
Length of output: 529
🏁 Script executed:
# Search for CTX and CTXPost usage without file type
rg "CTX|CTXPost" -B 2 -A 2Repository: Sofie-Automation/sofie-package-manager
Length of output: 4014
🏁 Script executed:
# Check the lib.ts file itself
cat -n apps/http-server/packages/generic/src/lib.tsRepository: Sofie-Automation/sofie-package-manager
Length of output: 838
🏁 Script executed:
# Verify that DefaultState and DefaultContext are available from 'koa' types
cat apps/http-server/packages/generic/package.json | grep -A 5 "@types/koa"Repository: Sofie-Automation/sofie-package-manager
Length of output: 318
🏁 Script executed:
# Quick check of `@types/koa` to confirm DefaultState/DefaultContext exports
find . -name "*.json" -path "*@types/koa*" 2>/dev/null | head -3Repository: Sofie-Automation/sofie-package-manager
Length of output: 64
🏁 Script executed:
# Check what's imported from 'koa' or '@koa/router' in the broader codebase to see patterns
rg "from ['\"](koa|@koa)" --type ts | head -15Repository: Sofie-Automation/sofie-package-manager
Length of output: 983
🏁 Script executed:
# Check if there are any custom context/state type definitions in the http-server packages
rg "interface|type.*Context|type.*State" apps/http-server/packages/generic/src --type ts -A 1 | head -25Repository: Sofie-Automation/sofie-package-manager
Length of output: 822
Avoid exporting CTX/CTXPost as RouterContext<any, any>.
Lines 4–5 currently erase handler context typing across the package. Use Koa's standard DefaultState and DefaultContext to maintain compile-time type safety.
♻️ Proposed typing fix
import type { RouterContext } from '@koa/router'
+import type { DefaultContext, DefaultState } from 'koa'
import { Readable, Writable } from 'stream'
-export type CTX = RouterContext<any, any>
-export type CTXPost = RouterContext<any, any>
+export type CTX = RouterContext<DefaultState, DefaultContext>
+export type CTXPost = RouterContext<DefaultState, DefaultContext>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import type { RouterContext } from '@koa/router' | |
| import { Readable, Writable } from 'stream' | |
| export type CTX = Koa.ParameterizedContext<any, Router.IRouterParamContext<any, any>> | |
| export type CTXPost = Koa.ParameterizedContext<any, Router.IRouterParamContext<any, any>> | |
| export type CTX = RouterContext<any, any> | |
| export type CTXPost = RouterContext<any, any> | |
| import type { RouterContext } from '@koa/router' | |
| import type { DefaultContext, DefaultState } from 'koa' | |
| import { Readable, Writable } from 'stream' | |
| export type CTX = RouterContext<DefaultState, DefaultContext> | |
| export type CTXPost = RouterContext<DefaultState, DefaultContext> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/http-server/packages/generic/src/lib.ts` around lines 1 - 5, The
exported CTX and CTXPost types currently alias RouterContext<any, any>, which
erases context/state typing; update their definitions to use Koa's DefaultState
and DefaultContext so compile-time types are preserved: replace occurrences of
RouterContext<any, any> for the CTX and CTXPost exports with
RouterContext<DefaultState, DefaultContext> (import DefaultState and
DefaultContext from 'koa') and keep the same export names (CTX, CTXPost).
| this.router.get('/package/*path', async (ctx) => { | ||
| await this.handleStorage(ctx, async () => this.storage.getPackage(ctx.params.path)) | ||
| }) | ||
| this.router.head('/package/:path+', async (ctx) => { | ||
| this.router.head('/package/*path', async (ctx) => { | ||
| await this.handleStorage(ctx, async () => this.storage.headPackage(ctx.params.path)) | ||
| }) | ||
| this.router.post('/package/:path+', async (ctx) => { | ||
| this.router.post('/package/*path', async (ctx) => { | ||
| this.logger.debug(`POST ${ctx.request.URL}`) |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In @koa/router v15+, for a named wildcard route parameter, is '/package/*path' valid, or should it be '/package/{/*path}'?
💡 Result:
In @koa/router v15+, a named wildcard (“splat”) parameter must be wrapped in braces:
- Use:
/package/{/*path} - Not:
/package/*path(that syntax isn’t the documented v15+ form for a named wildcard)
The README’s example is router.get('/files/{/*path}', ...) with ctx.params.path containing the rest of the path. [1]
🏁 Script executed:
# Check `@koa/router` version and related dependencies
find . -name "package.json" -type f | head -5 | xargs grep -l "@koa/router\|koa.*router" 2>/dev/nullRepository: Sofie-Automation/sofie-package-manager
Length of output: 66
🏁 Script executed:
# Locate the server.ts file
find . -path "*/apps/http-server/packages/generic/src/server.ts" -type fRepository: Sofie-Automation/sofie-package-manager
Length of output: 131
🏁 Script executed:
# Find package.json in the http-server package directory
find ./apps/http-server -name "package.json" -type fRepository: Sofie-Automation/sofie-package-manager
Length of output: 166
🏁 Script executed:
# Read the server.ts file at the relevant lines
sed -n '95,110p; 123,128p; 137,142p' ./apps/http-server/packages/generic/src/server.tsRepository: Sofie-Automation/sofie-package-manager
Length of output: 1159
🏁 Script executed:
# Check `@koa/router` version in the package.json
grep -A2 -B2 "@koa/router" ./apps/http-server/packages/generic/package.jsonRepository: Sofie-Automation/sofie-package-manager
Length of output: 226
Update wildcard route patterns to @koa/router v15+ syntax.
Routes at lines 98, 101, 104, 126, and 140 use /package/*path and /uploadForm/*path. With @koa/router v15.4.0, the correct syntax for named wildcard parameters is /{/*path}. The current patterns will not match routes correctly.
🔧 Proposed route-pattern fix
- this.router.get('/package/*path', async (ctx) => {
+ this.router.get('/package/{/*path}', async (ctx) => {
await this.handleStorage(ctx, async () => this.storage.getPackage(ctx.params.path))
})
- this.router.head('/package/*path', async (ctx) => {
+ this.router.head('/package/{/*path}', async (ctx) => {
await this.handleStorage(ctx, async () => this.storage.headPackage(ctx.params.path))
})
- this.router.post('/package/*path', async (ctx) => {
+ this.router.post('/package/{/*path}', async (ctx) => {
this.logger.debug(`POST ${ctx.request.URL}`)
const { files, fields } = await parseFormData(ctx.req, {
maxFileByteLength: MAX_UPLOAD_FILE_SIZE,
@@
- this.router.delete('/package/*path', async (ctx) => {
+ this.router.delete('/package/{/*path}', async (ctx) => {
this.logger.debug(`DELETE ${ctx.request.URL}`)
await this.handleStorage(ctx, async () => this.storage.deletePackage(ctx.params.path))
})
@@
- this.router.get('/uploadForm/*path', async (ctx) => {
+ this.router.get('/uploadForm/{/*path}', async (ctx) => {
// ctx.response.status = result.code
ctx.type = 'text/html'
ctx.body = (await fsReadFile(path.resolve('../static/uploadForm.html'), 'utf-8'))🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/http-server/packages/generic/src/server.ts` around lines 98 - 105, The
route patterns using the older wildcard syntax (e.g. '/package/*path' and
'/uploadForm/*path') won't match under `@koa/router` v15+; update the router calls
in server.ts (the router.get/ head/ post handlers that call handleStorage and
storage.getPackage/headPackage, and the routes around the uploadForm handlers)
to use the new named wildcard syntax '/package/{/*path}' and
'/uploadForm/{/*path}' so Koa will correctly bind ctx.params.path for the
existing handleStorage, storage.getPackage, storage.headPackage and the upload
form handlers.
| } | ||
| }) | ||
| this.router.get('/(.*)', async (ctx, next) => { | ||
| this.router.get('{/*path}', async (ctx, next) => { |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check for similar route patterns in other files to ensure consistency
echo "=== Checking route patterns in http-server and similar apps ==="
rg -n --type ts '@koa/router|{/\*' apps/Repository: Sofie-Automation/sofie-package-manager
Length of output: 266
🏁 Script executed:
#!/bin/bash
# First, find the server.ts file and examine the routes around line 123
echo "=== Locating server.ts ==="
fd -n "server.ts" apps/quantel-http-transformer-proxy/
echo "=== Examining routes in server.ts ==="
cat -n apps/quantel-http-transformer-proxy/packages/generic/src/server.ts | sed -n '110,135p'
echo "=== Checking package.json for dependencies ==="
cat apps/quantel-http-transformer-proxy/package.json | grep -A5 -B5 "path-to-regexp\|@koa"Repository: Sofie-Automation/sofie-package-manager
Length of output: 1527
🏁 Script executed:
#!/bin/bash
# Search for similar route patterns more carefully
echo "=== Checking for router.get patterns with catch-all routes ==="
rg -n "router\.(get|post|put|delete)" apps/quantel-http-transformer-proxy/ -A1 -t ts | head -50
echo "=== Checking for Koa router usage patterns ==="
rg -n "@koa/router|new Router" apps/ -t ts | head -20Repository: Sofie-Automation/sofie-package-manager
Length of output: 1425
🏁 Script executed:
#!/bin/bash
# Check for package.json files in the quantel-http-transformer-proxy
echo "=== Finding package.json files ==="
find apps/quantel-http-transformer-proxy -name "package.json" -type f
# Check the root package.json for dependencies
echo "=== Root package.json dependencies ==="
rg -A2 -B2 "@koa/router|path-to-regexp" package.json
# Check if there are any test files that demonstrate route patterns
echo "=== Looking for test files with router patterns ==="
find apps/quantel-http-transformer-proxy -name "*.test.ts" -o -name "*.spec.ts" | head -10Repository: Sofie-Automation/sofie-package-manager
Length of output: 393
🏁 Script executed:
#!/bin/bash
# Look at the full context of the server.ts file to understand the router setup
echo "=== Full route definitions in server.ts ==="
rg -n "router\.(get|post|put|delete)" apps/quantel-http-transformer-proxy/packages/generic/src/server.ts -B1 -A3
# Check if there's documentation or comments about the route pattern
echo "=== Search for any comments about route patterns ==="
rg -n "catch.all|{/\*|path\}" apps/quantel-http-transformer-proxy/ -t ts -B2 -A2Repository: Sofie-Automation/sofie-package-manager
Length of output: 950
🏁 Script executed:
#!/bin/bash
# Check package versions
echo "=== Checking `@koa/router` and dependencies in packages/generic/package.json ==="
cat apps/quantel-http-transformer-proxy/packages/generic/package.json | grep -A50 "dependencies"
echo "=== Checking `@koa/router` and dependencies in app/package.json ==="
cat apps/quantel-http-transformer-proxy/app/package.json | grep -A50 "dependencies"Repository: Sofie-Automation/sofie-package-manager
Length of output: 1633
🏁 Script executed:
#!/bin/bash
# Check the test file to see how routes are tested
echo "=== Examining test file ==="
cat -n apps/quantel-http-transformer-proxy/app/src/__tests__/test.spec.ts | head -100Repository: Sofie-Automation/sofie-package-manager
Length of output: 344
🌐 Web query:
@koa/router v15 path-to-regexp v8 catch-all route pattern {/*path}
💡 Result:
In @koa/router v15 (uses path-to-regexp v8), the catch-all is a named wildcard (you can’t use a bare *), and the equivalent of a “catch-all param” is:
-
Catch-all after a prefix (0 or more segments):
router.all('/files/{/*path}', (ctx) => { // matches /files and /files/a/b/c ctx.body = ctx.params.path; // e.g. "a/b/c" });
This is the documented wildcard form for v15. [1]
-
Catch-all for the whole app (0 or more segments, including
/):router.all('/{/*path}', (ctx) => { // matches / and /anything/here ctx.body = ctx.params.path; // undefined for "/", or "anything/here" });
-
If you want only non-empty paths (i.e., match
/a/bbut not/), use the non-optional wildcard form:router.all('/*path', (ctx) => { /* ... */ });
(Wildcard params are
*namein path-to-regexp v8. [2])
Why {/*path} instead of {*path}? In path-to-regexp v8, the * wildcard still needs a name, and braces { ... } make that part optional; @koa/router’s README shows the wildcard as /{/*path}-style under a prefix. [1][2]
Sources
[1] @koa/router README (Wildcard parameters example) (raw.githubusercontent.com)
[2] pillarjs/path-to-regexp README (Wildcard *name, and optional groups with {}) (github.com)
Citations:
- 1: https://raw.githubusercontent.com/koajs/router/master/README.md
- 2: https://github.com/pillarjs/path-to-regexp
🌐 Web query:
path-to-regexp zero or more segments braces syntax
💡 Result:
In current path-to-regexp (v6+), the old + / * repeat modifiers aren’t used on params anymore. Instead: braces {...} create an optional group, and wildcards *name capture across multiple / segments. (github.com)
Zero or more path segments (the “*” behavior) is done by combining both:
/files{/*path}This matches:
/files(zero segments)/files/a/files/a/b/c(many segments)
and path is captured as an array of segments. (github.com)
For comparison, one or more segments is just a wildcard:
/*path(which does not match / by itself). (github.com)
Citations:
- 1: https://github.com/pillarjs/path-to-regexp
- 2: https://github.com/pillarjs/path-to-regexp
- 3: https://github.com/pillarjs/path-to-regexp
🌐 Web query:
@koa/router v15 root catch-all route pattern /{/*path} vs {/*path}
💡 Result:
In @koa/router v15 (uses path-to-regexp v8), the * wildcard must be named (e.g. *path) and braces {...} create an optional group. (github.com)
So:
-
/{/*path}= “match/and anything below it”/*pathis inside an optional group, so it can be absent (root/) or present (/a,/a/b, …).- This is the right pattern for a root catch-all.
(github.com)
-
{/*path}(no leading/outside the group) = the whole route pattern starts with an optional/*path, meaning it can match the empty string as well as/....- Since Koa request paths always start with
/, this is generally not what you want for a normal router route; use/{/*path}instead.
(github.com)
- Since Koa request paths always start with
Citations:
- 1: https://github.com/pillarjs/path-to-regexp
- 2: https://github.com/pillarjs/path-to-regexp
- 3: https://github.com/pillarjs/path-to-regexp
🏁 Script executed:
#!/bin/bash
# Check if there are similar catch-all patterns in the codebase
echo "=== Searching for catch-all route patterns ==="
rg -n "router\.(get|post|all)" apps/ -t ts | rg "{/\*|/\*" | head -20
# Check http-server app for comparison
echo "=== Checking http-server for route patterns ==="
rg -n "router\.(get|post|all)" apps/http-server/ -t ts -A1 | head -40Repository: Sofie-Automation/sofie-package-manager
Length of output: 1923
Change catch-all route pattern from {/*path} to /{/*path}.
The pattern {/*path} is incorrect for a root catch-all. In path-to-regexp v8 (used by @koa/router v15.4.0), {/*path} without a leading / represents an optional group that can match an empty string, which does not work correctly with Koa routes. The correct pattern for matching all paths including the root / is /{/*path}.
Note: The http-server app also uses this same incorrect pattern on line 64 and should be corrected as well.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/quantel-http-transformer-proxy/packages/generic/src/server.ts` at line
123, Update the Koa route pattern: replace the incorrect catch-all string
"{/*path}" with the correct "/{/*path}" wherever it's used (e.g., the
this.router.get('{/*path}', async (ctx, next) => { ... }) route in server.ts);
also make the same replacement for the other occurrence in the http-server app
so the root "/" is properly matched.
025f340 to
2f1aa32
Compare
|
nytamin
left a comment
There was a problem hiding this comment.
It'll be great to get this updated, thanks for this!



About Me
Type of Contribution
This is a: Code improvement
Current Behavior
New Behavior
This updates a lot of the tooling and dependencies to be up to date. There are still some more bits that would be nice to look at, but I am unlikely to in this round.
A quick test with a demo rundown appears to be able to scan and generate previews as normal
Testing Instructions
Other Information
Status