@startsimpli/auth 0.1.4 → 0.1.5

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,40 +1,19 @@
1
1
  {
2
2
  "name": "@startsimpli/auth",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Shared authentication package for StartSimpli Next.js apps",
5
- "main": "./dist/index.js",
6
- "types": "./dist/index.d.ts",
5
+ "main": "./src/index.ts",
6
+ "types": "./src/index.ts",
7
7
  "exports": {
8
- ".": {
9
- "types": "./dist/index.d.ts",
10
- "import": "./dist/index.mjs",
11
- "require": "./dist/index.js"
12
- },
13
- "./client": {
14
- "types": "./dist/client/index.d.ts",
15
- "import": "./dist/client/index.mjs",
16
- "require": "./dist/client/index.js"
17
- },
18
- "./server": {
19
- "types": "./dist/server/index.d.ts",
20
- "import": "./dist/server/index.mjs",
21
- "require": "./dist/server/index.js"
22
- },
23
- "./types": {
24
- "types": "./dist/types/index.d.ts",
25
- "import": "./dist/types/index.mjs",
26
- "require": "./dist/types/index.js"
27
- },
28
- "./email": {
29
- "types": "./dist/email/index.d.ts",
30
- "import": "./dist/email/index.mjs",
31
- "require": "./dist/email/index.js"
32
- }
8
+ ".": "./src/index.ts",
9
+ "./client": "./src/client/index.ts",
10
+ "./server": "./src/server/index.ts",
11
+ "./types": "./src/types/index.ts",
12
+ "./email": "./src/email/index.ts"
33
13
  },
34
14
  "files": [
35
15
  "src",
36
- "README.md",
37
- "dist"
16
+ "README.md"
38
17
  ],
39
18
  "publishConfig": {
40
19
  "access": "public"
@@ -70,6 +49,5 @@
70
49
  ],
71
50
  "dependencies": {
72
51
  "zod": "^4.3.6"
73
- },
74
- "module": "./dist/index.mjs"
52
+ }
75
53
  }
