@tekcify/auth-backend 1.0.0 → 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.
- package/README.md +414 -22
- package/dist/application-management.d.ts +62 -0
- package/dist/application-management.d.ts.map +1 -0
- package/dist/application-management.js +133 -0
- package/dist/application-management.js.map +1 -0
- package/{src/express/index.ts → dist/express/index.d.ts} +1 -0
- package/dist/express/index.d.ts.map +1 -0
- package/dist/express/index.js +6 -0
- package/dist/express/index.js.map +1 -0
- package/dist/express/middleware.d.ts +16 -0
- package/dist/express/middleware.d.ts.map +1 -0
- package/dist/express/middleware.js +39 -0
- package/dist/express/middleware.js.map +1 -0
- package/{src/index.ts → dist/index.d.ts} +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/nestjs/decorator.d.ts +2 -0
- package/dist/nestjs/decorator.d.ts.map +1 -0
- package/dist/nestjs/decorator.js +11 -0
- package/dist/nestjs/decorator.js.map +1 -0
- package/dist/nestjs/guard.d.ts +13 -0
- package/dist/nestjs/guard.d.ts.map +1 -0
- package/dist/nestjs/guard.js +56 -0
- package/dist/nestjs/guard.js.map +1 -0
- package/{src/nestjs/index.ts → dist/nestjs/index.d.ts} +1 -0
- package/dist/nestjs/index.d.ts.map +1 -0
- package/dist/nestjs/index.js +8 -0
- package/dist/nestjs/index.js.map +1 -0
- package/dist/types.d.ts +22 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/user-profile.d.ts +18 -0
- package/dist/user-profile.d.ts.map +1 -0
- package/dist/user-profile.js +78 -0
- package/dist/user-profile.js.map +1 -0
- package/dist/userinfo.d.ts +9 -0
- package/dist/userinfo.d.ts.map +1 -0
- package/dist/userinfo.js +16 -0
- package/dist/userinfo.js.map +1 -0
- package/dist/verify.d.ts +4 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +38 -0
- package/dist/verify.js.map +1 -0
- package/package.json +13 -10
- package/src/__tests__/verify.test.ts +0 -80
- package/src/express/middleware.ts +0 -61
- package/src/nestjs/decorator.ts +0 -12
- package/src/nestjs/guard.ts +0 -57
- package/src/types.ts +0 -24
- package/src/userinfo.ts +0 -26
- package/src/verify.ts +0 -36
- package/tsconfig.json +0 -11
- package/tsconfig.tsbuildinfo +0 -1
- package/vitest.config.ts +0 -9
package/README.md
CHANGED
|
@@ -28,9 +28,16 @@ You need the JWT access secret from your Tekcify Auth server. This should match
|
|
|
28
28
|
|
|
29
29
|
```env
|
|
30
30
|
JWT_ACCESS_SECRET=your-jwt-access-secret-here
|
|
31
|
-
AUTH_SERVER_URL=http://localhost:7001
|
|
32
31
|
```
|
|
33
32
|
|
|
33
|
+
**Note:** The auth server URL is centralized in `@tekcify/auth-core-client` package as `AUTH_SERVER_URL` (default: `http://localhost:7001`, override with `AUTH_SERVER_URL` env). Functions that communicate with the auth server use this constant automatically.
|
|
34
|
+
|
|
35
|
+
## Auth Server Endpoints Used
|
|
36
|
+
|
|
37
|
+
- Base prefix: `/api`
|
|
38
|
+
- User profile: `GET/PUT /api/user/profile`, `POST /api/user/profile/picture`
|
|
39
|
+
- Applications: `GET/POST /api/applications`, `GET /api/applications/public/:clientId`, `PUT/DELETE /api/applications/:clientId`, `POST /api/applications/:clientId/logo`
|
|
40
|
+
|
|
34
41
|
## NestJS Integration
|
|
35
42
|
|
|
36
43
|
### Step 1: Install Dependencies
|
|
@@ -255,7 +262,7 @@ import { introspectToken } from '@tekcify/auth-core-client';
|
|
|
255
262
|
|
|
256
263
|
const token = req.headers.authorization?.replace('Bearer ', '');
|
|
257
264
|
|
|
258
|
-
const result = await introspectToken(
|
|
265
|
+
const result = await introspectToken({
|
|
259
266
|
token: token!,
|
|
260
267
|
clientId: process.env.CLIENT_ID,
|
|
261
268
|
clientSecret: process.env.CLIENT_SECRET,
|
|
@@ -277,16 +284,159 @@ Fetch user information from the auth server:
|
|
|
277
284
|
```typescript
|
|
278
285
|
import { fetchUserInfo } from '@tekcify/auth-backend';
|
|
279
286
|
|
|
280
|
-
const userInfo = await fetchUserInfo(
|
|
281
|
-
process.env.AUTH_SERVER_URL!,
|
|
282
|
-
accessToken
|
|
283
|
-
);
|
|
287
|
+
const userInfo = await fetchUserInfo(accessToken);
|
|
284
288
|
|
|
285
289
|
console.log('Email:', userInfo.email);
|
|
286
290
|
console.log('Name:', userInfo.name);
|
|
287
291
|
console.log('Verified:', userInfo.email_verified);
|
|
288
292
|
```
|
|
289
293
|
|
|
294
|
+
## User Profile Management
|
|
295
|
+
|
|
296
|
+
Manage user profiles with simple function calls:
|
|
297
|
+
|
|
298
|
+
### Get User Profile
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
import { getUserProfile } from '@tekcify/auth-backend';
|
|
302
|
+
|
|
303
|
+
const profile = await getUserProfile(accessToken);
|
|
304
|
+
|
|
305
|
+
console.log('User ID:', profile.userId);
|
|
306
|
+
console.log('Email:', profile.email);
|
|
307
|
+
console.log('Name:', profile.firstName, profile.lastName);
|
|
308
|
+
console.log('Avatar:', profile.avatarUrl);
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Update User Profile
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
import { updateUserProfile } from '@tekcify/auth-backend';
|
|
315
|
+
|
|
316
|
+
const updatedProfile = await updateUserProfile(accessToken, {
|
|
317
|
+
firstName: 'John',
|
|
318
|
+
lastName: 'Doe',
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
console.log('Profile updated:', updatedProfile);
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Upload Profile Picture
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
import { uploadProfilePicture } from '@tekcify/auth-backend';
|
|
328
|
+
|
|
329
|
+
// Browser (with File object)
|
|
330
|
+
const fileInput = document.querySelector<HTMLInputElement>('#profilePic');
|
|
331
|
+
const file = fileInput?.files?.[0];
|
|
332
|
+
|
|
333
|
+
if (file) {
|
|
334
|
+
const result = await uploadProfilePicture(accessToken, file);
|
|
335
|
+
console.log('New avatar URL:', result.avatarUrl);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Node.js (with Buffer)
|
|
339
|
+
import fs from 'fs';
|
|
340
|
+
|
|
341
|
+
const fileBuffer = fs.readFileSync('./avatar.jpg');
|
|
342
|
+
const result = await uploadProfilePicture(accessToken, fileBuffer, 'avatar.jpg');
|
|
343
|
+
console.log('New avatar URL:', result.avatarUrl);
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
## Application Management
|
|
347
|
+
|
|
348
|
+
Manage OAuth applications with simple function calls:
|
|
349
|
+
|
|
350
|
+
### List Applications
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
import { listApplications } from '@tekcify/auth-backend';
|
|
354
|
+
|
|
355
|
+
const apps = await listApplications(accessToken);
|
|
356
|
+
|
|
357
|
+
apps.forEach(app => {
|
|
358
|
+
console.log('App:', app.name);
|
|
359
|
+
console.log('Client ID:', app.clientId);
|
|
360
|
+
console.log('Logo:', app.logoUrl);
|
|
361
|
+
});
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Get Application by Client ID
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
import { getApplicationByClientId } from '@tekcify/auth-backend';
|
|
368
|
+
|
|
369
|
+
// Public endpoint - no auth required
|
|
370
|
+
const app = await getApplicationByClientId('your-client-id');
|
|
371
|
+
|
|
372
|
+
console.log('App Name:', app.name);
|
|
373
|
+
console.log('Scopes:', app.scopes);
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### Create Application
|
|
377
|
+
|
|
378
|
+
```typescript
|
|
379
|
+
import { createApplication } from '@tekcify/auth-backend';
|
|
380
|
+
|
|
381
|
+
const newApp = await createApplication(accessToken, {
|
|
382
|
+
name: 'My Cool App',
|
|
383
|
+
description: 'An awesome application',
|
|
384
|
+
redirectUris: ['https://myapp.com/callback'],
|
|
385
|
+
authorizedOrigins: ['https://myapp.com'],
|
|
386
|
+
scopes: ['read:profile', 'write:profile'],
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
console.log('Client ID:', newApp.clientId);
|
|
390
|
+
console.log('Client Secret:', newApp.clientSecret); // Save this securely!
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
### Update Application
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
import { updateApplication } from '@tekcify/auth-backend';
|
|
397
|
+
|
|
398
|
+
await updateApplication(accessToken, 'your-client-id', {
|
|
399
|
+
name: 'Updated App Name',
|
|
400
|
+
description: 'New description',
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
console.log('Application updated');
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### Upload Application Logo
|
|
407
|
+
|
|
408
|
+
```typescript
|
|
409
|
+
import { uploadApplicationLogo } from '@tekcify/auth-backend';
|
|
410
|
+
|
|
411
|
+
// Browser
|
|
412
|
+
const logoFile = document.querySelector<HTMLInputElement>('#logo')?.files?.[0];
|
|
413
|
+
if (logoFile) {
|
|
414
|
+
const result = await uploadApplicationLogo(accessToken, 'your-client-id', logoFile);
|
|
415
|
+
console.log('New logo URL:', result.logoUrl);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Node.js
|
|
419
|
+
import fs from 'fs';
|
|
420
|
+
|
|
421
|
+
const logoBuffer = fs.readFileSync('./logo.png');
|
|
422
|
+
const result = await uploadApplicationLogo(
|
|
423
|
+
accessToken,
|
|
424
|
+
'your-client-id',
|
|
425
|
+
logoBuffer,
|
|
426
|
+
'logo.png'
|
|
427
|
+
);
|
|
428
|
+
console.log('New logo URL:', result.logoUrl);
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
### Delete Application
|
|
432
|
+
|
|
433
|
+
```typescript
|
|
434
|
+
import { deleteApplication } from '@tekcify/auth-backend';
|
|
435
|
+
|
|
436
|
+
await deleteApplication(accessToken, 'your-client-id');
|
|
437
|
+
console.log('Application deleted');
|
|
438
|
+
```
|
|
439
|
+
|
|
290
440
|
## Complete NestJS Example
|
|
291
441
|
|
|
292
442
|
```typescript
|
|
@@ -335,7 +485,7 @@ export class ApiController {
|
|
|
335
485
|
|
|
336
486
|
```typescript
|
|
337
487
|
import express from 'express';
|
|
338
|
-
import { createAuthMiddleware } from '@tekcify/auth-backend
|
|
488
|
+
import { createAuthMiddleware, getUserProfile, updateUserProfile } from '@tekcify/auth-backend';
|
|
339
489
|
|
|
340
490
|
const app = express();
|
|
341
491
|
app.use(express.json());
|
|
@@ -354,17 +504,24 @@ app.get('/health', (req, res) => {
|
|
|
354
504
|
// Protected routes
|
|
355
505
|
app.use('/api', authMiddleware);
|
|
356
506
|
|
|
357
|
-
app.get('/api/profile', (req, res) => {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
})
|
|
507
|
+
app.get('/api/profile', async (req, res) => {
|
|
508
|
+
try {
|
|
509
|
+
const accessToken = req.headers.authorization?.replace('Bearer ', '');
|
|
510
|
+
const profile = await getUserProfile(accessToken!);
|
|
511
|
+
res.json(profile);
|
|
512
|
+
} catch (error) {
|
|
513
|
+
res.status(500).json({ error: error.message });
|
|
514
|
+
}
|
|
363
515
|
});
|
|
364
516
|
|
|
365
|
-
app.
|
|
366
|
-
|
|
367
|
-
|
|
517
|
+
app.put('/api/profile', async (req, res) => {
|
|
518
|
+
try {
|
|
519
|
+
const accessToken = req.headers.authorization?.replace('Bearer ', '');
|
|
520
|
+
const updated = await updateUserProfile(accessToken!, req.body);
|
|
521
|
+
res.json(updated);
|
|
522
|
+
} catch (error) {
|
|
523
|
+
res.status(500).json({ error: error.message });
|
|
524
|
+
}
|
|
368
525
|
});
|
|
369
526
|
|
|
370
527
|
app.listen(3000, () => {
|
|
@@ -372,6 +529,93 @@ app.listen(3000, () => {
|
|
|
372
529
|
});
|
|
373
530
|
```
|
|
374
531
|
|
|
532
|
+
## Complete Integration Example
|
|
533
|
+
|
|
534
|
+
Here's a complete example showing authentication, profile management, and application management:
|
|
535
|
+
|
|
536
|
+
```typescript
|
|
537
|
+
import {
|
|
538
|
+
OAuthClient,
|
|
539
|
+
generateCodeVerifier,
|
|
540
|
+
generateCodeChallenge,
|
|
541
|
+
} from '@tekcify/auth-core-client';
|
|
542
|
+
|
|
543
|
+
import {
|
|
544
|
+
getUserProfile,
|
|
545
|
+
updateUserProfile,
|
|
546
|
+
uploadProfilePicture,
|
|
547
|
+
listApplications,
|
|
548
|
+
createApplication,
|
|
549
|
+
uploadApplicationLogo,
|
|
550
|
+
} from '@tekcify/auth-backend';
|
|
551
|
+
|
|
552
|
+
// Step 1: Authenticate user (using OAuth flow)
|
|
553
|
+
const oauthClient = new OAuthClient({
|
|
554
|
+
clientId: 'your-client-id',
|
|
555
|
+
clientSecret: 'your-client-secret',
|
|
556
|
+
redirectUri: 'https://yourapp.com/callback',
|
|
557
|
+
scopes: ['read:profile', 'write:profile'],
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
// Generate PKCE parameters
|
|
561
|
+
const verifier = generateCodeVerifier();
|
|
562
|
+
const challenge = await generateCodeChallenge(verifier, 'S256');
|
|
563
|
+
|
|
564
|
+
// Build auth URL and redirect user
|
|
565
|
+
const authUrl = await oauthClient.buildAuthorizeUrl({
|
|
566
|
+
state: crypto.randomUUID(),
|
|
567
|
+
codeChallenge: challenge,
|
|
568
|
+
codeChallengeMethod: 'S256',
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
// After callback, exchange code for tokens
|
|
572
|
+
const tokens = await oauthClient.exchangeCode(code, verifier);
|
|
573
|
+
const accessToken = tokens.accessToken;
|
|
574
|
+
|
|
575
|
+
// Step 2: Manage user profile
|
|
576
|
+
const profile = await getUserProfile(accessToken);
|
|
577
|
+
console.log('Current profile:', profile);
|
|
578
|
+
|
|
579
|
+
// Update profile
|
|
580
|
+
const updated = await updateUserProfile(accessToken, {
|
|
581
|
+
firstName: 'John',
|
|
582
|
+
lastName: 'Doe',
|
|
583
|
+
});
|
|
584
|
+
console.log('Updated profile:', updated);
|
|
585
|
+
|
|
586
|
+
// Upload profile picture (browser)
|
|
587
|
+
const fileInput = document.querySelector<HTMLInputElement>('#profilePic');
|
|
588
|
+
if (fileInput?.files?.[0]) {
|
|
589
|
+
const result = await uploadProfilePicture(accessToken, fileInput.files[0]);
|
|
590
|
+
console.log('New avatar URL:', result.avatarUrl);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// Step 3: Manage applications
|
|
594
|
+
const apps = await listApplications(accessToken);
|
|
595
|
+
console.log('My applications:', apps);
|
|
596
|
+
|
|
597
|
+
// Create new application
|
|
598
|
+
const newApp = await createApplication(accessToken, {
|
|
599
|
+
name: 'My New App',
|
|
600
|
+
description: 'A cool application',
|
|
601
|
+
redirectUris: ['https://myapp.com/callback'],
|
|
602
|
+
scopes: ['read:profile'],
|
|
603
|
+
});
|
|
604
|
+
console.log('Created app:', newApp.clientId);
|
|
605
|
+
console.log('Client secret (save this!):', newApp.clientSecret);
|
|
606
|
+
|
|
607
|
+
// Upload application logo
|
|
608
|
+
const logoInput = document.querySelector<HTMLInputElement>('#logo');
|
|
609
|
+
if (logoInput?.files?.[0]) {
|
|
610
|
+
const logoResult = await uploadApplicationLogo(
|
|
611
|
+
accessToken,
|
|
612
|
+
newApp.clientId,
|
|
613
|
+
logoInput.files[0]
|
|
614
|
+
);
|
|
615
|
+
console.log('Logo uploaded:', logoResult.logoUrl);
|
|
616
|
+
}
|
|
617
|
+
```
|
|
618
|
+
|
|
375
619
|
## API Reference
|
|
376
620
|
|
|
377
621
|
### NestJS
|
|
@@ -412,6 +656,104 @@ createAuthMiddleware({
|
|
|
412
656
|
})
|
|
413
657
|
```
|
|
414
658
|
|
|
659
|
+
### User Profile Functions
|
|
660
|
+
|
|
661
|
+
#### `getUserProfile(accessToken)`
|
|
662
|
+
|
|
663
|
+
Get the authenticated user's profile.
|
|
664
|
+
|
|
665
|
+
```typescript
|
|
666
|
+
getUserProfile(accessToken: string): Promise<UserProfile>
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
#### `updateUserProfile(accessToken, data)`
|
|
670
|
+
|
|
671
|
+
Update the user's profile information.
|
|
672
|
+
|
|
673
|
+
```typescript
|
|
674
|
+
updateUserProfile(
|
|
675
|
+
accessToken: string,
|
|
676
|
+
data: UpdateProfileDto
|
|
677
|
+
): Promise<UserProfile>
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
#### `uploadProfilePicture(accessToken, file, fileName?)`
|
|
681
|
+
|
|
682
|
+
Upload a profile picture. Works with both File (browser) and Buffer (Node.js).
|
|
683
|
+
|
|
684
|
+
```typescript
|
|
685
|
+
uploadProfilePicture(
|
|
686
|
+
accessToken: string,
|
|
687
|
+
file: File | Buffer,
|
|
688
|
+
fileName?: string
|
|
689
|
+
): Promise<UploadResponse>
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
### Application Management Functions
|
|
693
|
+
|
|
694
|
+
#### `listApplications(accessToken)`
|
|
695
|
+
|
|
696
|
+
Get all applications owned by the authenticated user.
|
|
697
|
+
|
|
698
|
+
```typescript
|
|
699
|
+
listApplications(accessToken: string): Promise<Application[]>
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
#### `getApplicationByClientId(clientId)`
|
|
703
|
+
|
|
704
|
+
Get public application information (no auth required).
|
|
705
|
+
|
|
706
|
+
```typescript
|
|
707
|
+
getApplicationByClientId(clientId: string): Promise<Application>
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
#### `createApplication(accessToken, data)`
|
|
711
|
+
|
|
712
|
+
Create a new OAuth application.
|
|
713
|
+
|
|
714
|
+
```typescript
|
|
715
|
+
createApplication(
|
|
716
|
+
accessToken: string,
|
|
717
|
+
data: CreateApplicationDto
|
|
718
|
+
): Promise<CreateApplicationResponse>
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
#### `updateApplication(accessToken, clientId, data)`
|
|
722
|
+
|
|
723
|
+
Update an existing application.
|
|
724
|
+
|
|
725
|
+
```typescript
|
|
726
|
+
updateApplication(
|
|
727
|
+
accessToken: string,
|
|
728
|
+
clientId: string,
|
|
729
|
+
data: UpdateApplicationDto
|
|
730
|
+
): Promise<{ message: string }>
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
#### `uploadApplicationLogo(accessToken, clientId, file, fileName?)`
|
|
734
|
+
|
|
735
|
+
Upload an application logo. Works with both File (browser) and Buffer (Node.js).
|
|
736
|
+
|
|
737
|
+
```typescript
|
|
738
|
+
uploadApplicationLogo(
|
|
739
|
+
accessToken: string,
|
|
740
|
+
clientId: string,
|
|
741
|
+
file: File | Buffer,
|
|
742
|
+
fileName?: string
|
|
743
|
+
): Promise<LogoUploadResponse>
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
#### `deleteApplication(accessToken, clientId)`
|
|
747
|
+
|
|
748
|
+
Delete an application.
|
|
749
|
+
|
|
750
|
+
```typescript
|
|
751
|
+
deleteApplication(
|
|
752
|
+
accessToken: string,
|
|
753
|
+
clientId: string
|
|
754
|
+
): Promise<{ message: string }>
|
|
755
|
+
```
|
|
756
|
+
|
|
415
757
|
### Utilities
|
|
416
758
|
|
|
417
759
|
#### `verifyAccessToken(token, options)`
|
|
@@ -426,15 +768,12 @@ verifyAccessToken(token: string, {
|
|
|
426
768
|
}): VerifiedToken
|
|
427
769
|
```
|
|
428
770
|
|
|
429
|
-
#### `fetchUserInfo(
|
|
771
|
+
#### `fetchUserInfo(accessToken)`
|
|
430
772
|
|
|
431
|
-
Fetches user information from the auth server
|
|
773
|
+
Fetches user information from the Tekcify auth server using the centralized `AUTH_SERVER_URL`.
|
|
432
774
|
|
|
433
775
|
```typescript
|
|
434
|
-
fetchUserInfo(
|
|
435
|
-
authServerUrl: string,
|
|
436
|
-
accessToken: string
|
|
437
|
-
): Promise<UserInfo>
|
|
776
|
+
fetchUserInfo(accessToken: string): Promise<UserInfo>
|
|
438
777
|
```
|
|
439
778
|
|
|
440
779
|
### Types
|
|
@@ -450,6 +789,59 @@ interface VerifiedToken {
|
|
|
450
789
|
payload: TokenPayload;
|
|
451
790
|
valid: boolean;
|
|
452
791
|
}
|
|
792
|
+
|
|
793
|
+
interface UserProfile {
|
|
794
|
+
userId: string;
|
|
795
|
+
email: string;
|
|
796
|
+
firstName: string | null;
|
|
797
|
+
lastName: string | null;
|
|
798
|
+
avatarUrl: string | null;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
interface UpdateProfileDto {
|
|
802
|
+
firstName?: string;
|
|
803
|
+
lastName?: string;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
interface UploadResponse {
|
|
807
|
+
avatarUrl: string;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
interface Application {
|
|
811
|
+
clientId: string;
|
|
812
|
+
name: string;
|
|
813
|
+
description: string | null;
|
|
814
|
+
logoUrl: string | null;
|
|
815
|
+
redirectUris: string[];
|
|
816
|
+
authorizedOrigins: string[] | null;
|
|
817
|
+
scopes: string[];
|
|
818
|
+
createdAt: string;
|
|
819
|
+
updatedAt: string;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
interface CreateApplicationDto {
|
|
823
|
+
name: string;
|
|
824
|
+
description?: string;
|
|
825
|
+
redirectUris: string[];
|
|
826
|
+
authorizedOrigins?: string[];
|
|
827
|
+
scopes: string[];
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
interface CreateApplicationResponse extends Application {
|
|
831
|
+
clientSecret: string; // Only returned once!
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
interface UpdateApplicationDto {
|
|
835
|
+
name?: string;
|
|
836
|
+
description?: string;
|
|
837
|
+
redirectUris?: string[];
|
|
838
|
+
authorizedOrigins?: string[];
|
|
839
|
+
scopes?: string[];
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
interface LogoUploadResponse {
|
|
843
|
+
logoUrl: string;
|
|
844
|
+
}
|
|
453
845
|
```
|
|
454
846
|
|
|
455
847
|
## Error Handling
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export interface Application {
|
|
2
|
+
clientId: string;
|
|
3
|
+
name: string;
|
|
4
|
+
description: string | null;
|
|
5
|
+
logoUrl: string | null;
|
|
6
|
+
redirectUris: string[];
|
|
7
|
+
authorizedOrigins: string[] | null;
|
|
8
|
+
scopes: string[];
|
|
9
|
+
createdAt: string;
|
|
10
|
+
updatedAt: string;
|
|
11
|
+
}
|
|
12
|
+
export interface CreateApplicationDto {
|
|
13
|
+
name: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
redirectUris: string[];
|
|
16
|
+
authorizedOrigins?: string[];
|
|
17
|
+
scopes: string[];
|
|
18
|
+
}
|
|
19
|
+
export interface CreateApplicationResponse extends Application {
|
|
20
|
+
clientSecret: string;
|
|
21
|
+
}
|
|
22
|
+
export interface UpdateApplicationDto {
|
|
23
|
+
name?: string;
|
|
24
|
+
description?: string;
|
|
25
|
+
redirectUris?: string[];
|
|
26
|
+
authorizedOrigins?: string[];
|
|
27
|
+
scopes?: string[];
|
|
28
|
+
}
|
|
29
|
+
export interface LogoUploadResponse {
|
|
30
|
+
logoUrl: string;
|
|
31
|
+
}
|
|
32
|
+
export interface ApplicationStats {
|
|
33
|
+
total: number;
|
|
34
|
+
active: number;
|
|
35
|
+
inactive: number;
|
|
36
|
+
}
|
|
37
|
+
export interface PaginationInfo {
|
|
38
|
+
page: number;
|
|
39
|
+
limit: number;
|
|
40
|
+
total: number;
|
|
41
|
+
totalPages: number;
|
|
42
|
+
}
|
|
43
|
+
export interface ListApplicationsResponse {
|
|
44
|
+
success: boolean;
|
|
45
|
+
stats: ApplicationStats;
|
|
46
|
+
data: Application[];
|
|
47
|
+
pagination: PaginationInfo;
|
|
48
|
+
}
|
|
49
|
+
export declare function listApplications(accessToken: string, options?: {
|
|
50
|
+
page?: number;
|
|
51
|
+
limit?: number;
|
|
52
|
+
}): Promise<ListApplicationsResponse>;
|
|
53
|
+
export declare function getApplicationByClientId(clientId: string): Promise<Omit<Application, 'createdAt' | 'updatedAt'>>;
|
|
54
|
+
export declare function createApplication(accessToken: string, data: CreateApplicationDto): Promise<CreateApplicationResponse>;
|
|
55
|
+
export declare function updateApplication(accessToken: string, clientId: string, data: UpdateApplicationDto): Promise<{
|
|
56
|
+
message: string;
|
|
57
|
+
}>;
|
|
58
|
+
export declare function deleteApplication(accessToken: string, clientId: string): Promise<{
|
|
59
|
+
message: string;
|
|
60
|
+
}>;
|
|
61
|
+
export declare function uploadApplicationLogo(accessToken: string, clientId: string, file: Blob | File, fileName?: string): Promise<LogoUploadResponse>;
|
|
62
|
+
//# sourceMappingURL=application-management.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"application-management.d.ts","sourceRoot":"","sources":["../src/application-management.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,iBAAiB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACnC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,yBAA0B,SAAQ,WAAW;IAC5D,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,gBAAgB,CAAC;IACxB,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,UAAU,EAAE,cAAc,CAAC;CAC5B;AA8FD,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1C,OAAO,CAAC,wBAAwB,CAAC,CAWnC;AAED,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,WAAW,CAAC,CAAC,CAMvD;AAED,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,yBAAyB,CAAC,CAQpC;AAED,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAQ9B;AAED,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAO9B;AAED,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,IAAI,GAAG,IAAI,EACjB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,kBAAkB,CAAC,CAgB7B"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.listApplications = listApplications;
|
|
4
|
+
exports.getApplicationByClientId = getApplicationByClientId;
|
|
5
|
+
exports.createApplication = createApplication;
|
|
6
|
+
exports.updateApplication = updateApplication;
|
|
7
|
+
exports.deleteApplication = deleteApplication;
|
|
8
|
+
exports.uploadApplicationLogo = uploadApplicationLogo;
|
|
9
|
+
const auth_core_client_1 = require("@tekcify/auth-core-client");
|
|
10
|
+
function buildUrl(path, query) {
|
|
11
|
+
const url = new URL(`${auth_core_client_1.AUTH_SERVER_URL}${path}`);
|
|
12
|
+
Object.entries(query ?? {}).forEach(([key, value]) => {
|
|
13
|
+
if (value !== undefined) {
|
|
14
|
+
url.searchParams.set(key, String(value));
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
return url.toString();
|
|
18
|
+
}
|
|
19
|
+
function extractMessage(payload, fallback) {
|
|
20
|
+
if (typeof payload === 'string' && payload.trim()) {
|
|
21
|
+
return payload;
|
|
22
|
+
}
|
|
23
|
+
if (payload &&
|
|
24
|
+
typeof payload === 'object' &&
|
|
25
|
+
'message' in payload &&
|
|
26
|
+
typeof payload.message === 'string' &&
|
|
27
|
+
payload.message.trim()) {
|
|
28
|
+
return payload.message;
|
|
29
|
+
}
|
|
30
|
+
return fallback;
|
|
31
|
+
}
|
|
32
|
+
async function request(config) {
|
|
33
|
+
const { path, method, defaultError, token, query, body, formData, headers } = config;
|
|
34
|
+
const url = buildUrl(path, query);
|
|
35
|
+
const hasJsonBody = body !== undefined && !formData;
|
|
36
|
+
const mergedHeaders = new Headers();
|
|
37
|
+
if (token) {
|
|
38
|
+
mergedHeaders.set('Authorization', `Bearer ${token}`);
|
|
39
|
+
}
|
|
40
|
+
if (hasJsonBody) {
|
|
41
|
+
mergedHeaders.set('Content-Type', 'application/json');
|
|
42
|
+
}
|
|
43
|
+
if (headers) {
|
|
44
|
+
new Headers(headers).forEach((value, key) => {
|
|
45
|
+
mergedHeaders.set(key, value);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
const init = {
|
|
49
|
+
method,
|
|
50
|
+
headers: mergedHeaders,
|
|
51
|
+
body: formData ?? (hasJsonBody ? JSON.stringify(body) : undefined),
|
|
52
|
+
};
|
|
53
|
+
let response;
|
|
54
|
+
try {
|
|
55
|
+
response = await fetch(url, init);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
if (error instanceof Error) {
|
|
59
|
+
throw new Error(`${defaultError}: ${error.message}`);
|
|
60
|
+
}
|
|
61
|
+
throw new Error(defaultError);
|
|
62
|
+
}
|
|
63
|
+
const payload = await response.json().catch(() => null);
|
|
64
|
+
if (!response.ok) {
|
|
65
|
+
const message = extractMessage(payload, `${defaultError}: ${response.statusText} (Status: ${response.status})`);
|
|
66
|
+
throw new Error(message);
|
|
67
|
+
}
|
|
68
|
+
if (payload === null) {
|
|
69
|
+
throw new Error(`${defaultError}: Invalid response`);
|
|
70
|
+
}
|
|
71
|
+
return payload;
|
|
72
|
+
}
|
|
73
|
+
async function listApplications(accessToken, options) {
|
|
74
|
+
const page = options?.page ?? 1;
|
|
75
|
+
const limit = options?.limit ?? 10;
|
|
76
|
+
return request({
|
|
77
|
+
path: '/api/applications',
|
|
78
|
+
method: 'GET',
|
|
79
|
+
defaultError: 'Failed to list applications',
|
|
80
|
+
token: accessToken,
|
|
81
|
+
query: { page, limit },
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
async function getApplicationByClientId(clientId) {
|
|
85
|
+
return request({
|
|
86
|
+
path: `/api/applications/public/${clientId}`,
|
|
87
|
+
method: 'GET',
|
|
88
|
+
defaultError: 'Failed to get application',
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
async function createApplication(accessToken, data) {
|
|
92
|
+
return request({
|
|
93
|
+
path: '/api/applications',
|
|
94
|
+
method: 'POST',
|
|
95
|
+
defaultError: 'Failed to create application',
|
|
96
|
+
token: accessToken,
|
|
97
|
+
body: data,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
async function updateApplication(accessToken, clientId, data) {
|
|
101
|
+
return request({
|
|
102
|
+
path: `/api/applications/${clientId}`,
|
|
103
|
+
method: 'PUT',
|
|
104
|
+
defaultError: 'Failed to update application',
|
|
105
|
+
token: accessToken,
|
|
106
|
+
body: data,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
async function deleteApplication(accessToken, clientId) {
|
|
110
|
+
return request({
|
|
111
|
+
path: `/api/applications/${clientId}`,
|
|
112
|
+
method: 'DELETE',
|
|
113
|
+
defaultError: 'Failed to delete application',
|
|
114
|
+
token: accessToken,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
async function uploadApplicationLogo(accessToken, clientId, file, fileName) {
|
|
118
|
+
const formData = new FormData();
|
|
119
|
+
if (fileName && !(file instanceof File)) {
|
|
120
|
+
formData.append('file', file, fileName);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
formData.append('file', file);
|
|
124
|
+
}
|
|
125
|
+
return request({
|
|
126
|
+
path: `/api/applications/${clientId}/logo`,
|
|
127
|
+
method: 'POST',
|
|
128
|
+
defaultError: 'Failed to upload application logo',
|
|
129
|
+
token: accessToken,
|
|
130
|
+
formData,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=application-management.js.map
|