Remove the toolchain image module; node-tools is the repository's only module (issue 979, S1; ADR 0524 §5)
Only build-agent built inside that image, and it goes in R4g.
This commit is contained in:
-85
@@ -1,85 +0,0 @@
|
||||
ARG NODE_BASE=node:22-bookworm-slim
|
||||
# The mesh-tools module: the two images every TypeScript module is COMPILED in and may RUN in. The
|
||||
# runtime itself ships as the node-tools module's bundle (node-tools/, novox/hq ADR 0175, to-be 38
|
||||
# WP3); these images are the toolchain for TypeScript bundles and the base a module's own service
|
||||
# may still be built on. They are no longer how tools reach a node.
|
||||
#
|
||||
# **They were the same image, and that was a mistake.** A module's recipe starts from this and
|
||||
# invokes the compiler out of it, so the compiler had to be here — and because the same image was
|
||||
# also what every module ran in, every running container on every machine carried a TypeScript
|
||||
# compiler it would never invoke. The answer is separate stages rather than one image bad at both
|
||||
# jobs. `build.artifacts` in module.json names the published stage each — `toolchain` and `runtime`.
|
||||
#
|
||||
# The `deps` stage is neither published nor named there: it is where the mesh's package registry is
|
||||
# reached, so it is where — and only where — the credential to reach it exists. The toolchain copies
|
||||
# resolved node_modules out of it, so the credential is in no image any machine ever holds
|
||||
# (novox/hq ADR 0076). This is the buildkit-secret's job done without buildkit, because a machine's
|
||||
# docker may carry no buildx.
|
||||
|
||||
# ---- deps: node_modules resolved from the mesh's registry, credential and all ----------------
|
||||
FROM ${NODE_BASE} AS deps
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends git ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
WORKDIR /app
|
||||
COPY node-tools/package.json ./
|
||||
# The builder writes .npmrc into the build context; it authenticates to the mesh's package registry
|
||||
# for the @novox scope, which is where @novox/mesh-sdk resolves. This stage is not published, so the
|
||||
# credential travels no further than here. Development dependencies included: the compiler is one.
|
||||
COPY .npmrc ./.npmrc
|
||||
RUN npm install --no-audit --no-fund
|
||||
# **The SDK this image carries is the one the mesh last published** (novox/hq issue 212). The range in
|
||||
# package.json is resolved once and the layer above is cached, so a release reached no toolchain until
|
||||
# that file changed. The exact version arrives as a build argument from the SDK module's published
|
||||
# package (module.json `build.on`), so a new release is a new argument, this layer runs again — and
|
||||
# the planner orders this module after the SDK, so a release rebuilds the toolchain and, after it,
|
||||
# every bundle compiled in it (issue 211).
|
||||
ARG MESH_SDK=@novox/mesh-sdk@latest
|
||||
RUN npm install --no-audit --no-fund "${MESH_SDK}"
|
||||
|
||||
# ---- compiling: the runtime's own code built, WITHOUT the credential -------------------------
|
||||
FROM ${NODE_BASE} AS compiling
|
||||
WORKDIR /app
|
||||
COPY node-tools/package.json ./
|
||||
# The resolved libraries, but not the .npmrc that resolved them.
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY node-tools/tsconfig.json ./
|
||||
COPY node-tools/src ./src
|
||||
RUN npm run build
|
||||
|
||||
# ---- what a running bundle needs, and nothing else -------------------------------------------
|
||||
# Its own stage so the toolchain image keeps its build tools while the runtime image does not.
|
||||
FROM compiling AS lean
|
||||
RUN npm prune --omit=dev
|
||||
|
||||
# ---- toolchain: what a TypeScript bundle is compiled in ---------------------------------------
|
||||
# The compiler, and esbuild (a development dependency) at /app/node_modules/esbuild: the builder
|
||||
# bundles every entrypoint and launcher into one file with it (novox/hq ADR 0193), so a bundle
|
||||
# carries what it imports and not this image's node_modules.
|
||||
# Beside the compiler, at /app/runtime, what every TypeScript bundle runs with: the production
|
||||
# dependencies the SDK and the runtime need, and a package.json saying the compiled files are ES
|
||||
# modules. The builder copies this directory whole into a compiled bundle (novox/hq ADR 0188 §5),
|
||||
# so a bundle unpacked on a machine starts — a `.js` without that package.json is read as
|
||||
# CommonJS, and an import of `nats` without node_modules beside it resolves to nothing.
|
||||
#
|
||||
# **The client libraries a catalogue module depends on are here too** (novox/hq issue 385): pg, mongodb and
|
||||
# mssql, development dependencies of node-tools, so the runtime stage prunes them. A catalogue's
|
||||
# merge-check-typescript.sh fetches nothing and copies this image's node_modules beside a module; a module
|
||||
# depending on a package that is not here cannot be type-checked or tested, and fails its check.
|
||||
FROM compiling AS toolchain
|
||||
COPY --from=lean /app/node_modules /app/runtime/node_modules
|
||||
RUN printf '{"type":"module","private":true}\n' > /app/runtime/package.json
|
||||
# **git, because a pull request's merge check runs in this image too** (novox/hq ADR 0237): a repository's
|
||||
# own merge-check.sh that declares this toolchain runs here, and a suite that reads a repository's history
|
||||
# (the lab's last-run record) ran into "spawnSync git ENOENT". Nothing compiled here calls it.
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends git \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# ---- runtime: what a module's own service may run in ------------------------------------------
|
||||
FROM ${NODE_BASE} AS runtime
|
||||
WORKDIR /app
|
||||
COPY node-tools/package.json ./
|
||||
COPY --from=lean /app/node_modules ./node_modules
|
||||
COPY --from=compiling /app/dist ./dist
|
||||
ENTRYPOINT ["node", "dist/main.js"]
|
||||
@@ -1,13 +1,11 @@
|
||||
# mesh-tools
|
||||
|
||||
Two modules in one repository (novox/hq ADR 0069), one piece of software:
|
||||
One module, `node-tools`; the toolchain image module that stood beside it is retired (novox/hq ADR 0524 §5):
|
||||
|
||||
- **`node-tools`** (`node-tools/`) — the node's **tool runtime** as a module (ADR 0175, to-be 38
|
||||
WP3): one process per machine the host runs from this bundle, serving every assigned module's tools
|
||||
and every held seat's verbs on the bus, and answering MCP on the machine's loopback — the console
|
||||
(design 34). The code, its tests and the `mesh` client all live there.
|
||||
- **`mesh-tools`** (this directory) — the two images TypeScript bundles are compiled in and a module's
|
||||
own *service* may still run in. Built from the same code; no longer how tools reach a node.
|
||||
|
||||
The runtime:
|
||||
|
||||
@@ -49,8 +47,7 @@ MESH_BROKER_URL a plain URL instead of the credential, for the bootstrap
|
||||
|
||||
`node dist/main.js`. On a node the controller composes the variables and the host supervises the
|
||||
process like any other host-side workload (novox/hq to-be 38). As `node-tools` the same process is
|
||||
the console: MCP on `127.0.0.1:4270` (or `MESH_CONSOLE_LISTEN`). The container (`Dockerfile`) is how
|
||||
a module's own *service* may still be built; it is no longer how tools reach a node.
|
||||
the console: MCP on `127.0.0.1:4270` (or `MESH_CONSOLE_LISTEN`).
|
||||
|
||||
## `mesh` — the tools for whoever is on a machine
|
||||
|
||||
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"module": "mesh-tools",
|
||||
"version": "1",
|
||||
"slug": "tools",
|
||||
"build": {
|
||||
"artifacts": [
|
||||
{
|
||||
"name": "build",
|
||||
"kind": "image",
|
||||
"from": "Dockerfile",
|
||||
"target": "toolchain"
|
||||
},
|
||||
{
|
||||
"name": "runtime",
|
||||
"kind": "image",
|
||||
"from": "Dockerfile",
|
||||
"target": "runtime"
|
||||
}
|
||||
],
|
||||
"on": [
|
||||
{
|
||||
"arg": "NODE_BASE",
|
||||
"image": "node@sha256:48e4b67d85f87bd551df43704e24d252f56cc5f8e9718841aace50f19948f0f9"
|
||||
},
|
||||
{
|
||||
"arg": "MESH_SDK",
|
||||
"module": "mesh-sdk",
|
||||
"artifact": "lib"
|
||||
}
|
||||
]
|
||||
},
|
||||
"resources": []
|
||||
}
|
||||
@@ -90,3 +90,32 @@ func TestBundlesCannotBeLaunchedWithoutNodeOrTheSDKAndTheSkipSaysWhy(t *testing.
|
||||
t.Errorf("node and the package present said %q", why)
|
||||
}
|
||||
}
|
||||
|
||||
// The checker runs node-tools' Go level by Go's convention and its Node level by package.json's test script
|
||||
// (novox/hq ADR 0529): no script of the repository's own runs beside them, and no module but node-tools is built from
|
||||
// here (ADR 0524 §5, the toolchain image retired).
|
||||
func TestTheRepositoryHoldsNoCheckScriptAndNodeToolsIsItsOnlyModule(t *testing.T) {
|
||||
root := filepath.Join("..", "..", "..")
|
||||
if _, err := os.Stat(filepath.Join(root, "merge-check.sh")); err == nil {
|
||||
t.Errorf("merge-check.sh is back: the checker's levels run the tests")
|
||||
}
|
||||
var found []string
|
||||
err := filepath.WalkDir(root, func(p string, d os.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.IsDir() && (d.Name() == "node_modules" || d.Name() == ".git") {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
if !d.IsDir() && d.Name() == "module.json" {
|
||||
found = append(found, filepath.ToSlash(p))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(found) != 1 || !strings.HasSuffix(found[0], "/node-tools/module.json") {
|
||||
t.Errorf("the module manifests are %v, want node-tools' alone", found)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user