@vunexa/lixa 0.1.6-alpha.4 → 0.1.6-alpha.7
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 +167 -18
- package/README.template.md +167 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -363,14 +363,6 @@ export const lixa = new Lixa({
|
|
|
363
363
|
"accessToken": "gho_8f7b2a9e1c3...",
|
|
364
364
|
"linkedAt": 1771657250000
|
|
365
365
|
}
|
|
366
|
-
},
|
|
367
|
-
"resources": {
|
|
368
|
-
"github": {
|
|
369
|
-
"provider": "github",
|
|
370
|
-
"accessToken": "gho_resource_repo_9a8b7c...",
|
|
371
|
-
"scopes": ["repo", "read:org"],
|
|
372
|
-
"connectedAt": 1771657300000
|
|
373
|
-
}
|
|
374
366
|
}
|
|
375
367
|
}
|
|
376
368
|
```
|
|
@@ -498,16 +490,12 @@ export const lixa = new Lixa({
|
|
|
498
490
|
"accessToken": "gho_8f7b2a9e1c3...",
|
|
499
491
|
"linkedAt": 1771657250000
|
|
500
492
|
}
|
|
501
|
-
},
|
|
502
|
-
"resources": {
|
|
503
|
-
"github": {
|
|
504
|
-
"provider": "github",
|
|
505
|
-
"accessToken": "gho_resource_repo_9a8b7c...",
|
|
506
|
-
"scopes": ["repo", "read:org"],
|
|
507
|
-
"connectedAt": 1771657300000
|
|
508
|
-
}
|
|
509
493
|
}
|
|
510
|
-
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
---
|
|
511
499
|
|
|
512
500
|
## Custom Resource Storage Implementation (`ResourceStorage`)
|
|
513
501
|
|
|
@@ -601,7 +589,168 @@ export const lixa = new Lixa({
|
|
|
601
589
|
});
|
|
602
590
|
```
|
|
603
591
|
|
|
604
|
-
|
|
592
|
+
#### Saved JSON Records Example in SQLite (`user_resources` Table)
|
|
593
|
+
|
|
594
|
+
**Row 1 (GitHub Repositories)**:
|
|
595
|
+
```json
|
|
596
|
+
{
|
|
597
|
+
"user_id": "1049281048",
|
|
598
|
+
"provider": "github",
|
|
599
|
+
"data": {
|
|
600
|
+
"accessToken": "gho_resource_repo_9a8b7c...",
|
|
601
|
+
"refreshToken": "ghr_refresh_token_123...",
|
|
602
|
+
"scopes": ["repo", "read:org"],
|
|
603
|
+
"expiresAt": 1771743600000,
|
|
604
|
+
"connectedAt": 1771657300000
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
**Row 2 (Google Drive)**:
|
|
610
|
+
```json
|
|
611
|
+
{
|
|
612
|
+
"user_id": "1049281048",
|
|
613
|
+
"provider": "google",
|
|
614
|
+
"data": {
|
|
615
|
+
"accessToken": "ya29.drive_resource_token_456...",
|
|
616
|
+
"refreshToken": "1//09abc_google_refresh_token...",
|
|
617
|
+
"scopes": ["https://www.googleapis.com/auth/drive.readonly"],
|
|
618
|
+
"expiresAt": 1771660800000,
|
|
619
|
+
"connectedAt": 1771657400000
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
---
|
|
625
|
+
|
|
626
|
+
### 2. AWS DynamoDB Resource Storage (`@aws-sdk/lib-dynamodb`)
|
|
627
|
+
|
|
628
|
+
For serverless AWS deployments storing user API credentials in DynamoDB:
|
|
629
|
+
|
|
630
|
+
#### Table Configuration
|
|
631
|
+
|
|
632
|
+
- **Table Name**: `LixaUserResources`
|
|
633
|
+
- **Partition Key (PK)**: `userId` (String)
|
|
634
|
+
- **Sort Key (SK)**: `provider` (String)
|
|
635
|
+
|
|
636
|
+
#### TypeScript Implementation
|
|
637
|
+
|
|
638
|
+
```typescript
|
|
639
|
+
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
|
|
640
|
+
import { DynamoDBDocumentClient, PutCommand, GetCommand, DeleteCommand, QueryCommand } from "@aws-sdk/lib-dynamodb";
|
|
641
|
+
import { Lixa, type ResourceStorage, type ConnectedResource } from "@vunexa/lixa";
|
|
642
|
+
|
|
643
|
+
export class DynamoDbResourceStorage implements ResourceStorage {
|
|
644
|
+
private docClient: DynamoDBDocumentClient;
|
|
645
|
+
private tableName = "LixaUserResources";
|
|
646
|
+
|
|
647
|
+
constructor() {
|
|
648
|
+
const client = new DynamoDBClient({ region: process.env.AWS_REGION || "us-east-1" });
|
|
649
|
+
this.docClient = DynamoDBDocumentClient.from(client);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
async saveResource(userId: string, provider: string, resource: ConnectedResource): Promise<void> {
|
|
653
|
+
await this.docClient.send(
|
|
654
|
+
new PutCommand({
|
|
655
|
+
TableName: this.tableName,
|
|
656
|
+
Item: {
|
|
657
|
+
userId,
|
|
658
|
+
provider: provider.toLowerCase(),
|
|
659
|
+
resourceData: resource,
|
|
660
|
+
updatedAt: Date.now(),
|
|
661
|
+
},
|
|
662
|
+
})
|
|
663
|
+
);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
async getResource(userId: string, provider: string): Promise<ConnectedResource | null> {
|
|
667
|
+
const res = await this.docClient.send(
|
|
668
|
+
new GetCommand({
|
|
669
|
+
TableName: this.tableName,
|
|
670
|
+
Key: {
|
|
671
|
+
userId,
|
|
672
|
+
provider: provider.toLowerCase(),
|
|
673
|
+
},
|
|
674
|
+
})
|
|
675
|
+
);
|
|
676
|
+
|
|
677
|
+
return res.Item ? (res.Item.resourceData as ConnectedResource) : null;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
async getUserResources(userId: string): Promise<Record<string, ConnectedResource>> {
|
|
681
|
+
const res = await this.docClient.send(
|
|
682
|
+
new QueryCommand({
|
|
683
|
+
TableName: this.tableName,
|
|
684
|
+
KeyConditionExpression: "userId = :userId",
|
|
685
|
+
ExpressionAttributeValues: { ":userId": userId },
|
|
686
|
+
})
|
|
687
|
+
);
|
|
688
|
+
|
|
689
|
+
const result: Record<string, ConnectedResource> = {};
|
|
690
|
+
if (res.Items) {
|
|
691
|
+
for (const item of res.Items) {
|
|
692
|
+
result[item.provider] = item.resourceData as ConnectedResource;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
return result;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
async deleteResource(userId: string, provider: string): Promise<void> {
|
|
699
|
+
await this.docClient.send(
|
|
700
|
+
new DeleteCommand({
|
|
701
|
+
TableName: this.tableName,
|
|
702
|
+
Key: {
|
|
703
|
+
userId,
|
|
704
|
+
provider: provider.toLowerCase(),
|
|
705
|
+
},
|
|
706
|
+
})
|
|
707
|
+
);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// Pass to Lixa instance via resourceHandler
|
|
712
|
+
export const lixa = new Lixa({
|
|
713
|
+
resourceHandler: {
|
|
714
|
+
resourceStorage: new DynamoDbResourceStorage(),
|
|
715
|
+
},
|
|
716
|
+
providers: { /* ... */ },
|
|
717
|
+
});
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
#### Saved DynamoDB Resource Items Example (`LixaUserResources` Table)
|
|
721
|
+
|
|
722
|
+
```json
|
|
723
|
+
[
|
|
724
|
+
{
|
|
725
|
+
"userId": "1049281048",
|
|
726
|
+
"provider": "github",
|
|
727
|
+
"updatedAt": 1771657300000,
|
|
728
|
+
"resourceData": {
|
|
729
|
+
"accessToken": "gho_resource_repo_9a8b7c...",
|
|
730
|
+
"refreshToken": "ghr_refresh_token_123...",
|
|
731
|
+
"scopes": ["repo", "read:org"],
|
|
732
|
+
"expiresAt": 1771743600000,
|
|
733
|
+
"connectedAt": 1771657300000
|
|
734
|
+
}
|
|
735
|
+
},
|
|
736
|
+
{
|
|
737
|
+
"userId": "1049281048",
|
|
738
|
+
"provider": "google",
|
|
739
|
+
"updatedAt": 1771657400000,
|
|
740
|
+
"resourceData": {
|
|
741
|
+
"accessToken": "ya29.drive_resource_token_456...",
|
|
742
|
+
"refreshToken": "1//09abc_google_refresh_token...",
|
|
743
|
+
"scopes": ["https://www.googleapis.com/auth/drive.readonly"],
|
|
744
|
+
"expiresAt": 1771660800000,
|
|
745
|
+
"connectedAt": 1771657400000
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
]
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
---
|
|
752
|
+
|
|
753
|
+
### 3. Querying Connected Resources Directly by User ID
|
|
605
754
|
|
|
606
755
|
`ResourceStorage` enables background workers, cron jobs, and webhooks to access third-party API credentials by `userId` without an active HTTP session:
|
|
607
756
|
|
package/README.template.md
CHANGED
|
@@ -453,14 +453,6 @@ export const lixa = new Lixa({
|
|
|
453
453
|
"accessToken": "gho_8f7b2a9e1c3...",
|
|
454
454
|
"linkedAt": 1771657250000
|
|
455
455
|
}
|
|
456
|
-
},
|
|
457
|
-
"resources": {
|
|
458
|
-
"github": {
|
|
459
|
-
"provider": "github",
|
|
460
|
-
"accessToken": "gho_resource_repo_9a8b7c...",
|
|
461
|
-
"scopes": ["repo", "read:org"],
|
|
462
|
-
"connectedAt": 1771657300000
|
|
463
|
-
}
|
|
464
456
|
}
|
|
465
457
|
}
|
|
466
458
|
```
|
|
@@ -588,16 +580,12 @@ export const lixa = new Lixa({
|
|
|
588
580
|
"accessToken": "gho_8f7b2a9e1c3...",
|
|
589
581
|
"linkedAt": 1771657250000
|
|
590
582
|
}
|
|
591
|
-
},
|
|
592
|
-
"resources": {
|
|
593
|
-
"github": {
|
|
594
|
-
"provider": "github",
|
|
595
|
-
"accessToken": "gho_resource_repo_9a8b7c...",
|
|
596
|
-
"scopes": ["repo", "read:org"],
|
|
597
|
-
"connectedAt": 1771657300000
|
|
598
|
-
}
|
|
599
583
|
}
|
|
600
|
-
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
---
|
|
601
589
|
|
|
602
590
|
## Custom Resource Storage Implementation (`ResourceStorage`)
|
|
603
591
|
|
|
@@ -691,7 +679,168 @@ export const lixa = new Lixa({
|
|
|
691
679
|
});
|
|
692
680
|
```
|
|
693
681
|
|
|
694
|
-
|
|
682
|
+
#### Saved JSON Records Example in SQLite (`user_resources` Table)
|
|
683
|
+
|
|
684
|
+
**Row 1 (GitHub Repositories)**:
|
|
685
|
+
```json
|
|
686
|
+
{
|
|
687
|
+
"user_id": "1049281048",
|
|
688
|
+
"provider": "github",
|
|
689
|
+
"data": {
|
|
690
|
+
"accessToken": "gho_resource_repo_9a8b7c...",
|
|
691
|
+
"refreshToken": "ghr_refresh_token_123...",
|
|
692
|
+
"scopes": ["repo", "read:org"],
|
|
693
|
+
"expiresAt": 1771743600000,
|
|
694
|
+
"connectedAt": 1771657300000
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
**Row 2 (Google Drive)**:
|
|
700
|
+
```json
|
|
701
|
+
{
|
|
702
|
+
"user_id": "1049281048",
|
|
703
|
+
"provider": "google",
|
|
704
|
+
"data": {
|
|
705
|
+
"accessToken": "ya29.drive_resource_token_456...",
|
|
706
|
+
"refreshToken": "1//09abc_google_refresh_token...",
|
|
707
|
+
"scopes": ["https://www.googleapis.com/auth/drive.readonly"],
|
|
708
|
+
"expiresAt": 1771660800000,
|
|
709
|
+
"connectedAt": 1771657400000
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
---
|
|
715
|
+
|
|
716
|
+
### 2. AWS DynamoDB Resource Storage (`@aws-sdk/lib-dynamodb`)
|
|
717
|
+
|
|
718
|
+
For serverless AWS deployments storing user API credentials in DynamoDB:
|
|
719
|
+
|
|
720
|
+
#### Table Configuration
|
|
721
|
+
|
|
722
|
+
- **Table Name**: `LixaUserResources`
|
|
723
|
+
- **Partition Key (PK)**: `userId` (String)
|
|
724
|
+
- **Sort Key (SK)**: `provider` (String)
|
|
725
|
+
|
|
726
|
+
#### TypeScript Implementation
|
|
727
|
+
|
|
728
|
+
```typescript
|
|
729
|
+
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
|
|
730
|
+
import { DynamoDBDocumentClient, PutCommand, GetCommand, DeleteCommand, QueryCommand } from "@aws-sdk/lib-dynamodb";
|
|
731
|
+
import { Lixa, type ResourceStorage, type ConnectedResource } from "@vunexa/lixa";
|
|
732
|
+
|
|
733
|
+
export class DynamoDbResourceStorage implements ResourceStorage {
|
|
734
|
+
private docClient: DynamoDBDocumentClient;
|
|
735
|
+
private tableName = "LixaUserResources";
|
|
736
|
+
|
|
737
|
+
constructor() {
|
|
738
|
+
const client = new DynamoDBClient({ region: process.env.AWS_REGION || "us-east-1" });
|
|
739
|
+
this.docClient = DynamoDBDocumentClient.from(client);
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
async saveResource(userId: string, provider: string, resource: ConnectedResource): Promise<void> {
|
|
743
|
+
await this.docClient.send(
|
|
744
|
+
new PutCommand({
|
|
745
|
+
TableName: this.tableName,
|
|
746
|
+
Item: {
|
|
747
|
+
userId,
|
|
748
|
+
provider: provider.toLowerCase(),
|
|
749
|
+
resourceData: resource,
|
|
750
|
+
updatedAt: Date.now(),
|
|
751
|
+
},
|
|
752
|
+
})
|
|
753
|
+
);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
async getResource(userId: string, provider: string): Promise<ConnectedResource | null> {
|
|
757
|
+
const res = await this.docClient.send(
|
|
758
|
+
new GetCommand({
|
|
759
|
+
TableName: this.tableName,
|
|
760
|
+
Key: {
|
|
761
|
+
userId,
|
|
762
|
+
provider: provider.toLowerCase(),
|
|
763
|
+
},
|
|
764
|
+
})
|
|
765
|
+
);
|
|
766
|
+
|
|
767
|
+
return res.Item ? (res.Item.resourceData as ConnectedResource) : null;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
async getUserResources(userId: string): Promise<Record<string, ConnectedResource>> {
|
|
771
|
+
const res = await this.docClient.send(
|
|
772
|
+
new QueryCommand({
|
|
773
|
+
TableName: this.tableName,
|
|
774
|
+
KeyConditionExpression: "userId = :userId",
|
|
775
|
+
ExpressionAttributeValues: { ":userId": userId },
|
|
776
|
+
})
|
|
777
|
+
);
|
|
778
|
+
|
|
779
|
+
const result: Record<string, ConnectedResource> = {};
|
|
780
|
+
if (res.Items) {
|
|
781
|
+
for (const item of res.Items) {
|
|
782
|
+
result[item.provider] = item.resourceData as ConnectedResource;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
return result;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
async deleteResource(userId: string, provider: string): Promise<void> {
|
|
789
|
+
await this.docClient.send(
|
|
790
|
+
new DeleteCommand({
|
|
791
|
+
TableName: this.tableName,
|
|
792
|
+
Key: {
|
|
793
|
+
userId,
|
|
794
|
+
provider: provider.toLowerCase(),
|
|
795
|
+
},
|
|
796
|
+
})
|
|
797
|
+
);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
// Pass to Lixa instance via resourceHandler
|
|
802
|
+
export const lixa = new Lixa({
|
|
803
|
+
resourceHandler: {
|
|
804
|
+
resourceStorage: new DynamoDbResourceStorage(),
|
|
805
|
+
},
|
|
806
|
+
providers: { /* ... */ },
|
|
807
|
+
});
|
|
808
|
+
```
|
|
809
|
+
|
|
810
|
+
#### Saved DynamoDB Resource Items Example (`LixaUserResources` Table)
|
|
811
|
+
|
|
812
|
+
```json
|
|
813
|
+
[
|
|
814
|
+
{
|
|
815
|
+
"userId": "1049281048",
|
|
816
|
+
"provider": "github",
|
|
817
|
+
"updatedAt": 1771657300000,
|
|
818
|
+
"resourceData": {
|
|
819
|
+
"accessToken": "gho_resource_repo_9a8b7c...",
|
|
820
|
+
"refreshToken": "ghr_refresh_token_123...",
|
|
821
|
+
"scopes": ["repo", "read:org"],
|
|
822
|
+
"expiresAt": 1771743600000,
|
|
823
|
+
"connectedAt": 1771657300000
|
|
824
|
+
}
|
|
825
|
+
},
|
|
826
|
+
{
|
|
827
|
+
"userId": "1049281048",
|
|
828
|
+
"provider": "google",
|
|
829
|
+
"updatedAt": 1771657400000,
|
|
830
|
+
"resourceData": {
|
|
831
|
+
"accessToken": "ya29.drive_resource_token_456...",
|
|
832
|
+
"refreshToken": "1//09abc_google_refresh_token...",
|
|
833
|
+
"scopes": ["https://www.googleapis.com/auth/drive.readonly"],
|
|
834
|
+
"expiresAt": 1771660800000,
|
|
835
|
+
"connectedAt": 1771657400000
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
]
|
|
839
|
+
```
|
|
840
|
+
|
|
841
|
+
---
|
|
842
|
+
|
|
843
|
+
### 3. Querying Connected Resources Directly by User ID
|
|
695
844
|
|
|
696
845
|
`ResourceStorage` enables background workers, cron jobs, and webhooks to access third-party API credentials by `userId` without an active HTTP session:
|
|
697
846
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vunexa/lixa",
|
|
3
|
-
"version": "0.1.6-alpha.
|
|
3
|
+
"version": "0.1.6-alpha.7",
|
|
4
4
|
"description": "Lixa is a flexible, provider-agnostic OAuth and OpenID Connect (OIDC) client library that simplifies multi-provider authentication flows. It supports seamless integration with providers like Google and GitHub, offers extensible session management, and enables dynamic provider resolution based on callback URLs.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"oauth",
|