@suveren/gateway 0.33.0 → 0.34.0

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.
@@ -4316,11 +4316,45 @@ function invalidManifestContextReason(manifest) {
4316
4316
  }
4317
4317
  return null;
4318
4318
  }
4319
- function invalidManifestReadGateReason(manifest) {
4320
- const profileDef = getProfile2(manifest.profile);
4321
- if (!profileDef) return null;
4319
+ function overrideProfile(entry) {
4320
+ if (entry === null || typeof entry !== "object") return void 0;
4321
+ const p = entry.profile;
4322
+ return typeof p === "string" ? p : void 0;
4323
+ }
4324
+ function distinctProfilesOf(manifest) {
4325
+ const out = [manifest.profile];
4326
+ for (const entry of Object.values(manifest.toolGating?.overrides ?? {})) {
4327
+ const p = overrideProfile(entry);
4328
+ if (p && !out.includes(p)) out.push(p);
4329
+ }
4330
+ return out;
4331
+ }
4332
+ function invalidManifestOverrideProfilesReason(manifest) {
4322
4333
  const overrides = manifest.toolGating?.overrides ?? {};
4323
- return uncoveredReadSwitchReason(overrides, profileDef.boundsSchema);
4334
+ for (const [toolName, entry] of Object.entries(overrides)) {
4335
+ const profile = overrideProfile(entry);
4336
+ if (!profile) continue;
4337
+ if (!getProfile2(manifest.profile) && !getProfile2(profile)) continue;
4338
+ if (!getProfile2(profile)) {
4339
+ return `override "${toolName}".profile "${profile}" does not resolve to a known profile (full id or short name) \u2014 area-per-tool overrides must name a real profile, same as the manifest's own "profile"`;
4340
+ }
4341
+ }
4342
+ return null;
4343
+ }
4344
+ function invalidManifestReadGateReason(manifest) {
4345
+ const allOverrides = manifest.toolGating?.overrides ?? {};
4346
+ for (const profileId of distinctProfilesOf(manifest)) {
4347
+ const profileDef = getProfile2(profileId);
4348
+ if (!profileDef) continue;
4349
+ const ownOverrides = {};
4350
+ for (const [toolName, entry] of Object.entries(allOverrides)) {
4351
+ const resolved = overrideProfile(entry) ?? manifest.profile;
4352
+ if (resolved === profileId) ownOverrides[toolName] = entry;
4353
+ }
4354
+ const reason = uncoveredReadSwitchReason(ownOverrides, profileDef.boundsSchema);
4355
+ if (reason) return reason;
4356
+ }
4357
+ return null;
4324
4358
  }
4325
4359
  var manifests = /* @__PURE__ */ new Map();
4326
4360
  function loadManifests(integrationsDir) {
@@ -4359,6 +4393,11 @@ function loadManifests(integrationsDir) {
4359
4393
  console.error(`[ManifestLoader] Refusing manifest ${id} (${manifestPath}): ${contextReason}`);
4360
4394
  continue;
4361
4395
  }
4396
+ const overrideProfilesReason = invalidManifestOverrideProfilesReason(manifest);
4397
+ if (overrideProfilesReason) {
4398
+ console.error(`[ManifestLoader] Refusing manifest ${id} (${manifestPath}): ${overrideProfilesReason}`);
4399
+ continue;
4400
+ }
4362
4401
  const readGateReason = invalidManifestReadGateReason(manifest);
4363
4402
  if (readGateReason) {
4364
4403
  console.error(`[ManifestLoader] Refusing manifest ${id} (${manifestPath}): ${readGateReason}`);
@@ -6716,29 +6755,30 @@ function listIntegrationsHandler(state2, integrationManager2) {
6716
6755
  }
6717
6756
  const auths = state2.getEnrichedAuthorizations();
6718
6757
  const statuses = integrationManager2.getStatus();
6719
- const integrations = statuses.filter((s) => s.running).map((s) => {
6758
+ const integrations = statuses.filter((s) => s.running).flatMap((s) => {
6720
6759
  const tools = integrationManager2.getAllTools().filter((t) => t.integrationId === s.id);
6721
- const profile = tools[0]?.gating?.profile ?? null;
6722
- const matchingAuths = profile ? auths.filter((a) => a.complete && profileMatches(a.profileId, profile)) : [];
6723
- let status;
6724
- if (matchingAuths.length > 0) {
6725
- const soonestExpiry = Math.min(
6726
- ...matchingAuths.flatMap(
6727
- (a) => a.attestations.map((att) => att.expiresAt)
6728
- )
6729
- );
6730
- const remainingMs = soonestExpiry * 1e3 - Date.now();
6731
- const remainingMin = Math.ceil(remainingMs / 6e4);
6732
- status = `authorized (${matchingAuths.length} path${matchingAuths.length > 1 ? "s" : ""}, ${remainingMin} min remaining)`;
6733
- } else {
6734
- const allProfileAuths = profile ? auths.filter((a) => profileMatches(a.profileId, profile)) : [];
6735
- status = allProfileAuths.length > 0 ? "expired" : "no authorization";
6736
- }
6737
- return {
6738
- id: s.id,
6739
- profile: profile ? shortProfileName3(profile) : null,
6740
- status
6741
- };
6760
+ const profiles = [...new Set(tools.map((t) => t.gating?.profile).filter((p) => !!p))];
6761
+ if (profiles.length === 0) {
6762
+ return [{ id: s.id, profile: null, status: "no authorization" }];
6763
+ }
6764
+ return profiles.map((profile) => {
6765
+ const matchingAuths = auths.filter((a) => a.complete && profileMatches(a.profileId, profile));
6766
+ let status;
6767
+ if (matchingAuths.length > 0) {
6768
+ const soonestExpiry = Math.min(
6769
+ ...matchingAuths.flatMap(
6770
+ (a) => a.attestations.map((att) => att.expiresAt)
6771
+ )
6772
+ );
6773
+ const remainingMs = soonestExpiry * 1e3 - Date.now();
6774
+ const remainingMin = Math.ceil(remainingMs / 6e4);
6775
+ status = `authorized (${matchingAuths.length} path${matchingAuths.length > 1 ? "s" : ""}, ${remainingMin} min remaining)`;
6776
+ } else {
6777
+ const allProfileAuths = auths.filter((a) => profileMatches(a.profileId, profile));
6778
+ status = allProfileAuths.length > 0 ? "expired" : "no authorization";
6779
+ }
6780
+ return { id: s.id, profile: shortProfileName3(profile), status };
6781
+ });
6742
6782
  });
6743
6783
  const text = integrations.length === 0 ? "No integrations running." : integrations.map(
6744
6784
  (i) => `${i.id} [${i.profile ?? "ungated"}] \u2014 ${i.status}`
@@ -8601,18 +8641,26 @@ var IntegrationManager = class {
8601
8641
  /**
8602
8642
  * Resolve gating config for a tool from the profile's toolGating section.
8603
8643
  * Returns the runtime ToolGatingConfig that tool-proxy.ts consumes.
8644
+ *
8645
+ * Area per tool: an override may declare its OWN `profile`, gating that
8646
+ * one tool under a different area than the rest of the connector (e.g.
8647
+ * an ERP's `create_invoice` under `invoicing` while `create_quote` stays
8648
+ * under the manifest's own `sales`). `resolvedProfile` below is what every
8649
+ * downstream consumer reads as this tool's governing profile — falling
8650
+ * back to the manifest-level `profileId` when the override doesn't say.
8604
8651
  */
8605
8652
  resolveToolGating(profileId, profileGating, toolName) {
8606
8653
  if (!profileId || !profileGating) return null;
8607
8654
  if (profileGating.overrides && toolName in profileGating.overrides) {
8608
8655
  const override = profileGating.overrides[toolName];
8609
8656
  const ext = override ?? {};
8657
+ const resolvedProfile = ext.profile ?? profileId;
8610
8658
  if (ext.category === "disabled") {
8611
- return { profile: profileId, executionMapping: {}, category: "disabled" };
8659
+ return { profile: resolvedProfile, executionMapping: {}, category: "disabled" };
8612
8660
  }
8613
8661
  if (override === null || ext.category === "read") {
8614
8662
  return {
8615
- profile: profileId,
8663
+ profile: resolvedProfile,
8616
8664
  executionMapping: {},
8617
8665
  category: "read",
8618
8666
  boundField: ext.boundField,
@@ -8627,7 +8675,7 @@ var IntegrationManager = class {
8627
8675
  };
8628
8676
  }
8629
8677
  return {
8630
- profile: profileId,
8678
+ profile: resolvedProfile,
8631
8679
  executionMapping: override.executionMapping,
8632
8680
  staticExecution: override.staticExecution,
8633
8681
  // Which argument the receipt binds to. This resolver is an explicit