binoauth 0.0.1

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/src/index.ts ADDED
@@ -0,0 +1,387 @@
1
+ import {
2
+ AuthenticationApi,
3
+ OAuth2Api,
4
+ UserProfileApi,
5
+ Configuration as TenantConfiguration
6
+ } from '@binoauth/tenant-sdk';
7
+ import {
8
+ AdminApi,
9
+ Configuration as AdminConfiguration
10
+ } from '@binoauth/admin-sdk';
11
+
12
+ export interface BinoAuthConfig {
13
+ apiKey: string;
14
+ tenant: string;
15
+ baseUrl?: string;
16
+ }
17
+
18
+ export interface LoginCredentials {
19
+ email?: string;
20
+ password?: string;
21
+ otp?: string;
22
+ phone?: string;
23
+ }
24
+
25
+ export interface BinoAuthResponse<T = any> {
26
+ ok: boolean;
27
+ data?: T;
28
+ error?: string;
29
+ error_description?: string;
30
+ }
31
+
32
+ export class BinoAuth {
33
+ private tenantConfig: TenantConfiguration;
34
+ private adminConfig: AdminConfiguration;
35
+ private authApi: AuthenticationApi;
36
+ private oauthApi: OAuth2Api;
37
+ private userProfileApi: UserProfileApi;
38
+ private adminApi: AdminApi;
39
+
40
+ constructor(config: BinoAuthConfig) {
41
+ const baseUrl = config.baseUrl || 'https://api.binoauth.com';
42
+
43
+ // Configure tenant SDK
44
+ this.tenantConfig = new TenantConfiguration({
45
+ basePath: baseUrl,
46
+ headers: {
47
+ 'X-API-Key': config.apiKey,
48
+ 'X-Tenant-ID': config.tenant
49
+ }
50
+ });
51
+
52
+ // Configure admin SDK
53
+ this.adminConfig = new AdminConfiguration({
54
+ basePath: baseUrl,
55
+ headers: {
56
+ 'X-API-Key': config.apiKey,
57
+ 'X-Tenant-ID': config.tenant
58
+ }
59
+ });
60
+
61
+ // Initialize APIs
62
+ this.authApi = new AuthenticationApi(this.tenantConfig);
63
+ this.oauthApi = new OAuth2Api(this.tenantConfig);
64
+ this.userProfileApi = new UserProfileApi(this.tenantConfig);
65
+ this.adminApi = new AdminApi(this.adminConfig);
66
+ }
67
+
68
+ // Authentication Methods
69
+ async sendEmailOTP(email: string): Promise<BinoAuthResponse> {
70
+ try {
71
+ const response = await this.authApi.requestMagicLinkApiV1AuthMlPost({
72
+ magicLinkRequest: { email }
73
+ });
74
+ return { ok: true, data: response };
75
+ } catch (error: any) {
76
+ return {
77
+ ok: false,
78
+ error: error.message || 'Failed to send email OTP',
79
+ error_description: error.response?.data?.detail || error.message
80
+ };
81
+ }
82
+ }
83
+
84
+ async sendPhoneOTP(phone: string): Promise<BinoAuthResponse> {
85
+ try {
86
+ const response = await this.authApi.requestOtpViaPhoneApiV1AuthPhonePost({
87
+ phoneOTPRequest: { phone }
88
+ });
89
+ return { ok: true, data: response };
90
+ } catch (error: any) {
91
+ return {
92
+ ok: false,
93
+ error: error.message || 'Failed to send phone OTP',
94
+ error_description: error.response?.data?.detail || error.message
95
+ };
96
+ }
97
+ }
98
+
99
+ async sendMagicLink(email: string): Promise<BinoAuthResponse> {
100
+ try {
101
+ const response = await this.authApi.requestMagicLinkApiV1AuthMlPost({
102
+ magicLinkRequest: { email }
103
+ });
104
+ return { ok: true, data: response };
105
+ } catch (error: any) {
106
+ return {
107
+ ok: false,
108
+ error: error.message || 'Failed to send magic link',
109
+ error_description: error.response?.data?.detail || error.message
110
+ };
111
+ }
112
+ }
113
+
114
+ async login(type: 'password' | 'otp', credentials: LoginCredentials): Promise<BinoAuthResponse> {
115
+ try {
116
+ let response;
117
+
118
+ if (type === 'password') {
119
+ if (!credentials.email || !credentials.password) {
120
+ return {
121
+ ok: false,
122
+ error: 'Missing credentials',
123
+ error_description: 'Email and password are required for password login'
124
+ };
125
+ }
126
+
127
+ response = await this.authApi.loginApiV1AuthLoginPost({
128
+ loginRequest: {
129
+ email: credentials.email,
130
+ password: credentials.password
131
+ }
132
+ });
133
+ } else if (type === 'otp') {
134
+ if (!credentials.otp) {
135
+ return {
136
+ ok: false,
137
+ error: 'Missing OTP',
138
+ error_description: 'OTP code is required for OTP login'
139
+ };
140
+ }
141
+
142
+ // For OTP login, we need to verify the OTP
143
+ if (credentials.phone) {
144
+ response = await this.authApi.verifyPhoneOtpApiV1AuthPhoneVerifyPost({
145
+ phoneOTPVerificationRequest: {
146
+ otp: credentials.otp.toString()
147
+ }
148
+ });
149
+ } else {
150
+ response = await this.authApi.verifyMagicLinkCodeApiV1AuthMlCodeVerifyPost({
151
+ verifyMagicLinkCodeRequest: {
152
+ code: credentials.otp.toString()
153
+ }
154
+ });
155
+ }
156
+ }
157
+
158
+ return { ok: true, data: response };
159
+ } catch (error: any) {
160
+ return {
161
+ ok: false,
162
+ error: error.message || 'Login failed',
163
+ error_description: error.response?.data?.detail || error.message
164
+ };
165
+ }
166
+ }
167
+
168
+ // Password Reset
169
+ async sendResetPasswordEmailOTP(email: string): Promise<BinoAuthResponse> {
170
+ try {
171
+ const response = await this.authApi.requestMagicLinkApiV1AuthMlPost({
172
+ magicLinkRequest: { email }
173
+ });
174
+ return { ok: true, data: response };
175
+ } catch (error: any) {
176
+ return {
177
+ ok: false,
178
+ error: error.message || 'Failed to send reset password email',
179
+ error_description: error.response?.data?.detail || error.message
180
+ };
181
+ }
182
+ }
183
+
184
+ async sendResetPasswordPhoneOTP(phone: string): Promise<BinoAuthResponse> {
185
+ try {
186
+ const response = await this.authApi.requestOtpViaPhoneApiV1AuthPhonePost({
187
+ phoneOTPRequest: { phone }
188
+ });
189
+ return { ok: true, data: response };
190
+ } catch (error: any) {
191
+ return {
192
+ ok: false,
193
+ error: error.message || 'Failed to send reset password phone OTP',
194
+ error_description: error.response?.data?.detail || error.message
195
+ };
196
+ }
197
+ }
198
+
199
+ async resetPassword(params: { otp: string; newPassword: string; repeatNewPassword: string }): Promise<BinoAuthResponse> {
200
+ try {
201
+ if (params.newPassword !== params.repeatNewPassword) {
202
+ return {
203
+ ok: false,
204
+ error: 'Password mismatch',
205
+ error_description: 'New password and repeat password do not match'
206
+ };
207
+ }
208
+
209
+ // This would typically be handled by verifying the OTP first, then updating password
210
+ // For now, we'll verify the magic link code
211
+ const response = await this.authApi.verifyMagicLinkCodeApiV1AuthMlCodeVerifyPost({
212
+ verifyMagicLinkCodeRequest: {
213
+ code: params.otp
214
+ }
215
+ });
216
+
217
+ return { ok: true, data: response };
218
+ } catch (error: any) {
219
+ return {
220
+ ok: false,
221
+ error: error.message || 'Failed to reset password',
222
+ error_description: error.response?.data?.detail || error.message
223
+ };
224
+ }
225
+ }
226
+
227
+ // Token Management
228
+ async refreshToken(refreshToken: string): Promise<BinoAuthResponse> {
229
+ try {
230
+ const response = await this.oauthApi.getTokensApiV1OauthTokenPost({
231
+ tokenRequest: {
232
+ grantType: 'refresh_token',
233
+ clientId: 'binoauth-sdk',
234
+ refreshToken: refreshToken
235
+ }
236
+ });
237
+ return { ok: true, data: response };
238
+ } catch (error: any) {
239
+ return {
240
+ ok: false,
241
+ error: error.message || 'Failed to refresh token',
242
+ error_description: error.response?.data?.detail || error.message
243
+ };
244
+ }
245
+ }
246
+
247
+ async logout(accessToken?: string): Promise<BinoAuthResponse> {
248
+ try {
249
+ const response = await this.authApi.logoutApiV1AuthLogoutPost({
250
+ sessionBinoauth: accessToken || ''
251
+ });
252
+ return { ok: true, data: response };
253
+ } catch (error: any) {
254
+ return {
255
+ ok: false,
256
+ error: error.message || 'Failed to logout',
257
+ error_description: error.response?.data?.detail || error.message
258
+ };
259
+ }
260
+ }
261
+
262
+ // User Profile
263
+ async getProfile(): Promise<BinoAuthResponse> {
264
+ try {
265
+ const response = await this.userProfileApi.getCurrentUserApiV1AuthUserinfoGet();
266
+ return { ok: true, data: response };
267
+ } catch (error: any) {
268
+ return {
269
+ ok: false,
270
+ error: error.message || 'Failed to get profile',
271
+ error_description: error.response?.data?.detail || error.message
272
+ };
273
+ }
274
+ }
275
+
276
+ // Device Code Flow
277
+ async requestDeviceCode(): Promise<BinoAuthResponse> {
278
+ try {
279
+ const response = await this.oauthApi.deviceAuthorizationApiV1OauthDeviceCodePost({
280
+ deviceAuthorizationRequest: {
281
+ clientId: 'binoauth-sdk'
282
+ }
283
+ });
284
+ return { ok: true, data: response };
285
+ } catch (error: any) {
286
+ return {
287
+ ok: false,
288
+ error: error.message || 'Failed to request device code',
289
+ error_description: error.response?.data?.detail || error.message
290
+ };
291
+ }
292
+ }
293
+
294
+ async pollDeviceToken(deviceCode: string): Promise<BinoAuthResponse> {
295
+ try {
296
+ const response = await this.oauthApi.getTokensApiV1OauthTokenPost({
297
+ tokenRequest: {
298
+ grantType: 'urn:ietf:params:oauth:grant-type:device_code',
299
+ clientId: 'binoauth-sdk',
300
+ deviceCode: deviceCode
301
+ }
302
+ });
303
+ return { ok: true, data: response };
304
+ } catch (error: any) {
305
+ return {
306
+ ok: false,
307
+ error: error.message || 'Failed to poll device token',
308
+ error_description: error.response?.data?.detail || error.message
309
+ };
310
+ }
311
+ }
312
+
313
+ // User Management (Admin API)
314
+ async createUser(userData: any): Promise<BinoAuthResponse> {
315
+ try {
316
+ // Admin API user creation method may not be available - this is a placeholder
317
+ throw new Error('User creation not implemented in admin SDK');
318
+ } catch (error: any) {
319
+ return {
320
+ ok: false,
321
+ error: error.message || 'Failed to create user',
322
+ error_description: error.response?.data?.detail || error.message
323
+ };
324
+ }
325
+ }
326
+
327
+ async getUser(userId: string): Promise<BinoAuthResponse> {
328
+ try {
329
+ const response = await this.adminApi.getUserApiV1UsersUserIdGet({
330
+ userId,
331
+ xTenantId: ''
332
+ });
333
+ return { ok: true, data: response };
334
+ } catch (error: any) {
335
+ return {
336
+ ok: false,
337
+ error: error.message || 'Failed to get user',
338
+ error_description: error.response?.data?.detail || error.message
339
+ };
340
+ }
341
+ }
342
+
343
+ async getUsers(params: { page?: number; limit?: number } = {}): Promise<BinoAuthResponse> {
344
+ try {
345
+ const response = await this.adminApi.getUsersApiV1UsersGet({
346
+ page: params.page || 1,
347
+ limit: params.limit || 10,
348
+ xTenantId: ''
349
+ });
350
+ return { ok: true, data: response };
351
+ } catch (error: any) {
352
+ return {
353
+ ok: false,
354
+ error: error.message || 'Failed to get users',
355
+ error_description: error.response?.data?.detail || error.message
356
+ };
357
+ }
358
+ }
359
+
360
+ async updateUser(userId: string, userData: any): Promise<BinoAuthResponse> {
361
+ try {
362
+ // Admin API user update method may not be available - this is a placeholder
363
+ throw new Error('User update not implemented in admin SDK');
364
+ } catch (error: any) {
365
+ return {
366
+ ok: false,
367
+ error: error.message || 'Failed to update user',
368
+ error_description: error.response?.data?.detail || error.message
369
+ };
370
+ }
371
+ }
372
+
373
+ async deleteUser(userId: string): Promise<BinoAuthResponse> {
374
+ try {
375
+ // Admin API user delete method may not be available - this is a placeholder
376
+ throw new Error('User delete not implemented in admin SDK');
377
+ } catch (error: any) {
378
+ return {
379
+ ok: false,
380
+ error: error.message || 'Failed to delete user',
381
+ error_description: error.response?.data?.detail || error.message
382
+ };
383
+ }
384
+ }
385
+ }
386
+
387
+ export default BinoAuth;
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "module": "ES2020",
5
+ "outDir": "./dist/esm",
6
+ "target": "ES2020"
7
+ }
8
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "lib": ["ES2020"],
6
+ "declaration": true,
7
+ "outDir": "./dist",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "moduleResolution": "node",
13
+ "resolveJsonModule": true,
14
+ "allowSyntheticDefaultImports": true
15
+ },
16
+ "include": [
17
+ "src/**/*"
18
+ ],
19
+ "exclude": [
20
+ "node_modules",
21
+ "dist"
22
+ ]
23
+ }