@@ -1,134 +0,0 @@
1
- // src/utils/token.ts
2
- function decodeToken(token) {
3
- try {
4
- const parts = token.split(".");
5
- if (parts.length !== 3) {
6
- return null;
7
- }
8
- const payload = parts[1];
9
- const decoded = JSON.parse(atob(payload));
10
- return decoded;
11
- } catch (error) {
12
- console.error("Failed to decode token:", error);
13
- return null;
14
- }
15
- }
16
- function isTokenExpired(token) {
17
- const payload = decodeToken(token);
18
- if (!payload) {
19
- return true;
20
- }
21
- const now = Math.floor(Date.now() / 1e3);
22
- return payload.exp <= now;
23
- }
24
- function getTokenExpiresAt(token) {
25
- const payload = decodeToken(token);
26
- if (!payload) {
27
- return null;
28
- }
29
- return payload.exp * 1e3;
30
- }
31
- function getTokenPayload(token) {
32
- try {
33
- const parts = token.split(".");
34
- if (parts.length !== 3) {
35
- return null;
36
- }
37
- const payload = parts[1];
38
- const decoded = JSON.parse(atob(payload));
39
- if (typeof decoded !== "object" || decoded === null) {
40
- return null;
41
- }
42
- return decoded;
43
- } catch {
44
- return null;
45
- }
46
- }
47
- function shouldRefreshToken(token) {
48
- const expiresAt = getTokenExpiresAt(token);
49
- if (!expiresAt) {
50
- return true;
51
- }
52
- const now = Date.now();
53
- const timeUntilExpiry = expiresAt - now;
54
- const FIVE_MINUTES = 5 * 60 * 1e3;
55
- return timeUntilExpiry < FIVE_MINUTES;
56
- }
57
-
58
- // src/utils/cookies.ts
59
- function getCookie(name) {
60
- if (typeof document === "undefined") {
61
- return null;
62
- }
63
- const value = `; ${document.cookie}`;
64
- const parts = value.split(`; ${name}=`);
65
- if (parts.length === 2) {
66
- return parts.pop()?.split(";").shift() || null;
67
- }
68
- return null;
69
- }
70
- function setCookie(name, value, options = {}) {
71
- if (typeof document === "undefined") {
72
- return;
73
- }
74
- const {
75
- maxAge,
76
- path = "/",
77
- domain,
78
- secure = true,
79
- sameSite = "lax"
80
- } = options;
81
- let cookie = `${name}=${value}`;
82
- if (maxAge) {
83
- cookie += `; Max-Age=${maxAge}`;
84
- }
85
- cookie += `; Path=${path}`;
86
- if (domain) {
87
- cookie += `; Domain=${domain}`;
88
- }
89
- if (secure) {
90
- cookie += "; Secure";
91
- }
92
- cookie += `; SameSite=${sameSite}`;
93
- document.cookie = cookie;
94
- }
95
- function getCsrfToken() {
96
- return getCookie("csrftoken");
97
- }
98
- function deleteCookie(name, path = "/") {
99
- if (typeof document === "undefined") {
100
- return;
101
- }
102
- document.cookie = `${name}=; Path=${path}; Expires=Thu, 01 Jan 1970 00:00:00 GMT`;
103
- }
104
-
105
- // src/validation/index.ts
106
- var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
107
- function validateEmail(email) {
108
- return EMAIL_REGEX.test(email);
109
- }
110
- function validatePassword(password) {
111
- if (password.length < 8) {
112
- return { isValid: false, error: "Password must be at least 8 characters" };
113
- }
114
- if (!/[A-Z]/.test(password)) {
115
- return { isValid: false, error: "Password must contain at least one uppercase letter" };
116
- }
117
- if (!/[a-z]/.test(password)) {
118
- return { isValid: false, error: "Password must contain at least one lowercase letter" };
119
- }
120
- if (!/[0-9]/.test(password)) {
121
- return { isValid: false, error: "Password must contain at least one number" };
122
- }
123
- return { isValid: true };
124
- }
125
- function validatePasswordConfirm(password, confirm) {
126
- if (password !== confirm) {
127
- return { isValid: false, error: "Passwords do not match" };
128
- }
129
- return validatePassword(password);
130
- }
131
-
132
- export { EMAIL_REGEX, decodeToken, deleteCookie, getCookie, getCsrfToken, getTokenExpiresAt, getTokenPayload, isTokenExpired, setCookie, shouldRefreshToken, validateEmail, validatePassword, validatePasswordConfirm };
133
- //# sourceMappingURL=chunk-AADTGAI2.mjs.map
134
- //# sourceMappingURL=chunk-AADTGAI2.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/token.ts","../src/utils/cookies.ts","../src/validation/index.ts"],"names":[],"mappings":"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","file":"chunk-AADTGAI2.mjs","sourcesContent":["/**\n * JWT token utilities\n */\n\nimport type { TokenPayload, DecodedToken } from '../types';\n\n/**\n * Decode JWT token payload (does NOT verify signature)\n */\nexport function decodeToken(token: string): TokenPayload | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) {\n return null;\n }\n\n const payload = parts[1];\n const decoded = JSON.parse(atob(payload));\n return decoded as TokenPayload;\n } catch (error) {\n console.error('Failed to decode token:', error);\n return null;\n }\n}\n\n/**\n * Check if token is expired\n */\nexport function isTokenExpired(token: string): boolean {\n const payload = decodeToken(token);\n if (!payload) {\n return true;\n }\n\n const now = Math.floor(Date.now() / 1000);\n return payload.exp <= now;\n}\n\n/**\n * Get token expiration time in milliseconds\n */\nexport function getTokenExpiresAt(token: string): number | null {\n const payload = decodeToken(token);\n if (!payload) {\n return null;\n }\n\n return payload.exp * 1000;\n}\n\n/**\n * Get raw JWT payload as a generic record — framework and backend agnostic.\n * Does NOT verify the signature; use only for reading claims client-side.\n */\nexport function getTokenPayload(token: string): DecodedToken | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) {\n return null;\n }\n\n const payload = parts[1];\n const decoded = JSON.parse(atob(payload));\n\n if (typeof decoded !== 'object' || decoded === null) {\n return null;\n }\n\n return decoded as DecodedToken;\n } catch {\n return null;\n }\n}\n\n/**\n * Check if token needs refresh (expires in less than 5 minutes)\n */\nexport function shouldRefreshToken(token: string): boolean {\n const expiresAt = getTokenExpiresAt(token);\n if (!expiresAt) {\n return true;\n }\n\n const now = Date.now();\n const timeUntilExpiry = expiresAt - now;\n const FIVE_MINUTES = 5 * 60 * 1000;\n\n return timeUntilExpiry < FIVE_MINUTES;\n}\n","/**\n * Cookie utilities for client-side access\n */\n\n/**\n * Get cookie value by name\n */\nexport function getCookie(name: string): string | null {\n if (typeof document === 'undefined') {\n return null;\n }\n\n const value = `; ${document.cookie}`;\n const parts = value.split(`; ${name}=`);\n\n if (parts.length === 2) {\n return parts.pop()?.split(';').shift() || null;\n }\n\n return null;\n}\n\n/**\n * Set cookie with options\n */\nexport function setCookie(\n name: string,\n value: string,\n options: {\n maxAge?: number;\n path?: string;\n domain?: string;\n secure?: boolean;\n sameSite?: 'strict' | 'lax' | 'none';\n } = {}\n): void {\n if (typeof document === 'undefined') {\n return;\n }\n\n const {\n maxAge,\n path = '/',\n domain,\n secure = true,\n sameSite = 'lax',\n } = options;\n\n let cookie = `${name}=${value}`;\n\n if (maxAge) {\n cookie += `; Max-Age=${maxAge}`;\n }\n\n cookie += `; Path=${path}`;\n\n if (domain) {\n cookie += `; Domain=${domain}`;\n }\n\n if (secure) {\n cookie += '; Secure';\n }\n\n cookie += `; SameSite=${sameSite}`;\n\n document.cookie = cookie;\n}\n\n/**\n * Get the Django CSRF token from cookies\n */\nexport function getCsrfToken(): string | null {\n return getCookie('csrftoken');\n}\n\n/**\n * Delete cookie by name\n */\nexport function deleteCookie(name: string, path: string = '/'): void {\n if (typeof document === 'undefined') {\n return;\n }\n\n document.cookie = `${name}=; Path=${path}; Expires=Thu, 01 Jan 1970 00:00:00 GMT`;\n}\n","export const EMAIL_REGEX = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\nexport function validateEmail(email: string): boolean {\n return EMAIL_REGEX.test(email);\n}\n\nexport interface PasswordValidationResult {\n isValid: boolean;\n error?: string;\n}\n\n// Canonical password rules for all StartSimpli apps\nexport function validatePassword(password: string): PasswordValidationResult {\n if (password.length < 8) {\n return { isValid: false, error: 'Password must be at least 8 characters' };\n }\n if (!/[A-Z]/.test(password)) {\n return { isValid: false, error: 'Password must contain at least one uppercase letter' };\n }\n if (!/[a-z]/.test(password)) {\n return { isValid: false, error: 'Password must contain at least one lowercase letter' };\n }\n if (!/[0-9]/.test(password)) {\n return { isValid: false, error: 'Password must contain at least one number' };\n }\n return { isValid: true };\n}\n\nexport function validatePasswordConfirm(password: string, confirm: string): PasswordValidationResult {\n if (password !== confirm) {\n return { isValid: false, error: 'Passwords do not match' };\n }\n return validatePassword(password);\n}\n"]}
@@ -1,37 +0,0 @@
1
- // src/types/index.ts
2
- var ROLE_HIERARCHY = {
3
- owner: 4,
4
- admin: 3,
5
- member: 2,
6
- viewer: 1
7
- };
8
- function hasRolePermission(userRole, requiredRole) {
9
- return ROLE_HIERARCHY[userRole] >= ROLE_HIERARCHY[requiredRole];
10
- }
11
- var PasswordErrorCode = /* @__PURE__ */ ((PasswordErrorCode2) => {
12
- PasswordErrorCode2["TOO_SHORT"] = "password_too_short";
13
- PasswordErrorCode2["TOO_COMMON"] = "password_too_common";
14
- PasswordErrorCode2["ENTIRELY_NUMERIC"] = "password_entirely_numeric";
15
- PasswordErrorCode2["TOO_SIMILAR"] = "password_too_similar";
16
- PasswordErrorCode2["MISMATCH"] = "password_mismatch";
17
- PasswordErrorCode2["REQUIRED"] = "password_required";
18
- return PasswordErrorCode2;
19
- })(PasswordErrorCode || {});
20
- var EmailErrorCode = /* @__PURE__ */ ((EmailErrorCode2) => {
21
- EmailErrorCode2["INVALID_FORMAT"] = "email_invalid_format";
22
- EmailErrorCode2["REQUIRED"] = "email_required";
23
- EmailErrorCode2["NOT_FOUND"] = "email_not_found";
24
- EmailErrorCode2["ALREADY_EXISTS"] = "email_already_exists";
25
- return EmailErrorCode2;
26
- })(EmailErrorCode || {});
27
- var ValidationErrorCode = /* @__PURE__ */ ((ValidationErrorCode2) => {
28
- ValidationErrorCode2["REQUIRED"] = "required";
29
- ValidationErrorCode2["INVALID"] = "invalid";
30
- ValidationErrorCode2["TOO_SHORT"] = "too_short";
31
- ValidationErrorCode2["TOO_LONG"] = "too_long";
32
- return ValidationErrorCode2;
33
- })(ValidationErrorCode || {});
34
-
35
- export { EmailErrorCode, PasswordErrorCode, ROLE_HIERARCHY, ValidationErrorCode, hasRolePermission };
36
- //# sourceMappingURL=chunk-QAXZGJNQ.mjs.map
37
- //# sourceMappingURL=chunk-QAXZGJNQ.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/types/index.ts"],"names":["PasswordErrorCode","EmailErrorCode","ValidationErrorCode"],"mappings":";AA8HO,IAAM,cAAA,GAA8C;AAAA,EACzD,KAAA,EAAO,CAAA;AAAA,EACP,KAAA,EAAO,CAAA;AAAA,EACP,MAAA,EAAQ,CAAA;AAAA,EACR,MAAA,EAAQ;AACV;AAKO,SAAS,iBAAA,CACd,UACA,YAAA,EACS;AACT,EAAA,OAAO,cAAA,CAAe,QAAQ,CAAA,IAAK,cAAA,CAAe,YAAY,CAAA;AAChE;AAyEO,IAAK,iBAAA,qBAAAA,kBAAAA,KAAL;AACL,EAAAA,mBAAA,WAAA,CAAA,GAAY,oBAAA;AACZ,EAAAA,mBAAA,YAAA,CAAA,GAAa,qBAAA;AACb,EAAAA,mBAAA,kBAAA,CAAA,GAAmB,2BAAA;AACnB,EAAAA,mBAAA,aAAA,CAAA,GAAc,sBAAA;AACd,EAAAA,mBAAA,UAAA,CAAA,GAAW,mBAAA;AACX,EAAAA,mBAAA,UAAA,CAAA,GAAW,mBAAA;AAND,EAAA,OAAAA,kBAAAA;AAAA,CAAA,EAAA,iBAAA,IAAA,EAAA;AAYL,IAAK,cAAA,qBAAAC,eAAAA,KAAL;AACL,EAAAA,gBAAA,gBAAA,CAAA,GAAiB,sBAAA;AACjB,EAAAA,gBAAA,UAAA,CAAA,GAAW,gBAAA;AACX,EAAAA,gBAAA,WAAA,CAAA,GAAY,iBAAA;AACZ,EAAAA,gBAAA,gBAAA,CAAA,GAAiB,sBAAA;AAJP,EAAA,OAAAA,eAAAA;AAAA,CAAA,EAAA,cAAA,IAAA,EAAA;AAUL,IAAK,mBAAA,qBAAAC,oBAAAA,KAAL;AACL,EAAAA,qBAAA,UAAA,CAAA,GAAW,UAAA;AACX,EAAAA,qBAAA,SAAA,CAAA,GAAU,SAAA;AACV,EAAAA,qBAAA,WAAA,CAAA,GAAY,WAAA;AACZ,EAAAA,qBAAA,UAAA,CAAA,GAAW,UAAA;AAJD,EAAA,OAAAA,oBAAAA;AAAA,CAAA,EAAA,mBAAA,IAAA,EAAA","file":"chunk-QAXZGJNQ.mjs","sourcesContent":["/**\n * Authentication types for StartSimpli apps\n */\n\n/**\n * Generic token pair (access + optional refresh)\n */\nexport interface TokenPair {\n access: string;\n refresh?: string;\n}\n\n/**\n * Generic decoded JWT payload — framework and backend agnostic\n */\nexport interface DecodedToken {\n sub?: string;\n email?: string;\n exp?: number;\n iat?: number;\n [key: string]: unknown;\n}\n\n/**\n * Generic auth session — framework agnostic\n */\nexport interface AuthSession {\n user: {\n id: string;\n email: string;\n [key: string]: unknown;\n };\n accessToken: string;\n refreshToken?: string;\n}\n\n/**\n * User profile from Django backend\n */\nexport interface AuthUser {\n id: string;\n email: string;\n firstName: string;\n lastName: string;\n isEmailVerified: boolean;\n createdAt: string;\n updatedAt: string;\n // Company/team context (if applicable)\n companies?: Array<{\n id: string;\n name: string;\n role: 'owner' | 'admin' | 'member' | 'viewer';\n }>;\n currentCompanyId?: string;\n}\n\n/**\n * JWT token payload structure\n */\nexport interface TokenPayload {\n token_type: 'access';\n exp: number;\n iat: number;\n jti: string;\n user_id: string;\n}\n\n/**\n * Session data stored in client\n */\nexport interface Session {\n user: AuthUser;\n accessToken: string;\n expiresAt: number;\n}\n\n/**\n * Login response from Django backend\n */\nexport interface LoginResponse {\n access: string;\n user: AuthUser;\n}\n\n/**\n * Token refresh response\n */\nexport interface RefreshResponse {\n access: string;\n}\n\n/**\n * Permission check result\n */\nexport interface PermissionCheck {\n hasPermission: boolean;\n reason?: string;\n}\n\n/**\n * Auth configuration options\n */\nexport interface AuthConfig {\n apiBaseUrl: string;\n tokenRefreshInterval?: number; // milliseconds, default 4 minutes\n onSessionExpired?: () => void;\n onUnauthorized?: () => void;\n}\n\n/**\n * Auth state for React context\n */\nexport interface AuthState {\n session: Session | null;\n isLoading: boolean;\n isAuthenticated: boolean;\n}\n\n/**\n * Company role hierarchy\n */\nexport type CompanyRole = 'owner' | 'admin' | 'member' | 'viewer';\n\n/**\n * Role hierarchy map (higher number = more permissions)\n */\nexport const ROLE_HIERARCHY: Record<CompanyRole, number> = {\n owner: 4,\n admin: 3,\n member: 2,\n viewer: 1,\n};\n\n/**\n * Check if role has sufficient permissions\n */\nexport function hasRolePermission(\n userRole: CompanyRole,\n requiredRole: CompanyRole\n): boolean {\n return ROLE_HIERARCHY[userRole] >= ROLE_HIERARCHY[requiredRole];\n}\n\n/**\n * Password reset request payload\n * Initiates password reset flow by sending reset email\n */\nexport interface PasswordResetRequest {\n email: string;\n clientMetadata?: Record<string, any>;\n}\n\n/**\n * Password reset confirmation payload\n * Completes password reset with token and new password\n */\nexport interface PasswordResetConfirm {\n token: string;\n password: string;\n passwordConfirm: string;\n}\n\n/**\n * Email verification request payload\n * Verifies user email with token from verification email\n */\nexport interface EmailVerificationRequest {\n token: string;\n}\n\n/**\n * Email verification response\n * Returns updated user data after successful verification\n */\nexport interface EmailVerificationResponse {\n detail: string;\n user: {\n id: string;\n email: string;\n isEmailVerified: boolean;\n };\n}\n\n/**\n * API error response from Django backend\n * Standard error format for all API errors\n */\nexport interface ApiErrorResponse {\n detail?: string;\n message?: string;\n errors?: Record<string, string[]>;\n code?: string;\n status?: number;\n}\n\n/**\n * Validation error detail\n * Individual field validation error\n */\nexport interface ValidationError {\n field: string;\n message: string;\n code?: string;\n}\n\n/**\n * Validation errors map\n * Maps field names to error messages\n */\nexport type ValidationErrorsMap = Record<string, string[]>;\n\n/**\n * Password validation error codes\n */\nexport enum PasswordErrorCode {\n TOO_SHORT = 'password_too_short',\n TOO_COMMON = 'password_too_common',\n ENTIRELY_NUMERIC = 'password_entirely_numeric',\n TOO_SIMILAR = 'password_too_similar',\n MISMATCH = 'password_mismatch',\n REQUIRED = 'password_required',\n}\n\n/**\n * Email validation error codes\n */\nexport enum EmailErrorCode {\n INVALID_FORMAT = 'email_invalid_format',\n REQUIRED = 'email_required',\n NOT_FOUND = 'email_not_found',\n ALREADY_EXISTS = 'email_already_exists',\n}\n\n/**\n * General validation error codes\n */\nexport enum ValidationErrorCode {\n REQUIRED = 'required',\n INVALID = 'invalid',\n TOO_SHORT = 'too_short',\n TOO_LONG = 'too_long',\n}\n"]}