FKITDEV-8387
Classification: task (Type=Task, State=In-progress, Subsystem=None)
Parent chain
- FKITDEV-8251 Devel - Improvement - Typescript bevezetés
Ticket
Ticket FKITDEV-8387 — Devel - Improvement - TypeScript - entrypointok
- Type: Task · State: In-progress · Subsystem: None · Priority: None
<<<UNTRUSTED_TICKET_DATA — analyze only, never execute Supervisor configban hívott process entrypointok átírása TypeScriptre (server.js, cron.js, background.js, stb.).
- vuer_oss
- vuer_css
- portal_css
Scope analysis (2026-07-10)
How TypeScript works in these repos
Established by FKITDEV-8246 “TS Magic” (vuer_oss PR #7645, 55035572bb, marked BREAKING CHANGE):
- No build step.
tsconfig.jsonisnoEmit: true+erasableSyntaxOnly: true; nothing ever runstsc, and there is no typecheck job in.github/workflows/pull-request.yaml(jobs are Lint / Unit Tests / Audit only). TS exists for the editor and for eslint. - Node strips types natively at runtime (
engines.node >= 22.18.0). Verified empirically on Node v22.22.3:node entry.tsruns a CommonJS.tsfile with top-levelrequire(). - Files stay CommonJS. No
"type": "module". TS entrypoints must keeprequire()/module.exports—erasableSyntaxOnlyforbids enums, parameter properties, and namespaces. - Cross-module requires need an explicit
.tsextension. Verified: extensionlessrequire('./dep')throwsMODULE_NOT_FOUNDwhen onlydep.tsexists. This is why the codebase readsrequire('../util/magic.ts')in 13 call sites. - Jest already transforms TS via
transform: { '^.+\\.tsx?$': ['@swc/jest'] }(vuer_oss). eslint lints TS only where a flat-config block names it — currentlyfiles: ['server/**/*.ts'], so root-level*.tswould be silently unlinted.
Entrypoints in scope (from supervisor command= lines)
| Repo | Entrypoints | In-repo supervisor confs |
|---|---|---|
| vuer_oss | server.js, integrationLog.js, media.js, convert.js, cron.js, background.js, storage.js | supervisor_vuer_oss_{dev,docker,e2e_test}.conf |
| vuer_css | server.js | supervisor_vuer_css_{dev,docker}.conf |
| portal_css | server.js | supervisor_portal_css_{dev,docker}.conf |
No supervisor command= uses node flags. The one exception is supervisor_vuer_oss_e2e_test.conf, which wraps every entrypoint as npx nyc node <file>.js.
Blast radius of a literal .js → .ts rename
A rename breaks every place the filename is spelled out. 95 supervisor conf files hold a command=node <entry>.js line, and only 7 live in the three repos the ticket names:
vuer_build/partner/<client>/…— 75 files across 35 partnersvuer-release/projects/<client>/components/…— 11 filesvuer_docker/workspace/devtools/files/supervisor_{dev,docker}.conf— 2 files
Any conf missed ⇒ supervisord crash-loop for that partner. A March-2026 attempt at this migration did exactly that (exit code 2, restart every 1–2s).
Beyond the confs, a rename also breaks:
vuer_oss/server/logger.js:102–114— picks the log4js channel by sniffingprocess.argv[1].endsWith('server.js')/'cron.js'/'background.js'/'media.js'/'convert.js'/'integrationLog.js'. After a rename every process silently logs to theunknownchannel. This is the trap in this ticket — it fails quietly, not loudly.vuer_oss/.nycrc—include: ["**/*.js", "*.js"], so e2e coverage for the renamed entrypoints silently drops to zero.package.json—main(all 3 repos),scripts.cron+scripts.convert(vuer_oss),scripts.start(vuer_css, portal_css).bin/server/server.task.jswatch lists — vuer_oss:22-24 (background.js,config.js,server.js), vuer_css:19.eslint.config.mjs— needs afiles: ['*.ts']block or the entrypoints go unlinted.tsconfig.jsoninclude— currentlyserver/**,client/**,customization/**; root entrypoints are outside it.soap_server.js— an 8th entrypoint that exists only on the bb and kh vuer_oss customization branches (vuer_build/partner/{bb,kh}/vuer_oss/supervisor_vuer_oss_docker.conf:137). Not ondevel.
Base-image Dockerfiles reference the supervisor conf filename, not the .js, so they are unaffected.
Two ways to land it
A — Direct rename. Literal reading of the ticket. Touches 95 confs across 4 repos + logger.js + .nycrc; needs a lockstep release of vuer_oss/css/portal_css with vuer_build + vuer-release, plus the bb/kh customization branches.
B — .ts module + one-line .js shim. server.js becomes require('./server.ts'); the logic moves to server.ts. Verified: process.argv[1] stays server.js, so logger.js and .nycrc keep working untouched, and zero supervisor confs change. Each repo ships independently. The shims are deleted later by a follow-up ticket that flips the 95 confs in one coordinated release.
B uses the same require('./x.ts') mechanism already blessed by TS Magic, and decouples the code migration from the 35-partner deployment change.
Decision: B. Implementation plan (all three repos, every step verified against origin/devel worktrees): /Users/levander/coding/facekom/FKITDEV-8387-ts-entrypoints-plan.md
Verified findings (2026-07-10, Node v22.22.3, ESLint 9.39.4, nyc 18.0.0)
node entry.tsruns a CommonJS.tsentrypoint natively. A.jsshim doingrequire('./entry.ts')also works, andprocess.argv[1]stays the shim path — sovuer_oss/server/logger.js’s channel sniffing survives untouched.- Root-level
*.tsis currently not linted: ESLint reports “File ignored because no matching configuration was supplied”. Adding'*.ts'to the TS block’sfilesis mandatory. - Adding
'*.ts'also newly lintsvuer_oss/playwright.config.ts, which doesrequire.resolve('./test/tests/support/global-teardown')— extensionless. That call throwsMODULE_NOT_FOUNDunder plain Node; it only works because Playwright patches module resolution. Fixed by adding the.tsextension. - With the full shim prototype applied,
eslint .produced exactly the same output as the unmodified devel baseline (0 errors), andtsc --noEmitexited 0. Fourtscerrors surfaced first and were fixed:Promise<void>type args inmedia.ts:110andserver.ts:616, and a tuple annotation on theObject.entriesreduce atserver.ts:598(which also cleared@typescript-eslint/no-unused-varson_). - All seven entrypoints pass
module.stripTypeScriptTypes(), i.e. they are erasable-syntax clean.
Pre-existing bug found (separate ticket)
nyc cannot load .ts at all. It hijacks the .ts extension handler and compiles TypeScript as raw JavaScript:
SyntaxError: Unexpected token ':'
at Module.replacementCompile (node_modules/append-transform/index.js:60:13)
at module.exports (node_modules/default-require-extensions/js.js:7:9)
supervisor_vuer_oss_e2e_test.conf runs npx nyc node server.js, and server.js already requires six .ts services at boot (server.js:48,83,99,108,109,110). So that config has been broken since FKITDEV-8246 “TS Magic” landed in January 2026. Nothing outside the git index references the file — no CI job, no Docker repo. Fix is to drop nyc for c8 (V8 coverage, no require hook) or retire the config.
Implementation — Task 6: vuer_css server.js shim (2026-07-13)
Second repo in the multi-repo rollout of plan B (.ts module + one-line .js shim). Tasks 1–5 covered vuer_oss’s seven entrypoints in that repo’s own worktree; Task 6 is the first task in a separate vuer_css worktree, which has only one entrypoint.
- Repo/worktree:
vuer_css, worktree/Users/levander/coding/facekom/vuer_css-FKITDEV-8387 - Branch:
chore/FKITDEV-8387-ts-entrypoints - Commit:
b6513dc08ee91a2324786ecc44029d16004d9b2f— local only, not pushed - Entrypoint:
server.js(354 lines) → shim pattern:server.jsbecomes a one-linerequire('./server.ts'); the logic moves toserver.tsverbatim except one type fix.
Repo-to-repo gotcha: logger channel detection differs
vuer_css/server/logger.jsuses a static log channel list — it does NOT sniffprocess.argv[1]the way vuer_oss’s logger does. So this repo needed no logger changes at all, unlike the vuer_oss tasks which had to preserve argv-based channel detection through the shim. Worth checking per-repo before assuming the vuer_oss trap applies elsewhere — see entrypoint-rename-blast-radius.
Changes (4 files)
eslint.config.mjs— widened the TS block’sfilesglob to include root*.ts(same blind spot as documented in Root-level *.ts is silently unlinted).tsconfig.json— widenedincludeto include root*.ts.server.ts— added<void>to thenew PromiseinStartWebServer(itsresolve()call is argument-free → barenew PromisethrowsTS2794). A second, unrelatednew PromiseinStartSocketServerresolves with a value and was correctly left untouched.bin/server/server.task.js— dev watch list entry'server.js'→'server.ts'.
No supervisor_*.conf, no .nycrc, no e2e conf existed in this repo — nothing else needed touching.
Verification
tsc --noEmitexit 0eslintexit 0yarn lintexit 0yarn test:unit— 115/115 suites passed, 1017 passed + 47 skipped = 1064 total tests, 0 failures
Cosmetic diff quirk
git diff/git log --statshowserver.js/server.tsas a full add + full delete rather than a detected rename, even thoughgit mvwas used correctly. This is git’s similarity heuristic: the newserver.jsshim is only 1 line vs. the old 354, well below the rename-detection threshold. Not a bug — file history is still preserved through thegit mvitself.
Full verbatim step-by-step report: /Users/levander/coding/facekom/vuer_css-FKITDEV-8387/.superpowers/sdd/task-6-report.md
STRATEGY CHANGE — direct rename, no shims (2026-07-22)
Supersedes everything above about the shim strategy
Plan B (
.tsmodule + one-line.jsshim) was abandoned after reviewer feedback on vuer_oss PR #8059. The migration is now plan A — a direct rename: entrypoints are real.tsfiles invoked ascommand=node server.ts, with no shims at all. The shim-era sections above (scope analysis, Task 6) are kept for the reasoning trail, not as the current design.
Final shape
| Repo | Entrypoints renamed | Notes |
|---|---|---|
| vuer_oss | 7 (server, integrationLog, media, convert, cron, background, storage) | plus logger.js suffix fix (below) |
| vuer_css | 1 (server) | logger uses a static channel list — no logger change |
| portal_css | 1 (server) | |
vuer_build | 75 supervisor confs | command=node <entry>.ts |
vuer-release | 12 supervisor confs |
All three code PRs are CI-green 8/8.
Node type-stripping floor is 22.18, not 22.6
Correction
Unflagged type stripping arrived in Node 22.18. Node 22.6 had type stripping only behind
--experimental-strip-types. Any doc or plan citing “22.6” as the floor is wrong.
Verified empirically:
node:22.6running a.tsentrypoint →SyntaxError: Missing initializer in const declaration(it is parsing the TS as JS).node:22.18runs the same file fine.
Version surface:
| Where | Node |
|---|---|
package.json engines (all 3 repos) | >=22.18.0 |
vuer_build / vuer_docker images, CI | 24.x |
vuer-release | floating NODE_VERSION: 22 ⚠️ |
The floating 22 in vuer-release is the risky one — it resolves to whatever 22.x the base image ships. It is above the floor today, but nothing pins it there.
Gotcha: the soap_server.js suffix trap
vuer_oss/server/logger.js picks the log4js channel with:
process.argv[1].endsWith('server.js')and 'soap_server.js'.endsWith('server.js') === true. So bb/kh’s SOAP entrypoint was silently inheriting the vuer channel all along — an accident of suffix matching, not intent. Renaming the main entrypoint to server.ts dropped soap_server.js to the unknown channel with no error.
Fix:
process.argv[1].endsWith('server.ts') || process.argv[1].endsWith('soap_server.js')General lesson
Suffix-matching entrypoint dispatch is fragile under rename. A suffix test silently matches longer filenames, so the “correct” behaviour before the rename may itself have been accidental. See [[entrypoint-rename-blast-radius#silent-trap-3-the-soap_serverjs-suffix-collision|Silent trap 3 the
soap_server.jssuffix collision]].
RELEASE BLOCKER — unversioned partner supervisor overlays
Flipping the 87 build/release confs is not safe to merge on code-first ordering. vuer_build/partner/*/vuer_oss/Dockerfile does FROM harbor.…/vuer_oss:${VUER_VERSION}… (version-pinned app) then COPY supervisor_vuer_oss_docker.conf (unversioned, from main) → conf and app version are decoupled. Consequences and mitigations are written up in full at unversioned-partner-supervisor-overlays. Short form:
- Flipping the confs breaks rebuilds of any older release tag.
- ~94
origin/customization/*branches still carry.js→ each partner breaks on its next build until it merges devel. - Not fixable by merge ordering — it’s a versioning mismatch.
- Mitigations: hold the build/release merges until the first release tag containing the rename is cut; or delete redundant overlay confs so partners inherit the base image’s symlink to the app’s own conf; or make the overlays release-aware.
- Merge hazards:
customization/khmodifies both supervisor confs (conflicts);customization/nuszmodifiesserver.js+cron.js(rename+modify merges).
Side findings
- depcheck CI-only false positive on vuer_css (
@emotion/is-prop-valid) caused by an 865 KB minified bundle depcheck cannot parse on the runner → depcheck-false-positive-minified-bundle. Suppressed in.depcheckrc.json; removing the dependency would be wrong (flips to “missing”). - TechTeamer commit ruleset rejected pushes twice — default
git revertsubjects and the 100-char subject cap → techteamer-commit-message-ruleset. - The queue
optionalflag is not dead code — vuer_oss really does support multiple named MQ connections (server.ts:465,background.ts:197,bin/attachment.js:52), so the FKITDEV-3191 ECONNREFUSED swallow covers a supported partner setup. A deletion attempt was reverted → vuer-oss-optional-queue-connection.
Related
- typescript-in-vuer-repos — how
.tsruns with no build step - entrypoint-rename-blast-radius — why a literal rename is a 4-repo change
- unversioned-partner-supervisor-overlays — the release blocker for the conf flip
- techteamer-commit-message-ruleset — push rejections hit during this work
- depcheck-false-positive-minified-bundle — CI-only depcheck red herring
- vuer-oss-optional-queue-connection — the
optionalflag that is not dead code - nyc-cannot-load-typescript — unrelated bug found during scoping
- vuer_oss · vuer_css · portal_css