@flutchai/flutch-sdk 0.2.9 → 0.2.11

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/dist/index.cjs CHANGED
@@ -53,6 +53,7 @@ var path2__namespace = /*#__PURE__*/_interopNamespace(path2);
53
53
  var os__namespace = /*#__PURE__*/_interopNamespace(os);
54
54
  var net__namespace = /*#__PURE__*/_interopNamespace(net);
55
55
  var mongoose__default = /*#__PURE__*/_interopDefault(mongoose);
56
+ var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
56
57
  var LangGraph__namespace = /*#__PURE__*/_interopNamespace(LangGraph);
57
58
  var axios2__default = /*#__PURE__*/_interopDefault(axios2);
58
59
 
@@ -1365,10 +1366,10 @@ exports.AbstractGraphBuilder = class AbstractGraphBuilder {
1365
1366
  return null;
1366
1367
  }
1367
1368
  try {
1368
- const fs2 = await import('fs/promises');
1369
- const path3 = await import('path');
1370
- const manifestFullPath = path3.resolve(this.manifestPath);
1371
- const manifestContent = await fs2.readFile(manifestFullPath, "utf-8");
1369
+ const fs3 = await import('fs/promises');
1370
+ const path4 = await import('path');
1371
+ const manifestFullPath = path4.resolve(this.manifestPath);
1372
+ const manifestContent = await fs3.readFile(manifestFullPath, "utf-8");
1372
1373
  const manifest = JSON.parse(manifestContent);
1373
1374
  this.manifest = manifest;
1374
1375
  return manifest;
@@ -1387,10 +1388,10 @@ exports.AbstractGraphBuilder = class AbstractGraphBuilder {
1387
1388
  return null;
1388
1389
  }
1389
1390
  try {
1390
- const fs2 = __require("fs");
1391
- const path3 = __require("path");
1392
- const manifestFullPath = path3.resolve(this.manifestPath);
1393
- const manifestContent = fs2.readFileSync(manifestFullPath, "utf-8");
1391
+ const fs3 = __require("fs");
1392
+ const path4 = __require("path");
1393
+ const manifestFullPath = path4.resolve(this.manifestPath);
1394
+ const manifestContent = fs3.readFileSync(manifestFullPath, "utf-8");
1394
1395
  const manifest = JSON.parse(manifestContent);
1395
1396
  this.manifest = manifest;
1396
1397
  return manifest;
@@ -1430,12 +1431,12 @@ exports.AbstractGraphBuilder = class AbstractGraphBuilder {
1430
1431
  let configSchema = null;
1431
1432
  if (versionConfig.configSchemaPath) {
1432
1433
  try {
1433
- const fs2 = await import('fs/promises');
1434
+ const fs3 = await import('fs/promises');
1434
1435
  const schemaPath = path2__namespace.resolve(
1435
1436
  process.cwd(),
1436
1437
  versionConfig.configSchemaPath
1437
1438
  );
1438
- const schemaContent = await fs2.readFile(schemaPath, "utf-8");
1439
+ const schemaContent = await fs3.readFile(schemaPath, "utf-8");
1439
1440
  const schemaData = JSON.parse(schemaContent);
1440
1441
  configSchema = schemaData.schema;
1441
1442
  } catch (error) {
@@ -2847,8 +2848,8 @@ exports.IdempotencyManager = __decorateClass([
2847
2848
 
2848
2849
  // src/callbacks/smart-callback.router.ts
2849
2850
  exports.SmartCallbackRouter = class SmartCallbackRouter {
2850
- constructor(registry, store, acl, auditor, metrics, rateLimiter, idempotencyManager, patchService) {
2851
- this.registry = registry;
2851
+ constructor(registry2, store, acl, auditor, metrics, rateLimiter, idempotencyManager, patchService) {
2852
+ this.registry = registry2;
2852
2853
  this.store = store;
2853
2854
  this.acl = acl;
2854
2855
  this.auditor = auditor;
@@ -3127,8 +3128,8 @@ var UniversalCallbackService = class {
3127
3128
  };
3128
3129
 
3129
3130
  // src/callbacks/example.callback.ts
3130
- function registerFinanceExampleCallback(registry) {
3131
- registry.register(
3131
+ function registerFinanceExampleCallback(registry2) {
3132
+ registry2.register(
3132
3133
  "example",
3133
3134
  async () => ({
3134
3135
  success: true,
@@ -3653,8 +3654,8 @@ exports.CallbackMetrics = class CallbackMetrics {
3653
3654
  activeCallbacks;
3654
3655
  pendingCallbacks;
3655
3656
  queueSize;
3656
- constructor(registry) {
3657
- this.registry = registry ?? new promClient.Registry();
3657
+ constructor(registry2) {
3658
+ this.registry = registry2 ?? new promClient.Registry();
3658
3659
  promClient.collectDefaultMetrics({ register: this.registry });
3659
3660
  this.callbacksTotal = new promClient.Counter({
3660
3661
  name: "graph_callbacks_total",
@@ -5657,7 +5658,7 @@ exports.UniversalGraphModule = class UniversalGraphModule {
5657
5658
  },
5658
5659
  {
5659
5660
  provide: exports.CallbackMetrics,
5660
- useFactory: (registry) => new exports.CallbackMetrics(registry),
5661
+ useFactory: (registry2) => new exports.CallbackMetrics(registry2),
5661
5662
  inject: ["PROMETHEUS_REGISTRY"]
5662
5663
  },
5663
5664
  {
@@ -5685,8 +5686,8 @@ exports.UniversalGraphModule = class UniversalGraphModule {
5685
5686
  },
5686
5687
  {
5687
5688
  provide: exports.SmartCallbackRouter,
5688
- useFactory: (registry, store, acl, auditor, metrics, rateLimiter, idempotencyManager, patchService) => new exports.SmartCallbackRouter(
5689
- registry,
5689
+ useFactory: (registry2, store, acl, auditor, metrics, rateLimiter, idempotencyManager, patchService) => new exports.SmartCallbackRouter(
5690
+ registry2,
5690
5691
  store,
5691
5692
  acl,
5692
5693
  auditor,
@@ -5718,8 +5719,8 @@ exports.UniversalGraphModule = class UniversalGraphModule {
5718
5719
  },
5719
5720
  {
5720
5721
  provide: "CALLBACK_EXAMPLE_REGISTRATION",
5721
- useFactory: (registry) => {
5722
- registerFinanceExampleCallback(registry);
5722
+ useFactory: (registry2) => {
5723
+ registerFinanceExampleCallback(registry2);
5723
5724
  },
5724
5725
  inject: [CallbackRegistry]
5725
5726
  },
@@ -5782,8 +5783,8 @@ exports.UniversalGraphModule = class UniversalGraphModule {
5782
5783
  },
5783
5784
  {
5784
5785
  provide: "GRAPH_BUILDERS",
5785
- useFactory: (registry) => {
5786
- return registry.getBuilders();
5786
+ useFactory: (registry2) => {
5787
+ return registry2.getBuilders();
5787
5788
  },
5788
5789
  inject: [exports.BuilderRegistryService]
5789
5790
  },
@@ -7325,6 +7326,250 @@ exports.StaticDiscovery = class StaticDiscovery {
7325
7326
  exports.StaticDiscovery = __decorateClass([
7326
7327
  common.Injectable()
7327
7328
  ], exports.StaticDiscovery);
7329
+ var ALGORITHM = "aes-256-cbc";
7330
+ var IV_LENGTH = 16;
7331
+ function encryptTokens(tokens, key) {
7332
+ const iv = crypto__namespace.randomBytes(IV_LENGTH);
7333
+ const cipher = crypto__namespace.createCipheriv(ALGORITHM, Buffer.from(key), iv);
7334
+ const json = JSON.stringify(tokens);
7335
+ let encrypted = cipher.update(json, "utf8", "hex");
7336
+ encrypted += cipher.final("hex");
7337
+ return iv.toString("hex") + ":" + encrypted;
7338
+ }
7339
+ function decryptTokens(encrypted, key) {
7340
+ const separatorIndex = encrypted.indexOf(":");
7341
+ if (separatorIndex === -1) {
7342
+ throw new Error("Invalid encrypted token format");
7343
+ }
7344
+ const ivHex = encrypted.substring(0, separatorIndex);
7345
+ const encryptedData = encrypted.substring(separatorIndex + 1);
7346
+ const iv = Buffer.from(ivHex, "hex");
7347
+ const decipher = crypto__namespace.createDecipheriv(ALGORITHM, Buffer.from(key), iv);
7348
+ let decrypted = decipher.update(encryptedData, "hex", "utf8");
7349
+ decrypted += decipher.final("utf8");
7350
+ return JSON.parse(decrypted);
7351
+ }
7352
+
7353
+ // src/oauth/oauth-token.manager.ts
7354
+ var EXPIRY_BUFFER_MS = 6e4;
7355
+ var OAuthTokenManager = class {
7356
+ store;
7357
+ encryptionKey;
7358
+ cache = /* @__PURE__ */ new Map();
7359
+ constructor(options) {
7360
+ if (!options.encryptionKey || options.encryptionKey.length < 32) {
7361
+ throw new Error(
7362
+ "OAUTH_ENCRYPTION_KEY must be at least 32 characters for AES-256-CBC"
7363
+ );
7364
+ }
7365
+ this.store = options.store;
7366
+ this.encryptionKey = options.encryptionKey;
7367
+ }
7368
+ /**
7369
+ * Get a fresh access token for the given provider.
7370
+ * Returns from cache → store → refresh flow (in that order).
7371
+ */
7372
+ async getAccessToken(config) {
7373
+ const cached = this.cache.get(config.provider);
7374
+ if (cached && cached.expiresAt > Date.now() + EXPIRY_BUFFER_MS) {
7375
+ return cached.token;
7376
+ }
7377
+ const encrypted = await this.store.get(config.provider);
7378
+ if (!encrypted) {
7379
+ throw new Error(
7380
+ `No OAuth tokens found for "${config.provider}". Complete the OAuth consent flow first and call saveTokens().`
7381
+ );
7382
+ }
7383
+ const tokens = decryptTokens(encrypted, this.encryptionKey);
7384
+ if (tokens.expiresAt > Date.now() + EXPIRY_BUFFER_MS) {
7385
+ this.setCache(config.provider, tokens.accessToken, tokens.expiresAt);
7386
+ return tokens.accessToken;
7387
+ }
7388
+ const refreshed = await this.refreshAccessToken(
7389
+ config,
7390
+ tokens.refreshToken
7391
+ );
7392
+ await this.persistTokens(config.provider, refreshed);
7393
+ return refreshed.accessToken;
7394
+ }
7395
+ /**
7396
+ * Store tokens after the initial OAuth consent flow.
7397
+ * Call this once after the user completes the OAuth redirect.
7398
+ */
7399
+ async saveTokens(provider, tokens) {
7400
+ await this.persistTokens(provider, tokens);
7401
+ }
7402
+ /**
7403
+ * Remove all tokens for a provider.
7404
+ */
7405
+ async revokeTokens(provider) {
7406
+ await this.store.delete(provider);
7407
+ this.cache.delete(provider);
7408
+ }
7409
+ /**
7410
+ * Check if tokens exist for a provider (without decrypting).
7411
+ */
7412
+ async hasTokens(provider) {
7413
+ const encrypted = await this.store.get(provider);
7414
+ return encrypted !== null;
7415
+ }
7416
+ async refreshAccessToken(config, refreshToken) {
7417
+ try {
7418
+ const response = await axios2__default.default.post(
7419
+ config.tokenUrl,
7420
+ new URLSearchParams({
7421
+ grant_type: "refresh_token",
7422
+ client_id: config.clientId,
7423
+ client_secret: config.clientSecret,
7424
+ refresh_token: refreshToken
7425
+ }).toString(),
7426
+ {
7427
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
7428
+ timeout: 1e4
7429
+ }
7430
+ );
7431
+ const data = response.data;
7432
+ return {
7433
+ accessToken: data.access_token,
7434
+ // Some providers rotate refresh tokens; keep the old one if not rotated
7435
+ refreshToken: data.refresh_token || refreshToken,
7436
+ expiresAt: Date.now() + (data.expires_in || 3600) * 1e3
7437
+ };
7438
+ } catch (error) {
7439
+ const status = error?.response?.status;
7440
+ const body = error?.response?.data;
7441
+ throw new Error(
7442
+ `OAuth refresh failed for "${config.provider}": ${status || "network error"} ${JSON.stringify(body) || error.message}`
7443
+ );
7444
+ }
7445
+ }
7446
+ async persistTokens(provider, tokens) {
7447
+ const encrypted = encryptTokens(tokens, this.encryptionKey);
7448
+ await this.store.save(provider, encrypted);
7449
+ this.setCache(provider, tokens.accessToken, tokens.expiresAt);
7450
+ }
7451
+ setCache(provider, token, expiresAt) {
7452
+ this.cache.set(provider, { token, expiresAt });
7453
+ }
7454
+ };
7455
+
7456
+ // src/oauth/oauth-provider.registry.ts
7457
+ var registry = {};
7458
+ function loadOAuthProviders(providers) {
7459
+ registry = { ...providers };
7460
+ }
7461
+ function getOAuthProvider(provider) {
7462
+ const def = registry[provider];
7463
+ if (!def) {
7464
+ throw new Error(`Unknown OAuth provider: ${provider}`);
7465
+ }
7466
+ return def;
7467
+ }
7468
+ function getOAuthProviderNames() {
7469
+ return Object.keys(registry);
7470
+ }
7471
+ function resolveOAuthProviderConfig(provider) {
7472
+ const def = getOAuthProvider(provider);
7473
+ const clientId = process.env[def.clientIdEnvVar];
7474
+ const clientSecret = process.env[def.clientSecretEnvVar];
7475
+ if (!clientId) {
7476
+ throw new Error(`Missing env var: ${def.clientIdEnvVar}`);
7477
+ }
7478
+ if (!clientSecret) {
7479
+ throw new Error(`Missing env var: ${def.clientSecretEnvVar}`);
7480
+ }
7481
+ return {
7482
+ provider: def.name,
7483
+ tokenUrl: def.tokenUrl,
7484
+ clientId,
7485
+ clientSecret
7486
+ };
7487
+ }
7488
+ function buildOAuthAuthorizationUrl(provider, params) {
7489
+ const def = getOAuthProvider(provider);
7490
+ const clientId = process.env[def.clientIdEnvVar];
7491
+ if (!clientId) {
7492
+ throw new Error(`Missing env var: ${def.clientIdEnvVar}`);
7493
+ }
7494
+ const query = new URLSearchParams({
7495
+ client_id: clientId,
7496
+ redirect_uri: params.redirectUri,
7497
+ response_type: "code",
7498
+ state: params.state
7499
+ });
7500
+ if (def.scopes.length > 0) {
7501
+ query.set("scope", def.scopes.join(" "));
7502
+ }
7503
+ return `${def.authorizationUrl}?${query.toString()}`;
7504
+ }
7505
+ var FileTokenStore = class {
7506
+ constructor(filePath) {
7507
+ this.filePath = filePath;
7508
+ }
7509
+ async get(provider) {
7510
+ const data = this.readFile();
7511
+ return data[provider] ?? null;
7512
+ }
7513
+ async save(provider, encrypted) {
7514
+ const data = this.readFile();
7515
+ data[provider] = encrypted;
7516
+ this.writeFile(data);
7517
+ }
7518
+ async delete(provider) {
7519
+ const data = this.readFile();
7520
+ delete data[provider];
7521
+ this.writeFile(data);
7522
+ }
7523
+ readFile() {
7524
+ try {
7525
+ if (fs__namespace.existsSync(this.filePath)) {
7526
+ const content = fs__namespace.readFileSync(this.filePath, "utf8");
7527
+ return JSON.parse(content);
7528
+ }
7529
+ } catch {
7530
+ }
7531
+ return {};
7532
+ }
7533
+ writeFile(data) {
7534
+ const dir = path2__namespace.dirname(this.filePath);
7535
+ if (!fs__namespace.existsSync(dir)) {
7536
+ fs__namespace.mkdirSync(dir, { recursive: true });
7537
+ }
7538
+ fs__namespace.writeFileSync(this.filePath, JSON.stringify(data, null, 2), "utf8");
7539
+ }
7540
+ };
7541
+
7542
+ // src/oauth/stores/mongo-token.store.ts
7543
+ var DEFAULT_COLLECTION = "oauth_tokens";
7544
+ var MongoTokenStore = class {
7545
+ constructor(db, collectionName) {
7546
+ this.db = db;
7547
+ this.collectionName = collectionName ?? DEFAULT_COLLECTION;
7548
+ }
7549
+ collectionName;
7550
+ initialized = false;
7551
+ async get(provider) {
7552
+ await this.ensureIndex();
7553
+ const doc = await this.db.collection(this.collectionName).findOne({ provider });
7554
+ return doc?.encrypted ?? null;
7555
+ }
7556
+ async save(provider, encrypted) {
7557
+ await this.ensureIndex();
7558
+ await this.db.collection(this.collectionName).updateOne(
7559
+ { provider },
7560
+ { $set: { provider, encrypted, updatedAt: /* @__PURE__ */ new Date() } },
7561
+ { upsert: true }
7562
+ );
7563
+ }
7564
+ async delete(provider) {
7565
+ await this.db.collection(this.collectionName).deleteOne({ provider });
7566
+ }
7567
+ async ensureIndex() {
7568
+ if (this.initialized) return;
7569
+ await this.db.collection(this.collectionName).createIndex({ provider: 1 }, { unique: true });
7570
+ this.initialized = true;
7571
+ }
7572
+ };
7328
7573
 
7329
7574
  exports.AttachmentType = AttachmentType;
7330
7575
  exports.BaseGraphServiceController = exports.GraphController;
@@ -7337,6 +7582,7 @@ exports.ChatFeature = ChatFeature;
7337
7582
  exports.DEFAULT_ATTACHMENT_THRESHOLD = DEFAULT_ATTACHMENT_THRESHOLD;
7338
7583
  exports.DEFAULT_TRACER_OPTIONS = DEFAULT_TRACER_OPTIONS;
7339
7584
  exports.Endpoint = Endpoint;
7585
+ exports.FileTokenStore = FileTokenStore;
7340
7586
  exports.GraphEngineType = GraphEngineType;
7341
7587
  exports.GraphManifestSchema = GraphManifestSchema;
7342
7588
  exports.GraphManifestValidator = GraphManifestValidator;
@@ -7347,6 +7593,8 @@ exports.McpToolFilter = McpToolFilter;
7347
7593
  exports.ModelInitializer = ModelInitializer;
7348
7594
  exports.ModelProvider = ModelProvider;
7349
7595
  exports.ModelType = ModelType;
7596
+ exports.MongoTokenStore = MongoTokenStore;
7597
+ exports.OAuthTokenManager = OAuthTokenManager;
7350
7598
  exports.RetrieverSearchType = RetrieverSearchType;
7351
7599
  exports.StreamChannel = StreamChannel;
7352
7600
  exports.UIEndpoint = UIEndpoint;
@@ -7357,12 +7605,15 @@ exports.WithEndpoints = WithEndpoints;
7357
7605
  exports.WithUIEndpoints = WithUIEndpoints;
7358
7606
  exports._internals = _internals;
7359
7607
  exports.bootstrap = bootstrap;
7608
+ exports.buildOAuthAuthorizationUrl = buildOAuthAuthorizationUrl;
7360
7609
  exports.clearAttachmentDataStore = clearAttachmentDataStore;
7361
7610
  exports.createEndpointDescriptors = createEndpointDescriptors;
7362
7611
  exports.createGraphAttachment = createGraphAttachment;
7363
7612
  exports.createMongoClientAdapter = createMongoClientAdapter;
7364
7613
  exports.createStaticMessage = createStaticMessage;
7614
+ exports.decryptTokens = decryptTokens;
7365
7615
  exports.dispatchAttachments = dispatchAttachments;
7616
+ exports.encryptTokens = encryptTokens;
7366
7617
  exports.executeToolWithAttachments = executeToolWithAttachments;
7367
7618
  exports.findCallbackMethod = findCallbackMethod;
7368
7619
  exports.findEndpointMethod = findEndpointMethod;
@@ -7370,12 +7621,16 @@ exports.generateAttachmentSummary = generateAttachmentSummary;
7370
7621
  exports.getAttachmentData = getAttachmentData;
7371
7622
  exports.getCallbackMetadata = getCallbackMetadata;
7372
7623
  exports.getEndpointMetadata = getEndpointMetadata;
7624
+ exports.getOAuthProvider = getOAuthProvider;
7625
+ exports.getOAuthProviderNames = getOAuthProviderNames;
7373
7626
  exports.getUIEndpointClassMetadata = getUIEndpointClassMetadata;
7374
7627
  exports.getUIEndpointMethodsMetadata = getUIEndpointMethodsMetadata;
7375
7628
  exports.hasCallbacks = hasCallbacks;
7376
7629
  exports.hasUIEndpoints = hasUIEndpoints;
7630
+ exports.loadOAuthProviders = loadOAuthProviders;
7377
7631
  exports.registerFinanceExampleCallback = registerFinanceExampleCallback;
7378
7632
  exports.registerUIEndpointsFromClass = registerUIEndpointsFromClass;
7633
+ exports.resolveOAuthProviderConfig = resolveOAuthProviderConfig;
7379
7634
  exports.sanitizeTraceData = sanitizeTraceData;
7380
7635
  exports.storeAttachmentData = storeAttachmentData;
7381
7636
  exports.traceApiCall = traceApiCall;