Skip to content

v1.5.0

Choose a tag to compare

@7nohe 7nohe released this 26 Jul 04:25
db50a27

The largest release since 1.0: three RFCs land complete, make:auth grows from a login form into a full authentication stack, and Guren gains a first-class Cloudflare Workers target.

About the tag. vX.Y.Z has historically tracked @guren/server, which moves to 1.4.0 here — but v1.4.0 is already taken by the previous cli-led release, so this tag advances to the next unused number. Tag names are organizational and do not correspond 1:1 to any single package's version.

Packages

Package Version
@guren/server 1.3.0 → 1.4.0
@guren/cli 1.4.0 → 1.5.0
@guren/core 1.2.0 → 1.3.0
@guren/orm 1.1.0 → 1.2.0
@guren/testing 1.1.0 → 1.2.0
create-guren-app 1.2.0 → 1.3.0
@guren/plugin-vercel 0.1.2 → 0.2.0
@guren/plugin-cloudflare — → 0.2.0 (first release)

@guren/inertia-client and @guren/openapi are unchanged.

Application modules and architecture boundaries (RFC 0002)

An app no longer has to grow as one flat app/, routes/, and db/schema.ts. modules/<name>/ is now a recognized convention: defineModule() declares a module's routes and providers, guren make:module <name> scaffolds and wires one up, and most make:* generators take --module <name> to scaffold inside it.

The whole toolchain is module-aware — check, audit, context, model:list, doctor, codegen, openapi:generate, and route:list all see routes registered in a module's own routes.ts. Once any modules/ directory exists, guren check derives boundary rules with no configuration and flags cross-module imports that reach past a module's public surface.

For apps that want explicit layering, guren check also enforces a hand-written guren.arch.ts. Two flags support agent edit hooks and large repos: --arch runs only the boundary checks, and --changed restricts any check to files changed against the merge base with main.

Serverless and Cloudflare Workers (RFC 0003)

@guren/plugin-cloudflare is new. createWorkersHandler(app) wraps an Application in a Workers module handler with lazy, deduplicated boot on the first request, and guren cloudflare:build assembles a deployable .cloudflare/ directory — built SSR bundle, static assets, and a wrangler.jsonc scaffold with a D1 binding and the drizzle migrations directory.

createD1Database joins the postgres/mysql/sqlite factories. D1 speaks the SQLite dialect, so existing SQLite schemas port unchanged. Migration commands deliberately throw with guidance instead of executing — wrangler owns the D1 migration lifecycle.

DatabaseSessionStore and DatabaseOAuthStateStore make Redis optional on serverless. Sessions are strongly consistent, so login → redirect → read works, and OAuth state survives the callback landing on a different instance than the authorize request.

CSRF moved out of the session into signed tokens, and session writes dropped sharply: empty anonymous sessions are no longer persisted, flash aging only dirties sessions that carried flash data, and stores can implement touch() so rolling expiry is a TTL refresh rather than a full rewrite. This matters wherever writes are metered — D1's free tier allows 100k row writes/day, and previously every page view consumed one.

guren.dev itself now runs on this stack.

Authentication scaffolding

guren make:auth went from a login form to a complete stack:

  • --registration — registration flow with password confirmation
  • password reset (ForgotPasswordController, ResetPasswordController)
  • --verify — email verification
  • --oauth <providers> — OAuth login buttons for a comma-separated provider list
  • --oauth-only — OAuth as the app's sole sign-in method, with genuinely passwordless accounts

Several correctness fixes came out of adopting the full stack in a real application: OAuth accounts are no longer created from unverified email addresses, --verify --oauth marks verified providers' accounts verified at creation, and the scaffolded profile form no longer lets an account replace the email its identity is keyed on. OAuthUserProfile gains emailVerified so providers can report verification separately from the address, and OAuthProviderConfig gains fetchFallbackEmail for providers whose userinfo response omits one.

Spec-anchored docs (RFC 0004)

  • guren context <Entity> joins everything the CLI knows about one model — columns, relationships, routes with validation schemas, controller actions, pages with extracted Props, resource, policy, factories, seeders, tests — into a single bundle, also exposed over MCP.
  • Doc–code linking — markdown under docs/ declares entities and related in frontmatter, code declares @docs JSDoc tags, and guren check --docs validates the links. make:adr scaffolds numbered ADRs with prefilled frontmatter.
  • Derived spec views with a drift gateguren spec:generate writes committed ER/domain/screen/module views, and guren check --spec fails when they drift from the code.

Developer experience

dev:server now runs under bun --hot in both templates, so controller, route, and model edits take effect on the next request without a restart. Two leaks that only surface under hot reload were fixed along the way: database connections accumulating one per reload, and interval timers surviving reevaluation.

setInertiaDocument() lets an app configure the server-rendered document's body class, critical CSS, and prepaint script instead of relying on a hardcoded Docs/* special case — the fix for pages flashing the wrong surface color before hydration.

Breaking changes

@guren/plugin-vercel (0.x) — the provider export changed from the GurenPluginVercelProvider class to a vercelPlugin() factory, matching definePlugin(). Update your createApp({ providers }) entry accordingly.

