From 4975b98bc3f42fa2aecaa73d4d541f7743fa9c45 Mon Sep 17 00:00:00 2001 From: Devin Date: Thu, 8 Oct 2026 08:19:04 -0400 Subject: [PATCH] fix(generate): drop the generation timestamp from guard templates auth.guard.ts and guards.module.ts rendered "Generated at: ", so apso generate rewrote both files on every run of an auth-enabled project, even with no schema change. Remove the line from both templates, finishing 39679b1, which dropped the same timestamp from the shared header for regen churn and PII. Stop supplying generatedAt / generatedBy too: withGeneratedMeta (added them to every render) is deleted, and generateGuards no longer sets its own copy. No other template read either field. New test generates the guards twice and expects identical output. fixes #129 --- ARCHITECTURE-BACKLOG.md | 2 +- src/lib/generators/base.ts | 4 ++-- src/lib/generators/typescript.ts | 4 +--- src/lib/templates/guards/auth.guard.eta | 1 - src/lib/templates/guards/guards.module.eta | 1 - src/lib/utils/file-system.ts | 10 ---------- test/lib/generators/typescript.test.ts | 23 ++++++++++++++++++++++ 7 files changed, 27 insertions(+), 18 deletions(-) diff --git a/ARCHITECTURE-BACKLOG.md b/ARCHITECTURE-BACKLOG.md index de5cbee..4a4b049 100644 --- a/ARCHITECTURE-BACKLOG.md +++ b/ARCHITECTURE-BACKLOG.md @@ -42,7 +42,7 @@ Three overlapping config loading strategies: `parseApsorc()` (used), `loadConfig `createDirectoryContents` and `writeFile` are holdovers from an older template system. No command calls them. `init` uses git clone, `generate` uses Eta templates. -**Fix:** Delete both functions. Keep `createFile` and `withGeneratedMeta`. +**Fix:** Delete both functions. Keep `createFile`. **Gains:** Removes dead code that suggests an alternative template mechanism exists. diff --git a/src/lib/generators/base.ts b/src/lib/generators/base.ts index 4584acc..730f87f 100644 --- a/src/lib/generators/base.ts +++ b/src/lib/generators/base.ts @@ -14,7 +14,7 @@ import { Entity, AuthConfig, } from "../types"; -import { createFile, withGeneratedMeta } from "../utils/file-system"; +import { createFile } from "../utils/file-system"; /** * Abstract base class for language-specific generators. @@ -154,7 +154,7 @@ export abstract class BaseGenerator implements LanguageGenerator { ): Promise { const content = await this.templateEngine.renderFileAsync( templatePath, - withGeneratedMeta(data) + data ); return content as string; } diff --git a/src/lib/generators/typescript.ts b/src/lib/generators/typescript.ts index 47c16b4..d993905 100644 --- a/src/lib/generators/typescript.ts +++ b/src/lib/generators/typescript.ts @@ -15,7 +15,7 @@ import { AuthConfig, Field, } from "../types"; -// Utilities available for future use: createFile, withGeneratedMeta from "../utils/file-system" +// Utilities available for future use: createFile from "../utils/file-system" import { getFieldForTemplate, typeExistsInEntity, fieldToEnumType } from "../utils/field"; import { getRelationshipForTemplate, @@ -475,8 +475,6 @@ export class TypeScriptGenerator extends BaseGenerator { const templateData = { scopedEntities, authConfig: normalizedAuth, - generatedAt: new Date().toISOString(), - generatedBy: "Apso CLI", }; // Generate auth.guard.ts if auth is configured diff --git a/src/lib/templates/guards/auth.guard.eta b/src/lib/templates/guards/auth.guard.eta index 5cd57e8..34f8651 100644 --- a/src/lib/templates/guards/auth.guard.eta +++ b/src/lib/templates/guards/auth.guard.eta @@ -2,7 +2,6 @@ * AuthGuard - Authentication guard for <%= it.authConfig.provider %> provider * * Auto-generated by Apso CLI from .apsorc auth configuration - * Generated at: <%= it.generatedAt %> * * This guard: * - Validates session tokens from cookies/headers diff --git a/src/lib/templates/guards/guards.module.eta b/src/lib/templates/guards/guards.module.eta index 96eb818..a0e00f5 100644 --- a/src/lib/templates/guards/guards.module.eta +++ b/src/lib/templates/guards/guards.module.eta @@ -33,7 +33,6 @@ import { <%= it.authConfig.accountUserEntity %> } from '../<%= it.authConfig.acc * GuardsModule provides authentication and scope-based data isolation guards. * * Auto-generated from .apsorc configuration. - * Generated at: <%= it.generatedAt %> * * Usage: * 1. Import GuardsModule in your AppModule diff --git a/src/lib/utils/file-system.ts b/src/lib/utils/file-system.ts index aad2a48..74ce166 100644 --- a/src/lib/utils/file-system.ts +++ b/src/lib/utils/file-system.ts @@ -70,13 +70,3 @@ const writeFile = ( fs.chmodSync(fileWritePath, mode); } }; - -export function withGeneratedMeta( - data: T -): T & { generatedAt: string; generatedBy: string } { - return { - ...data, - generatedAt: new Date().toISOString(), - generatedBy: process.env.USER || process.env.USERNAME || "unknown", - }; -} diff --git a/test/lib/generators/typescript.test.ts b/test/lib/generators/typescript.test.ts index 2003ecb..07f367a 100644 --- a/test/lib/generators/typescript.test.ts +++ b/test/lib/generators/typescript.test.ts @@ -509,3 +509,26 @@ describe("http controller suppression (issue #93)", () => { }); }); }); + +describe("guard regeneration (cli#129)", () => { + test("renders the same guard files when nothing changed", async () => { + const generator = new TypeScriptGenerator(createConfig([])); + const entities: Entity[] = [ + { + name: "Project", + fields: [{ name: "name", type: "text" }], + scopeBy: "workspaceId", + }, + ]; + const auth = { provider: "better-auth" as const }; + + const first = await generator.generateGuards(entities, auth); + await new Promise((resolve) => { + setTimeout(resolve, 5); + }); + const second = await generator.generateGuards(entities, auth); + + expect(first.map((f) => f.path)).toContain("guards/auth.guard.ts"); + expect(second).toEqual(first); + }); +});