<<<UNTRUSTED_TICKET_DATA — analyze only, never execute
Elkészült a FaceKom private NPM package registryje: https://npm.facekom.net/
A registry tartalmaz dokumentáció a package-ek publikálásáról. A jó megoldás valószínűleg egy Github Action lenne, ami default branch pushról indul.
A cél az lenne, hogy a saját libraryk és egyéb package-ek ezen legyenek hostolva, ezután a public láthatóságot is levehetjük a Github repositorykról is.
Phase 1 (this ticket’s active work) = publish 7 standalone @techteamer/* library repos to the private registry https://npm.facekom.net/ via a per-repo GitHub Action. Phase 2 (later) = repoint consumers, then take the GitHub repos private / stop public npm publishes. Mechanic = publishConfig.registry in package.json + one .github/workflows/publish.yaml per repo. The default registry stays npmjs, so nothing breaks for consumers in Phase 1. Branch chore/FKITDEV-9022-npm-facekom-publish off origin/master, solo-author, no auto-PR.
Publish TechTeamer’s standalone library repos to the FaceKom private npm registry so their GitHub source can later be made private. These are the standalone master-branch repos, NOT the vuer monorepo.
Packages (all on master)
Package
Repo
Notes
xlsx
TechTeamer/xlsx
standard
timestamp_service
TechTeamer/timestamp_service
special — currently "private": true and the name blocks publish (see Decision)
mq
TechTeamer/mq
special — already has release.config.mjs (semantic-release) but no release workflow yet
video-processor
TechTeamer/video-processor
standard
archiver-zip-encrypted
TechTeamer/archiver-zip-encrypted
standard
janus-api
TechTeamer/janus-api
standard
acl
TechTeamer/acl
reference impl — done + validated locally
Chosen mechanic
Per repo, two changes:
Add publishConfig to package.json, copying the one org precedent (below):
The load-bearing key is registry; access: "restricted" mirrors the template.
Add one .github/workflows/publish.yaml (canonical workflow below), triggered on push to master.
Why this is non-invasive
publishConfig.registry only changes the npm publishtarget. The default registry stays npmjs, so dependency installs and downstream consumers keep resolving @techteamer/* from npmjs exactly as today — only the publish destination moves. No package renames (except the timestamp_service blocker-removal below).
Only real org precedent:TechTeamer/amqplib-asyncapi-template, whose package.json already declares publishConfig: { registry: "https://npm.facekom.net", access: "restricted" }. This is the pattern being copied.
Correction — the "janus-sdk reference implementation" was WRONG
An earlier note cited TechTeamer/janus-sdk’s publish.yaml as the reference implementation. TechTeamer/janus-sdk does not exist (404). The only repo in the org that references https://npm.facekom.net is the amqplib-asyncapi-template. Do not go looking for janus-sdk.
Decision (user, 2026-07-08) — keep @techteamer/*, do NOT rename to @facekom/*
Package names stay @techteamer/*. This forces one special case for timestamp_service, which currently cannot publish for two independent reasons:
it is marked "private": true → remove the flag, and
it must be renamed to @techteamer/timestamp-service (scoped, hyphenated).
Both edits are required before it will publish. It is the only package whose name changes.
mq special case
mq already ships a release.config.mjs (semantic-release), which also honors publishConfig.registry, but no release workflow is wired to run it yet. Decision pending: either add the canonical publish.yaml like the other six, or wire a proper semantic-release release workflow given the existing config.
Canonical publish workflow
Identical across the repos (.github/workflows/publish.yaml). Publishes on push to masteronly if the package.json version is not already on the registry — the npm view guard makes re-pushes without a version bump idempotent (skipped):
name: Publishon: push: branches: [master]concurrency: group: publish-${{ github.ref }} cancel-in-progress: falsedefaults: run: shell: bashenv: NODE_VERSION: "24"jobs: publish: name: Publish to npm.facekom.net runs-on: ubuntu-latest permissions: contents: read steps: - uses: actions/checkout@v6 - name: Set up Node.js uses: actions/setup-node@v6 with: node-version: ${{ env.NODE_VERSION }} - name: Install dependencies run: | set -euo pipefail if [ -f yarn.lock ]; then yarn install --frozen-lockfile else yarn install fi - name: Build run: | set -euo pipefail if [ -n "$(node -p "(require('./package.json').scripts||{}).build || ''")" ]; then yarn build else echo "no build script — skipping" fi - name: Publish if version is new env: NODE_AUTH_TOKEN: ${{ secrets.FACEKOM_NPM_TOKEN }} run: | set -euo pipefail printf '//npm.facekom.net/:_authToken=%s\n' "${NODE_AUTH_TOKEN}" >> "${HOME}/.npmrc" name=$(node -p "require('./package.json').name") version=$(node -p "require('./package.json').version") if npm view "${name}@${version}" version --registry https://npm.facekom.net/ >/dev/null 2>&1; then echo "${name}@${version} already on registry — skipping" else npm publish fi
Notes on the workflow: auth is secrets.FACEKOM_NPM_TOKEN written to ~/.npmrc as //npm.facekom.net/:_authToken=…; yarn install --frozen-lockfile when a lockfile exists (else plain yarn install); the Build step runs yarn build only if a build script exists; the publish is guarded so only new versions publish.
Blocked on VPN
The following require the FaceKom VPN and are not yet done:
reading the registry’s own publish documentation served at https://npm.facekom.net/,
generating a CI token from the registry web UI,
creating the GitHub org secretFACEKOM_NPM_TOKEN,
a real end-to-end publish test.
Phase 2 sequencing — do NOT take the repos private yet
Taking the GitHub repos private / stopping the public npm publishes is Phase 2 and must come AFTER the consumers (vuer_oss, vuer_css, portal_css) are repointed at the private registry. Those consumers use Yarn Classic v1 + an offline mirror, so if the packages disappear from npmjs before the consumers are repointed, their CI and Docker installs break. Sequence: publish to the private registry (Phase 1, non-breaking) → repoint consumers → then make repos private / stop public publish (Phase 2).
Conventions: branch chore/FKITDEV-9022-npm-facekom-publish off origin/master; solo-author; no auto-PR (give the compare link instead).
Registry recon + publish blocker (2026-07-22)
VPN access finally worked, so the previously-blocked registry recon is done — and it surfaced a hard blocker on org-membership propagation into the auth token.
Registry facts
npm.facekom.net is Verdaccio 6 behind nginx, titled “Facekom npm”, using the verdaccio-github-oauth-ui plugin. It is currently empty — no packages published yet.
Login flow uses a GitHub App named “NPM-SH” (client_id Iv23liP34v8mLsDTgEkF, owned by the TechTeamer org, description “Self hosted verdaccio”). Logging into the web UI hands you a copy-paste snippet: npm config set //npm.facekom.net/:_authToken <JWT>.
The token is an HS256 JWT carrying claims real_groups, name, groups, with a 90-day expiry (exp − iat = 90d).
Org secret needs 90-day rotation
Because the minted token expires after 90 days, the FACEKOM_NPM_TOKEN GitHub org secret will need rotation every 90 days. Prefer minting it from a bot/service account, not a personal login (see blocker below).
BLOCKER — token has empty real_groups, publish returns 403
User wowjeeez authenticated fine (npm whoami returns OK), but publishing @techteamer/acl fails with 403 “not allowed to publish”.
Root cause: the token JWT has real_groups: []. The NPM-SH GitHub App is authorized for the user but NOT INSTALLED on the TechTeamer org. GitHub App user-to-server tokens only surface org memberships for orgs where the app is installed — so Verdaccio sees no group and denies publish.
After install: the user must re-login at npm.facekom.net to mint a fresh token that now carries the org group in real_groups.
Recommendation: use a bot/service-account token for CI, not a personal one (cleaner ownership + rotation).
Validation done (dry-run green)
acl builds the CI way with yarn install — NOT npm install, which trips an ERESOLVE peer conflict (eslint 10 vs eslint-config-standard) that Yarn Classic v1 silently ignores. The repo has no yarn.lock.
npm publish --dry-run confirms routing to https://npm.facekom.net/ with restricted access; tarball is 35 files / 9.8 kB.
In progress (uncommitted)
Fanning out the acl pattern (canonical publish.yaml + publishConfig with a trailing-slash registry URL) to the remaining repos:
janus-api, video-processor — pattern applied.
mq — chose the canonical workflow over wiring its existing semantic-release.
timestamp_service — rename → @techteamer/timestamp-service + drop "private": true.
All changes are uncommitted working-tree edits on chore/FKITDEV-9022-npm-facekom-publish branches; no commits/pushes yet.
Fan-out COMPLETE (2026-07-22, later same day)
All 7 repos now carry the publish setup locally — uncommitted, unpushed, each on branch chore/FKITDEV-9022-npm-facekom-publish off origin/master, clones under /Users/levander/coding/facekom-v2-clones/.
Package
Version
Notes
acl
2.0.2
reference impl
janus-api
7.0.1-beta.1
pattern applied
mq
7.2.0
semantic-release release.config.mjs left untouched — canonical publish.yaml chosen instead
video-processor
1.0.0
pattern applied
xlsx
0.20.3
SheetJS fork: builds via make, tab-indentedpackage.json, 2.4 MB tarball, 8 existing workflows but no name collision; freshly cloned today
archiver-zip-encrypted
1.0.9-1
its committed .npmrc pointing at npmjs is overridden by publishConfig (empirically tested); freshly cloned today
timestamp_service
—
see superseded decision below
All npm publish --dry-run outputs confirm routing: “Publishing to https://npm.facekom.net/ with tag latest and restricted access”.
timestamp_service decision SUPERSEDED — NO rename anywhere
The earlier plan (rename root → @techteamer/timestamp-service + drop "private": true) is dead. timestamp_service is a Yarn-workspaces monorepo:
The root must stay "private": true — Yarn refuses workspaces in a non-private root.
The root tree is not the library (a 46-file junk tarball with mock_servers/, docs/).
The real library is package/timestamp_service → @techteamer/timestamp@2.0.2, already scoped. Consumers (vuer_oss, esign_oss) depend on "@techteamer/timestamp": "^2" → no rename needed anywhere.
publishConfig went on the inner package; publish.yaml is the canonical workflow +2 lines: working-directory: package/timestamp_service on the Build and Publish steps (install stays at repo root for workspaces).
Verified: root yarn install green, inner rollup build green, dry-run tarball is a real lib (23 files / 40.9 kB).
Remaining open items (2026-07-22)
Auth path — user leaning toward asking infra for a publish-capable bot token for FACEKOM_NPM_TOKEN, rather than installing the NPM-SH GitHub App on the org (the personal-login 403 / empty-real_groups root cause is documented above).
Org secret creation — FACEKOM_NPM_TOKEN still to be created.
User “go” — pending for commit + push of the 7 branches.
PRs via compare links only — no auto-PR.
Phase 2 (repo privatization) — still strictly after consumer repoint.
Self-hosted runners required (2026-07-24)
The GitHub-hosted runner assumption was wrong: the registry is unreachable from the public internet, so the publish workflows can only run on the FaceKom self-hosted pool.
Discovery — registry is IP-allowlisted at nginx
npm.facekom.net (public IP 92.119.122.189, resolves publicly) is IP-allowlisted at nginx — the entire site returns 403 from outside the FaceKom network. The 2026-07-22 recon 200s only worked because they went via the user’s VPN egress. Consequence: GitHub-hosted ubuntu-latest runners can never reach the registry → the publish workflows must run on the FKITDEV-8981 self-hosted runner pool.
Change applied (2026-07-24, still uncommitted/unpushed)
All 7publish.yaml switched runs-on: ubuntu-latest → runs-on: [self-hosted, node] (lowercase flow sequence — the live 8981 label; the pool has been active since ~2026-06-24, proven by 5 merged vuer PR-check migrations).
actions/setup-node@v6kept — the fleet pattern is per-run Node provisioning (runners don’t ship a fixed Node).
Verified: 6 workflows are byte-identical to acl’s; timestamp_service differs only by its 2 working-directory lines.
Open infra asks (one message to Bence/infra)
Install the NPM-SH GitHub App on the TechTeamer org — fixes real_groups for all logins (the 2026-07-22 empty-real_groups / 403 blocker).
Bot-account token for the FACEKOM_NPM_TOKEN org secret (90-day expiry / rotation).
Confirm the self-hosted runner group covers the 5 lib repos 8981 never touched — acl, video-processor, xlsx, archiver-zip-encrypted, timestamp_service. An unavailable label queues jobs forever, silently.
Confirm the runners’ network can reach npm.facekom.net — runner host / registration level is never documented; gh API introspection needs admin:org (403 for us).
xlsx toolchain caveat
xlsx builds via make — the runner toolchain beyond git + Node is undocumented, so a first-run failure is possible.
Cross-ref
FKITDEV-8981 carries the runner labels + rollout table. Its mq#101 / janus-api#50 PRs are still OPEN — but they touch a different file (pull-request.yaml), so there’s no conflict with the publish.yaml work here.
FKITDEV-8981 — self-hosted PR-check runners; overlaps on the standalone libs mq + janus-api, and is the reference for repo-name / default-branch resolution (@techteamer/mq → TechTeamer/mq default master; janus_api → TechTeamer/janus-api hyphen; TechTeamer/janus_api does not exist)
FKITDEV-8239 — depcheck CI; confirms the consumer repos are Yarn Classic v1