@suveren/gateway 0.35.1 → 0.35.2

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.
@@ -5749,18 +5749,19 @@ async function finalizeAttachmentsForExecution(integrationManager2, integrationI
5749
5749
  contentBase64: d.contentBase64
5750
5750
  }));
5751
5751
  } else {
5752
- const to = toStringArray(outgoing.to);
5753
- const cc = toStringArray(outgoing.cc);
5754
- const subject = typeof outgoing.subject === "string" ? outgoing.subject : "";
5755
- const bodyText = typeof outgoing.body === "string" ? outgoing.body : "";
5756
- const mime = buildMimeMessage({
5757
- to,
5758
- cc,
5759
- subject,
5760
- bodyText,
5761
- attachments: resolvedDocs.map((d) => ({ filename: d.filename, contentType: d.contentType, contentBase64: d.contentBase64 }))
5752
+ const arg = transport.arg;
5753
+ const attachments = resolvedDocs.map((d) => ({ filename: d.filename, contentType: d.contentType, contentBase64: d.contentBase64 }));
5754
+ const withRaw = (a) => ({
5755
+ ...a,
5756
+ [arg]: toBase64Url(buildMimeMessage({
5757
+ to: toStringArray(a.to),
5758
+ cc: toStringArray(a.cc),
5759
+ subject: typeof a.subject === "string" ? a.subject : "",
5760
+ bodyText: typeof a.body === "string" ? a.body : "",
5761
+ attachments
5762
+ }))
5762
5763
  });
5763
- outgoing[transport.arg] = toBase64Url(mime);
5764
+ return { ok: true, args: withRaw(outgoing), rebuildTransport: withRaw };
5764
5765
  }
5765
5766
  }
5766
5767
  return { ok: true, args: outgoing };
@@ -6795,12 +6796,14 @@ Proposal ID: ${proposal.id}. Check status with check-pending-commitments(proposa
6795
6796
  }
6796
6797
  }
6797
6798
  let finalArgs = callArgs;
6799
+ let rebuildTransport;
6798
6800
  if (tool.gating?.attachmentsArg || tool.gating?.insertFields?.length) {
6799
6801
  const finalized = await finalizeAttachmentsForExecution(integrationManager2, tool.integrationId, callArgs);
6800
6802
  if (!finalized.ok) {
6801
6803
  return { content: [{ type: "text", text: finalized.message }], isError: true };
6802
6804
  }
6803
6805
  finalArgs = finalized.args;
6806
+ rebuildTransport = finalized.rebuildTransport;
6804
6807
  }
6805
6808
  let receiptId;
