@zaaxch/tailframe 4.0.5 → 4.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zaaxch/tailframe",
3
- "version": "4.0.5",
3
+ "version": "4.0.6",
4
4
  "description": "Tailframe architecture toolkit: validates the Tailframe structure, import-boundary, and file-convention contracts. The package version is the contract version.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/new.mjs CHANGED
@@ -292,7 +292,7 @@ export const env = {
292
292
  firebaseServiceAccountPath: process.env.FIREBASE_SERVICE_ACCOUNT_PATH,` : ""}
293
293
  ${postgres ? `postgresUri: process.env.POSTGRES_URI ?? "postgresql://${options.name}-app:development@localhost:5432/${databaseName}",` : `mongodbUri: process.env.MONGODB_URI ?? "mongodb://localhost:27017/?replicaSet=rs0&directConnection=true",
294
294
  mongodbDbName: process.env.MONGODB_DB_NAME ?? "${databaseName}",`}
295
- ${options.redis ? `redisUrl: process.env.REDIS_URL ?? "redis://localhost:6379",` : ""}
295
+ ${options.redis ? `redisUrl: process.env.REDIS_URL ?? "redis://localhost:6379"` : ""}
296
296
  };`);
297
297
  const databaseSource = postgres ? `import { Pool } from "pg";
298
298
  import { env } from "@/platform/config/env";
@@ -358,15 +358,36 @@ if (options.worker) add(`${svc}/src/worker.ts`, `import "reflect-metadata";\nimp
358
358
  add(`${svc}/src/modules/health/__tests__/GetHealth.test.ts`, getHealthTestSource);
359
359
  add(`${svc}/src/modules/health/__tests__/GetReadiness.test.ts`, getReadinessTestSource);
360
360
  add(`${svc}/src/__tests__/testDb.ts`, postgres ? `import { Pool } from "pg";
361
- const pool = new Pool({ connectionString: process.env.TEST_POSTGRES_URI ?? "postgresql://postgres:postgres@localhost:5433/${databaseName}_test" });
362
- export async function openTestDatabase() { await pool.query("SELECT 1"); return pool; }
363
- export async function resetTestDatabase() { await pool.query("DROP SCHEMA IF EXISTS public CASCADE; CREATE SCHEMA public"); return pool; }
364
- export async function closeTestDatabase() { await pool.end(); }
361
+ const pool = new Pool({
362
+ connectionString: process.env.TEST_POSTGRES_URI ?? "postgresql://postgres:postgres@localhost:5433/${databaseName}_test"
363
+ });
364
+ export async function openTestDatabase() {
365
+ await pool.query("SELECT 1");
366
+ return pool;
367
+ }
368
+ export async function resetTestDatabase() {
369
+ await pool.query("DROP SCHEMA IF EXISTS public CASCADE; CREATE SCHEMA public");
370
+ return pool;
371
+ }
372
+ export async function closeTestDatabase() {
373
+ await pool.end();
374
+ }
365
375
  ` : `import { MongoClient } from "mongodb";
366
- const client = new MongoClient(process.env.TEST_MONGODB_URI ?? "mongodb://localhost:27018/?replicaSet=rs0&directConnection=true");
367
- export async function openTestDatabase() { await client.connect(); return client.db(process.env.TEST_MONGODB_DB_NAME ?? "${options.name.replaceAll("-", "_")}_test"); }
368
- export async function resetTestDatabase() { const database = await openTestDatabase(); await database.dropDatabase(); return database; }
369
- export async function closeTestDatabase() { await client.close(); }
376
+ const client = new MongoClient(
377
+ process.env.TEST_MONGODB_URI ?? "mongodb://localhost:27018/?replicaSet=rs0&directConnection=true"
378
+ );
379
+ export async function openTestDatabase() {
380
+ await client.connect();
381
+ return client.db(process.env.TEST_MONGODB_DB_NAME ?? "${options.name.replaceAll("-", "_")}_test");
382
+ }
383
+ export async function resetTestDatabase() {
384
+ const database = await openTestDatabase();
385
+ await database.dropDatabase();
386
+ return database;
387
+ }
388
+ export async function closeTestDatabase() {
389
+ await client.close();
390
+ }
370
391
  `);
