@mars-stack/core 0.4.0
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/README.md +32 -0
- package/cursor/manifest.json +304 -0
- package/cursor/rules/mars-composition-patterns.mdc +186 -0
- package/cursor/rules/mars-data-access.mdc +26 -0
- package/cursor/rules/mars-project-structure.mdc +34 -0
- package/cursor/rules/mars-security.mdc +25 -0
- package/cursor/rules/mars-testing.mdc +24 -0
- package/cursor/rules/mars-ui-conventions.mdc +29 -0
- package/cursor/skills/mars-add-api-route/SKILL.md +120 -0
- package/cursor/skills/mars-add-audit-log/SKILL.md +373 -0
- package/cursor/skills/mars-add-blog/SKILL.md +447 -0
- package/cursor/skills/mars-add-command-palette/SKILL.md +438 -0
- package/cursor/skills/mars-add-component/SKILL.md +158 -0
- package/cursor/skills/mars-add-crud-routes/SKILL.md +221 -0
- package/cursor/skills/mars-add-e2e-test/SKILL.md +227 -0
- package/cursor/skills/mars-add-error-boundary/SKILL.md +472 -0
- package/cursor/skills/mars-add-feature/SKILL.md +174 -0
- package/cursor/skills/mars-add-middleware/SKILL.md +135 -0
- package/cursor/skills/mars-add-page/SKILL.md +153 -0
- package/cursor/skills/mars-add-prisma-model/SKILL.md +148 -0
- package/cursor/skills/mars-add-protected-resource/SKILL.md +192 -0
- package/cursor/skills/mars-add-role/SKILL.md +156 -0
- package/cursor/skills/mars-add-server-action/SKILL.md +167 -0
- package/cursor/skills/mars-add-webhook/SKILL.md +192 -0
- package/cursor/skills/mars-build-complete-feature/SKILL.md +228 -0
- package/cursor/skills/mars-build-dashboard/SKILL.md +211 -0
- package/cursor/skills/mars-build-data-table/SKILL.md +284 -0
- package/cursor/skills/mars-build-form/SKILL.md +229 -0
- package/cursor/skills/mars-build-landing-page/SKILL.md +248 -0
- package/cursor/skills/mars-capture-conversation-context/SKILL.md +119 -0
- package/cursor/skills/mars-configure-ai/SKILL.md +617 -0
- package/cursor/skills/mars-configure-analytics/SKILL.md +413 -0
- package/cursor/skills/mars-configure-dark-mode/SKILL.md +309 -0
- package/cursor/skills/mars-configure-email/SKILL.md +170 -0
- package/cursor/skills/mars-configure-email-verification/SKILL.md +333 -0
- package/cursor/skills/mars-configure-feature-flags/SKILL.md +361 -0
- package/cursor/skills/mars-configure-i18n/SKILL.md +518 -0
- package/cursor/skills/mars-configure-jobs/SKILL.md +500 -0
- package/cursor/skills/mars-configure-magic-links/SKILL.md +385 -0
- package/cursor/skills/mars-configure-multi-tenancy/SKILL.md +611 -0
- package/cursor/skills/mars-configure-notifications/SKILL.md +569 -0
- package/cursor/skills/mars-configure-oauth/SKILL.md +217 -0
- package/cursor/skills/mars-configure-onboarding/SKILL.md +483 -0
- package/cursor/skills/mars-configure-payments/SKILL.md +243 -0
- package/cursor/skills/mars-configure-realtime/SKILL.md +733 -0
- package/cursor/skills/mars-configure-search/SKILL.md +581 -0
- package/cursor/skills/mars-configure-storage/SKILL.md +273 -0
- package/cursor/skills/mars-configure-two-factor/SKILL.md +518 -0
- package/cursor/skills/mars-create-execution-plan/SKILL.md +204 -0
- package/cursor/skills/mars-create-seed/SKILL.md +191 -0
- package/cursor/skills/mars-deploy-to-vercel/SKILL.md +300 -0
- package/cursor/skills/mars-design-tokens/SKILL.md +138 -0
- package/cursor/skills/mars-setup-billing/SKILL.md +322 -0
- package/cursor/skills/mars-setup-project/SKILL.md +104 -0
- package/cursor/skills/mars-setup-teams/SKILL.md +688 -0
- package/cursor/skills/mars-test-api-route/SKILL.md +219 -0
- package/cursor/skills/mars-update-architecture-docs/SKILL.md +189 -0
- package/dist/api-error/index.d.ts +27 -0
- package/dist/api-error/index.d.ts.map +1 -0
- package/dist/api-error/index.js +2 -0
- package/dist/auth/credential-tag.d.ts +5 -0
- package/dist/auth/credential-tag.d.ts.map +1 -0
- package/dist/auth/credential-tag.js +2 -0
- package/dist/auth/crypto-utils.d.ts +43 -0
- package/dist/auth/crypto-utils.d.ts.map +1 -0
- package/dist/auth/crypto-utils.js +1 -0
- package/dist/auth/csrf.d.ts +32 -0
- package/dist/auth/csrf.d.ts.map +1 -0
- package/dist/auth/csrf.js +2 -0
- package/dist/auth/hooks/index.d.ts +4 -0
- package/dist/auth/hooks/index.d.ts.map +1 -0
- package/dist/auth/hooks/index.js +68 -0
- package/dist/auth/hooks/useCSRF.d.ts +7 -0
- package/dist/auth/hooks/useCSRF.d.ts.map +1 -0
- package/dist/auth/hooks/usePasswordStrength.d.ts +17 -0
- package/dist/auth/hooks/usePasswordStrength.d.ts.map +1 -0
- package/dist/auth/internal-api-key.d.ts +5 -0
- package/dist/auth/internal-api-key.d.ts.map +1 -0
- package/dist/auth/internal-api-key.js +30 -0
- package/dist/auth/link-utils.d.ts +13 -0
- package/dist/auth/link-utils.d.ts.map +1 -0
- package/dist/auth/link-utils.js +1 -0
- package/dist/auth/middleware.d.ts +56 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +3 -0
- package/dist/auth/password.d.ts +28 -0
- package/dist/auth/password.d.ts.map +1 -0
- package/dist/auth/password.js +1 -0
- package/dist/auth/reset-token.d.ts +3 -0
- package/dist/auth/reset-token.d.ts.map +1 -0
- package/dist/auth/reset-token.js +9 -0
- package/dist/auth/responses.d.ts +15 -0
- package/dist/auth/responses.d.ts.map +1 -0
- package/dist/auth/responses.js +2 -0
- package/dist/auth/session.d.ts +79 -0
- package/dist/auth/session.d.ts.map +1 -0
- package/dist/auth/session.js +1 -0
- package/dist/auth/types.d.ts +18 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +10 -0
- package/dist/auth/validation.d.ts +146 -0
- package/dist/auth/validation.d.ts.map +1 -0
- package/dist/auth/validation.js +116 -0
- package/dist/auth/validators.d.ts +4 -0
- package/dist/auth/validators.d.ts.map +1 -0
- package/dist/auth/validators.js +27 -0
- package/dist/auth/verification.d.ts +54 -0
- package/dist/auth/verification.d.ts.map +1 -0
- package/dist/auth/verification.js +39 -0
- package/dist/chunk-4LS3QDD5.js +162 -0
- package/dist/chunk-ABBUHT5Z.js +110 -0
- package/dist/chunk-CTYAVMOF.js +15 -0
- package/dist/chunk-GVLH2GQP.js +14 -0
- package/dist/chunk-HOSMMQMA.js +109 -0
- package/dist/chunk-MXQ66RUN.js +28 -0
- package/dist/chunk-PZE3JGXO.js +149 -0
- package/dist/chunk-QAH2Y5WK.js +93 -0
- package/dist/chunk-QWMN5UJC.js +76 -0
- package/dist/chunk-ROQV54MU.js +117 -0
- package/dist/chunk-U4NZQ366.js +46 -0
- package/dist/chunk-WBJOIENS.js +22 -0
- package/dist/chunk-WO6FHJHG.js +29 -0
- package/dist/chunk-Z5BEKPJI.js +96 -0
- package/dist/chunk-ZA46T6GX.js +24 -0
- package/dist/configure-mars.d.ts +104 -0
- package/dist/configure-mars.d.ts.map +1 -0
- package/dist/database/index.d.ts +8 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +1 -0
- package/dist/email/index.d.ts +25 -0
- package/dist/email/index.d.ts.map +1 -0
- package/dist/email/index.js +2 -0
- package/dist/email/types.d.ts +18 -0
- package/dist/email/types.d.ts.map +1 -0
- package/dist/env/index.d.ts +36 -0
- package/dist/env/index.d.ts.map +1 -0
- package/dist/env/index.js +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +163 -0
- package/dist/logger/index.d.ts +80 -0
- package/dist/logger/index.d.ts.map +1 -0
- package/dist/logger/index.js +1 -0
- package/dist/payments/index.d.ts +53 -0
- package/dist/payments/index.d.ts.map +1 -0
- package/dist/payments/index.js +72 -0
- package/dist/plugin/builtin/email-plugins.d.ts +10 -0
- package/dist/plugin/builtin/email-plugins.d.ts.map +1 -0
- package/dist/plugin/builtin/index.d.ts +4 -0
- package/dist/plugin/builtin/index.d.ts.map +1 -0
- package/dist/plugin/builtin/index.js +324 -0
- package/dist/plugin/builtin/payment-plugins.d.ts +4 -0
- package/dist/plugin/builtin/payment-plugins.d.ts.map +1 -0
- package/dist/plugin/builtin/storage-plugins.d.ts +5 -0
- package/dist/plugin/builtin/storage-plugins.d.ts.map +1 -0
- package/dist/plugin/index.d.ts +21 -0
- package/dist/plugin/index.d.ts.map +1 -0
- package/dist/plugin/index.js +30 -0
- package/dist/rate-limit/index.d.ts +89 -0
- package/dist/rate-limit/index.d.ts.map +1 -0
- package/dist/rate-limit/index.js +166 -0
- package/dist/seo/faq.d.ts +37 -0
- package/dist/seo/faq.d.ts.map +1 -0
- package/dist/seo/index.d.ts +75 -0
- package/dist/seo/index.d.ts.map +1 -0
- package/dist/seo/index.js +1 -0
- package/dist/storage/index.d.ts +50 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +211 -0
- package/dist/test-utils/factories.d.ts +38 -0
- package/dist/test-utils/factories.d.ts.map +1 -0
- package/dist/test-utils/index.d.ts +6 -0
- package/dist/test-utils/index.d.ts.map +1 -0
- package/dist/test-utils/index.js +117 -0
- package/dist/test-utils/mock-auth.d.ts +25 -0
- package/dist/test-utils/mock-auth.d.ts.map +1 -0
- package/dist/test-utils/mock-prisma.d.ts +55 -0
- package/dist/test-utils/mock-prisma.d.ts.map +1 -0
- package/dist/test-utils/render.d.ts +4 -0
- package/dist/test-utils/render.d.ts.map +1 -0
- package/dist/test-utils/request-helpers.d.ts +6 -0
- package/dist/test-utils/request-helpers.d.ts.map +1 -0
- package/dist/types.d.ts +53 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/math.d.ts +2 -0
- package/dist/utils/math.d.ts.map +1 -0
- package/dist/utils/math.js +7 -0
- package/dist/utils/optional-import.d.ts +14 -0
- package/dist/utils/optional-import.d.ts.map +1 -0
- package/package.json +205 -0
- package/scripts/generate-skill-adapters.ts +146 -0
- package/scripts/postinstall.mjs +146 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# Skill: Test an API Route
|
|
2
|
+
|
|
3
|
+
Write unit tests for a MARS API route using Vitest, mock-auth, and Prisma mocking.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
Use this skill when the user asks to test an API endpoint, write backend tests, or add test coverage for a route handler.
|
|
8
|
+
|
|
9
|
+
## Architecture
|
|
10
|
+
|
|
11
|
+
MARS API route tests:
|
|
12
|
+
- Import and call the exported handler function directly (no HTTP server needed)
|
|
13
|
+
- Mock Prisma, auth session, and external services
|
|
14
|
+
- Assert response status and body
|
|
15
|
+
- Test all paths: success, validation errors, auth errors, database errors
|
|
16
|
+
|
|
17
|
+
## Template: Full API Route Test
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// src/app/api/protected/projects/route.test.ts
|
|
21
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
22
|
+
import { GET, POST } from './route';
|
|
23
|
+
import { mockAuth, createTestRequest, createTestRequestWithBody } from '@mars-stack/core/test-utils';
|
|
24
|
+
|
|
25
|
+
// Mock database
|
|
26
|
+
const mockFindMany = vi.fn();
|
|
27
|
+
const mockCreate = vi.fn();
|
|
28
|
+
|
|
29
|
+
vi.mock('@/lib/prisma', () => ({
|
|
30
|
+
prisma: {
|
|
31
|
+
project: {
|
|
32
|
+
findMany: (...args: unknown[]) => mockFindMany(...args),
|
|
33
|
+
create: (...args: unknown[]) => mockCreate(...args),
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
isDatabaseError: vi.fn(() => false),
|
|
37
|
+
formatDatabaseError: vi.fn(),
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
// Mock auth -- return a valid session
|
|
41
|
+
vi.mock('@/lib/mars', () => ({
|
|
42
|
+
verifySessionForAPI: vi.fn(() => Promise.resolve(mockAuth)),
|
|
43
|
+
}));
|
|
44
|
+
|
|
45
|
+
describe('GET /api/protected/projects', () => {
|
|
46
|
+
beforeEach(() => {
|
|
47
|
+
vi.clearAllMocks();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('returns projects for the authenticated user', async () => {
|
|
51
|
+
const projects = [
|
|
52
|
+
{ id: '1', name: 'Project A', userId: mockAuth.userId },
|
|
53
|
+
{ id: '2', name: 'Project B', userId: mockAuth.userId },
|
|
54
|
+
];
|
|
55
|
+
mockFindMany.mockResolvedValue(projects);
|
|
56
|
+
|
|
57
|
+
const request = createTestRequest('GET', '/api/protected/projects');
|
|
58
|
+
const response = await GET(request);
|
|
59
|
+
const body = await response.json();
|
|
60
|
+
|
|
61
|
+
expect(response.status).toBe(200);
|
|
62
|
+
expect(body).toHaveLength(2);
|
|
63
|
+
expect(mockFindMany).toHaveBeenCalledWith(
|
|
64
|
+
expect.objectContaining({
|
|
65
|
+
where: { userId: mockAuth.userId },
|
|
66
|
+
}),
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('returns 401 when not authenticated', async () => {
|
|
71
|
+
const { verifySessionForAPI } = await import('@/lib/mars');
|
|
72
|
+
vi.mocked(verifySessionForAPI).mockResolvedValueOnce(null);
|
|
73
|
+
|
|
74
|
+
const request = createTestRequest('GET', '/api/protected/projects');
|
|
75
|
+
const response = await GET(request);
|
|
76
|
+
|
|
77
|
+
expect(response.status).toBe(401);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('POST /api/protected/projects', () => {
|
|
82
|
+
beforeEach(() => {
|
|
83
|
+
vi.clearAllMocks();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('creates a project with valid data', async () => {
|
|
87
|
+
const newProject = { id: '3', name: 'New Project', userId: mockAuth.userId };
|
|
88
|
+
mockCreate.mockResolvedValue(newProject);
|
|
89
|
+
|
|
90
|
+
const request = createTestRequestWithBody('POST', '/api/protected/projects', {
|
|
91
|
+
name: 'New Project',
|
|
92
|
+
});
|
|
93
|
+
const response = await POST(request);
|
|
94
|
+
const body = await response.json();
|
|
95
|
+
|
|
96
|
+
expect(response.status).toBe(201);
|
|
97
|
+
expect(body.name).toBe('New Project');
|
|
98
|
+
expect(mockCreate).toHaveBeenCalledWith(
|
|
99
|
+
expect.objectContaining({
|
|
100
|
+
data: expect.objectContaining({
|
|
101
|
+
name: 'New Project',
|
|
102
|
+
userId: mockAuth.userId,
|
|
103
|
+
}),
|
|
104
|
+
}),
|
|
105
|
+
);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('returns 400 for invalid input', async () => {
|
|
109
|
+
const request = createTestRequestWithBody('POST', '/api/protected/projects', {
|
|
110
|
+
name: '', // Empty name should fail validation
|
|
111
|
+
});
|
|
112
|
+
const response = await POST(request);
|
|
113
|
+
|
|
114
|
+
expect(response.status).toBe(400);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('returns 503 when database is unavailable', async () => {
|
|
118
|
+
const dbError = new Error("Can't reach database server");
|
|
119
|
+
Object.defineProperty(dbError, 'name', { value: 'PrismaClientInitializationError' });
|
|
120
|
+
mockCreate.mockRejectedValue(dbError);
|
|
121
|
+
|
|
122
|
+
const { isDatabaseError } = await import('@/lib/prisma');
|
|
123
|
+
vi.mocked(isDatabaseError).mockReturnValueOnce(true);
|
|
124
|
+
|
|
125
|
+
const request = createTestRequestWithBody('POST', '/api/protected/projects', {
|
|
126
|
+
name: 'Test Project',
|
|
127
|
+
});
|
|
128
|
+
const response = await POST(request);
|
|
129
|
+
|
|
130
|
+
expect(response.status).toBe(503);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Mock Auth Utilities
|
|
136
|
+
|
|
137
|
+
MARS provides mock auth utilities via `@mars-stack/core/test-utils`:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import { mockAuth, mockAuthAsAdmin, mockAuthAsUser } from '@mars-stack/core/test-utils';
|
|
141
|
+
import { createTestRequest, createTestRequestWithBody } from '@mars-stack/core/test-utils';
|
|
142
|
+
|
|
143
|
+
// mockAuth — default mock session object
|
|
144
|
+
// mockAuthAsAdmin / mockAuthAsUser — role-specific variants
|
|
145
|
+
// createTestRequest(method, path) — build a NextRequest without a body
|
|
146
|
+
// createTestRequestWithBody(method, path, body) — build a NextRequest with JSON body
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Testing Patterns
|
|
150
|
+
|
|
151
|
+
### Test Auth Required
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
it('returns 401 when not authenticated', async () => {
|
|
155
|
+
const { verifySessionForAPI } = await import('@/lib/mars');
|
|
156
|
+
vi.mocked(verifySessionForAPI).mockResolvedValueOnce(null);
|
|
157
|
+
// ...assert 401
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Test Role Requirement
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
it('returns 403 for non-admin users', async () => {
|
|
165
|
+
const { verifySessionForAPI } = await import('@/lib/mars');
|
|
166
|
+
vi.mocked(verifySessionForAPI).mockResolvedValueOnce({ ...mockAuth, role: 'user' });
|
|
167
|
+
|
|
168
|
+
// For withRole, also mock the DB role check
|
|
169
|
+
mockFindUnique.mockResolvedValueOnce({ role: 'user' });
|
|
170
|
+
|
|
171
|
+
// ...assert 403
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Test Validation Errors
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
it('returns 400 with validation errors', async () => {
|
|
179
|
+
const request = createTestRequestWithBody('POST', '/api/protected/resource', {
|
|
180
|
+
email: 'not-an-email',
|
|
181
|
+
});
|
|
182
|
+
const response = await handler(request);
|
|
183
|
+
const body = await response.json();
|
|
184
|
+
|
|
185
|
+
expect(response.status).toBe(400);
|
|
186
|
+
expect(body.error).toBeDefined();
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Test Database Errors
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
it('returns 503 when database is down', async () => {
|
|
194
|
+
mockFindMany.mockRejectedValueOnce(new Error("Can't reach database"));
|
|
195
|
+
// ... assert 503
|
|
196
|
+
});
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Running Tests
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
yarn test # Run all tests
|
|
203
|
+
yarn test src/app/api/ # Run only API tests
|
|
204
|
+
yarn test:watch # Watch mode
|
|
205
|
+
yarn test:coverage # With coverage report
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Checklist
|
|
209
|
+
|
|
210
|
+
- [ ] Test file created next to route (`route.test.ts`)
|
|
211
|
+
- [ ] Prisma mocked with `vi.mock('@/lib/prisma')`
|
|
212
|
+
- [ ] Auth session mocked with `vi.mock('@/lib/mars')`
|
|
213
|
+
- [ ] `vi.clearAllMocks()` in `beforeEach`
|
|
214
|
+
- [ ] Success path tested
|
|
215
|
+
- [ ] 401 unauthorized tested
|
|
216
|
+
- [ ] 400 validation error tested
|
|
217
|
+
- [ ] 403 forbidden tested (if role-gated)
|
|
218
|
+
- [ ] 503 database error tested
|
|
219
|
+
- [ ] Response status AND body assertions
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Skill: Update Architecture Docs
|
|
2
|
+
|
|
3
|
+
Keep the Mars project documentation in sync with code changes. Covers when and how to update ARCHITECTURE.md, AGENTS.md, QUALITY_SCORE.md, and generated docs.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
Use this skill when:
|
|
8
|
+
- You have just added a new feature, service, or package
|
|
9
|
+
- You have changed the database schema
|
|
10
|
+
- You have added or removed a skill or rule
|
|
11
|
+
- You have completed an execution plan
|
|
12
|
+
- The user asks to update docs, sync docs, or refresh documentation
|
|
13
|
+
- Another skill's checklist includes "update docs"
|
|
14
|
+
|
|
15
|
+
## Prerequisites
|
|
16
|
+
|
|
17
|
+
- Read `ARCHITECTURE.md` to understand the current documented state.
|
|
18
|
+
- Read `AGENTS.md` for the project-level agent guide.
|
|
19
|
+
- Read `docs/QUALITY_SCORE.md` for current quality grades.
|
|
20
|
+
|
|
21
|
+
## Document Index
|
|
22
|
+
|
|
23
|
+
| Document | Location | Purpose | Update frequency |
|
|
24
|
+
|----------|----------|---------|------------------|
|
|
25
|
+
| `AGENTS.md` | Repo root | First file any agent reads. Overview + pointers | On structure changes |
|
|
26
|
+
| `ARCHITECTURE.md` | Repo root | Detailed technical architecture | On arch changes |
|
|
27
|
+
| `docs/QUALITY_SCORE.md` | Docs | Quality grades by domain | After every improvement |
|
|
28
|
+
| `docs/generated/package-map.md` | Docs | Auto-generated package structure | Regenerate on package changes |
|
|
29
|
+
| `docs/generated/skill-inventory.md` | Docs | Auto-generated skill list | Regenerate on skill changes |
|
|
30
|
+
| `template/AGENTS.md` | Template | Consumer-facing project guide | On template structure changes |
|
|
31
|
+
| `packages/core/cursor/manifest.json` | Core | Skill index with triggers | On skill add/remove |
|
|
32
|
+
|
|
33
|
+
## When to Update Each Document
|
|
34
|
+
|
|
35
|
+
### ARCHITECTURE.md
|
|
36
|
+
|
|
37
|
+
Update when:
|
|
38
|
+
- A new package is added to the monorepo
|
|
39
|
+
- The build pipeline changes (new build step, tool change)
|
|
40
|
+
- A new export path is added to a package
|
|
41
|
+
- The security model changes (new auth pattern, new middleware)
|
|
42
|
+
- The skill/rule system changes
|
|
43
|
+
|
|
44
|
+
What to update:
|
|
45
|
+
1. Package layering diagram (if dependency graph changed)
|
|
46
|
+
2. Package export table (if new exports added)
|
|
47
|
+
3. Build pipeline section (if build process changed)
|
|
48
|
+
4. Security architecture section (if auth patterns changed)
|
|
49
|
+
5. Skills and rules section (if skill system changed)
|
|
50
|
+
|
|
51
|
+
### AGENTS.md (Root)
|
|
52
|
+
|
|
53
|
+
Update when:
|
|
54
|
+
- A new top-level directory is added
|
|
55
|
+
- A new CLI command is added
|
|
56
|
+
- The "How to Run" commands change
|
|
57
|
+
- A new "How to" section is needed (e.g., "How to Add a Plugin")
|
|
58
|
+
|
|
59
|
+
Keep it concise — AGENTS.md should fit in a single context window.
|
|
60
|
+
|
|
61
|
+
### template/AGENTS.md
|
|
62
|
+
|
|
63
|
+
Update when:
|
|
64
|
+
- The template directory structure changes
|
|
65
|
+
- New route groups are added
|
|
66
|
+
- New feature modules are added to the template
|
|
67
|
+
- The config structure changes
|
|
68
|
+
- New "How to Run" commands are added
|
|
69
|
+
|
|
70
|
+
### docs/QUALITY_SCORE.md
|
|
71
|
+
|
|
72
|
+
Update when:
|
|
73
|
+
- A quality grade changes (feature implemented, bug fixed, test added)
|
|
74
|
+
- A new domain is added to the grading table
|
|
75
|
+
- An execution plan is completed
|
|
76
|
+
|
|
77
|
+
How to update:
|
|
78
|
+
1. Find the relevant row in the appropriate table
|
|
79
|
+
2. Update the grade (A/B/C/D/F)
|
|
80
|
+
3. Update the notes to reflect current state
|
|
81
|
+
4. Add date reference if significant change
|
|
82
|
+
|
|
83
|
+
```markdown
|
|
84
|
+
| Dashboard | B | Basic layout with stat cards. Missing: chart widgets, date range filter |
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Generated Docs
|
|
88
|
+
|
|
89
|
+
Regenerate `docs/generated/package-map.md` when:
|
|
90
|
+
- A package's exports change
|
|
91
|
+
- A new package is added
|
|
92
|
+
- A package is removed
|
|
93
|
+
|
|
94
|
+
Regenerate `docs/generated/skill-inventory.md` when:
|
|
95
|
+
- A skill is added, removed, or renamed
|
|
96
|
+
- Skill triggers or dependencies change
|
|
97
|
+
|
|
98
|
+
### manifest.json
|
|
99
|
+
|
|
100
|
+
Update when:
|
|
101
|
+
- A new skill is added (add entry with triggers, dependencies, capabilities)
|
|
102
|
+
- A skill is removed (remove entry)
|
|
103
|
+
- Skill triggers change (update triggers array)
|
|
104
|
+
- Skill dependencies change (update dependencies array)
|
|
105
|
+
|
|
106
|
+
## Step-by-Step: After Adding a Feature
|
|
107
|
+
|
|
108
|
+
1. **QUALITY_SCORE.md** — Update the grade for the relevant domain:
|
|
109
|
+
|
|
110
|
+
```markdown
|
|
111
|
+
| Billing | B | Stripe checkout, portal, webhook. Missing: usage-based billing |
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
2. **ARCHITECTURE.md** — If the feature introduces a new architectural pattern:
|
|
115
|
+
|
|
116
|
+
```markdown
|
|
117
|
+
### Billing Architecture
|
|
118
|
+
|
|
119
|
+
The billing system uses Stripe as the payment provider...
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
3. **template/AGENTS.md** — If the feature adds new directories or conventions:
|
|
123
|
+
|
|
124
|
+
```markdown
|
|
125
|
+
├── features/
|
|
126
|
+
│ └── billing/ # Subscription management
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
4. **Execution plan** — Mark tasks complete, update verification:
|
|
130
|
+
|
|
131
|
+
```markdown
|
|
132
|
+
- [x] **3.1 Billing page** — Done. `src/app/(protected)/billing/page.tsx`
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Step-by-Step: After Adding a Skill
|
|
136
|
+
|
|
137
|
+
1. **manifest.json** — Add the skill entry:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
"new-skill-name": {
|
|
141
|
+
"file": "skills/mars-new-skill-name/SKILL.md",
|
|
142
|
+
"triggers": ["trigger phrase 1", "trigger phrase 2"],
|
|
143
|
+
"dependencies": ["dependency-skill"],
|
|
144
|
+
"capabilities": ["file-edit", "terminal"]
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
2. **skill-inventory.md** — Regenerate or manually add:
|
|
149
|
+
|
|
150
|
+
```markdown
|
|
151
|
+
| new-skill-name | Add a new thing | file-edit, terminal |
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
3. **AGENTS.md** — If the skill represents a new "How to" workflow:
|
|
155
|
+
|
|
156
|
+
```markdown
|
|
157
|
+
## How to Add a New Thing
|
|
158
|
+
|
|
159
|
+
1. Create the skill file
|
|
160
|
+
2. Add to manifest
|
|
161
|
+
3. ...
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Step-by-Step: After a Schema Change
|
|
165
|
+
|
|
166
|
+
1. **ARCHITECTURE.md** — Update if the change affects the data model section
|
|
167
|
+
2. **template/AGENTS.md** — Update the schema file listing if new files added
|
|
168
|
+
3. **QUALITY_SCORE.md** — Update database-related grades
|
|
169
|
+
|
|
170
|
+
## Validation
|
|
171
|
+
|
|
172
|
+
After updating docs, verify:
|
|
173
|
+
|
|
174
|
+
1. **No broken links** — Check that referenced files exist
|
|
175
|
+
2. **Consistent terminology** — Use the same names as the code
|
|
176
|
+
3. **Up-to-date grades** — Quality scores reflect actual state
|
|
177
|
+
4. **AGENTS.md fits in context** — Keep it under ~200 lines
|
|
178
|
+
|
|
179
|
+
## Checklist
|
|
180
|
+
|
|
181
|
+
- [ ] Identified which documents need updating
|
|
182
|
+
- [ ] ARCHITECTURE.md updated (if architectural change)
|
|
183
|
+
- [ ] AGENTS.md updated (if structure or workflow change)
|
|
184
|
+
- [ ] template/AGENTS.md updated (if template structure change)
|
|
185
|
+
- [ ] QUALITY_SCORE.md grades updated
|
|
186
|
+
- [ ] manifest.json updated (if skill change)
|
|
187
|
+
- [ ] Generated docs regenerated (if package or skill change)
|
|
188
|
+
- [ ] No broken internal links
|
|
189
|
+
- [ ] Execution plan marked as complete (if applicable)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
interface ApiErrorHandlerConfig {
|
|
3
|
+
logger: {
|
|
4
|
+
error: (...args: unknown[]) => void;
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
export interface ApiErrorOptions {
|
|
8
|
+
endpoint: string;
|
|
9
|
+
fallbackMessage?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Creates an API error handler that maps Zod validation errors, database errors,
|
|
13
|
+
* and unhandled exceptions to appropriate JSON responses with status codes.
|
|
14
|
+
*
|
|
15
|
+
* @param config - Configuration with a structured logger
|
|
16
|
+
* @returns An object containing the `handleApiError` function
|
|
17
|
+
* @example
|
|
18
|
+
* const { handleApiError } = createApiErrorHandler({ logger: console });
|
|
19
|
+
* try { ... } catch (error) {
|
|
20
|
+
* return handleApiError(error, { endpoint: '/api/users' });
|
|
21
|
+
* }
|
|
22
|
+
*/
|
|
23
|
+
export declare function createApiErrorHandler(config: ApiErrorHandlerConfig): {
|
|
24
|
+
handleApiError: (error: unknown, options: ApiErrorOptions) => NextResponse;
|
|
25
|
+
};
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api-error/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,UAAU,qBAAqB;IAC7B,MAAM,EAAE;QAAE,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;KAAE,CAAC;CACjD;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AA0BD;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB;4BAClC,OAAO,WAAW,eAAe,KAAG,YAAY;EAyBhF"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import 'server-only';
|
|
2
|
+
/** Tag for users without a password (e.g. OAuth-only). Sessions cannot be individually revoked. */
|
|
3
|
+
export declare const NO_PASSWORD_TAG = "no-password";
|
|
4
|
+
export declare function buildCredentialTag(passwordHash: string | null | undefined, _revocationSeed?: string): Promise<string>;
|
|
5
|
+
//# sourceMappingURL=credential-tag.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credential-tag.d.ts","sourceRoot":"","sources":["../../src/auth/credential-tag.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AAMrB,mGAAmG;AACnG,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAE7C,wBAAsB,kBAAkB,CACtC,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACvC,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC,CAOjB"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import 'server-only';
|
|
2
|
+
/**
|
|
3
|
+
* Constant-time string comparison to prevent timing attacks.
|
|
4
|
+
* Pads comparison to max length so length mismatch does not leak information.
|
|
5
|
+
*
|
|
6
|
+
* @param a - First string to compare
|
|
7
|
+
* @param b - Second string to compare
|
|
8
|
+
* @returns True if the strings are identical
|
|
9
|
+
* @example
|
|
10
|
+
* if (constantTimeEqual(suppliedToken, expectedToken)) { /* valid *\/ }
|
|
11
|
+
*/
|
|
12
|
+
export declare function constantTimeEqual(a: string, b: string): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Converts a byte array to a lowercase hex-encoded string.
|
|
15
|
+
*
|
|
16
|
+
* @param bytes - The byte array to convert
|
|
17
|
+
* @returns The hex-encoded string
|
|
18
|
+
* @example
|
|
19
|
+
* const hex = bytesToHex(new Uint8Array([0xde, 0xad])); // 'dead'
|
|
20
|
+
*/
|
|
21
|
+
export declare function bytesToHex(bytes: Uint8Array): string;
|
|
22
|
+
/**
|
|
23
|
+
* Escapes HTML special characters to prevent XSS in email templates.
|
|
24
|
+
*
|
|
25
|
+
* @param str - The raw string to escape
|
|
26
|
+
* @returns The HTML-safe string with &, <, >, ", ' escaped
|
|
27
|
+
* @example
|
|
28
|
+
* const safe = escapeHtml('<script>alert("xss")</script>');
|
|
29
|
+
* // '<script>alert("xss")</script>'
|
|
30
|
+
*/
|
|
31
|
+
export declare function escapeHtml(str: string): string;
|
|
32
|
+
/**
|
|
33
|
+
* Hashes a token with a domain separator for secure storage.
|
|
34
|
+
* Uses SHA-256(domain + ":" + token) to prevent cross-protocol hash collisions.
|
|
35
|
+
*
|
|
36
|
+
* @param token - The raw token to hash
|
|
37
|
+
* @param domain - A domain separator string (e.g. 'email-verification')
|
|
38
|
+
* @returns The hex-encoded SHA-256 hash
|
|
39
|
+
* @example
|
|
40
|
+
* const hashed = await hashToken(rawToken, 'password-reset');
|
|
41
|
+
*/
|
|
42
|
+
export declare function hashToken(token: string, domain: string): Promise<string>;
|
|
43
|
+
//# sourceMappingURL=crypto-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto-utils.d.ts","sourceRoot":"","sources":["../../src/auth/crypto-utils.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AAErB;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAU/D;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAIpD;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO9C;AAED;;;;;;;;;GASG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAK9E"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { bytesToHex, constantTimeEqual, escapeHtml, hashToken } from '../chunk-MXQ66RUN.js';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import 'server-only';
|
|
2
|
+
import { NextRequest } from 'next/server';
|
|
3
|
+
interface CSRFProtectionConfig {
|
|
4
|
+
getJWTSecret: () => string;
|
|
5
|
+
logViolation: (event: {
|
|
6
|
+
ipAddress?: string;
|
|
7
|
+
userAgent?: string;
|
|
8
|
+
endpoint?: string;
|
|
9
|
+
}) => void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Creates a CSRF protection module with token generation, verification, and
|
|
13
|
+
* request validation. Derives a separate HMAC key from the JWT secret to
|
|
14
|
+
* prevent key reuse across protocols.
|
|
15
|
+
*
|
|
16
|
+
* @param config - Configuration with JWT secret accessor and violation logger
|
|
17
|
+
* @returns An object with CSRF token lifecycle and request validation methods
|
|
18
|
+
* @example
|
|
19
|
+
* const csrf = createCSRFProtection({
|
|
20
|
+
* getJWTSecret: () => env.JWT_SECRET,
|
|
21
|
+
* logViolation: (event) => logger.warn('CSRF violation', event),
|
|
22
|
+
* });
|
|
23
|
+
* const token = await csrf.generateCSRFToken(session.fingerprint);
|
|
24
|
+
*/
|
|
25
|
+
export declare function createCSRFProtection(config: CSRFProtectionConfig): {
|
|
26
|
+
generateCSRFToken: (sessionFingerprint?: string) => Promise<string>;
|
|
27
|
+
verifyCSRFToken: (token: string, expectedFingerprint?: string) => Promise<boolean>;
|
|
28
|
+
requireCSRFToken: (sessionFingerprint?: string) => Promise<string>;
|
|
29
|
+
validateCSRFRequest: (request: NextRequest, sessionFingerprint?: string) => Promise<boolean>;
|
|
30
|
+
};
|
|
31
|
+
export {};
|
|
32
|
+
//# sourceMappingURL=csrf.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../../src/auth/csrf.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AAGrB,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAiC1C,UAAU,oBAAoB;IAC5B,YAAY,EAAE,MAAM,MAAM,CAAC;IAC3B,YAAY,EAAE,CAAC,KAAK,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CAC9F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,oBAAoB;6CAUT,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;6BAYrE,MAAM,wBACS,MAAM,KAC3B,OAAO,CAAC,OAAO,CAAC;4CAkCkC,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;mCA2ClE,WAAW,uBACC,MAAM,KAC1B,OAAO,CAAC,OAAO,CAAC;EA4CpB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/auth/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { useState, useEffect, useMemo } from 'react';
|
|
2
|
+
|
|
3
|
+
// src/auth/hooks/useCSRF.ts
|
|
4
|
+
function useCSRF() {
|
|
5
|
+
const [csrfToken, setCSRFToken] = useState(null);
|
|
6
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
const fetchCSRFToken = async () => {
|
|
9
|
+
try {
|
|
10
|
+
const response = await fetch("/api/csrf", {
|
|
11
|
+
method: "GET",
|
|
12
|
+
credentials: "include"
|
|
13
|
+
});
|
|
14
|
+
if (response.ok) {
|
|
15
|
+
const data = await response.json();
|
|
16
|
+
setCSRFToken(data.token);
|
|
17
|
+
}
|
|
18
|
+
} catch (error) {
|
|
19
|
+
console.error("Failed to fetch CSRF token:", error);
|
|
20
|
+
} finally {
|
|
21
|
+
setIsLoading(false);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
fetchCSRFToken();
|
|
25
|
+
}, []);
|
|
26
|
+
function getCSRFHeaders() {
|
|
27
|
+
if (!csrfToken) return {};
|
|
28
|
+
return { "X-CSRF-Token": csrfToken };
|
|
29
|
+
}
|
|
30
|
+
function getCSRFFormData() {
|
|
31
|
+
if (!csrfToken) return {};
|
|
32
|
+
return { csrfToken };
|
|
33
|
+
}
|
|
34
|
+
return { csrfToken, isLoading, getCSRFHeaders, getCSRFFormData };
|
|
35
|
+
}
|
|
36
|
+
function usePasswordStrength(password) {
|
|
37
|
+
return useMemo(() => {
|
|
38
|
+
if (!password) {
|
|
39
|
+
return {
|
|
40
|
+
strength: "Weak",
|
|
41
|
+
requirements: {
|
|
42
|
+
length: false,
|
|
43
|
+
lowercase: false,
|
|
44
|
+
uppercase: false,
|
|
45
|
+
number: false,
|
|
46
|
+
special: false,
|
|
47
|
+
noPassword: false,
|
|
48
|
+
noSequential: false
|
|
49
|
+
},
|
|
50
|
+
score: 0
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const requirements = {
|
|
54
|
+
length: password.length >= 8 && password.length <= 100,
|
|
55
|
+
lowercase: /[a-z]/.test(password),
|
|
56
|
+
uppercase: /[A-Z]/.test(password),
|
|
57
|
+
number: /[0-9]/.test(password),
|
|
58
|
+
special: /[^A-Za-z0-9]/.test(password),
|
|
59
|
+
noPassword: !password.toLowerCase().includes("password"),
|
|
60
|
+
noSequential: !password.includes("123")
|
|
61
|
+
};
|
|
62
|
+
const score = Object.values(requirements).filter(Boolean).length;
|
|
63
|
+
const strength = score >= 6 ? "Strong" : score >= 4 ? "Medium" : "Weak";
|
|
64
|
+
return { strength, requirements, score };
|
|
65
|
+
}, [password]);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export { useCSRF, usePasswordStrength };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCSRF.d.ts","sourceRoot":"","sources":["../../../src/auth/hooks/useCSRF.ts"],"names":[],"mappings":"AAIA,wBAAgB,OAAO;;;0BA0BM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;2BAKrB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;EAMnD"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface PasswordRequirements {
|
|
2
|
+
length: boolean;
|
|
3
|
+
lowercase: boolean;
|
|
4
|
+
uppercase: boolean;
|
|
5
|
+
number: boolean;
|
|
6
|
+
special: boolean;
|
|
7
|
+
noPassword: boolean;
|
|
8
|
+
noSequential: boolean;
|
|
9
|
+
}
|
|
10
|
+
export type PasswordStrength = 'Weak' | 'Medium' | 'Strong';
|
|
11
|
+
export interface UsePasswordStrengthResult {
|
|
12
|
+
strength: PasswordStrength;
|
|
13
|
+
requirements: PasswordRequirements;
|
|
14
|
+
score: number;
|
|
15
|
+
}
|
|
16
|
+
export declare function usePasswordStrength(password: string): UsePasswordStrengthResult;
|
|
17
|
+
//# sourceMappingURL=usePasswordStrength.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePasswordStrength.d.ts","sourceRoot":"","sources":["../../../src/auth/hooks/usePasswordStrength.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE5D,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,YAAY,EAAE,oBAAoB,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,yBAAyB,CAiC/E"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import 'server-only';
|
|
2
|
+
export declare function getRequiredInternalApiKey(): string;
|
|
3
|
+
export declare function getInternalApiKeys(): string[];
|
|
4
|
+
export declare function isInternalApiRequestAuthorized(authHeader: string | null, expectedApiKeys: string | string[]): boolean;
|
|
5
|
+
//# sourceMappingURL=internal-api-key.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal-api-key.d.ts","sourceRoot":"","sources":["../../src/auth/internal-api-key.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AAerB,wBAAgB,yBAAyB,IAAI,MAAM,CAMlD;AAED,wBAAgB,kBAAkB,IAAI,MAAM,EAAE,CAE7C;AAED,wBAAgB,8BAA8B,CAC5C,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,eAAe,EAAE,MAAM,GAAG,MAAM,EAAE,GACjC,OAAO,CAST"}
|