Repository navigation
v0.1.40
The reload does work under a TypeScript runner
The note added with the fix said the opposite, as measured. Re-measured
at tsx 4.7.0, 4.19.2 and 4.23.13, under tsx and tsx watch, with pages
written as .js and as .ts: importing Page.js?v=1 then Page.js?v=2 yields
two instances in every one of them, registered resolve hooks included,
and the second import sees an edited template.
The earlier reading is what a silently failed hook registration looks
like — the .js/.ts bug fixed in the same commit — and it is indeed
indistinguishable from a runner that ignores hooks. Which is why the
claim is now held up by a test that spawns a process and reads what
comes back, rather than by a comment: without the hooks the second
render still says ORIGINAL, so the assertion carries its weight.
A page reloaded; what it imported did not
Pages.resolve busts the ESM cache for a page with its own mtime, and its
comment says why: Node keys modules by URL, so a stable one freezes the
first-imported version for the process lifetime. That is right, and it
covers exactly one file. A page's layout, its organisms and the services it
pulls in resolve relative to that URL and come out without a query — onto
stable URLs already in the cache. Editing a page therefore reloaded and
editing a template did not, which from the outside reads as the server
caching files rather than as a module registry doing its job.
Two halves, neither of which works alone. The page's token becomes the
newest mtime anywhere under the pages root, so any edit in the tree gives
it a new key; and a resolution hook stamps each import under that root with
its own mtime, so the re-imported page gets fresh children — only the ones
that actually changed, since an untouched module keeps its key.
An already-versioned URL is left alone by the hook. Re-stamping the page
with its own mtime is precisely the bug, reintroduced one level up.
Measured while building it, and it bounds what this can do: the whole
approach rests on Node keying modules by full URL. Under plain Node it
does — two tokens, two instances, the second sees the edit. Under tsx it
does not: the query is normalised away, both imports return the same
instance, and a registered resolve hook never sees a relative specifier. So
under a TypeScript runner nothing here applies, including the page-level
busting that predates it, and the only reload left is restarting the
process. That belongs to a watcher, and a dev script should watch the page
sources as well as the server's own.
The registration reports a failure instead of swallowing it. The first
version caught everything and said nothing, so ERR_MODULE_NOT_FOUND on a
hooks file that ships as .js and lives as .ts produced no symptom
except templates going on not reloading — this bug, one level up again.
Both extensions are now tried.
Declare the Node floor this package already has
24 of the cohort's packages declared engines.node >=22.0.0 and 8 did
not. Seven of the eight depend on @c9up/ream, which declares it, so
their real floor was already 22 -- just invisible to npm. helix is
standalone but its CI builds and tests on Node 22 only.
Undeclared, a Node 20 install succeeds without a word and the failure
arrives later as a runtime error far from its cause.
Give every aurora error a code
aurora threw plain Errors everywhere, so the only way to branch on a
failure was to match its message -- prose, free to change. The cohort
shape is E__; inker, eclipse, blackhole and prism
already carry it, aurora and rosetta did not.
AuroraError extends Error with a typed code and standard ErrorOptions,
so cause passes through. All twelve throw sites converted, messages
unchanged, and the class is exported from both barrels -- a caller can
now catch every aurora failure by one name. The module has no Node
imports, so the browser barrel stays node-free.
Upstream shape, read from the tarballs rather than recalled: Edge's
loader discriminates on a filesystem fact (error.code === 'ENOENT')
and names the path; @adonisjs/core wraps with a message about the
operation and keeps { cause }, both in configure.js and codemods.js.
Report why a page import failed, not that the page is missing
Pages.resolve() reported every import failure as "page not found",
against the page's own path. A page's module graph fails for reasons
that say nothing about whether the page is there: a syntax error
anywhere in the graph, a throw at module top level, an export missing
from a transitively imported module. The message asserted a false
cause, pointed at the one file certain to be present, and named the
real culprit only at the end of the sentence. It also flattened the
original error into a string, losing the stack.
The page's presence is now answered from the filesystem rather than
from the error text. Node raises ERR_MODULE_NOT_FOUND for a missing
specifier anywhere in the graph and names the page in both cases --
as the missing module when it is the page, as the IMPORTER when a
transitive is missing -- so a substring test mis-sorts the second.
Under a loader that is not plain Node the text differs entirely.
A missing export in dev also carries the reason it can be on disk and
absent from the loaded module at once: only the page URL is
cache-busted, so an edited module it imports stays frozen in the ESM
cache. The docs already covered the hot-hook fix; they now name the
symptom that leads there.
Keep the dev-dependency alignment, drop the workspace: protocol
The internal ranges had been rewritten to workspace:^. That resolves inside
this monorepo and nowhere else: every package CI checks out its own repository
alone and runs pnpm install, where the protocol has no workspace to point at
and fails with ERR_PNPM_WORKSPACE_PKG_NOT_FOUND before a single test runs. The
concrete ranges are back; the dev-dependency bumps that came with the same edit
are kept, and now match what the lockfile already resolved.
Changes since v0.1.39.