Behavior changes worth checking

  • Anonymous visitors no longer receive a session cookie unconditionally. A session and its cookie now appear the moment something is stored. With the default auth stack that is the first CSRF-protected page, so most apps see no difference — but an app that depended on every visitor having a session cookie will.
  • The Docs/* Inertia document special case is gone. No scaffold or template ever emitted a page component under that name, so nothing should need migrating.

What's Changed

  • feat(cli): generate destroy action in make:feature by @7nohe in #138
  • feat(cli): support ignoring route/model audit findings via config by @7nohe in #137
  • RFC: Application modules and architecture boundary checking by @7nohe in #139
  • feat(cli): add registration scaffold to make:auth by @7nohe in #141
  • feat(cli): add architecture boundary checking via guren check --arch by @7nohe in #140
  • feat(cli): add password reset flow to make:auth by @7nohe in #142
  • feat(server,cli): application modules (RFC 0002 Part 2) by @7nohe in #144
  • chore: add changesets for RFC 0002 (arch boundary checking + modules) by @7nohe in #146
  • docs: remove internal jargon leaked into user-facing guides by @7nohe in #147
  • feat(cli): add email verification to make:auth --verify by @7nohe in #143
  • feat(cli): add OAuth login buttons to make:auth --oauth by @7nohe in #145
  • chore: switch site URL to guren.dev by @7nohe in #148
  • docs: RFC 0003 — Cloudflare Workers adapter (@guren/plugin-cloudflare) by @7nohe in #150
  • feat: add @guren/plugin-cloudflare Workers adapter (RFC 0003 Part 1) by @7nohe in #151
  • feat(orm): add createD1Database for Cloudflare D1 (RFC 0003 Part 2) by @7nohe in #152
  • feat(examples): adopt full make:auth stack in blog example by @7nohe in #149
  • refactor!: expose vercelPlugin() via definePlugin instead of a class provider by @7nohe in #153
  • feat(core): add DatabaseSessionStore and DatabaseOAuthStateStore (RFC 0003 Part 3a) by @7nohe in #154
  • feat(server): stop persisting sessions on every request (RFC 0003 Part 3b) by @7nohe in #155
  • fix(server): make OAuth state consumption atomic by @7nohe in #156
  • docs: add RFC 0004 spec-anchored development by @7nohe in #157
  • feat(server): stateless signed double-submit CSRF tokens (RFC 0003 Part 3c) by @7nohe in #158
  • feat(cli): scaffold passwordless OAuth accounts in make:auth --oauth (RFC 0003 Part 3d) by @7nohe in #159
  • feat(cli): entity-centric context bundles (RFC 0004 Part 1) by @7nohe in #160
  • feat(cli): add make:auth --oauth-only for passwordless scaffolds by @7nohe in #162
  • feat(docs): add favicon and X social link to homepage by @7nohe in #164
  • docs(cli): document that the routes cache-buster is inert on Bun by @7nohe in #165
  • docs: correct backend hot-reload claim in dev server docs by @7nohe in #167
  • feat(server): add OAuth --oauth-only scaffold and email verification signal by @7nohe in #168
  • fix(cli): keep OAuth accounts on their provider-vouched email by @7nohe in #166
  • feat(cli): doc-code linking (RFC 0004 Part 2) by @7nohe in #163
  • fix(cli): fix false positives in guren check's controller-test detection by @7nohe in #161
  • fix(cli): make generated-file writes idempotent by @7nohe in #169
  • fix(cli): stop MCP context tools from serving stale routes by @7nohe in #170
  • fix(orm): close leaked database connections under bun --hot by @7nohe in #173
  • fix(plugin-cloudflare): close the gaps a real app hits on Workers by @7nohe in #171
  • feat(cli): derived spec views with drift gate (RFC 0004 Part 3) by @7nohe in #172
  • feat(cli): scaffold and harness support for docs/spec conventions (RFC 0004 Part 4) by @7nohe in #175
  • fix(server): unblock the dev-only MCP endpoint from CSRF by @7nohe in #176
  • docs: introduce the spec-anchored development principle site-wide by @7nohe in #177
  • docs: close RFC 0004 open questions with implementation resolutions by @7nohe in #178
  • feat(web): run guren.dev on Cloudflare Workers with a Guren-built blog by @7nohe in #174
  • fix(server): make guren_codegen regenerate changed artifacts by @7nohe in #179
  • feat(create-app): reload backend changes without restarting the dev server by @7nohe in #180
  • docs: record stale dist as a silent test-failure mode by @7nohe in #181
  • fix(server): stop interval timers leaked across hot reloads by @7nohe in #182
  • fix(orm): keep spaces and parentheses in the hot-reload caller path by @7nohe in #183
  • fix: keep a single ORM copy in the Workers bundle by @7nohe in #184
  • chore(web): serve the site at guren.dev by @7nohe in #185
  • chore(web): retire the Vercel deployment by @7nohe in #186
  • docs(examples): add Vercel and Cloudflare deploy recipes, and audit the Vercel build by @7nohe in #187
  • fix(server): let apps configure the Inertia document instead of hardcoding a Docs/ prefix by @7nohe in #188
  • fix(plugin-vercel): route the asset base onto the output root by @7nohe in #189
  • chore: version packages for v1.5.0 by @7nohe in #190

Full Changelog: v1.4.0...v1.5.0