Skip to content

feat: update libs#276

Open
Julusian wants to merge 9 commits intomainfrom
feat/update-libs
Open

feat: update libs#276
Julusian wants to merge 9 commits intomainfrom
feat/update-libs

Conversation

@Julusian
Copy link
Member

@Julusian Julusian commented Mar 17, 2026

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

  • PR is ready to be reviewed.
  • The functionality has been tested by the author.
  • Relevant unit tests has been added / updated.
  • Relevant documentation (code comments, system documentation) has been added / updated.

@coderabbitai
Copy link

coderabbitai bot commented Mar 17, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a351d931-5cad-43c0-9eda-acf92b84ce0b

📥 Commits

Reviewing files that changed from the base of the PR and between 025f340 and 2f1aa32.

📒 Files selected for processing (1)
  • tsconfig.build.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • tsconfig.build.json

Walkthrough

Monorepo-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

Cohort / File(s) Summary
GitHub Actions Workflows
.github/workflows/build-windows.yaml, .github/workflows/lint-and-test.yaml, .github/workflows/publish-prerelease.yaml
Removed cache: 'yarn' from actions/setup-node steps.
Yarn Config
.yarnrc.yml
Removed yarnPath entry.
Root manifests & tooling
package.json, jest.config.base.js, lerna.json
Bumped many devDeps (lerna→9, jest→30, ts-jest, typescript etc.); jest config: added JS transform, diagnostics ignore, transformIgnorePatterns; lerna: added $schema, removed useWorkspaces, condensed packages array.
TypeScript configs
tsconfig.build.json, tsconfig.jest.json
module → node20, target → es2024, lib → es2023; added tsconfig.jest.json extending build config with allowJs.
Koa v3 & router migration
apps/http-server/.../package.json, .../src/lib.ts, .../src/server.ts, apps/quantel-http-transformer-proxy/.../package.json, .../src/server.ts
Upgraded koa v2→v3, replaced koa-router with @koa/router; updated route path patterns (:path+*path/{*path}) and context typing (use RouterContext).
App dependency bumps
apps/.../app/package.json, apps/.../packages/generic/package.json (multiple apps listed)
Consistent version bumps: lerna, rimraf, underscore, tslib, ws, and other app-specific dependency updates.
Shared packages & tests
shared/packages/*/package.json, shared/packages/api/src/websocketServer.ts, shared/packages/worker/src/.../__tests__/*.spec.ts, shared/packages/worker/.../FTPClient.ts, shared/packages/worker/.../fetch.ts
Updated runtime/dev deps (underscore, kairos-lib, winston, ws, jest, rimraf, @types/*); added null-check in WebsocketServer.port; switched test matchers to toThrow; added p-queue import; removed external abort-controller import.
Tests manifests
tests/internal-tests/package.json
Bumped jest and underscore versions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'feat: update libs' is too vague and generic, using the non-descriptive term 'update libs' that does not convey specific information about which libraries or the nature of the updates. Consider a more specific title that indicates the scope, such as 'feat: upgrade dependencies and tooling to latest versions' or 'feat: update build tools, Koa v3, and project dependencies'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description is related to the changeset as it explains the PR updates tooling and dependencies to be up-to-date, mentions testing was performed, and notes remaining items are out of scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/update-libs
📝 Coding Plan
  • Generate coding plan for human review comments

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Julusian Julusian marked this pull request as ready for review March 17, 2026 13:25
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 | 🟠 Major

Add cd to the methodsToOverride list to serialize all FTP operations.

The queue wraps certain FTP methods for exclusive execution, but cd is missing from the list. This leaves direct this.client.cd('/') calls at lines 96, 199, 218, and 322 running outside the queue, allowing them to interleave with queued operations like ensureDir and remove. 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 | 🔴 Critical

Unsafe JSON.stringify(args) breaks upload/download operations before execution.

The queue wrapper serializes args on line 53 for error context. Since uploadFrom and downloadTo methods receive stream objects (Readable, PassThrough) as arguments, JSON.stringify() throws on circular references and crashes the queued operation before orgMethod.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/winston stub.

Line 20 adds a legacy stub package while winston v3 already provides its own typings. Version mismatch between the @types/winston v2.4.4 stubs and winston v3.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 using node:path for explicit built-in module identification.

While require('path') is standard and always valid, the node: 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/cors in dependencies and devDependencies.

@koa/cors is listed in both dependencies (line 14) and devDependencies (line 29) with the same version. This is redundant—it only needs to be in dependencies since 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

📥 Commits

Reviewing files that changed from the base of the PR and between 051c811 and 025f340.

⛔ Files ignored due to path filters (2)
  • .yarn/releases/yarn-4.1.1.cjs is excluded by !**/.yarn/**
  • yarn.lock is 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.yml
  • apps/_boilerplate/app/package.json
  • apps/_boilerplate/packages/generic/package.json
  • apps/appcontainer-node/app/package.json
  • apps/appcontainer-node/packages/generic/package.json
  • apps/html-renderer/app/package.json
  • apps/html-renderer/packages/generic/package.json
  • apps/http-server/app/package.json
  • apps/http-server/packages/generic/package.json
  • apps/http-server/packages/generic/src/lib.ts
  • apps/http-server/packages/generic/src/server.ts
  • apps/package-manager/app/package.json
  • apps/package-manager/packages/generic/package.json
  • apps/quantel-http-transformer-proxy/app/package.json
  • apps/quantel-http-transformer-proxy/packages/generic/package.json
  • apps/quantel-http-transformer-proxy/packages/generic/src/server.ts
  • apps/single-app/app/package.json
  • apps/worker/app/package.json
  • apps/worker/packages/generic/package.json
  • apps/workforce/app/package.json
  • apps/workforce/packages/generic/package.json
  • jest.config.base.js
  • lerna.json
  • package.json
  • shared/packages/api/package.json
  • shared/packages/api/src/websocketServer.ts
  • shared/packages/expectationManager/package.json
  • shared/packages/worker/package.json
  • shared/packages/worker/src/worker/accessorHandlers/__tests__/fileShare.spec.ts
  • shared/packages/worker/src/worker/accessorHandlers/__tests__/localFolder.spec.ts
  • shared/packages/worker/src/worker/accessorHandlers/lib/FTPClient/FTPClient.ts
  • shared/packages/worker/src/worker/accessorHandlers/lib/fetch.ts
  • shared/packages/workforce/package.json
  • tests/internal-tests/package.json
  • tsconfig.build.json
  • tsconfig.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"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 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 -40

Repository: 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.

Comment on lines +1 to +5
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>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 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 -5

Repository: 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 2

Repository: 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 -20

Repository: 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 2

Repository: 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.ts

Repository: 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 -3

Repository: 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 -15

Repository: 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 -25

Repository: 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.

Suggested change
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).

Comment on lines +98 to 105
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}`)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 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/null

Repository: 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 f

Repository: 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 f

Repository: 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.ts

Repository: 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.json

Repository: 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) => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 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 -20

Repository: 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 -10

Repository: 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 -A2

Repository: 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 -100

Repository: 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/b but not /), use the non-optional wildcard form:

    router.all('/*path', (ctx) => { /* ... */ });

    (Wildcard params are *name in 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:


🌐 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:


🌐 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”

    • /*path is 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)

Citations:


🏁 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 -40

Repository: 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.

@sonarqubecloud
Copy link

Copy link
Member

@nytamin nytamin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'll be great to get this updated, thanks for this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants