@liveartx/authentication 1.0.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 ADDED
@@ -0,0 +1,5 @@
1
+ ## Liveart authentication package
2
+
3
+ #### Install package
4
+
5
+ 1. Provide env variable API_AUTH_SERVICE_URL
@@ -0,0 +1,13 @@
1
+ declare class AuthApiClient {
2
+ private readonly apiAuthServiceUrl;
3
+ constructor();
4
+ loginOrSignUpByEmail(email: string): Promise<void>;
5
+ verifyCode(email: string, code: string): Promise<VerifyCodeResponse>;
6
+ }
7
+ interface VerifyCodeResponse {
8
+ access_token: string;
9
+ token_type: string;
10
+ user_id: string;
11
+ email: string;
12
+ }
13
+ export { AuthApiClient };
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AuthApiClient = void 0;
4
+ const assert_1 = require("~/utils/assert");
5
+ const API_AUTH_SERVICE_URL = process.env.API_AUTH_SERVICE_URL;
6
+ class AuthApiClient {
7
+ apiAuthServiceUrl;
8
+ constructor() {
9
+ (0, assert_1.assert)(!!API_AUTH_SERVICE_URL, 'API_AUTH_SERVICE_URL env is required');
10
+ this.apiAuthServiceUrl = API_AUTH_SERVICE_URL;
11
+ }
12
+ async loginOrSignUpByEmail(email) {
13
+ const response = await fetch(`${this.apiAuthServiceUrl}/auth/email/send-code`, {
14
+ method: 'POST',
15
+ headers: {
16
+ 'Content-Type': 'application/json',
17
+ },
18
+ body: JSON.stringify({ email }),
19
+ });
20
+ (0, assert_1.assert)(!!response.ok, 'Code sending failed');
21
+ }
22
+ async verifyCode(email, code) {
23
+ const response = await fetch(`${this.apiAuthServiceUrl}/auth/email/verify-code`, {
24
+ method: 'POST',
25
+ headers: {
26
+ 'Content-Type': 'application/json',
27
+ },
28
+ body: JSON.stringify({ email, code }),
29
+ });
30
+ (0, assert_1.assert)(!!response.ok, 'Code verification failed');
31
+ const data = await response.json();
32
+ return data;
33
+ }
34
+ }
35
+ exports.AuthApiClient = AuthApiClient;
@@ -0,0 +1,20 @@
1
+ import { AuthApiClient } from '~/api/authApiClient';
2
+ interface AuthTokenData {
3
+ accessToken: string;
4
+ tokenType: string;
5
+ userId: string;
6
+ email: string;
7
+ }
8
+ interface SendCodeResult {
9
+ success: boolean;
10
+ error: string | null;
11
+ }
12
+ interface VerifyCodeResult {
13
+ success: boolean;
14
+ tokenData: AuthTokenData | null;
15
+ error: string | null;
16
+ }
17
+ declare function sendVerificationCode(email: string, authClient: AuthApiClient): Promise<SendCodeResult>;
18
+ declare function verifyCodeAndSaveToken(email: string, code: string, authClient: AuthApiClient, cookieName?: string): Promise<VerifyCodeResult>;
19
+ export { sendVerificationCode, verifyCodeAndSaveToken };
20
+ export type { AuthTokenData, SendCodeResult, VerifyCodeResult };
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.verifyCodeAndSaveToken = exports.sendVerificationCode = void 0;
4
+ const cookieService_1 = require("~/services/cookieService");
5
+ function validateEmail(email) {
6
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
7
+ return emailRegex.test(email);
8
+ }
9
+ function validateCode(code) {
10
+ return code.length > 0;
11
+ }
12
+ function validateEmailInput(email) {
13
+ if (!validateEmail(email)) {
14
+ return { valid: false, error: 'Invalid email format' };
15
+ }
16
+ return { valid: true, error: null };
17
+ }
18
+ function validateVerifyInput(email, code) {
19
+ if (!validateEmail(email)) {
20
+ return { valid: false, error: 'Invalid email format' };
21
+ }
22
+ if (!validateCode(code)) {
23
+ return { valid: false, error: 'Code is required' };
24
+ }
25
+ return { valid: true, error: null };
26
+ }
27
+ function transformVerifyCodeResponse(response) {
28
+ return {
29
+ accessToken: response.access_token,
30
+ tokenType: response.token_type,
31
+ userId: response.user_id,
32
+ email: response.email,
33
+ };
34
+ }
35
+ function createCookieOptions() {
36
+ const maxAge = 60 * 60 * 24 * 30;
37
+ return {
38
+ maxAge,
39
+ path: '/',
40
+ secure: true,
41
+ sameSite: 'lax',
42
+ };
43
+ }
44
+ function saveAuthTokenToCookie(token, cookieName = 'auth_token') {
45
+ const options = createCookieOptions();
46
+ (0, cookieService_1.setCookie)(cookieName, token, options);
47
+ }
48
+ async function sendVerificationCode(email, authClient) {
49
+ const validation = validateEmailInput(email);
50
+ if (!validation.valid) {
51
+ return {
52
+ success: false,
53
+ error: validation.error,
54
+ };
55
+ }
56
+ try {
57
+ await authClient.loginOrSignUpByEmail(email);
58
+ return {
59
+ success: true,
60
+ error: null,
61
+ };
62
+ }
63
+ catch (error) {
64
+ return {
65
+ success: false,
66
+ error: error instanceof Error ? error.message : 'Code sending failed',
67
+ };
68
+ }
69
+ }
70
+ exports.sendVerificationCode = sendVerificationCode;
71
+ async function verifyCodeAndSaveToken(email, code, authClient, cookieName) {
72
+ const validation = validateVerifyInput(email, code);
73
+ if (!validation.valid) {
74
+ return {
75
+ success: false,
76
+ tokenData: null,
77
+ error: validation.error,
78
+ };
79
+ }
80
+ try {
81
+ const response = await authClient.verifyCode(email, code);
82
+ const tokenData = transformVerifyCodeResponse(response);
83
+ saveAuthTokenToCookie(tokenData.accessToken, cookieName);
84
+ return {
85
+ success: true,
86
+ tokenData,
87
+ error: null,
88
+ };
89
+ }
90
+ catch (error) {
91
+ return {
92
+ success: false,
93
+ tokenData: null,
94
+ error: error instanceof Error ? error.message : 'Code verification failed',
95
+ };
96
+ }
97
+ }
98
+ exports.verifyCodeAndSaveToken = verifyCodeAndSaveToken;
package/lib/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './features/signInOrSignUp';
package/lib/index.js ADDED
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./features/signInOrSignUp"), exports);
@@ -0,0 +1,14 @@
1
+ interface CookieOptions {
2
+ expires?: Date;
3
+ maxAge?: number;
4
+ path?: string;
5
+ domain?: string;
6
+ secure?: boolean;
7
+ sameSite?: 'strict' | 'lax' | 'none';
8
+ }
9
+ declare function buildCookieString(name: string, value: string, options?: CookieOptions): string;
10
+ declare function setCookie(name: string, value: string, options?: CookieOptions): void;
11
+ declare function getCookie(name: string): string | null;
12
+ declare function removeCookie(name: string, options?: Omit<CookieOptions, 'expires' | 'maxAge'>): void;
13
+ export { buildCookieString, getCookie, removeCookie, setCookie };
14
+ export type { CookieOptions };
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setCookie = exports.removeCookie = exports.getCookie = exports.buildCookieString = void 0;
4
+ function buildCookieString(name, value, options) {
5
+ const parts = [`${encodeURIComponent(name)}=${encodeURIComponent(value)}`];
6
+ if (options?.expires) {
7
+ parts.push(`expires=${options.expires.toUTCString()}`);
8
+ }
9
+ if (options?.maxAge != null) {
10
+ parts.push(`max-age=${options.maxAge}`);
11
+ }
12
+ if (options?.path) {
13
+ parts.push(`path=${options.path}`);
14
+ }
15
+ if (options?.domain) {
16
+ parts.push(`domain=${options.domain}`);
17
+ }
18
+ if (options?.secure) {
19
+ parts.push('secure');
20
+ }
21
+ if (options?.sameSite) {
22
+ parts.push(`samesite=${options.sameSite}`);
23
+ }
24
+ return parts.join('; ');
25
+ }
26
+ exports.buildCookieString = buildCookieString;
27
+ function setCookie(name, value, options) {
28
+ if (typeof document === 'undefined') {
29
+ return;
30
+ }
31
+ document.cookie = buildCookieString(name, value, options);
32
+ }
33
+ exports.setCookie = setCookie;
34
+ function getCookie(name) {
35
+ if (typeof document === 'undefined') {
36
+ return null;
37
+ }
38
+ const nameEQ = `${encodeURIComponent(name)}=`;
39
+ const cookies = document.cookie.split(';');
40
+ for (const cookie of cookies) {
41
+ const trimmed = cookie.trim();
42
+ if (trimmed.startsWith(nameEQ)) {
43
+ return decodeURIComponent(trimmed.substring(nameEQ.length));
44
+ }
45
+ }
46
+ return null;
47
+ }
48
+ exports.getCookie = getCookie;
49
+ function removeCookie(name, options) {
50
+ setCookie(name, '', {
51
+ ...options,
52
+ expires: new Date(0),
53
+ });
54
+ }
55
+ exports.removeCookie = removeCookie;
@@ -0,0 +1,13 @@
1
+ declare class AuthApiClient {
2
+ private readonly apiAuthServiceUrl;
3
+ constructor();
4
+ loginOrSignUpByEmail(email: string): Promise<void>;
5
+ verifyCode(email: string, code: string): Promise<VerifyCodeResponse>;
6
+ }
7
+ interface VerifyCodeResponse {
8
+ access_token: string;
9
+ token_type: string;
10
+ user_id: string;
11
+ email: string;
12
+ }
13
+ export { AuthApiClient };
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AuthApiClient = void 0;
4
+ const assert_1 = require("../utils/assert");
5
+ const API_AUTH_SERVICE_URL = process.env.API_AUTH_SERVICE_URL;
6
+ class AuthApiClient {
7
+ apiAuthServiceUrl;
8
+ constructor() {
9
+ (0, assert_1.assert)(!!API_AUTH_SERVICE_URL, 'API_AUTH_SERVICE_URL env is required');
10
+ this.apiAuthServiceUrl = API_AUTH_SERVICE_URL;
11
+ }
12
+ async loginOrSignUpByEmail(email) {
13
+ const response = await fetch(`${this.apiAuthServiceUrl}/auth/email/send-code`, {
14
+ method: 'POST',
15
+ headers: {
16
+ 'Content-Type': 'application/json',
17
+ },
18
+ body: JSON.stringify({ email }),
19
+ });
20
+ (0, assert_1.assert)(!!response.ok, 'Code sending failed');
21
+ }
22
+ async verifyCode(email, code) {
23
+ const response = await fetch(`${this.apiAuthServiceUrl}/auth/email/verify-code`, {
24
+ method: 'POST',
25
+ headers: {
26
+ 'Content-Type': 'application/json',
27
+ },
28
+ body: JSON.stringify({ email, code }),
29
+ });
30
+ (0, assert_1.assert)(!!response.ok, 'Code verification failed');
31
+ const data = await response.json();
32
+ return data;
33
+ }
34
+ }
35
+ exports.AuthApiClient = AuthApiClient;
@@ -0,0 +1,20 @@
1
+ import { AuthApiClient } from '../api/authApiClient';
2
+ interface AuthTokenData {
3
+ accessToken: string;
4
+ tokenType: string;
5
+ userId: string;
6
+ email: string;
7
+ }
8
+ interface SendCodeResult {
9
+ success: boolean;
10
+ error: string | null;
11
+ }
12
+ interface VerifyCodeResult {
13
+ success: boolean;
14
+ tokenData: AuthTokenData | null;
15
+ error: string | null;
16
+ }
17
+ declare function sendVerificationCode(email: string, authClient: AuthApiClient): Promise<SendCodeResult>;
18
+ declare function verifyCodeAndSaveToken(email: string, code: string, authClient: AuthApiClient, cookieName?: string): Promise<VerifyCodeResult>;
19
+ export { sendVerificationCode, verifyCodeAndSaveToken };
20
+ export type { AuthTokenData, SendCodeResult, VerifyCodeResult };
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.verifyCodeAndSaveToken = exports.sendVerificationCode = void 0;
4
+ const cookieService_1 = require("../services/cookieService");
5
+ function validateEmail(email) {
6
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
7
+ return emailRegex.test(email);
8
+ }
9
+ function validateCode(code) {
10
+ return code.length > 0;
11
+ }
12
+ function validateEmailInput(email) {
13
+ if (!validateEmail(email)) {
14
+ return { valid: false, error: 'Invalid email format' };
15
+ }
16
+ return { valid: true, error: null };
17
+ }
18
+ function validateVerifyInput(email, code) {
19
+ if (!validateEmail(email)) {
20
+ return { valid: false, error: 'Invalid email format' };
21
+ }
22
+ if (!validateCode(code)) {
23
+ return { valid: false, error: 'Code is required' };
24
+ }
25
+ return { valid: true, error: null };
26
+ }
27
+ function transformVerifyCodeResponse(response) {
28
+ return {
29
+ accessToken: response.access_token,
30
+ tokenType: response.token_type,
31
+ userId: response.user_id,
32
+ email: response.email,
33
+ };
34
+ }
35
+ function createCookieOptions() {
36
+ const maxAge = 60 * 60 * 24 * 30;
37
+ return {
38
+ maxAge,
39
+ path: '/',
40
+ secure: true,
41
+ sameSite: 'lax',
42
+ };
43
+ }
44
+ function saveAuthTokenToCookie(token, cookieName = 'auth_token') {
45
+ const options = createCookieOptions();
46
+ (0, cookieService_1.setCookie)(cookieName, token, options);
47
+ }
48
+ async function sendVerificationCode(email, authClient) {
49
+ const validation = validateEmailInput(email);
50
+ if (!validation.valid) {
51
+ return {
52
+ success: false,
53
+ error: validation.error,
54
+ };
55
+ }
56
+ try {
57
+ await authClient.loginOrSignUpByEmail(email);
58
+ return {
59
+ success: true,
60
+ error: null,
61
+ };
62
+ }
63
+ catch (error) {
64
+ return {
65
+ success: false,
66
+ error: error instanceof Error ? error.message : 'Code sending failed',
67
+ };
68
+ }
69
+ }
70
+ exports.sendVerificationCode = sendVerificationCode;
71
+ async function verifyCodeAndSaveToken(email, code, authClient, cookieName) {
72
+ const validation = validateVerifyInput(email, code);
73
+ if (!validation.valid) {
74
+ return {
75
+ success: false,
76
+ tokenData: null,
77
+ error: validation.error,
78
+ };
79
+ }
80
+ try {
81
+ const response = await authClient.verifyCode(email, code);
82
+ const tokenData = transformVerifyCodeResponse(response);
83
+ saveAuthTokenToCookie(tokenData.accessToken, cookieName);
84
+ return {
85
+ success: true,
86
+ tokenData,
87
+ error: null,
88
+ };
89
+ }
90
+ catch (error) {
91
+ return {
92
+ success: false,
93
+ tokenData: null,
94
+ error: error instanceof Error ? error.message : 'Code verification failed',
95
+ };
96
+ }
97
+ }
98
+ exports.verifyCodeAndSaveToken = verifyCodeAndSaveToken;
@@ -0,0 +1 @@
1
+ export * from './features/signInOrSignUp';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./features/signInOrSignUp"), exports);
@@ -0,0 +1,14 @@
1
+ interface CookieOptions {
2
+ expires?: Date;
3
+ maxAge?: number;
4
+ path?: string;
5
+ domain?: string;
6
+ secure?: boolean;
7
+ sameSite?: 'strict' | 'lax' | 'none';
8
+ }
9
+ declare function buildCookieString(name: string, value: string, options?: CookieOptions): string;
10
+ declare function setCookie(name: string, value: string, options?: CookieOptions): void;
11
+ declare function getCookie(name: string): string | null;
12
+ declare function removeCookie(name: string, options?: Omit<CookieOptions, 'expires' | 'maxAge'>): void;
13
+ export { buildCookieString, getCookie, removeCookie, setCookie };
14
+ export type { CookieOptions };
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setCookie = exports.removeCookie = exports.getCookie = exports.buildCookieString = void 0;
4
+ function buildCookieString(name, value, options) {
5
+ const parts = [`${encodeURIComponent(name)}=${encodeURIComponent(value)}`];
6
+ if (options?.expires) {
7
+ parts.push(`expires=${options.expires.toUTCString()}`);
8
+ }
9
+ if (options?.maxAge != null) {
10
+ parts.push(`max-age=${options.maxAge}`);
11
+ }
12
+ if (options?.path) {
13
+ parts.push(`path=${options.path}`);
14
+ }
15
+ if (options?.domain) {
16
+ parts.push(`domain=${options.domain}`);
17
+ }
18
+ if (options?.secure) {
19
+ parts.push('secure');
20
+ }
21
+ if (options?.sameSite) {
22
+ parts.push(`samesite=${options.sameSite}`);
23
+ }
24
+ return parts.join('; ');
25
+ }
26
+ exports.buildCookieString = buildCookieString;
27
+ function setCookie(name, value, options) {
28
+ if (typeof document === 'undefined') {
29
+ return;
30
+ }
31
+ document.cookie = buildCookieString(name, value, options);
32
+ }
33
+ exports.setCookie = setCookie;
34
+ function getCookie(name) {
35
+ if (typeof document === 'undefined') {
36
+ return null;
37
+ }
38
+ const nameEQ = `${encodeURIComponent(name)}=`;
39
+ const cookies = document.cookie.split(';');
40
+ for (const cookie of cookies) {
41
+ const trimmed = cookie.trim();
42
+ if (trimmed.startsWith(nameEQ)) {
43
+ return decodeURIComponent(trimmed.substring(nameEQ.length));
44
+ }
45
+ }
46
+ return null;
47
+ }
48
+ exports.getCookie = getCookie;
49
+ function removeCookie(name, options) {
50
+ setCookie(name, '', {
51
+ ...options,
52
+ expires: new Date(0),
53
+ });
54
+ }
55
+ exports.removeCookie = removeCookie;
@@ -0,0 +1,2 @@
1
+ declare function assert(condition: boolean, message: string): asserts condition;
2
+ export { assert };
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assert = void 0;
4
+ function assert(condition, message) {
5
+ if (!condition) {
6
+ throw new Error(message);
7
+ }
8
+ }
9
+ exports.assert = assert;
@@ -0,0 +1,2 @@
1
+ declare function assert(condition: boolean, message: string): asserts condition;
2
+ export { assert };
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assert = void 0;
4
+ function assert(condition, message) {
5
+ if (!condition) {
6
+ throw new Error(message);
7
+ }
8
+ }
9
+ exports.assert = assert;
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@liveartx/authentication",
3
+ "version": "1.0.0",
4
+ "description": "LiveArt authentication package",
5
+ "files": [
6
+ "lib/**/*"
7
+ ],
8
+ "main": "lib/index.js",
9
+ "types": "lib/index.d.ts",
10
+ "scripts": {
11
+ "build": "npx tsc --project tsconfig.json && npx tscpaths -p tsconfig.json -s ./src -o ./lib/src",
12
+ "format": "prettier --write \"index.ts\" \"src/**/*.ts\"",
13
+ "lint": "eslint src/ --ext .js,.jsx,.ts,.tsx --max-warnings=0 --fix",
14
+ "check:types": "tsc -p ./tsconfig.json --pretty --noEmit",
15
+ "prepare": "husky install"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+ssh://git@gitlab.com/live-art-project/liveartx-auth.git"
20
+ },
21
+ "author": "",
22
+ "license": "ISC",
23
+ "devDependencies": {
24
+ "@types/node": "^25.0.3",
25
+ "@typescript-eslint/eslint-plugin": "5.31.0",
26
+ "@typescript-eslint/parser": "5.31.0",
27
+ "eslint": "7.32.0",
28
+ "eslint-config-prettier": "8.5.0",
29
+ "eslint-plugin-import": "2.24.1",
30
+ "eslint-plugin-prettier": "3.4.1",
31
+ "eslint-plugin-simple-import-sort": "7.0.0",
32
+ "husky": "8.0.1",
33
+ "prettier": "2.7.1",
34
+ "ts-node": "10.9.2",
35
+ "tscpaths": "0.0.9",
36
+ "typescript": "4.7.4"
37
+ },
38
+ "lint-staged": {
39
+ "**/*.{ts,tsx}": [
40
+ "prettier --write",
41
+ "eslint --fix"
42
+ ]
43
+ }
44
+ }