371
392
  add(`${svc}/docker-compose.test.yml`, postgres ? `name: ${options.name}-test
372
393
  services:
@@ -468,13 +489,20 @@ ${csrf ? `
468
489
  ` : ""}${options.ui ? `
469
490
  it("serves the production SPA without falling through for API paths", async () => {
470
491
  const app = createApplication({ production: true, publicPath: path.join(__dirname, "fixtures/public") });
471
- await request(app).get("/dashboard").expect(200).expect(({ text }) => expect(text).toContain("boundary-test-spa"));
492
+ await request(app)
493
+ .get("/dashboard")
494
+ .expect(200)
495
+ .expect(({ text }) => expect(text).toContain("boundary-test-spa"));
472
496
  await request(app).get("/api/v1/does-not-exist").expect(404);
473
- });
474
- ` : ""}
497
+ });` : ""}
475
498
  });
476
499
  `);
477
- if (options.ui) add(`${svc}/src/app/__tests__/fixtures/public/index.html`, `<!doctype html><html><body><div id="app">boundary-test-spa</div></body></html>`);
500
+ if (options.ui) add(`${svc}/src/app/__tests__/fixtures/public/index.html`, `<!doctype html>
501
+ <html>
502
+ <body>
503
+ <div id="app">boundary-test-spa</div>
504
+ </body>
505
+ </html>`);
478
506
  add(`${svc}/AGENTS.md`, `# ${title} service guidance
479
507
 
480
508
  ## Scope
