@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,30 @@
|
|
|
1
|
+
import { constantTimeEqual } from '../chunk-MXQ66RUN.js';
|
|
2
|
+
import 'server-only';
|
|
3
|
+
|
|
4
|
+
var MIN_INTERNAL_API_KEY_LENGTH = 32;
|
|
5
|
+
function parseInternalApiKeys() {
|
|
6
|
+
const raw = process.env.INTERNAL_API_KEY;
|
|
7
|
+
if (!raw) return [];
|
|
8
|
+
return raw.split(",").map((k) => k.trim()).filter((k) => k.length >= MIN_INTERNAL_API_KEY_LENGTH);
|
|
9
|
+
}
|
|
10
|
+
function getRequiredInternalApiKey() {
|
|
11
|
+
const keys = parseInternalApiKeys();
|
|
12
|
+
if (keys.length === 0) {
|
|
13
|
+
throw new Error("INTERNAL_API_KEY must be set and at least 32 characters long");
|
|
14
|
+
}
|
|
15
|
+
return keys[0];
|
|
16
|
+
}
|
|
17
|
+
function getInternalApiKeys() {
|
|
18
|
+
return parseInternalApiKeys();
|
|
19
|
+
}
|
|
20
|
+
function isInternalApiRequestAuthorized(authHeader, expectedApiKeys) {
|
|
21
|
+
if (!authHeader) return false;
|
|
22
|
+
const keys = Array.isArray(expectedApiKeys) ? expectedApiKeys : [expectedApiKeys];
|
|
23
|
+
for (const key of keys) {
|
|
24
|
+
const expected = `Bearer ${key}`;
|
|
25
|
+
if (constantTimeEqual(authHeader, expected)) return true;
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export { getInternalApiKeys, getRequiredInternalApiKey, isInternalApiRequestAuthorized };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface BuildEmailVerificationUrlParams {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
token: string;
|
|
4
|
+
}
|
|
5
|
+
export interface BuildPasswordResetUrlParams {
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
token: string;
|
|
8
|
+
email: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function normalizeEmailFromQueryParam(rawEmail: string): string;
|
|
11
|
+
export declare function buildEmailVerificationUrl({ baseUrl, token, }: BuildEmailVerificationUrlParams): string;
|
|
12
|
+
export declare function buildPasswordResetUrl({ baseUrl, token, email, }: BuildPasswordResetUrlParams): string;
|
|
13
|
+
//# sourceMappingURL=link-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-utils.d.ts","sourceRoot":"","sources":["../../src/auth/link-utils.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,+BAA+B;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,wBAAgB,yBAAyB,CAAC,EACxC,OAAO,EACP,KAAK,GACN,EAAE,+BAA+B,GAAG,MAAM,CAE1C;AAED,wBAAgB,qBAAqB,CAAC,EACpC,OAAO,EACP,KAAK,EACL,KAAK,GACN,EAAE,2BAA2B,GAAG,MAAM,CAKtC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { buildEmailVerificationUrl, buildPasswordResetUrl, normalizeEmailFromQueryParam } from '../chunk-WBJOIENS.js';
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import type { SessionPayload } from './session';
|
|
3
|
+
export interface AuthenticatedRequest extends NextRequest {
|
|
4
|
+
session: SessionPayload;
|
|
5
|
+
}
|
|
6
|
+
export type AuthenticatedAPIHandler = (request: AuthenticatedRequest, context: {
|
|
7
|
+
params: Promise<{
|
|
8
|
+
[key: string]: string;
|
|
9
|
+
}>;
|
|
10
|
+
}) => Promise<NextResponse>;
|
|
11
|
+
export type AuthenticatedAPIHandlerNoParams = (request: AuthenticatedRequest) => Promise<NextResponse>;
|
|
12
|
+
export type AuthenticatedAPIHandlerSimple = () => Promise<NextResponse>;
|
|
13
|
+
interface AuthMiddlewareConfig {
|
|
14
|
+
verifySession: () => Promise<SessionPayload | null>;
|
|
15
|
+
findUserRole: (userId: string) => Promise<string | null>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Creates authentication middleware wrappers for Next.js API routes.
|
|
19
|
+
* All wrappers verify the session, attach it to the request, and return
|
|
20
|
+
* appropriate HTTP error responses on failure.
|
|
21
|
+
*
|
|
22
|
+
* @param config - Configuration with session verifier and role lookup
|
|
23
|
+
* @returns An object containing withAuth, withAuthNoParams, withAuthSimple, withRole, and withOwnership wrappers
|
|
24
|
+
* @example
|
|
25
|
+
* const { withAuth, withRole, withOwnership } = createAuthMiddleware({
|
|
26
|
+
* verifySession: () => sessions.verifySessionForAPI(),
|
|
27
|
+
* findUserRole: (userId) => db.user.findRole(userId),
|
|
28
|
+
* });
|
|
29
|
+
* export const GET = withAuth(async (req, ctx) => { ... });
|
|
30
|
+
* export const DELETE = withRole(['admin'], async (req, ctx) => { ... });
|
|
31
|
+
*/
|
|
32
|
+
export declare function createAuthMiddleware(config: AuthMiddlewareConfig): {
|
|
33
|
+
withAuth: (handler: AuthenticatedAPIHandler) => (request: NextRequest, context: {
|
|
34
|
+
params: Promise<{
|
|
35
|
+
[key: string]: string;
|
|
36
|
+
}>;
|
|
37
|
+
}) => Promise<NextResponse>;
|
|
38
|
+
withAuthNoParams: (handler: AuthenticatedAPIHandlerNoParams) => (request: NextRequest) => Promise<NextResponse>;
|
|
39
|
+
withAuthSimple: (handler: AuthenticatedAPIHandlerSimple) => (_request: NextRequest) => Promise<NextResponse>;
|
|
40
|
+
withRole: (allowedRoles: string[], handler: AuthenticatedAPIHandler) => (request: NextRequest, context: {
|
|
41
|
+
params: Promise<{
|
|
42
|
+
[key: string]: string;
|
|
43
|
+
}>;
|
|
44
|
+
}) => Promise<NextResponse>;
|
|
45
|
+
withOwnership: (getResourceUserId: (request: AuthenticatedRequest, context: {
|
|
46
|
+
params: Promise<{
|
|
47
|
+
[key: string]: string;
|
|
48
|
+
}>;
|
|
49
|
+
}) => Promise<string | null | undefined>, handler: AuthenticatedAPIHandler) => (request: NextRequest, context: {
|
|
50
|
+
params: Promise<{
|
|
51
|
+
[key: string]: string;
|
|
52
|
+
}>;
|
|
53
|
+
}) => Promise<NextResponse>;
|
|
54
|
+
};
|
|
55
|
+
export {};
|
|
56
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/auth/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGhD,MAAM,WAAW,oBAAqB,SAAQ,WAAW;IACvD,OAAO,EAAE,cAAc,CAAC;CACzB;AAED,MAAM,MAAM,uBAAuB,GAAG,CACpC,OAAO,EAAE,oBAAoB,EAC7B,OAAO,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,KACpD,OAAO,CAAC,YAAY,CAAC,CAAC;AAE3B,MAAM,MAAM,+BAA+B,GAAG,CAC5C,OAAO,EAAE,oBAAoB,KAC1B,OAAO,CAAC,YAAY,CAAC,CAAC;AAE3B,MAAM,MAAM,6BAA6B,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;AAExE,UAAU,oBAAoB;IAC5B,aAAa,EAAE,MAAM,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACpD,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC1D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,oBAAoB;wBACpC,uBAAuB,MAE9C,SAAS,WAAW,EACpB,SAAS;QAAE,MAAM,EAAE,OAAO,CAAC;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,KACtD,OAAO,CAAC,YAAY,CAAC;gCAgBS,+BAA+B,MAClD,SAAS,WAAW,KAAG,OAAO,CAAC,YAAY,CAAC;8BAgB3B,6BAA6B,MAC9C,UAAU,WAAW,KAAG,OAAO,CAAC,YAAY,CAAC;6BAa7B,MAAM,EAAE,WAAW,uBAAuB,eAjD7D,WAAW,WACX;QAAE,MAAM,EAAE,OAAO,CAAC;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,KACtD,OAAO,CAAC,YAAY,CAAC;uCA6DL,CACjB,OAAO,EAAE,oBAAoB,EAC7B,OAAO,EAAE;QAAE,MAAM,EAAE,OAAO,CAAC;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,KACpD,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,WAC9B,uBAAuB,eAnErB,WAAW,WACX;QAAE,MAAM,EAAE,OAAO,CAAC;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,KACtD,OAAO,CAAC,YAAY,CAAC;EAyF3B"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import 'server-only';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
/** Zod schema enforcing password strength rules: 8-100 chars, mixed case, digit, special char, no common patterns. */
|
|
4
|
+
export declare const passwordSchema: z.ZodString;
|
|
5
|
+
/**
|
|
6
|
+
* Hashes a password using SHA-256 prehash followed by bcrypt (cost 12).
|
|
7
|
+
* The prehash step allows bcrypt to work with passwords of any length while
|
|
8
|
+
* maintaining a domain separator to prevent cross-protocol collisions.
|
|
9
|
+
*
|
|
10
|
+
* @param password - The plaintext password to hash
|
|
11
|
+
* @returns The bcrypt hash string
|
|
12
|
+
* @example
|
|
13
|
+
* const hash = await hashPassword('mySecureP@ss1');
|
|
14
|
+
*/
|
|
15
|
+
export declare function hashPassword(password: string): Promise<string>;
|
|
16
|
+
/**
|
|
17
|
+
* Verifies a plaintext password against a stored bcrypt hash.
|
|
18
|
+
* Attempts prehashed comparison first, then falls back to direct comparison
|
|
19
|
+
* for backwards compatibility with legacy hashes.
|
|
20
|
+
*
|
|
21
|
+
* @param plainPassword - The plaintext password to verify
|
|
22
|
+
* @param hashedPassword - The stored bcrypt hash
|
|
23
|
+
* @returns True if the password matches
|
|
24
|
+
* @example
|
|
25
|
+
* const valid = await verifyPassword('mySecureP@ss1', storedHash);
|
|
26
|
+
*/
|
|
27
|
+
export declare function verifyPassword(plainPassword: string, hashedPassword: string): Promise<boolean>;
|
|
28
|
+
//# sourceMappingURL=password.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password.d.ts","sourceRoot":"","sources":["../../src/auth/password.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AAErB,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAaxB,sHAAsH;AACtH,eAAO,MAAM,cAAc,aAYqE,CAAC;AAEjG;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAIpE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,cAAc,CAClC,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,OAAO,CAAC,CAMlB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { hashPassword, passwordSchema, verifyPassword } from '../chunk-WO6FHJHG.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reset-token.d.ts","sourceRoot":"","sources":["../../src/auth/reset-token.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AAMrB,wBAAsB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAE3E"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import 'server-only';
|
|
2
|
+
import { NextResponse } from 'next/server';
|
|
3
|
+
export declare const AUTH_RESPONSES: {
|
|
4
|
+
readonly UNAUTHORIZED: () => NextResponse<{
|
|
5
|
+
error: string;
|
|
6
|
+
}>;
|
|
7
|
+
readonly FORBIDDEN: () => NextResponse<{
|
|
8
|
+
error: string;
|
|
9
|
+
}>;
|
|
10
|
+
readonly SERVER_ERROR: () => NextResponse<{
|
|
11
|
+
error: string;
|
|
12
|
+
}>;
|
|
13
|
+
};
|
|
14
|
+
export declare function validateOwnership(resourceUserId: string, sessionUserId: string): boolean;
|
|
15
|
+
//# sourceMappingURL=responses.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"responses.d.ts","sourceRoot":"","sources":["../../src/auth/responses.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AAErB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQ3C,eAAO,MAAM,cAAc;;;;;;;;;;CAajB,CAAC;AAEX,wBAAgB,iBAAiB,CAAC,cAAc,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAExF"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import 'server-only';
|
|
2
|
+
export interface SessionPayload {
|
|
3
|
+
userId: string;
|
|
4
|
+
email: string;
|
|
5
|
+
name: string;
|
|
6
|
+
role: string;
|
|
7
|
+
fingerprint: string;
|
|
8
|
+
emailVerified: boolean;
|
|
9
|
+
credentialTag: string;
|
|
10
|
+
createdAt: number;
|
|
11
|
+
expiresAt: number;
|
|
12
|
+
lastActivity: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Encrypts a session payload into a JWE token using AES-256-GCM with a HKDF-derived key.
|
|
16
|
+
*
|
|
17
|
+
* @param payload - The session data to encrypt
|
|
18
|
+
* @param secret - The JWT secret used to derive the encryption key
|
|
19
|
+
* @returns The encrypted JWE token string
|
|
20
|
+
* @example
|
|
21
|
+
* const token = await encrypt(sessionPayload, process.env.JWT_SECRET);
|
|
22
|
+
*/
|
|
23
|
+
export declare function encrypt(payload: SessionPayload, secret: string): Promise<string>;
|
|
24
|
+
/**
|
|
25
|
+
* Decrypts a JWE session token and validates expiration, inactivity, and absolute lifetime.
|
|
26
|
+
* Deletes the session cookie if decryption fails (e.g. legacy/corrupted cookie).
|
|
27
|
+
*
|
|
28
|
+
* @param session - The encrypted JWE token string (or undefined)
|
|
29
|
+
* @param secret - The JWT secret used to derive the decryption key
|
|
30
|
+
* @returns The decrypted session payload, or null if invalid/expired
|
|
31
|
+
* @example
|
|
32
|
+
* const session = await decrypt(cookieValue, process.env.JWT_SECRET);
|
|
33
|
+
* if (session) console.log(session.userId);
|
|
34
|
+
*/
|
|
35
|
+
export declare function decrypt(session: string | undefined, secret: string): Promise<SessionPayload | null>;
|
|
36
|
+
interface SessionManagerConfig {
|
|
37
|
+
getJWTSecret: () => string;
|
|
38
|
+
signInRoute: string;
|
|
39
|
+
validateCredential: (userId: string, credentialTag: string) => Promise<boolean>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Creates a session manager with methods for creating, reading, updating, and
|
|
43
|
+
* deleting encrypted HTTP-only session cookies. Uses HKDF-derived keys and
|
|
44
|
+
* validates credential tags against the database on every read.
|
|
45
|
+
*
|
|
46
|
+
* @param config - Configuration with JWT secret accessor, sign-in route, and credential validator
|
|
47
|
+
* @returns An object with session lifecycle methods
|
|
48
|
+
* @example
|
|
49
|
+
* const sessions = createSessionManager({
|
|
50
|
+
* getJWTSecret: () => env.JWT_SECRET,
|
|
51
|
+
* signInRoute: '/sign-in',
|
|
52
|
+
* validateCredential: async (userId, tag) => db.user.checkCredential(userId, tag),
|
|
53
|
+
* });
|
|
54
|
+
* await sessions.createSession(user);
|
|
55
|
+
*/
|
|
56
|
+
export declare function createSessionManager(config: SessionManagerConfig): {
|
|
57
|
+
createSession: (user: {
|
|
58
|
+
id: string;
|
|
59
|
+
email: string;
|
|
60
|
+
name: string;
|
|
61
|
+
role: string;
|
|
62
|
+
emailVerified: boolean;
|
|
63
|
+
credentialTag: string;
|
|
64
|
+
}) => Promise<void>;
|
|
65
|
+
getSession: () => Promise<SessionPayload | null>;
|
|
66
|
+
updateSession: () => Promise<void>;
|
|
67
|
+
deleteSession: () => Promise<void>;
|
|
68
|
+
verifySession: () => Promise<SessionPayload>;
|
|
69
|
+
verifySessionForAPI: () => Promise<SessionPayload | null>;
|
|
70
|
+
getCurrentUser: () => Promise<{
|
|
71
|
+
id: string;
|
|
72
|
+
email: string;
|
|
73
|
+
name: string;
|
|
74
|
+
role: string;
|
|
75
|
+
emailVerified: boolean;
|
|
76
|
+
} | null>;
|
|
77
|
+
};
|
|
78
|
+
export {};
|
|
79
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/auth/session.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AAwCrB,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMtF;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,SAAc,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAkC9G;AAED,UAAU,oBAAoB;IAC5B,YAAY,EAAE,MAAM,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACjF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,oBAAoB;0BAC5B;QACjC,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,aAAa,EAAE,OAAO,CAAC;QACvB,aAAa,EAAE,MAAM,CAAC;KACvB,KAAG,OAAO,CAAC,IAAI,CAAC;sBA6BY,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;yBAiB3B,OAAO,CAAC,IAAI,CAAC;yBAyBb,OAAO,CAAC,IAAI,CAAC;yBAKP,OAAO,CAAC,cAAc,CAAC;+BAUjB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;0BAKzC,OAAO,CAAC;QACvC,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,aAAa,EAAE,OAAO,CAAC;KACxB,GAAG,IAAI,CAAC;EAsBV"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createSessionManager, decrypt, encrypt } from '../chunk-4LS3QDD5.js';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface AuthError {
|
|
2
|
+
code: string;
|
|
3
|
+
message: string;
|
|
4
|
+
}
|
|
5
|
+
export interface AuthUser {
|
|
6
|
+
id: string;
|
|
7
|
+
email: string;
|
|
8
|
+
name?: string;
|
|
9
|
+
role: string;
|
|
10
|
+
emailVerified: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare enum AuthErrorCode {
|
|
13
|
+
INVALID_CREDENTIALS = "invalid_credentials",
|
|
14
|
+
EMAIL_NOT_VERIFIED = "email_not_verified",
|
|
15
|
+
ACCOUNT_LOCKED = "account_locked",
|
|
16
|
+
SERVER_ERROR = "server_error"
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,oBAAY,aAAa;IACvB,mBAAmB,wBAAwB;IAC3C,kBAAkB,uBAAuB;IACzC,cAAc,mBAAmB;IACjC,YAAY,iBAAiB;CAC9B"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// src/auth/types.ts
|
|
2
|
+
var AuthErrorCode = /* @__PURE__ */ ((AuthErrorCode2) => {
|
|
3
|
+
AuthErrorCode2["INVALID_CREDENTIALS"] = "invalid_credentials";
|
|
4
|
+
AuthErrorCode2["EMAIL_NOT_VERIFIED"] = "email_not_verified";
|
|
5
|
+
AuthErrorCode2["ACCOUNT_LOCKED"] = "account_locked";
|
|
6
|
+
AuthErrorCode2["SERVER_ERROR"] = "server_error";
|
|
7
|
+
return AuthErrorCode2;
|
|
8
|
+
})(AuthErrorCode || {});
|
|
9
|
+
|
|
10
|
+
export { AuthErrorCode };
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** Individual field-level Zod schemas for email, password, name, token, and confirmPassword. */
|
|
3
|
+
export declare const fieldSchemas: {
|
|
4
|
+
email: z.ZodString;
|
|
5
|
+
password: z.ZodString;
|
|
6
|
+
name: z.ZodString;
|
|
7
|
+
token: z.ZodString;
|
|
8
|
+
confirmPassword: z.ZodString;
|
|
9
|
+
};
|
|
10
|
+
/** Client-side form validation schemas with cross-field refinements (e.g. password confirmation). */
|
|
11
|
+
export declare const formSchemas: {
|
|
12
|
+
login: z.ZodObject<{
|
|
13
|
+
email: z.ZodString;
|
|
14
|
+
password: z.ZodString;
|
|
15
|
+
}, z.core.$strip>;
|
|
16
|
+
signup: z.ZodObject<{
|
|
17
|
+
email: z.ZodString;
|
|
18
|
+
password: z.ZodString;
|
|
19
|
+
name: z.ZodOptional<z.ZodString>;
|
|
20
|
+
confirmPassword: z.ZodString;
|
|
21
|
+
termsAccepted: z.ZodBoolean;
|
|
22
|
+
marketingOptIn: z.ZodOptional<z.ZodBoolean>;
|
|
23
|
+
}, z.core.$strip>;
|
|
24
|
+
forgotPassword: z.ZodObject<{
|
|
25
|
+
email: z.ZodString;
|
|
26
|
+
}, z.core.$strip>;
|
|
27
|
+
resetPassword: z.ZodObject<{
|
|
28
|
+
token: z.ZodString;
|
|
29
|
+
email: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodString>;
|
|
30
|
+
password: z.ZodString;
|
|
31
|
+
confirmPassword: z.ZodString;
|
|
32
|
+
}, z.core.$strip>;
|
|
33
|
+
emailVerification: z.ZodObject<{
|
|
34
|
+
token: z.ZodString;
|
|
35
|
+
email: z.ZodOptional<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodString>>;
|
|
36
|
+
}, z.core.$strip>;
|
|
37
|
+
};
|
|
38
|
+
/** Server-side API validation schemas (no confirmPassword field — that's a client concern). */
|
|
39
|
+
export declare const apiSchemas: {
|
|
40
|
+
login: z.ZodObject<{
|
|
41
|
+
email: z.ZodString;
|
|
42
|
+
password: z.ZodString;
|
|
43
|
+
}, z.core.$strip>;
|
|
44
|
+
signup: z.ZodObject<{
|
|
45
|
+
email: z.ZodString;
|
|
46
|
+
password: z.ZodString;
|
|
47
|
+
name: z.ZodOptional<z.ZodString>;
|
|
48
|
+
termsAccepted: z.ZodBoolean;
|
|
49
|
+
marketingOptIn: z.ZodOptional<z.ZodBoolean>;
|
|
50
|
+
}, z.core.$strip>;
|
|
51
|
+
forgotPassword: z.ZodObject<{
|
|
52
|
+
email: z.ZodString;
|
|
53
|
+
}, z.core.$strip>;
|
|
54
|
+
resetPassword: z.ZodObject<{
|
|
55
|
+
token: z.ZodString;
|
|
56
|
+
email: z.ZodString;
|
|
57
|
+
password: z.ZodString;
|
|
58
|
+
}, z.core.$strip>;
|
|
59
|
+
emailVerification: z.ZodObject<{
|
|
60
|
+
token: z.ZodString;
|
|
61
|
+
email: z.ZodOptional<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodString>>;
|
|
62
|
+
}, z.core.$strip>;
|
|
63
|
+
};
|
|
64
|
+
export type LoginFormData = z.infer<typeof formSchemas.login>;
|
|
65
|
+
export type SignupFormData = z.infer<typeof formSchemas.signup>;
|
|
66
|
+
export type ForgotPasswordFormData = z.infer<typeof formSchemas.forgotPassword>;
|
|
67
|
+
export type ResetPasswordFormData = z.infer<typeof formSchemas.resetPassword>;
|
|
68
|
+
export type EmailVerificationData = z.infer<typeof formSchemas.emailVerification>;
|
|
69
|
+
/**
|
|
70
|
+
* Calculates a password strength score based on character diversity and common pattern avoidance.
|
|
71
|
+
*
|
|
72
|
+
* @param password - The password to evaluate
|
|
73
|
+
* @returns An object with a numeric score (0-7) and a strength label
|
|
74
|
+
* @example
|
|
75
|
+
* const { score, strength } = getPasswordStrength('MyP@ss99!');
|
|
76
|
+
* // { score: 7, strength: 'Strong' }
|
|
77
|
+
*/
|
|
78
|
+
export declare function getPasswordStrength(password: string): {
|
|
79
|
+
score: number;
|
|
80
|
+
strength: 'Weak' | 'Medium' | 'Strong';
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Returns a boolean map of which password requirements are satisfied.
|
|
84
|
+
* Useful for rendering a live requirements checklist in signup forms.
|
|
85
|
+
*
|
|
86
|
+
* @param password - The password to check
|
|
87
|
+
* @returns An object with boolean flags for each requirement
|
|
88
|
+
* @example
|
|
89
|
+
* const reqs = getPasswordRequirements('Hello1!');
|
|
90
|
+
* // { length: false, lowercase: true, uppercase: true, number: true, special: true, ... }
|
|
91
|
+
*/
|
|
92
|
+
export declare function getPasswordRequirements(password: string): {
|
|
93
|
+
length: boolean;
|
|
94
|
+
lowercase: boolean;
|
|
95
|
+
uppercase: boolean;
|
|
96
|
+
number: boolean;
|
|
97
|
+
special: boolean;
|
|
98
|
+
noPassword: boolean;
|
|
99
|
+
noSequential: boolean;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Validates a single value against a Zod schema.
|
|
103
|
+
*
|
|
104
|
+
* @param schema - The Zod schema to validate against
|
|
105
|
+
* @param value - The value to validate
|
|
106
|
+
* @returns The first error message string, or null if valid
|
|
107
|
+
* @example
|
|
108
|
+
* const error = validateField(fieldSchemas.email, 'bad');
|
|
109
|
+
* // 'Please enter a valid email address'
|
|
110
|
+
*/
|
|
111
|
+
export declare function validateField<T extends z.ZodSchema>(schema: T, value: unknown): string | null;
|
|
112
|
+
/**
|
|
113
|
+
* Validates a complete form data object against a Zod schema.
|
|
114
|
+
*
|
|
115
|
+
* @param schema - The Zod schema to validate against
|
|
116
|
+
* @param data - The form data object to validate
|
|
117
|
+
* @returns An object with success flag, parsed data (or null), and a path-keyed errors map
|
|
118
|
+
* @example
|
|
119
|
+
* const result = validateForm(formSchemas.login, { email: '', password: '' });
|
|
120
|
+
* // { success: false, data: null, errors: { email: 'Email is required', ... } }
|
|
121
|
+
*/
|
|
122
|
+
export declare function validateForm<T extends z.ZodSchema>(schema: T, data: unknown): {
|
|
123
|
+
success: boolean;
|
|
124
|
+
data: z.core.output<T>;
|
|
125
|
+
errors: {};
|
|
126
|
+
} | {
|
|
127
|
+
success: boolean;
|
|
128
|
+
data: null;
|
|
129
|
+
errors: Record<string, string>;
|
|
130
|
+
};
|
|
131
|
+
export declare const passwordSchema: z.ZodString;
|
|
132
|
+
export declare const loginSchema: z.ZodObject<{
|
|
133
|
+
email: z.ZodString;
|
|
134
|
+
password: z.ZodString;
|
|
135
|
+
}, z.core.$strip>;
|
|
136
|
+
export declare const signupSchema: z.ZodObject<{
|
|
137
|
+
email: z.ZodString;
|
|
138
|
+
password: z.ZodString;
|
|
139
|
+
name: z.ZodOptional<z.ZodString>;
|
|
140
|
+
termsAccepted: z.ZodBoolean;
|
|
141
|
+
marketingOptIn: z.ZodOptional<z.ZodBoolean>;
|
|
142
|
+
}, z.core.$strip>;
|
|
143
|
+
export declare const forgotPasswordSchema: z.ZodObject<{
|
|
144
|
+
email: z.ZodString;
|
|
145
|
+
}, z.core.$strip>;
|
|
146
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/auth/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,gGAAgG;AAChG,eAAO,MAAM,YAAY;;;;;;CAwBxB,CAAC;AA0CF,qGAAqG;AACrG,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;CAgBvB,CAAC;AAEF,+FAA+F;AAC/F,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;CAoBtB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;AAC9D,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC;AAChE,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,cAAc,CAAC,CAAC;AAChF,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,aAAa,CAAC,CAAC;AAC9E,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,iBAAiB,CAAC,CAAC;AAElF;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,GACf;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAA;CAAE,CAa3D;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM;;;;;;;;EAUvD;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,iBAG7E;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO;;;;;;;;EAW3E;AAED,eAAO,MAAM,cAAc,aAAwB,CAAC;AACpD,eAAO,MAAM,WAAW;;;iBAAmB,CAAC;AAC5C,eAAO,MAAM,YAAY;;;;;;iBAAoB,CAAC;AAC9C,eAAO,MAAM,oBAAoB;;iBAA4B,CAAC"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { normalizeEmailFromQueryParam } from '../chunk-WBJOIENS.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
var fieldSchemas = {
|
|
5
|
+
email: z.string().min(1, "Email is required").email("Please enter a valid email address"),
|
|
6
|
+
password: z.string().min(8, "Password must be at least 8 characters").max(100, "Password must be less than 100 characters").regex(/[A-Z]/, "Password must contain at least one uppercase letter").regex(/[a-z]/, "Password must contain at least one lowercase letter").regex(/[0-9]/, "Password must contain at least one number").regex(/[^A-Za-z0-9]/, "Password must contain at least one special character").refine((password) => !password.toLowerCase().includes("password"), "Password cannot contain 'password'").refine((password) => !password.includes("123"), "Password cannot contain sequential numbers"),
|
|
7
|
+
name: z.string().min(1, "Name is required").min(2, "Name must be at least 2 characters").max(100, "Name must be less than 100 characters").regex(/^[a-zA-Z\s'-]+$/, "Name can only contain letters, spaces, hyphens, and apostrophes"),
|
|
8
|
+
token: z.string().min(1, "Token is required"),
|
|
9
|
+
confirmPassword: z.string().min(1, "Please confirm your password")
|
|
10
|
+
};
|
|
11
|
+
var baseSchemas = {
|
|
12
|
+
login: z.object({
|
|
13
|
+
email: fieldSchemas.email,
|
|
14
|
+
password: z.string().min(1, "Password is required")
|
|
15
|
+
}),
|
|
16
|
+
signupBase: z.object({
|
|
17
|
+
email: fieldSchemas.email,
|
|
18
|
+
password: fieldSchemas.password,
|
|
19
|
+
name: fieldSchemas.name.optional(),
|
|
20
|
+
confirmPassword: fieldSchemas.confirmPassword,
|
|
21
|
+
termsAccepted: z.boolean().refine((val) => val === true, "You must accept the terms and conditions"),
|
|
22
|
+
marketingOptIn: z.boolean().optional()
|
|
23
|
+
}),
|
|
24
|
+
forgotPassword: z.object({
|
|
25
|
+
email: fieldSchemas.email
|
|
26
|
+
}),
|
|
27
|
+
resetPasswordBase: z.object({
|
|
28
|
+
token: fieldSchemas.token,
|
|
29
|
+
email: z.preprocess(
|
|
30
|
+
(value) => typeof value === "string" ? normalizeEmailFromQueryParam(value) : value,
|
|
31
|
+
fieldSchemas.email
|
|
32
|
+
),
|
|
33
|
+
password: fieldSchemas.password,
|
|
34
|
+
confirmPassword: fieldSchemas.confirmPassword
|
|
35
|
+
}),
|
|
36
|
+
emailVerification: z.object({
|
|
37
|
+
token: fieldSchemas.token,
|
|
38
|
+
email: z.preprocess(
|
|
39
|
+
(value) => typeof value === "string" ? normalizeEmailFromQueryParam(value) : value,
|
|
40
|
+
fieldSchemas.email
|
|
41
|
+
).optional()
|
|
42
|
+
})
|
|
43
|
+
};
|
|
44
|
+
var formSchemas = {
|
|
45
|
+
login: baseSchemas.login,
|
|
46
|
+
signup: baseSchemas.signupBase.refine((data) => data.password === data.confirmPassword, {
|
|
47
|
+
message: "Passwords do not match",
|
|
48
|
+
path: ["confirmPassword"]
|
|
49
|
+
}),
|
|
50
|
+
forgotPassword: baseSchemas.forgotPassword,
|
|
51
|
+
resetPassword: baseSchemas.resetPasswordBase.refine(
|
|
52
|
+
(data) => data.password === data.confirmPassword,
|
|
53
|
+
{ message: "Passwords do not match", path: ["confirmPassword"] }
|
|
54
|
+
),
|
|
55
|
+
emailVerification: baseSchemas.emailVerification
|
|
56
|
+
};
|
|
57
|
+
var apiSchemas = {
|
|
58
|
+
login: baseSchemas.login,
|
|
59
|
+
signup: z.object({
|
|
60
|
+
email: fieldSchemas.email,
|
|
61
|
+
password: fieldSchemas.password,
|
|
62
|
+
name: fieldSchemas.name.optional(),
|
|
63
|
+
termsAccepted: z.boolean().refine((val) => val === true, "You must accept the terms and conditions"),
|
|
64
|
+
marketingOptIn: z.boolean().optional()
|
|
65
|
+
}),
|
|
66
|
+
forgotPassword: baseSchemas.forgotPassword,
|
|
67
|
+
resetPassword: z.object({
|
|
68
|
+
token: fieldSchemas.token,
|
|
69
|
+
email: fieldSchemas.email,
|
|
70
|
+
password: fieldSchemas.password
|
|
71
|
+
}),
|
|
72
|
+
emailVerification: baseSchemas.emailVerification
|
|
73
|
+
};
|
|
74
|
+
function getPasswordStrength(password) {
|
|
75
|
+
let score = 0;
|
|
76
|
+
if (password.length >= 8) score++;
|
|
77
|
+
if (/[a-z]/.test(password)) score++;
|
|
78
|
+
if (/[A-Z]/.test(password)) score++;
|
|
79
|
+
if (/[0-9]/.test(password)) score++;
|
|
80
|
+
if (/[^A-Za-z0-9]/.test(password)) score++;
|
|
81
|
+
if (!password.toLowerCase().includes("password")) score++;
|
|
82
|
+
if (!password.includes("123")) score++;
|
|
83
|
+
const strength = score >= 6 ? "Strong" : score >= 4 ? "Medium" : "Weak";
|
|
84
|
+
return { score, strength };
|
|
85
|
+
}
|
|
86
|
+
function getPasswordRequirements(password) {
|
|
87
|
+
return {
|
|
88
|
+
length: password.length >= 8 && password.length <= 100,
|
|
89
|
+
lowercase: /[a-z]/.test(password),
|
|
90
|
+
uppercase: /[A-Z]/.test(password),
|
|
91
|
+
number: /[0-9]/.test(password),
|
|
92
|
+
special: /[^A-Za-z0-9]/.test(password),
|
|
93
|
+
noPassword: !password.toLowerCase().includes("password"),
|
|
94
|
+
noSequential: !password.includes("123")
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function validateField(schema, value) {
|
|
98
|
+
const result = schema.safeParse(value);
|
|
99
|
+
return result.success ? null : result.error.issues[0]?.message || "Invalid value";
|
|
100
|
+
}
|
|
101
|
+
function validateForm(schema, data) {
|
|
102
|
+
const result = schema.safeParse(data);
|
|
103
|
+
if (result.success) return { success: true, data: result.data, errors: {} };
|
|
104
|
+
const errors = {};
|
|
105
|
+
result.error.issues.forEach((issue) => {
|
|
106
|
+
const path = issue.path.join(".");
|
|
107
|
+
errors[path] = issue.message;
|
|
108
|
+
});
|
|
109
|
+
return { success: false, data: null, errors };
|
|
110
|
+
}
|
|
111
|
+
var passwordSchema = fieldSchemas.password;
|
|
112
|
+
var loginSchema = apiSchemas.login;
|
|
113
|
+
var signupSchema = apiSchemas.signup;
|
|
114
|
+
var forgotPasswordSchema = apiSchemas.forgotPassword;
|
|
115
|
+
|
|
116
|
+
export { apiSchemas, fieldSchemas, forgotPasswordSchema, formSchemas, getPasswordRequirements, getPasswordStrength, loginSchema, passwordSchema, signupSchema, validateField, validateForm };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function validateEmail(value: string): string | undefined;
|
|
2
|
+
export declare function validatePassword(value: string): string | undefined;
|
|
3
|
+
export declare function validateRequired(fieldName: string): (value: string) => string | undefined;
|
|
4
|
+
//# sourceMappingURL=validators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../src/auth/validators.ts"],"names":[],"mappings":"AAEA,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAO/D;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAUlE;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,IACxC,OAAO,MAAM,KAAG,MAAM,GAAG,SAAS,CAI3C"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { passwordSchema } from '../chunk-WO6FHJHG.js';
|
|
2
|
+
|
|
3
|
+
// src/auth/validators.ts
|
|
4
|
+
function validateEmail(value) {
|
|
5
|
+
if (!value) return "Email is required";
|
|
6
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
7
|
+
if (!emailRegex.test(value)) return "Please enter a valid email address";
|
|
8
|
+
return void 0;
|
|
9
|
+
}
|
|
10
|
+
function validatePassword(value) {
|
|
11
|
+
if (!value) return "Password is required";
|
|
12
|
+
try {
|
|
13
|
+
passwordSchema.parse(value);
|
|
14
|
+
return void 0;
|
|
15
|
+
} catch (error) {
|
|
16
|
+
if (error instanceof Error) return error.message;
|
|
17
|
+
return "Password validation failed";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function validateRequired(fieldName) {
|
|
21
|
+
return (value) => {
|
|
22
|
+
if (!value) return `${fieldName} is required`;
|
|
23
|
+
return void 0;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { validateEmail, validatePassword, validateRequired };
|