Releases: arkstack-hq/arkstack
0.16.0
What's New
Inertia for create-arkstack
Scaffold an Inertia app on any runtime — no per-combination templates.
- New InertiaStack step in the wizard (
None / React / Vue / Svelte):
Runtime → Lean/Full → Name → Description → Location → InertiaStack → Alpha.
Also available as--s|stack <none|react|vue|svelte>. - The chosen runtime (Express or H3) is layered with Inertia automatically —
everythingark publish --package @arkstack/inertiadoes, plus the wiring it
leaves to you, with no extra prompts: adapter config, root Edge template,
stylesheet, Vite client types, the framework client entry /vite.config.ts/
Pages/Index.*, the required dependencies,dev:client/build:client
scripts, theinertia()middleware (afterresora()), the root route, and
tsconfig.json(JSX for React,include: resources). - Fixed: dependency auto-install ran in the CLI's working directory instead
of the new project, sonode_modulesnever landed in the scaffold. - Resilience: the generated root template is normalized to guarantee the
React@viteReactRefreshpreamble and the correct client-entry extension
(app.tsx), even when the downloaded stub predates them.
@arkstack/inertia
- First-class client scaffolding publishable via
ark publish— React, Vue,
and Svelte stubs (client entry,vite.config.ts,Pages/Index.*,
vite-env.d.ts), an adapter config, a styled root template, and a starter
app.css. - Hydration-safe page payload: the initial page object is now emitted as a
JSON<script>element rather than adata-pageattribute. appNameshared on every page fromconfig('app.name')— without
clobbering an explicitly shared value or adding an empty key when no app config
is loaded.
@arkstack/view
- New
@viteReactRefreshEdge tag (andviteReactRefresh()helper): emits
the React Refresh preamble in development, nothing in production. Required with
@vitejs/plugin-reactwhen Edge renders the page — otherwise React throws
"can't detect preamble." Place it immediately before@vite.
Interactive publish confirmations (@arkstack/console + @arkstack/common)
- Packages can now drive what and how they publish via
Publisher.confirm():
prompt the user to pick an option, gate tags behind that choice, and transform
each published stub through a callback. ark publishhonors--tag(bypasses the prompt, still applies the callback)
and--no-interaction(skips prompts; gated tags stay unpublished).
Optional arkormx
@arkstack/common,@arkstack/console, and@arkstack/httpnow load without
arkormxinstalled (marked an optional peer dependency) —prepareno longer
fails in production deployments that don't use the ORM.
Templates & tooling
- New
express-inertiareference template; Express/H3 templates and tsdown
configs updated. - Test harness exposes a deterministic
config()global (testsSetup.ts) so
config-dependent code is testable.
Full Changelog: 0.15.3...0.16.0
0.15.3
Edge tags: @vite, @inertia, @inertiaHead
Cleaner root templates — no more manual <script> wiring or {{{ ... }}}
interpolations for Inertia and Vite assets.
@arkstack/view — @vite(...)
A first-class Vite asset tag:
@vite('resources/js/app.ts')
@vite(['resources/css/app.css', 'resources/js/app.ts'])- Development: emits the Vite dev-server client + module scripts.
- Production: reads
public/build/.vite/manifest.jsonand emits the hashed<script>/<link>tags, including a chunk's imported CSS. Throws a clear error if the manifest or an entry is missing. - Configurable via
VITE_DEV_URL(dev server) and the exportedviteTags(entries, options)helper (hot/devUrl/manifest/buildDir). Registered on every view factory. - Register your own tags too:
view().tag(name, block, seekable, compile).
@arkstack/inertia — @inertia and @inertiaHead
The root template now reads:
<head>
@inertiaHead
@vite('resources/js/app.ts')
</head>
<body>
@inertia
</body>@inertia— the mount element (or server-rendered markup with SSR).@inertiaHead— SSR head tags (empty without SSR).
Both fall back to empty output when absent (no strayundefined), and the publishedapp.edgestub uses them out of the box.
Compatibility
Backward compatible: the adapter still passes inertia / inertiaHead data, so
existing templates using {{{ inertia }}} keep working.
Note: Edge tags are line-level — put
@inertia,@inertiaHead, and@vite(...)each on their own line.
Full Changelog: 0.15.1...0.15.3
0.15.1
What's New
ark dev — local network & HTTPS
The development server gains two flags for testing on real devices and over
secure connections.
Highlights
--hostexpose the dev server on your local network. The dev server
now binds127.0.0.1by default (local-only);--hostswitches it to
0.0.0.0and prints the detected LAN URL alongside the local one, so you can
open the app from your phone or another machine.--s|secureserves the dev server over HTTPS using an auto-generated,
in-memory self-signed certificate (no setup; browsers show the usual
self-signed warning).- Both compose with the existing
--t|tunnel(Ngrok) flag.
Examples
ark dev # http://127.0.0.1:3000 (local only)
ark dev --host # + Network: http://192.168.1.20:3000
ark dev --secure # https://127.0.0.1:3000 (self-signed)
ark dev --host --secure # HTTPS, exposed on the LANFull Changelog: 0.15.0...0.15.1
0.15.0
What's New
@arkstack/inertia — Server-side rendering
The Inertia adapter now supports SSR, so the initial page load is fully
rendered HTML (great for first paint and crawlers) and the client hydrates it.
Subsequent Inertia visits stay client-side.
Highlights
- SSR rendering — when
ssr.enabled, the initial visit is rendered by an
external Node SSR server (your built SSR bundle); the markup and head tags are
embedded in the response. If the SSR server is unreachable, the adapter falls
back to client-side rendering, so SSR can never take a request down. ark inertia:ssr— a new command that runs and supervises the SSR bundle,
restarting it if it crashes (--bundle <path>,--no-restart). Auto-discovered
like other package commands.Inertia.configure({ ... })— override Inertia config at runtime (e.g.
enable SSR programmatically); handy for tests and custom setups.- New config —
ssr.url(render endpoint, defaulthttp://127.0.0.1:13714/render)
andssr.bundle(defaultdist-ssr/ssr.js). - Exports —
renderViaSsr(),superviseProcess(),resolveSsrBundle(),
DEFAULT_SSR_URL,DEFAULT_SSR_BUNDLE, plusSsrResponse/SuperviseOptionstypes.
Setup
- Add an SSR entry (
src/ssr.ts) using your client adapter's server renderer. - Build it:
vite build --ssr src/ssr.ts --outDir dist-ssr. - Run it:
ark inertia:ssr. - Enable it: set
ssr.enabled(orINERTIA_SSR=true) insrc/config/inertia.ts.
Verified
SSR shipped with 8 unit tests (markup/head injection, fallbacks) plus a real
browser E2E (Vue 3 SSR server + hydration, no full reload). The inertia:ssr
command adds 8 more tests — real-process restart/stop/failure coverage — and a
smoke test supervising the live SSR bundle (health → crash → restart → health →
clean stop).
See the Inertia guide.
Full Changelog: 0.14.22...0.15.0
0.14.22
What's new
Custom error response bodies (@arkstack/common)
AppException (and any subclass) can now define a body property that is merged
into the serialized error payload. This lets you extend the framework's standard
error shape — { status, code, message, errors?, stack? } — with your own fields,
or override the defaults entirely.
import { AppException } from '@arkstack/common'
class PaymentException extends AppException {
body = { error_code: 'PAYMENT_FAILED', retryable: true }
}
throw new PaymentException('Payment failed', 402)
// → { status: 'error', code: 402, message: 'Payment failed',
// error_code: 'PAYMENT_FAILED', retryable: true }
**Full Changelog**: https://github.com/arkstack-hq/arkstack/compare/0.14.19...0.14.220.14.19: fix(common): fall back to the alternate build output when loading config
What's Changed
Features
- Typed
env()return values. Added an augmentableEnvRegistryinterface mapping known environment variables to their coerced types, withenv()(andEnvLoader.get()) inferring returns from it:- Known keys infer their type,
env('APP_PORT')→number,env('NODE_ENV')→'development' | 'production' | 'test',env('MAIL_SECURE')→boolean. - Unknown keys fall back to
string; a provided default is unioned into the result. - An explicit value type still wins (
env<boolean>('FLAG')), and applications can extendEnvRegistryvia declaration merging. - New exported helper types:
EnvRegistry,EnvKey,EnvLookup,EnvReturn.
- Known keys infer their type,
- Auto-generated env types.
prepare/build now generates anEnvRegistryaugmentation from the application's.env.example(falling back to.env) into.arkstack/ark.d.ts, mirroring config-interface generation. Each variable's type is inferred (number / boolean / string), and framework-owned keys are skipped so the generated declaration never conflicts with the curated baseline, your app-specific variables get types automatically. Exposed viaBuildInterfaces.env()and the pureBuildInterfaces.envRegistryFromEnv().
Fixes
- Environment loading is no longer import-order dependent.
.envis now loaded lazily on the firstenv()read instead of relying on a side-effectimport 'dotenv/config'. Linters/bundlers that reorder imports could previously place an env-reading module before dotenv populatedprocess.env, leaving it with default/stale values. (dotenv is loaded with{ quiet: true }and never overrides already-set variables.) - No duplicate
export {}in generated.arkstack/ark.d.ts. The env-registry block no longer emits its own module marker; the generator ensures the combined declaration file has exactly one.
Refactor
EnvLoaderandConfigLoaderclasses. Environment and configuration handling were extracted fromsystem.tsinto dedicatedEnvLoaderandConfigLoaderclasses (new exports, with sharedenvLoader/configLoadersingletons).env()andconfig()now delegate to these instances; their call signatures and return values are unchanged.- Dropped now-redundant explicit generics at call sites that pass a default (
NODE_ENV,TUNNEL,SESSION_LIFETIME) so they infer fromEnvRegistry, and coercedappUrl's numeric port forurl.port.
Internal
- Added
dotenvas a direct dependency of@arkstack/common. - New tests:
EnvLoadercoercion and the env-registry generator.
Full Changelog: 0.14.17...0.14.19
0.14.17
What's Changed
Features
- Production module resolution. Application modules — models, route groups, and console commands — now resolve from the compiled build output (
dist) in production and from TypeScript source in development. A production deploy can ship onlydist(nosrc); the build strips the leadingsrc/segment (src/app/models/User.ts→dist/app/models/User.js) and the framework remaps paths accordingly.- New
@arkstack/commonhelpers:resolveRuntimeModule(sourcePath)— resolves a source module path to an importable file (source in dev, compiled output in prod), choosing the correct extension.resolveRuntimeDir(sourcePath)— directory counterpart of the above, for resolving source directories (e.g.src/routes) to their runtime location.toOutputPath(sourcePath)— pure path transform mapping a source path to its build-output counterpart.
getModel(), console command discovery, and the Express/H3 route-group loaders now use these resolvers, fixing failures in production deploys that previously reached forsrc/files at runtime.
- New
Docs
- New Deployment guide covering build output,
NODE_ENV, output directories, and the runtime resolution helpers.
Requires
NODE_ENV=productionin production (the same assumption the config loader already makes).
Full Changelog: 0.14.16...0.14.17
0.14.16
What's Changed
Fixes
- Production module resolution. The framework no longer reaches for
src/files at runtime in production. Models, console commands, and route groups now resolve from the build output (dist) when running compiled, falling back to source in development. Previously a production deploy that shipped onlydistcould fail to load models (getModel) and route groups because the loaders importedsrc/...paths directly, even though the build strips thesrc/segment (src/app/models/User.ts→dist/app/models/User.js).- New
resolveRuntimeModule()/toOutputPath()helpers in@arkstack/commonmap a source path to its compiled counterpart and pick the right file per environment (production prefersdist, development prefers source). getModel()resolves the configured model path through the new resolver.discoverCommands()orders its candidate directories by environment instead of always preferringsrc.- The Express and H3 drivers resolve
routes/apiandroutes/webroute groups through the resolver instead of joiningsrc/routes/*directly.
- New
Note: this relies on
NODE_ENV=productionbeing set in production (the same assumption the config loader already makes).
Full Changelog: 0.14.15...0.14.16
0.14.15
What's Changed
- Replace the --ignore flag with the global --no-interation flag KeyGenerateCommand
Full Changelog: 0.14.14...0.14.15
0.14.14
What's Changed
- Add
--ignoreoption to silently skip app key generation in KeyGenerateCommand
Full Changelog: 0.14.3...0.14.14