@@ -659,8 +687,22 @@ import NotificationHost from "@/app/components/NotificationHost.vue";
659
687
  </script>`);
660
688
  add(`${ui}/src/app/startApplication.ts`, `import { createApp } from "vue";\nimport { createPinia } from "pinia";\nimport PrimeVue from "primevue/config";\nimport App from "@/app/App.vue";\n${options.auth === "firebase" ? 'import { configureHttp } from "@/app/configureHttp";\n' : ""}import router from "@/app/router";\nimport "@/app/styles.css";\nexport function startApplication() {\n\tconst app = createApp(App);\n\tconst pinia = createPinia();\n\tapp.use(pinia).use(PrimeVue).use(router);\n\t${options.auth === "firebase" ? "configureHttp(pinia);\n\t" : ""}app.mount("#app");\n}\n`);
661
689
  add(`${ui}/src/main.ts`, `import { startApplication } from "@/app/startApplication";\nstartApplication();\n`);
662
- add(`${ui}/src/app/styles.css`, `@import "tailwindcss";\n:root { font-family: Inter, ui-sans-serif, system-ui; color: #17221c; background: #f5f3ec; }\nbody { margin: 0; }`);
663
- add(`${ui}/src/app/__tests__/App.spec.ts`, `import { mount } from "@vue/test-utils";\nimport App from "@/app/App.vue";\ndescribe("App", () => { it("renders a router view", () => { expect(mount(App, { global: { stubs: ["RouterView", "NotificationHost"] } }).exists()).toBe(true); }); });`);
690
+ add(`${ui}/src/app/styles.css`, `@import "tailwindcss";
691
+ :root {
692
+ font-family: Inter, ui-sans-serif, system-ui;
693
+ color: #17221c;
694
+ background: #f5f3ec;
695
+ }
696
+ body {
697
+ margin: 0;
698
+ }`);
699
+ add(`${ui}/src/app/__tests__/App.spec.ts`, `import { mount } from "@vue/test-utils";
700
+ import App from "@/app/App.vue";
701
+ describe("App", () => {
702
+ it("renders a router view", () => {
703
+ expect(mount(App, { global: { stubs: ["RouterView", "NotificationHost"] } }).exists()).toBe(true);
704
+ });
705
+ });`);
664
706
  add(`${ui}/AGENTS.md`, `# ${title} UI guidance
665
707
 
666
708
  ## Scope
@@ -80,7 +80,10 @@ const errorTranslationTestSource = `import { AppError, type FailureKind } from "
80
80
  import { errorHandler } from "@/platform/http/errors";
81
81
  import { logger } from "@/platform/logging/logger";
82
82
 
83
- jest.mock("@/platform/logging/logger", () => ({ logger: { log: jest.fn() }, serializeError: (error: unknown) => error }));
83
+ jest.mock("@/platform/logging/logger", () => ({
84
+ logger: { log: jest.fn() },
85
+ serializeError: (error: unknown) => error
86
+ }));
84
87
 
85
88
  const log = logger.log as jest.MockedFunction<typeof logger.log>;
86
89
 
@@ -104,13 +107,15 @@ it.each(statuses)("translates %s to HTTP %i", (kind, status) => {
104
107
  errorHandler(new AppError({ code: "CODE", message: "message", kind }), request, response, jest.fn());
105
108
  expect((response as { status: jest.Mock }).status).toHaveBeenCalledWith(status);
106
109
  expect(json).toHaveBeenCalledWith({ error: { code: "CODE", message: "message" } });
107
- expect(log).toHaveBeenCalledWith(expect.objectContaining({
108
- level: status >= 500 ? "error" : "warn",
109
- event: "http.request.failed",
110
- requestId: "request-1",
111
- code: "CODE",
112
- kind
113
- }));
110
+ expect(log).toHaveBeenCalledWith(
111
+ expect.objectContaining({
112
+ level: status >= 500 ? "error" : "warn",
113
+ event: "http.request.failed",
114
+ requestId: "request-1",
115
+ code: "CODE",
116
+ kind
117
+ })
118
+ );
114
119
  });
115
120
 
116
121
  it("logs an unknown failure without exposing it to the client", () => {
@@ -120,11 +125,13 @@ it("logs an unknown failure without exposing it to the client", () => {
120
125
  const error = new Error("database disconnected");
121
126
  errorHandler(error, { method: "POST", path: "/health.get" } as never, response, jest.fn());
122
127
  expect(json).toHaveBeenCalledWith({ error: { code: "INTERNAL", message: "Internal server error" } });
123
- expect(log).toHaveBeenCalledWith(expect.objectContaining({
124
- level: "error",
125
- code: "INTERNAL",
126
- error: expect.objectContaining({ message: "database disconnected" })
127
- }));
128
+ expect(log).toHaveBeenCalledWith(
129
+ expect.objectContaining({
130
+ level: "error",
131
+ code: "INTERNAL",
132
+ error: expect.objectContaining({ message: "database disconnected" })
133
+ })
134
+ );
128
135
  });
129
136
 
130
137
  it("logs a preserved application-error cause", () => {
@@ -138,9 +145,13 @@ it("logs a preserved application-error cause", () => {
138
145
  response,
139
146
  jest.fn()
140
147
  );
141
- expect(log).toHaveBeenCalledWith(expect.objectContaining({
142
- error: expect.objectContaining({ cause: expect.objectContaining({ message: "Firebase token verification failed" }) })
143
- }));
148
+ expect(log).toHaveBeenCalledWith(
149
+ expect.objectContaining({
150
+ error: expect.objectContaining({
151
+ cause: expect.objectContaining({ message: "Firebase token verification failed" })
152
+ })
153
+ })
154
+ );
144
155
  });
145
156
  `;
146
157
 
@@ -417,7 +417,15 @@ export function createRateLimiter(client: RedisClientType, policy: RateLimitPoli
417
417
  if (error instanceof RateLimiterRes)
418
418
  next(new AppError({ code: "RATE_LIMITED", message: "Too many requests", kind: "rate_limited" }));
419
419
  else if (error instanceof AppError) next(error);
420
- else next(new AppError({ code: "RATE_LIMIT_UNAVAILABLE", message: "Request protection unavailable", kind: "unavailable", cause: error }));
420
+ else
421
+ next(
422
+ new AppError({
423
+ code: "RATE_LIMIT_UNAVAILABLE",
424
+ message: "Request protection unavailable",
425
+ kind: "unavailable",
426
+ cause: error
427
+ })
428
+ );
421
429
  }
422
430
  };
423
431
  }
@@ -499,7 +507,12 @@ export class GetReadiness implements UseCase<Record<string, never>, ReadinessRes
499
507
  await Promise.all(this.probes.map((probe) => probe.check()));
500
508
  return { status: "ready" };
501
509
  } catch (error) {
502
- throw new AppError({ code: "NOT_READY", message: "Service is not ready", kind: "unavailable", cause: error });
510
+ throw new AppError({
511
+ code: "NOT_READY",
512
+ message: "Service is not ready",
513
+ kind: "unavailable",
514
+ cause: error
515
+ });
503
516
  }
504
517
  }
505
518
  }