From 01c3fa4c35d8a2b9aaa923d2d29d17c0424ab1b9 Mon Sep 17 00:00:00 2001 From: Antoine Toussaint <312536060+antoinetoussaint-byte@users.noreply.github.com> Date: Thu, 29 Oct 2026 12:04:41 -0400 Subject: [PATCH] fix(add): the playground names the token its install needs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The page's kits are published to GitHub Packages and the remote's .npmrc reads ${NODE_AUTH_TOKEN}, so a newcomer's first `make playground` died on: npm error code E401 npm error 401 Unauthorized - unauthenticated: User cannot be authenticated with the token provided. which names neither the variable nor the scope nor the command that sets it. wiki's playground README states it; the scaffolded one said nothing. The remote target now refuses before npm runs, printing the one command to run, and the README carries it as a prerequisite above `make playground`. Nothing about the install changed — only whether the person is told what it needs. Found by asking what someone else would hit on a clean machine, which is the whole point of scaffolding the playground at all. Co-Authored-By: Claude Opus 5 --- cmd/add/solution_playground.go | 16 ++++++++++++++++ cmd/add/solution_test.go | 18 ++++++++++++++++++ docs/commands.md | 17 ++++++++++++++--- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/cmd/add/solution_playground.go b/cmd/add/solution_playground.go index c67dbc78..80139939 100644 --- a/cmd/add/solution_playground.go +++ b/cmd/add/solution_playground.go @@ -215,6 +215,14 @@ playground: remote .PHONY: remote remote: + @test -n "$$NODE_AUTH_TOKEN" || { \ + echo "NODE_AUTH_TOKEN is not set. The page's kits are published to GitHub"; \ + echo "Packages, so the install needs a token with read:packages:"; \ + echo ""; \ + echo " export NODE_AUTH_TOKEN=\$$(gh auth token)"; \ + echo ""; \ + echo "Without it npm answers 401 Unauthorized and says nothing about why."; \ + exit 1; } cd services/fe-remote && npm install --no-audit --no-fund && npm run build test -f services/fe-remote/dist/mf-manifest.json `, titleFromName(name), name, name, playgroundDir) @@ -223,6 +231,7 @@ remote: func playgroundReadme(name string) string { return fmt.Sprintf(`# %s — the playground + export NODE_AUTH_TOKEN=$(gh auth token) # read:packages, for the page's kits make playground Then open the address the EDGE prints: @@ -239,6 +248,13 @@ Then open the address the EDGE prints: | `+"`%s/backend`"+` | this solution's entry service | | `+"`%s/web`"+` | the shell that serves the page, mounting the same `+"`./Page`"+` a host federates | +## The token + +The page's kits (@codefly-dev/*) are published to GitHub Packages, and +services/fe-remote/.npmrc reads NODE_AUTH_TOKEN for them. Without it npm +answers "401 Unauthorized - unauthenticated" and names no cause, so +make playground refuses to start until it is set. + ## The two addresses that are not it - **the shell's own port.** The page asks the edge for `+"`/auth/session`"+` on diff --git a/cmd/add/solution_test.go b/cmd/add/solution_test.go index 903fd5a4..a3c6cac4 100644 --- a/cmd/add/solution_test.go +++ b/cmd/add/solution_test.go @@ -577,3 +577,21 @@ func TestThePlaygroundBuildsTheRemoteFirst(t *testing.T) { } } } + +// TestThePlaygroundRefusesWithoutTheRegistryToken. The page's kits are +// published to GitHub Packages and the remote's .npmrc reads +// NODE_AUTH_TOKEN, so without it npm answers "401 Unauthorized - +// unauthenticated" and names no cause. The playground says so itself rather +// than letting a newcomer meet that. +func TestThePlaygroundRefusesWithoutTheRegistryToken(t *testing.T) { + makefile := playgroundMakefile("notes") + if !strings.Contains(makefile, "NODE_AUTH_TOKEN") { + t.Fatalf("the remote target must check for the registry token:\n%s", makefile) + } + if !strings.Contains(makefile, "gh auth token") { + t.Fatal("the refusal must name the command that sets it") + } + if !strings.Contains(playgroundReadme("notes"), "NODE_AUTH_TOKEN") { + t.Fatal("the playground README must state the token as a prerequisite") + } +} diff --git a/docs/commands.md b/docs/commands.md index 851e1047..cd698152 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -2435,9 +2435,20 @@ What it creates: `services/fe-remote` — the `./Page` remote itself — is written by the solution agent, not by this command: it is an npm package, not a Codefly service. -**Running it.** `make playground` builds the page's remote, starts the -development authority and this solution, and prints the one address a browser -opens: +**Running it.** + +```sh +export NODE_AUTH_TOKEN=$(gh auth token) # read:packages, for the page's kits +make playground +``` + +The token is a prerequisite, not a nicety: the page's `@codefly-dev/*` kits are +published to GitHub Packages and the remote's `.npmrc` reads it, so without one +npm answers `401 Unauthorized - unauthenticated` and names no cause. The +playground refuses to start and says which command sets it. + +`make playground` builds the page's remote, starts the development authority +and this solution, and prints the one address a browser opens: ``` edge listening on :14581, routing 1 module(s)