nocal-auth-sdk 0.1.7 → 0.1.9

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.
@@ -1,37 +1,30 @@
1
- export type PopupResult<T = Record<string, unknown>> = {
2
- type: "success";
3
- data: T;
4
- } | {
5
- type: "error";
6
- error: string;
7
- } | {
8
- type: "closed";
9
- };
10
1
  export interface NocalAuthOptions {
11
- clientId: string;
12
- redirectUri: string;
2
+ authorizeUrl?: string;
3
+ clientId?: string;
4
+ redirectUri?: string;
13
5
  scope?: string;
14
6
  state?: string;
15
- issuerOrigin?: string;
16
- responseType?: "code" | "token";
17
- popupFeatures?: string;
18
- extraParams?: Record<string, string | number | boolean | undefined>;
7
+ [key: string]: any;
19
8
  }
20
- export interface PopupOptions {
9
+ export interface NocalPopupResult {
10
+ success: boolean;
11
+ data?: Record<string, any>;
12
+ error?: string;
13
+ message?: string;
14
+ }
15
+ export interface LoginWithPopupOptions {
16
+ url?: string;
17
+ popupName?: string;
21
18
  width?: number;
22
19
  height?: number;
23
- popupName?: string;
20
+ features?: string;
24
21
  }
25
22
  export declare class NocalAuth {
26
- private readonly clientId;
27
- private readonly redirectUri;
28
- private readonly scope?;
29
- private readonly state?;
30
- private readonly issuerOrigin;
31
- private readonly responseType;
32
- private readonly popupFeatures?;
33
- private readonly extraParams?;
34
- constructor(options: NocalAuthOptions);
35
- private getAuthorizeUrl;
36
- loginWithPopup(popupOptions?: PopupOptions): Promise<Record<string, unknown>>;
23
+ private authorizeUrl;
24
+ private options;
25
+ constructor(options?: NocalAuthOptions);
26
+ static notifyPopupResult(result: NocalPopupResult, targetWindow?: Window | null): boolean;
27
+ getAuthorizeUrl(): string;
28
+ static loginWithPopup(options?: LoginWithPopupOptions): Promise<unknown>;
29
+ loginWithPopup(options?: LoginWithPopupOptions): Promise<unknown>;
37
30
  }
package/dist/NocalAuth.js CHANGED
@@ -1,131 +1,104 @@
1
- function buildQuery(params) {
2
- const qs = Object.entries(params)
3
- .filter(([, value]) => value !== undefined && value !== null && value !== "")
4
- .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
5
- .join("&");
6
- return qs ? `?${qs}` : "";
7
- }
8
1
  export class NocalAuth {
9
- constructor(options) {
10
- if (!options.clientId) {
11
- throw new Error("NocalAuth requires a clientId");
12
- }
13
- if (!options.redirectUri) {
14
- throw new Error("NocalAuth requires a redirectUri");
15
- }
16
- this.clientId = options.clientId;
17
- this.redirectUri = options.redirectUri;
18
- this.scope = options.scope;
19
- this.state = options.state;
20
- this.issuerOrigin = (options.issuerOrigin ?? "https://auth.nocal.vn").replace(/\/$/, "");
21
- this.responseType = options.responseType ?? "code";
22
- this.popupFeatures = options.popupFeatures;
23
- this.extraParams = options.extraParams;
2
+ constructor(options = {}) {
3
+ this.options = options;
4
+ this.authorizeUrl =
5
+ options.authorizeUrl || "https://auth.nocal.vn/oauth/authorize";
6
+ }
7
+ static notifyPopupResult(result, targetWindow = typeof window !== "undefined"
8
+ ? window.opener
9
+ : null) {
10
+ if (typeof window === "undefined")
11
+ return false;
12
+ const opener = targetWindow ?? window.opener;
13
+ if (!opener)
14
+ return false;
15
+ const payload = {
16
+ type: "nocal_auth_result",
17
+ success: result.success,
18
+ ...(result.success
19
+ ? { data: result.data ?? {} }
20
+ : {
21
+ error: result.error || "AUTH_FAILED",
22
+ message: result.message || result.error || "AUTH_FAILED",
23
+ }),
24
+ };
25
+ opener.postMessage(payload, "*");
26
+ return true;
24
27
  }
25
28
  getAuthorizeUrl() {
26
- const baseUrl = `${this.issuerOrigin}/dang-nhap`;
27
- const query = buildQuery({
28
- client_id: this.clientId,
29
- redirect_uri: this.redirectUri,
30
- response_type: this.responseType,
31
- scope: this.scope,
32
- state: this.state,
33
- ...this.extraParams,
29
+ const url = new URL(this.authorizeUrl || "https://auth.nocal.vn/oauth/authorize");
30
+ const params = {
31
+ client_id: this.options.clientId,
32
+ redirect_uri: this.options.redirectUri,
33
+ scope: this.options.scope,
34
+ state: this.options.state,
35
+ ...this.options,
36
+ };
37
+ Object.entries(params).forEach(([key, value]) => {
38
+ if (value === undefined || value === null || value === "")
39
+ return;
40
+ if (key === "authorizeUrl")
41
+ return;
42
+ url.searchParams.set(key, String(value));
34
43
  });
35
- return `${baseUrl}${query}`;
44
+ return url.toString();
36
45
  }
37
- async loginWithPopup(popupOptions = {}) {
46
+ static loginWithPopup(options = {}) {
38
47
  if (typeof window === "undefined") {
39
- throw new Error("loginWithPopup() can only be used in a browser environment");
40
- }
41
- const width = popupOptions.width ?? 500;
42
- const height = popupOptions.height ?? 700;
43
- const popupName = popupOptions.popupName ?? "nocal_auth_popup";
44
- const dualScreenLeft = window.screenLeft ?? window.screenX ?? 0;
45
- const dualScreenTop = window.screenTop ?? window.screenY ?? 0;
46
- const screenWidth = window.innerWidth ??
47
- document.documentElement.clientWidth ??
48
- window.screen.width ??
49
- 1280;
50
- const screenHeight = window.innerHeight ??
51
- document.documentElement.clientHeight ??
52
- window.screen.height ??
53
- 720;
54
- const left = Math.round(dualScreenLeft + (screenWidth - width) / 2);
55
- const top = Math.round(dualScreenTop + (screenHeight - height) / 2);
56
- const features = [
57
- `width=${width}`,
58
- `height=${height}`,
59
- `left=${left}`,
60
- `top=${top}`,
61
- "resizable=yes",
62
- "scrollbars=yes",
63
- this.popupFeatures ?? "",
64
- ]
65
- .filter(Boolean)
66
- .join(",");
67
- // Xây dựng URL với tham số display=popup và các tham số khác
68
- const authUrl = new URL(this.getAuthorizeUrl());
69
- authUrl.searchParams.set("display", "popup");
70
- const popup = window.open(authUrl.toString(), popupName, features);
71
- if (!popup) {
72
- throw new Error("POPUP_BLOCKED");
48
+ return Promise.reject(new Error("loginWithPopup() can only be used in a browser environment"));
73
49
  }
74
- popup.focus?.();
50
+ const url = options.url || "https://auth.nocal.vn/oauth/authorize";
51
+ const width = options.width ?? 500;
52
+ const height = options.height ?? 700;
53
+ const left = window.screenX + (window.innerWidth - width) / 2;
54
+ const top = window.screenY + (window.innerHeight - height) / 2;
55
+ const features = options.features ??
56
+ `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`;
75
57
  return new Promise((resolve, reject) => {
58
+ const popup = window.open(url, options.popupName ?? "nocal_auth_popup", features);
59
+ if (!popup)
60
+ return reject(new Error("POPUP_BLOCKED"));
61
+ popup.focus();
76
62
  let settled = false;
77
- let checkInterval = undefined;
63
+ let timer = null;
78
64
  const cleanup = () => {
79
- settled = true;
80
- window.removeEventListener("message", handleMessage);
81
- if (checkInterval) {
82
- clearInterval(checkInterval);
83
- }
84
- };
85
- const rejectWith = (message) => {
86
65
  if (settled)
87
66
  return;
88
- cleanup();
89
- reject(new Error(message));
67
+ settled = true;
68
+ window.removeEventListener("message", handleMessage);
69
+ if (timer)
70
+ clearInterval(timer);
90
71
  };
91
72
  const handleMessage = (event) => {
92
- if (settled)
93
- return;
94
- // Kiểm tra origin bảo mật
95
- if (event.origin !== this.issuerOrigin) {
96
- return;
97
- }
98
73
  const payload = event.data;
99
- if (!payload || typeof payload !== "object") {
100
- return;
101
- }
102
- if (payload.type !== "nocal_auth_result") {
74
+ if (!payload || payload.type !== "nocal_auth_result")
103
75
  return;
104
- }
105
76
  cleanup();
106
- if (payload.success === false || payload.error) {
107
- rejectWith(typeof payload.error === "string" ? payload.error : "AUTH_FAILED");
108
- return;
77
+ if (payload.success) {
78
+ resolve(payload.data ?? {});
109
79
  }
110
- const rawData = payload.data ?? payload;
111
- const data = {
112
- token: rawData.accessToken ?? rawData.token ?? rawData.access_token,
113
- refreshToken: rawData.refreshToken,
114
- user: rawData.user,
115
- state: rawData.state,
116
- };
117
- if (!data || Object.keys(data).length === 0) {
118
- rejectWith("AUTH_DATA_MISSING");
119
- return;
80
+ else {
81
+ reject(new Error(payload.error || payload.message || "AUTH_FAILED"));
120
82
  }
121
- resolve(data);
122
83
  };
123
- window.addEventListener("message", handleMessage, false);
124
- checkInterval = window.setInterval(() => {
125
- if (popup.closed) {
126
- rejectWith("POPUP_CLOSED");
84
+ window.addEventListener("message", handleMessage);
85
+ timer = setInterval(() => {
86
+ try {
87
+ if (popup.closed) {
88
+ cleanup();
89
+ reject(new Error("POPUP_CLOSED"));
90
+ }
91
+ }
92
+ catch {
93
+ // Ignore cross-origin checks while popup is redirecting.
127
94
  }
128
95
  }, 500);
129
96
  });
130
97
  }
98
+ loginWithPopup(options = {}) {
99
+ return NocalAuth.loginWithPopup({
100
+ ...options,
101
+ url: options.url || this.getAuthorizeUrl(),
102
+ });
103
+ }
131
104
  }
@@ -0,0 +1,46 @@
1
+ import * as _supabase_auth_js from '@supabase/auth-js';
2
+ import { User, Session } from '@supabase/supabase-js';
3
+ export { Session, User } from '@supabase/supabase-js';
4
+
5
+ interface NocalClientConfig {
6
+ clientId: string;
7
+ redirectUri: string;
8
+ }
9
+ type NocalOAuthProvider = "google" | "facebook" | "github" | "apple";
10
+ interface OAuthLoginReq {
11
+ provider?: NocalOAuthProvider;
12
+ redirectTo?: string;
13
+ }
14
+
15
+ declare class NocalAuthSDK {
16
+ private supabase;
17
+ private clientId;
18
+ private redirectUri;
19
+ constructor(config: NocalClientConfig);
20
+ /**
21
+ * Mở Popup UI Đăng nhập/Đăng ký tập trung của Nocal
22
+ */
23
+ signInWithNocal(req?: OAuthLoginReq): Promise<User>;
24
+ /**
25
+ * Lấy thông tin User hiện tại
26
+ */
27
+ getUser(): Promise<User | null>;
28
+ /**
29
+ * Lấy Session / Access Token hiện tại
30
+ */
31
+ getSession(): Promise<Session | null>;
32
+ /**
33
+ * Đăng xuất khỏi hệ thống
34
+ */
35
+ signOut(): Promise<void>;
36
+ /**
37
+ * Lắng nghe sự kiện đăng nhập / đăng xuất
38
+ */
39
+ onAuthStateChange(callback: (event: string, session: Session | null) => void): {
40
+ data: {
41
+ subscription: _supabase_auth_js.Subscription;
42
+ };
43
+ };
44
+ }
45
+
46
+ export { NocalAuthSDK, type NocalClientConfig, type NocalOAuthProvider, type OAuthLoginReq };
package/dist/index.d.ts CHANGED
@@ -1,2 +1,32 @@
1
- export { NocalAuth } from './NocalAuth';
2
- export type { NocalAuthOptions, PopupOptions, PopupResult } from './NocalAuth';
1
+ import { NocalClientConfig, OAuthLoginReq, User as NocalUser, Session as NocalSession } from "./types";
2
+ export declare class NocalAuthSDK {
3
+ private supabase;
4
+ private clientId;
5
+ private redirectUri;
6
+ constructor(config: NocalClientConfig);
7
+ /**
8
+ * Mở Popup UI Đăng nhập/Đăng ký tập trung của Nocal
9
+ */
10
+ signInWithNocal(req?: OAuthLoginReq): Promise<NocalUser>;
11
+ /**
12
+ * Lấy thông tin User hiện tại
13
+ */
14
+ getUser(): Promise<NocalUser | null>;
15
+ /**
16
+ * Lấy Session / Access Token hiện tại
17
+ */
18
+ getSession(): Promise<NocalSession | null>;
19
+ /**
20
+ * Đăng xuất khỏi hệ thống
21
+ */
22
+ signOut(): Promise<void>;
23
+ /**
24
+ * Lắng nghe sự kiện đăng nhập / đăng xuất
25
+ */
26
+ onAuthStateChange(callback: (event: string, session: NocalSession | null) => void): {
27
+ data: {
28
+ subscription: import("@supabase/auth-js").Subscription;
29
+ };
30
+ };
31
+ }
32
+ export * from "./types";
package/dist/index.js CHANGED
@@ -1 +1,109 @@
1
- export { NocalAuth } from './NocalAuth';
1
+ import { createClient, } from "@supabase/supabase-js";
2
+ const NOCAL_AUTH_SERVER_URL = "https://hldymiruucsqqzicnwdv.supabase.co";
3
+ const NOCAL_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImhsZHltaXJ1dWNzcXF6aWNud2R2Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3ODk2MTQ2NzAsImV4cCI6MjEwNTE5MDY3MH0.dLaPWdgTV8mRVToNT1XLg1EUjHvyvRRK2qc0DQAu8YI";
4
+ export class NocalAuthSDK {
5
+ constructor(config) {
6
+ this.clientId = config.clientId;
7
+ this.redirectUri = config.redirectUri;
8
+ this.supabase = createClient(NOCAL_AUTH_SERVER_URL, NOCAL_ANON_KEY, {
9
+ auth: {
10
+ autoRefreshToken: true,
11
+ persistSession: true,
12
+ detectSessionInUrl: true,
13
+ },
14
+ });
15
+ }
16
+ /**
17
+ * Mở Popup UI Đăng nhập/Đăng ký tập trung của Nocal
18
+ */
19
+ async signInWithNocal(req) {
20
+ const targetRedirect = req?.redirectTo || this.redirectUri;
21
+ const provider = (req?.provider || "google");
22
+ // 1. Gọi Supabase SDK để sinh URL ủy quyền chuẩn OAuth 2.0 / PKCE
23
+ const { data, error } = await this.supabase.auth.signInWithOAuth({
24
+ provider,
25
+ options: {
26
+ redirectTo: targetRedirect,
27
+ skipBrowserRedirect: true, // Lấy URL trả về, không nhảy trang tab chính
28
+ queryParams: {
29
+ client_id: this.clientId, // Gắn Client ID để Auth Server nhận diện App
30
+ },
31
+ },
32
+ });
33
+ if (error)
34
+ throw error;
35
+ if (!data?.url)
36
+ throw new Error("CANNOT_GENERATE_AUTH_URL");
37
+ // 2. Tính toán kích thước và căn giữa màn hình Popup
38
+ const width = 480;
39
+ const height = 680;
40
+ const left = typeof window !== "undefined"
41
+ ? window.screenX + (window.outerWidth - width) / 2
42
+ : 0;
43
+ const top = typeof window !== "undefined"
44
+ ? window.screenY + (window.outerHeight - height) / 2
45
+ : 0;
46
+ // 3. Mở Cửa sổ Popup chứa UI đăng nhập Nocal
47
+ const popup = window.open(data.url, "NocalAuthPopup", `width=${width},height=${height},left=${left},top=${top},status=yes,scrollbars=yes`);
48
+ if (!popup) {
49
+ throw new Error("POPUP_BLOCKED");
50
+ }
51
+ // 4. Lắng nghe và kiểm tra khi Popup đóng
52
+ return new Promise((resolve, reject) => {
53
+ const isPopupClosed = () => {
54
+ try {
55
+ return popup.closed;
56
+ }
57
+ catch (e) {
58
+ return false;
59
+ }
60
+ };
61
+ const timer = setInterval(async () => {
62
+ if (isPopupClosed()) {
63
+ clearInterval(timer);
64
+ // Sau khi popup đóng, lấy session đã đăng nhập
65
+ const { data: sessionData } = await this.supabase.auth.getSession();
66
+ if (sessionData?.session?.user) {
67
+ resolve(sessionData.session.user);
68
+ }
69
+ else {
70
+ reject(new Error("LOGIN_CANCELLED_OR_FAILED"));
71
+ }
72
+ }
73
+ }, 500);
74
+ });
75
+ }
76
+ /**
77
+ * Lấy thông tin User hiện tại
78
+ */
79
+ async getUser() {
80
+ const { data: { user }, error, } = await this.supabase.auth.getUser();
81
+ if (error)
82
+ throw error;
83
+ return user;
84
+ }
85
+ /**
86
+ * Lấy Session / Access Token hiện tại
87
+ */
88
+ async getSession() {
89
+ const { data: { session }, error, } = await this.supabase.auth.getSession();
90
+ if (error)
91
+ throw error;
92
+ return session;
93
+ }
94
+ /**
95
+ * Đăng xuất khỏi hệ thống
96
+ */
97
+ async signOut() {
98
+ const { error } = await this.supabase.auth.signOut();
99
+ if (error)
100
+ throw error;
101
+ }
102
+ /**
103
+ * Lắng nghe sự kiện đăng nhập / đăng xuất
104
+ */
105
+ onAuthStateChange(callback) {
106
+ return this.supabase.auth.onAuthStateChange(callback);
107
+ }
108
+ }
109
+ export * from "./types";
package/dist/index.mjs ADDED
@@ -0,0 +1,110 @@
1
+ // src/index.ts
2
+ import {
3
+ createClient
4
+ } from "@supabase/supabase-js";
5
+ var NOCAL_AUTH_SERVER_URL = "https://hldymiruucsqqzicnwdv.supabase.co";
6
+ var NOCAL_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImhsZHltaXJ1dWNzcXF6aWNud2R2Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3ODk2MTQ2NzAsImV4cCI6MjEwNTE5MDY3MH0.dLaPWdgTV8mRVToNT1XLg1EUjHvyvRRK2qc0DQAu8YI";
7
+ var NocalAuthSDK = class {
8
+ constructor(config) {
9
+ this.clientId = config.clientId;
10
+ this.redirectUri = config.redirectUri;
11
+ this.supabase = createClient(NOCAL_AUTH_SERVER_URL, NOCAL_ANON_KEY, {
12
+ auth: {
13
+ autoRefreshToken: true,
14
+ persistSession: true,
15
+ detectSessionInUrl: true
16
+ }
17
+ });
18
+ }
19
+ /**
20
+ * Mở Popup UI Đăng nhập/Đăng ký tập trung của Nocal
21
+ */
22
+ async signInWithNocal(req) {
23
+ const targetRedirect = req?.redirectTo || this.redirectUri;
24
+ const provider = req?.provider || "google";
25
+ const { data, error } = await this.supabase.auth.signInWithOAuth({
26
+ provider,
27
+ options: {
28
+ redirectTo: targetRedirect,
29
+ skipBrowserRedirect: true,
30
+ // Lấy URL trả về, không nhảy trang tab chính
31
+ queryParams: {
32
+ client_id: this.clientId
33
+ // Gắn Client ID để Auth Server nhận diện App
34
+ }
35
+ }
36
+ });
37
+ if (error) throw error;
38
+ if (!data?.url) throw new Error("CANNOT_GENERATE_AUTH_URL");
39
+ const width = 480;
40
+ const height = 680;
41
+ const left = typeof window !== "undefined" ? window.screenX + (window.outerWidth - width) / 2 : 0;
42
+ const top = typeof window !== "undefined" ? window.screenY + (window.outerHeight - height) / 2 : 0;
43
+ const popup = window.open(
44
+ data.url,
45
+ "NocalAuthPopup",
46
+ `width=${width},height=${height},left=${left},top=${top},status=yes,scrollbars=yes`
47
+ );
48
+ if (!popup) {
49
+ throw new Error("POPUP_BLOCKED");
50
+ }
51
+ return new Promise((resolve, reject) => {
52
+ const isPopupClosed = () => {
53
+ try {
54
+ return popup.closed;
55
+ } catch (e) {
56
+ return false;
57
+ }
58
+ };
59
+ const timer = setInterval(async () => {
60
+ if (isPopupClosed()) {
61
+ clearInterval(timer);
62
+ const { data: sessionData } = await this.supabase.auth.getSession();
63
+ if (sessionData?.session?.user) {
64
+ resolve(sessionData.session.user);
65
+ } else {
66
+ reject(new Error("LOGIN_CANCELLED_OR_FAILED"));
67
+ }
68
+ }
69
+ }, 500);
70
+ });
71
+ }
72
+ /**
73
+ * Lấy thông tin User hiện tại
74
+ */
75
+ async getUser() {
76
+ const {
77
+ data: { user },
78
+ error
79
+ } = await this.supabase.auth.getUser();
80
+ if (error) throw error;
81
+ return user;
82
+ }
83
+ /**
84
+ * Lấy Session / Access Token hiện tại
85
+ */
86
+ async getSession() {
87
+ const {
88
+ data: { session },
89
+ error
90
+ } = await this.supabase.auth.getSession();
91
+ if (error) throw error;
92
+ return session;
93
+ }
94
+ /**
95
+ * Đăng xuất khỏi hệ thống
96
+ */
97
+ async signOut() {
98
+ const { error } = await this.supabase.auth.signOut();
99
+ if (error) throw error;
100
+ }
101
+ /**
102
+ * Lắng nghe sự kiện đăng nhập / đăng xuất
103
+ */
104
+ onAuthStateChange(callback) {
105
+ return this.supabase.auth.onAuthStateChange(callback);
106
+ }
107
+ };
108
+ export {
109
+ NocalAuthSDK
110
+ };
@@ -0,0 +1,11 @@
1
+ import { User, Session } from "@supabase/supabase-js";
2
+ export interface NocalClientConfig {
3
+ clientId: string;
4
+ redirectUri: string;
5
+ }
6
+ export type NocalOAuthProvider = "google" | "facebook" | "github" | "apple";
7
+ export interface OAuthLoginReq {
8
+ provider?: NocalOAuthProvider;
9
+ redirectTo?: string;
10
+ }
11
+ export type { User, Session };
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nocal-auth-sdk",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Nocal Auth - client-side SDK for Login with Nocal (popup flow)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",