6806
6809
  try {
@@ -7031,6 +7034,7 @@ Proposal ID: ${proposal.id}. Use check-pending-commitments to track status.` + a
7031
7034
  });
7032
7035
  let outgoingArgs = shouldAttachFooter() && receiptId ? appendVerificationFooter(tool, finalArgs, receiptId, auth.subjects?.[0]) : finalArgs;
7033
7036
  if (receiptId) outgoingArgs = attachTicketId(tool, outgoingArgs, receiptId);
7037
+ if (rebuildTransport) outgoingArgs = rebuildTransport(outgoingArgs);
7034
7038
  outgoingArgs = encodeOutgoingArgs(tool, outgoingArgs);
7035
7039
  outgoingArgs = stripSourceLink(outgoingArgs);
7036
7040
  outgoingArgs = stripAttachmentsSealedMeta(outgoingArgs);
@@ -8654,6 +8658,9 @@ function withoutBlockedArgs(schema, blocked) {
8654
8658
  }
8655
8659
  return out;
8656
8660
  }
8661
+ function stableEnvKey(env) {
8662
+ return JSON.stringify(Object.keys(env).sort().map((k) => [k, env[k]]));
8663
+ }
8657
8664
  var RESPAWN_DELAYS = [2e3, 4e3, 6e3];
8658
8665
  var MAX_RESPAWN_ATTEMPTS = 3;
8659
8666
  var CONNECT_TIMEOUT_MS = 3e4;
@@ -8995,6 +9002,7 @@ var IntegrationManager = class {
8995
9002
  );
8996
9003
  }
8997
9004
  const env = this.resolveEnvKeys(config);
9005
+ const credentialEnv = stableEnvKey(env);
8998
9006
  if (isSimulationMode()) {
8999
9007
  const manifest = getManifest(config.id);
9000
9008
  const simDecl = manifest?.simulation;
@@ -9068,7 +9076,8 @@ var IntegrationManager = class {
9068
9076
  client,
9069
9077
  transport,
9070
9078
  tools,
9071
- respawnAttempts: 0
9079
+ respawnAttempts: 0,
9080
+ credentialEnv
9072
9081
  };
9073
9082
  this.running.set(config.id, entry);
9074
9083
  transport.onclose = () => {
@@ -9391,6 +9400,21 @@ var IntegrationManager = class {
9391
9400
  isRunning(id) {
9392
9401
  return this.running.has(id);
9393
9402
  }
9403
+ /**
9404
+ * True when the integration is running but the vault credentials would now
9405
+ * resolve to a different env than the one its process was started with.
9406
+ *
9407
+ * Why: at boot the gateway starts connectors whose settings are all optional
9408
+ * (ERP, CRM — mode/adapter/company file) BEFORE the vault is unlocked, so they
9409
+ * come up on their defaults (simulation). The settings arrive on unlock, and
9410
+ * without a restart the process keeps running on the wrong mode — the user's
9411
+ * live data silently disappears from view.
9412
+ */
9413
+ credentialsChangedSinceStart(config) {
9414
+ const entry = this.running.get(config.id);
9415
+ if (!entry) return false;
9416
+ return stableEnvKey(this.resolveEnvKeys(config)) !== entry.credentialEnv;
9417
+ }
9394
9418
  /**
9395
9419
  * Check if all required env keys for an integration can be resolved.
9396
9420
  */
@@ -9557,7 +9581,8 @@ var IntegrationManager = class {
9557
9581
  client: null,
9558
9582
  transport: null,
9559
9583
  tools: [],
9560
- respawnAttempts: attempts + 1
9584
+ respawnAttempts: attempts + 1,
9585
+ credentialEnv: ""
9561
9586
  };
9562
9587
  this.running.set(id, fakeEntry);
9563
9588
  this.handleCrash(id);
@@ -11708,11 +11733,16 @@ async function startIntegrationForService(serviceId) {
11708
11733
  (c) => c.id === serviceId || Object.values(c.envKeys ?? {}).some((ref) => typeof ref === "string" && ref.startsWith(`${serviceId}.`))
11709
11734
  );
11710
11735
  for (const config of candidates) {
11736
+ if (integrationManager.isRunning(config.id) && integrationManager.credentialsChangedSinceStart(config)) {
11737
+ console.error(`[Suveren MCP] ${config.id}: credentials changed since start \u2014 restarting`);
11738
+ await startOneIntegration(config, { restart: true });
11739
+ continue;
11740
+ }
11711
11741
  await startOneIntegration(config);
11712
11742
  }
11713
11743
  }
11714
- async function startOneIntegration(config) {
11715
- if (integrationManager.isRunning(config.id)) return;
11744
+ async function startOneIntegration(config, opts = {}) {
11745
+ if (!opts.restart && integrationManager.isRunning(config.id)) return;
11716
11746
  const needsCreds = Object.keys(config.envKeys ?? {}).length > 0;
11717
11747
  if (needsCreds && !integrationManager.canResolveEnvKeys(config)) {
11718
11748
  const missing = [];
@@ -11731,7 +11761,7 @@ async function startOneIntegration(config) {
11731
11761
  const manifest = getManifest(config.id);
11732
11762
  const effectiveConfig = manifest ? { ...config, toolGating: manifest.toolGating, npmPackage: manifest.npmPackage ?? config.npmPackage } : config;
11733
11763
  try {
11734
- await integrationManager.startIntegration(effectiveConfig, { skipIfRunning: true });
11764
+ await integrationManager.startIntegration(effectiveConfig, { skipIfRunning: !opts.restart });
11735
11765
  } catch (err) {
11736
11766
  console.error(`[Suveren MCP] Failed to start integration ${config.id}:`, err);
11737
11767
  }