@manifest-network/manifest-mcp-fred 0.6.0 → 0.6.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.
- package/dist/http/fred.d.ts +31 -1
- package/dist/http/fred.d.ts.map +1 -1
- package/dist/http/fred.js +37 -3
- package/dist/http/fred.js.map +1 -1
- package/dist/http/provider.d.ts +1 -1
- package/dist/http/provider.d.ts.map +1 -1
- package/dist/http/provider.js +33 -15
- package/dist/http/provider.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/tools/appStatus.d.ts +1 -1
- package/dist/tools/deployApp.d.ts +7 -0
- package/dist/tools/deployApp.d.ts.map +1 -1
- package/dist/tools/deployApp.js +12 -3
- package/dist/tools/deployApp.js.map +1 -1
- package/package.json +2 -2
package/dist/http/fred.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ProviderApiError } from "./provider.js";
|
|
1
2
|
import { LeaseState } from "@manifest-network/manifest-mcp-core";
|
|
2
3
|
|
|
3
4
|
//#region src/http/fred.d.ts
|
|
@@ -62,13 +63,42 @@ interface FredLeaseInfo {
|
|
|
62
63
|
readonly ports?: Record<string, unknown>;
|
|
63
64
|
}
|
|
64
65
|
declare function getLeaseInfo(providerUrl: string, leaseUuid: string, authToken: string, fetchFn?: typeof globalThis.fetch): Promise<FredLeaseInfo>;
|
|
66
|
+
type TerminalChainLeaseState = 'closed' | 'rejected' | 'expired';
|
|
67
|
+
interface TerminalChainState {
|
|
68
|
+
readonly state: TerminalChainLeaseState;
|
|
69
|
+
}
|
|
65
70
|
interface PollOptions {
|
|
66
71
|
readonly intervalMs?: number;
|
|
67
72
|
readonly timeoutMs?: number;
|
|
68
73
|
readonly abortSignal?: AbortSignal;
|
|
69
74
|
readonly onProgress?: (status: FredLeaseStatus) => void;
|
|
75
|
+
/** Runs once per iteration before the provider is queried. Non-null return throws; errors propagate. */
|
|
76
|
+
readonly checkChainState?: () => Promise<TerminalChainState | null>;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Thrown by pollLeaseUntilReady when the caller's checkChainState callback
|
|
80
|
+
* reports a terminal lease state on-chain. Extends ProviderApiError so
|
|
81
|
+
* existing catchers keep working; use `instanceof TerminalChainStateError`
|
|
82
|
+
* or read `chainState` to distinguish from provider-reported terminal states.
|
|
83
|
+
*/
|
|
84
|
+
interface TerminalChainStateContext {
|
|
85
|
+
readonly providerUuid?: string;
|
|
86
|
+
readonly providerUrl?: string;
|
|
87
|
+
}
|
|
88
|
+
declare class TerminalChainStateError extends ProviderApiError {
|
|
89
|
+
readonly chainState: TerminalChainLeaseState;
|
|
90
|
+
readonly leaseUuid: string;
|
|
91
|
+
readonly providerUuid?: string;
|
|
92
|
+
readonly providerUrl?: string;
|
|
93
|
+
constructor(leaseUuid: string, chainState: TerminalChainLeaseState, context?: TerminalChainStateContext);
|
|
94
|
+
/**
|
|
95
|
+
* Returns a new instance with the same lease/state and the supplied context,
|
|
96
|
+
* preserving the original stack trace so debugging points to where the
|
|
97
|
+
* terminal state was first detected.
|
|
98
|
+
*/
|
|
99
|
+
withContext(context: TerminalChainStateContext): TerminalChainStateError;
|
|
70
100
|
}
|
|
71
101
|
declare function pollLeaseUntilReady(providerUrl: string, leaseUuid: string, authToken: string | (() => Promise<string>), opts?: PollOptions, fetchFn?: typeof globalThis.fetch): Promise<FredLeaseStatus>;
|
|
72
102
|
//#endregion
|
|
73
|
-
export { FredActionResponse, FredInstanceInfo, FredLeaseInfo, FredLeaseLogs, FredLeaseProvision, FredLeaseRelease, FredLeaseReleases, FredLeaseStatus, FredServiceStatus, MAX_TAIL, PollOptions, getLeaseInfo, getLeaseLogs, getLeaseProvision, getLeaseReleases, getLeaseStatus, pollLeaseUntilReady, restartLease, updateLease };
|
|
103
|
+
export { FredActionResponse, FredInstanceInfo, FredLeaseInfo, FredLeaseLogs, FredLeaseProvision, FredLeaseRelease, FredLeaseReleases, FredLeaseStatus, FredServiceStatus, MAX_TAIL, PollOptions, TerminalChainLeaseState, TerminalChainState, TerminalChainStateContext, TerminalChainStateError, getLeaseInfo, getLeaseLogs, getLeaseProvision, getLeaseReleases, getLeaseStatus, pollLeaseUntilReady, restartLease, updateLease };
|
|
74
104
|
//# sourceMappingURL=fred.d.ts.map
|
package/dist/http/fred.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fred.d.ts","names":[],"sources":["../../src/http/fred.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"fred.d.ts","names":[],"sources":["../../src/http/fred.ts"],"mappings":";;;;cAaa,QAAA;AAAA,UAEI,gBAAA;EAAA,SACN,IAAA;EAAA,SACA,MAAA;EAAA,SACA,KAAA,GAAQ,MAAA;EAAA,SACR,IAAA;AAAA;AAAA,UAGM,iBAAA;EAAA,SACN,SAAA,WAAoB,gBAAA;AAAA;AAAA,UAGd,eAAA;EAAA,SACN,KAAA,EAAO,UAAA;EAAA,SACP,gBAAA;EAAA,SACA,KAAA;EAAA,SACA,KAAA,GAAQ,MAAA;EAAA,SACR,SAAA,YAAqB,gBAAA;EAAA,SACrB,SAAA,GAAY,MAAA;EAAA,SACZ,UAAA;EAAA,SACA,UAAA;EAAA,SACA,UAAA;EAAA,SACA,QAAA,GAAW,MAAA,SAAe,iBAAA;AAAA;AAAA,iBAQf,cAAA,CACpB,WAAA,UACA,SAAA,UACA,SAAA,UACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,eAAA;AAAA,UAsBM,aAAA;EAAA,SACN,UAAA;EAAA,SACA,MAAA;EAAA,SACA,aAAA;EAAA,SACA,IAAA,EAAM,MAAA;AAAA;AAAA,iBAGK,YAAA,CACpB,WAAA,UACA,SAAA,UACA,SAAA,UACA,IAAA,WACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,aAAA;AAAA,UAgBM,kBAAA;EAAA,SACN,MAAA;EAAA,SACA,UAAA;EAAA,SACA,UAAA;AAAA;AAAA,iBAGW,iBAAA,CACpB,WAAA,UACA,SAAA,UACA,SAAA,UACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,kBAAA;AAAA,UAcM,kBAAA;EAAA,SACN,MAAA;AAAA;AAAA,iBAGW,YAAA,CACpB,WAAA,UACA,SAAA,UACA,SAAA,UACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,kBAAA;AAAA,iBAeW,WAAA,CACpB,WAAA,UACA,SAAA,UACA,OAAA,EAAS,UAAA,EACT,SAAA,UACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,kBAAA;AAAA,UAqBM,gBAAA;EAAA,SACN,OAAA;EAAA,SACA,KAAA;EAAA,SACA,MAAA;EAAA,SACA,UAAA;EAAA,SACA,KAAA;EAAA,SACA,QAAA;AAAA;AAAA,UAGM,iBAAA;EAAA,SACN,UAAA;EAAA,SACA,MAAA;EAAA,SACA,aAAA;EAAA,SACA,QAAA,WAAmB,gBAAA;AAAA;AAAA,iBAGR,gBAAA,CACpB,WAAA,UACA,SAAA,UACA,SAAA,UACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,iBAAA;AAAA,UAcM,aAAA;EAAA,SACN,IAAA;EAAA,SACA,KAAA,GAAQ,MAAA;AAAA;AAAA,iBAGG,YAAA,CACpB,WAAA,UACA,SAAA,UACA,SAAA,UACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,aAAA;AAAA,KAcC,uBAAA;AAAA,UAEK,kBAAA;EAAA,SACN,KAAA,EAAO,uBAAA;AAAA;AAAA,UAGD,WAAA;EAAA,SACN,UAAA;EAAA,SACA,SAAA;EAAA,SACA,WAAA,GAAc,WAAA;EAAA,SACd,UAAA,IAAc,MAAA,EAAQ,eAAA;EA9KhB;EAAA,SAgLN,eAAA,SAAwB,OAAA,CAAQ,kBAAA;AAAA;;;;;;;UAoB1B,yBAAA;EAAA,SACN,YAAA;EAAA,SACA,WAAA;AAAA;AAAA,cAGE,uBAAA,SAAgC,gBAAA;EAAA,SAC3B,UAAA,EAAY,uBAAA;EAAA,SACZ,SAAA;EAAA,SACA,YAAA;EAAA,SACA,WAAA;cAGd,SAAA,UACA,UAAA,EAAY,uBAAA,EACZ,OAAA,GAAU,yBAAA;EA1MZ;;;;;EA8NA,WAAA,CAAY,OAAA,EAAS,yBAAA,GAA4B,uBAAA;AAAA;AAAA,iBA8B7B,mBAAA,CACpB,WAAA,UACA,SAAA,UACA,SAAA,kBAA2B,OAAA,WAC3B,IAAA,GAAM,WAAA,EACN,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,eAAA"}
|
package/dist/http/fred.js
CHANGED
|
@@ -51,9 +51,36 @@ async function getLeaseInfo(providerUrl, leaseUuid, authToken, fetchFn) {
|
|
|
51
51
|
const url = `${validateProviderUrl(providerUrl)}/v1/leases/${encodeURIComponent(leaseUuid)}/info`;
|
|
52
52
|
return await parseJsonResponse(await checkedFetch(url, { headers: { Authorization: `Bearer ${authToken}` } }, void 0, fetchFn), url);
|
|
53
53
|
}
|
|
54
|
+
const CHAIN_STATE_TO_LEASE_STATE = {
|
|
55
|
+
closed: LeaseState.LEASE_STATE_CLOSED,
|
|
56
|
+
rejected: LeaseState.LEASE_STATE_REJECTED,
|
|
57
|
+
expired: LeaseState.LEASE_STATE_EXPIRED
|
|
58
|
+
};
|
|
54
59
|
function leaseStateName(state) {
|
|
55
60
|
return LeaseState[state] ?? String(state);
|
|
56
61
|
}
|
|
62
|
+
var TerminalChainStateError = class TerminalChainStateError extends ProviderApiError {
|
|
63
|
+
constructor(leaseUuid, chainState, context) {
|
|
64
|
+
const mapped = CHAIN_STATE_TO_LEASE_STATE[chainState];
|
|
65
|
+
super(0, `Lease ${leaseUuid} entered terminal state ${leaseStateName(mapped)} on chain`);
|
|
66
|
+
this.name = "TerminalChainStateError";
|
|
67
|
+
this.chainState = chainState;
|
|
68
|
+
this.leaseUuid = leaseUuid;
|
|
69
|
+
this.providerUuid = context?.providerUuid;
|
|
70
|
+
this.providerUrl = context?.providerUrl;
|
|
71
|
+
Object.setPrototypeOf(this, TerminalChainStateError.prototype);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Returns a new instance with the same lease/state and the supplied context,
|
|
75
|
+
* preserving the original stack trace so debugging points to where the
|
|
76
|
+
* terminal state was first detected.
|
|
77
|
+
*/
|
|
78
|
+
withContext(context) {
|
|
79
|
+
const enriched = new TerminalChainStateError(this.leaseUuid, this.chainState, context);
|
|
80
|
+
if (this.stack) enriched.stack = this.stack;
|
|
81
|
+
return enriched;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
57
84
|
function abortableSleep(ms, signal) {
|
|
58
85
|
if (!signal) return new Promise((resolve) => setTimeout(resolve, ms));
|
|
59
86
|
signal.throwIfAborted();
|
|
@@ -70,12 +97,19 @@ function abortableSleep(ms, signal) {
|
|
|
70
97
|
});
|
|
71
98
|
}
|
|
72
99
|
async function pollLeaseUntilReady(providerUrl, leaseUuid, authToken, opts = {}, fetchFn) {
|
|
73
|
-
const { intervalMs = 3e3, timeoutMs = 12e4, abortSignal, onProgress } = opts;
|
|
100
|
+
const { intervalMs = 3e3, timeoutMs = 12e4, abortSignal, onProgress, checkChainState } = opts;
|
|
74
101
|
const deadline = Date.now() + timeoutMs;
|
|
75
102
|
let lastState;
|
|
76
103
|
while (Date.now() < deadline) {
|
|
77
104
|
abortSignal?.throwIfAborted();
|
|
78
|
-
|
|
105
|
+
if (checkChainState) {
|
|
106
|
+
const chainState = await checkChainState();
|
|
107
|
+
if (chainState) throw new TerminalChainStateError(leaseUuid, chainState.state);
|
|
108
|
+
abortSignal?.throwIfAborted();
|
|
109
|
+
}
|
|
110
|
+
const token = typeof authToken === "function" ? await authToken() : authToken;
|
|
111
|
+
abortSignal?.throwIfAborted();
|
|
112
|
+
const status = await getLeaseStatus(providerUrl, leaseUuid, token, fetchFn);
|
|
79
113
|
lastState = status.state;
|
|
80
114
|
onProgress?.(status);
|
|
81
115
|
switch (status.state) {
|
|
@@ -91,6 +125,6 @@ async function pollLeaseUntilReady(providerUrl, leaseUuid, authToken, opts = {},
|
|
|
91
125
|
throw new ProviderApiError(0, `Lease ${leaseUuid} poll timed out after ${timeoutMs}ms (last state: ${lastState !== void 0 ? leaseStateName(lastState) : "unknown"})`);
|
|
92
126
|
}
|
|
93
127
|
//#endregion
|
|
94
|
-
export { MAX_TAIL, getLeaseInfo, getLeaseLogs, getLeaseProvision, getLeaseReleases, getLeaseStatus, pollLeaseUntilReady, restartLease, updateLease };
|
|
128
|
+
export { MAX_TAIL, TerminalChainStateError, getLeaseInfo, getLeaseLogs, getLeaseProvision, getLeaseReleases, getLeaseStatus, pollLeaseUntilReady, restartLease, updateLease };
|
|
95
129
|
|
|
96
130
|
//# sourceMappingURL=fred.js.map
|
package/dist/http/fred.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fred.js","names":[],"sources":["../../src/http/fred.ts"],"sourcesContent":["import { toBase64 } from '@cosmjs/encoding';\nimport {\n LeaseState,\n leaseStateFromJSON,\n logger,\n} from '@manifest-network/manifest-mcp-core';\nimport {\n checkedFetch,\n ProviderApiError,\n parseJsonResponse,\n validateProviderUrl,\n} from './provider.js';\n\nexport const MAX_TAIL = 1000;\n\nexport interface FredInstanceInfo {\n readonly name: string;\n readonly status: string;\n readonly ports?: Record<string, number>;\n readonly fqdn?: string;\n}\n\nexport interface FredServiceStatus {\n readonly instances: readonly FredInstanceInfo[];\n}\n\nexport interface FredLeaseStatus {\n readonly state: LeaseState;\n readonly provision_status?: string;\n readonly phase?: string;\n readonly steps?: Record<string, string>;\n readonly instances?: readonly FredInstanceInfo[];\n readonly endpoints?: Record<string, string>;\n readonly last_error?: string;\n readonly fail_count?: number;\n readonly created_at?: string;\n readonly services?: Record<string, FredServiceStatus>;\n}\n\n/** Raw wire shape before LeaseState conversion */\ninterface RawLeaseStatus extends Omit<FredLeaseStatus, 'state'> {\n readonly state: string;\n}\n\nexport async function getLeaseStatus(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseStatus> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/status`;\n const res = await checkedFetch(\n url,\n {\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n const raw = await parseJsonResponse<RawLeaseStatus>(res, url);\n const state = leaseStateFromJSON(raw.state);\n if (state === LeaseState.UNRECOGNIZED) {\n logger.warn(\n `[getLeaseStatus] Unrecognized lease state \"${raw.state}\" for lease ${leaseUuid}. ` +\n 'The provider may be running a newer version than the client supports.',\n );\n }\n return { ...raw, state };\n}\n\nexport interface FredLeaseLogs {\n readonly lease_uuid: string;\n readonly tenant: string;\n readonly provider_uuid: string;\n readonly logs: Record<string, string>;\n}\n\nexport async function getLeaseLogs(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n tail?: number,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseLogs> {\n const validated = validateProviderUrl(providerUrl);\n const cappedTail = tail !== undefined ? Math.min(tail, MAX_TAIL) : undefined;\n const qs = cappedTail !== undefined ? `?tail=${cappedTail}` : '';\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/logs${qs}`;\n const res = await checkedFetch(\n url,\n {\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredLeaseLogs>(res, url);\n}\n\nexport interface FredLeaseProvision {\n readonly status: string;\n readonly fail_count: number;\n readonly last_error: string;\n}\n\nexport async function getLeaseProvision(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseProvision> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/provision`;\n const res = await checkedFetch(\n url,\n {\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredLeaseProvision>(res, url);\n}\n\nexport interface FredActionResponse {\n readonly status: string;\n}\n\nexport async function restartLease(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredActionResponse> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/restart`;\n const res = await checkedFetch(\n url,\n {\n method: 'POST',\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredActionResponse>(res, url);\n}\n\nexport async function updateLease(\n providerUrl: string,\n leaseUuid: string,\n payload: Uint8Array,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredActionResponse> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/update`;\n // The provider expects JSON with a base64-encoded payload (Go []byte field).\n const b64 = toBase64(payload);\n const res = await checkedFetch(\n url,\n {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${authToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ payload: b64 }),\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredActionResponse>(res, url);\n}\n\nexport interface FredLeaseRelease {\n readonly version: number;\n readonly image: string;\n readonly status: string;\n readonly created_at: string;\n readonly error?: string;\n readonly manifest?: string;\n}\n\nexport interface FredLeaseReleases {\n readonly lease_uuid: string;\n readonly tenant: string;\n readonly provider_uuid: string;\n readonly releases: readonly FredLeaseRelease[];\n}\n\nexport async function getLeaseReleases(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseReleases> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/releases`;\n const res = await checkedFetch(\n url,\n {\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredLeaseReleases>(res, url);\n}\n\nexport interface FredLeaseInfo {\n readonly host: string;\n readonly ports?: Record<string, unknown>;\n}\n\nexport async function getLeaseInfo(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseInfo> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/info`;\n const res = await checkedFetch(\n url,\n {\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredLeaseInfo>(res, url);\n}\n\nexport interface PollOptions {\n readonly intervalMs?: number;\n readonly timeoutMs?: number;\n readonly abortSignal?: AbortSignal;\n readonly onProgress?: (status: FredLeaseStatus) => void;\n}\n\nfunction leaseStateName(state: LeaseState): string {\n return LeaseState[state] ?? String(state);\n}\n\nfunction abortableSleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (!signal) return new Promise((resolve) => setTimeout(resolve, ms));\n signal.throwIfAborted();\n return new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n clearTimeout(timer);\n reject(\n signal.reason ??\n new DOMException('The operation was aborted', 'AbortError'),\n );\n };\n const timer = setTimeout(() => {\n signal.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n signal.addEventListener('abort', onAbort, { once: true });\n });\n}\n\nexport async function pollLeaseUntilReady(\n providerUrl: string,\n leaseUuid: string,\n authToken: string | (() => Promise<string>),\n opts: PollOptions = {},\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseStatus> {\n const {\n intervalMs = 3_000,\n timeoutMs = 120_000,\n abortSignal,\n onProgress,\n } = opts;\n const deadline = Date.now() + timeoutMs;\n let lastState: LeaseState | undefined;\n\n while (Date.now() < deadline) {\n abortSignal?.throwIfAborted();\n const token =\n typeof authToken === 'function' ? await authToken() : authToken;\n const status = await getLeaseStatus(providerUrl, leaseUuid, token, fetchFn);\n lastState = status.state;\n onProgress?.(status);\n switch (status.state) {\n case LeaseState.LEASE_STATE_ACTIVE:\n return status;\n case LeaseState.LEASE_STATE_PENDING:\n break;\n case LeaseState.LEASE_STATE_CLOSED:\n case LeaseState.LEASE_STATE_REJECTED:\n case LeaseState.LEASE_STATE_EXPIRED:\n throw new ProviderApiError(\n 0,\n `Lease ${leaseUuid} entered terminal state ${leaseStateName(status.state)}`,\n );\n default:\n throw new ProviderApiError(\n 0,\n `Lease ${leaseUuid} returned unexpected state ${leaseStateName(status.state)}`,\n );\n }\n await abortableSleep(intervalMs, abortSignal);\n }\n\n throw new ProviderApiError(\n 0,\n `Lease ${leaseUuid} poll timed out after ${timeoutMs}ms (last state: ${lastState !== undefined ? leaseStateName(lastState) : 'unknown'})`,\n );\n}\n"],"mappings":";;;;AAaA,MAAa,WAAW;AA+BxB,eAAsB,eACpB,aACA,WACA,WACA,SAC0B;CAE1B,MAAM,MAAM,GADM,oBAAoB,YAAY,CACzB,aAAa,mBAAmB,UAAU,CAAC;CASpE,MAAM,MAAM,MAAM,kBARN,MAAM,aAChB,KACA,EACE,SAAS,EAAE,eAAe,UAAU,aAAa,EAClD,EACD,KAAA,GACA,QACD,EACwD,IAAI;CAC7D,MAAM,QAAQ,mBAAmB,IAAI,MAAM;AAC3C,KAAI,UAAU,WAAW,aACvB,QAAO,KACL,8CAA8C,IAAI,MAAM,cAAc,UAAU,yEAEjF;AAEH,QAAO;EAAE,GAAG;EAAK;EAAO;;AAU1B,eAAsB,aACpB,aACA,WACA,WACA,MACA,SACwB;CACxB,MAAM,YAAY,oBAAoB,YAAY;CAClD,MAAM,aAAa,SAAS,KAAA,IAAY,KAAK,IAAI,MAAM,SAAS,GAAG,KAAA;CACnE,MAAM,KAAK,eAAe,KAAA,IAAY,SAAS,eAAe;CAC9D,MAAM,MAAM,GAAG,UAAU,aAAa,mBAAmB,UAAU,CAAC,OAAO;AAS3E,QAAO,MAAM,kBARD,MAAM,aAChB,KACA,EACE,SAAS,EAAE,eAAe,UAAU,aAAa,EAClD,EACD,KAAA,GACA,QACD,EACkD,IAAI;;AASzD,eAAsB,kBACpB,aACA,WACA,WACA,SAC6B;CAE7B,MAAM,MAAM,GADM,oBAAoB,YAAY,CACzB,aAAa,mBAAmB,UAAU,CAAC;AASpE,QAAO,MAAM,kBARD,MAAM,aAChB,KACA,EACE,SAAS,EAAE,eAAe,UAAU,aAAa,EAClD,EACD,KAAA,GACA,QACD,EACuD,IAAI;;AAO9D,eAAsB,aACpB,aACA,WACA,WACA,SAC6B;CAE7B,MAAM,MAAM,GADM,oBAAoB,YAAY,CACzB,aAAa,mBAAmB,UAAU,CAAC;AAUpE,QAAO,MAAM,kBATD,MAAM,aAChB,KACA;EACE,QAAQ;EACR,SAAS,EAAE,eAAe,UAAU,aAAa;EAClD,EACD,KAAA,GACA,QACD,EACuD,IAAI;;AAG9D,eAAsB,YACpB,aACA,WACA,SACA,WACA,SAC6B;CAE7B,MAAM,MAAM,GADM,oBAAoB,YAAY,CACzB,aAAa,mBAAmB,UAAU,CAAC;CAEpE,MAAM,MAAM,SAAS,QAAQ;AAc7B,QAAO,MAAM,kBAbD,MAAM,aAChB,KACA;EACE,QAAQ;EACR,SAAS;GACP,eAAe,UAAU;GACzB,gBAAgB;GACjB;EACD,MAAM,KAAK,UAAU,EAAE,SAAS,KAAK,CAAC;EACvC,EACD,KAAA,GACA,QACD,EACuD,IAAI;;AAmB9D,eAAsB,iBACpB,aACA,WACA,WACA,SAC4B;CAE5B,MAAM,MAAM,GADM,oBAAoB,YAAY,CACzB,aAAa,mBAAmB,UAAU,CAAC;AASpE,QAAO,MAAM,kBARD,MAAM,aAChB,KACA,EACE,SAAS,EAAE,eAAe,UAAU,aAAa,EAClD,EACD,KAAA,GACA,QACD,EACsD,IAAI;;AAQ7D,eAAsB,aACpB,aACA,WACA,WACA,SACwB;CAExB,MAAM,MAAM,GADM,oBAAoB,YAAY,CACzB,aAAa,mBAAmB,UAAU,CAAC;AASpE,QAAO,MAAM,kBARD,MAAM,aAChB,KACA,EACE,SAAS,EAAE,eAAe,UAAU,aAAa,EAClD,EACD,KAAA,GACA,QACD,EACkD,IAAI;;AAUzD,SAAS,eAAe,OAA2B;AACjD,QAAO,WAAW,UAAU,OAAO,MAAM;;AAG3C,SAAS,eAAe,IAAY,QAAqC;AACvE,KAAI,CAAC,OAAQ,QAAO,IAAI,SAAS,YAAY,WAAW,SAAS,GAAG,CAAC;AACrE,QAAO,gBAAgB;AACvB,QAAO,IAAI,SAAe,SAAS,WAAW;EAC5C,MAAM,gBAAgB;AACpB,gBAAa,MAAM;AACnB,UACE,OAAO,UACL,IAAI,aAAa,6BAA6B,aAAa,CAC9D;;EAEH,MAAM,QAAQ,iBAAiB;AAC7B,UAAO,oBAAoB,SAAS,QAAQ;AAC5C,YAAS;KACR,GAAG;AACN,SAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,MAAM,CAAC;GACzD;;AAGJ,eAAsB,oBACpB,aACA,WACA,WACA,OAAoB,EAAE,EACtB,SAC0B;CAC1B,MAAM,EACJ,aAAa,KACb,YAAY,MACZ,aACA,eACE;CACJ,MAAM,WAAW,KAAK,KAAK,GAAG;CAC9B,IAAI;AAEJ,QAAO,KAAK,KAAK,GAAG,UAAU;AAC5B,eAAa,gBAAgB;EAG7B,MAAM,SAAS,MAAM,eAAe,aAAa,WAD/C,OAAO,cAAc,aAAa,MAAM,WAAW,GAAG,WACW,QAAQ;AAC3E,cAAY,OAAO;AACnB,eAAa,OAAO;AACpB,UAAQ,OAAO,OAAf;GACE,KAAK,WAAW,mBACd,QAAO;GACT,KAAK,WAAW,oBACd;GACF,KAAK,WAAW;GAChB,KAAK,WAAW;GAChB,KAAK,WAAW,oBACd,OAAM,IAAI,iBACR,GACA,SAAS,UAAU,0BAA0B,eAAe,OAAO,MAAM,GAC1E;GACH,QACE,OAAM,IAAI,iBACR,GACA,SAAS,UAAU,6BAA6B,eAAe,OAAO,MAAM,GAC7E;;AAEL,QAAM,eAAe,YAAY,YAAY;;AAG/C,OAAM,IAAI,iBACR,GACA,SAAS,UAAU,wBAAwB,UAAU,kBAAkB,cAAc,KAAA,IAAY,eAAe,UAAU,GAAG,UAAU,GACxI"}
|
|
1
|
+
{"version":3,"file":"fred.js","names":[],"sources":["../../src/http/fred.ts"],"sourcesContent":["import { toBase64 } from '@cosmjs/encoding';\nimport {\n LeaseState,\n leaseStateFromJSON,\n logger,\n} from '@manifest-network/manifest-mcp-core';\nimport {\n checkedFetch,\n ProviderApiError,\n parseJsonResponse,\n validateProviderUrl,\n} from './provider.js';\n\nexport const MAX_TAIL = 1000;\n\nexport interface FredInstanceInfo {\n readonly name: string;\n readonly status: string;\n readonly ports?: Record<string, number>;\n readonly fqdn?: string;\n}\n\nexport interface FredServiceStatus {\n readonly instances: readonly FredInstanceInfo[];\n}\n\nexport interface FredLeaseStatus {\n readonly state: LeaseState;\n readonly provision_status?: string;\n readonly phase?: string;\n readonly steps?: Record<string, string>;\n readonly instances?: readonly FredInstanceInfo[];\n readonly endpoints?: Record<string, string>;\n readonly last_error?: string;\n readonly fail_count?: number;\n readonly created_at?: string;\n readonly services?: Record<string, FredServiceStatus>;\n}\n\n/** Raw wire shape before LeaseState conversion */\ninterface RawLeaseStatus extends Omit<FredLeaseStatus, 'state'> {\n readonly state: string;\n}\n\nexport async function getLeaseStatus(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseStatus> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/status`;\n const res = await checkedFetch(\n url,\n {\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n const raw = await parseJsonResponse<RawLeaseStatus>(res, url);\n const state = leaseStateFromJSON(raw.state);\n if (state === LeaseState.UNRECOGNIZED) {\n logger.warn(\n `[getLeaseStatus] Unrecognized lease state \"${raw.state}\" for lease ${leaseUuid}. ` +\n 'The provider may be running a newer version than the client supports.',\n );\n }\n return { ...raw, state };\n}\n\nexport interface FredLeaseLogs {\n readonly lease_uuid: string;\n readonly tenant: string;\n readonly provider_uuid: string;\n readonly logs: Record<string, string>;\n}\n\nexport async function getLeaseLogs(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n tail?: number,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseLogs> {\n const validated = validateProviderUrl(providerUrl);\n const cappedTail = tail !== undefined ? Math.min(tail, MAX_TAIL) : undefined;\n const qs = cappedTail !== undefined ? `?tail=${cappedTail}` : '';\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/logs${qs}`;\n const res = await checkedFetch(\n url,\n {\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredLeaseLogs>(res, url);\n}\n\nexport interface FredLeaseProvision {\n readonly status: string;\n readonly fail_count: number;\n readonly last_error: string;\n}\n\nexport async function getLeaseProvision(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseProvision> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/provision`;\n const res = await checkedFetch(\n url,\n {\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredLeaseProvision>(res, url);\n}\n\nexport interface FredActionResponse {\n readonly status: string;\n}\n\nexport async function restartLease(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredActionResponse> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/restart`;\n const res = await checkedFetch(\n url,\n {\n method: 'POST',\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredActionResponse>(res, url);\n}\n\nexport async function updateLease(\n providerUrl: string,\n leaseUuid: string,\n payload: Uint8Array,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredActionResponse> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/update`;\n // The provider expects JSON with a base64-encoded payload (Go []byte field).\n const b64 = toBase64(payload);\n const res = await checkedFetch(\n url,\n {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${authToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ payload: b64 }),\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredActionResponse>(res, url);\n}\n\nexport interface FredLeaseRelease {\n readonly version: number;\n readonly image: string;\n readonly status: string;\n readonly created_at: string;\n readonly error?: string;\n readonly manifest?: string;\n}\n\nexport interface FredLeaseReleases {\n readonly lease_uuid: string;\n readonly tenant: string;\n readonly provider_uuid: string;\n readonly releases: readonly FredLeaseRelease[];\n}\n\nexport async function getLeaseReleases(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseReleases> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/releases`;\n const res = await checkedFetch(\n url,\n {\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredLeaseReleases>(res, url);\n}\n\nexport interface FredLeaseInfo {\n readonly host: string;\n readonly ports?: Record<string, unknown>;\n}\n\nexport async function getLeaseInfo(\n providerUrl: string,\n leaseUuid: string,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseInfo> {\n const validated = validateProviderUrl(providerUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/info`;\n const res = await checkedFetch(\n url,\n {\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<FredLeaseInfo>(res, url);\n}\n\nexport type TerminalChainLeaseState = 'closed' | 'rejected' | 'expired';\n\nexport interface TerminalChainState {\n readonly state: TerminalChainLeaseState;\n}\n\nexport interface PollOptions {\n readonly intervalMs?: number;\n readonly timeoutMs?: number;\n readonly abortSignal?: AbortSignal;\n readonly onProgress?: (status: FredLeaseStatus) => void;\n /** Runs once per iteration before the provider is queried. Non-null return throws; errors propagate. */\n readonly checkChainState?: () => Promise<TerminalChainState | null>;\n}\n\nconst CHAIN_STATE_TO_LEASE_STATE: Record<TerminalChainLeaseState, LeaseState> =\n {\n closed: LeaseState.LEASE_STATE_CLOSED,\n rejected: LeaseState.LEASE_STATE_REJECTED,\n expired: LeaseState.LEASE_STATE_EXPIRED,\n };\n\nfunction leaseStateName(state: LeaseState): string {\n return LeaseState[state] ?? String(state);\n}\n\n/**\n * Thrown by pollLeaseUntilReady when the caller's checkChainState callback\n * reports a terminal lease state on-chain. Extends ProviderApiError so\n * existing catchers keep working; use `instanceof TerminalChainStateError`\n * or read `chainState` to distinguish from provider-reported terminal states.\n */\nexport interface TerminalChainStateContext {\n readonly providerUuid?: string;\n readonly providerUrl?: string;\n}\n\nexport class TerminalChainStateError extends ProviderApiError {\n public readonly chainState: TerminalChainLeaseState;\n public readonly leaseUuid: string;\n public readonly providerUuid?: string;\n public readonly providerUrl?: string;\n\n constructor(\n leaseUuid: string,\n chainState: TerminalChainLeaseState,\n context?: TerminalChainStateContext,\n ) {\n const mapped = CHAIN_STATE_TO_LEASE_STATE[chainState];\n super(\n 0,\n `Lease ${leaseUuid} entered terminal state ${leaseStateName(mapped)} on chain`,\n );\n this.name = 'TerminalChainStateError';\n this.chainState = chainState;\n this.leaseUuid = leaseUuid;\n this.providerUuid = context?.providerUuid;\n this.providerUrl = context?.providerUrl;\n Object.setPrototypeOf(this, TerminalChainStateError.prototype);\n }\n\n /**\n * Returns a new instance with the same lease/state and the supplied context,\n * preserving the original stack trace so debugging points to where the\n * terminal state was first detected.\n */\n withContext(context: TerminalChainStateContext): TerminalChainStateError {\n const enriched = new TerminalChainStateError(\n this.leaseUuid,\n this.chainState,\n context,\n );\n if (this.stack) enriched.stack = this.stack;\n return enriched;\n }\n}\n\nfunction abortableSleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (!signal) return new Promise((resolve) => setTimeout(resolve, ms));\n signal.throwIfAborted();\n return new Promise<void>((resolve, reject) => {\n const onAbort = () => {\n clearTimeout(timer);\n reject(\n signal.reason ??\n new DOMException('The operation was aborted', 'AbortError'),\n );\n };\n const timer = setTimeout(() => {\n signal.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n signal.addEventListener('abort', onAbort, { once: true });\n });\n}\n\nexport async function pollLeaseUntilReady(\n providerUrl: string,\n leaseUuid: string,\n authToken: string | (() => Promise<string>),\n opts: PollOptions = {},\n fetchFn?: typeof globalThis.fetch,\n): Promise<FredLeaseStatus> {\n const {\n intervalMs = 3_000,\n timeoutMs = 120_000,\n abortSignal,\n onProgress,\n checkChainState,\n } = opts;\n const deadline = Date.now() + timeoutMs;\n let lastState: LeaseState | undefined;\n\n while (Date.now() < deadline) {\n abortSignal?.throwIfAborted();\n if (checkChainState) {\n const chainState = await checkChainState();\n if (chainState) {\n throw new TerminalChainStateError(leaseUuid, chainState.state);\n }\n abortSignal?.throwIfAborted();\n }\n const token =\n typeof authToken === 'function' ? await authToken() : authToken;\n abortSignal?.throwIfAborted();\n const status = await getLeaseStatus(providerUrl, leaseUuid, token, fetchFn);\n lastState = status.state;\n onProgress?.(status);\n switch (status.state) {\n case LeaseState.LEASE_STATE_ACTIVE:\n return status;\n case LeaseState.LEASE_STATE_PENDING:\n break;\n case LeaseState.LEASE_STATE_CLOSED:\n case LeaseState.LEASE_STATE_REJECTED:\n case LeaseState.LEASE_STATE_EXPIRED:\n throw new ProviderApiError(\n 0,\n `Lease ${leaseUuid} entered terminal state ${leaseStateName(status.state)}`,\n );\n default:\n throw new ProviderApiError(\n 0,\n `Lease ${leaseUuid} returned unexpected state ${leaseStateName(status.state)}`,\n );\n }\n await abortableSleep(intervalMs, abortSignal);\n }\n\n throw new ProviderApiError(\n 0,\n `Lease ${leaseUuid} poll timed out after ${timeoutMs}ms (last state: ${lastState !== undefined ? leaseStateName(lastState) : 'unknown'})`,\n );\n}\n"],"mappings":"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"}
|
package/dist/http/provider.d.ts
CHANGED
|
@@ -46,7 +46,7 @@ interface LeaseConnectionResponse {
|
|
|
46
46
|
readonly connection: ConnectionDetails;
|
|
47
47
|
}
|
|
48
48
|
declare function getLeaseConnectionInfo(providerApiUrl: string, leaseUuid: string, authToken: string, fetchFn?: typeof globalThis.fetch): Promise<LeaseConnectionResponse>;
|
|
49
|
-
declare function uploadLeaseData(providerApiUrl: string, leaseUuid: string, payload: Uint8Array, authToken: string, fetchFn?: typeof globalThis.fetch): Promise<void>;
|
|
49
|
+
declare function uploadLeaseData(providerApiUrl: string, leaseUuid: string, payload: Uint8Array, authToken: string, fetchFn?: typeof globalThis.fetch, abortSignal?: AbortSignal): Promise<void>;
|
|
50
50
|
//#endregion
|
|
51
51
|
export { ConnectionDetails, InstanceInfo, LeaseConnectionResponse, ProviderApiError, ProviderHealthResponse, ServiceConnectionDetails, checkedFetch, getLeaseConnectionInfo, getProviderHealth, parseJsonResponse, uploadLeaseData, validateProviderUrl };
|
|
52
52
|
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","names":[],"sources":["../../src/http/provider.ts"],"mappings":";cAAa,gBAAA,SAAyB,KAAA;EAAA,SACpB,MAAA;cAEJ,MAAA,UAAgB,OAAA;AAAA;AAAA,iBAUd,mBAAA,CAAoB,GAAA;AAAA,iBAwBd,YAAA,CACpB,GAAA,UACA,IAAA,GAAO,WAAA,EACP,SAAA,WACA,OAAA,UAAgB,UAAA,CAAW,KAAA,GAC1B,OAAA,CAAQ,QAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"provider.d.ts","names":[],"sources":["../../src/http/provider.ts"],"mappings":";cAAa,gBAAA,SAAyB,KAAA;EAAA,SACpB,MAAA;cAEJ,MAAA,UAAgB,OAAA;AAAA;AAAA,iBAUd,mBAAA,CAAoB,GAAA;AAAA,iBAwBd,YAAA,CACpB,GAAA,UACA,IAAA,GAAO,WAAA,EACP,SAAA,WACA,OAAA,UAAgB,UAAA,CAAW,KAAA,GAC1B,OAAA,CAAQ,QAAA;AAAA,iBAyEW,iBAAA,GAAA,CACpB,GAAA,EAAK,QAAA,EACL,GAAA,WACC,OAAA,CAAQ,CAAA;AAAA,UAcM,sBAAA;EAAA,SACN,MAAA;EAAA,SACA,aAAA;EAAA,SACA,MAAA;IAAA,SACE,KAAA;MAAA,SAAmB,MAAA;IAAA;EAAA;AAAA;AAAA,iBAIV,iBAAA,CACpB,cAAA,UACA,SAAA,WACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,sBAAA;AAAA,UAOM,YAAA;EAAA,SACN,cAAA;EAAA,SACA,YAAA;EAAA,SACA,KAAA;EAAA,SACA,MAAA;EAAA,SACA,KAAA,GAAQ,MAAA;EAAA,SACR,IAAA;AAAA;AAAA,UAGM,wBAAA;EAAA,SACN,IAAA;EAAA,SACA,IAAA;EAAA,SACA,KAAA,GAAQ,MAAA;EAAA,SACR,SAAA,YAAqB,YAAA;AAAA;AAAA,UAGf,iBAAA;EAAA,SACN,IAAA;EAAA,SACA,IAAA;EAAA,SACA,KAAA,GAAQ,MAAA;EAAA,SACR,SAAA,YAAqB,YAAA;EAAA,SACrB,QAAA;EAAA,SACA,QAAA,GAAW,MAAA;EAAA,SACX,QAAA,GAAW,MAAA,SAAe,wBAAA;AAAA;AAAA,UAGpB,uBAAA;EAAA,SACN,UAAA;EAAA,SACA,MAAA;EAAA,SACA,aAAA;EAAA,SACA,UAAA,EAAY,iBAAA;AAAA;AAAA,iBAGD,sBAAA,CACpB,cAAA,UACA,SAAA,UACA,SAAA,UACA,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,uBAAA;AAAA,iBAcW,eAAA,CACpB,cAAA,UACA,SAAA,UACA,OAAA,EAAS,UAAA,EACT,SAAA,UACA,OAAA,UAAiB,UAAA,CAAW,KAAA,EAC5B,WAAA,GAAc,WAAA,GACb,OAAA"}
|
package/dist/http/provider.js
CHANGED
|
@@ -25,29 +25,44 @@ function validateProviderUrl(url) {
|
|
|
25
25
|
}
|
|
26
26
|
const DEFAULT_FETCH_TIMEOUT_MS = 3e4;
|
|
27
27
|
async function checkedFetch(url, init, timeoutMs = DEFAULT_FETCH_TIMEOUT_MS, fetchFn = globalThis.fetch) {
|
|
28
|
-
const
|
|
29
|
-
|
|
28
|
+
const callerSignal = init?.signal ?? void 0;
|
|
29
|
+
const composed = new AbortController();
|
|
30
30
|
let timer;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
let timedOut = false;
|
|
32
|
+
let callerAbortHandler;
|
|
33
|
+
if (callerSignal?.aborted) composed.abort(callerSignal.reason);
|
|
34
|
+
else if (callerSignal) {
|
|
35
|
+
callerAbortHandler = () => {
|
|
36
|
+
if (timer !== void 0) {
|
|
37
|
+
clearTimeout(timer);
|
|
38
|
+
timer = void 0;
|
|
39
|
+
}
|
|
40
|
+
composed.abort(callerSignal.reason);
|
|
38
41
|
};
|
|
42
|
+
callerSignal.addEventListener("abort", callerAbortHandler, { once: true });
|
|
39
43
|
}
|
|
44
|
+
if (timeoutMs > 0 && !composed.signal.aborted) timer = setTimeout(() => {
|
|
45
|
+
if (composed.signal.aborted) return;
|
|
46
|
+
timedOut = true;
|
|
47
|
+
composed.abort();
|
|
48
|
+
}, timeoutMs);
|
|
40
49
|
let res;
|
|
41
50
|
try {
|
|
42
|
-
|
|
51
|
+
composed.signal.throwIfAborted();
|
|
52
|
+
res = await fetchFn(url, {
|
|
53
|
+
...init,
|
|
54
|
+
signal: composed.signal
|
|
55
|
+
});
|
|
43
56
|
} catch (err) {
|
|
44
57
|
if (err instanceof DOMException && err.name === "AbortError") {
|
|
45
|
-
if (
|
|
46
|
-
throw
|
|
58
|
+
if (timedOut) throw new ProviderApiError(0, `Request to ${url} timed out after ${timeoutMs}ms`);
|
|
59
|
+
throw composed.signal.reason;
|
|
47
60
|
}
|
|
61
|
+
if (composed.signal.aborted && !timedOut) throw composed.signal.reason;
|
|
48
62
|
throw new ProviderApiError(0, `Network request to ${url} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
49
63
|
} finally {
|
|
50
64
|
if (timer !== void 0) clearTimeout(timer);
|
|
65
|
+
if (callerAbortHandler && callerSignal) callerSignal.removeEventListener("abort", callerAbortHandler);
|
|
51
66
|
}
|
|
52
67
|
if (!res.ok) {
|
|
53
68
|
const body = await res.text().catch((readErr) => `[body read failed: ${readErr instanceof Error ? readErr.message : String(readErr)}]`);
|
|
@@ -72,15 +87,18 @@ async function getLeaseConnectionInfo(providerApiUrl, leaseUuid, authToken, fetc
|
|
|
72
87
|
const url = `${validateProviderUrl(providerApiUrl)}/v1/leases/${encodeURIComponent(leaseUuid)}/connection`;
|
|
73
88
|
return await parseJsonResponse(await checkedFetch(url, { headers: { Authorization: `Bearer ${authToken}` } }, void 0, fetchFn), url);
|
|
74
89
|
}
|
|
75
|
-
async function uploadLeaseData(providerApiUrl, leaseUuid, payload, authToken, fetchFn) {
|
|
76
|
-
|
|
90
|
+
async function uploadLeaseData(providerApiUrl, leaseUuid, payload, authToken, fetchFn, abortSignal) {
|
|
91
|
+
const validated = validateProviderUrl(providerApiUrl);
|
|
92
|
+
const init = {
|
|
77
93
|
method: "POST",
|
|
78
94
|
headers: {
|
|
79
95
|
Authorization: `Bearer ${authToken}`,
|
|
80
96
|
"Content-Type": "application/octet-stream"
|
|
81
97
|
},
|
|
82
98
|
body: payload
|
|
83
|
-
}
|
|
99
|
+
};
|
|
100
|
+
if (abortSignal) init.signal = abortSignal;
|
|
101
|
+
await checkedFetch(`${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/data`, init, void 0, fetchFn);
|
|
84
102
|
}
|
|
85
103
|
//#endregion
|
|
86
104
|
export { ProviderApiError, checkedFetch, getLeaseConnectionInfo, getProviderHealth, parseJsonResponse, uploadLeaseData, validateProviderUrl };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.js","names":[],"sources":["../../src/http/provider.ts"],"sourcesContent":["export class ProviderApiError extends Error {\n public readonly status: number;\n\n constructor(status: number, message: string) {\n super(message);\n this.name = 'ProviderApiError';\n this.status = status;\n Object.setPrototypeOf(this, ProviderApiError.prototype);\n }\n}\n\nconst LOCALHOST_HOSTS = new Set(['localhost', '127.0.0.1', '[::1]']);\n\nexport function validateProviderUrl(url: string): string {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n throw new ProviderApiError(0, `Invalid provider URL: ${url}`);\n }\n\n if (parsed.protocol === 'https:') {\n return url.replace(/\\/+$/, '');\n }\n\n if (parsed.protocol === 'http:' && LOCALHOST_HOSTS.has(parsed.hostname)) {\n return url.replace(/\\/+$/, '');\n }\n\n throw new ProviderApiError(\n 0,\n `Provider URL must use HTTPS (or HTTP for localhost): ${url}`,\n );\n}\n\nconst DEFAULT_FETCH_TIMEOUT_MS = 30_000;\n\nexport async function checkedFetch(\n url: string,\n init?: RequestInit,\n timeoutMs: number = DEFAULT_FETCH_TIMEOUT_MS,\n fetchFn: typeof globalThis.fetch = globalThis.fetch,\n): Promise<Response> {\n const
|
|
1
|
+
{"version":3,"file":"provider.js","names":[],"sources":["../../src/http/provider.ts"],"sourcesContent":["export class ProviderApiError extends Error {\n public readonly status: number;\n\n constructor(status: number, message: string) {\n super(message);\n this.name = 'ProviderApiError';\n this.status = status;\n Object.setPrototypeOf(this, ProviderApiError.prototype);\n }\n}\n\nconst LOCALHOST_HOSTS = new Set(['localhost', '127.0.0.1', '[::1]']);\n\nexport function validateProviderUrl(url: string): string {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n throw new ProviderApiError(0, `Invalid provider URL: ${url}`);\n }\n\n if (parsed.protocol === 'https:') {\n return url.replace(/\\/+$/, '');\n }\n\n if (parsed.protocol === 'http:' && LOCALHOST_HOSTS.has(parsed.hostname)) {\n return url.replace(/\\/+$/, '');\n }\n\n throw new ProviderApiError(\n 0,\n `Provider URL must use HTTPS (or HTTP for localhost): ${url}`,\n );\n}\n\nconst DEFAULT_FETCH_TIMEOUT_MS = 30_000;\n\nexport async function checkedFetch(\n url: string,\n init?: RequestInit,\n timeoutMs: number = DEFAULT_FETCH_TIMEOUT_MS,\n fetchFn: typeof globalThis.fetch = globalThis.fetch,\n): Promise<Response> {\n const callerSignal = init?.signal ?? undefined;\n\n // Compose the caller's signal with an internal timeout so callers cannot\n // accidentally disable the safety net by supplying their own signal.\n const composed = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n let timedOut = false;\n let callerAbortHandler: (() => void) | undefined;\n\n if (callerSignal?.aborted) {\n composed.abort(callerSignal.reason);\n } else if (callerSignal) {\n callerAbortHandler = () => {\n // Clear the timer so a delayed fetch rejection can't be misclassified\n // as a timeout after the caller already cancelled.\n if (timer !== undefined) {\n clearTimeout(timer);\n timer = undefined;\n }\n composed.abort(callerSignal.reason);\n };\n callerSignal.addEventListener('abort', callerAbortHandler, { once: true });\n }\n if (timeoutMs > 0 && !composed.signal.aborted) {\n timer = setTimeout(() => {\n // Defensive: if the caller already aborted, don't flip timedOut.\n if (composed.signal.aborted) return;\n timedOut = true;\n composed.abort();\n }, timeoutMs);\n }\n\n let res: Response;\n try {\n // Don't even dispatch fetch if the caller's signal is already aborted.\n composed.signal.throwIfAborted();\n res = await fetchFn(url, { ...init, signal: composed.signal });\n } catch (err) {\n if (err instanceof DOMException && err.name === 'AbortError') {\n if (timedOut) {\n throw new ProviderApiError(\n 0,\n `Request to ${url} timed out after ${timeoutMs}ms`,\n );\n }\n // Surface the caller's original abort reason (e.g. `new Error('cancelled')`)\n // rather than the fetch-internal DOMException AbortError.\n throw composed.signal.reason;\n }\n if (composed.signal.aborted && !timedOut) throw composed.signal.reason;\n throw new ProviderApiError(\n 0,\n `Network request to ${url} failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n if (callerAbortHandler && callerSignal) {\n callerSignal.removeEventListener('abort', callerAbortHandler);\n }\n }\n if (!res.ok) {\n const body = await res\n .text()\n .catch(\n (readErr: unknown) =>\n `[body read failed: ${readErr instanceof Error ? readErr.message : String(readErr)}]`,\n );\n throw new ProviderApiError(res.status, body || `HTTP ${res.status}`);\n }\n return res;\n}\n\nexport async function parseJsonResponse<T>(\n res: Response,\n url: string,\n): Promise<T> {\n const text = await res.text();\n try {\n return JSON.parse(text) as T;\n } catch (parseErr) {\n const reason =\n parseErr instanceof Error ? parseErr.message : 'parse failed';\n throw new ProviderApiError(\n res.status,\n `Invalid JSON from ${url} (${reason}): ${text.slice(0, 200)}`,\n );\n }\n}\n\nexport interface ProviderHealthResponse {\n readonly status: string;\n readonly provider_uuid: string;\n readonly checks?: {\n readonly chain?: { readonly status: string };\n };\n}\n\nexport async function getProviderHealth(\n providerApiUrl: string,\n timeoutMs = 5_000,\n fetchFn?: typeof globalThis.fetch,\n): Promise<ProviderHealthResponse> {\n const validated = validateProviderUrl(providerApiUrl);\n const url = `${validated}/health`;\n const res = await checkedFetch(url, undefined, timeoutMs, fetchFn);\n return await parseJsonResponse<ProviderHealthResponse>(res, url);\n}\n\nexport interface InstanceInfo {\n readonly instance_index: number;\n readonly container_id: string;\n readonly image: string;\n readonly status: string;\n readonly ports?: Record<string, unknown>;\n readonly fqdn?: string;\n}\n\nexport interface ServiceConnectionDetails {\n readonly host?: string;\n readonly fqdn?: string;\n readonly ports?: Record<string, unknown>;\n readonly instances?: readonly InstanceInfo[];\n}\n\nexport interface ConnectionDetails {\n readonly host: string;\n readonly fqdn?: string;\n readonly ports?: Record<string, unknown>;\n readonly instances?: readonly InstanceInfo[];\n readonly protocol?: string;\n readonly metadata?: Record<string, string>;\n readonly services?: Record<string, ServiceConnectionDetails>;\n}\n\nexport interface LeaseConnectionResponse {\n readonly lease_uuid: string;\n readonly tenant: string;\n readonly provider_uuid: string;\n readonly connection: ConnectionDetails;\n}\n\nexport async function getLeaseConnectionInfo(\n providerApiUrl: string,\n leaseUuid: string,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n): Promise<LeaseConnectionResponse> {\n const validated = validateProviderUrl(providerApiUrl);\n const url = `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/connection`;\n const res = await checkedFetch(\n url,\n {\n headers: { Authorization: `Bearer ${authToken}` },\n },\n undefined,\n fetchFn,\n );\n return await parseJsonResponse<LeaseConnectionResponse>(res, url);\n}\n\nexport async function uploadLeaseData(\n providerApiUrl: string,\n leaseUuid: string,\n payload: Uint8Array,\n authToken: string,\n fetchFn?: typeof globalThis.fetch,\n abortSignal?: AbortSignal,\n): Promise<void> {\n const validated = validateProviderUrl(providerApiUrl);\n const init: RequestInit = {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${authToken}`,\n 'Content-Type': 'application/octet-stream',\n },\n body: payload,\n };\n if (abortSignal) {\n init.signal = abortSignal;\n }\n await checkedFetch(\n `${validated}/v1/leases/${encodeURIComponent(leaseUuid)}/data`,\n init,\n undefined,\n fetchFn,\n );\n}\n"],"mappings":";AAAA,IAAa,mBAAb,MAAa,yBAAyB,MAAM;CAG1C,YAAY,QAAgB,SAAiB;AAC3C,QAAM,QAAQ;AACd,OAAK,OAAO;AACZ,OAAK,SAAS;AACd,SAAO,eAAe,MAAM,iBAAiB,UAAU;;;AAI3D,MAAM,kBAAkB,IAAI,IAAI;CAAC;CAAa;CAAa;CAAQ,CAAC;AAEpE,SAAgB,oBAAoB,KAAqB;CACvD,IAAI;AACJ,KAAI;AACF,WAAS,IAAI,IAAI,IAAI;SACf;AACN,QAAM,IAAI,iBAAiB,GAAG,yBAAyB,MAAM;;AAG/D,KAAI,OAAO,aAAa,SACtB,QAAO,IAAI,QAAQ,QAAQ,GAAG;AAGhC,KAAI,OAAO,aAAa,WAAW,gBAAgB,IAAI,OAAO,SAAS,CACrE,QAAO,IAAI,QAAQ,QAAQ,GAAG;AAGhC,OAAM,IAAI,iBACR,GACA,wDAAwD,MACzD;;AAGH,MAAM,2BAA2B;AAEjC,eAAsB,aACpB,KACA,MACA,YAAoB,0BACpB,UAAmC,WAAW,OAC3B;CACnB,MAAM,eAAe,MAAM,UAAU,KAAA;CAIrC,MAAM,WAAW,IAAI,iBAAiB;CACtC,IAAI;CACJ,IAAI,WAAW;CACf,IAAI;AAEJ,KAAI,cAAc,QAChB,UAAS,MAAM,aAAa,OAAO;UAC1B,cAAc;AACvB,6BAA2B;AAGzB,OAAI,UAAU,KAAA,GAAW;AACvB,iBAAa,MAAM;AACnB,YAAQ,KAAA;;AAEV,YAAS,MAAM,aAAa,OAAO;;AAErC,eAAa,iBAAiB,SAAS,oBAAoB,EAAE,MAAM,MAAM,CAAC;;AAE5E,KAAI,YAAY,KAAK,CAAC,SAAS,OAAO,QACpC,SAAQ,iBAAiB;AAEvB,MAAI,SAAS,OAAO,QAAS;AAC7B,aAAW;AACX,WAAS,OAAO;IACf,UAAU;CAGf,IAAI;AACJ,KAAI;AAEF,WAAS,OAAO,gBAAgB;AAChC,QAAM,MAAM,QAAQ,KAAK;GAAE,GAAG;GAAM,QAAQ,SAAS;GAAQ,CAAC;UACvD,KAAK;AACZ,MAAI,eAAe,gBAAgB,IAAI,SAAS,cAAc;AAC5D,OAAI,SACF,OAAM,IAAI,iBACR,GACA,cAAc,IAAI,mBAAmB,UAAU,IAChD;AAIH,SAAM,SAAS,OAAO;;AAExB,MAAI,SAAS,OAAO,WAAW,CAAC,SAAU,OAAM,SAAS,OAAO;AAChE,QAAM,IAAI,iBACR,GACA,sBAAsB,IAAI,WAAW,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GACtF;WACO;AACR,MAAI,UAAU,KAAA,EAAW,cAAa,MAAM;AAC5C,MAAI,sBAAsB,aACxB,cAAa,oBAAoB,SAAS,mBAAmB;;AAGjE,KAAI,CAAC,IAAI,IAAI;EACX,MAAM,OAAO,MAAM,IAChB,MAAM,CACN,OACE,YACC,sBAAsB,mBAAmB,QAAQ,QAAQ,UAAU,OAAO,QAAQ,CAAC,GACtF;AACH,QAAM,IAAI,iBAAiB,IAAI,QAAQ,QAAQ,QAAQ,IAAI,SAAS;;AAEtE,QAAO;;AAGT,eAAsB,kBACpB,KACA,KACY;CACZ,MAAM,OAAO,MAAM,IAAI,MAAM;AAC7B,KAAI;AACF,SAAO,KAAK,MAAM,KAAK;UAChB,UAAU;EACjB,MAAM,SACJ,oBAAoB,QAAQ,SAAS,UAAU;AACjD,QAAM,IAAI,iBACR,IAAI,QACJ,qBAAqB,IAAI,IAAI,OAAO,KAAK,KAAK,MAAM,GAAG,IAAI,GAC5D;;;AAYL,eAAsB,kBACpB,gBACA,YAAY,KACZ,SACiC;CAEjC,MAAM,MAAM,GADM,oBAAoB,eAAe,CAC5B;AAEzB,QAAO,MAAM,kBADD,MAAM,aAAa,KAAK,KAAA,GAAW,WAAW,QAAQ,EACN,IAAI;;AAoClE,eAAsB,uBACpB,gBACA,WACA,WACA,SACkC;CAElC,MAAM,MAAM,GADM,oBAAoB,eAAe,CAC5B,aAAa,mBAAmB,UAAU,CAAC;AASpE,QAAO,MAAM,kBARD,MAAM,aAChB,KACA,EACE,SAAS,EAAE,eAAe,UAAU,aAAa,EAClD,EACD,KAAA,GACA,QACD,EAC4D,IAAI;;AAGnE,eAAsB,gBACpB,gBACA,WACA,SACA,WACA,SACA,aACe;CACf,MAAM,YAAY,oBAAoB,eAAe;CACrD,MAAM,OAAoB;EACxB,QAAQ;EACR,SAAS;GACP,eAAe,UAAU;GACzB,gBAAgB;GACjB;EACD,MAAM;EACP;AACD,KAAI,YACF,MAAK,SAAS;AAEhB,OAAM,aACJ,GAAG,UAAU,aAAa,mBAAmB,UAAU,CAAC,QACxD,MACA,KAAA,GACA,QACD"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AuthTokenPayload, createAuthToken, createLeaseDataSignMessage, createSignMessage } from "./http/auth.js";
|
|
2
|
-
import { FredActionResponse, FredInstanceInfo, FredLeaseInfo, FredLeaseLogs, FredLeaseProvision, FredLeaseRelease, FredLeaseReleases, FredLeaseStatus, FredServiceStatus, MAX_TAIL, PollOptions, getLeaseInfo, getLeaseLogs, getLeaseProvision, getLeaseReleases, getLeaseStatus, pollLeaseUntilReady, restartLease, updateLease } from "./http/fred.js";
|
|
3
2
|
import { ConnectionDetails, InstanceInfo, LeaseConnectionResponse, ProviderApiError, ProviderHealthResponse, ServiceConnectionDetails, checkedFetch, getLeaseConnectionInfo, getProviderHealth, uploadLeaseData, validateProviderUrl } from "./http/provider.js";
|
|
3
|
+
import { FredActionResponse, FredInstanceInfo, FredLeaseInfo, FredLeaseLogs, FredLeaseProvision, FredLeaseRelease, FredLeaseReleases, FredLeaseStatus, FredServiceStatus, MAX_TAIL, PollOptions, TerminalChainLeaseState, TerminalChainState, TerminalChainStateContext, TerminalChainStateError, getLeaseInfo, getLeaseLogs, getLeaseProvision, getLeaseReleases, getLeaseStatus, pollLeaseUntilReady, restartLease, updateLease } from "./http/fred.js";
|
|
4
4
|
import { BuildManifestOptions, buildManifest, buildStackManifest, deriveAppNameFromImage, getServiceNames, isStackManifest, mergeManifest, normalizePorts, parseStackManifest, validateServiceName } from "./manifest.js";
|
|
5
5
|
import { appStatus } from "./tools/appStatus.js";
|
|
6
6
|
import { browseCatalog, mapWithConcurrency } from "./tools/browseCatalog.js";
|
|
@@ -30,5 +30,5 @@ declare class FredMCPServer {
|
|
|
30
30
|
}
|
|
31
31
|
declare function createMnemonicFredServer(config: MnemonicServerConfig): Promise<FredMCPServer>;
|
|
32
32
|
//#endregion
|
|
33
|
-
export { type AuthTokenPayload, type BuildManifestOptions, type ConnectionDetails, type DeployAppInput, type DeployAppResult, type FredActionResponse, type FredInstanceInfo, type FredLeaseInfo, type FredLeaseLogs, type FredLeaseProvision, type FredLeaseRelease, type FredLeaseReleases, type FredLeaseStatus, FredMCPServer, type FredServiceStatus, INFRASTRUCTURE_ERROR_CODES, type InstanceInfo, type LeaseConnectionResponse, MAX_TAIL, ManifestMCPError, ManifestMCPErrorCode, type ManifestMCPServerOptions, type PollOptions, ProviderApiError, type ProviderHealthResponse, type ServiceConfig, type ServiceConnectionDetails, appStatus, browseCatalog, buildManifest, buildStackManifest, checkedFetch, createAuthToken, createLeaseDataSignMessage, createMnemonicFredServer, createSignMessage, deployApp, deriveAppNameFromImage, fetchActiveLease, getAppLogs, getLeaseConnectionInfo, getLeaseInfo, getLeaseLogs, getLeaseProvision, getLeaseReleases, getLeaseStatus, getProviderHealth, getServiceNames, isStackManifest, mapWithConcurrency, mergeManifest, normalizePorts, parseStackManifest, pollLeaseUntilReady, resolveProviderUrl, restartApp, restartLease, updateApp, updateLease, uploadLeaseData, validateProviderUrl, validateServiceName };
|
|
33
|
+
export { type AuthTokenPayload, type BuildManifestOptions, type ConnectionDetails, type DeployAppInput, type DeployAppResult, type FredActionResponse, type FredInstanceInfo, type FredLeaseInfo, type FredLeaseLogs, type FredLeaseProvision, type FredLeaseRelease, type FredLeaseReleases, type FredLeaseStatus, FredMCPServer, type FredServiceStatus, INFRASTRUCTURE_ERROR_CODES, type InstanceInfo, type LeaseConnectionResponse, MAX_TAIL, ManifestMCPError, ManifestMCPErrorCode, type ManifestMCPServerOptions, type PollOptions, ProviderApiError, type ProviderHealthResponse, type ServiceConfig, type ServiceConnectionDetails, type TerminalChainLeaseState, type TerminalChainState, type TerminalChainStateContext, TerminalChainStateError, appStatus, browseCatalog, buildManifest, buildStackManifest, checkedFetch, createAuthToken, createLeaseDataSignMessage, createMnemonicFredServer, createSignMessage, deployApp, deriveAppNameFromImage, fetchActiveLease, getAppLogs, getLeaseConnectionInfo, getLeaseInfo, getLeaseLogs, getLeaseProvision, getLeaseReleases, getLeaseStatus, getProviderHealth, getServiceNames, isStackManifest, mapWithConcurrency, mergeManifest, normalizePorts, parseStackManifest, pollLeaseUntilReady, resolveProviderUrl, restartApp, restartLease, updateApp, updateLease, uploadLeaseData, validateProviderUrl, validateServiceName };
|
|
34
34
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;;;;;;;cA6Ga,aAAA;EAAA,QACH,SAAA;EAAA,QACA,aAAA;EAAA,QACA,cAAA;cAEI,OAAA,EAAS,0BAAA;EAAA,QAuBb,oBAAA;EAAA,QAUA,cAAA;EAAA,QAEM,oBAAA;EAAA,QAiBA,qBAAA;EAAA,QAuBN,aAAA;EA6ZR,SAAA,CAAA,GAAa,MAAA;EAIb,gBAAA,CAAA,GAAoB,mBAAA;EAIpB,UAAA,CAAA;AAAA;AAAA,iBAKc,wBAAA,CACd,MAAA,EAAQ,oBAAA,GACP,OAAA,CAAQ,aAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AuthTimestampTracker, createAuthToken, createLeaseDataSignMessage, createSignMessage } from "./http/auth.js";
|
|
2
2
|
import { ProviderApiError, checkedFetch, getLeaseConnectionInfo, getProviderHealth, uploadLeaseData, validateProviderUrl } from "./http/provider.js";
|
|
3
|
-
import { MAX_TAIL, getLeaseInfo, getLeaseLogs, getLeaseProvision, getLeaseReleases, getLeaseStatus, pollLeaseUntilReady, restartLease, updateLease } from "./http/fred.js";
|
|
3
|
+
import { MAX_TAIL, TerminalChainStateError, getLeaseInfo, getLeaseLogs, getLeaseProvision, getLeaseReleases, getLeaseStatus, pollLeaseUntilReady, restartLease, updateLease } from "./http/fred.js";
|
|
4
4
|
import { resolveProviderUrl } from "./tools/resolveLeaseProvider.js";
|
|
5
5
|
import { appStatus } from "./tools/appStatus.js";
|
|
6
6
|
import { browseCatalog, mapWithConcurrency } from "./tools/browseCatalog.js";
|
|
@@ -209,6 +209,6 @@ function createMnemonicFredServer(config) {
|
|
|
209
209
|
return createMnemonicServer(config, FredMCPServer);
|
|
210
210
|
}
|
|
211
211
|
//#endregion
|
|
212
|
-
export { FredMCPServer, INFRASTRUCTURE_ERROR_CODES, MAX_TAIL, ManifestMCPError, ManifestMCPErrorCode, ProviderApiError, appStatus, browseCatalog, buildManifest, buildStackManifest, checkedFetch, createAuthToken, createLeaseDataSignMessage, createMnemonicFredServer, createSignMessage, deployApp, deriveAppNameFromImage, fetchActiveLease, getAppLogs, getLeaseConnectionInfo, getLeaseInfo, getLeaseLogs, getLeaseProvision, getLeaseReleases, getLeaseStatus, getProviderHealth, getServiceNames, isStackManifest, mapWithConcurrency, mergeManifest, normalizePorts, parseStackManifest, pollLeaseUntilReady, resolveProviderUrl, restartApp, restartLease, updateApp, updateLease, uploadLeaseData, validateProviderUrl, validateServiceName };
|
|
212
|
+
export { FredMCPServer, INFRASTRUCTURE_ERROR_CODES, MAX_TAIL, ManifestMCPError, ManifestMCPErrorCode, ProviderApiError, TerminalChainStateError, appStatus, browseCatalog, buildManifest, buildStackManifest, checkedFetch, createAuthToken, createLeaseDataSignMessage, createMnemonicFredServer, createSignMessage, deployApp, deriveAppNameFromImage, fetchActiveLease, getAppLogs, getLeaseConnectionInfo, getLeaseInfo, getLeaseLogs, getLeaseProvision, getLeaseReleases, getLeaseStatus, getProviderHealth, getServiceNames, isStackManifest, mapWithConcurrency, mergeManifest, normalizePorts, parseStackManifest, pollLeaseUntilReady, resolveProviderUrl, restartApp, restartLease, updateApp, updateLease, uploadLeaseData, validateProviderUrl, validateServiceName };
|
|
213
213
|
|
|
214
214
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["ManifestMCPError","ManifestMCPErrorCode"],"sources":["../src/index.ts"],"sourcesContent":["import type { WalletProvider } from '@manifest-network/manifest-mcp-core';\nimport {\n bigIntReplacer,\n CosmosClientManager,\n createMnemonicServer,\n createValidatedConfig,\n jsonResponse,\n ManifestMCPError,\n ManifestMCPErrorCode,\n type ManifestMCPServerOptions,\n type MnemonicServerConfig,\n VERSION,\n withErrorHandling,\n} from '@manifest-network/manifest-mcp-core';\nimport type { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport {\n AuthTimestampTracker,\n createAuthToken,\n createLeaseDataSignMessage,\n createSignMessage,\n} from './http/auth.js';\nimport { getLeaseProvision, getLeaseReleases, MAX_TAIL } from './http/fred.js';\nimport { appStatus } from './tools/appStatus.js';\nimport { browseCatalog } from './tools/browseCatalog.js';\nimport { deployApp } from './tools/deployApp.js';\nimport { fetchActiveLease } from './tools/fetchActiveLease.js';\nimport { getAppLogs } from './tools/getLogs.js';\nimport { resolveProviderUrl } from './tools/resolveLeaseProvider.js';\nimport { restartApp } from './tools/restartApp.js';\nimport { updateApp } from './tools/updateApp.js';\n\nexport type { ManifestMCPServerOptions } from '@manifest-network/manifest-mcp-core';\nexport {\n INFRASTRUCTURE_ERROR_CODES,\n ManifestMCPError,\n ManifestMCPErrorCode,\n} from '@manifest-network/manifest-mcp-core';\nexport {\n type AuthTokenPayload,\n createAuthToken,\n createLeaseDataSignMessage,\n createSignMessage,\n} from './http/auth.js';\nexport {\n type FredActionResponse,\n type FredInstanceInfo,\n type FredLeaseInfo,\n type FredLeaseLogs,\n type FredLeaseProvision,\n type FredLeaseRelease,\n type FredLeaseReleases,\n type FredLeaseStatus,\n type FredServiceStatus,\n getLeaseInfo,\n getLeaseLogs,\n getLeaseProvision,\n getLeaseReleases,\n getLeaseStatus,\n MAX_TAIL,\n type PollOptions,\n pollLeaseUntilReady,\n restartLease,\n updateLease,\n} from './http/fred.js';\nexport {\n type ConnectionDetails,\n checkedFetch,\n getLeaseConnectionInfo,\n getProviderHealth,\n type InstanceInfo,\n type LeaseConnectionResponse,\n ProviderApiError,\n type ProviderHealthResponse,\n type ServiceConnectionDetails,\n uploadLeaseData,\n validateProviderUrl,\n} from './http/provider.js';\nexport {\n type BuildManifestOptions,\n buildManifest,\n buildStackManifest,\n deriveAppNameFromImage,\n getServiceNames,\n isStackManifest,\n mergeManifest,\n normalizePorts,\n parseStackManifest,\n validateServiceName,\n} from './manifest.js';\nexport { appStatus } from './tools/appStatus.js';\nexport { browseCatalog, mapWithConcurrency } from './tools/browseCatalog.js';\nexport {\n type DeployAppInput,\n type DeployAppResult,\n deployApp,\n type ServiceConfig,\n} from './tools/deployApp.js';\nexport { fetchActiveLease } from './tools/fetchActiveLease.js';\nexport { getAppLogs } from './tools/getLogs.js';\nexport { resolveProviderUrl } from './tools/resolveLeaseProvider.js';\nexport { restartApp } from './tools/restartApp.js';\nexport { updateApp } from './tools/updateApp.js';\n\nexport class FredMCPServer {\n private mcpServer: McpServer;\n private clientManager: CosmosClientManager;\n private walletProvider: WalletProvider;\n\n constructor(options: ManifestMCPServerOptions) {\n const config = createValidatedConfig(options.config);\n this.walletProvider = options.walletProvider;\n this.clientManager = CosmosClientManager.getInstance(\n config,\n this.walletProvider,\n );\n\n this.mcpServer = new McpServer(\n {\n name: '@manifest-network/manifest-mcp-fred',\n version: VERSION,\n },\n {\n capabilities: {\n tools: {},\n },\n },\n );\n\n this.registerTools();\n }\n\n private requireSignArbitrary(): NonNullable<WalletProvider['signArbitrary']> {\n if (!this.walletProvider.signArbitrary) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'Wallet does not support signArbitrary (ADR-036). Required for provider authentication. Use a wallet provider that implements signArbitrary.',\n );\n }\n return this.walletProvider.signArbitrary.bind(this.walletProvider);\n }\n\n private authTimestamps = new AuthTimestampTracker();\n\n private async getProviderAuthToken(\n address: string,\n leaseUuid: string,\n ): Promise<string> {\n const signArbitrary = this.requireSignArbitrary();\n const timestamp = await this.authTimestamps.next();\n const message = createSignMessage(address, leaseUuid, timestamp);\n const { pub_key, signature } = await signArbitrary(address, message);\n return createAuthToken(\n address,\n leaseUuid,\n timestamp,\n pub_key.value,\n signature,\n );\n }\n\n private async getLeaseDataAuthToken(\n address: string,\n leaseUuid: string,\n metaHashHex: string,\n ): Promise<string> {\n const signArbitrary = this.requireSignArbitrary();\n const timestamp = await this.authTimestamps.next();\n const message = createLeaseDataSignMessage(\n leaseUuid,\n metaHashHex,\n timestamp,\n );\n const { pub_key, signature } = await signArbitrary(address, message);\n return createAuthToken(\n address,\n leaseUuid,\n timestamp,\n pub_key.value,\n signature,\n metaHashHex,\n );\n }\n\n private registerTools(): void {\n // -- browse_catalog --\n this.mcpServer.registerTool(\n 'browse_catalog',\n {\n description:\n 'Browse available cloud providers and service tiers with live health checks. Use this before deploy_app to see which providers are online and what SKU sizes (e.g. docker-micro, docker-small) are available with pricing.',\n },\n withErrorHandling('browse_catalog', async () => {\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await browseCatalog(queryClient);\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- app_status --\n this.mcpServer.registerTool(\n 'app_status',\n {\n description:\n 'Get detailed status and connection info for a deployed app. Use this after deploy_app to check if an app is running and get its URL.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to check'),\n },\n },\n withErrorHandling('app_status', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await appStatus(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- get_logs --\n this.mcpServer.registerTool(\n 'get_logs',\n {\n description:\n 'Get recent container logs for a deployed app. Use this to debug apps that are failing or to verify an app started correctly after deploy_app.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to get logs for'),\n tail: z\n .number()\n .int()\n .min(1)\n .max(MAX_TAIL)\n .optional()\n .describe('Number of recent log lines to retrieve'),\n },\n },\n withErrorHandling('get_logs', async (args) => {\n const leaseUuid = args.lease_uuid;\n const tail = args.tail;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await getAppLogs(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n tail,\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- deploy_app --\n this.mcpServer.registerTool(\n 'deploy_app',\n {\n description:\n 'Deploy a new containerized application. Requires funded credits (use fund_credit if needed). Creates a lease on-chain, uploads the container manifest to a provider, and polls until ready. Use browse_catalog first to see available SKU sizes.',\n inputSchema: {\n image: z\n .string()\n .optional()\n .describe(\n 'Docker image to deploy. Required unless services is provided.',\n ),\n port: z\n .number()\n .int()\n .min(1)\n .max(65535)\n .optional()\n .describe(\n 'Container port to expose. Required unless services is provided.',\n ),\n size: z\n .string()\n .describe('SKU tier name (e.g. \"docker-micro\", \"docker-small\")'),\n env: z\n .record(z.string(), z.string())\n .optional()\n .describe('Environment variables as key-value pairs'),\n command: z\n .array(z.string())\n .optional()\n .describe('Override container command (entrypoint)'),\n args: z\n .array(z.string())\n .optional()\n .describe('Arguments to the container command'),\n user: z\n .string()\n .optional()\n .describe('User to run the container as (e.g. \"1000:1000\")'),\n tmpfs: z\n .array(z.string())\n .optional()\n .describe('tmpfs mounts (e.g. [\"/tmp:size=64M\"])'),\n health_check: z\n .object({\n test: z.array(z.string()),\n interval: z.string().optional(),\n timeout: z.string().optional(),\n retries: z.number().int().optional(),\n start_period: z.string().optional(),\n })\n .optional()\n .describe('Container health check configuration'),\n stop_grace_period: z\n .string()\n .optional()\n .describe('Grace period before force-killing (e.g. \"30s\")'),\n init: z\n .boolean()\n .optional()\n .describe('Run an init process inside the container'),\n expose: z\n .array(z.string())\n .optional()\n .describe('Expose ports without publishing (e.g. [\"8080/tcp\"])'),\n labels: z\n .record(z.string(), z.string())\n .optional()\n .describe('Container labels as key-value pairs'),\n storage: z\n .string()\n .optional()\n .describe(\n 'Storage SKU name for persistent disk (adds a second lease item)',\n ),\n depends_on: z\n .record(z.string(), z.object({ condition: z.string() }))\n .optional()\n .describe('Service dependencies'),\n services: z\n .record(\n z.string(),\n z.object({\n image: z.string(),\n ports: z.record(z.string(), z.object({})).optional(),\n env: z.record(z.string(), z.string()).optional(),\n command: z.array(z.string()).optional(),\n args: z.array(z.string()).optional(),\n user: z.string().optional(),\n tmpfs: z.array(z.string()).optional(),\n health_check: z\n .object({\n test: z.array(z.string()),\n interval: z.string().optional(),\n timeout: z.string().optional(),\n retries: z.number().int().optional(),\n start_period: z.string().optional(),\n })\n .optional(),\n stop_grace_period: z.string().optional(),\n depends_on: z\n .record(z.string(), z.object({ condition: z.string() }))\n .optional(),\n expose: z.array(z.string()).optional(),\n labels: z.record(z.string(), z.string()).optional(),\n }),\n )\n .optional()\n .describe(\n 'Multi-service stack. Mutually exclusive with image/port. Keys are service names (RFC 1123 DNS labels).',\n ),\n gas_multiplier: z\n .number()\n .finite()\n .min(1)\n .optional()\n .describe(\n 'Gas simulation multiplier override for this transaction. Defaults to the server-configured value (typically 1.5). Increase if a transaction fails with out-of-gas errors.',\n ),\n },\n },\n withErrorHandling('deploy_app', async (args) => {\n const result = await deployApp(\n this.clientManager,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n (addr, uuid, metaHashHex) =>\n this.getLeaseDataAuthToken(addr, uuid, metaHashHex),\n {\n image: args.image,\n port: args.port,\n size: args.size,\n env: args.env,\n command: args.command,\n args: args.args,\n user: args.user,\n tmpfs: args.tmpfs,\n health_check: args.health_check,\n stop_grace_period: args.stop_grace_period,\n init: args.init,\n expose: args.expose,\n labels: args.labels,\n storage: args.storage,\n depends_on: args.depends_on,\n services: args.services,\n gasMultiplier: args.gas_multiplier,\n },\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- restart_app --\n this.mcpServer.registerTool(\n 'restart_app',\n {\n description:\n 'Restart a running app via the provider without closing its lease. Use this to apply configuration changes or recover from a crash.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to restart'),\n },\n },\n withErrorHandling('restart_app', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await restartApp(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- update_app --\n this.mcpServer.registerTool(\n 'update_app',\n {\n description:\n 'Update a deployed app with a new container manifest. Use this to change the Docker image, ports, or environment variables of a running app without closing the lease.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to update'),\n manifest: z\n .string()\n .describe('The full manifest JSON string to deploy'),\n existing_manifest: z\n .string()\n .optional()\n .describe(\n 'The current manifest JSON. When provided, the new manifest is merged over the existing one (env, ports, labels merged; other fields carried forward if not in new).',\n ),\n },\n },\n withErrorHandling('update_app', async (args) => {\n const manifest = args.manifest;\n\n try {\n const parsed = JSON.parse(manifest);\n if (\n parsed === null ||\n typeof parsed !== 'object' ||\n Array.isArray(parsed)\n ) {\n throw new Error('must be a JSON object');\n }\n } catch (err) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n `Invalid manifest: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n\n const result = await updateApp(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n manifest,\n args.existing_manifest,\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- app_diagnostics --\n this.mcpServer.registerTool(\n 'app_diagnostics',\n {\n description:\n 'Get provision diagnostics for a deployed app. Use this to debug apps stuck in provisioning or that failed to start. Returns provision status, failure count, and last error message.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to diagnose'),\n },\n },\n withErrorHandling('app_diagnostics', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n\n const lease = await fetchActiveLease(\n queryClient,\n leaseUuid,\n 'cannot be diagnosed',\n );\n const providerUrl = await resolveProviderUrl(\n queryClient,\n lease.providerUuid,\n );\n const authToken = await this.getProviderAuthToken(address, leaseUuid);\n const provision = await getLeaseProvision(\n providerUrl,\n leaseUuid,\n authToken,\n );\n\n return jsonResponse(\n {\n lease_uuid: leaseUuid,\n provision_status: provision.status,\n fail_count: provision.fail_count,\n last_error: provision.last_error,\n },\n bigIntReplacer,\n );\n }),\n );\n\n // -- app_releases --\n this.mcpServer.registerTool(\n 'app_releases',\n {\n description:\n 'Get release/version history for a deployed app. Use this to see what versions have been deployed, when they were created, and their status.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to get release history for'),\n },\n },\n withErrorHandling('app_releases', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n\n const lease = await fetchActiveLease(\n queryClient,\n leaseUuid,\n 'releases are not available',\n );\n const providerUrl = await resolveProviderUrl(\n queryClient,\n lease.providerUuid,\n );\n const authToken = await this.getProviderAuthToken(address, leaseUuid);\n const result = await getLeaseReleases(\n providerUrl,\n leaseUuid,\n authToken,\n );\n\n return jsonResponse(\n {\n lease_uuid: leaseUuid,\n releases: result.releases,\n },\n bigIntReplacer,\n );\n }),\n );\n }\n\n getServer(): Server {\n return this.mcpServer.server;\n }\n\n getClientManager(): CosmosClientManager {\n return this.clientManager;\n }\n\n disconnect(): void {\n this.clientManager.disconnect();\n }\n}\n\nexport function createMnemonicFredServer(\n config: MnemonicServerConfig,\n): Promise<FredMCPServer> {\n return createMnemonicServer(config, FredMCPServer);\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAyGA,IAAa,gBAAb,MAA2B;CAKzB,YAAY,SAAmC;AAiC/C,OAAQ,iBAAiB,IAAI,sBAAsB;EAhCjD,MAAM,SAAS,sBAAsB,QAAQ,OAAO;AACpD,OAAK,iBAAiB,QAAQ;AAC9B,OAAK,gBAAgB,oBAAoB,YACvC,QACA,KAAK,eACN;AAED,OAAK,YAAY,IAAI,UACnB;GACE,MAAM;GACN,SAAS;GACV,EACD,EACE,cAAc,EACZ,OAAO,EAAE,EACV,EACF,CACF;AAED,OAAK,eAAe;;CAGtB,uBAA6E;AAC3E,MAAI,CAAC,KAAK,eAAe,cACvB,OAAM,IAAIA,mBACRC,uBAAqB,gBACrB,8IACD;AAEH,SAAO,KAAK,eAAe,cAAc,KAAK,KAAK,eAAe;;CAKpE,MAAc,qBACZ,SACA,WACiB;EACjB,MAAM,gBAAgB,KAAK,sBAAsB;EACjD,MAAM,YAAY,MAAM,KAAK,eAAe,MAAM;EAElD,MAAM,EAAE,SAAS,cAAc,MAAM,cAAc,SADnC,kBAAkB,SAAS,WAAW,UAAU,CACI;AACpE,SAAO,gBACL,SACA,WACA,WACA,QAAQ,OACR,UACD;;CAGH,MAAc,sBACZ,SACA,WACA,aACiB;EACjB,MAAM,gBAAgB,KAAK,sBAAsB;EACjD,MAAM,YAAY,MAAM,KAAK,eAAe,MAAM;EAMlD,MAAM,EAAE,SAAS,cAAc,MAAM,cAAc,SALnC,2BACd,WACA,aACA,UACD,CACmE;AACpE,SAAO,gBACL,SACA,WACA,WACA,QAAQ,OACR,WACA,YACD;;CAGH,gBAA8B;AAE5B,OAAK,UAAU,aACb,kBACA,EACE,aACE,6NACH,EACD,kBAAkB,kBAAkB,YAAY;AAC9C,SAAM,KAAK,cAAc,kBAAkB;AAG3C,UAAO,aADQ,MAAM,cADD,MAAM,KAAK,cAAc,gBAAgB,CACd,EACnB,eAAe;IAC3C,CACH;AAGD,OAAK,UAAU,aACb,cACA;GACE,aACE;GACF,aAAa,EACX,YAAY,EACT,QAAQ,CACR,MAAM,CACN,SAAS,qCAAqC,EAClD;GACF,EACD,kBAAkB,cAAc,OAAO,SAAS;GAC9C,MAAM,YAAY,KAAK;GACvB,MAAM,UAAU,MAAM,KAAK,eAAe,YAAY;AACtD,SAAM,KAAK,cAAc,kBAAkB;AAQ3C,UAAO,aANQ,MAAM,UADD,MAAM,KAAK,cAAc,gBAAgB,EAG3D,SACA,YACC,MAAM,SAAS,KAAK,qBAAqB,MAAM,KAAK,CACtD,EAC2B,eAAe;IAC3C,CACH;AAGD,OAAK,UAAU,aACb,YACA;GACE,aACE;GACF,aAAa;IACX,YAAY,EACT,QAAQ,CACR,MAAM,CACN,SAAS,4CAA4C;IACxD,MAAM,EACH,QAAQ,CACR,KAAK,CACL,IAAI,EAAE,CACN,IAAI,SAAS,CACb,UAAU,CACV,SAAS,yCAAyC;IACtD;GACF,EACD,kBAAkB,YAAY,OAAO,SAAS;GAC5C,MAAM,YAAY,KAAK;GACvB,MAAM,OAAO,KAAK;GAClB,MAAM,UAAU,MAAM,KAAK,eAAe,YAAY;AACtD,SAAM,KAAK,cAAc,kBAAkB;AAS3C,UAAO,aAPQ,MAAM,WADD,MAAM,KAAK,cAAc,gBAAgB,EAG3D,SACA,YACC,MAAM,SAAS,KAAK,qBAAqB,MAAM,KAAK,EACrD,KACD,EAC2B,eAAe;IAC3C,CACH;AAGD,OAAK,UAAU,aACb,cACA;GACE,aACE;GACF,aAAa;IACX,OAAO,EACJ,QAAQ,CACR,UAAU,CACV,SACC,gEACD;IACH,MAAM,EACH,QAAQ,CACR,KAAK,CACL,IAAI,EAAE,CACN,IAAI,MAAM,CACV,UAAU,CACV,SACC,kEACD;IACH,MAAM,EACH,QAAQ,CACR,SAAS,0DAAsD;IAClE,KAAK,EACF,OAAO,EAAE,QAAQ,EAAE,EAAE,QAAQ,CAAC,CAC9B,UAAU,CACV,SAAS,2CAA2C;IACvD,SAAS,EACN,MAAM,EAAE,QAAQ,CAAC,CACjB,UAAU,CACV,SAAS,0CAA0C;IACtD,MAAM,EACH,MAAM,EAAE,QAAQ,CAAC,CACjB,UAAU,CACV,SAAS,qCAAqC;IACjD,MAAM,EACH,QAAQ,CACR,UAAU,CACV,SAAS,oDAAkD;IAC9D,OAAO,EACJ,MAAM,EAAE,QAAQ,CAAC,CACjB,UAAU,CACV,SAAS,0CAAwC;IACpD,cAAc,EACX,OAAO;KACN,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC;KACzB,UAAU,EAAE,QAAQ,CAAC,UAAU;KAC/B,SAAS,EAAE,QAAQ,CAAC,UAAU;KAC9B,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,UAAU;KACpC,cAAc,EAAE,QAAQ,CAAC,UAAU;KACpC,CAAC,CACD,UAAU,CACV,SAAS,uCAAuC;IACnD,mBAAmB,EAChB,QAAQ,CACR,UAAU,CACV,SAAS,mDAAiD;IAC7D,MAAM,EACH,SAAS,CACT,UAAU,CACV,SAAS,2CAA2C;IACvD,QAAQ,EACL,MAAM,EAAE,QAAQ,CAAC,CACjB,UAAU,CACV,SAAS,wDAAsD;IAClE,QAAQ,EACL,OAAO,EAAE,QAAQ,EAAE,EAAE,QAAQ,CAAC,CAC9B,UAAU,CACV,SAAS,sCAAsC;IAClD,SAAS,EACN,QAAQ,CACR,UAAU,CACV,SACC,kEACD;IACH,YAAY,EACT,OAAO,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC,CACvD,UAAU,CACV,SAAS,uBAAuB;IACnC,UAAU,EACP,OACC,EAAE,QAAQ,EACV,EAAE,OAAO;KACP,OAAO,EAAE,QAAQ;KACjB,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,UAAU;KACpD,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,QAAQ,CAAC,CAAC,UAAU;KAChD,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,UAAU;KACvC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,UAAU;KACpC,MAAM,EAAE,QAAQ,CAAC,UAAU;KAC3B,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,UAAU;KACrC,cAAc,EACX,OAAO;MACN,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC;MACzB,UAAU,EAAE,QAAQ,CAAC,UAAU;MAC/B,SAAS,EAAE,QAAQ,CAAC,UAAU;MAC9B,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,UAAU;MACpC,cAAc,EAAE,QAAQ,CAAC,UAAU;MACpC,CAAC,CACD,UAAU;KACb,mBAAmB,EAAE,QAAQ,CAAC,UAAU;KACxC,YAAY,EACT,OAAO,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC,CACvD,UAAU;KACb,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,UAAU;KACtC,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,QAAQ,CAAC,CAAC,UAAU;KACpD,CAAC,CACH,CACA,UAAU,CACV,SACC,yGACD;IACH,gBAAgB,EACb,QAAQ,CACR,QAAQ,CACR,IAAI,EAAE,CACN,UAAU,CACV,SACC,4KACD;IACJ;GACF,EACD,kBAAkB,cAAc,OAAO,SAAS;AA0B9C,UAAO,aAzBQ,MAAM,UACnB,KAAK,gBACJ,MAAM,SAAS,KAAK,qBAAqB,MAAM,KAAK,GACpD,MAAM,MAAM,gBACX,KAAK,sBAAsB,MAAM,MAAM,YAAY,EACrD;IACE,OAAO,KAAK;IACZ,MAAM,KAAK;IACX,MAAM,KAAK;IACX,KAAK,KAAK;IACV,SAAS,KAAK;IACd,MAAM,KAAK;IACX,MAAM,KAAK;IACX,OAAO,KAAK;IACZ,cAAc,KAAK;IACnB,mBAAmB,KAAK;IACxB,MAAM,KAAK;IACX,QAAQ,KAAK;IACb,QAAQ,KAAK;IACb,SAAS,KAAK;IACd,YAAY,KAAK;IACjB,UAAU,KAAK;IACf,eAAe,KAAK;IACrB,CACF,EAC2B,eAAe;IAC3C,CACH;AAGD,OAAK,UAAU,aACb,eACA;GACE,aACE;GACF,aAAa,EACX,YAAY,EACT,QAAQ,CACR,MAAM,CACN,SAAS,uCAAuC,EACpD;GACF,EACD,kBAAkB,eAAe,OAAO,SAAS;GAC/C,MAAM,YAAY,KAAK;GACvB,MAAM,UAAU,MAAM,KAAK,eAAe,YAAY;AACtD,SAAM,KAAK,cAAc,kBAAkB;AAQ3C,UAAO,aANQ,MAAM,WADD,MAAM,KAAK,cAAc,gBAAgB,EAG3D,SACA,YACC,MAAM,SAAS,KAAK,qBAAqB,MAAM,KAAK,CACtD,EAC2B,eAAe;IAC3C,CACH;AAGD,OAAK,UAAU,aACb,cACA;GACE,aACE;GACF,aAAa;IACX,YAAY,EACT,QAAQ,CACR,MAAM,CACN,SAAS,sCAAsC;IAClD,UAAU,EACP,QAAQ,CACR,SAAS,0CAA0C;IACtD,mBAAmB,EAChB,QAAQ,CACR,UAAU,CACV,SACC,sKACD;IACJ;GACF,EACD,kBAAkB,cAAc,OAAO,SAAS;GAC9C,MAAM,WAAW,KAAK;AAEtB,OAAI;IACF,MAAM,SAAS,KAAK,MAAM,SAAS;AACnC,QACE,WAAW,QACX,OAAO,WAAW,YAClB,MAAM,QAAQ,OAAO,CAErB,OAAM,IAAI,MAAM,wBAAwB;YAEnC,KAAK;AACZ,UAAM,IAAID,mBACRC,uBAAqB,gBACrB,qBAAqB,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,GACtE;;GAGH,MAAM,YAAY,KAAK;GACvB,MAAM,UAAU,MAAM,KAAK,eAAe,YAAY;AACtD,SAAM,KAAK,cAAc,kBAAkB;AAW3C,UAAO,aARQ,MAAM,UAFD,MAAM,KAAK,cAAc,gBAAgB,EAI3D,SACA,YACC,MAAM,SAAS,KAAK,qBAAqB,MAAM,KAAK,EACrD,UACA,KAAK,kBACN,EAC2B,eAAe;IAC3C,CACH;AAGD,OAAK,UAAU,aACb,mBACA;GACE,aACE;GACF,aAAa,EACX,YAAY,EACT,QAAQ,CACR,MAAM,CACN,SAAS,wCAAwC,EACrD;GACF,EACD,kBAAkB,mBAAmB,OAAO,SAAS;GACnD,MAAM,YAAY,KAAK;GACvB,MAAM,UAAU,MAAM,KAAK,eAAe,YAAY;AACtD,SAAM,KAAK,cAAc,kBAAkB;GAC3C,MAAM,cAAc,MAAM,KAAK,cAAc,gBAAgB;GAY7D,MAAM,YAAY,MAAM,kBALJ,MAAM,mBACxB,cANY,MAAM,iBAClB,aACA,WACA,sBACD,EAGO,aACP,EAIC,WAHgB,MAAM,KAAK,qBAAqB,SAAS,UAAU,CAKpE;AAED,UAAO,aACL;IACE,YAAY;IACZ,kBAAkB,UAAU;IAC5B,YAAY,UAAU;IACtB,YAAY,UAAU;IACvB,EACD,eACD;IACD,CACH;AAGD,OAAK,UAAU,aACb,gBACA;GACE,aACE;GACF,aAAa,EACX,YAAY,EACT,QAAQ,CACR,MAAM,CACN,SAAS,uDAAuD,EACpE;GACF,EACD,kBAAkB,gBAAgB,OAAO,SAAS;GAChD,MAAM,YAAY,KAAK;GACvB,MAAM,UAAU,MAAM,KAAK,eAAe,YAAY;AACtD,SAAM,KAAK,cAAc,kBAAkB;GAC3C,MAAM,cAAc,MAAM,KAAK,cAAc,gBAAgB;AAkB7D,UAAO,aACL;IACE,YAAY;IACZ,WATW,MAAM,iBALD,MAAM,mBACxB,cANY,MAAM,iBAClB,aACA,WACA,6BACD,EAGO,aACP,EAIC,WAHgB,MAAM,KAAK,qBAAqB,SAAS,UAAU,CAKpE,EAKoB;IAClB,EACD,eACD;IACD,CACH;;CAGH,YAAoB;AAClB,SAAO,KAAK,UAAU;;CAGxB,mBAAwC;AACtC,SAAO,KAAK;;CAGd,aAAmB;AACjB,OAAK,cAAc,YAAY;;;AAInC,SAAgB,yBACd,QACwB;AACxB,QAAO,qBAAqB,QAAQ,cAAc"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["ManifestMCPError","ManifestMCPErrorCode"],"sources":["../src/index.ts"],"sourcesContent":["import type { WalletProvider } from '@manifest-network/manifest-mcp-core';\nimport {\n bigIntReplacer,\n CosmosClientManager,\n createMnemonicServer,\n createValidatedConfig,\n jsonResponse,\n ManifestMCPError,\n ManifestMCPErrorCode,\n type ManifestMCPServerOptions,\n type MnemonicServerConfig,\n VERSION,\n withErrorHandling,\n} from '@manifest-network/manifest-mcp-core';\nimport type { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport {\n AuthTimestampTracker,\n createAuthToken,\n createLeaseDataSignMessage,\n createSignMessage,\n} from './http/auth.js';\nimport { getLeaseProvision, getLeaseReleases, MAX_TAIL } from './http/fred.js';\nimport { appStatus } from './tools/appStatus.js';\nimport { browseCatalog } from './tools/browseCatalog.js';\nimport { deployApp } from './tools/deployApp.js';\nimport { fetchActiveLease } from './tools/fetchActiveLease.js';\nimport { getAppLogs } from './tools/getLogs.js';\nimport { resolveProviderUrl } from './tools/resolveLeaseProvider.js';\nimport { restartApp } from './tools/restartApp.js';\nimport { updateApp } from './tools/updateApp.js';\n\nexport type { ManifestMCPServerOptions } from '@manifest-network/manifest-mcp-core';\nexport {\n INFRASTRUCTURE_ERROR_CODES,\n ManifestMCPError,\n ManifestMCPErrorCode,\n} from '@manifest-network/manifest-mcp-core';\nexport {\n type AuthTokenPayload,\n createAuthToken,\n createLeaseDataSignMessage,\n createSignMessage,\n} from './http/auth.js';\nexport {\n type FredActionResponse,\n type FredInstanceInfo,\n type FredLeaseInfo,\n type FredLeaseLogs,\n type FredLeaseProvision,\n type FredLeaseRelease,\n type FredLeaseReleases,\n type FredLeaseStatus,\n type FredServiceStatus,\n getLeaseInfo,\n getLeaseLogs,\n getLeaseProvision,\n getLeaseReleases,\n getLeaseStatus,\n MAX_TAIL,\n type PollOptions,\n pollLeaseUntilReady,\n restartLease,\n type TerminalChainLeaseState,\n type TerminalChainState,\n type TerminalChainStateContext,\n TerminalChainStateError,\n updateLease,\n} from './http/fred.js';\nexport {\n type ConnectionDetails,\n checkedFetch,\n getLeaseConnectionInfo,\n getProviderHealth,\n type InstanceInfo,\n type LeaseConnectionResponse,\n ProviderApiError,\n type ProviderHealthResponse,\n type ServiceConnectionDetails,\n uploadLeaseData,\n validateProviderUrl,\n} from './http/provider.js';\nexport {\n type BuildManifestOptions,\n buildManifest,\n buildStackManifest,\n deriveAppNameFromImage,\n getServiceNames,\n isStackManifest,\n mergeManifest,\n normalizePorts,\n parseStackManifest,\n validateServiceName,\n} from './manifest.js';\nexport { appStatus } from './tools/appStatus.js';\nexport { browseCatalog, mapWithConcurrency } from './tools/browseCatalog.js';\nexport {\n type DeployAppInput,\n type DeployAppResult,\n deployApp,\n type ServiceConfig,\n} from './tools/deployApp.js';\nexport { fetchActiveLease } from './tools/fetchActiveLease.js';\nexport { getAppLogs } from './tools/getLogs.js';\nexport { resolveProviderUrl } from './tools/resolveLeaseProvider.js';\nexport { restartApp } from './tools/restartApp.js';\nexport { updateApp } from './tools/updateApp.js';\n\nexport class FredMCPServer {\n private mcpServer: McpServer;\n private clientManager: CosmosClientManager;\n private walletProvider: WalletProvider;\n\n constructor(options: ManifestMCPServerOptions) {\n const config = createValidatedConfig(options.config);\n this.walletProvider = options.walletProvider;\n this.clientManager = CosmosClientManager.getInstance(\n config,\n this.walletProvider,\n );\n\n this.mcpServer = new McpServer(\n {\n name: '@manifest-network/manifest-mcp-fred',\n version: VERSION,\n },\n {\n capabilities: {\n tools: {},\n },\n },\n );\n\n this.registerTools();\n }\n\n private requireSignArbitrary(): NonNullable<WalletProvider['signArbitrary']> {\n if (!this.walletProvider.signArbitrary) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'Wallet does not support signArbitrary (ADR-036). Required for provider authentication. Use a wallet provider that implements signArbitrary.',\n );\n }\n return this.walletProvider.signArbitrary.bind(this.walletProvider);\n }\n\n private authTimestamps = new AuthTimestampTracker();\n\n private async getProviderAuthToken(\n address: string,\n leaseUuid: string,\n ): Promise<string> {\n const signArbitrary = this.requireSignArbitrary();\n const timestamp = await this.authTimestamps.next();\n const message = createSignMessage(address, leaseUuid, timestamp);\n const { pub_key, signature } = await signArbitrary(address, message);\n return createAuthToken(\n address,\n leaseUuid,\n timestamp,\n pub_key.value,\n signature,\n );\n }\n\n private async getLeaseDataAuthToken(\n address: string,\n leaseUuid: string,\n metaHashHex: string,\n ): Promise<string> {\n const signArbitrary = this.requireSignArbitrary();\n const timestamp = await this.authTimestamps.next();\n const message = createLeaseDataSignMessage(\n leaseUuid,\n metaHashHex,\n timestamp,\n );\n const { pub_key, signature } = await signArbitrary(address, message);\n return createAuthToken(\n address,\n leaseUuid,\n timestamp,\n pub_key.value,\n signature,\n metaHashHex,\n );\n }\n\n private registerTools(): void {\n // -- browse_catalog --\n this.mcpServer.registerTool(\n 'browse_catalog',\n {\n description:\n 'Browse available cloud providers and service tiers with live health checks. Use this before deploy_app to see which providers are online and what SKU sizes (e.g. docker-micro, docker-small) are available with pricing.',\n },\n withErrorHandling('browse_catalog', async () => {\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await browseCatalog(queryClient);\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- app_status --\n this.mcpServer.registerTool(\n 'app_status',\n {\n description:\n 'Get detailed status and connection info for a deployed app. Use this after deploy_app to check if an app is running and get its URL.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to check'),\n },\n },\n withErrorHandling('app_status', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await appStatus(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- get_logs --\n this.mcpServer.registerTool(\n 'get_logs',\n {\n description:\n 'Get recent container logs for a deployed app. Use this to debug apps that are failing or to verify an app started correctly after deploy_app.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to get logs for'),\n tail: z\n .number()\n .int()\n .min(1)\n .max(MAX_TAIL)\n .optional()\n .describe('Number of recent log lines to retrieve'),\n },\n },\n withErrorHandling('get_logs', async (args) => {\n const leaseUuid = args.lease_uuid;\n const tail = args.tail;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await getAppLogs(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n tail,\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- deploy_app --\n this.mcpServer.registerTool(\n 'deploy_app',\n {\n description:\n 'Deploy a new containerized application. Requires funded credits (use fund_credit if needed). Creates a lease on-chain, uploads the container manifest to a provider, and polls until ready. Use browse_catalog first to see available SKU sizes.',\n inputSchema: {\n image: z\n .string()\n .optional()\n .describe(\n 'Docker image to deploy. Required unless services is provided.',\n ),\n port: z\n .number()\n .int()\n .min(1)\n .max(65535)\n .optional()\n .describe(\n 'Container port to expose. Required unless services is provided.',\n ),\n size: z\n .string()\n .describe('SKU tier name (e.g. \"docker-micro\", \"docker-small\")'),\n env: z\n .record(z.string(), z.string())\n .optional()\n .describe('Environment variables as key-value pairs'),\n command: z\n .array(z.string())\n .optional()\n .describe('Override container command (entrypoint)'),\n args: z\n .array(z.string())\n .optional()\n .describe('Arguments to the container command'),\n user: z\n .string()\n .optional()\n .describe('User to run the container as (e.g. \"1000:1000\")'),\n tmpfs: z\n .array(z.string())\n .optional()\n .describe('tmpfs mounts (e.g. [\"/tmp:size=64M\"])'),\n health_check: z\n .object({\n test: z.array(z.string()),\n interval: z.string().optional(),\n timeout: z.string().optional(),\n retries: z.number().int().optional(),\n start_period: z.string().optional(),\n })\n .optional()\n .describe('Container health check configuration'),\n stop_grace_period: z\n .string()\n .optional()\n .describe('Grace period before force-killing (e.g. \"30s\")'),\n init: z\n .boolean()\n .optional()\n .describe('Run an init process inside the container'),\n expose: z\n .array(z.string())\n .optional()\n .describe('Expose ports without publishing (e.g. [\"8080/tcp\"])'),\n labels: z\n .record(z.string(), z.string())\n .optional()\n .describe('Container labels as key-value pairs'),\n storage: z\n .string()\n .optional()\n .describe(\n 'Storage SKU name for persistent disk (adds a second lease item)',\n ),\n depends_on: z\n .record(z.string(), z.object({ condition: z.string() }))\n .optional()\n .describe('Service dependencies'),\n services: z\n .record(\n z.string(),\n z.object({\n image: z.string(),\n ports: z.record(z.string(), z.object({})).optional(),\n env: z.record(z.string(), z.string()).optional(),\n command: z.array(z.string()).optional(),\n args: z.array(z.string()).optional(),\n user: z.string().optional(),\n tmpfs: z.array(z.string()).optional(),\n health_check: z\n .object({\n test: z.array(z.string()),\n interval: z.string().optional(),\n timeout: z.string().optional(),\n retries: z.number().int().optional(),\n start_period: z.string().optional(),\n })\n .optional(),\n stop_grace_period: z.string().optional(),\n depends_on: z\n .record(z.string(), z.object({ condition: z.string() }))\n .optional(),\n expose: z.array(z.string()).optional(),\n labels: z.record(z.string(), z.string()).optional(),\n }),\n )\n .optional()\n .describe(\n 'Multi-service stack. Mutually exclusive with image/port. Keys are service names (RFC 1123 DNS labels).',\n ),\n gas_multiplier: z\n .number()\n .finite()\n .min(1)\n .optional()\n .describe(\n 'Gas simulation multiplier override for this transaction. Defaults to the server-configured value (typically 1.5). Increase if a transaction fails with out-of-gas errors.',\n ),\n },\n },\n withErrorHandling('deploy_app', async (args) => {\n const result = await deployApp(\n this.clientManager,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n (addr, uuid, metaHashHex) =>\n this.getLeaseDataAuthToken(addr, uuid, metaHashHex),\n {\n image: args.image,\n port: args.port,\n size: args.size,\n env: args.env,\n command: args.command,\n args: args.args,\n user: args.user,\n tmpfs: args.tmpfs,\n health_check: args.health_check,\n stop_grace_period: args.stop_grace_period,\n init: args.init,\n expose: args.expose,\n labels: args.labels,\n storage: args.storage,\n depends_on: args.depends_on,\n services: args.services,\n gasMultiplier: args.gas_multiplier,\n },\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- restart_app --\n this.mcpServer.registerTool(\n 'restart_app',\n {\n description:\n 'Restart a running app via the provider without closing its lease. Use this to apply configuration changes or recover from a crash.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to restart'),\n },\n },\n withErrorHandling('restart_app', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n const result = await restartApp(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- update_app --\n this.mcpServer.registerTool(\n 'update_app',\n {\n description:\n 'Update a deployed app with a new container manifest. Use this to change the Docker image, ports, or environment variables of a running app without closing the lease.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to update'),\n manifest: z\n .string()\n .describe('The full manifest JSON string to deploy'),\n existing_manifest: z\n .string()\n .optional()\n .describe(\n 'The current manifest JSON. When provided, the new manifest is merged over the existing one (env, ports, labels merged; other fields carried forward if not in new).',\n ),\n },\n },\n withErrorHandling('update_app', async (args) => {\n const manifest = args.manifest;\n\n try {\n const parsed = JSON.parse(manifest);\n if (\n parsed === null ||\n typeof parsed !== 'object' ||\n Array.isArray(parsed)\n ) {\n throw new Error('must be a JSON object');\n }\n } catch (err) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n `Invalid manifest: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n\n const result = await updateApp(\n queryClient,\n address,\n leaseUuid,\n (addr, uuid) => this.getProviderAuthToken(addr, uuid),\n manifest,\n args.existing_manifest,\n );\n return jsonResponse(result, bigIntReplacer);\n }),\n );\n\n // -- app_diagnostics --\n this.mcpServer.registerTool(\n 'app_diagnostics',\n {\n description:\n 'Get provision diagnostics for a deployed app. Use this to debug apps stuck in provisioning or that failed to start. Returns provision status, failure count, and last error message.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to diagnose'),\n },\n },\n withErrorHandling('app_diagnostics', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n\n const lease = await fetchActiveLease(\n queryClient,\n leaseUuid,\n 'cannot be diagnosed',\n );\n const providerUrl = await resolveProviderUrl(\n queryClient,\n lease.providerUuid,\n );\n const authToken = await this.getProviderAuthToken(address, leaseUuid);\n const provision = await getLeaseProvision(\n providerUrl,\n leaseUuid,\n authToken,\n );\n\n return jsonResponse(\n {\n lease_uuid: leaseUuid,\n provision_status: provision.status,\n fail_count: provision.fail_count,\n last_error: provision.last_error,\n },\n bigIntReplacer,\n );\n }),\n );\n\n // -- app_releases --\n this.mcpServer.registerTool(\n 'app_releases',\n {\n description:\n 'Get release/version history for a deployed app. Use this to see what versions have been deployed, when they were created, and their status.',\n inputSchema: {\n lease_uuid: z\n .string()\n .uuid()\n .describe('The lease UUID of the app to get release history for'),\n },\n },\n withErrorHandling('app_releases', async (args) => {\n const leaseUuid = args.lease_uuid;\n const address = await this.walletProvider.getAddress();\n await this.clientManager.acquireRateLimit();\n const queryClient = await this.clientManager.getQueryClient();\n\n const lease = await fetchActiveLease(\n queryClient,\n leaseUuid,\n 'releases are not available',\n );\n const providerUrl = await resolveProviderUrl(\n queryClient,\n lease.providerUuid,\n );\n const authToken = await this.getProviderAuthToken(address, leaseUuid);\n const result = await getLeaseReleases(\n providerUrl,\n leaseUuid,\n authToken,\n );\n\n return jsonResponse(\n {\n lease_uuid: leaseUuid,\n releases: result.releases,\n },\n bigIntReplacer,\n );\n }),\n );\n }\n\n getServer(): Server {\n return this.mcpServer.server;\n }\n\n getClientManager(): CosmosClientManager {\n return this.clientManager;\n }\n\n disconnect(): void {\n this.clientManager.disconnect();\n }\n}\n\nexport function createMnemonicFredServer(\n config: MnemonicServerConfig,\n): Promise<FredMCPServer> {\n return createMnemonicServer(config, FredMCPServer);\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { FredLeaseStatus } from "../http/fred.js";
|
|
2
1
|
import { ConnectionDetails } from "../http/provider.js";
|
|
2
|
+
import { FredLeaseStatus } from "../http/fred.js";
|
|
3
3
|
import { LeaseState, ManifestQueryClient } from "@manifest-network/manifest-mcp-core";
|
|
4
4
|
|
|
5
5
|
//#region src/tools/appStatus.d.ts
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ConnectionDetails } from "../http/provider.js";
|
|
2
|
+
import { PollOptions } from "../http/fred.js";
|
|
2
3
|
import { CosmosClientManager, LeaseState } from "@manifest-network/manifest-mcp-core";
|
|
3
4
|
|
|
4
5
|
//#region src/tools/deployApp.d.ts
|
|
@@ -50,6 +51,12 @@ interface DeployAppInput {
|
|
|
50
51
|
}>;
|
|
51
52
|
services?: Record<string, ServiceConfig>;
|
|
52
53
|
gasMultiplier?: number;
|
|
54
|
+
/** Fires once after the create-lease TX confirms, before upload/poll. Awaited. Errors propagate. */
|
|
55
|
+
onLeaseCreated?: (leaseUuid: string, providerUrl: string) => void | Promise<void>;
|
|
56
|
+
/** Aborts upload and poll (not the already-submitted chain TX). */
|
|
57
|
+
abortSignal?: AbortSignal;
|
|
58
|
+
/** Forwarded to the internal pollLeaseUntilReady call. abortSignal is the top-level field above. */
|
|
59
|
+
pollOptions?: Omit<PollOptions, 'abortSignal'>;
|
|
53
60
|
}
|
|
54
61
|
interface DeployAppResult {
|
|
55
62
|
readonly lease_uuid: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deployApp.d.ts","names":[],"sources":["../../src/tools/deployApp.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"deployApp.d.ts","names":[],"sources":["../../src/tools/deployApp.ts"],"mappings":";;;;;UA6FiB,aAAA;EACf,KAAA;EACA,KAAA,GAAQ,MAAA,SAAe,MAAA;EACvB,GAAA,GAAM,MAAA;EACN,OAAA;EACA,IAAA;EACA,IAAA;EACA,KAAA;EACA,YAAA;IACE,IAAA;IACA,QAAA;IACA,OAAA;IACA,OAAA;IACA,YAAA;EAAA;EAEF,iBAAA;EACA,UAAA,GAAa,MAAA;IAAiB,SAAA;EAAA;EAC9B,MAAA;EACA,MAAA,GAAS,MAAA;AAAA;AAAA,UAGM,cAAA;EACf,KAAA;EACA,IAAA;EACA,IAAA;EACA,GAAA,GAAM,MAAA;EACN,OAAA;EACA,IAAA;EACA,IAAA;EACA,KAAA;EACA,YAAA;IACE,IAAA;IACA,QAAA;IACA,OAAA;IACA,OAAA;IACA,YAAA;EAAA;EAEF,iBAAA;EACA,IAAA;EACA,MAAA;EACA,MAAA,GAAS,MAAA;EACT,OAAA;EACA,UAAA,GAAa,MAAA;IAAiB,SAAA;EAAA;EAC9B,QAAA,GAAW,MAAA,SAAe,aAAA;EAC1B,aAAA;EASc;EAPd,cAAA,IACE,SAAA,UACA,WAAA,oBACU,OAAA;EAIM;EAFlB,WAAA,GAAc,WAAA;EA5Bd;EA8BA,WAAA,GAAc,IAAA,CAAK,WAAA;AAAA;AAAA,UAGJ,eAAA;EAAA,SACN,UAAA;EAAA,SACA,aAAA;EAAA,SACA,YAAA;EAAA,SACA,KAAA,EAAO,UAAA;EAAA,SACP,GAAA;EAAA,SACA,UAAA,GAAa,iBAAA;EAAA,SACb,eAAA;AAAA;AAAA,iBAGW,SAAA,CACpB,aAAA,EAAe,mBAAA,EACf,YAAA,GAAe,OAAA,UAAiB,SAAA,aAAsB,OAAA,UACtD,qBAAA,GACE,OAAA,UACA,SAAA,UACA,WAAA,aACG,OAAA,UACL,KAAA,EAAO,cAAA,EACP,OAAA,UAAiB,UAAA,CAAW,KAAA,GAC3B,OAAA,CAAQ,eAAA"}
|
package/dist/tools/deployApp.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getLeaseConnectionInfo, uploadLeaseData } from "../http/provider.js";
|
|
2
|
-
import { pollLeaseUntilReady } from "../http/fred.js";
|
|
2
|
+
import { TerminalChainStateError, pollLeaseUntilReady } from "../http/fred.js";
|
|
3
3
|
import { resolveProviderUrl } from "./resolveLeaseProvider.js";
|
|
4
4
|
import { buildManifest, buildStackManifest, validateServiceName } from "../manifest.js";
|
|
5
5
|
import { MAX_PAGE_LIMIT, ManifestMCPError, ManifestMCPErrorCode, cosmosTx, createPagination, logger, requireUuid, sanitizeForLogging } from "@manifest-network/manifest-mcp-core";
|
|
@@ -95,12 +95,21 @@ async function deployApp(clientManager, getAuthToken, getLeaseDataAuthToken, inp
|
|
|
95
95
|
metaHashHex,
|
|
96
96
|
...leaseItems
|
|
97
97
|
], true, overrides));
|
|
98
|
+
await input.onLeaseCreated?.(leaseUuid, providerUrl);
|
|
98
99
|
let status;
|
|
99
100
|
try {
|
|
101
|
+
input.abortSignal?.throwIfAborted();
|
|
100
102
|
const leaseDataToken = await getLeaseDataAuthToken(address, leaseUuid, metaHashHex);
|
|
101
|
-
await uploadLeaseData(providerUrl, leaseUuid, new TextEncoder().encode(manifestJson), leaseDataToken, fetchFn);
|
|
102
|
-
status = await pollLeaseUntilReady(providerUrl, leaseUuid, () => getAuthToken(address, leaseUuid),
|
|
103
|
+
await uploadLeaseData(providerUrl, leaseUuid, new TextEncoder().encode(manifestJson), leaseDataToken, fetchFn, input.abortSignal);
|
|
104
|
+
status = await pollLeaseUntilReady(providerUrl, leaseUuid, () => getAuthToken(address, leaseUuid), {
|
|
105
|
+
...input.pollOptions,
|
|
106
|
+
abortSignal: input.abortSignal
|
|
107
|
+
}, fetchFn);
|
|
103
108
|
} catch (err) {
|
|
109
|
+
if (err instanceof TerminalChainStateError) throw err.withContext({
|
|
110
|
+
providerUuid,
|
|
111
|
+
providerUrl
|
|
112
|
+
});
|
|
104
113
|
const code = err instanceof ManifestMCPError ? err.code : ManifestMCPErrorCode.QUERY_FAILED;
|
|
105
114
|
const details = err instanceof ManifestMCPError ? {
|
|
106
115
|
...err.details,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deployApp.js","names":[],"sources":["../../src/tools/deployApp.ts"],"sourcesContent":["import type {\n CosmosClientManager,\n CosmosTxResult,\n LeaseState,\n ManifestQueryClient,\n} from '@manifest-network/manifest-mcp-core';\nimport {\n cosmosTx,\n createPagination,\n logger,\n MAX_PAGE_LIMIT,\n ManifestMCPError,\n ManifestMCPErrorCode,\n requireUuid,\n sanitizeForLogging,\n} from '@manifest-network/manifest-mcp-core';\nimport type { FredLeaseStatus } from '../http/fred.js';\nimport { pollLeaseUntilReady } from '../http/fred.js';\nimport {\n type ConnectionDetails,\n getLeaseConnectionInfo,\n uploadLeaseData,\n} from '../http/provider.js';\nimport {\n type BuildManifestOptions,\n buildManifest,\n buildStackManifest,\n validateServiceName,\n} from '../manifest.js';\nimport { resolveProviderUrl } from './resolveLeaseProvider.js';\n\nasync function sha256(data: string): Promise<string> {\n const encoded = new TextEncoder().encode(data);\n const hashBuffer = await crypto.subtle.digest('SHA-256', encoded);\n const bytes = new Uint8Array(hashBuffer);\n return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n\nfunction extractLeaseUuid(txResult: CosmosTxResult): string {\n if (!txResult.events) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.TX_FAILED,\n 'No events in transaction result; cannot extract lease UUID',\n );\n }\n\n for (const event of txResult.events) {\n if (!event.type.includes('lease') && !event.type.includes('Lease'))\n continue;\n for (const attr of event.attributes) {\n if (attr.key === 'lease_uuid' || attr.key === 'uuid') {\n const raw = attr.value.replace(/^\"|\"$/g, '');\n // Validate the extracted value is a proper UUID\n requireUuid(\n { lease_uuid: raw },\n 'lease_uuid',\n ManifestMCPErrorCode.TX_FAILED,\n );\n return raw;\n }\n }\n }\n\n throw new ManifestMCPError(\n ManifestMCPErrorCode.TX_FAILED,\n 'Could not find lease UUID in transaction events',\n { events: txResult.events as unknown as Record<string, unknown>[] },\n );\n}\n\nasync function findSkuUuid(\n queryClient: ManifestQueryClient,\n size: string,\n): Promise<{ skuUuid: string; providerUuid: string }> {\n const pagination = createPagination(MAX_PAGE_LIMIT);\n const result = await queryClient.liftedinit.sku.v1.sKUs({\n activeOnly: true,\n pagination,\n });\n\n for (const sku of result.skus) {\n if (sku.name === size) {\n return { skuUuid: sku.uuid, providerUuid: sku.providerUuid };\n }\n }\n\n const available = result.skus.map((s) => s.name);\n throw new ManifestMCPError(\n ManifestMCPErrorCode.QUERY_FAILED,\n `SKU tier \"${size}\" not found. Available: ${available.join(', ')}`,\n );\n}\n\nexport interface ServiceConfig {\n image: string;\n ports?: Record<string, Record<string, never>>;\n env?: Record<string, string>;\n command?: string[];\n args?: string[];\n user?: string;\n tmpfs?: string[];\n health_check?: {\n test: string[];\n interval?: string;\n timeout?: string;\n retries?: number;\n start_period?: string;\n };\n stop_grace_period?: string;\n depends_on?: Record<string, { condition: string }>;\n expose?: string[];\n labels?: Record<string, string>;\n}\n\nexport interface DeployAppInput {\n image?: string;\n port?: number;\n size: string;\n env?: Record<string, string>;\n command?: string[];\n args?: string[];\n user?: string;\n tmpfs?: string[];\n health_check?: {\n test: string[];\n interval?: string;\n timeout?: string;\n retries?: number;\n start_period?: string;\n };\n stop_grace_period?: string;\n init?: boolean;\n expose?: string[];\n labels?: Record<string, string>;\n storage?: string;\n depends_on?: Record<string, { condition: string }>;\n services?: Record<string, ServiceConfig>;\n gasMultiplier?: number;\n}\n\nexport interface DeployAppResult {\n readonly lease_uuid: string;\n readonly provider_uuid: string;\n readonly provider_url: string;\n readonly state: LeaseState;\n readonly url?: string;\n readonly connection?: ConnectionDetails;\n readonly connectionError?: string;\n}\n\nexport async function deployApp(\n clientManager: CosmosClientManager,\n getAuthToken: (address: string, leaseUuid: string) => Promise<string>,\n getLeaseDataAuthToken: (\n address: string,\n leaseUuid: string,\n metaHashHex: string,\n ) => Promise<string>,\n input: DeployAppInput,\n fetchFn?: typeof globalThis.fetch,\n): Promise<DeployAppResult> {\n // Validate mutually exclusive inputs\n if (input.image && input.services) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'image and services are mutually exclusive',\n );\n }\n if (!input.image && !input.services) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'either image or services is required',\n );\n }\n if (input.image && !input.port) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'port is required when using image',\n );\n }\n\n const address = await clientManager.getAddress();\n await clientManager.acquireRateLimit();\n const queryClient = await clientManager.getQueryClient();\n\n // 1. Build manifest\n let manifestJson: string;\n if (input.services) {\n for (const name of Object.keys(input.services)) {\n if (!validateServiceName(name)) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n `Invalid service name: \"${name}\". Must be 1-63 chars, lowercase alphanumeric + hyphens, no leading/trailing hyphens.`,\n );\n }\n }\n\n const services: Record<string, BuildManifestOptions> = {};\n for (const [name, svc] of Object.entries(input.services)) {\n services[name] = {\n image: svc.image,\n ports: svc.ports ?? {},\n env: svc.env,\n command: svc.command,\n args: svc.args,\n user: svc.user,\n tmpfs: svc.tmpfs,\n health_check: svc.health_check,\n stop_grace_period: svc.stop_grace_period,\n depends_on: svc.depends_on,\n expose: svc.expose,\n labels: svc.labels,\n };\n }\n manifestJson = JSON.stringify(buildStackManifest({ services }));\n } else {\n // image is guaranteed defined here: the guard above ensures !image && !services is false,\n // and the if-branch handles the services case. TypeScript can't narrow across if/else.\n const image = input.image as string;\n manifestJson = JSON.stringify(\n buildManifest({\n image,\n ports: { [`${input.port}/tcp`]: {} },\n env: input.env,\n command: input.command,\n args: input.args,\n user: input.user,\n tmpfs: input.tmpfs,\n health_check: input.health_check,\n stop_grace_period: input.stop_grace_period,\n init: input.init,\n expose: input.expose,\n labels: input.labels,\n depends_on: input.depends_on,\n }),\n );\n }\n\n // 2. SHA-256 hash of manifest\n const metaHashHex = await sha256(manifestJson);\n\n // 3. Find matching SKU(s)\n const { skuUuid, providerUuid } = await findSkuUuid(queryClient, input.size);\n\n let leaseItems: string[];\n if (input.services) {\n const serviceNames = Object.keys(input.services);\n leaseItems = serviceNames.map((name) => `${skuUuid}:1:${name}`);\n } else {\n leaseItems = [`${skuUuid}:1`];\n }\n\n if (input.storage) {\n const { skuUuid: storageSkuUuid } = await findSkuUuid(\n queryClient,\n input.storage,\n );\n leaseItems.push(`${storageSkuUuid}:1`);\n }\n\n // 4. Get provider URL\n const providerUrl = await resolveProviderUrl(queryClient, providerUuid);\n\n // 5. Create lease\n const overrides =\n input.gasMultiplier !== undefined\n ? { gasMultiplier: input.gasMultiplier }\n : undefined;\n const txResult = await cosmosTx(\n clientManager,\n 'billing',\n 'create-lease',\n ['--meta-hash', metaHashHex, ...leaseItems],\n true,\n overrides,\n );\n\n // 6. Extract lease UUID\n const leaseUuid = extractLeaseUuid(txResult);\n\n let status: FredLeaseStatus;\n try {\n // 7. Upload manifest with lease-data auth token\n const leaseDataToken = await getLeaseDataAuthToken(\n address,\n leaseUuid,\n metaHashHex,\n );\n await uploadLeaseData(\n providerUrl,\n leaseUuid,\n new TextEncoder().encode(manifestJson),\n leaseDataToken,\n fetchFn,\n );\n\n // 8. Poll until ready\n status = await pollLeaseUntilReady(\n providerUrl,\n leaseUuid,\n () => getAuthToken(address, leaseUuid),\n undefined,\n fetchFn,\n );\n } catch (err) {\n const code =\n err instanceof ManifestMCPError\n ? err.code\n : ManifestMCPErrorCode.QUERY_FAILED;\n const details =\n err instanceof ManifestMCPError\n ? {\n ...err.details,\n lease_uuid: leaseUuid,\n provider_uuid: providerUuid,\n provider_url: providerUrl,\n }\n : {\n lease_uuid: leaseUuid,\n provider_uuid: providerUuid,\n provider_url: providerUrl,\n };\n throw new ManifestMCPError(\n code,\n `Deploy partially succeeded: lease ${leaseUuid} was created but subsequent steps failed. ` +\n `Close this lease with close_lease if needed. Error: ${err instanceof Error ? err.message : String(err)}`,\n details,\n );\n }\n\n // 9. Get connection info (best-effort)\n let connection: ConnectionDetails | undefined;\n let url: string | undefined;\n let connectionError: string | undefined;\n try {\n const authToken = await getAuthToken(address, leaseUuid);\n const connResp = await getLeaseConnectionInfo(\n providerUrl,\n leaseUuid,\n authToken,\n fetchFn,\n );\n connection = connResp.connection;\n if (connection.host && connection.ports) {\n const firstPort = Object.values(connection.ports)[0];\n if (typeof firstPort === 'number' || typeof firstPort === 'string') {\n url = `${connection.host}:${firstPort}`;\n }\n }\n } catch (err) {\n const rawMsg = err instanceof Error ? err.message : String(err);\n // Log raw message to stderr for debugging; sanitize only the user-facing return value\n logger.error(\n `[deploy_app] Failed to fetch connection info for lease ${leaseUuid}: ${rawMsg}`,\n );\n connectionError = sanitizeForLogging(rawMsg) as string;\n }\n\n return {\n lease_uuid: leaseUuid,\n provider_uuid: providerUuid,\n provider_url: providerUrl,\n state: status.state,\n ...(url && { url }),\n ...(connection && { connection }),\n ...(connectionError && { connectionError }),\n };\n}\n"],"mappings":";;;;;;AA+BA,eAAe,OAAO,MAA+B;CACnD,MAAM,UAAU,IAAI,aAAa,CAAC,OAAO,KAAK;CAC9C,MAAM,aAAa,MAAM,OAAO,OAAO,OAAO,WAAW,QAAQ;CACjE,MAAM,QAAQ,IAAI,WAAW,WAAW;AACxC,QAAO,MAAM,KAAK,QAAQ,MAAM,EAAE,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,KAAK,GAAG;;AAG3E,SAAS,iBAAiB,UAAkC;AAC1D,KAAI,CAAC,SAAS,OACZ,OAAM,IAAI,iBACR,qBAAqB,WACrB,6DACD;AAGH,MAAK,MAAM,SAAS,SAAS,QAAQ;AACnC,MAAI,CAAC,MAAM,KAAK,SAAS,QAAQ,IAAI,CAAC,MAAM,KAAK,SAAS,QAAQ,CAChE;AACF,OAAK,MAAM,QAAQ,MAAM,WACvB,KAAI,KAAK,QAAQ,gBAAgB,KAAK,QAAQ,QAAQ;GACpD,MAAM,MAAM,KAAK,MAAM,QAAQ,UAAU,GAAG;AAE5C,eACE,EAAE,YAAY,KAAK,EACnB,cACA,qBAAqB,UACtB;AACD,UAAO;;;AAKb,OAAM,IAAI,iBACR,qBAAqB,WACrB,mDACA,EAAE,QAAQ,SAAS,QAAgD,CACpE;;AAGH,eAAe,YACb,aACA,MACoD;CACpD,MAAM,aAAa,iBAAiB,eAAe;CACnD,MAAM,SAAS,MAAM,YAAY,WAAW,IAAI,GAAG,KAAK;EACtD,YAAY;EACZ;EACD,CAAC;AAEF,MAAK,MAAM,OAAO,OAAO,KACvB,KAAI,IAAI,SAAS,KACf,QAAO;EAAE,SAAS,IAAI;EAAM,cAAc,IAAI;EAAc;CAIhE,MAAM,YAAY,OAAO,KAAK,KAAK,MAAM,EAAE,KAAK;AAChD,OAAM,IAAI,iBACR,qBAAqB,cACrB,aAAa,KAAK,0BAA0B,UAAU,KAAK,KAAK,GACjE;;AA4DH,eAAsB,UACpB,eACA,cACA,uBAKA,OACA,SAC0B;AAE1B,KAAI,MAAM,SAAS,MAAM,SACvB,OAAM,IAAI,iBACR,qBAAqB,gBACrB,4CACD;AAEH,KAAI,CAAC,MAAM,SAAS,CAAC,MAAM,SACzB,OAAM,IAAI,iBACR,qBAAqB,gBACrB,uCACD;AAEH,KAAI,MAAM,SAAS,CAAC,MAAM,KACxB,OAAM,IAAI,iBACR,qBAAqB,gBACrB,oCACD;CAGH,MAAM,UAAU,MAAM,cAAc,YAAY;AAChD,OAAM,cAAc,kBAAkB;CACtC,MAAM,cAAc,MAAM,cAAc,gBAAgB;CAGxD,IAAI;AACJ,KAAI,MAAM,UAAU;AAClB,OAAK,MAAM,QAAQ,OAAO,KAAK,MAAM,SAAS,CAC5C,KAAI,CAAC,oBAAoB,KAAK,CAC5B,OAAM,IAAI,iBACR,qBAAqB,gBACrB,0BAA0B,KAAK,uFAChC;EAIL,MAAM,WAAiD,EAAE;AACzD,OAAK,MAAM,CAAC,MAAM,QAAQ,OAAO,QAAQ,MAAM,SAAS,CACtD,UAAS,QAAQ;GACf,OAAO,IAAI;GACX,OAAO,IAAI,SAAS,EAAE;GACtB,KAAK,IAAI;GACT,SAAS,IAAI;GACb,MAAM,IAAI;GACV,MAAM,IAAI;GACV,OAAO,IAAI;GACX,cAAc,IAAI;GAClB,mBAAmB,IAAI;GACvB,YAAY,IAAI;GAChB,QAAQ,IAAI;GACZ,QAAQ,IAAI;GACb;AAEH,iBAAe,KAAK,UAAU,mBAAmB,EAAE,UAAU,CAAC,CAAC;QAC1D;EAGL,MAAM,QAAQ,MAAM;AACpB,iBAAe,KAAK,UAClB,cAAc;GACZ;GACA,OAAO,GAAG,GAAG,MAAM,KAAK,QAAQ,EAAE,EAAE;GACpC,KAAK,MAAM;GACX,SAAS,MAAM;GACf,MAAM,MAAM;GACZ,MAAM,MAAM;GACZ,OAAO,MAAM;GACb,cAAc,MAAM;GACpB,mBAAmB,MAAM;GACzB,MAAM,MAAM;GACZ,QAAQ,MAAM;GACd,QAAQ,MAAM;GACd,YAAY,MAAM;GACnB,CAAC,CACH;;CAIH,MAAM,cAAc,MAAM,OAAO,aAAa;CAG9C,MAAM,EAAE,SAAS,iBAAiB,MAAM,YAAY,aAAa,MAAM,KAAK;CAE5E,IAAI;AACJ,KAAI,MAAM,SAER,cADqB,OAAO,KAAK,MAAM,SAAS,CACtB,KAAK,SAAS,GAAG,QAAQ,KAAK,OAAO;KAE/D,cAAa,CAAC,GAAG,QAAQ,IAAI;AAG/B,KAAI,MAAM,SAAS;EACjB,MAAM,EAAE,SAAS,mBAAmB,MAAM,YACxC,aACA,MAAM,QACP;AACD,aAAW,KAAK,GAAG,eAAe,IAAI;;CAIxC,MAAM,cAAc,MAAM,mBAAmB,aAAa,aAAa;CAGvE,MAAM,YACJ,MAAM,kBAAkB,KAAA,IACpB,EAAE,eAAe,MAAM,eAAe,GACtC,KAAA;CAWN,MAAM,YAAY,iBAVD,MAAM,SACrB,eACA,WACA,gBACA;EAAC;EAAe;EAAa,GAAG;EAAW,EAC3C,MACA,UACD,CAG2C;CAE5C,IAAI;AACJ,KAAI;EAEF,MAAM,iBAAiB,MAAM,sBAC3B,SACA,WACA,YACD;AACD,QAAM,gBACJ,aACA,WACA,IAAI,aAAa,CAAC,OAAO,aAAa,EACtC,gBACA,QACD;AAGD,WAAS,MAAM,oBACb,aACA,iBACM,aAAa,SAAS,UAAU,EACtC,KAAA,GACA,QACD;UACM,KAAK;EACZ,MAAM,OACJ,eAAe,mBACX,IAAI,OACJ,qBAAqB;EAC3B,MAAM,UACJ,eAAe,mBACX;GACE,GAAG,IAAI;GACP,YAAY;GACZ,eAAe;GACf,cAAc;GACf,GACD;GACE,YAAY;GACZ,eAAe;GACf,cAAc;GACf;AACP,QAAM,IAAI,iBACR,MACA,qCAAqC,UAAU,gGACU,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,IACzG,QACD;;CAIH,IAAI;CACJ,IAAI;CACJ,IAAI;AACJ,KAAI;AAQF,gBANiB,MAAM,uBACrB,aACA,WAHgB,MAAM,aAAa,SAAS,UAAU,EAKtD,QACD,EACqB;AACtB,MAAI,WAAW,QAAQ,WAAW,OAAO;GACvC,MAAM,YAAY,OAAO,OAAO,WAAW,MAAM,CAAC;AAClD,OAAI,OAAO,cAAc,YAAY,OAAO,cAAc,SACxD,OAAM,GAAG,WAAW,KAAK,GAAG;;UAGzB,KAAK;EACZ,MAAM,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAE/D,SAAO,MACL,0DAA0D,UAAU,IAAI,SACzE;AACD,oBAAkB,mBAAmB,OAAO;;AAG9C,QAAO;EACL,YAAY;EACZ,eAAe;EACf,cAAc;EACd,OAAO,OAAO;EACd,GAAI,OAAO,EAAE,KAAK;EAClB,GAAI,cAAc,EAAE,YAAY;EAChC,GAAI,mBAAmB,EAAE,iBAAiB;EAC3C"}
|
|
1
|
+
{"version":3,"file":"deployApp.js","names":[],"sources":["../../src/tools/deployApp.ts"],"sourcesContent":["import type {\n CosmosClientManager,\n CosmosTxResult,\n LeaseState,\n ManifestQueryClient,\n} from '@manifest-network/manifest-mcp-core';\nimport {\n cosmosTx,\n createPagination,\n logger,\n MAX_PAGE_LIMIT,\n ManifestMCPError,\n ManifestMCPErrorCode,\n requireUuid,\n sanitizeForLogging,\n} from '@manifest-network/manifest-mcp-core';\nimport type { FredLeaseStatus, PollOptions } from '../http/fred.js';\nimport { pollLeaseUntilReady, TerminalChainStateError } from '../http/fred.js';\nimport {\n type ConnectionDetails,\n getLeaseConnectionInfo,\n uploadLeaseData,\n} from '../http/provider.js';\nimport {\n type BuildManifestOptions,\n buildManifest,\n buildStackManifest,\n validateServiceName,\n} from '../manifest.js';\nimport { resolveProviderUrl } from './resolveLeaseProvider.js';\n\nasync function sha256(data: string): Promise<string> {\n const encoded = new TextEncoder().encode(data);\n const hashBuffer = await crypto.subtle.digest('SHA-256', encoded);\n const bytes = new Uint8Array(hashBuffer);\n return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n\nfunction extractLeaseUuid(txResult: CosmosTxResult): string {\n if (!txResult.events) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.TX_FAILED,\n 'No events in transaction result; cannot extract lease UUID',\n );\n }\n\n for (const event of txResult.events) {\n if (!event.type.includes('lease') && !event.type.includes('Lease'))\n continue;\n for (const attr of event.attributes) {\n if (attr.key === 'lease_uuid' || attr.key === 'uuid') {\n const raw = attr.value.replace(/^\"|\"$/g, '');\n // Validate the extracted value is a proper UUID\n requireUuid(\n { lease_uuid: raw },\n 'lease_uuid',\n ManifestMCPErrorCode.TX_FAILED,\n );\n return raw;\n }\n }\n }\n\n throw new ManifestMCPError(\n ManifestMCPErrorCode.TX_FAILED,\n 'Could not find lease UUID in transaction events',\n { events: txResult.events as unknown as Record<string, unknown>[] },\n );\n}\n\nasync function findSkuUuid(\n queryClient: ManifestQueryClient,\n size: string,\n): Promise<{ skuUuid: string; providerUuid: string }> {\n const pagination = createPagination(MAX_PAGE_LIMIT);\n const result = await queryClient.liftedinit.sku.v1.sKUs({\n activeOnly: true,\n pagination,\n });\n\n for (const sku of result.skus) {\n if (sku.name === size) {\n return { skuUuid: sku.uuid, providerUuid: sku.providerUuid };\n }\n }\n\n const available = result.skus.map((s) => s.name);\n throw new ManifestMCPError(\n ManifestMCPErrorCode.QUERY_FAILED,\n `SKU tier \"${size}\" not found. Available: ${available.join(', ')}`,\n );\n}\n\nexport interface ServiceConfig {\n image: string;\n ports?: Record<string, Record<string, never>>;\n env?: Record<string, string>;\n command?: string[];\n args?: string[];\n user?: string;\n tmpfs?: string[];\n health_check?: {\n test: string[];\n interval?: string;\n timeout?: string;\n retries?: number;\n start_period?: string;\n };\n stop_grace_period?: string;\n depends_on?: Record<string, { condition: string }>;\n expose?: string[];\n labels?: Record<string, string>;\n}\n\nexport interface DeployAppInput {\n image?: string;\n port?: number;\n size: string;\n env?: Record<string, string>;\n command?: string[];\n args?: string[];\n user?: string;\n tmpfs?: string[];\n health_check?: {\n test: string[];\n interval?: string;\n timeout?: string;\n retries?: number;\n start_period?: string;\n };\n stop_grace_period?: string;\n init?: boolean;\n expose?: string[];\n labels?: Record<string, string>;\n storage?: string;\n depends_on?: Record<string, { condition: string }>;\n services?: Record<string, ServiceConfig>;\n gasMultiplier?: number;\n /** Fires once after the create-lease TX confirms, before upload/poll. Awaited. Errors propagate. */\n onLeaseCreated?: (\n leaseUuid: string,\n providerUrl: string,\n ) => void | Promise<void>;\n /** Aborts upload and poll (not the already-submitted chain TX). */\n abortSignal?: AbortSignal;\n /** Forwarded to the internal pollLeaseUntilReady call. abortSignal is the top-level field above. */\n pollOptions?: Omit<PollOptions, 'abortSignal'>;\n}\n\nexport interface DeployAppResult {\n readonly lease_uuid: string;\n readonly provider_uuid: string;\n readonly provider_url: string;\n readonly state: LeaseState;\n readonly url?: string;\n readonly connection?: ConnectionDetails;\n readonly connectionError?: string;\n}\n\nexport async function deployApp(\n clientManager: CosmosClientManager,\n getAuthToken: (address: string, leaseUuid: string) => Promise<string>,\n getLeaseDataAuthToken: (\n address: string,\n leaseUuid: string,\n metaHashHex: string,\n ) => Promise<string>,\n input: DeployAppInput,\n fetchFn?: typeof globalThis.fetch,\n): Promise<DeployAppResult> {\n // Validate mutually exclusive inputs\n if (input.image && input.services) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'image and services are mutually exclusive',\n );\n }\n if (!input.image && !input.services) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'either image or services is required',\n );\n }\n if (input.image && !input.port) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'port is required when using image',\n );\n }\n\n const address = await clientManager.getAddress();\n await clientManager.acquireRateLimit();\n const queryClient = await clientManager.getQueryClient();\n\n // 1. Build manifest\n let manifestJson: string;\n if (input.services) {\n for (const name of Object.keys(input.services)) {\n if (!validateServiceName(name)) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n `Invalid service name: \"${name}\". Must be 1-63 chars, lowercase alphanumeric + hyphens, no leading/trailing hyphens.`,\n );\n }\n }\n\n const services: Record<string, BuildManifestOptions> = {};\n for (const [name, svc] of Object.entries(input.services)) {\n services[name] = {\n image: svc.image,\n ports: svc.ports ?? {},\n env: svc.env,\n command: svc.command,\n args: svc.args,\n user: svc.user,\n tmpfs: svc.tmpfs,\n health_check: svc.health_check,\n stop_grace_period: svc.stop_grace_period,\n depends_on: svc.depends_on,\n expose: svc.expose,\n labels: svc.labels,\n };\n }\n manifestJson = JSON.stringify(buildStackManifest({ services }));\n } else {\n // image is guaranteed defined here: the guard above ensures !image && !services is false,\n // and the if-branch handles the services case. TypeScript can't narrow across if/else.\n const image = input.image as string;\n manifestJson = JSON.stringify(\n buildManifest({\n image,\n ports: { [`${input.port}/tcp`]: {} },\n env: input.env,\n command: input.command,\n args: input.args,\n user: input.user,\n tmpfs: input.tmpfs,\n health_check: input.health_check,\n stop_grace_period: input.stop_grace_period,\n init: input.init,\n expose: input.expose,\n labels: input.labels,\n depends_on: input.depends_on,\n }),\n );\n }\n\n // 2. SHA-256 hash of manifest\n const metaHashHex = await sha256(manifestJson);\n\n // 3. Find matching SKU(s)\n const { skuUuid, providerUuid } = await findSkuUuid(queryClient, input.size);\n\n let leaseItems: string[];\n if (input.services) {\n const serviceNames = Object.keys(input.services);\n leaseItems = serviceNames.map((name) => `${skuUuid}:1:${name}`);\n } else {\n leaseItems = [`${skuUuid}:1`];\n }\n\n if (input.storage) {\n const { skuUuid: storageSkuUuid } = await findSkuUuid(\n queryClient,\n input.storage,\n );\n leaseItems.push(`${storageSkuUuid}:1`);\n }\n\n // 4. Get provider URL\n const providerUrl = await resolveProviderUrl(queryClient, providerUuid);\n\n // 5. Create lease\n const overrides =\n input.gasMultiplier !== undefined\n ? { gasMultiplier: input.gasMultiplier }\n : undefined;\n const txResult = await cosmosTx(\n clientManager,\n 'billing',\n 'create-lease',\n ['--meta-hash', metaHashHex, ...leaseItems],\n true,\n overrides,\n );\n\n // 6. Extract lease UUID\n const leaseUuid = extractLeaseUuid(txResult);\n\n // Outside the partial-success try: callback errors surface raw, not wrapped.\n // The lease exists on-chain regardless of abortSignal state — always notify.\n await input.onLeaseCreated?.(leaseUuid, providerUrl);\n\n let status: FredLeaseStatus;\n try {\n input.abortSignal?.throwIfAborted();\n\n // 7. Upload manifest with lease-data auth token\n const leaseDataToken = await getLeaseDataAuthToken(\n address,\n leaseUuid,\n metaHashHex,\n );\n await uploadLeaseData(\n providerUrl,\n leaseUuid,\n new TextEncoder().encode(manifestJson),\n leaseDataToken,\n fetchFn,\n input.abortSignal,\n );\n\n // 8. Poll until ready\n status = await pollLeaseUntilReady(\n providerUrl,\n leaseUuid,\n () => getAuthToken(address, leaseUuid),\n { ...input.pollOptions, abortSignal: input.abortSignal },\n fetchFn,\n );\n } catch (err) {\n // Chain-terminal states are self-explanatory and need no \"close this lease\"\n // advice (the lease is already terminal on-chain). Let Barney & friends\n // observe the typed error directly via `instanceof` / `err.chainState`.\n // withContext preserves the original stack (debugging points at the poll,\n // not at this catch) while attaching deployApp's provider context so\n // callers don't need to re-query the chain to recover it.\n if (err instanceof TerminalChainStateError) {\n throw err.withContext({ providerUuid, providerUrl });\n }\n const code =\n err instanceof ManifestMCPError\n ? err.code\n : ManifestMCPErrorCode.QUERY_FAILED;\n const details =\n err instanceof ManifestMCPError\n ? {\n ...err.details,\n lease_uuid: leaseUuid,\n provider_uuid: providerUuid,\n provider_url: providerUrl,\n }\n : {\n lease_uuid: leaseUuid,\n provider_uuid: providerUuid,\n provider_url: providerUrl,\n };\n throw new ManifestMCPError(\n code,\n `Deploy partially succeeded: lease ${leaseUuid} was created but subsequent steps failed. ` +\n `Close this lease with close_lease if needed. Error: ${err instanceof Error ? err.message : String(err)}`,\n details,\n );\n }\n\n // 9. Get connection info (best-effort)\n let connection: ConnectionDetails | undefined;\n let url: string | undefined;\n let connectionError: string | undefined;\n try {\n const authToken = await getAuthToken(address, leaseUuid);\n const connResp = await getLeaseConnectionInfo(\n providerUrl,\n leaseUuid,\n authToken,\n fetchFn,\n );\n connection = connResp.connection;\n if (connection.host && connection.ports) {\n const firstPort = Object.values(connection.ports)[0];\n if (typeof firstPort === 'number' || typeof firstPort === 'string') {\n url = `${connection.host}:${firstPort}`;\n }\n }\n } catch (err) {\n const rawMsg = err instanceof Error ? err.message : String(err);\n // Log raw message to stderr for debugging; sanitize only the user-facing return value\n logger.error(\n `[deploy_app] Failed to fetch connection info for lease ${leaseUuid}: ${rawMsg}`,\n );\n connectionError = sanitizeForLogging(rawMsg) as string;\n }\n\n return {\n lease_uuid: leaseUuid,\n provider_uuid: providerUuid,\n provider_url: providerUrl,\n state: status.state,\n ...(url && { url }),\n ...(connection && { connection }),\n ...(connectionError && { connectionError }),\n };\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@manifest-network/manifest-mcp-fred",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "MCP server for Manifest provider (Fred) operations (deploy, status, logs, restart, update)",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
],
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@cosmjs/encoding": "0.32.4",
|
|
49
|
-
"@manifest-network/manifest-mcp-core": "^0.6.
|
|
49
|
+
"@manifest-network/manifest-mcp-core": "^0.6.2",
|
|
50
50
|
"@modelcontextprotocol/sdk": "1.27.1",
|
|
51
51
|
"zod": "^4.3.6"
|
|
52
52
|
},
|