@nons-dev/sdk-react 1.0.3

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.
@@ -0,0 +1,8 @@
1
+ import { AuthModule } from './modules/auth.module';
2
+ import { NonsClientConfig } from './types/config.types';
3
+ export declare class NonsClient {
4
+ private http;
5
+ private tokenManager;
6
+ readonly auth: AuthModule;
7
+ constructor(config: NonsClientConfig);
8
+ }
package/dist/client.js ADDED
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NonsClient = void 0;
4
+ const http_1 = require("./core/http");
5
+ const token_manager_1 = require("./core/token-manager");
6
+ const auth_module_1 = require("./modules/auth.module");
7
+ class MemoryStorageAdapter {
8
+ accessToken = null;
9
+ refreshToken = null;
10
+ getAccessToken() { return this.accessToken; }
11
+ setAccessToken(token) { this.accessToken = token; }
12
+ getRefreshToken() { return this.refreshToken; }
13
+ setRefreshToken(token) { this.refreshToken = token; }
14
+ clearTokens() {
15
+ this.accessToken = null;
16
+ this.refreshToken = null;
17
+ }
18
+ }
19
+ class NonsClient {
20
+ http;
21
+ tokenManager;
22
+ auth;
23
+ constructor(config) {
24
+ const storage = config.storage || new MemoryStorageAdapter();
25
+ this.tokenManager = new token_manager_1.TokenManager(storage);
26
+ this.http = new http_1.HttpClient({
27
+ baseUrl: config.baseUrl,
28
+ timeout: config.timeout ?? 10000,
29
+ tokenManager: this.tokenManager,
30
+ onUnauthorized: config.onUnauthorized,
31
+ });
32
+ this.auth = new auth_module_1.AuthModule(this.http, config.baseUrl);
33
+ }
34
+ }
35
+ exports.NonsClient = NonsClient;
36
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":";;;AAAA,sCAAyC;AACzC,wDAAoD;AACpD,uDAAmD;AAGnD,MAAM,oBAAoB;IAChB,WAAW,GAAkB,IAAI,CAAC;IAClC,YAAY,GAAkB,IAAI,CAAC;IAE3C,cAAc,KAAK,OAAO,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;IAC7C,cAAc,CAAC,KAAa,IAAI,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC;IAC3D,eAAe,KAAK,OAAO,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;IAC/C,eAAe,CAAC,KAAa,IAAI,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC;IAC7D,WAAW;QACT,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;IAC3B,CAAC;CACF;AAED,MAAa,UAAU;IACb,IAAI,CAAa;IACjB,YAAY,CAAe;IAE1B,IAAI,CAAa;IAE1B,YAAY,MAAwB;QAClC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,IAAI,oBAAoB,EAAE,CAAC;QAC7D,IAAI,CAAC,YAAY,GAAG,IAAI,4BAAY,CAAC,OAAO,CAAC,CAAC;QAE9C,IAAI,CAAC,IAAI,GAAG,IAAI,iBAAU,CAAC;YACzB,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,KAAK;YAChC,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,cAAc,EAAE,MAAM,CAAC,cAAc;SACtC,CAAC,CAAC;QAEH,IAAI,CAAC,IAAI,GAAG,IAAI,wBAAU,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACxD,CAAC;CACF;AAnBD,gCAmBC"}
@@ -0,0 +1,18 @@
1
+ export declare enum ErrorCode {
2
+ UNAUTHORIZED = "UNAUTHORIZED",
3
+ TOKEN_EXPIRED = "TOKEN_EXPIRED",
4
+ INVALID_CREDENTIALS = "INVALID_CREDENTIALS",
5
+ VALIDATION_ERROR = "VALIDATION_ERROR",
6
+ SERVER_ERROR = "SERVER_ERROR",
7
+ NETWORK_ERROR = "NETWORK_ERROR",
8
+ UNKNOWN = "UNKNOWN"
9
+ }
10
+ export declare class NonsError extends Error {
11
+ readonly code: ErrorCode | string;
12
+ readonly statusCode: number;
13
+ readonly details?: unknown | undefined;
14
+ constructor(code: ErrorCode | string, message: string, statusCode: number, details?: unknown | undefined);
15
+ isAuthError(): boolean;
16
+ isValidationError(): boolean;
17
+ }
18
+ export declare function parseErrorResponse(response: Response): Promise<NonsError>;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NonsError = exports.ErrorCode = void 0;
4
+ exports.parseErrorResponse = parseErrorResponse;
5
+ var ErrorCode;
6
+ (function (ErrorCode) {
7
+ ErrorCode["UNAUTHORIZED"] = "UNAUTHORIZED";
8
+ ErrorCode["TOKEN_EXPIRED"] = "TOKEN_EXPIRED";
9
+ ErrorCode["INVALID_CREDENTIALS"] = "INVALID_CREDENTIALS";
10
+ ErrorCode["VALIDATION_ERROR"] = "VALIDATION_ERROR";
11
+ ErrorCode["SERVER_ERROR"] = "SERVER_ERROR";
12
+ ErrorCode["NETWORK_ERROR"] = "NETWORK_ERROR";
13
+ ErrorCode["UNKNOWN"] = "UNKNOWN";
14
+ })(ErrorCode || (exports.ErrorCode = ErrorCode = {}));
15
+ class NonsError extends Error {
16
+ code;
17
+ statusCode;
18
+ details;
19
+ constructor(code, message, statusCode, details) {
20
+ super(message);
21
+ this.code = code;
22
+ this.statusCode = statusCode;
23
+ this.details = details;
24
+ this.name = 'NonsError';
25
+ Object.setPrototypeOf(this, NonsError.prototype);
26
+ }
27
+ isAuthError() {
28
+ return this.statusCode === 401 || this.code === ErrorCode.UNAUTHORIZED;
29
+ }
30
+ isValidationError() {
31
+ return this.statusCode === 422 || this.code === ErrorCode.VALIDATION_ERROR;
32
+ }
33
+ }
34
+ exports.NonsError = NonsError;
35
+ async function parseErrorResponse(response) {
36
+ let code = ErrorCode.UNKNOWN;
37
+ let message = 'خطای ناشناخته';
38
+ let details;
39
+ try {
40
+ const body = await response.json();
41
+ code = body.code || (body.error && body.error.code) || ErrorCode.UNKNOWN;
42
+ message = body.message || (body.error && body.error.message) || message;
43
+ details = body.details || (body.error && body.error.details);
44
+ }
45
+ catch {
46
+ message = `خطای سرور — کد ${response.status}`;
47
+ }
48
+ return new NonsError(code, message, response.status, details);
49
+ }
50
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":";;;AA+BA,gDAeC;AA9CD,IAAY,SAQX;AARD,WAAY,SAAS;IACnB,0CAAoC,CAAA;IACpC,4CAAqC,CAAA;IACrC,wDAA2C,CAAA;IAC3C,kDAAwC,CAAA;IACxC,0CAAoC,CAAA;IACpC,4CAAqC,CAAA;IACrC,gCAA+B,CAAA;AACjC,CAAC,EARW,SAAS,yBAAT,SAAS,QAQpB;AAED,MAAa,SAAU,SAAQ,KAAK;IAEhB;IAEA;IACA;IAJlB,YACkB,IAAwB,EACxC,OAAe,EACC,UAAkB,EAClB,OAAiB;QAEjC,KAAK,CAAC,OAAO,CAAC,CAAC;QALC,SAAI,GAAJ,IAAI,CAAoB;QAExB,eAAU,GAAV,UAAU,CAAQ;QAClB,YAAO,GAAP,OAAO,CAAU;QAGjC,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACnD,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,UAAU,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,YAAY,CAAC;IACzE,CAAC;IAED,iBAAiB;QACf,OAAO,IAAI,CAAC,UAAU,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,gBAAgB,CAAC;IAC7E,CAAC;CACF;AAnBD,8BAmBC;AAEM,KAAK,UAAU,kBAAkB,CAAC,QAAkB;IACzD,IAAI,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC;IAC7B,IAAI,OAAO,GAAG,eAAe,CAAC;IAC9B,IAAI,OAAgB,CAAC;IAErB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,OAAO,CAAC;QACzE,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC;QACxE,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,kBAAkB,QAAQ,CAAC,MAAM,EAAE,CAAC;IAChD,CAAC;IAED,OAAO,IAAI,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { HttpClientConfig } from '../types/config.types';
2
+ export declare class HttpClient {
3
+ private baseUrl;
4
+ private timeout;
5
+ private tokenManager;
6
+ private onUnauthorized?;
7
+ constructor(config: HttpClientConfig);
8
+ request<T>(path: string, options?: RequestInit): Promise<T>;
9
+ get<T>(path: string, params?: Record<string, unknown>): Promise<T>;
10
+ post<T>(path: string, body?: unknown): Promise<T>;
11
+ put<T>(path: string, body?: unknown): Promise<T>;
12
+ patch<T>(path: string, body?: unknown): Promise<T>;
13
+ delete<T>(path: string): Promise<T>;
14
+ }
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HttpClient = void 0;
4
+ const errors_1 = require("./errors");
5
+ class HttpClient {
6
+ baseUrl;
7
+ timeout;
8
+ tokenManager;
9
+ onUnauthorized;
10
+ constructor(config) {
11
+ this.baseUrl = config.baseUrl;
12
+ this.timeout = config.timeout ?? 10000;
13
+ this.tokenManager = config.tokenManager;
14
+ this.onUnauthorized = config.onUnauthorized;
15
+ }
16
+ async request(path, options = {}) {
17
+ const token = await this.tokenManager.getAccessToken();
18
+ const headers = {
19
+ 'Content-Type': 'application/json',
20
+ ...(options.headers || {}),
21
+ };
22
+ if (token) {
23
+ headers['Authorization'] = `Bearer ${token}`;
24
+ }
25
+ const controller = new AbortController();
26
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
27
+ let response;
28
+ try {
29
+ response = await fetch(`${this.baseUrl}${path}`, {
30
+ credentials: 'include',
31
+ ...options,
32
+ headers,
33
+ signal: controller.signal,
34
+ });
35
+ }
36
+ catch (err) {
37
+ if (err.name === 'AbortError') {
38
+ throw new errors_1.NonsError(errors_1.ErrorCode.NETWORK_ERROR, 'درخواست به timeout رسید', 0);
39
+ }
40
+ throw new errors_1.NonsError(errors_1.ErrorCode.NETWORK_ERROR, 'خطا در اتصال به سرور', 0);
41
+ }
42
+ finally {
43
+ clearTimeout(timeoutId);
44
+ }
45
+ if (response.status === 401) {
46
+ const newToken = await this.tokenManager.refresh(this.baseUrl);
47
+ if (newToken) {
48
+ headers['Authorization'] = `Bearer ${newToken}`;
49
+ response = await fetch(`${this.baseUrl}${path}`, { credentials: 'include', ...options, headers });
50
+ }
51
+ else {
52
+ if (this.onUnauthorized) {
53
+ this.onUnauthorized();
54
+ }
55
+ throw new errors_1.NonsError(errors_1.ErrorCode.UNAUTHORIZED, 'لطفاً دوباره وارد شوید', 401);
56
+ }
57
+ }
58
+ if (response.ok) {
59
+ if (response.status === 204)
60
+ return undefined;
61
+ return response.json();
62
+ }
63
+ throw await (0, errors_1.parseErrorResponse)(response);
64
+ }
65
+ get(path, params) {
66
+ const url = params ? `${path}?${new URLSearchParams(params)}` : path;
67
+ return this.request(url, { method: 'GET' });
68
+ }
69
+ post(path, body) {
70
+ return this.request(path, { method: 'POST', body: JSON.stringify(body) });
71
+ }
72
+ put(path, body) {
73
+ return this.request(path, { method: 'PUT', body: JSON.stringify(body) });
74
+ }
75
+ patch(path, body) {
76
+ return this.request(path, { method: 'PATCH', body: JSON.stringify(body) });
77
+ }
78
+ delete(path) {
79
+ return this.request(path, { method: 'DELETE' });
80
+ }
81
+ }
82
+ exports.HttpClient = HttpClient;
83
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/core/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { StorageAdapter } from '../types/config.types';
2
+ export declare class TokenManager {
3
+ private storage;
4
+ constructor(storage: StorageAdapter);
5
+ getAccessToken(): Promise<string | null>;
6
+ setTokens(accessToken: string, refreshToken: string): Promise<void>;
7
+ clearTokens(): Promise<void>;
8
+ refresh(baseUrl: string): Promise<string | null>;
9
+ }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TokenManager = void 0;
4
+ class TokenManager {
5
+ storage;
6
+ constructor(storage) {
7
+ this.storage = storage;
8
+ }
9
+ async getAccessToken() {
10
+ return this.storage.getAccessToken();
11
+ }
12
+ async setTokens(accessToken, refreshToken) {
13
+ await this.storage.setAccessToken(accessToken);
14
+ await this.storage.setRefreshToken(refreshToken);
15
+ }
16
+ async clearTokens() {
17
+ await this.storage.clearTokens();
18
+ }
19
+ async refresh(baseUrl) {
20
+ const refreshToken = await this.storage.getRefreshToken();
21
+ if (!refreshToken)
22
+ return null;
23
+ try {
24
+ const response = await fetch(`${baseUrl}/v1/auth/refresh`, {
25
+ method: 'POST',
26
+ headers: { 'Content-Type': 'application/json' },
27
+ body: JSON.stringify({ refreshToken }),
28
+ });
29
+ if (!response.ok) {
30
+ await this.storage.clearTokens();
31
+ return null;
32
+ }
33
+ const data = await response.json();
34
+ await this.setTokens(data.accessToken, data.refreshToken);
35
+ return data.accessToken;
36
+ }
37
+ catch {
38
+ await this.storage.clearTokens();
39
+ return null;
40
+ }
41
+ }
42
+ }
43
+ exports.TokenManager = TokenManager;
44
+ //# sourceMappingURL=token-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-manager.js","sourceRoot":"","sources":["../../src/core/token-manager.ts"],"names":[],"mappings":";;;AAEA,MAAa,YAAY;IACH;IAApB,YAAoB,OAAuB;QAAvB,YAAO,GAAP,OAAO,CAAgB;IAAG,CAAC;IAE/C,KAAK,CAAC,cAAc;QAClB,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,WAAmB,EAAE,YAAoB;QACvD,MAAM,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;QAC/C,MAAM,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,WAAW;QACf,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAe;QAC3B,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;QAC1D,IAAI,CAAC,YAAY;YAAE,OAAO,IAAI,CAAC;QAE/B,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,kBAAkB,EAAE;gBACzD,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,CAAC;aACvC,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;gBACjC,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnC,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;YAC1D,OAAO,IAAI,CAAC,WAAW,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;CACF;AAxCD,oCAwCC"}
@@ -0,0 +1,6 @@
1
+ export * from './client';
2
+ export * from './core/errors';
3
+ export * from './core/token-manager';
4
+ export * from './core/http';
5
+ export * from './modules/auth.module';
6
+ export * from './types';
package/dist/index.js ADDED
@@ -0,0 +1,23 @@
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("./client"), exports);
18
+ __exportStar(require("./core/errors"), exports);
19
+ __exportStar(require("./core/token-manager"), exports);
20
+ __exportStar(require("./core/http"), exports);
21
+ __exportStar(require("./modules/auth.module"), exports);
22
+ __exportStar(require("./types"), exports);
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,gDAA8B;AAC9B,uDAAqC;AACrC,8CAA4B;AAC5B,wDAAsC;AACtC,0CAAwB"}
@@ -0,0 +1,22 @@
1
+ import { HttpClient } from '../core/http';
2
+ export declare class AuthModule {
3
+ private http;
4
+ private baseUrl;
5
+ constructor(http: HttpClient, baseUrl: string);
6
+ initializeLoginFlow(): Promise<{
7
+ id: string;
8
+ ui: any;
9
+ }>;
10
+ sendMagicCode(flowId: string, email: string): Promise<any>;
11
+ verifyMagicCode(flowId: string, code: string): Promise<any>;
12
+ getGoogleLoginUrl(loginChallenge: string): string;
13
+ getCurrentSession(): Promise<any>;
14
+ getAuthStatus(): Promise<{
15
+ authenticated: boolean;
16
+ email: string | null;
17
+ name: string | null;
18
+ identityId: string | null;
19
+ }>;
20
+ logout(logoutChallenge: string): Promise<void>;
21
+ isOnboardingRequired(session: any): boolean;
22
+ }
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AuthModule = void 0;
4
+ class AuthModule {
5
+ http;
6
+ baseUrl;
7
+ constructor(http, baseUrl) {
8
+ this.http = http;
9
+ this.baseUrl = baseUrl;
10
+ }
11
+ async initializeLoginFlow() {
12
+ return this.http.get('/v1/auth/kratos/self-service/login/api');
13
+ }
14
+ async sendMagicCode(flowId, email) {
15
+ return this.http.post(`/v1/auth/kratos/self-service/login?flow=${flowId}`, {
16
+ method: 'code',
17
+ identifier: email,
18
+ });
19
+ }
20
+ async verifyMagicCode(flowId, code) {
21
+ return this.http.post(`/v1/auth/kratos/self-service/login?flow=${flowId}`, {
22
+ method: 'code',
23
+ code: code,
24
+ });
25
+ }
26
+ getGoogleLoginUrl(loginChallenge) {
27
+ const postLoginUrl = `${this.baseUrl}/v1/auth/post-login?login_challenge=${encodeURIComponent(loginChallenge)}`;
28
+ return `${this.baseUrl}/v1/auth/kratos/self-service/login/browser?provider=google&return_to=${encodeURIComponent(postLoginUrl)}`;
29
+ }
30
+ async getCurrentSession() {
31
+ return this.http.get('/v1/auth/kratos/sessions/whoami');
32
+ }
33
+ async getAuthStatus() {
34
+ return this.http.get('/v1/auth');
35
+ }
36
+ async logout(logoutChallenge) {
37
+ await this.http.get(`/v1/auth/logout?logout_challenge=${encodeURIComponent(logoutChallenge)}`);
38
+ }
39
+ isOnboardingRequired(session) {
40
+ const onboarded = session?.identity?.traits?.onboarded;
41
+ return onboarded !== true;
42
+ }
43
+ }
44
+ exports.AuthModule = AuthModule;
45
+ //# sourceMappingURL=auth.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.module.js","sourceRoot":"","sources":["../../src/modules/auth.module.ts"],"names":[],"mappings":";;;AAEA,MAAa,UAAU;IAGD;IAFZ,OAAO,CAAS;IAExB,YAAoB,IAAgB,EAAE,OAAe;QAAjC,SAAI,GAAJ,IAAI,CAAY;QAClC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,mBAAmB;QACvB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAA0B,wCAAwC,CAAC,CAAC;IAC1F,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,MAAc,EAAE,KAAa;QAC/C,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAM,2CAA2C,MAAM,EAAE,EAAE;YAC9E,MAAM,EAAE,MAAM;YACd,UAAU,EAAE,KAAK;SAClB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,MAAc,EAAE,IAAY;QAChD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAM,2CAA2C,MAAM,EAAE,EAAE;YAC9E,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI;SACX,CAAC,CAAC;IACL,CAAC;IAED,iBAAiB,CAAC,cAAsB;QACtC,MAAM,YAAY,GAAG,GAAG,IAAI,CAAC,OAAO,uCAAuC,kBAAkB,CAAC,cAAc,CAAC,EAAE,CAAC;QAChH,OAAO,GAAG,IAAI,CAAC,OAAO,wEAAwE,kBAAkB,CAAC,YAAY,CAAC,EAAE,CAAC;IACnI,CAAC;IAED,KAAK,CAAC,iBAAiB;QACrB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAM,iCAAiC,CAAC,CAAC;IAC/D,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAmG,UAAU,CAAC,CAAC;IACrI,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,eAAuB;QAClC,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,oCAAoC,kBAAkB,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;IACjG,CAAC;IAED,oBAAoB,CAAC,OAAY;QAC/B,MAAM,SAAS,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC;QACvD,OAAO,SAAS,KAAK,IAAI,CAAC;IAC5B,CAAC;CACF;AA9CD,gCA8CC"}
@@ -0,0 +1,19 @@
1
+ export interface StorageAdapter {
2
+ getAccessToken(): string | null | Promise<string | null>;
3
+ setAccessToken(token: string): void | Promise<void>;
4
+ getRefreshToken(): string | null | Promise<string | null>;
5
+ setRefreshToken(token: string): void | Promise<void>;
6
+ clearTokens(): void | Promise<void>;
7
+ }
8
+ export interface NonsClientConfig {
9
+ baseUrl: string;
10
+ storage?: StorageAdapter;
11
+ timeout?: number;
12
+ onUnauthorized?: () => void;
13
+ }
14
+ export interface HttpClientConfig {
15
+ baseUrl: string;
16
+ timeout: number;
17
+ tokenManager: any;
18
+ onUnauthorized?: () => void;
19
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=config.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.types.js","sourceRoot":"","sources":["../../src/types/config.types.ts"],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ export * from './config.types';
@@ -0,0 +1,18 @@
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("./config.types"), exports);
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iDAA+B"}
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@nons-dev/sdk-react",
3
+ "version": "1.0.3",
4
+ "description": "NONS React/Frontend Authentication SDK",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/nons-dev/sdk-react.git"
13
+ },
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "test": "vitest run"
17
+ },
18
+ "publishConfig": {
19
+ "access": "public",
20
+ "registry": "https://registry.npmjs.org"
21
+ },
22
+ "devDependencies": {
23
+ "@types/node": "^20.14.9",
24
+ "typescript": "^5.4.5",
25
+ "vitest": "^1.6.0"
26
+ }
27
+ }
package/readme.md ADDED
@@ -0,0 +1,191 @@
1
+ # NONS React Authentication SDK
2
+ `@nons/sdk-react`
3
+
4
+ Official React/Frontend Authentication SDK for the NONS Platform, built to interface seamlessly with Ory Kratos, Ory Hydra, and the API Gateway bridge.
5
+
6
+ ---
7
+
8
+ ## 📋 Table of Contents
9
+ 1. [Installation Guide](#-installation-guide)
10
+ 2. [SDK Usage Guide](#-sdk-usage-guide)
11
+ 3. [Development Guide](#-development-guide)
12
+ 4. [Release Guide](#-release-guide)
13
+ 5. [Consumer Setup](#-consumer-setup)
14
+
15
+ ---
16
+
17
+ ## 🚀 Installation Guide
18
+
19
+ Install the package directly from GitHub Packages:
20
+
21
+ ### Using NPM
22
+ ```bash
23
+ npm install @nons/sdk-react
24
+ ```
25
+
26
+ ### Using PNPM
27
+ ```bash
28
+ pnpm add @nons/sdk-react
29
+ ```
30
+
31
+ To configure GitHub Packages registry, add the following to your `.npmrc` file:
32
+ ```ini
33
+ @nons:registry=https://npm.pkg.github.com
34
+ //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
35
+ ```
36
+
37
+ ---
38
+
39
+ ## 📖 SDK Usage Guide
40
+
41
+ ### 1. Initialize the Client
42
+ Instantiate `NonsClient` with your API Gateway bridge endpoint and a `StorageAdapter`:
43
+
44
+ ```typescript
45
+ import { NonsClient, StorageAdapter } from "@nons/sdk-react";
46
+
47
+ class LocalStorageStorageAdapter implements StorageAdapter {
48
+ getAccessToken() { return localStorage.getItem("access_token"); }
49
+ setAccessToken(token: string) { localStorage.setItem("access_token", token); }
50
+ getRefreshToken() { return localStorage.getItem("refresh_token"); }
51
+ setRefreshToken(token: string) { localStorage.setItem("refresh_token", token); }
52
+ clearTokens() {
53
+ localStorage.removeItem("access_token");
54
+ localStorage.removeItem("refresh_token");
55
+ }
56
+ }
57
+
58
+ export const nonsClient = new NonsClient({
59
+ baseUrl: "https://api.nons.ir",
60
+ storage: new LocalStorageStorageAdapter(),
61
+ timeout: 10000,
62
+ });
63
+ ```
64
+
65
+ ### 2. Magic Code Flow
66
+
67
+ #### Step A: Initialize Flow & Request Code
68
+ ```typescript
69
+ const flow = await nonsClient.auth.initializeLoginFlow();
70
+ const flowId = flow.id; // Save this to submit with verification code
71
+
72
+ await nonsClient.auth.sendMagicCode(flowId, "user@example.com");
73
+ ```
74
+
75
+ #### Step B: Submit Verification Code (OTP)
76
+ ```typescript
77
+ const session = await nonsClient.auth.verifyMagicCode(flowId, "123456");
78
+ const onboardingRequired = nonsClient.auth.isOnboardingRequired(session);
79
+
80
+ if (onboardingRequired) {
81
+ // Redirect to Onboarding profile form
82
+ } else {
83
+ // Login successful
84
+ }
85
+ ```
86
+
87
+ ### 3. Google OIDC Login
88
+ Construct the browser redirection URL and navigate the user to complete Google Consent verification:
89
+
90
+ ```typescript
91
+ const loginChallenge = "hydra_login_challenge_from_query_params";
92
+ const googleLoginUrl = nonsClient.auth.getGoogleLoginUrl(loginChallenge);
93
+
94
+ // Redirect the browser
95
+ window.location.assign(googleLoginUrl);
96
+ ```
97
+
98
+ ### 4. Session & Logout
99
+ Check the active session or logout:
100
+
101
+ ```typescript
102
+ // Get Kratos Session
103
+ const session = await nonsClient.auth.getCurrentSession();
104
+
105
+ // Logout
106
+ const logoutChallenge = "hydra_logout_challenge";
107
+ await nonsClient.auth.logout(logoutChallenge);
108
+ ```
109
+
110
+ ---
111
+
112
+ ## 🛠️ Development Guide
113
+
114
+ ### Install Dependencies
115
+ ```bash
116
+ pnpm install
117
+ ```
118
+
119
+ ### Run Tests
120
+ The test suite utilizes `Vitest` to validate all authentication methods, error parsing, and timeout behaviors:
121
+ ```bash
122
+ pnpm test
123
+ ```
124
+
125
+ ### Build the Package
126
+ Compiles TypeScript files and exports types to the `dist` directory:
127
+ ```bash
128
+ pnpm run build
129
+ ```
130
+
131
+ ---
132
+
133
+ ## 📦 Release Guide
134
+
135
+ The package is versioned and published independently:
136
+
137
+ 1. **Increment Version:** Update `version` in `package.json` according to semver.
138
+ 2. **Commit and Tag:** Commit the changes and create a git tag matching the version:
139
+ ```bash
140
+ git add package.json
141
+ git commit -m "chore: release v1.0.0"
142
+ git tag v1.0.0
143
+ ```
144
+ 3. **Publish to GitHub Packages:**
145
+ Pushing the tag triggers the GitHub Actions release workflow automatically. Alternatively, run:
146
+ ```bash
147
+ pnpm run build
148
+ pnpm publish
149
+ ```
150
+
151
+ ---
152
+
153
+ ## 🌐 Consumer Setup
154
+
155
+ Instructions for setting up consumer projects (like `auth-ui`):
156
+
157
+ ### 1. Local Development
158
+ To develop and test changes locally without publishing to GitHub Packages:
159
+ * Option A (File reference): Use a relative path dependency in `package.json`:
160
+ ```json
161
+ "@nons/sdk-react": "file:../sdk-react"
162
+ ```
163
+ * Option B (Symlinking): Link the package using `pnpm link`:
164
+ ```bash
165
+ cd sdk-react && pnpm link --global
166
+ cd ../auth-ui && pnpm link --global @nons/sdk-react
167
+ ```
168
+
169
+ ### 2. CI Pipelines
170
+ For GitHub Actions or other CI runners to resolve the dependency, configure a `GITHUB_TOKEN` environment variable with package read permission:
171
+ ```yaml
172
+ - name: Setup Node.js
173
+ uses: actions/setup-node@v4
174
+ with:
175
+ node-version: '22'
176
+ registry-url: 'https://npm.pkg.github.com'
177
+ scope: '@nons'
178
+ env:
179
+ NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
180
+ ```
181
+
182
+ ### 3. Vercel Deployment
183
+ To deploy consumer applications to Vercel:
184
+ 1. Ensure the `.npmrc` file is present in the repository root:
185
+ ```ini
186
+ @nons:registry=https://npm.pkg.github.com/
187
+ //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
188
+ ```
189
+ 2. Navigate to your Vercel Project Settings -> **Environment Variables**.
190
+ 3. Create a new variable named `GITHUB_TOKEN` and paste your GitHub Personal Access Token (PAT) with `read:packages` scope as the value.
191
+ 4. Trigger the deployment. Vercel will resolve, download, and build the project successfully.