11import { z } from '@hono/zod-openapi' ;
2+ import { type AllAuthCredentials , type AuthModeType , Nango } from '@nangohq/node' ;
3+ import type { ApiKeyCredentials , ApiPublicIntegration } from '@nangohq/types' ;
24import { CredentialStoreType } from '../types' ;
35import type { CredentialStore } from '../types/server' ;
46import { getLogger } from '../utils/logger' ;
57
68const logger = getLogger ( 'nango-credential-store' ) ;
79
8- // Dynamic import types - these are loaded at runtime if Nango is installed
9- type NangoType = import ( '@nangohq/node' ) . Nango ;
10- type AllAuthCredentials = import ( '@nangohq/node' ) . AllAuthCredentials ;
11- type AuthModeType = import ( '@nangohq/node' ) . AuthModeType ;
12- type ApiKeyCredentials = import ( '@nangohq/types' ) . ApiKeyCredentials ;
13- type ApiPublicIntegration = import ( '@nangohq/types' ) . ApiPublicIntegration ;
14-
15- // Lazy-loaded Nango module
16- let nangoModule : typeof import ( '@nangohq/node' ) | null = null ;
17-
18- /**
19- * Check if Nango is available
20- */
21- export function isNangoAvailable ( ) : boolean {
22- try {
23- require . resolve ( '@nangohq/node' ) ;
24- return true ;
25- } catch {
26- return false ;
27- }
28- }
29-
30- /**
31- * Dynamically load Nango module
32- */
33- async function loadNangoModule ( ) : Promise < typeof import ( '@nangohq/node' ) > {
34- if ( nangoModule ) {
35- return nangoModule ;
36- }
37-
38- try {
39- nangoModule = await import ( '@nangohq/node' ) ;
40- return nangoModule ;
41- } catch {
42- throw new Error (
43- 'Nango is not installed. To use Nango credential store, install it with: npm install @nangohq/node @nangohq/types'
44- ) ;
45- }
46- }
47-
4810const CredentialKeySchema = z . object ( {
4911 connectionId : z . string ( ) . min ( 1 , 'connectionId must be a non-empty string' ) ,
5012 providerConfigKey : z . string ( ) . min ( 1 , 'providerConfigKey must be a non-empty string' ) ,
@@ -114,35 +76,20 @@ function isSupportedAuthMode(mode: unknown): mode is SupportedAuthMode {
11476/**
11577 * Nango-based CredentialStore that fetches OAuth credentials from Nango API
11678 * Uses connectionId and providerConfigKey from metadata to fetch live credentials
117- *
118- * Note: This store requires the @nangohq/node and @nangohq/types packages to be installed.
119- * If Nango is not installed, the store will throw helpful error messages.
12079 */
12180export class NangoCredentialStore implements CredentialStore {
12281 public readonly id : string ;
12382 public readonly type = CredentialStoreType . nango ;
12483 private nangoConfig : NangoConfig ;
125- private nangoClient : NangoType | null = null ;
84+ private nangoClient : Nango ;
12685
12786 constructor ( id : string , config : NangoConfig ) {
12887 this . id = id ;
12988 this . nangoConfig = config ;
130- }
131-
132- /**
133- * Initialize Nango client lazily
134- */
135- private async getNangoClient ( ) : Promise < NangoType > {
136- if ( this . nangoClient ) {
137- return this . nangoClient ;
138- }
139-
140- const { Nango } = await loadNangoModule ( ) ;
14189 this . nangoClient = new Nango ( {
14290 secretKey : this . nangoConfig . secretKey ,
14391 host : this . nangoConfig . apiUrl ,
14492 } ) ;
145- return this . nangoClient ;
14693 }
14794
14895 private getAccessToken ( credentials : AllAuthCredentials ) : Record < string , any > | null {
@@ -239,8 +186,7 @@ export class NangoCredentialStore implements CredentialStore {
239186 uniqueKey : string
240187 ) : Promise < ( ApiPublicIntegration & { areCredentialsSet : boolean } ) | null > {
241188 try {
242- const nangoClient = await this . getNangoClient ( ) ;
243- const response = await nangoClient . getIntegration (
189+ const response = await this . nangoClient . getIntegration (
244190 { uniqueKey } ,
245191 { include : [ 'credentials' ] }
246192 ) ;
@@ -316,8 +262,7 @@ export class NangoCredentialStore implements CredentialStore {
316262 * where true race conditions could occur.
317263 */
318264 try {
319- const nangoClient = await this . getNangoClient ( ) ;
320- const response = await nangoClient . createIntegration ( {
265+ const response = await this . nangoClient . createIntegration ( {
321266 provider,
322267 unique_key : uniqueKey ,
323268 display_name : displayName ,
@@ -394,8 +339,7 @@ export class NangoCredentialStore implements CredentialStore {
394339 providerConfigKey : string ;
395340 } ) : Promise < NangoCredentialData | null > {
396341 try {
397- const nangoClient = await this . getNangoClient ( ) ;
398- const nangoConnection = await nangoClient . getConnection ( providerConfigKey , connectionId ) ;
342+ const nangoConnection = await this . nangoClient . getConnection ( providerConfigKey , connectionId ) ;
399343
400344 const tokenAndCredentials = this . getAccessToken ( nangoConnection . credentials ) ?? { } ;
401345
@@ -507,8 +451,7 @@ export class NangoCredentialStore implements CredentialStore {
507451
508452 const { connectionId, providerConfigKey } = parsedKey ;
509453
510- const nangoClient = await this . getNangoClient ( ) ;
511- await nangoClient . deleteConnection ( providerConfigKey , connectionId ) ;
454+ await this . nangoClient . deleteConnection ( providerConfigKey , connectionId ) ;
512455 return true ;
513456 } catch ( error ) {
514457 logger . error (
@@ -527,14 +470,6 @@ export class NangoCredentialStore implements CredentialStore {
527470 * Check if the credential store is available and functional
528471 */
529472 async checkAvailability ( ) : Promise < { available : boolean ; reason ?: string } > {
530- // First check if Nango is installed
531- if ( ! isNangoAvailable ( ) ) {
532- return {
533- available : false ,
534- reason : 'Nango is not installed. Install with: npm install @nangohq/node @nangohq/types' ,
535- } ;
536- }
537-
538473 if ( ! this . nangoConfig . secretKey ) {
539474 return {
540475 available : false ,
@@ -561,21 +496,11 @@ export class NangoCredentialStore implements CredentialStore {
561496/**
562497 * Factory function to create NangoCredentialStore
563498 * Automatically reads NANGO_SECRET_KEY from environment and validates it
564- *
565- * Note: This function requires the @nangohq/node and @nangohq/types packages to be installed.
566- * If Nango is not installed, this will throw a helpful error message.
567499 */
568500export function createNangoCredentialStore (
569501 id : string ,
570502 config ?: Partial < NangoConfig >
571503) : NangoCredentialStore {
572- // Check if Nango is available
573- if ( ! isNangoAvailable ( ) ) {
574- throw new Error (
575- 'Nango is not installed. To use Nango credential store, install it with: npm install @nangohq/node @nangohq/types'
576- ) ;
577- }
578-
579504 const nangoSecretKey = config ?. secretKey || process . env . NANGO_SECRET_KEY ;
580505
581506 if (
0 commit comments