@inkeep/agents-core 0.35.2 → 0.35.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.
@@ -0,0 +1,763 @@
1
+ import { getLogger } from './chunk-DN4B564Y.js';
2
+ import { CredentialStoreType } from './chunk-YFHT5M2R.js';
3
+ import { Nango } from '@nangohq/node';
4
+ import { z } from 'zod';
5
+
6
+ // src/credential-stores/CredentialStoreRegistry.ts
7
+ var CredentialStoreRegistry = class {
8
+ stores = /* @__PURE__ */ new Map();
9
+ logger = getLogger("credential-store-registry");
10
+ constructor(initialStores = []) {
11
+ for (const store of initialStores) {
12
+ this.add(store);
13
+ }
14
+ }
15
+ /**
16
+ * Add a credential store to the registry
17
+ */
18
+ add(store) {
19
+ if (this.stores.has(store.id)) {
20
+ this.logger.warn(
21
+ { storeId: store.id },
22
+ `Credential store ${store.id} already registered, replacing`
23
+ );
24
+ }
25
+ this.stores.set(store.id, store);
26
+ this.logger.info(
27
+ { storeId: store.id, storeType: store.type },
28
+ `Registered credential store: ${store.id} (type: ${store.type})`
29
+ );
30
+ }
31
+ /**
32
+ * Get a credential store by ID
33
+ */
34
+ get(id) {
35
+ return this.stores.get(id);
36
+ }
37
+ /**
38
+ * Get all registered credential stores
39
+ */
40
+ getAll() {
41
+ return Array.from(this.stores.values());
42
+ }
43
+ /**
44
+ * Get all credential store IDs
45
+ */
46
+ getIds() {
47
+ return Array.from(this.stores.keys());
48
+ }
49
+ /**
50
+ * Check if a credential store is registered
51
+ */
52
+ has(id) {
53
+ return this.stores.has(id);
54
+ }
55
+ /**
56
+ * Remove a credential store
57
+ */
58
+ remove(id) {
59
+ const removed = this.stores.delete(id);
60
+ if (removed) {
61
+ this.logger.info({ id }, `Removed credential store: ${id}`);
62
+ }
63
+ return removed;
64
+ }
65
+ /**
66
+ * Get the number of registered stores
67
+ */
68
+ size() {
69
+ return this.stores.size;
70
+ }
71
+ };
72
+
73
+ // src/credential-stores/keychain-store.ts
74
+ var KeyChainStore = class {
75
+ id;
76
+ type = CredentialStoreType.keychain;
77
+ service;
78
+ logger = getLogger("KeyChainStore");
79
+ keytarAvailable = false;
80
+ keytar = null;
81
+ initializationPromise;
82
+ constructor(id, servicePrefix = "inkeep-agent-framework") {
83
+ this.id = id;
84
+ this.service = `${servicePrefix}-${id}`;
85
+ this.initializationPromise = this.initializeKeytar();
86
+ }
87
+ /**
88
+ * Initialize keytar dynamically to handle optional availability
89
+ */
90
+ async initializeKeytar() {
91
+ if (this.keytar) {
92
+ this.keytarAvailable = true;
93
+ return;
94
+ }
95
+ try {
96
+ this.keytar = (await import('keytar')).default;
97
+ this.keytarAvailable = true;
98
+ this.logger.info(
99
+ {
100
+ storeId: this.id,
101
+ service: this.service
102
+ },
103
+ "Keytar initialized successfully"
104
+ );
105
+ } catch (error) {
106
+ this.logger.warn(
107
+ {
108
+ storeId: this.id,
109
+ error: error instanceof Error ? error.message : "Unknown error"
110
+ },
111
+ "Keytar not available - KeyChainStore will return null for all operations"
112
+ );
113
+ this.keytarAvailable = false;
114
+ }
115
+ }
116
+ /**
117
+ * Get a credential from the keychain
118
+ */
119
+ async get(key) {
120
+ await this.initializationPromise;
121
+ if (!this.keytarAvailable || !this.keytar) {
122
+ this.logger.debug({ storeId: this.id, key }, "Keytar not available, returning null");
123
+ return null;
124
+ }
125
+ try {
126
+ const password = await this.keytar.getPassword(this.service, key);
127
+ if (password === null) {
128
+ this.logger.debug(
129
+ { storeId: this.id, service: this.service, account: key },
130
+ "No credential found in keychain"
131
+ );
132
+ }
133
+ return password;
134
+ } catch (error) {
135
+ this.logger.error(
136
+ {
137
+ storeId: this.id,
138
+ service: this.service,
139
+ account: key,
140
+ error: error instanceof Error ? error.message : "Unknown error"
141
+ },
142
+ "Error getting credential from keychain"
143
+ );
144
+ return null;
145
+ }
146
+ }
147
+ /**
148
+ * Set a credential in the keychain
149
+ * @param metadata - Optional metadata (ignored by keychain store)
150
+ */
151
+ async set(key, value, _metadata) {
152
+ await this.initializationPromise;
153
+ if (!this.keytarAvailable || !this.keytar) {
154
+ this.logger.warn({ storeId: this.id, key }, "Keytar not available, cannot set credential");
155
+ throw new Error("Keytar not available - cannot store credentials in system keychain");
156
+ }
157
+ try {
158
+ await this.keytar.setPassword(this.service, key, value);
159
+ this.logger.debug(
160
+ { storeId: this.id, service: this.service, account: key },
161
+ "Credential stored in keychain"
162
+ );
163
+ } catch (error) {
164
+ this.logger.error(
165
+ {
166
+ storeId: this.id,
167
+ service: this.service,
168
+ account: key,
169
+ error: error instanceof Error ? error.message : "Unknown error"
170
+ },
171
+ "Error setting credential in keychain"
172
+ );
173
+ throw new Error(
174
+ `Failed to store credential in keychain: ${error instanceof Error ? error.message : "Unknown error"}`
175
+ );
176
+ }
177
+ }
178
+ /**
179
+ * Check if a credential exists in the keychain
180
+ */
181
+ async has(key) {
182
+ const credential = await this.get(key);
183
+ return credential !== null;
184
+ }
185
+ /**
186
+ * Check if the credential store is available and functional
187
+ */
188
+ async checkAvailability() {
189
+ await this.initializationPromise;
190
+ if (!this.keytarAvailable || !this.keytar) {
191
+ return {
192
+ available: false,
193
+ reason: "Keytar not available - cannot store credentials in system keychain"
194
+ };
195
+ }
196
+ return {
197
+ available: true
198
+ };
199
+ }
200
+ /**
201
+ * Delete a credential from the keychain
202
+ */
203
+ async delete(key) {
204
+ await this.initializationPromise;
205
+ if (!this.keytarAvailable || !this.keytar) {
206
+ this.logger.warn({ storeId: this.id, key }, "Keytar not available, cannot delete credential");
207
+ return false;
208
+ }
209
+ try {
210
+ const result = await this.keytar.deletePassword(this.service, key);
211
+ if (result) {
212
+ this.logger.debug(
213
+ { storeId: this.id, service: this.service, account: key },
214
+ "Credential deleted from keychain"
215
+ );
216
+ } else {
217
+ this.logger.debug(
218
+ { storeId: this.id, service: this.service, account: key },
219
+ "Credential not found in keychain for deletion"
220
+ );
221
+ }
222
+ return result;
223
+ } catch (error) {
224
+ this.logger.error(
225
+ {
226
+ storeId: this.id,
227
+ service: this.service,
228
+ account: key,
229
+ error: error instanceof Error ? error.message : "Unknown error"
230
+ },
231
+ "Error deleting credential from keychain"
232
+ );
233
+ return false;
234
+ }
235
+ }
236
+ /**
237
+ * Find all credentials for this service
238
+ * Useful for debugging and listing stored credentials
239
+ */
240
+ async findAllCredentials() {
241
+ await this.initializationPromise;
242
+ if (!this.keytarAvailable || !this.keytar) {
243
+ return [];
244
+ }
245
+ try {
246
+ const credentials = await this.keytar.findCredentials(this.service);
247
+ return credentials || [];
248
+ } catch (error) {
249
+ this.logger.error(
250
+ {
251
+ storeId: this.id,
252
+ service: this.service,
253
+ error: error instanceof Error ? error.message : "Unknown error"
254
+ },
255
+ "Error finding credentials in keychain"
256
+ );
257
+ return [];
258
+ }
259
+ }
260
+ /**
261
+ * Clear all credentials for this service
262
+ * WARNING: This will delete all credentials stored under this service
263
+ */
264
+ async clearAll() {
265
+ const credentials = await this.findAllCredentials();
266
+ let deletedCount = 0;
267
+ for (const cred of credentials) {
268
+ const deleted = await this.delete(cred.account);
269
+ if (deleted) {
270
+ deletedCount++;
271
+ }
272
+ }
273
+ if (deletedCount > 0) {
274
+ this.logger.info(
275
+ {
276
+ storeId: this.id,
277
+ service: this.service,
278
+ deletedCount
279
+ },
280
+ "Cleared all credentials from keychain"
281
+ );
282
+ }
283
+ return deletedCount;
284
+ }
285
+ };
286
+ function createKeyChainStore(id, options) {
287
+ return new KeyChainStore(id, options?.servicePrefix);
288
+ }
289
+
290
+ // src/credential-stores/memory-store.ts
291
+ var InMemoryCredentialStore = class {
292
+ id;
293
+ type = CredentialStoreType.memory;
294
+ credentials = /* @__PURE__ */ new Map();
295
+ constructor(id = "memory-default") {
296
+ this.id = id;
297
+ }
298
+ /**
299
+ * Get a credential from the in memory store.
300
+ * If the key is not found in the in memory store then it is loaded from environment variables.
301
+ * If the key is not found in the environment variables or in the in memory store then returns null.
302
+ * @param key - The key of the credential to get
303
+ * @returns The credential value or null if not found
304
+ */
305
+ async get(key) {
306
+ const credential = this.credentials.get(key);
307
+ if (!credential) {
308
+ const envValue = process.env[key];
309
+ if (envValue) {
310
+ this.credentials.set(key, envValue);
311
+ return envValue;
312
+ }
313
+ return null;
314
+ }
315
+ return credential;
316
+ }
317
+ /**
318
+ * Set a credential in the in memory store.
319
+ * @param key - The key of the credential to set
320
+ * @param value - The value of the credential to set
321
+ * @param metadata - Optional metadata (ignored by memory store)
322
+ */
323
+ async set(key, value, _metadata) {
324
+ this.credentials.set(key, value);
325
+ }
326
+ /**
327
+ * Check if a credential exists in the in memory store.
328
+ * @param key - The key of the credential to check
329
+ * @returns True if the credential exists, false otherwise
330
+ */
331
+ async has(key) {
332
+ return this.credentials.has(key);
333
+ }
334
+ /**
335
+ * Delete a credential from the in memory store.
336
+ * @param key - The key of the credential to delete
337
+ * @returns True if the credential was deleted, false otherwise
338
+ */
339
+ async delete(key) {
340
+ return this.credentials.delete(key);
341
+ }
342
+ /**
343
+ * Check if the credential store is available and functional
344
+ */
345
+ async checkAvailability() {
346
+ return {
347
+ available: true
348
+ };
349
+ }
350
+ };
351
+ var logger = getLogger("nango-credential-store");
352
+ var CredentialKeySchema = z.object({
353
+ connectionId: z.string().min(1, "connectionId must be a non-empty string"),
354
+ providerConfigKey: z.string().min(1, "providerConfigKey must be a non-empty string"),
355
+ integrationDisplayName: z.string().nullish()
356
+ });
357
+ function parseCredentialKey(key) {
358
+ try {
359
+ const parsed = JSON.parse(key);
360
+ return CredentialKeySchema.parse(parsed);
361
+ } catch (error) {
362
+ logger.warn(
363
+ {
364
+ key: key.substring(0, 100),
365
+ error: error instanceof Error ? error.message : "Unknown error"
366
+ },
367
+ "Failed to parse credential key"
368
+ );
369
+ return null;
370
+ }
371
+ }
372
+ var SUPPORTED_AUTH_MODES = [
373
+ "APP",
374
+ "API_KEY",
375
+ "BASIC",
376
+ "CUSTOM",
377
+ "JWT",
378
+ "NONE",
379
+ "OAUTH1",
380
+ "OAUTH2",
381
+ "OAUTH2_CC",
382
+ "TBA"
383
+ ];
384
+ function isSupportedAuthMode(mode) {
385
+ return SUPPORTED_AUTH_MODES.includes(mode);
386
+ }
387
+ var NangoCredentialStore = class {
388
+ id;
389
+ type = CredentialStoreType.nango;
390
+ nangoConfig;
391
+ nangoClient;
392
+ constructor(id, config) {
393
+ this.id = id;
394
+ this.nangoConfig = config;
395
+ this.nangoClient = new Nango({
396
+ secretKey: this.nangoConfig.secretKey,
397
+ host: this.nangoConfig.apiUrl
398
+ });
399
+ }
400
+ getAccessToken(credentials) {
401
+ const { type } = credentials;
402
+ if (!isSupportedAuthMode(type)) {
403
+ return null;
404
+ }
405
+ const extractAccessTokenForBearerType = (tokenString) => {
406
+ if (tokenString && typeof tokenString === "string") {
407
+ try {
408
+ const parsedToken = JSON.parse(tokenString);
409
+ if (parsedToken.access_token && typeof parsedToken.access_token === "string") {
410
+ return parsedToken.access_token;
411
+ }
412
+ } catch {
413
+ }
414
+ return tokenString;
415
+ }
416
+ return void 0;
417
+ };
418
+ switch (type) {
419
+ case "API_KEY":
420
+ return {
421
+ token: extractAccessTokenForBearerType(
422
+ credentials.apiKey || credentials.api_key
423
+ )
424
+ };
425
+ case "APP":
426
+ return {
427
+ token: extractAccessTokenForBearerType(
428
+ credentials.accessToken || credentials.access_token
429
+ )
430
+ };
431
+ case "BASIC":
432
+ return {
433
+ username: credentials.username,
434
+ token: credentials.password
435
+ };
436
+ case "CUSTOM":
437
+ return credentials.raw;
438
+ case "JWT":
439
+ return {
440
+ token: extractAccessTokenForBearerType(credentials.token)
441
+ };
442
+ case "OAUTH1":
443
+ return {
444
+ token: credentials.oauth_token,
445
+ token_secret: credentials.oauth_token_secret
446
+ };
447
+ case "OAUTH2":
448
+ return {
449
+ token: extractAccessTokenForBearerType(credentials.access_token),
450
+ refresh_token: credentials.refresh_token,
451
+ expiresAt: credentials.expires_at
452
+ };
453
+ case "OAUTH2_CC":
454
+ return {
455
+ token: extractAccessTokenForBearerType(credentials.token),
456
+ client_certificate: credentials.client_certificate,
457
+ client_id: credentials.client_id,
458
+ client_private_key: credentials.client_private_key,
459
+ client_secret: credentials.client_secret
460
+ };
461
+ case "TBA":
462
+ return {
463
+ token: credentials.token_id,
464
+ token_secret: credentials.token_secret
465
+ };
466
+ default:
467
+ return null;
468
+ }
469
+ }
470
+ sanitizeMetadata(metadata) {
471
+ if (!metadata || typeof metadata !== "object") return {};
472
+ const result = {};
473
+ for (const [key, value] of Object.entries(metadata)) {
474
+ if (typeof key !== "string") continue;
475
+ if (typeof value === "string") {
476
+ result[key] = value;
477
+ }
478
+ }
479
+ return result;
480
+ }
481
+ /**
482
+ * Fetch a specific Nango integration
483
+ */
484
+ async fetchNangoIntegration(uniqueKey) {
485
+ try {
486
+ const response = await this.nangoClient.getIntegration(
487
+ { uniqueKey },
488
+ { include: ["credentials"] }
489
+ );
490
+ const integration = response.data;
491
+ let areCredentialsSet = false;
492
+ if (integration.credentials?.type === "OAUTH2" || integration.credentials?.type === "OAUTH1" || integration.credentials?.type === "TBA") {
493
+ areCredentialsSet = !!(integration.credentials?.client_id && integration.credentials?.client_secret);
494
+ } else if (integration.credentials?.type === "APP") {
495
+ areCredentialsSet = !!(integration.credentials?.app_id && integration.credentials?.app_link);
496
+ } else {
497
+ areCredentialsSet = true;
498
+ }
499
+ const { credentials: _credentials, ...integrationWithoutCredentials } = integration;
500
+ return {
501
+ ...integrationWithoutCredentials,
502
+ areCredentialsSet
503
+ };
504
+ } catch (error) {
505
+ if (error && typeof error === "object" && "status" in error && error.status === 404) {
506
+ return null;
507
+ }
508
+ logger.error(
509
+ { error: error instanceof Error ? error.message : "Unknown error", uniqueKey },
510
+ `Failed to fetch integration ${uniqueKey}`
511
+ );
512
+ return null;
513
+ }
514
+ }
515
+ /**
516
+ * Create an API key credential by setting up Nango integration and importing the connection
517
+ */
518
+ async createNangoApiKeyConnection({
519
+ uniqueKey,
520
+ displayName,
521
+ apiKeyToSet,
522
+ metadata
523
+ }) {
524
+ const provider = "private-api-bearer";
525
+ try {
526
+ let integration;
527
+ try {
528
+ const response2 = await this.nangoClient.createIntegration({
529
+ provider,
530
+ unique_key: uniqueKey,
531
+ display_name: displayName
532
+ });
533
+ integration = response2.data;
534
+ } catch (error) {
535
+ const existingIntegration = await this.fetchNangoIntegration(uniqueKey);
536
+ if (existingIntegration) {
537
+ integration = existingIntegration;
538
+ } else {
539
+ console.log(`Integration creation failed for unexpected reasons`, error);
540
+ }
541
+ }
542
+ if (!integration) {
543
+ throw new Error(`Integration '${uniqueKey}' not found`);
544
+ }
545
+ const importConnectionUrl = `${process.env.NANGO_SERVER_URL || "https://api.nango.dev"}/connections`;
546
+ const credentials = {
547
+ type: "API_KEY",
548
+ apiKey: apiKeyToSet
549
+ };
550
+ const body = {
551
+ provider_config_key: integration.unique_key,
552
+ connection_id: uniqueKey,
553
+ metadata,
554
+ credentials
555
+ };
556
+ const response = await fetch(importConnectionUrl, {
557
+ method: "POST",
558
+ headers: {
559
+ Authorization: `Bearer ${process.env.NANGO_SECRET_KEY}`,
560
+ "Content-Type": "application/json"
561
+ },
562
+ body: JSON.stringify(body)
563
+ });
564
+ if (!response.ok) {
565
+ const errorText = await response.text();
566
+ throw new Error(
567
+ `Failed to import connection: HTTP ${response.status} - ${response.statusText}. Response: ${errorText}`
568
+ );
569
+ }
570
+ } catch (error) {
571
+ logger.error(
572
+ {
573
+ error: error instanceof Error ? error.message : "Unknown error",
574
+ displayName
575
+ },
576
+ `Unexpected error creating API key credential '${displayName}'`
577
+ );
578
+ throw new Error(
579
+ `Failed to create API key credential '${displayName}': ${error instanceof Error ? error.message : "Unknown error"}`
580
+ );
581
+ }
582
+ }
583
+ /**
584
+ * Fetch credentials from Nango API using connection information
585
+ * @param connectionId - The connection ID for the Nango connection
586
+ * @param providerConfigKey - The provider config key for the Nango connection
587
+ * @returns The credential data or null if the credentials are not found
588
+ */
589
+ async fetchCredentialsFromNango({
590
+ connectionId,
591
+ providerConfigKey
592
+ }) {
593
+ try {
594
+ const nangoConnection = await this.nangoClient.getConnection(providerConfigKey, connectionId);
595
+ const tokenAndCredentials = this.getAccessToken(nangoConnection.credentials) ?? {};
596
+ const credentialData = {
597
+ ...tokenAndCredentials,
598
+ connectionId,
599
+ providerConfigKey,
600
+ provider: nangoConnection.provider || "unknown",
601
+ secretKey: this.nangoConfig.secretKey,
602
+ metadata: this.sanitizeMetadata(nangoConnection.metadata ?? {})
603
+ };
604
+ return credentialData;
605
+ } catch (error) {
606
+ logger.error(
607
+ {
608
+ error: error instanceof Error ? error.message : "Unknown error",
609
+ connectionId,
610
+ providerConfigKey
611
+ },
612
+ "Error fetching credentials from Nango"
613
+ );
614
+ return null;
615
+ }
616
+ }
617
+ /**
618
+ * Get credentials by key - implements CredentialStore interface
619
+ * Key format: JSON string with connectionId and providerConfigKey
620
+ */
621
+ async get(key) {
622
+ try {
623
+ const parsedKey = parseCredentialKey(key);
624
+ if (!parsedKey) {
625
+ return null;
626
+ }
627
+ const { connectionId, providerConfigKey } = parsedKey;
628
+ const credentials = await this.fetchCredentialsFromNango({ connectionId, providerConfigKey });
629
+ if (!credentials) {
630
+ return null;
631
+ }
632
+ const credentialString = JSON.stringify(credentials);
633
+ return credentialString;
634
+ } catch (error) {
635
+ logger.error(
636
+ {
637
+ storeId: this.id,
638
+ key: key.substring(0, 100),
639
+ error: error instanceof Error ? error.message : "Unknown error"
640
+ },
641
+ "Error getting credentials from Nango"
642
+ );
643
+ return null;
644
+ }
645
+ }
646
+ /**
647
+ * Set credentials - this is used to save bearer auth
648
+ * Key format: JSON string with connectionId and providerConfigKey
649
+ */
650
+ async set(key, value, metadata = {}) {
651
+ const parsedKey = parseCredentialKey(key);
652
+ if (!parsedKey) {
653
+ throw new Error(`Invalid credential key: ${key}`);
654
+ }
655
+ const { connectionId, providerConfigKey, integrationDisplayName } = parsedKey;
656
+ await this.createNangoApiKeyConnection({
657
+ uniqueKey: connectionId,
658
+ displayName: integrationDisplayName ?? providerConfigKey,
659
+ apiKeyToSet: value,
660
+ metadata
661
+ });
662
+ }
663
+ /**
664
+ * Check if credentials exist by attempting to fetch them
665
+ */
666
+ async has(key) {
667
+ try {
668
+ const credentials = await this.get(key);
669
+ return credentials !== null;
670
+ } catch (error) {
671
+ logger.error(
672
+ {
673
+ error: error instanceof Error ? error.message : "Unknown error",
674
+ key
675
+ },
676
+ "Error checking credentials existence"
677
+ );
678
+ return false;
679
+ }
680
+ }
681
+ /**
682
+ * Delete credentials - not supported for Nango (revoke through Nango dashboard)
683
+ */
684
+ async delete(key) {
685
+ try {
686
+ const parsedKey = parseCredentialKey(key);
687
+ if (!parsedKey) {
688
+ return false;
689
+ }
690
+ const { connectionId, providerConfigKey } = parsedKey;
691
+ await this.nangoClient.deleteConnection(providerConfigKey, connectionId);
692
+ return true;
693
+ } catch (error) {
694
+ logger.error(
695
+ {
696
+ storeId: this.id,
697
+ key: key.substring(0, 100),
698
+ error: error instanceof Error ? error.message : "Unknown error"
699
+ },
700
+ "Error deleting credentials from Nango"
701
+ );
702
+ return false;
703
+ }
704
+ }
705
+ /**
706
+ * Check if the credential store is available and functional
707
+ */
708
+ async checkAvailability() {
709
+ if (!this.nangoConfig.secretKey) {
710
+ return {
711
+ available: false,
712
+ reason: "Nango secret key not configured"
713
+ };
714
+ }
715
+ if (this.nangoConfig.secretKey.includes("mock") || this.nangoConfig.secretKey === "your_nango_secret_key") {
716
+ return {
717
+ available: false,
718
+ reason: "Nango secret key appears to be a placeholder or mock value"
719
+ };
720
+ }
721
+ return {
722
+ available: true
723
+ };
724
+ }
725
+ };
726
+ function createNangoCredentialStore(id, config) {
727
+ const nangoSecretKey = config?.secretKey || process.env.NANGO_SECRET_KEY;
728
+ if (!nangoSecretKey || nangoSecretKey === "your_nango_secret_key" || nangoSecretKey.includes("mock")) {
729
+ throw new Error(
730
+ "NANGO_SECRET_KEY environment variable is required and must be a real Nango secret key (not mock/placeholder)"
731
+ );
732
+ }
733
+ return new NangoCredentialStore(id, {
734
+ apiUrl: "https://api.nango.dev",
735
+ ...config,
736
+ secretKey: nangoSecretKey
737
+ });
738
+ }
739
+
740
+ // src/credential-stores/defaults.ts
741
+ function createDefaultCredentialStores() {
742
+ const stores = [];
743
+ stores.push(new InMemoryCredentialStore("memory-default"));
744
+ if (process.env.NANGO_SECRET_KEY) {
745
+ stores.push(
746
+ createNangoCredentialStore("nango-default", {
747
+ apiUrl: process.env.NANGO_SERVER_URL || "https://api.nango.dev",
748
+ secretKey: process.env.NANGO_SECRET_KEY
749
+ })
750
+ );
751
+ }
752
+ try {
753
+ stores.push(createKeyChainStore("keychain-default"));
754
+ } catch (error) {
755
+ console.warn(
756
+ "Failed to create keychain store:",
757
+ error instanceof Error ? error.message : error
758
+ );
759
+ }
760
+ return stores;
761
+ }
762
+
763
+ export { CredentialStoreRegistry, InMemoryCredentialStore, KeyChainStore, NangoCredentialStore, createDefaultCredentialStores, createKeyChainStore, createNangoCredentialStore };