@alfe.ai/gateway 0.9.10 → 0.9.12
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/health.js +533 -180
- package/package.json +2 -2
package/dist/health.js
CHANGED
|
@@ -287,151 +287,6 @@ function pluginConnectionId() {
|
|
|
287
287
|
return createId(ID_PREFIXES.pluginConnection);
|
|
288
288
|
}
|
|
289
289
|
//#endregion
|
|
290
|
-
//#region ../../packages-internal/api-client/dist/client.js
|
|
291
|
-
/**
|
|
292
|
-
* @alfe/api-client — Typed HTTP client for Alfe services.
|
|
293
|
-
*
|
|
294
|
-
* Platform-agnostic: works in React Native and browser environments.
|
|
295
|
-
* Uses standard fetch() API — no Node.js dependencies.
|
|
296
|
-
*/
|
|
297
|
-
var AlfeApiClient = class {
|
|
298
|
-
apiBaseUrl;
|
|
299
|
-
getToken;
|
|
300
|
-
onAuthFailure;
|
|
301
|
-
constructor(options) {
|
|
302
|
-
this.apiBaseUrl = options.apiBaseUrl.replace(/\/+$/, "");
|
|
303
|
-
this.getToken = options.getToken;
|
|
304
|
-
this.onAuthFailure = options.onAuthFailure;
|
|
305
|
-
}
|
|
306
|
-
/**
|
|
307
|
-
* Shared fetch logic — handles auth, 401, and network errors.
|
|
308
|
-
*
|
|
309
|
-
* `skipAuth` callers (public endpoints like OAuth device-code) opt out of
|
|
310
|
-
* the auth-header injection AND the synthetic 401 short-circuit. Without
|
|
311
|
-
* this opt-out, a CLI calling /auth/device-code (no token yet by design)
|
|
312
|
-
* would never reach the network — the `getToken: () => null` path would
|
|
313
|
-
* synthesize a 401 and fire onAuthFailure, breaking the entire flow.
|
|
314
|
-
*/
|
|
315
|
-
async _fetch(path, options, skipAuth = false) {
|
|
316
|
-
try {
|
|
317
|
-
const url = `${this.apiBaseUrl}${path}`;
|
|
318
|
-
const headers = new Headers(options?.headers);
|
|
319
|
-
if (typeof options?.body === "string" && !headers.has("Content-Type")) headers.set("Content-Type", "application/json");
|
|
320
|
-
headers.set("x-correlation-id", correlationId());
|
|
321
|
-
if (!skipAuth) {
|
|
322
|
-
const token = await this.getToken();
|
|
323
|
-
if (!token) {
|
|
324
|
-
this.onAuthFailure?.();
|
|
325
|
-
return {
|
|
326
|
-
ok: false,
|
|
327
|
-
result: {
|
|
328
|
-
ok: false,
|
|
329
|
-
error: "No auth token available",
|
|
330
|
-
status: 401
|
|
331
|
-
}
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
headers.set("Authorization", `Bearer ${token}`);
|
|
335
|
-
}
|
|
336
|
-
const res = await fetch(url, {
|
|
337
|
-
...options,
|
|
338
|
-
headers
|
|
339
|
-
});
|
|
340
|
-
if (res.status === 401 && !skipAuth) {
|
|
341
|
-
this.onAuthFailure?.();
|
|
342
|
-
return {
|
|
343
|
-
ok: false,
|
|
344
|
-
result: {
|
|
345
|
-
ok: false,
|
|
346
|
-
error: "Session expired",
|
|
347
|
-
status: 401
|
|
348
|
-
}
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
const text = res.status === 204 ? "" : await res.text();
|
|
352
|
-
let body;
|
|
353
|
-
if (text) try {
|
|
354
|
-
body = JSON.parse(text);
|
|
355
|
-
} catch {
|
|
356
|
-
body = text;
|
|
357
|
-
}
|
|
358
|
-
if (!res.ok) {
|
|
359
|
-
const errBody = body;
|
|
360
|
-
return {
|
|
361
|
-
ok: false,
|
|
362
|
-
result: {
|
|
363
|
-
ok: false,
|
|
364
|
-
error: (typeof errBody === "object" ? errBody.message : void 0) ?? (typeof body === "string" ? body : `API error: ${String(res.status)}`),
|
|
365
|
-
status: res.status
|
|
366
|
-
}
|
|
367
|
-
};
|
|
368
|
-
}
|
|
369
|
-
return {
|
|
370
|
-
ok: true,
|
|
371
|
-
res,
|
|
372
|
-
body
|
|
373
|
-
};
|
|
374
|
-
} catch (err) {
|
|
375
|
-
return {
|
|
376
|
-
ok: false,
|
|
377
|
-
result: {
|
|
378
|
-
ok: false,
|
|
379
|
-
error: err instanceof Error ? err.message : "Network error"
|
|
380
|
-
}
|
|
381
|
-
};
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
/**
|
|
385
|
-
* Make an authenticated request to an Alfe API endpoint.
|
|
386
|
-
* Unwraps the @auriclabs/api-core `{ data, timestamp, requestId }` envelope.
|
|
387
|
-
*/
|
|
388
|
-
async request(path, options) {
|
|
389
|
-
const result = await this._fetch(path, options);
|
|
390
|
-
if (!result.ok) return result.result;
|
|
391
|
-
if (result.body === void 0) return {
|
|
392
|
-
ok: true,
|
|
393
|
-
data: void 0
|
|
394
|
-
};
|
|
395
|
-
return {
|
|
396
|
-
ok: true,
|
|
397
|
-
data: result.body.data
|
|
398
|
-
};
|
|
399
|
-
}
|
|
400
|
-
/**
|
|
401
|
-
* Make a request to a PUBLIC endpoint that does not require authentication.
|
|
402
|
-
* Skips both the Authorization header injection AND the onAuthFailure
|
|
403
|
-
* callback. Use for endpoints like /auth/device-code that the CLI hits
|
|
404
|
-
* before it has a token.
|
|
405
|
-
*/
|
|
406
|
-
async publicRequest(path, options) {
|
|
407
|
-
const result = await this._fetch(path, options, true);
|
|
408
|
-
if (!result.ok) return result.result;
|
|
409
|
-
if (result.body === void 0) return {
|
|
410
|
-
ok: true,
|
|
411
|
-
data: void 0
|
|
412
|
-
};
|
|
413
|
-
return {
|
|
414
|
-
ok: true,
|
|
415
|
-
data: result.body.data
|
|
416
|
-
};
|
|
417
|
-
}
|
|
418
|
-
/**
|
|
419
|
-
* Make an authenticated request that returns the body directly (no envelope unwrap).
|
|
420
|
-
* Use for APIs that don't use the @auriclabs/api-core response format (e.g. gateway).
|
|
421
|
-
*/
|
|
422
|
-
async rawRequest(path, options) {
|
|
423
|
-
const result = await this._fetch(path, options);
|
|
424
|
-
if (!result.ok) return result.result;
|
|
425
|
-
return {
|
|
426
|
-
ok: true,
|
|
427
|
-
data: result.body
|
|
428
|
-
};
|
|
429
|
-
}
|
|
430
|
-
getApiBaseUrl() {
|
|
431
|
-
return this.apiBaseUrl;
|
|
432
|
-
}
|
|
433
|
-
};
|
|
434
|
-
//#endregion
|
|
435
290
|
//#region ../../packages-internal/types/dist/lib/enum-values.js
|
|
436
291
|
/**
|
|
437
292
|
* Converts a const enum object into a non-empty readonly tuple.
|
|
@@ -4154,7 +4009,8 @@ enumValues({
|
|
|
4154
4009
|
ClaudeMax: "claude-max",
|
|
4155
4010
|
OpenAICodexMax: "openai-codex-max",
|
|
4156
4011
|
OpenAICodexSubscription: "openai-codex-subscription",
|
|
4157
|
-
GeminiMax: "gemini-max"
|
|
4012
|
+
GeminiMax: "gemini-max",
|
|
4013
|
+
AlfeAws: "alfe-aws"
|
|
4158
4014
|
});
|
|
4159
4015
|
enumValues({
|
|
4160
4016
|
Month: "month",
|
|
@@ -4227,6 +4083,179 @@ object({
|
|
|
4227
4083
|
ttsModel: _enum(TTS_MODELS).optional(),
|
|
4228
4084
|
enabled: boolean().optional()
|
|
4229
4085
|
});
|
|
4086
|
+
//#endregion
|
|
4087
|
+
//#region ../../packages-internal/types/dist/access.js
|
|
4088
|
+
/**
|
|
4089
|
+
* Runtime catalog of declared permission subjects + allowed actions.
|
|
4090
|
+
*
|
|
4091
|
+
* Mirrors the compile-time `PermissionDefinitions` augmentation in
|
|
4092
|
+
* `@alfe/api-core/auriclabs-roles.ts`. Kept here so browser code
|
|
4093
|
+
* (dashboard) can consume it without pulling in server-only deps
|
|
4094
|
+
* (`@middy/core`, `aws-lambda`, etc.).
|
|
4095
|
+
*/
|
|
4096
|
+
const PERMISSION_CATALOG = {
|
|
4097
|
+
all: ["manage"],
|
|
4098
|
+
user: [
|
|
4099
|
+
"create",
|
|
4100
|
+
"read",
|
|
4101
|
+
"update",
|
|
4102
|
+
"delete",
|
|
4103
|
+
"manage"
|
|
4104
|
+
],
|
|
4105
|
+
agent: [
|
|
4106
|
+
"create",
|
|
4107
|
+
"read",
|
|
4108
|
+
"update",
|
|
4109
|
+
"delete",
|
|
4110
|
+
"exec",
|
|
4111
|
+
"chat",
|
|
4112
|
+
"manage"
|
|
4113
|
+
],
|
|
4114
|
+
chat: [
|
|
4115
|
+
"read",
|
|
4116
|
+
"write",
|
|
4117
|
+
"upload",
|
|
4118
|
+
"manage"
|
|
4119
|
+
],
|
|
4120
|
+
sync: [
|
|
4121
|
+
"read",
|
|
4122
|
+
"write",
|
|
4123
|
+
"manage"
|
|
4124
|
+
],
|
|
4125
|
+
integration: [
|
|
4126
|
+
"create",
|
|
4127
|
+
"read",
|
|
4128
|
+
"update",
|
|
4129
|
+
"delete",
|
|
4130
|
+
"manage"
|
|
4131
|
+
],
|
|
4132
|
+
gateway: ["connect", "manage"],
|
|
4133
|
+
voice: ["read", "manage"],
|
|
4134
|
+
identity: ["read", "manage"],
|
|
4135
|
+
token: [
|
|
4136
|
+
"create",
|
|
4137
|
+
"read",
|
|
4138
|
+
"update",
|
|
4139
|
+
"delete",
|
|
4140
|
+
"manage"
|
|
4141
|
+
],
|
|
4142
|
+
billing: ["read", "manage"],
|
|
4143
|
+
template: [
|
|
4144
|
+
"create",
|
|
4145
|
+
"read",
|
|
4146
|
+
"update",
|
|
4147
|
+
"delete",
|
|
4148
|
+
"manage"
|
|
4149
|
+
],
|
|
4150
|
+
team: [
|
|
4151
|
+
"create",
|
|
4152
|
+
"read",
|
|
4153
|
+
"update",
|
|
4154
|
+
"delete",
|
|
4155
|
+
"manage"
|
|
4156
|
+
],
|
|
4157
|
+
project: [
|
|
4158
|
+
"create",
|
|
4159
|
+
"read",
|
|
4160
|
+
"update",
|
|
4161
|
+
"delete",
|
|
4162
|
+
"manage"
|
|
4163
|
+
],
|
|
4164
|
+
org_file: ["read", "write"],
|
|
4165
|
+
org_knowledge: ["read", "write"],
|
|
4166
|
+
model_policy: ["read", "manage"],
|
|
4167
|
+
data_boundary: ["read", "manage"],
|
|
4168
|
+
secret: [
|
|
4169
|
+
"create",
|
|
4170
|
+
"read",
|
|
4171
|
+
"update",
|
|
4172
|
+
"delete",
|
|
4173
|
+
"manage"
|
|
4174
|
+
],
|
|
4175
|
+
database: [
|
|
4176
|
+
"read",
|
|
4177
|
+
"write",
|
|
4178
|
+
"manage"
|
|
4179
|
+
],
|
|
4180
|
+
role_management: ["read", "manage"],
|
|
4181
|
+
org: ["read", "manage"],
|
|
4182
|
+
connection: [
|
|
4183
|
+
"create",
|
|
4184
|
+
"read",
|
|
4185
|
+
"update",
|
|
4186
|
+
"delete",
|
|
4187
|
+
"manage"
|
|
4188
|
+
],
|
|
4189
|
+
remote: ["control", "terminal"],
|
|
4190
|
+
subscription: ["read", "manage"],
|
|
4191
|
+
referral: ["manage"],
|
|
4192
|
+
promo_code: ["manage"],
|
|
4193
|
+
pricing: ["manage"],
|
|
4194
|
+
access_gate: ["manage"],
|
|
4195
|
+
dlq: ["read", "manage"],
|
|
4196
|
+
support: ["read"],
|
|
4197
|
+
discounts: ["manage"],
|
|
4198
|
+
stats: ["read"],
|
|
4199
|
+
mobile: ["read", "manage"],
|
|
4200
|
+
impersonation: ["manage"],
|
|
4201
|
+
partner: ["manage"]
|
|
4202
|
+
};
|
|
4203
|
+
/**
|
|
4204
|
+
* Subjects a tenant may grant via a custom role.
|
|
4205
|
+
*
|
|
4206
|
+
* Excludes `all` (platform-admin escape hatch) and every platform-only
|
|
4207
|
+
* permission subject listed after it in the catalog.
|
|
4208
|
+
*/
|
|
4209
|
+
const TENANT_ALLOWED_SUBJECTS = [
|
|
4210
|
+
"agent",
|
|
4211
|
+
"chat",
|
|
4212
|
+
"sync",
|
|
4213
|
+
"integration",
|
|
4214
|
+
"secret",
|
|
4215
|
+
"database",
|
|
4216
|
+
"template",
|
|
4217
|
+
"org_file",
|
|
4218
|
+
"org_knowledge",
|
|
4219
|
+
"team",
|
|
4220
|
+
"project",
|
|
4221
|
+
"model_policy",
|
|
4222
|
+
"data_boundary",
|
|
4223
|
+
"role_management",
|
|
4224
|
+
"billing",
|
|
4225
|
+
"identity",
|
|
4226
|
+
"token",
|
|
4227
|
+
"user",
|
|
4228
|
+
"gateway",
|
|
4229
|
+
"voice",
|
|
4230
|
+
"org",
|
|
4231
|
+
"connection",
|
|
4232
|
+
"remote",
|
|
4233
|
+
"subscription"
|
|
4234
|
+
];
|
|
4235
|
+
/**
|
|
4236
|
+
* Subjects a PLATFORM ADMIN may grant via a custom **admin** role (authored at
|
|
4237
|
+
* the flat `admin:` scope, stored under the `"system"` tenant). Two groups:
|
|
4238
|
+
*
|
|
4239
|
+
* 1. Platform-only subjects — every catalog subject that is NOT in
|
|
4240
|
+
* `TENANT_ALLOWED_SUBJECTS` (and never `all`). Derived from
|
|
4241
|
+
* `PERMISSION_CATALOG` so a newly-declared admin-only subject becomes
|
|
4242
|
+
* grantable in custom admin roles automatically.
|
|
4243
|
+
* 2. Dual-surface subjects an admin also curates platform-wide: `user`
|
|
4244
|
+
* (platform user management), `role_management` (admin role authoring),
|
|
4245
|
+
* and `subscription` (reviewing every tenant's plan/startup application).
|
|
4246
|
+
*
|
|
4247
|
+
* `all` is deliberately excluded — it is reserved for the built-in
|
|
4248
|
+
* `sys:admin:admin` super-admin role and must never be grantable through a
|
|
4249
|
+
* custom admin role. The complement of `TENANT_ALLOWED_SUBJECTS` keeps the
|
|
4250
|
+
* tenant vocabulary and the admin vocabulary from drifting into each other.
|
|
4251
|
+
*/
|
|
4252
|
+
const ADMIN_DUAL_SURFACE_SUBJECTS = [
|
|
4253
|
+
"user",
|
|
4254
|
+
"role_management",
|
|
4255
|
+
"subscription"
|
|
4256
|
+
];
|
|
4257
|
+
const TENANT_ALLOWED_SUBJECT_LOOKUP = new Set(TENANT_ALLOWED_SUBJECTS);
|
|
4258
|
+
[...Object.keys(PERMISSION_CATALOG).filter((subject) => subject !== "all" && !TENANT_ALLOWED_SUBJECT_LOOKUP.has(subject)), ...ADMIN_DUAL_SURFACE_SUBJECTS];
|
|
4230
4259
|
enumValues({
|
|
4231
4260
|
Org: "org",
|
|
4232
4261
|
Team: "team",
|
|
@@ -4353,6 +4382,26 @@ enumValues({
|
|
|
4353
4382
|
Demo: "demo",
|
|
4354
4383
|
Live: "live"
|
|
4355
4384
|
});
|
|
4385
|
+
function createClerkReverificationResponse(afterMinutes) {
|
|
4386
|
+
if (!Number.isInteger(afterMinutes) || afterMinutes < 0) throw new TypeError("afterMinutes must be a non-negative integer");
|
|
4387
|
+
return { clerk_error: {
|
|
4388
|
+
type: "forbidden",
|
|
4389
|
+
reason: "reverification-error",
|
|
4390
|
+
metadata: { reverification: {
|
|
4391
|
+
level: "second_factor",
|
|
4392
|
+
afterMinutes
|
|
4393
|
+
} }
|
|
4394
|
+
} };
|
|
4395
|
+
}
|
|
4396
|
+
/** Strictly identify the only authorization hint the API client may expose. */
|
|
4397
|
+
function isClerkReverificationResponse(value) {
|
|
4398
|
+
if (!value || typeof value !== "object") return false;
|
|
4399
|
+
const clerkError = value.clerk_error;
|
|
4400
|
+
if (!clerkError || typeof clerkError !== "object") return false;
|
|
4401
|
+
const error = clerkError;
|
|
4402
|
+
const reverification = error.metadata?.reverification;
|
|
4403
|
+
return error.type === "forbidden" && error.reason === "reverification-error" && reverification?.level === "second_factor" && Number.isInteger(reverification.afterMinutes) && reverification.afterMinutes >= 0;
|
|
4404
|
+
}
|
|
4356
4405
|
//#endregion
|
|
4357
4406
|
//#region ../../packages-internal/types/dist/models.js
|
|
4358
4407
|
const AnthropicModel = {
|
|
@@ -4480,6 +4529,35 @@ _enum(QWEN_MODELS);
|
|
|
4480
4529
|
string().trim().min(1);
|
|
4481
4530
|
AnthropicModel.Opus5, AnthropicModel.Opus48, AnthropicModel.Opus47, AnthropicModel.Opus46, AnthropicModel.Sonnet5, AnthropicModel.Sonnet46, AnthropicModel.Haiku45, OpenAIModel.GPT4o, OpenAIModel.GPT4oMini, OpenAIModel.O3, OpenAIModel.GPT41, OpenAIModel.GPT41Mini, OpenAIModel.GPT41Nano, OpenAIModel.GPT54, OpenAIModel.GPT54Mini, OpenAIModel.GPT54Nano, OpenAIModel.GPT54Pro, OpenAIModel.GPT55, OpenAIModel.GPT55Pro, OpenAIModel.GPT56Sol, OpenAIModel.GPT56Terra, OpenAIModel.GPT56Luna, OpenAIModel.O3Mini, OpenAIModel.O4Mini, OpenAIModel.TextEmbedding3Small, OpenAIModel.TextEmbedding3Large, DeepSeekModel.Chat, DeepSeekModel.Reasoner, DeepSeekModel.V4Flash, DeepSeekModel.V4Pro, GoogleModel.Gemini35Flash, GoogleModel.Gemini31Pro, GoogleModel.Gemini31FlashLite, GoogleModel.Gemini25Pro, GoogleModel.Gemini25Flash, GoogleModel.Gemini25FlashLite, GoogleModel.Gemini20Flash, MiniMaxModel.M3, MiniMaxModel.M27, MiniMaxModel.M27HighSpeed, MiniMaxModel.M25, MiniMaxModel.M21, MiniMaxModel.M2, MistralModel.Large, MistralModel.Medium, MistralModel.Small, MistralModel.Codestral, MistralModel.Ministral8b, MistralModel.Ministral3b, MistralModel.MagistralMedium, MistralModel.MagistralSmall, MistralModel.DevstralMedium, XAIModel.Grok45, XAIModel.Grok43, XAIModel.Grok4, XAIModel.Grok41Fast, ZhipuModel.GLM52, ZhipuModel.GLM51, ZhipuModel.GLM46, ZhipuModel.GLM45, ZhipuModel.GLM45Air, MoonshotModel.K3, MoonshotModel.K26, MoonshotModel.K27Code, MoonshotModel.K27CodeHighSpeed, QwenModel.Qwen37Max, QwenModel.Qwen37Plus, QwenModel.Qwen36Flash, QwenModel.Qwen35Flash;
|
|
4482
4531
|
AnthropicModel.Opus5, AnthropicModel.Opus48, AnthropicModel.Opus47, AnthropicModel.Opus46, AnthropicModel.Sonnet5, AnthropicModel.Sonnet46, AnthropicModel.Haiku45, OpenAIModel.GPT4o, OpenAIModel.GPT4oMini, OpenAIModel.O3, OpenAIModel.GPT41, OpenAIModel.GPT41Mini, OpenAIModel.GPT41Nano, OpenAIModel.GPT54, OpenAIModel.GPT54Mini, OpenAIModel.GPT54Nano, OpenAIModel.GPT54Pro, OpenAIModel.GPT55, OpenAIModel.GPT55Pro, OpenAIModel.GPT56Sol, OpenAIModel.GPT56Terra, OpenAIModel.GPT56Luna, OpenAIModel.O3Mini, OpenAIModel.O4Mini, OpenAIModel.TextEmbedding3Small, OpenAIModel.TextEmbedding3Large, DeepSeekModel.Chat, DeepSeekModel.Reasoner, DeepSeekModel.V4Flash, DeepSeekModel.V4Pro, GoogleModel.Gemini35Flash, GoogleModel.Gemini31Pro, GoogleModel.Gemini31FlashLite, GoogleModel.Gemini25Pro, GoogleModel.Gemini25Flash, GoogleModel.Gemini25FlashLite, GoogleModel.Gemini20Flash, MiniMaxModel.M3, MiniMaxModel.M27, MiniMaxModel.M27HighSpeed, MiniMaxModel.M25, MiniMaxModel.M21, MiniMaxModel.M2, MistralModel.Large, MistralModel.Medium, MistralModel.Small, MistralModel.Codestral, MistralModel.Ministral8b, MistralModel.Ministral3b, MistralModel.MagistralMedium, MistralModel.MagistralSmall, MistralModel.DevstralMedium, XAIModel.Grok45, XAIModel.Grok43, XAIModel.Grok4, XAIModel.Grok41Fast, ZhipuModel.GLM52, ZhipuModel.GLM51, ZhipuModel.GLM46, ZhipuModel.GLM45, ZhipuModel.GLM45Air, MoonshotModel.K3, MoonshotModel.K26, MoonshotModel.K27Code, MoonshotModel.K27CodeHighSpeed, QwenModel.Qwen37Max, QwenModel.Qwen37Plus, QwenModel.Qwen36Flash, QwenModel.Qwen35Flash;
|
|
4532
|
+
enumValues({
|
|
4533
|
+
Standard: "standard",
|
|
4534
|
+
AwsPrivate: "aws_private"
|
|
4535
|
+
});
|
|
4536
|
+
enumValues({ ApSoutheast2: "ap-southeast-2" });
|
|
4537
|
+
enumValues({
|
|
4538
|
+
Standard: "standard",
|
|
4539
|
+
Requested: "requested",
|
|
4540
|
+
Provisioning: "provisioning",
|
|
4541
|
+
Ready: "ready",
|
|
4542
|
+
CuttingOver: "cutting_over",
|
|
4543
|
+
Active: "active",
|
|
4544
|
+
Failing: "failing",
|
|
4545
|
+
Decommissioning: "decommissioning"
|
|
4546
|
+
});
|
|
4547
|
+
enumValues({
|
|
4548
|
+
RegionalShared: "regional_shared",
|
|
4549
|
+
Dedicated: "dedicated"
|
|
4550
|
+
});
|
|
4551
|
+
enumValues({
|
|
4552
|
+
Inference: "inference",
|
|
4553
|
+
AuthProjection: "auth_projection",
|
|
4554
|
+
ChatGateway: "chat_gateway",
|
|
4555
|
+
AgentCompute: "agent_compute",
|
|
4556
|
+
Attachments: "attachments",
|
|
4557
|
+
Memory: "memory",
|
|
4558
|
+
CapabilityPolicy: "capability_policy",
|
|
4559
|
+
Observability: "observability"
|
|
4560
|
+
});
|
|
4483
4561
|
enumValues({
|
|
4484
4562
|
PendingChallenge: "pending_challenge",
|
|
4485
4563
|
Creating: "creating",
|
|
@@ -4568,6 +4646,8 @@ const NotificationType = {
|
|
|
4568
4646
|
BrowserTakeoverRequested: "browser_takeover_requested",
|
|
4569
4647
|
InviteCreated: "onboarding.invite.created",
|
|
4570
4648
|
OrgClaimed: "onboarding.org.claimed",
|
|
4649
|
+
ElevatedSupportRequested: "partner.elevated_support.requested",
|
|
4650
|
+
ElevatedSupportStarted: "partner.elevated_support.started",
|
|
4571
4651
|
TeamMemberAdded: "team.member.added",
|
|
4572
4652
|
ProjectMemberAdded: "project.member.added",
|
|
4573
4653
|
IntegrationInstalled: "integration.installed",
|
|
@@ -4582,7 +4662,213 @@ const RecipientStrategy = {
|
|
|
4582
4662
|
TenantAdmins: "tenant_admins",
|
|
4583
4663
|
SpecificUser: "specific_user"
|
|
4584
4664
|
};
|
|
4585
|
-
NotificationType.PaymentSucceeded, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.PaymentFailed, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationChannel.Sms, NotificationType.TopUpCompleted, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.AutoRechargeCompleted, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationType.AutoRechargeFailed, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationChannel.Sms, NotificationType.SubscriptionCreated, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationType.SubscriptionCancelled, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.StartupGrantEnded, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.GrantEnded, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.EnterpriseGrantEnded, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.SubscriptionPastDue, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationChannel.Sms, NotificationType.BalanceThresholdWarning, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.PlatformTierPriceIncrease, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationType.AgentCreated, NotificationCategory.Agents, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.AgentProvisionFailed, NotificationCategory.Agents, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.AgentBillingSuspended, NotificationCategory.Agents, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.AgentDisconnectedExtended, NotificationCategory.Agents, RecipientStrategy.TenantAdmins, NotificationChannel.Push, NotificationType.BrowserTakeoverRequested, NotificationCategory.Agents, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.InviteCreated, NotificationCategory.System, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationType.OrgClaimed, NotificationCategory.System, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.TeamMemberAdded, NotificationCategory.Team, RecipientStrategy.SpecificUser, NotificationChannel.Email, NotificationChannel.Push, NotificationType.ProjectMemberAdded, NotificationCategory.Team, RecipientStrategy.SpecificUser, NotificationChannel.Email, NotificationChannel.Push, NotificationType.IntegrationInstalled, NotificationCategory.Integrations, RecipientStrategy.TenantAdmins, NotificationChannel.Push, NotificationType.IntegrationRemoved, NotificationCategory.Integrations, RecipientStrategy.TenantAdmins, NotificationChannel.Push;
|
|
4665
|
+
NotificationType.PaymentSucceeded, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.PaymentFailed, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationChannel.Sms, NotificationType.TopUpCompleted, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.AutoRechargeCompleted, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationType.AutoRechargeFailed, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationChannel.Sms, NotificationType.SubscriptionCreated, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationType.SubscriptionCancelled, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.StartupGrantEnded, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.GrantEnded, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.EnterpriseGrantEnded, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.SubscriptionPastDue, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationChannel.Sms, NotificationType.BalanceThresholdWarning, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.PlatformTierPriceIncrease, NotificationCategory.Billing, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationType.AgentCreated, NotificationCategory.Agents, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.AgentProvisionFailed, NotificationCategory.Agents, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.AgentBillingSuspended, NotificationCategory.Agents, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.AgentDisconnectedExtended, NotificationCategory.Agents, RecipientStrategy.TenantAdmins, NotificationChannel.Push, NotificationType.BrowserTakeoverRequested, NotificationCategory.Agents, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.InviteCreated, NotificationCategory.System, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationType.OrgClaimed, NotificationCategory.System, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.ElevatedSupportRequested, NotificationCategory.System, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.ElevatedSupportStarted, NotificationCategory.System, RecipientStrategy.TenantAdmins, NotificationChannel.Email, NotificationChannel.Push, NotificationType.TeamMemberAdded, NotificationCategory.Team, RecipientStrategy.SpecificUser, NotificationChannel.Email, NotificationChannel.Push, NotificationType.ProjectMemberAdded, NotificationCategory.Team, RecipientStrategy.SpecificUser, NotificationChannel.Email, NotificationChannel.Push, NotificationType.IntegrationInstalled, NotificationCategory.Integrations, RecipientStrategy.TenantAdmins, NotificationChannel.Push, NotificationType.IntegrationRemoved, NotificationCategory.Integrations, RecipientStrategy.TenantAdmins, NotificationChannel.Push;
|
|
4666
|
+
//#endregion
|
|
4667
|
+
//#region ../../packages-internal/api-client/dist/client.js
|
|
4668
|
+
/**
|
|
4669
|
+
* @alfe/api-client — Typed HTTP client for Alfe services.
|
|
4670
|
+
*
|
|
4671
|
+
* Platform-agnostic: works in React Native and browser environments.
|
|
4672
|
+
* Uses standard fetch() API — no Node.js dependencies.
|
|
4673
|
+
*/
|
|
4674
|
+
var AlfeApiClient = class {
|
|
4675
|
+
apiBaseUrl;
|
|
4676
|
+
getToken;
|
|
4677
|
+
onAuthFailure;
|
|
4678
|
+
constructor(options) {
|
|
4679
|
+
this.apiBaseUrl = options.apiBaseUrl.replace(/\/+$/, "");
|
|
4680
|
+
this.getToken = options.getToken;
|
|
4681
|
+
this.onAuthFailure = options.onAuthFailure;
|
|
4682
|
+
}
|
|
4683
|
+
/**
|
|
4684
|
+
* Shared fetch logic — handles auth, 401, and network errors.
|
|
4685
|
+
*
|
|
4686
|
+
* `skipAuth` callers (public endpoints like OAuth device-code) opt out of
|
|
4687
|
+
* the auth-header injection AND the synthetic 401 short-circuit. Without
|
|
4688
|
+
* this opt-out, a CLI calling /auth/device-code (no token yet by design)
|
|
4689
|
+
* would never reach the network — the `getToken: () => null` path would
|
|
4690
|
+
* synthesize a 401 and fire onAuthFailure, breaking the entire flow.
|
|
4691
|
+
*/
|
|
4692
|
+
async _fetchResponse(path, options, skipAuth = false) {
|
|
4693
|
+
try {
|
|
4694
|
+
const url = `${this.apiBaseUrl}${path}`;
|
|
4695
|
+
const headers = new Headers(options?.headers);
|
|
4696
|
+
if (typeof options?.body === "string" && !headers.has("Content-Type")) headers.set("Content-Type", "application/json");
|
|
4697
|
+
headers.set("x-correlation-id", correlationId());
|
|
4698
|
+
if (!skipAuth) {
|
|
4699
|
+
const token = await this.getToken();
|
|
4700
|
+
if (!token) {
|
|
4701
|
+
this.onAuthFailure?.();
|
|
4702
|
+
return {
|
|
4703
|
+
ok: false,
|
|
4704
|
+
result: {
|
|
4705
|
+
ok: false,
|
|
4706
|
+
error: "No auth token available",
|
|
4707
|
+
status: 401
|
|
4708
|
+
}
|
|
4709
|
+
};
|
|
4710
|
+
}
|
|
4711
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
4712
|
+
}
|
|
4713
|
+
const res = await fetch(url, {
|
|
4714
|
+
...options,
|
|
4715
|
+
headers
|
|
4716
|
+
});
|
|
4717
|
+
if (res.status === 401 && !skipAuth) {
|
|
4718
|
+
this.onAuthFailure?.();
|
|
4719
|
+
return {
|
|
4720
|
+
ok: false,
|
|
4721
|
+
result: {
|
|
4722
|
+
ok: false,
|
|
4723
|
+
error: "Session expired",
|
|
4724
|
+
status: 401
|
|
4725
|
+
}
|
|
4726
|
+
};
|
|
4727
|
+
}
|
|
4728
|
+
if (!res.ok) {
|
|
4729
|
+
const text = res.status === 204 ? "" : await res.text();
|
|
4730
|
+
let body;
|
|
4731
|
+
if (text) try {
|
|
4732
|
+
body = JSON.parse(text);
|
|
4733
|
+
} catch {
|
|
4734
|
+
body = text;
|
|
4735
|
+
}
|
|
4736
|
+
const errBody = body;
|
|
4737
|
+
const errorMessage = typeof errBody === "object" ? errBody.message : void 0;
|
|
4738
|
+
return {
|
|
4739
|
+
ok: false,
|
|
4740
|
+
body,
|
|
4741
|
+
result: {
|
|
4742
|
+
ok: false,
|
|
4743
|
+
error: errorMessage ?? (typeof body === "string" ? body : `API error: ${String(res.status)}`),
|
|
4744
|
+
status: res.status
|
|
4745
|
+
}
|
|
4746
|
+
};
|
|
4747
|
+
}
|
|
4748
|
+
return {
|
|
4749
|
+
ok: true,
|
|
4750
|
+
res
|
|
4751
|
+
};
|
|
4752
|
+
} catch (err) {
|
|
4753
|
+
return {
|
|
4754
|
+
ok: false,
|
|
4755
|
+
result: {
|
|
4756
|
+
ok: false,
|
|
4757
|
+
error: err instanceof Error ? err.message : "Network error"
|
|
4758
|
+
}
|
|
4759
|
+
};
|
|
4760
|
+
}
|
|
4761
|
+
}
|
|
4762
|
+
async _fetch(path, options, skipAuth = false) {
|
|
4763
|
+
const response = await this._fetchResponse(path, options, skipAuth);
|
|
4764
|
+
if (!response.ok) return response;
|
|
4765
|
+
const text = response.res.status === 204 ? "" : await response.res.text();
|
|
4766
|
+
let body;
|
|
4767
|
+
if (text) try {
|
|
4768
|
+
body = JSON.parse(text);
|
|
4769
|
+
} catch {
|
|
4770
|
+
body = text;
|
|
4771
|
+
}
|
|
4772
|
+
return {
|
|
4773
|
+
ok: true,
|
|
4774
|
+
res: response.res,
|
|
4775
|
+
body
|
|
4776
|
+
};
|
|
4777
|
+
}
|
|
4778
|
+
/**
|
|
4779
|
+
* Make an authenticated request to an Alfe API endpoint.
|
|
4780
|
+
* Unwraps the @auriclabs/api-core `{ data, timestamp, requestId }` envelope.
|
|
4781
|
+
*/
|
|
4782
|
+
async request(path, options) {
|
|
4783
|
+
const result = await this._fetch(path, options);
|
|
4784
|
+
if (!result.ok) return result.result;
|
|
4785
|
+
if (result.body === void 0) return {
|
|
4786
|
+
ok: true,
|
|
4787
|
+
data: void 0
|
|
4788
|
+
};
|
|
4789
|
+
return {
|
|
4790
|
+
ok: true,
|
|
4791
|
+
data: result.body.data
|
|
4792
|
+
};
|
|
4793
|
+
}
|
|
4794
|
+
/**
|
|
4795
|
+
* Make an authenticated request whose 403 response may ask Clerk to
|
|
4796
|
+
* reverify the current session. Unlike `request`, this preserves only the
|
|
4797
|
+
* strictly validated Clerk hint; all ordinary failures retain `ApiResult`.
|
|
4798
|
+
*/
|
|
4799
|
+
async reverifiableRequest(path, options) {
|
|
4800
|
+
const result = await this._fetch(path, options);
|
|
4801
|
+
if (!result.ok) {
|
|
4802
|
+
if (isClerkReverificationResponse(result.body)) return createClerkReverificationResponse(result.body.clerk_error.metadata.reverification.afterMinutes);
|
|
4803
|
+
return result.result;
|
|
4804
|
+
}
|
|
4805
|
+
if (result.body === void 0) return {
|
|
4806
|
+
ok: true,
|
|
4807
|
+
data: void 0
|
|
4808
|
+
};
|
|
4809
|
+
return {
|
|
4810
|
+
ok: true,
|
|
4811
|
+
data: result.body.data
|
|
4812
|
+
};
|
|
4813
|
+
}
|
|
4814
|
+
/**
|
|
4815
|
+
* Make a request to a PUBLIC endpoint that does not require authentication.
|
|
4816
|
+
* Skips both the Authorization header injection AND the onAuthFailure
|
|
4817
|
+
* callback. Use for endpoints like /auth/device-code that the CLI hits
|
|
4818
|
+
* before it has a token.
|
|
4819
|
+
*/
|
|
4820
|
+
async publicRequest(path, options) {
|
|
4821
|
+
const result = await this._fetch(path, options, true);
|
|
4822
|
+
if (!result.ok) return result.result;
|
|
4823
|
+
if (result.body === void 0) return {
|
|
4824
|
+
ok: true,
|
|
4825
|
+
data: void 0
|
|
4826
|
+
};
|
|
4827
|
+
return {
|
|
4828
|
+
ok: true,
|
|
4829
|
+
data: result.body.data
|
|
4830
|
+
};
|
|
4831
|
+
}
|
|
4832
|
+
/**
|
|
4833
|
+
* Make an authenticated request that returns the body directly (no envelope unwrap).
|
|
4834
|
+
* Use for APIs that don't use the @auriclabs/api-core response format (e.g. gateway).
|
|
4835
|
+
*/
|
|
4836
|
+
async rawRequest(path, options) {
|
|
4837
|
+
const result = await this._fetch(path, options);
|
|
4838
|
+
if (!result.ok) return result.result;
|
|
4839
|
+
return {
|
|
4840
|
+
ok: true,
|
|
4841
|
+
data: result.body
|
|
4842
|
+
};
|
|
4843
|
+
}
|
|
4844
|
+
/**
|
|
4845
|
+
* Make an authenticated request without attempting text/JSON decoding.
|
|
4846
|
+
* Use for downloads such as a Teams app ZIP where UTF-8 conversion would
|
|
4847
|
+
* corrupt the payload.
|
|
4848
|
+
*/
|
|
4849
|
+
async binaryRequest(path, options) {
|
|
4850
|
+
const result = await this._fetchResponse(path, options);
|
|
4851
|
+
if (!result.ok) return result.result;
|
|
4852
|
+
try {
|
|
4853
|
+
return {
|
|
4854
|
+
ok: true,
|
|
4855
|
+
data: {
|
|
4856
|
+
body: await result.res.arrayBuffer(),
|
|
4857
|
+
contentType: result.res.headers.get("Content-Type") ?? void 0,
|
|
4858
|
+
contentDisposition: result.res.headers.get("Content-Disposition") ?? void 0
|
|
4859
|
+
}
|
|
4860
|
+
};
|
|
4861
|
+
} catch (err) {
|
|
4862
|
+
return {
|
|
4863
|
+
ok: false,
|
|
4864
|
+
error: err instanceof Error ? err.message : "Failed to read binary response"
|
|
4865
|
+
};
|
|
4866
|
+
}
|
|
4867
|
+
}
|
|
4868
|
+
getApiBaseUrl() {
|
|
4869
|
+
return this.apiBaseUrl;
|
|
4870
|
+
}
|
|
4871
|
+
};
|
|
4586
4872
|
//#endregion
|
|
4587
4873
|
//#region ../../packages-internal/api-client/dist/services/auth.js
|
|
4588
4874
|
var AuthService = class {
|
|
@@ -4592,7 +4878,7 @@ var AuthService = class {
|
|
|
4592
4878
|
}
|
|
4593
4879
|
prefix = "/auth";
|
|
4594
4880
|
validate(token) {
|
|
4595
|
-
return this.client.
|
|
4881
|
+
return this.client.publicRequest(`${this.prefix}/validate`, {
|
|
4596
4882
|
method: "POST",
|
|
4597
4883
|
body: JSON.stringify({ token })
|
|
4598
4884
|
});
|
|
@@ -4609,6 +4895,24 @@ var AuthService = class {
|
|
|
4609
4895
|
deleteToken(tokenId) {
|
|
4610
4896
|
return this.client.request(`${this.prefix}/tokens/${encodeURIComponent(tokenId)}`, { method: "DELETE" });
|
|
4611
4897
|
}
|
|
4898
|
+
mintPartnerDelegation(input) {
|
|
4899
|
+
return this.client.request(`${this.prefix}/partner-delegations`, {
|
|
4900
|
+
method: "POST",
|
|
4901
|
+
body: JSON.stringify(input)
|
|
4902
|
+
});
|
|
4903
|
+
}
|
|
4904
|
+
mintPartnerElevatedDelegation(input) {
|
|
4905
|
+
return this.client.request(`${this.prefix}/partner-delegations/elevated`, {
|
|
4906
|
+
method: "POST",
|
|
4907
|
+
body: JSON.stringify(input)
|
|
4908
|
+
});
|
|
4909
|
+
}
|
|
4910
|
+
refreshPartnerDelegation(delegationId) {
|
|
4911
|
+
return this.client.request(`${this.prefix}/partner-delegations/${encodeURIComponent(delegationId)}/refresh`, { method: "POST" });
|
|
4912
|
+
}
|
|
4913
|
+
revokePartnerDelegation(delegationId) {
|
|
4914
|
+
return this.client.request(`${this.prefix}/partner-delegations/${encodeURIComponent(delegationId)}`, { method: "DELETE" });
|
|
4915
|
+
}
|
|
4612
4916
|
/**
|
|
4613
4917
|
* Start a device-code flow. Called by the CLI when the user runs
|
|
4614
4918
|
* `alfe login` and picks the browser path. The returned `device_code`
|
|
@@ -4967,6 +5271,12 @@ var IntegrationsService = class {
|
|
|
4967
5271
|
listSlackChannels(agentId) {
|
|
4968
5272
|
return this.client.request(`/slack/agents/${encodeURIComponent(agentId)}/channels`);
|
|
4969
5273
|
}
|
|
5274
|
+
createSlackApp(agentId) {
|
|
5275
|
+
return this.client.request("/slack/apps/create", {
|
|
5276
|
+
method: "POST",
|
|
5277
|
+
body: JSON.stringify({ agentId })
|
|
5278
|
+
});
|
|
5279
|
+
}
|
|
4970
5280
|
sendSlackMessage(agentId, channel, text) {
|
|
4971
5281
|
return this.client.request(`/slack/agents/${encodeURIComponent(agentId)}/send`, {
|
|
4972
5282
|
method: "POST",
|
|
@@ -6416,25 +6726,44 @@ var ConfigReconciler = class {
|
|
|
6416
6726
|
status: "applied"
|
|
6417
6727
|
};
|
|
6418
6728
|
const failures = [];
|
|
6729
|
+
const inconclusiveKeys = [];
|
|
6419
6730
|
for (const [key, want] of entries) try {
|
|
6420
6731
|
if (getConfigRaw) {
|
|
6421
|
-
|
|
6732
|
+
let current;
|
|
6733
|
+
try {
|
|
6734
|
+
current = await getConfigRaw(key);
|
|
6735
|
+
} catch (err) {
|
|
6736
|
+
log$4.warn({
|
|
6737
|
+
key,
|
|
6738
|
+
err: err instanceof Error ? err.message : String(err)
|
|
6739
|
+
}, "Config diff read failed — attempting the write");
|
|
6740
|
+
}
|
|
6741
|
+
if (current === want) {
|
|
6422
6742
|
log$4.debug({ key }, "Config already at desired value — no-op");
|
|
6423
6743
|
continue;
|
|
6424
6744
|
}
|
|
6425
6745
|
}
|
|
6426
6746
|
await setConfigRaw(key, want);
|
|
6427
6747
|
if (getConfigRaw) {
|
|
6428
|
-
|
|
6748
|
+
const outcome = await this.verify(getConfigRaw, key, want);
|
|
6749
|
+
if (outcome === "mismatched") failures.push(`${key}: verify failed (read-back did not match)`);
|
|
6750
|
+
else if (outcome === "inconclusive") inconclusiveKeys.push(key);
|
|
6429
6751
|
}
|
|
6430
6752
|
} catch (err) {
|
|
6431
6753
|
const msg = err instanceof Error ? err.message : String(err);
|
|
6432
|
-
if (getConfigRaw
|
|
6433
|
-
|
|
6434
|
-
|
|
6435
|
-
|
|
6436
|
-
|
|
6437
|
-
|
|
6754
|
+
if (getConfigRaw) {
|
|
6755
|
+
const outcome = await this.verify(getConfigRaw, key, want);
|
|
6756
|
+
if (outcome === "matched") {
|
|
6757
|
+
log$4.warn({
|
|
6758
|
+
key,
|
|
6759
|
+
err: msg
|
|
6760
|
+
}, "config set errored but value landed — treating as applied");
|
|
6761
|
+
continue;
|
|
6762
|
+
}
|
|
6763
|
+
if (outcome === "inconclusive") {
|
|
6764
|
+
inconclusiveKeys.push(key);
|
|
6765
|
+
continue;
|
|
6766
|
+
}
|
|
6438
6767
|
}
|
|
6439
6768
|
failures.push(`${key}: ${msg}`);
|
|
6440
6769
|
}
|
|
@@ -6451,6 +6780,13 @@ var ConfigReconciler = class {
|
|
|
6451
6780
|
reason
|
|
6452
6781
|
};
|
|
6453
6782
|
}
|
|
6783
|
+
if (inconclusiveKeys.length > 0) {
|
|
6784
|
+
log$4.warn({
|
|
6785
|
+
version: desired.version,
|
|
6786
|
+
keys: inconclusiveKeys
|
|
6787
|
+
}, "Config reconcile verification was inconclusive — leaving version pending");
|
|
6788
|
+
return null;
|
|
6789
|
+
}
|
|
6454
6790
|
log$4.info({
|
|
6455
6791
|
version: desired.version,
|
|
6456
6792
|
keys: entries.length
|
|
@@ -6461,11 +6797,21 @@ var ConfigReconciler = class {
|
|
|
6461
6797
|
};
|
|
6462
6798
|
}
|
|
6463
6799
|
async verify(getConfigRaw, key, want) {
|
|
6800
|
+
let observedValue = false;
|
|
6464
6801
|
for (let attempt = 0; attempt <= this.verifyRetries; attempt++) {
|
|
6465
|
-
|
|
6802
|
+
try {
|
|
6803
|
+
const current = await getConfigRaw(key);
|
|
6804
|
+
if (current === want) return "matched";
|
|
6805
|
+
if (current !== void 0) observedValue = true;
|
|
6806
|
+
} catch (err) {
|
|
6807
|
+
log$4.debug({
|
|
6808
|
+
key,
|
|
6809
|
+
err: err instanceof Error ? err.message : String(err)
|
|
6810
|
+
}, "Config verify read failed");
|
|
6811
|
+
}
|
|
6466
6812
|
if (attempt < this.verifyRetries && this.verifyRetryDelayMs > 0) await delay(this.verifyRetryDelayMs * 2 ** attempt);
|
|
6467
6813
|
}
|
|
6468
|
-
return
|
|
6814
|
+
return observedValue ? "mismatched" : "inconclusive";
|
|
6469
6815
|
}
|
|
6470
6816
|
};
|
|
6471
6817
|
//#endregion
|
|
@@ -7735,7 +8081,7 @@ function warnFailedMcpServers(bundler, log, reason) {
|
|
|
7735
8081
|
* List every server entry in the alfe bundler store. Lets agents inspect
|
|
7736
8082
|
* what they've already registered before adding a new one.
|
|
7737
8083
|
*/
|
|
7738
|
-
function handleMcpListServers(manager) {
|
|
8084
|
+
function handleMcpListServers(manager, liveStatusAvailable = manager?.serverStatuses !== void 0) {
|
|
7739
8085
|
if (!manager) return {
|
|
7740
8086
|
ok: false,
|
|
7741
8087
|
error: {
|
|
@@ -7743,21 +8089,24 @@ function handleMcpListServers(manager) {
|
|
|
7743
8089
|
message: "MCP manager not initialized"
|
|
7744
8090
|
}
|
|
7745
8091
|
};
|
|
7746
|
-
const statuses = manager.serverStatuses ? manager.serverStatuses() : [];
|
|
8092
|
+
const statuses = liveStatusAvailable && manager.serverStatuses ? manager.serverStatuses() : [];
|
|
7747
8093
|
const byName = new Map(statuses.map((s) => [s.name, s]));
|
|
7748
8094
|
return {
|
|
7749
8095
|
ok: true,
|
|
7750
|
-
payload: { servers: manager.listServers().map(({ id, entry }) =>
|
|
7751
|
-
id
|
|
7752
|
-
|
|
7753
|
-
|
|
7754
|
-
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
|
|
7758
|
-
|
|
7759
|
-
|
|
7760
|
-
|
|
8096
|
+
payload: { servers: manager.listServers().map(({ id, entry }) => {
|
|
8097
|
+
const status = byName.get(id);
|
|
8098
|
+
return {
|
|
8099
|
+
id,
|
|
8100
|
+
entry: toPublicServerEntry(entry),
|
|
8101
|
+
fingerprint: serverLaunchFingerprint(entry),
|
|
8102
|
+
...liveStatusAvailable ? { status: status ?? {
|
|
8103
|
+
name: id,
|
|
8104
|
+
connected: false,
|
|
8105
|
+
toolCount: 0,
|
|
8106
|
+
consecutiveFailures: 0
|
|
8107
|
+
} } : {}
|
|
8108
|
+
};
|
|
8109
|
+
}) }
|
|
7761
8110
|
};
|
|
7762
8111
|
}
|
|
7763
8112
|
function toPublicServerEntry(entry) {
|
|
@@ -7786,10 +8135,12 @@ const MCP_ADD_WARM_TIMEOUT_MS = 12e3;
|
|
|
7786
8135
|
* server actually works. Owned as `'manual'` so the agent can later remove it
|
|
7787
8136
|
* without an expectedOwner conflict — matches what `alfe mcp add` does from the
|
|
7788
8137
|
* CLI. Registration is durable regardless of the probe outcome: a probe
|
|
7789
|
-
* failure
|
|
7790
|
-
*
|
|
8138
|
+
* failure still returns `ok`; the store watcher / runtime picks the entry up.
|
|
8139
|
+
* A runtime that mirrors the store but owns its MCP children (Hermes and
|
|
8140
|
+
* Claude Code) has no daemon-side status authority, so it omits connected/tool
|
|
8141
|
+
* fields instead of presenting unknown as a definite disconnection.
|
|
7791
8142
|
*/
|
|
7792
|
-
async function handleMcpAddServer(params, manager) {
|
|
8143
|
+
async function handleMcpAddServer(params, manager, liveStatusAvailable = manager?.warmServer !== void 0) {
|
|
7793
8144
|
if (!manager) return {
|
|
7794
8145
|
ok: false,
|
|
7795
8146
|
error: {
|
|
@@ -7833,7 +8184,7 @@ async function handleMcpAddServer(params, manager) {
|
|
|
7833
8184
|
};
|
|
7834
8185
|
}
|
|
7835
8186
|
let status = null;
|
|
7836
|
-
if (manager.warmServer) try {
|
|
8187
|
+
if (liveStatusAvailable && manager.warmServer) try {
|
|
7837
8188
|
status = await manager.warmServer(p.id, MCP_ADD_WARM_TIMEOUT_MS);
|
|
7838
8189
|
} catch (err) {
|
|
7839
8190
|
logger$1.warn({
|
|
@@ -7845,9 +8196,11 @@ async function handleMcpAddServer(params, manager) {
|
|
|
7845
8196
|
ok: true,
|
|
7846
8197
|
payload: {
|
|
7847
8198
|
id: p.id,
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
8199
|
+
...status ? {
|
|
8200
|
+
connected: status.connected,
|
|
8201
|
+
toolCount: status.toolCount,
|
|
8202
|
+
...status.lastError !== void 0 ? { error: status.lastError } : {}
|
|
8203
|
+
} : {}
|
|
7851
8204
|
}
|
|
7852
8205
|
};
|
|
7853
8206
|
}
|
|
@@ -25076,8 +25429,8 @@ function handlePluginRequest(method, params, pluginId) {
|
|
|
25076
25429
|
case "integration.report": return Promise.resolve(handleIntegrationReport(params, pluginId));
|
|
25077
25430
|
case "mcp.list_tools": return Promise.resolve(handleMcpListTools(mcpBundler));
|
|
25078
25431
|
case "mcp.call_tool": return handleMcpCallTool(mcpBundler, params);
|
|
25079
|
-
case "mcp.list_servers": return Promise.resolve(handleMcpListServers(mcpManagerRef));
|
|
25080
|
-
case "mcp.add_server": return handleMcpAddServer(params, mcpManagerRef);
|
|
25432
|
+
case "mcp.list_servers": return Promise.resolve(handleMcpListServers(mcpManagerRef, mcpBundler !== null));
|
|
25433
|
+
case "mcp.add_server": return handleMcpAddServer(params, mcpManagerRef, mcpBundler !== null);
|
|
25081
25434
|
case "mcp.remove_server": return handleMcpRemoveServer(params, mcpManagerRef);
|
|
25082
25435
|
default: return Promise.resolve({
|
|
25083
25436
|
ok: false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alfe.ai/gateway",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.12",
|
|
4
4
|
"description": "Alfe local gateway daemon — persistent control plane for agent integrations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"pino-roll": "^1.2.0",
|
|
24
24
|
"smol-toml": ">=1.6.1",
|
|
25
25
|
"ws": "^8.18.0",
|
|
26
|
-
"@alfe.ai/agent-api-client": "^0.
|
|
26
|
+
"@alfe.ai/agent-api-client": "^0.17.0",
|
|
27
27
|
"@alfe.ai/ai-proxy-local": "^0.0.16",
|
|
28
28
|
"@alfe.ai/config": "^0.4.1",
|
|
29
29
|
"@alfe.ai/integration-manifest": "^0.3.6",
|