@vunexa/lixa 0.1.6-alpha.2 → 0.1.6-alpha.4
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 +114 -47
- package/README.template.md +113 -17
- package/dist/dao/types.d.ts +47 -0
- package/dist/dao/types.d.ts.map +1 -1
- package/dist/export-types/index.d.ts +95 -5
- package/dist/index.cjs +185 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +94 -6
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +185 -12
- package/dist/index.js.map +1 -1
- package/dist/lixa.d.ts +37 -5
- package/dist/lixa.d.ts.map +1 -1
- package/dist/models/session.d.ts +2 -0
- package/dist/models/session.d.ts.map +1 -1
- package/dist/types.d.ts +11 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -28,36 +28,7 @@ A flexible, provider-agnostic OAuth 2.0 and OpenID Connect (OIDC) client library
|
|
|
28
28
|
|
|
29
29
|
## Architecture Overview
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
graph TD
|
|
33
|
-
User([User Client / Browser])
|
|
34
|
-
|
|
35
|
-
subgraph Lixa ["Lixa Core Engine"]
|
|
36
|
-
AuthNGuard["Primary AuthN Guard<br/>(Minimal Identity Scopes Only)"]
|
|
37
|
-
SessionMgr["Session Handler & Unified Session"]
|
|
38
|
-
AccountLinker["Account Linker<br/>(AUTO_LINK_BY_VERIFIED_EMAIL)"]
|
|
39
|
-
ResourceConn["Resource Connection API<br/>(Post-Login AuthZ)"]
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
subgraph IdentityProviders ["Identity Providers (AuthN)"]
|
|
43
|
-
GoogleAuth["Google / OIDC"]
|
|
44
|
-
GitHubAuth["GitHub OAuth"]
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
subgraph ResourceProviders ["Resource APIs (AuthZ)"]
|
|
48
|
-
GitHubAPI["GitHub API (repos, orgs)"]
|
|
49
|
-
GoogleDriveAPI["Google Drive API"]
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
User -->|"1. Primary Login / Link Account"| AuthNGuard
|
|
53
|
-
AuthNGuard -->|"Request Identity"| IdentityProviders
|
|
54
|
-
IdentityProviders -->|"Tokens + UserInfo"| AccountLinker
|
|
55
|
-
AccountLinker -->|"Unified Session (session.accounts)"| SessionMgr
|
|
56
|
-
|
|
57
|
-
User -->|"2. Connect Resource API (Post-Login)"| ResourceConn
|
|
58
|
-
ResourceConn -->|"Request Permissions (repo, drive)"| ResourceProviders
|
|
59
|
-
ResourceProviders -->|"Resource Access Tokens"| SessionMgr
|
|
60
|
-
```
|
|
31
|
+

|
|
61
32
|
|
|
62
33
|
---
|
|
63
34
|
|
|
@@ -216,15 +187,16 @@ app.get("/connect/github/callback", async (req, res) => {
|
|
|
216
187
|
res.redirect("/dashboard");
|
|
217
188
|
});
|
|
218
189
|
|
|
219
|
-
// 3. Query Connected Resource Access Token
|
|
190
|
+
// 3. Query Connected Resource Access Token (Auto-Refreshes Expired Tokens)
|
|
220
191
|
app.get("/api/github/repos", async (req, res) => {
|
|
192
|
+
// Queries by active session OR user ID, auto-refreshing expired access tokens
|
|
221
193
|
const resource = await lixa.getConnectedResource(req.cookies.session_id, "github");
|
|
222
194
|
|
|
223
195
|
if (!resource) {
|
|
224
196
|
return res.status(403).json({ error: "GitHub resource not connected" });
|
|
225
197
|
}
|
|
226
198
|
|
|
227
|
-
// Call GitHub API with resource access token
|
|
199
|
+
// Call GitHub API with active resource access token
|
|
228
200
|
const response = await fetch("https://api.github.com/user/repos", {
|
|
229
201
|
headers: { Authorization: `Bearer ${resource.accessToken}` },
|
|
230
202
|
});
|
|
@@ -233,7 +205,10 @@ app.get("/api/github/repos", async (req, res) => {
|
|
|
233
205
|
res.json(repos);
|
|
234
206
|
});
|
|
235
207
|
|
|
236
|
-
// 4.
|
|
208
|
+
// 4. Query Resource Directly by User ID (e.g. inside background cron jobs or webhooks)
|
|
209
|
+
const githubResource = await lixa.getUserResource(userId, "github");
|
|
210
|
+
|
|
211
|
+
// 5. Disconnect Resource Provider
|
|
237
212
|
app.delete("/connect/github", async (req, res) => {
|
|
238
213
|
await lixa.disconnectResource(req.cookies.session_id, "github");
|
|
239
214
|
res.json({ success: true });
|
|
@@ -371,10 +346,8 @@ export const lixa = new Lixa({
|
|
|
371
346
|
```json
|
|
372
347
|
{
|
|
373
348
|
"id": "e4a91f82c3b4a07f",
|
|
374
|
-
"token": "ya29.a0ARW5m7...",
|
|
375
349
|
"userId": "1049281048",
|
|
376
350
|
"email": "alex.developer@example.com",
|
|
377
|
-
"provider": "google",
|
|
378
351
|
"accounts": {
|
|
379
352
|
"google": {
|
|
380
353
|
"provider": "google",
|
|
@@ -398,11 +371,6 @@ export const lixa = new Lixa({
|
|
|
398
371
|
"scopes": ["repo", "read:org"],
|
|
399
372
|
"connectedAt": 1771657300000
|
|
400
373
|
}
|
|
401
|
-
},
|
|
402
|
-
"raw": {
|
|
403
|
-
"access_token": "ya29.a0ARW5m7...",
|
|
404
|
-
"token_type": "Bearer",
|
|
405
|
-
"expires_in": 3599
|
|
406
374
|
}
|
|
407
375
|
}
|
|
408
376
|
```
|
|
@@ -513,10 +481,8 @@ export const lixa = new Lixa({
|
|
|
513
481
|
"ttl": 1771743600,
|
|
514
482
|
"sessionData": {
|
|
515
483
|
"id": "e4a91f82c3b4a07f",
|
|
516
|
-
"token": "ya29.a0ARW5m7...",
|
|
517
484
|
"userId": "1049281048",
|
|
518
485
|
"email": "alex.developer@example.com",
|
|
519
|
-
"provider": "google",
|
|
520
486
|
"accounts": {
|
|
521
487
|
"google": {
|
|
522
488
|
"provider": "google",
|
|
@@ -540,14 +506,115 @@ export const lixa = new Lixa({
|
|
|
540
506
|
"scopes": ["repo", "read:org"],
|
|
541
507
|
"connectedAt": 1771657300000
|
|
542
508
|
}
|
|
543
|
-
},
|
|
544
|
-
"raw": {
|
|
545
|
-
"access_token": "ya29.a0ARW5m7...",
|
|
546
|
-
"token_type": "Bearer",
|
|
547
|
-
"expires_in": 3599
|
|
548
509
|
}
|
|
510
|
+
---
|
|
511
|
+
|
|
512
|
+
## Custom Resource Storage Implementation (`ResourceStorage`)
|
|
513
|
+
|
|
514
|
+
While `SessionStorage` manages short-lived user authentication sessions (indexed by `sessionId`), **`ResourceStorage`** manages long-lived third-party API tokens (**AuthZ**) bound directly to a **User ID** (or Email). This ensures that third-party credentials (such as GitHub Repositories or Google Drive) persist across session expirations and logouts.
|
|
515
|
+
|
|
516
|
+
### `ResourceStorage` Interface
|
|
517
|
+
|
|
518
|
+
```typescript
|
|
519
|
+
export interface ResourceStorage {
|
|
520
|
+
saveResource(userId: string, provider: string, resource: ConnectedResource): Promise<void>;
|
|
521
|
+
getResource(userId: string, provider: string): Promise<ConnectedResource | null>;
|
|
522
|
+
getUserResources(userId: string): Promise<Record<string, ConnectedResource>>;
|
|
523
|
+
deleteResource(userId: string, provider: string): Promise<void>;
|
|
524
|
+
}
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
### 1. SQLite Resource Storage (`better-sqlite3`)
|
|
528
|
+
|
|
529
|
+
#### Table Schema (SQL DDL)
|
|
530
|
+
|
|
531
|
+
```sql
|
|
532
|
+
CREATE TABLE IF NOT EXISTS user_resources (
|
|
533
|
+
user_id TEXT NOT NULL,
|
|
534
|
+
provider TEXT NOT NULL,
|
|
535
|
+
data TEXT NOT NULL,
|
|
536
|
+
updated_at INTEGER NOT NULL,
|
|
537
|
+
PRIMARY KEY (user_id, provider)
|
|
538
|
+
);
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
#### TypeScript Implementation
|
|
542
|
+
|
|
543
|
+
```typescript
|
|
544
|
+
import Database from "better-sqlite3";
|
|
545
|
+
import { Lixa, type ResourceStorage, type ConnectedResource } from "@vunexa/lixa";
|
|
546
|
+
|
|
547
|
+
export class SqliteResourceStorage implements ResourceStorage {
|
|
548
|
+
private db = new Database("lixa_resources.db");
|
|
549
|
+
|
|
550
|
+
constructor() {
|
|
551
|
+
this.db.exec(`
|
|
552
|
+
CREATE TABLE IF NOT EXISTS user_resources (
|
|
553
|
+
user_id TEXT NOT NULL,
|
|
554
|
+
provider TEXT NOT NULL,
|
|
555
|
+
data TEXT NOT NULL,
|
|
556
|
+
updated_at INTEGER NOT NULL,
|
|
557
|
+
PRIMARY KEY (user_id, provider)
|
|
558
|
+
);
|
|
559
|
+
`);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
async saveResource(userId: string, provider: string, resource: ConnectedResource): Promise<void> {
|
|
563
|
+
const stmt = this.db.prepare(`
|
|
564
|
+
INSERT INTO user_resources (user_id, provider, data, updated_at)
|
|
565
|
+
VALUES (?, ?, ?, ?)
|
|
566
|
+
ON CONFLICT(user_id, provider) DO UPDATE SET
|
|
567
|
+
data = excluded.data,
|
|
568
|
+
updated_at = excluded.updated_at
|
|
569
|
+
`);
|
|
570
|
+
stmt.run(userId, provider.toLowerCase(), JSON.stringify(resource), Date.now());
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
async getResource(userId: string, provider: string): Promise<ConnectedResource | null> {
|
|
574
|
+
const stmt = this.db.prepare(`SELECT data FROM user_resources WHERE user_id = ? AND provider = ?`);
|
|
575
|
+
const row = stmt.get(userId, provider.toLowerCase()) as { data: string } | undefined;
|
|
576
|
+
return row ? (JSON.parse(row.data) as ConnectedResource) : null;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
async getUserResources(userId: string): Promise<Record<string, ConnectedResource>> {
|
|
580
|
+
const stmt = this.db.prepare(`SELECT provider, data FROM user_resources WHERE user_id = ?`);
|
|
581
|
+
const rows = stmt.all(userId) as Array<{ provider: string; data: string }>;
|
|
582
|
+
const result: Record<string, ConnectedResource> = {};
|
|
583
|
+
for (const r of rows) {
|
|
584
|
+
result[r.provider] = JSON.parse(r.data);
|
|
585
|
+
}
|
|
586
|
+
return result;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
async deleteResource(userId: string, provider: string): Promise<void> {
|
|
590
|
+
const stmt = this.db.prepare(`DELETE FROM user_resources WHERE user_id = ? AND provider = ?`);
|
|
591
|
+
stmt.run(userId, provider.toLowerCase());
|
|
549
592
|
}
|
|
550
593
|
}
|
|
594
|
+
|
|
595
|
+
// Pass to Lixa instance via resourceHandler
|
|
596
|
+
export const lixa = new Lixa({
|
|
597
|
+
resourceHandler: {
|
|
598
|
+
resourceStorage: new SqliteResourceStorage(),
|
|
599
|
+
},
|
|
600
|
+
providers: { /* ... */ },
|
|
601
|
+
});
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
### 2. Querying Connected Resources Directly by User ID
|
|
605
|
+
|
|
606
|
+
`ResourceStorage` enables background workers, cron jobs, and webhooks to access third-party API credentials by `userId` without an active HTTP session:
|
|
607
|
+
|
|
608
|
+
```typescript
|
|
609
|
+
// Background worker querying user's GitHub Repos token
|
|
610
|
+
const githubResource = await lixa.getUserResource(user.id, "github");
|
|
611
|
+
|
|
612
|
+
if (githubResource) {
|
|
613
|
+
// Lixa auto-refreshes expired access tokens transparently!
|
|
614
|
+
const response = await fetch("https://api.github.com/user/repos", {
|
|
615
|
+
headers: { Authorization: `Bearer ${githubResource.accessToken}` },
|
|
616
|
+
});
|
|
617
|
+
}
|
|
551
618
|
```
|
|
552
619
|
|
|
553
620
|
---
|
package/README.template.md
CHANGED
|
@@ -277,15 +277,16 @@ app.get("/connect/github/callback", async (req, res) => {
|
|
|
277
277
|
res.redirect("/dashboard");
|
|
278
278
|
});
|
|
279
279
|
|
|
280
|
-
// 3. Query Connected Resource Access Token
|
|
280
|
+
// 3. Query Connected Resource Access Token (Auto-Refreshes Expired Tokens)
|
|
281
281
|
app.get("/api/github/repos", async (req, res) => {
|
|
282
|
+
// Queries by active session OR user ID, auto-refreshing expired access tokens
|
|
282
283
|
const resource = await lixa.getConnectedResource(req.cookies.session_id, "github");
|
|
283
284
|
|
|
284
285
|
if (!resource) {
|
|
285
286
|
return res.status(403).json({ error: "GitHub resource not connected" });
|
|
286
287
|
}
|
|
287
288
|
|
|
288
|
-
// Call GitHub API with resource access token
|
|
289
|
+
// Call GitHub API with active resource access token
|
|
289
290
|
const response = await fetch("https://api.github.com/user/repos", {
|
|
290
291
|
headers: { Authorization: `Bearer ${resource.accessToken}` },
|
|
291
292
|
});
|
|
@@ -294,7 +295,10 @@ app.get("/api/github/repos", async (req, res) => {
|
|
|
294
295
|
res.json(repos);
|
|
295
296
|
});
|
|
296
297
|
|
|
297
|
-
// 4.
|
|
298
|
+
// 4. Query Resource Directly by User ID (e.g. inside background cron jobs or webhooks)
|
|
299
|
+
const githubResource = await lixa.getUserResource(userId, "github");
|
|
300
|
+
|
|
301
|
+
// 5. Disconnect Resource Provider
|
|
298
302
|
app.delete("/connect/github", async (req, res) => {
|
|
299
303
|
await lixa.disconnectResource(req.cookies.session_id, "github");
|
|
300
304
|
res.json({ success: true });
|
|
@@ -432,10 +436,8 @@ export const lixa = new Lixa({
|
|
|
432
436
|
```json
|
|
433
437
|
{
|
|
434
438
|
"id": "e4a91f82c3b4a07f",
|
|
435
|
-
"token": "ya29.a0ARW5m7...",
|
|
436
439
|
"userId": "1049281048",
|
|
437
440
|
"email": "alex.developer@example.com",
|
|
438
|
-
"provider": "google",
|
|
439
441
|
"accounts": {
|
|
440
442
|
"google": {
|
|
441
443
|
"provider": "google",
|
|
@@ -459,11 +461,6 @@ export const lixa = new Lixa({
|
|
|
459
461
|
"scopes": ["repo", "read:org"],
|
|
460
462
|
"connectedAt": 1771657300000
|
|
461
463
|
}
|
|
462
|
-
},
|
|
463
|
-
"raw": {
|
|
464
|
-
"access_token": "ya29.a0ARW5m7...",
|
|
465
|
-
"token_type": "Bearer",
|
|
466
|
-
"expires_in": 3599
|
|
467
464
|
}
|
|
468
465
|
}
|
|
469
466
|
```
|
|
@@ -574,10 +571,8 @@ export const lixa = new Lixa({
|
|
|
574
571
|
"ttl": 1771743600,
|
|
575
572
|
"sessionData": {
|
|
576
573
|
"id": "e4a91f82c3b4a07f",
|
|
577
|
-
"token": "ya29.a0ARW5m7...",
|
|
578
574
|
"userId": "1049281048",
|
|
579
575
|
"email": "alex.developer@example.com",
|
|
580
|
-
"provider": "google",
|
|
581
576
|
"accounts": {
|
|
582
577
|
"google": {
|
|
583
578
|
"provider": "google",
|
|
@@ -601,14 +596,115 @@ export const lixa = new Lixa({
|
|
|
601
596
|
"scopes": ["repo", "read:org"],
|
|
602
597
|
"connectedAt": 1771657300000
|
|
603
598
|
}
|
|
604
|
-
},
|
|
605
|
-
"raw": {
|
|
606
|
-
"access_token": "ya29.a0ARW5m7...",
|
|
607
|
-
"token_type": "Bearer",
|
|
608
|
-
"expires_in": 3599
|
|
609
599
|
}
|
|
600
|
+
---
|
|
601
|
+
|
|
602
|
+
## Custom Resource Storage Implementation (`ResourceStorage`)
|
|
603
|
+
|
|
604
|
+
While `SessionStorage` manages short-lived user authentication sessions (indexed by `sessionId`), **`ResourceStorage`** manages long-lived third-party API tokens (**AuthZ**) bound directly to a **User ID** (or Email). This ensures that third-party credentials (such as GitHub Repositories or Google Drive) persist across session expirations and logouts.
|
|
605
|
+
|
|
606
|
+
### `ResourceStorage` Interface
|
|
607
|
+
|
|
608
|
+
```typescript
|
|
609
|
+
export interface ResourceStorage {
|
|
610
|
+
saveResource(userId: string, provider: string, resource: ConnectedResource): Promise<void>;
|
|
611
|
+
getResource(userId: string, provider: string): Promise<ConnectedResource | null>;
|
|
612
|
+
getUserResources(userId: string): Promise<Record<string, ConnectedResource>>;
|
|
613
|
+
deleteResource(userId: string, provider: string): Promise<void>;
|
|
614
|
+
}
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
### 1. SQLite Resource Storage (`better-sqlite3`)
|
|
618
|
+
|
|
619
|
+
#### Table Schema (SQL DDL)
|
|
620
|
+
|
|
621
|
+
```sql
|
|
622
|
+
CREATE TABLE IF NOT EXISTS user_resources (
|
|
623
|
+
user_id TEXT NOT NULL,
|
|
624
|
+
provider TEXT NOT NULL,
|
|
625
|
+
data TEXT NOT NULL,
|
|
626
|
+
updated_at INTEGER NOT NULL,
|
|
627
|
+
PRIMARY KEY (user_id, provider)
|
|
628
|
+
);
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
#### TypeScript Implementation
|
|
632
|
+
|
|
633
|
+
```typescript
|
|
634
|
+
import Database from "better-sqlite3";
|
|
635
|
+
import { Lixa, type ResourceStorage, type ConnectedResource } from "@vunexa/lixa";
|
|
636
|
+
|
|
637
|
+
export class SqliteResourceStorage implements ResourceStorage {
|
|
638
|
+
private db = new Database("lixa_resources.db");
|
|
639
|
+
|
|
640
|
+
constructor() {
|
|
641
|
+
this.db.exec(`
|
|
642
|
+
CREATE TABLE IF NOT EXISTS user_resources (
|
|
643
|
+
user_id TEXT NOT NULL,
|
|
644
|
+
provider TEXT NOT NULL,
|
|
645
|
+
data TEXT NOT NULL,
|
|
646
|
+
updated_at INTEGER NOT NULL,
|
|
647
|
+
PRIMARY KEY (user_id, provider)
|
|
648
|
+
);
|
|
649
|
+
`);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
async saveResource(userId: string, provider: string, resource: ConnectedResource): Promise<void> {
|
|
653
|
+
const stmt = this.db.prepare(`
|
|
654
|
+
INSERT INTO user_resources (user_id, provider, data, updated_at)
|
|
655
|
+
VALUES (?, ?, ?, ?)
|
|
656
|
+
ON CONFLICT(user_id, provider) DO UPDATE SET
|
|
657
|
+
data = excluded.data,
|
|
658
|
+
updated_at = excluded.updated_at
|
|
659
|
+
`);
|
|
660
|
+
stmt.run(userId, provider.toLowerCase(), JSON.stringify(resource), Date.now());
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
async getResource(userId: string, provider: string): Promise<ConnectedResource | null> {
|
|
664
|
+
const stmt = this.db.prepare(`SELECT data FROM user_resources WHERE user_id = ? AND provider = ?`);
|
|
665
|
+
const row = stmt.get(userId, provider.toLowerCase()) as { data: string } | undefined;
|
|
666
|
+
return row ? (JSON.parse(row.data) as ConnectedResource) : null;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
async getUserResources(userId: string): Promise<Record<string, ConnectedResource>> {
|
|
670
|
+
const stmt = this.db.prepare(`SELECT provider, data FROM user_resources WHERE user_id = ?`);
|
|
671
|
+
const rows = stmt.all(userId) as Array<{ provider: string; data: string }>;
|
|
672
|
+
const result: Record<string, ConnectedResource> = {};
|
|
673
|
+
for (const r of rows) {
|
|
674
|
+
result[r.provider] = JSON.parse(r.data);
|
|
675
|
+
}
|
|
676
|
+
return result;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
async deleteResource(userId: string, provider: string): Promise<void> {
|
|
680
|
+
const stmt = this.db.prepare(`DELETE FROM user_resources WHERE user_id = ? AND provider = ?`);
|
|
681
|
+
stmt.run(userId, provider.toLowerCase());
|
|
610
682
|
}
|
|
611
683
|
}
|
|
684
|
+
|
|
685
|
+
// Pass to Lixa instance via resourceHandler
|
|
686
|
+
export const lixa = new Lixa({
|
|
687
|
+
resourceHandler: {
|
|
688
|
+
resourceStorage: new SqliteResourceStorage(),
|
|
689
|
+
},
|
|
690
|
+
providers: { /* ... */ },
|
|
691
|
+
});
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
### 2. Querying Connected Resources Directly by User ID
|
|
695
|
+
|
|
696
|
+
`ResourceStorage` enables background workers, cron jobs, and webhooks to access third-party API credentials by `userId` without an active HTTP session:
|
|
697
|
+
|
|
698
|
+
```typescript
|
|
699
|
+
// Background worker querying user's GitHub Repos token
|
|
700
|
+
const githubResource = await lixa.getUserResource(user.id, "github");
|
|
701
|
+
|
|
702
|
+
if (githubResource) {
|
|
703
|
+
// Lixa auto-refreshes expired access tokens transparently!
|
|
704
|
+
const response = await fetch("https://api.github.com/user/repos", {
|
|
705
|
+
headers: { Authorization: `Bearer ${githubResource.accessToken}` },
|
|
706
|
+
});
|
|
707
|
+
}
|
|
612
708
|
```
|
|
613
709
|
|
|
614
710
|
---
|
package/dist/dao/types.d.ts
CHANGED
|
@@ -220,6 +220,53 @@ export interface SessionStorage {
|
|
|
220
220
|
session: T;
|
|
221
221
|
} | null>;
|
|
222
222
|
}
|
|
223
|
+
/**
|
|
224
|
+
* Resource storage operations interface.
|
|
225
|
+
*
|
|
226
|
+
* @remarks
|
|
227
|
+
* Manages long-lived third-party resource provider tokens (AuthZ) bound to a user account
|
|
228
|
+
* (User ID or Email), independent of short-lived user sessions.
|
|
229
|
+
*
|
|
230
|
+
* @public
|
|
231
|
+
*/
|
|
232
|
+
export interface ResourceStorage {
|
|
233
|
+
/**
|
|
234
|
+
* Saves a connected resource token for a user.
|
|
235
|
+
*
|
|
236
|
+
* @param userId - Unique user identifier or email
|
|
237
|
+
* @param provider - Resource provider name (e.g. 'github', 'google')
|
|
238
|
+
* @param resource - Connected resource details including access & refresh tokens
|
|
239
|
+
*/
|
|
240
|
+
saveResource(userId: string, provider: string, resource: import("../models/session").ConnectedResource): Promise<void>;
|
|
241
|
+
/**
|
|
242
|
+
* Retrieves a connected resource token for a user.
|
|
243
|
+
*
|
|
244
|
+
* @param userId - Unique user identifier or email
|
|
245
|
+
* @param provider - Resource provider name
|
|
246
|
+
*/
|
|
247
|
+
getResource(userId: string, provider: string): Promise<import("../models/session").ConnectedResource | null>;
|
|
248
|
+
/**
|
|
249
|
+
* Retrieves all connected resources for a user.
|
|
250
|
+
*
|
|
251
|
+
* @param userId - Unique user identifier or email
|
|
252
|
+
*/
|
|
253
|
+
getUserResources(userId: string): Promise<Record<string, import("../models/session").ConnectedResource>>;
|
|
254
|
+
/**
|
|
255
|
+
* Deletes a connected resource token for a user.
|
|
256
|
+
*
|
|
257
|
+
* @param userId - Unique user identifier or email
|
|
258
|
+
* @param provider - Resource provider name
|
|
259
|
+
*/
|
|
260
|
+
deleteResource(userId: string, provider: string): Promise<void>;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Resource handler configuration.
|
|
264
|
+
*
|
|
265
|
+
* @public
|
|
266
|
+
*/
|
|
267
|
+
export interface ResourceHandler {
|
|
268
|
+
resourceStorage?: ResourceStorage;
|
|
269
|
+
}
|
|
223
270
|
/**
|
|
224
271
|
* Session handler for OAuth authentication.
|
|
225
272
|
*
|
package/dist/dao/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/dao/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;;;;;;;;GASG;AACH,MAAM,WAAW,SAAS;IACxB;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;;;OAMG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;OAMG;IACH,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnF;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAEnD;;;;OAIG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACH,aAAa,CAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAE9E;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;;OAMG;IACH,WAAW,CAAC,CAAC,SAAS,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvG;;;;;OAKG;IACH,UAAU,CAAC,CAAC,SAAS,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAEpE;;;;OAIG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhD;;;;OAIG;IACH,iBAAiB,CAAC,CAAC,CAAC,SAAS,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,CAAC,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;CACzG;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsFG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgDG;IACH,eAAe,CAAC,CAAC,CAAC,SAAS,OAAO,EAChC,SAAS,EAAE,OAAO,mBAAmB,EAAE,kBAAkB,EACzD,gBAAgB,EAAE,OAAO,mBAAmB,EAAE,gBAAgB,GAC7D,OAAO,CAAC,CAAC,CAAC,CAAC;IAEd;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAEhC;;;;;OAKG;IACH,eAAe,CAAC,CAAC,CAAC,SAAS,OAAO,EAChC,SAAS,EAAE,OAAO,mBAAmB,EAAE,kBAAkB,EACzD,gBAAgB,EAAE,OAAO,mBAAmB,EAAE,gBAAgB,GAC7D,OAAO,CAAC,CAAC,CAAC,CAAC;CACf"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/dao/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -141,6 +141,8 @@ export declare interface ConnectedResource {
|
|
|
141
141
|
accessToken: string;
|
|
142
142
|
/** Optional refresh token for offline resource access */
|
|
143
143
|
refreshToken?: string | undefined;
|
|
144
|
+
/** Unix timestamp in milliseconds when the resource access token expires */
|
|
145
|
+
expiresAt?: number | undefined;
|
|
144
146
|
/** Resource scopes granted by the user */
|
|
145
147
|
scopes: string[];
|
|
146
148
|
/** Full raw token response from provider */
|
|
@@ -437,6 +439,7 @@ export declare class Lixa<TConfig extends LixaConfig<Record<string, ProviderConf
|
|
|
437
439
|
private config;
|
|
438
440
|
private stateHandler;
|
|
439
441
|
private sessionHandler;
|
|
442
|
+
private resourceHandler;
|
|
440
443
|
private debug;
|
|
441
444
|
/**
|
|
442
445
|
* Creates a new Lixa instance with the provided configuration.
|
|
@@ -749,6 +752,12 @@ export declare class Lixa<TConfig extends LixaConfig<Record<string, ProviderConf
|
|
|
749
752
|
* @param params - Object containing sessionId, provider, code, state, and requested scopes
|
|
750
753
|
* @returns Updated Session containing stored resource tokens under session.resources[provider]
|
|
751
754
|
*/
|
|
755
|
+
private static userResourceStore;
|
|
756
|
+
static LOCAL_RESOURCE_HANDLER: ResourceHandler;
|
|
757
|
+
private getUserKeyFromSession;
|
|
758
|
+
/**
|
|
759
|
+
* Handles the OAuth callback for a connected resource provider and stores resource tokens bound to user account.
|
|
760
|
+
*/
|
|
752
761
|
handleResourceCallback(params: {
|
|
753
762
|
sessionId: string;
|
|
754
763
|
provider: ConfiguredProviderKey<TConfig> | string;
|
|
@@ -757,17 +766,41 @@ export declare class Lixa<TConfig extends LixaConfig<Record<string, ProviderConf
|
|
|
757
766
|
scopes?: string[];
|
|
758
767
|
}): Promise<Session>;
|
|
759
768
|
/**
|
|
760
|
-
* Retrieves a connected resource
|
|
769
|
+
* Retrieves a connected resource for a specific User ID / Email directly (independent of session IDs).
|
|
770
|
+
* Automatically refreshes expired access tokens if a refresh token is present.
|
|
771
|
+
*
|
|
772
|
+
* @param userIdOrEmail - User identifier or email
|
|
773
|
+
* @param provider - Resource provider identifier (e.g. 'github', 'google')
|
|
774
|
+
*/
|
|
775
|
+
getUserResource(userIdOrEmail: string, provider: string): Promise<ConnectedResource | null>;
|
|
776
|
+
/**
|
|
777
|
+
* Retrieves all connected resources for a specific User ID / Email.
|
|
778
|
+
*/
|
|
779
|
+
getUserResources(userIdOrEmail: string): Promise<Record<string, ConnectedResource>>;
|
|
780
|
+
/**
|
|
781
|
+
* Retrieves a connected resource provider token for an active session, auto-refreshing expired tokens if possible.
|
|
761
782
|
*
|
|
762
783
|
* @param sessionId - Active session ID
|
|
763
|
-
* @param provider - Provider identifier (e.g. 'github')
|
|
784
|
+
* @param provider - Provider identifier (e.g. 'github', 'google')
|
|
764
785
|
*/
|
|
765
786
|
getConnectedResource(sessionId: string, provider: string): Promise<ConnectedResource | null>;
|
|
766
787
|
/**
|
|
767
|
-
*
|
|
788
|
+
* Refreshes a user's resource access token using its refresh token.
|
|
768
789
|
*
|
|
769
|
-
* @param
|
|
770
|
-
* @param provider - Provider identifier
|
|
790
|
+
* @param userIdOrEmail - User identifier or email
|
|
791
|
+
* @param provider - Provider identifier (e.g. 'google', 'github')
|
|
792
|
+
*/
|
|
793
|
+
refreshUserResourceToken(userIdOrEmail: string, provider: string, existingResource?: ConnectedResource): Promise<ConnectedResource>;
|
|
794
|
+
/**
|
|
795
|
+
* Refreshes a connected resource access token for an active session.
|
|
796
|
+
*/
|
|
797
|
+
refreshResourceToken(sessionId: string, provider: string): Promise<ConnectedResource>;
|
|
798
|
+
/**
|
|
799
|
+
* Disconnects a resource provider for a specific User ID / Email.
|
|
800
|
+
*/
|
|
801
|
+
disconnectUserResource(userIdOrEmail: string, provider: string): Promise<boolean>;
|
|
802
|
+
/**
|
|
803
|
+
* Disconnects a resource provider from an active session and user account.
|
|
771
804
|
*/
|
|
772
805
|
disconnectResource(sessionId: string, provider: string): Promise<boolean>;
|
|
773
806
|
fetchSessionInfo(sessionId: string): Promise<Session | null>;
|
|
@@ -815,6 +848,14 @@ export declare interface LixaConfig<TProviders extends Record<string, ProviderCo
|
|
|
815
848
|
* @see {@link SessionHandler}
|
|
816
849
|
*/
|
|
817
850
|
sessionHandler?: SessionHandler;
|
|
851
|
+
/**
|
|
852
|
+
* Optional custom resource handler.
|
|
853
|
+
* Handles storage and management of long-lived third-party resource provider tokens (AuthZ)
|
|
854
|
+
* bound directly to user accounts (User ID or Email), independent of transient session IDs.
|
|
855
|
+
*
|
|
856
|
+
* @see {@link ResourceHandler}
|
|
857
|
+
*/
|
|
858
|
+
resourceHandler?: ResourceHandler;
|
|
818
859
|
/**
|
|
819
860
|
* Enable debug logging.
|
|
820
861
|
* When enabled, outputs structured logs for initialization, auth flow, and errors.
|
|
@@ -945,6 +986,55 @@ export declare interface ProviderMetadata {
|
|
|
945
986
|
};
|
|
946
987
|
}
|
|
947
988
|
|
|
989
|
+
/**
|
|
990
|
+
* Resource handler configuration.
|
|
991
|
+
*
|
|
992
|
+
* @public
|
|
993
|
+
*/
|
|
994
|
+
export declare interface ResourceHandler {
|
|
995
|
+
resourceStorage?: ResourceStorage;
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
/**
|
|
999
|
+
* Resource storage operations interface.
|
|
1000
|
+
*
|
|
1001
|
+
* @remarks
|
|
1002
|
+
* Manages long-lived third-party resource provider tokens (AuthZ) bound to a user account
|
|
1003
|
+
* (User ID or Email), independent of short-lived user sessions.
|
|
1004
|
+
*
|
|
1005
|
+
* @public
|
|
1006
|
+
*/
|
|
1007
|
+
export declare interface ResourceStorage {
|
|
1008
|
+
/**
|
|
1009
|
+
* Saves a connected resource token for a user.
|
|
1010
|
+
*
|
|
1011
|
+
* @param userId - Unique user identifier or email
|
|
1012
|
+
* @param provider - Resource provider name (e.g. 'github', 'google')
|
|
1013
|
+
* @param resource - Connected resource details including access & refresh tokens
|
|
1014
|
+
*/
|
|
1015
|
+
saveResource(userId: string, provider: string, resource: ConnectedResource): Promise<void>;
|
|
1016
|
+
/**
|
|
1017
|
+
* Retrieves a connected resource token for a user.
|
|
1018
|
+
*
|
|
1019
|
+
* @param userId - Unique user identifier or email
|
|
1020
|
+
* @param provider - Resource provider name
|
|
1021
|
+
*/
|
|
1022
|
+
getResource(userId: string, provider: string): Promise<ConnectedResource | null>;
|
|
1023
|
+
/**
|
|
1024
|
+
* Retrieves all connected resources for a user.
|
|
1025
|
+
*
|
|
1026
|
+
* @param userId - Unique user identifier or email
|
|
1027
|
+
*/
|
|
1028
|
+
getUserResources(userId: string): Promise<Record<string, ConnectedResource>>;
|
|
1029
|
+
/**
|
|
1030
|
+
* Deletes a connected resource token for a user.
|
|
1031
|
+
*
|
|
1032
|
+
* @param userId - Unique user identifier or email
|
|
1033
|
+
* @param provider - Resource provider name
|
|
1034
|
+
*/
|
|
1035
|
+
deleteResource(userId: string, provider: string): Promise<void>;
|
|
1036
|
+
}
|
|
1037
|
+
|
|
948
1038
|
/**
|
|
949
1039
|
* Helper type to create a configuration with only registered providers.
|
|
950
1040
|
* Use this with Lixa.createConfig() for type safety.
|