@alfe.ai/integrations 0.6.4 → 0.6.5
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.d.ts +19 -6
- package/dist/index.js +64 -10
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -450,6 +450,8 @@ declare class McpApplier {
|
|
|
450
450
|
*/
|
|
451
451
|
applyForIntegration(integrationId: string, servers: McpServerDeclaration[], mergedConfig: Record<string, unknown>, opts?: {
|
|
452
452
|
connectionId?: string;
|
|
453
|
+
connectionAuthorityVersion?: string;
|
|
454
|
+
strictReconcile?: boolean;
|
|
453
455
|
}): Promise<string[]>;
|
|
454
456
|
/**
|
|
455
457
|
* Drop every entry owned by this integration. Store writes are
|
|
@@ -562,6 +564,8 @@ interface IntegrationInfo {
|
|
|
562
564
|
version?: string;
|
|
563
565
|
status: IntegrationStatus;
|
|
564
566
|
installedAt?: string;
|
|
567
|
+
connectionAuthorityVersion?: string;
|
|
568
|
+
connectionAuthorityPendingVersion?: string;
|
|
565
569
|
config?: Record<string, unknown>;
|
|
566
570
|
error?: string;
|
|
567
571
|
}
|
|
@@ -620,7 +624,12 @@ declare class IntegrationManager {
|
|
|
620
624
|
*/
|
|
621
625
|
activate(integrationId: string, opts?: {
|
|
622
626
|
forcePlugins?: boolean;
|
|
627
|
+
refresh?: boolean;
|
|
623
628
|
}): Promise<ManagerResponse>;
|
|
629
|
+
/** Refresh only the consumers whose manifest depends on changed account authority. */
|
|
630
|
+
refreshConnections(integrationId: string, connectionAuthorityVersion: string, opts?: {
|
|
631
|
+
onBeforeRuntimeMutation?: () => Promise<void>;
|
|
632
|
+
}): Promise<void>;
|
|
624
633
|
/**
|
|
625
634
|
* Deactivate a running integration.
|
|
626
635
|
*
|
|
@@ -1836,7 +1845,13 @@ interface IIntegrationManager {
|
|
|
1836
1845
|
version: string;
|
|
1837
1846
|
status: string;
|
|
1838
1847
|
installedAt?: string;
|
|
1848
|
+
connectionAuthorityVersion?: string;
|
|
1849
|
+
connectionAuthorityPendingVersion?: string;
|
|
1839
1850
|
}[]>;
|
|
1851
|
+
/** Reconcile account-bearing MCP processes after their effective account set changes. */
|
|
1852
|
+
refreshConnections(integrationId: string, connectionAuthorityVersion: string, opts?: {
|
|
1853
|
+
onBeforeRuntimeMutation?: () => Promise<void>;
|
|
1854
|
+
}): Promise<void>;
|
|
1840
1855
|
/** Install an integration at a specific version with config */
|
|
1841
1856
|
install(integrationId: string, version: string, config: unknown, customSource?: CustomInstallSource): Promise<void>;
|
|
1842
1857
|
/** Activate an installed integration. `opts.forcePlugins` forces version-drift reinstall of already-installed plugins. */
|
|
@@ -1877,12 +1892,10 @@ interface IIntegrationManager {
|
|
|
1877
1892
|
declare class IntegrationManagerAdapter implements IIntegrationManager {
|
|
1878
1893
|
private readonly manager;
|
|
1879
1894
|
constructor(manager: IntegrationManager);
|
|
1880
|
-
getInstalledIntegrations():
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
installedAt?: string;
|
|
1885
|
-
}[]>;
|
|
1895
|
+
getInstalledIntegrations(): ReturnType<IIntegrationManager['getInstalledIntegrations']>;
|
|
1896
|
+
refreshConnections(integrationId: string, connectionAuthorityVersion: string, opts?: {
|
|
1897
|
+
onBeforeRuntimeMutation?: () => Promise<void>;
|
|
1898
|
+
}): Promise<void>;
|
|
1886
1899
|
install(integrationId: string, version: string, config: unknown, customSource?: CustomInstallSource): Promise<void>;
|
|
1887
1900
|
activate(integrationId: string, opts?: {
|
|
1888
1901
|
forcePlugins?: boolean;
|
package/dist/index.js
CHANGED
|
@@ -907,7 +907,7 @@ function validateStateFile(value) {
|
|
|
907
907
|
const integrations = Object.create(null);
|
|
908
908
|
for (const [id, rawEntry] of Object.entries(value.integrations)) {
|
|
909
909
|
assertSafePathSegment(id, "Persisted integration id");
|
|
910
|
-
if (!isRecord$1(rawEntry) || typeof rawEntry.status !== "string" || !VALID_STATUSES.has(rawEntry.status) || typeof rawEntry.version !== "string" || typeof rawEntry.installedAt !== "string" || !isRecord$1(rawEntry.config) || rawEntry.error !== void 0 && typeof rawEntry.error !== "string" || rawEntry.reinstallAttempts !== void 0 && (typeof rawEntry.reinstallAttempts !== "number" || !Number.isSafeInteger(rawEntry.reinstallAttempts) || rawEntry.reinstallAttempts < 0) || rawEntry.customConnectionId !== void 0 && typeof rawEntry.customConnectionId !== "string") throw new Error(`Integration state entry "${id}" has an invalid shape`);
|
|
910
|
+
if (!isRecord$1(rawEntry) || typeof rawEntry.status !== "string" || !VALID_STATUSES.has(rawEntry.status) || typeof rawEntry.version !== "string" || typeof rawEntry.installedAt !== "string" || !isRecord$1(rawEntry.config) || rawEntry.error !== void 0 && typeof rawEntry.error !== "string" || rawEntry.reinstallAttempts !== void 0 && (typeof rawEntry.reinstallAttempts !== "number" || !Number.isSafeInteger(rawEntry.reinstallAttempts) || rawEntry.reinstallAttempts < 0) || rawEntry.customConnectionId !== void 0 && typeof rawEntry.customConnectionId !== "string" || rawEntry.connectionAuthorityVersion !== void 0 && (typeof rawEntry.connectionAuthorityVersion !== "string" || !/^[a-f0-9]{64}$/.test(rawEntry.connectionAuthorityVersion)) || rawEntry.connectionAuthorityPendingVersion !== void 0 && (typeof rawEntry.connectionAuthorityPendingVersion !== "string" || !/^[a-f0-9]{64}$/.test(rawEntry.connectionAuthorityPendingVersion))) throw new Error(`Integration state entry "${id}" has an invalid shape`);
|
|
911
911
|
integrations[id] = rawEntry;
|
|
912
912
|
}
|
|
913
913
|
return {
|
|
@@ -1697,7 +1697,7 @@ var IntegrationManager = class {
|
|
|
1697
1697
|
async activate(integrationId, opts) {
|
|
1698
1698
|
const entry = this.state.get(integrationId);
|
|
1699
1699
|
if (!entry) return this.err("NOT_FOUND", `Integration "${integrationId}" is not installed`);
|
|
1700
|
-
if (entry.status === "active") return {
|
|
1700
|
+
if (entry.status === "active" && !opts?.refresh) return {
|
|
1701
1701
|
ok: true,
|
|
1702
1702
|
payload: {
|
|
1703
1703
|
name: integrationId,
|
|
@@ -1705,7 +1705,7 @@ var IntegrationManager = class {
|
|
|
1705
1705
|
message: "Already active"
|
|
1706
1706
|
}
|
|
1707
1707
|
};
|
|
1708
|
-
if (entry.status !== "configured" && entry.status !== "installed" && entry.status !== "error") return this.err("INVALID_STATE", `Cannot activate integration in "${entry.status}" state`);
|
|
1708
|
+
if (entry.status !== "configured" && entry.status !== "installed" && entry.status !== "error" && !(entry.status === "active" && opts?.refresh)) return this.err("INVALID_STATE", `Cannot activate integration in "${entry.status}" state`);
|
|
1709
1709
|
this.log.info(`Activating integration: ${integrationId}`);
|
|
1710
1710
|
try {
|
|
1711
1711
|
const installPath = this.installer.getInstallPath(integrationId);
|
|
@@ -1844,6 +1844,41 @@ var IntegrationManager = class {
|
|
|
1844
1844
|
return this.err("ACTIVATE_FAILED", message);
|
|
1845
1845
|
}
|
|
1846
1846
|
}
|
|
1847
|
+
/** Refresh only the consumers whose manifest depends on changed account authority. */
|
|
1848
|
+
async refreshConnections(integrationId, connectionAuthorityVersion, opts) {
|
|
1849
|
+
if (!/^[a-f0-9]{64}$/.test(connectionAuthorityVersion)) throw new Error("Invalid connection authority version");
|
|
1850
|
+
const entry = this.state.get(integrationId);
|
|
1851
|
+
if (!entry || entry.status !== "active" && !(entry.status === "error" && entry.connectionAuthorityPendingVersion)) throw new Error("Connection refresh requires an active integration or a pending authority retry");
|
|
1852
|
+
if (entry.connectionAuthorityVersion === connectionAuthorityVersion && !entry.connectionAuthorityPendingVersion) return;
|
|
1853
|
+
const manifest = parseManifestFile(join(this.installer.getInstallPath(integrationId), "alfe-integration.yaml"));
|
|
1854
|
+
this.state.update(integrationId, { connectionAuthorityPendingVersion: connectionAuthorityVersion });
|
|
1855
|
+
const supported = this.manifestSupportsRegisteredRuntime(manifest);
|
|
1856
|
+
if (supported && (Boolean(manifest.hooks.post_activate) || [...this.runtimeAppliers.keys()].some((runtime) => {
|
|
1857
|
+
if (manifest.supported_agents?.length && !manifest.supported_agents.includes(runtime)) return false;
|
|
1858
|
+
const installs = resolveInstallsForRuntime(manifest, runtime);
|
|
1859
|
+
return installs.plugins.length > 0 || installs.skills.length > 0 || Object.keys(installs.config ?? {}).length > 0;
|
|
1860
|
+
}))) {
|
|
1861
|
+
await opts?.onBeforeRuntimeMutation?.();
|
|
1862
|
+
const refreshed = await this.activate(integrationId, { refresh: true });
|
|
1863
|
+
if (!refreshed.ok) throw new Error(refreshed.error?.message ?? "Connection consumer refresh failed");
|
|
1864
|
+
}
|
|
1865
|
+
if (supported && manifest.mcp_servers.length > 0) {
|
|
1866
|
+
if (!this.mcpApplier) throw new Error("Connection refresh requires an MCP applier");
|
|
1867
|
+
const secretEntries = this.secrets.get(integrationId);
|
|
1868
|
+
if ((await this.mcpApplier.applyForIntegration(integrationId, manifest.mcp_servers, {
|
|
1869
|
+
...entry.config,
|
|
1870
|
+
...secretEntries ? Object.fromEntries(secretEntries) : {}
|
|
1871
|
+
}, {
|
|
1872
|
+
connectionId: entry.customConnectionId,
|
|
1873
|
+
connectionAuthorityVersion,
|
|
1874
|
+
strictReconcile: true
|
|
1875
|
+
})).length !== manifest.mcp_servers.length) throw new Error("Connection refresh could not resolve every MCP credential");
|
|
1876
|
+
}
|
|
1877
|
+
this.state.update(integrationId, {
|
|
1878
|
+
connectionAuthorityVersion,
|
|
1879
|
+
connectionAuthorityPendingVersion: void 0
|
|
1880
|
+
});
|
|
1881
|
+
}
|
|
1847
1882
|
/**
|
|
1848
1883
|
* Deactivate a running integration.
|
|
1849
1884
|
*
|
|
@@ -1982,7 +2017,7 @@ var IntegrationManager = class {
|
|
|
1982
2017
|
secrets: this.secrets.get(name),
|
|
1983
2018
|
runtimes: [...this.runtimeAppliers.keys()]
|
|
1984
2019
|
}, INSTALL_HOOK_TIMEOUT_MS);
|
|
1985
|
-
if (hookResult.exitCode !== 0)
|
|
2020
|
+
if (hookResult.exitCode !== 0) throw new Error(this.hookFailureMessage("pre_uninstall hook failed", hookResult));
|
|
1986
2021
|
}
|
|
1987
2022
|
if (uninstallHooksSupported && manifest?.hooks.post_uninstall) {
|
|
1988
2023
|
this.log.info(`Running post_uninstall hook: ${manifest.hooks.post_uninstall}`);
|
|
@@ -1992,7 +2027,7 @@ var IntegrationManager = class {
|
|
|
1992
2027
|
secrets: this.secrets.get(name),
|
|
1993
2028
|
runtimes: [...this.runtimeAppliers.keys()]
|
|
1994
2029
|
}, INSTALL_HOOK_TIMEOUT_MS);
|
|
1995
|
-
if (hookResult.exitCode !== 0)
|
|
2030
|
+
if (hookResult.exitCode !== 0) throw new Error(this.hookFailureMessage("post_uninstall hook failed", hookResult));
|
|
1996
2031
|
}
|
|
1997
2032
|
if (this.installer.isInstalled(name)) {
|
|
1998
2033
|
await this.installer.remove(name);
|
|
@@ -2238,6 +2273,8 @@ var IntegrationManager = class {
|
|
|
2238
2273
|
version: entry.version,
|
|
2239
2274
|
status: entry.status,
|
|
2240
2275
|
installedAt: entry.installedAt,
|
|
2276
|
+
connectionAuthorityVersion: entry.connectionAuthorityVersion,
|
|
2277
|
+
connectionAuthorityPendingVersion: entry.connectionAuthorityPendingVersion,
|
|
2241
2278
|
config: entry.config,
|
|
2242
2279
|
error: entry.error
|
|
2243
2280
|
}));
|
|
@@ -2278,6 +2315,8 @@ var IntegrationManager = class {
|
|
|
2278
2315
|
version: entry.version,
|
|
2279
2316
|
status: entry.status,
|
|
2280
2317
|
installedAt: entry.installedAt,
|
|
2318
|
+
connectionAuthorityVersion: entry.connectionAuthorityVersion,
|
|
2319
|
+
connectionAuthorityPendingVersion: entry.connectionAuthorityPendingVersion,
|
|
2281
2320
|
config: entry.config,
|
|
2282
2321
|
error: entry.error
|
|
2283
2322
|
};
|
|
@@ -4771,7 +4810,10 @@ var McpApplier = class {
|
|
|
4771
4810
|
const id = `${integrationId}-${server.id}`;
|
|
4772
4811
|
const envResolved = await this.resolveEnv(server, mergedConfig, opts?.connectionId);
|
|
4773
4812
|
if (envResolved == null) {
|
|
4774
|
-
await this.manager.removeServer(id, {
|
|
4813
|
+
await this.manager.removeServer(id, {
|
|
4814
|
+
expectedOwner: owner,
|
|
4815
|
+
...opts?.strictReconcile ? { strictReconcile: true } : {}
|
|
4816
|
+
});
|
|
4775
4817
|
log.info({
|
|
4776
4818
|
integrationId,
|
|
4777
4819
|
server: server.id,
|
|
@@ -4779,13 +4821,20 @@ var McpApplier = class {
|
|
|
4779
4821
|
}, "Skipping MCP server registration — required credentials missing or fetch failed");
|
|
4780
4822
|
continue;
|
|
4781
4823
|
}
|
|
4782
|
-
await this.manager.addServer(toBundlerConfig(server,
|
|
4824
|
+
await this.manager.addServer(toBundlerConfig(server, {
|
|
4825
|
+
...envResolved,
|
|
4826
|
+
...opts?.connectionAuthorityVersion ? { ALFE_CONNECTION_AUTHORITY_VERSION: opts.connectionAuthorityVersion } : {}
|
|
4827
|
+
}), {
|
|
4783
4828
|
id,
|
|
4784
|
-
owner
|
|
4829
|
+
owner,
|
|
4830
|
+
...opts?.strictReconcile ? { strictReconcile: true } : {}
|
|
4785
4831
|
});
|
|
4786
4832
|
applied.push(id);
|
|
4787
4833
|
}
|
|
4788
|
-
for (const { id, entry } of this.manager.listServers()) if (entry.owner === owner && !declaredIds.has(id)) await this.manager.removeServer(id, {
|
|
4834
|
+
for (const { id, entry } of this.manager.listServers()) if (entry.owner === owner && !declaredIds.has(id)) await this.manager.removeServer(id, {
|
|
4835
|
+
expectedOwner: owner,
|
|
4836
|
+
...opts?.strictReconcile ? { strictReconcile: true } : {}
|
|
4837
|
+
});
|
|
4789
4838
|
for (const id of applied) this.manager.warmServer(id, MCP_ACTIVATION_WARM_TIMEOUT_MS).then((status) => {
|
|
4790
4839
|
if (!status) return;
|
|
4791
4840
|
if (status.connected) log.info({
|
|
@@ -4919,9 +4968,14 @@ var IntegrationManagerAdapter = class {
|
|
|
4919
4968
|
id: i.id,
|
|
4920
4969
|
version: i.version ?? "unknown",
|
|
4921
4970
|
status: i.status,
|
|
4922
|
-
installedAt: i.installedAt
|
|
4971
|
+
installedAt: i.installedAt,
|
|
4972
|
+
connectionAuthorityVersion: i.connectionAuthorityVersion,
|
|
4973
|
+
connectionAuthorityPendingVersion: i.connectionAuthorityPendingVersion
|
|
4923
4974
|
})));
|
|
4924
4975
|
}
|
|
4976
|
+
async refreshConnections(integrationId, connectionAuthorityVersion, opts) {
|
|
4977
|
+
await this.manager.refreshConnections(integrationId, connectionAuthorityVersion, opts);
|
|
4978
|
+
}
|
|
4925
4979
|
async install(integrationId, version, config, customSource) {
|
|
4926
4980
|
const result = await this.manager.install({
|
|
4927
4981
|
name: integrationId,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alfe.ai/integrations",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.5",
|
|
4
4
|
"description": "Integration lifecycle management for Alfe — registry, resolution, installation, and state",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@auriclabs/logger": "^0.1.1",
|
|
16
16
|
"yaml": ">=2.8.3",
|
|
17
|
-
"@alfe.ai/integration-manifest": "^0.4.
|
|
18
|
-
"@alfe.ai/mcp-bundler": "^0.4.
|
|
17
|
+
"@alfe.ai/integration-manifest": "^0.4.1",
|
|
18
|
+
"@alfe.ai/mcp-bundler": "^0.4.2"
|
|
19
19
|
},
|
|
20
20
|
"files": [
|
|
21
21
|
"dist"
|