@mars-stack/cli 8.0.7 → 8.0.9

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": "@mars-stack/cli",
3
- "version": "8.0.7",
3
+ "version": "8.0.9",
4
4
  "description": "MARS CLI: scaffold, configure, and maintain SaaS apps",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -9,7 +9,7 @@ alwaysApply: true
9
9
  - Every API route under `src/app/api/protected/` MUST use `withAuth`, `withAuthNoParams`, `withRole`, or `withOwnership` from `@/lib/mars`.
10
10
  - Admin-only routes MUST use `withRole(['admin'], ...)` which verifies the role against the database on every request. Never trust the JWT role claim alone.
11
11
  - Ownership-gated routes MUST use `withOwnership`. Never accept a `userId` parameter from the client for authorization.
12
- - Public auth endpoints (`login`, `signup`, `forgot`, `reset`, `verify`) MUST call `checkRateLimit` with the appropriate `RATE_LIMITS` config from `@mars-stack/core/rate-limit`.
12
+ - Public auth endpoints (`login`, `signup`, `forgot`, `reset`, `verify`, `me`, `logout`) MUST call `checkRateLimit` with the appropriate `RATE_LIMITS` config from `@mars-stack/core/rate-limit`.
13
13
 
14
14
  ## Secrets
15
15
 
@@ -7,6 +7,9 @@ import { defineConfig, devices } from '@playwright/test';
7
7
  export default defineConfig({
8
8
  testDir: '.',
9
9
  testMatch: 'kitchen-sink-catalog.spec.ts',
10
+ // Scaffold copies template/e2e-kitchen-sink/ into the project; the runner also copies this
11
+ // spec to the repo root — without ignore, Playwright discovers the same tests twice (CI timeout).
12
+ testIgnore: '**/e2e-kitchen-sink/**',
10
13
  fullyParallel: false,
11
14
  forbidOnly: !!process.env.CI,
12
15
  retries: process.env.CI ? 2 : 0,
@@ -1,4 +1,7 @@
1
- import { PrismaClient } from '../prisma/generated/prisma/client.js';
1
+ // Relative import: `prisma db seed` runs this file with `tsx`. The `@db` tsconfig alias
2
+ // is not a valid Node package name (ERR_INVALID_MODULE_SPECIFIER). Omit `.js` so tsx
3
+ // resolves Prisma’s emitted `client.ts` (there is no standalone `client.js` on disk).
4
+ import { PrismaClient } from '../prisma/generated/prisma/client';
2
5
  import { PrismaPg } from '@prisma/adapter-pg';
3
6
  import { hashPassword } from '@mars-stack/core/auth/password-hash';
4
7
 
@@ -1,8 +1,15 @@
1
- import { deleteSession, getSession } from '@/lib/mars';
1
+ import 'server-only';
2
+
3
+ import { deleteSession, getSession, handleApiError } from '@/lib/mars';
4
+ import { checkRateLimit, getClientIP, RATE_LIMITS, rateLimitResponse } from '@mars-stack/core/rate-limit';
2
5
  import { revokeAllSessionsForUser } from '@/features/auth/server/sessions';
3
6
  import { NextResponse } from 'next/server';
4
7
 
5
- export async function POST() {
8
+ export async function POST(request: Request) {
9
+ const ip = getClientIP(request);
10
+ const rateLimit = await checkRateLimit(ip, RATE_LIMITS.logout);
11
+ if (!rateLimit.success) return rateLimitResponse(rateLimit.resetAt);
12
+
6
13
  try {
7
14
  const session = await getSession();
8
15
 
@@ -13,7 +20,6 @@ export async function POST() {
13
20
  await deleteSession();
14
21
  return NextResponse.json({ message: 'Logout successful' }, { status: 200 });
15
22
  } catch (error) {
16
- console.error('Logout error:', error);
17
- return NextResponse.json({ error: 'An error occurred during logout' }, { status: 500 });
23
+ return handleApiError(error, { endpoint: '/api/auth/logout' });
18
24
  }
19
25
  }
@@ -1,7 +1,14 @@
1
+ import 'server-only';
2
+
1
3
  import { handleApiError, getSession } from '@/lib/mars';
4
+ import { checkRateLimit, getClientIP, RATE_LIMITS, rateLimitResponse } from '@mars-stack/core/rate-limit';
2
5
  import { NextResponse } from 'next/server';
3
6
 
4
- export async function GET() {
7
+ export async function GET(request: Request) {
8
+ const ip = getClientIP(request);
9
+ const rateLimit = await checkRateLimit(ip, RATE_LIMITS.sessionMe);
10
+ if (!rateLimit.success) return rateLimitResponse(rateLimit.resetAt);
11
+
5
12
  try {
6
13
  const session = await getSession();
7
14