@frontmcp/testing 1.9.1 → 1.9.3
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/esm/fixtures/index.mjs +40 -0
- package/esm/index.mjs +40 -0
- package/esm/package.json +6 -6
- package/esm/perf/index.mjs +39 -0
- package/fixtures/fixture-types.d.ts +4 -1
- package/fixtures/fixture-types.d.ts.map +1 -1
- package/fixtures/index.js +40 -0
- package/fixtures/test-fixture.d.ts.map +1 -1
- package/index.js +40 -0
- package/package.json +6 -6
- package/perf/index.js +39 -0
- package/server/port-registry.d.ts +1 -0
- package/server/port-registry.d.ts.map +1 -1
- package/server/test-server.d.ts +5 -0
- package/server/test-server.d.ts.map +1 -1
package/esm/fixtures/index.mjs
CHANGED
|
@@ -2989,6 +2989,7 @@ var ProgressCollector = class {
|
|
|
2989
2989
|
|
|
2990
2990
|
// libs/testing/src/server/test-server.ts
|
|
2991
2991
|
import { execFile, spawn } from "child_process";
|
|
2992
|
+
import { connect } from "net";
|
|
2992
2993
|
import { sha256Hex } from "@frontmcp/utils";
|
|
2993
2994
|
|
|
2994
2995
|
// libs/testing/src/errors/index.ts
|
|
@@ -3217,6 +3218,7 @@ async function releasePort(port) {
|
|
|
3217
3218
|
}
|
|
3218
3219
|
|
|
3219
3220
|
// libs/testing/src/server/test-server.ts
|
|
3221
|
+
var SERVER_EXIT_TIMEOUT_MS = 12e3;
|
|
3220
3222
|
var DEBUG_SERVER = process.env["DEBUG_SERVER"] === "1" || process.env["DEBUG"] === "1";
|
|
3221
3223
|
var TestServer = class _TestServer {
|
|
3222
3224
|
process = null;
|
|
@@ -3372,9 +3374,12 @@ var TestServer = class _TestServer {
|
|
|
3372
3374
|
async stopProcess() {
|
|
3373
3375
|
if (this.process) {
|
|
3374
3376
|
this.log("Stopping server...");
|
|
3377
|
+
const serverPid = this._info.pid !== this._info.shellPid ? this._info.pid : void 0;
|
|
3375
3378
|
if (this.process.exitCode !== null || this.process.signalCode !== null) {
|
|
3376
3379
|
this.log(`Server already exited (code: ${this.process.exitCode}, signal: ${this.process.signalCode})`);
|
|
3377
3380
|
this.process = null;
|
|
3381
|
+
if (serverPid !== void 0) signalIfRunning(serverPid, "SIGTERM");
|
|
3382
|
+
await this.waitForServerGone(serverPid);
|
|
3378
3383
|
return;
|
|
3379
3384
|
}
|
|
3380
3385
|
const pid = this.process.pid;
|
|
@@ -3412,9 +3417,26 @@ var TestServer = class _TestServer {
|
|
|
3412
3417
|
await exitPromise;
|
|
3413
3418
|
clearTimeout(killTimeout);
|
|
3414
3419
|
this.process = null;
|
|
3420
|
+
await this.waitForServerGone(serverPid);
|
|
3415
3421
|
this.log("Server stopped");
|
|
3416
3422
|
}
|
|
3417
3423
|
}
|
|
3424
|
+
/**
|
|
3425
|
+
* Wait until the server process has exited and its port refuses connections. A server that
|
|
3426
|
+
* drains on SIGTERM can keep listening after the shell it was started through has exited.
|
|
3427
|
+
*/
|
|
3428
|
+
async waitForServerGone(serverPid) {
|
|
3429
|
+
const deadline = Date.now() + SERVER_EXIT_TIMEOUT_MS;
|
|
3430
|
+
while (Date.now() < deadline) {
|
|
3431
|
+
const serverRunning = serverPid !== void 0 && pidIsAlive(serverPid);
|
|
3432
|
+
if (!serverRunning && !await acceptsConnections(this._info.port)) return;
|
|
3433
|
+
await sleep2(100);
|
|
3434
|
+
}
|
|
3435
|
+
if (serverPid !== void 0 && pidIsAlive(serverPid)) {
|
|
3436
|
+
this.log("Force killing server process after timeout...");
|
|
3437
|
+
signalIfRunning(serverPid, "SIGKILL");
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3418
3440
|
/**
|
|
3419
3441
|
* Wait for server to be ready
|
|
3420
3442
|
*/
|
|
@@ -3634,6 +3656,23 @@ TIP: Set DEBUG_SERVER=1 or DEBUG=1 environment variable for verbose output`
|
|
|
3634
3656
|
function sleep2(ms) {
|
|
3635
3657
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3636
3658
|
}
|
|
3659
|
+
function signalIfRunning(pid, signal) {
|
|
3660
|
+
try {
|
|
3661
|
+
process.kill(pid, signal);
|
|
3662
|
+
} catch (error) {
|
|
3663
|
+
if (error.code !== "ESRCH") throw error;
|
|
3664
|
+
}
|
|
3665
|
+
}
|
|
3666
|
+
function acceptsConnections(port) {
|
|
3667
|
+
return new Promise((resolve) => {
|
|
3668
|
+
const socket = connect(port, "127.0.0.1");
|
|
3669
|
+
socket.once("connect", () => {
|
|
3670
|
+
socket.destroy();
|
|
3671
|
+
resolve(true);
|
|
3672
|
+
});
|
|
3673
|
+
socket.once("error", () => resolve(false));
|
|
3674
|
+
});
|
|
3675
|
+
}
|
|
3637
3676
|
function findListeningPid(port) {
|
|
3638
3677
|
if (process.platform === "win32") return Promise.resolve(void 0);
|
|
3639
3678
|
return new Promise((resolve) => {
|
|
@@ -3831,6 +3870,7 @@ function serverKey(config) {
|
|
|
3831
3870
|
}
|
|
3832
3871
|
function serverEnv(config) {
|
|
3833
3872
|
const extra = {};
|
|
3873
|
+
if (config.logLevel) extra["FRONTMCP_LOG_LEVEL"] = config.logLevel;
|
|
3834
3874
|
if (config.auth?.mode) extra["FRONTMCP_TEST_AUTH_MODE"] = config.auth.mode;
|
|
3835
3875
|
if (config.auth?.type) extra["FRONTMCP_TEST_AUTH_TYPE"] = config.auth.type;
|
|
3836
3876
|
if (Object.keys(extra).length === 0 && !config.env) return void 0;
|
package/esm/index.mjs
CHANGED
|
@@ -4567,6 +4567,7 @@ var MockCimdServer = class {
|
|
|
4567
4567
|
|
|
4568
4568
|
// libs/testing/src/server/test-server.ts
|
|
4569
4569
|
import { execFile, spawn } from "child_process";
|
|
4570
|
+
import { connect } from "net";
|
|
4570
4571
|
import { sha256Hex } from "@frontmcp/utils";
|
|
4571
4572
|
|
|
4572
4573
|
// libs/testing/src/errors/index.ts
|
|
@@ -4831,6 +4832,7 @@ async function releasePort(port) {
|
|
|
4831
4832
|
}
|
|
4832
4833
|
|
|
4833
4834
|
// libs/testing/src/server/test-server.ts
|
|
4835
|
+
var SERVER_EXIT_TIMEOUT_MS = 12e3;
|
|
4834
4836
|
var DEBUG_SERVER = process.env["DEBUG_SERVER"] === "1" || process.env["DEBUG"] === "1";
|
|
4835
4837
|
var TestServer = class _TestServer {
|
|
4836
4838
|
process = null;
|
|
@@ -4986,9 +4988,12 @@ var TestServer = class _TestServer {
|
|
|
4986
4988
|
async stopProcess() {
|
|
4987
4989
|
if (this.process) {
|
|
4988
4990
|
this.log("Stopping server...");
|
|
4991
|
+
const serverPid = this._info.pid !== this._info.shellPid ? this._info.pid : void 0;
|
|
4989
4992
|
if (this.process.exitCode !== null || this.process.signalCode !== null) {
|
|
4990
4993
|
this.log(`Server already exited (code: ${this.process.exitCode}, signal: ${this.process.signalCode})`);
|
|
4991
4994
|
this.process = null;
|
|
4995
|
+
if (serverPid !== void 0) signalIfRunning(serverPid, "SIGTERM");
|
|
4996
|
+
await this.waitForServerGone(serverPid);
|
|
4992
4997
|
return;
|
|
4993
4998
|
}
|
|
4994
4999
|
const pid = this.process.pid;
|
|
@@ -5026,9 +5031,26 @@ var TestServer = class _TestServer {
|
|
|
5026
5031
|
await exitPromise;
|
|
5027
5032
|
clearTimeout(killTimeout);
|
|
5028
5033
|
this.process = null;
|
|
5034
|
+
await this.waitForServerGone(serverPid);
|
|
5029
5035
|
this.log("Server stopped");
|
|
5030
5036
|
}
|
|
5031
5037
|
}
|
|
5038
|
+
/**
|
|
5039
|
+
* Wait until the server process has exited and its port refuses connections. A server that
|
|
5040
|
+
* drains on SIGTERM can keep listening after the shell it was started through has exited.
|
|
5041
|
+
*/
|
|
5042
|
+
async waitForServerGone(serverPid) {
|
|
5043
|
+
const deadline = Date.now() + SERVER_EXIT_TIMEOUT_MS;
|
|
5044
|
+
while (Date.now() < deadline) {
|
|
5045
|
+
const serverRunning = serverPid !== void 0 && pidIsAlive(serverPid);
|
|
5046
|
+
if (!serverRunning && !await acceptsConnections(this._info.port)) return;
|
|
5047
|
+
await sleep2(100);
|
|
5048
|
+
}
|
|
5049
|
+
if (serverPid !== void 0 && pidIsAlive(serverPid)) {
|
|
5050
|
+
this.log("Force killing server process after timeout...");
|
|
5051
|
+
signalIfRunning(serverPid, "SIGKILL");
|
|
5052
|
+
}
|
|
5053
|
+
}
|
|
5032
5054
|
/**
|
|
5033
5055
|
* Wait for server to be ready
|
|
5034
5056
|
*/
|
|
@@ -5248,6 +5270,23 @@ TIP: Set DEBUG_SERVER=1 or DEBUG=1 environment variable for verbose output`
|
|
|
5248
5270
|
function sleep2(ms) {
|
|
5249
5271
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
5250
5272
|
}
|
|
5273
|
+
function signalIfRunning(pid, signal) {
|
|
5274
|
+
try {
|
|
5275
|
+
process.kill(pid, signal);
|
|
5276
|
+
} catch (error) {
|
|
5277
|
+
if (error.code !== "ESRCH") throw error;
|
|
5278
|
+
}
|
|
5279
|
+
}
|
|
5280
|
+
function acceptsConnections(port) {
|
|
5281
|
+
return new Promise((resolve) => {
|
|
5282
|
+
const socket = connect(port, "127.0.0.1");
|
|
5283
|
+
socket.once("connect", () => {
|
|
5284
|
+
socket.destroy();
|
|
5285
|
+
resolve(true);
|
|
5286
|
+
});
|
|
5287
|
+
socket.once("error", () => resolve(false));
|
|
5288
|
+
});
|
|
5289
|
+
}
|
|
5251
5290
|
function findListeningPid(port) {
|
|
5252
5291
|
if (process.platform === "win32") return Promise.resolve(void 0);
|
|
5253
5292
|
return new Promise((resolve) => {
|
|
@@ -5610,6 +5649,7 @@ function serverKey(config) {
|
|
|
5610
5649
|
}
|
|
5611
5650
|
function serverEnv(config) {
|
|
5612
5651
|
const extra = {};
|
|
5652
|
+
if (config.logLevel) extra["FRONTMCP_LOG_LEVEL"] = config.logLevel;
|
|
5613
5653
|
if (config.auth?.mode) extra["FRONTMCP_TEST_AUTH_MODE"] = config.auth.mode;
|
|
5614
5654
|
if (config.auth?.type) extra["FRONTMCP_TEST_AUTH_TYPE"] = config.auth.type;
|
|
5615
5655
|
if (Object.keys(extra).length === 0 && !config.env) return void 0;
|
package/esm/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/testing",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.3",
|
|
4
4
|
"description": "E2E testing framework for FrontMCP servers - MCP client, auth mocks, Playwright integration",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"homepage": "https://docs.agentfront.dev",
|
|
@@ -87,9 +87,9 @@
|
|
|
87
87
|
"./esm": null
|
|
88
88
|
},
|
|
89
89
|
"peerDependencies": {
|
|
90
|
-
"@frontmcp/lazy-zod": "1.9.
|
|
91
|
-
"@frontmcp/sdk": "1.9.
|
|
92
|
-
"@frontmcp/ui": "1.9.
|
|
90
|
+
"@frontmcp/lazy-zod": "1.9.3",
|
|
91
|
+
"@frontmcp/sdk": "1.9.3",
|
|
92
|
+
"@frontmcp/ui": "1.9.3",
|
|
93
93
|
"@jest/globals": "^29.0.0 || ^30.0.0",
|
|
94
94
|
"@playwright/test": "^1.40.0",
|
|
95
95
|
"jest": "^29.0.0 || ^30.0.0"
|
|
@@ -112,8 +112,8 @@
|
|
|
112
112
|
"node": ">=24.0.0"
|
|
113
113
|
},
|
|
114
114
|
"dependencies": {
|
|
115
|
-
"@frontmcp/protocol": "1.9.
|
|
116
|
-
"@frontmcp/utils": "1.9.
|
|
115
|
+
"@frontmcp/protocol": "1.9.3",
|
|
116
|
+
"@frontmcp/utils": "1.9.3",
|
|
117
117
|
"@swc/core": "~1.15.41",
|
|
118
118
|
"@swc/jest": "~0.2.38",
|
|
119
119
|
"jose": "^6.0.11",
|
package/esm/perf/index.mjs
CHANGED
|
@@ -3756,6 +3756,7 @@ var ProgressCollector = class {
|
|
|
3756
3756
|
|
|
3757
3757
|
// libs/testing/src/server/test-server.ts
|
|
3758
3758
|
import { execFile, spawn } from "child_process";
|
|
3759
|
+
import { connect } from "net";
|
|
3759
3760
|
import { sha256Hex } from "@frontmcp/utils";
|
|
3760
3761
|
|
|
3761
3762
|
// libs/testing/src/errors/index.ts
|
|
@@ -3984,6 +3985,7 @@ async function releasePort(port) {
|
|
|
3984
3985
|
}
|
|
3985
3986
|
|
|
3986
3987
|
// libs/testing/src/server/test-server.ts
|
|
3988
|
+
var SERVER_EXIT_TIMEOUT_MS = 12e3;
|
|
3987
3989
|
var DEBUG_SERVER = process.env["DEBUG_SERVER"] === "1" || process.env["DEBUG"] === "1";
|
|
3988
3990
|
var TestServer = class _TestServer {
|
|
3989
3991
|
process = null;
|
|
@@ -4139,9 +4141,12 @@ var TestServer = class _TestServer {
|
|
|
4139
4141
|
async stopProcess() {
|
|
4140
4142
|
if (this.process) {
|
|
4141
4143
|
this.log("Stopping server...");
|
|
4144
|
+
const serverPid = this._info.pid !== this._info.shellPid ? this._info.pid : void 0;
|
|
4142
4145
|
if (this.process.exitCode !== null || this.process.signalCode !== null) {
|
|
4143
4146
|
this.log(`Server already exited (code: ${this.process.exitCode}, signal: ${this.process.signalCode})`);
|
|
4144
4147
|
this.process = null;
|
|
4148
|
+
if (serverPid !== void 0) signalIfRunning(serverPid, "SIGTERM");
|
|
4149
|
+
await this.waitForServerGone(serverPid);
|
|
4145
4150
|
return;
|
|
4146
4151
|
}
|
|
4147
4152
|
const pid = this.process.pid;
|
|
@@ -4179,9 +4184,26 @@ var TestServer = class _TestServer {
|
|
|
4179
4184
|
await exitPromise;
|
|
4180
4185
|
clearTimeout(killTimeout);
|
|
4181
4186
|
this.process = null;
|
|
4187
|
+
await this.waitForServerGone(serverPid);
|
|
4182
4188
|
this.log("Server stopped");
|
|
4183
4189
|
}
|
|
4184
4190
|
}
|
|
4191
|
+
/**
|
|
4192
|
+
* Wait until the server process has exited and its port refuses connections. A server that
|
|
4193
|
+
* drains on SIGTERM can keep listening after the shell it was started through has exited.
|
|
4194
|
+
*/
|
|
4195
|
+
async waitForServerGone(serverPid) {
|
|
4196
|
+
const deadline = Date.now() + SERVER_EXIT_TIMEOUT_MS;
|
|
4197
|
+
while (Date.now() < deadline) {
|
|
4198
|
+
const serverRunning = serverPid !== void 0 && pidIsAlive(serverPid);
|
|
4199
|
+
if (!serverRunning && !await acceptsConnections(this._info.port)) return;
|
|
4200
|
+
await sleep4(100);
|
|
4201
|
+
}
|
|
4202
|
+
if (serverPid !== void 0 && pidIsAlive(serverPid)) {
|
|
4203
|
+
this.log("Force killing server process after timeout...");
|
|
4204
|
+
signalIfRunning(serverPid, "SIGKILL");
|
|
4205
|
+
}
|
|
4206
|
+
}
|
|
4185
4207
|
/**
|
|
4186
4208
|
* Wait for server to be ready
|
|
4187
4209
|
*/
|
|
@@ -4401,6 +4423,23 @@ TIP: Set DEBUG_SERVER=1 or DEBUG=1 environment variable for verbose output`
|
|
|
4401
4423
|
function sleep4(ms) {
|
|
4402
4424
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4403
4425
|
}
|
|
4426
|
+
function signalIfRunning(pid, signal) {
|
|
4427
|
+
try {
|
|
4428
|
+
process.kill(pid, signal);
|
|
4429
|
+
} catch (error) {
|
|
4430
|
+
if (error.code !== "ESRCH") throw error;
|
|
4431
|
+
}
|
|
4432
|
+
}
|
|
4433
|
+
function acceptsConnections(port) {
|
|
4434
|
+
return new Promise((resolve) => {
|
|
4435
|
+
const socket = connect(port, "127.0.0.1");
|
|
4436
|
+
socket.once("connect", () => {
|
|
4437
|
+
socket.destroy();
|
|
4438
|
+
resolve(true);
|
|
4439
|
+
});
|
|
4440
|
+
socket.once("error", () => resolve(false));
|
|
4441
|
+
});
|
|
4442
|
+
}
|
|
4404
4443
|
function findListeningPid(port) {
|
|
4405
4444
|
if (process.platform === "win32") return Promise.resolve(void 0);
|
|
4406
4445
|
return new Promise((resolve) => {
|
|
@@ -40,7 +40,10 @@ export interface TestConfig {
|
|
|
40
40
|
* Use this for testing servers configured with `auth: { mode: 'public' }`.
|
|
41
41
|
*/
|
|
42
42
|
publicMode?: boolean;
|
|
43
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* The booted server's log level (`FRONTMCP_LOG_LEVEL`), for a server whose `logging.level` isn't set.
|
|
45
|
+
* `debug` also prints the server's command and output.
|
|
46
|
+
*/
|
|
44
47
|
logLevel?: 'debug' | 'info' | 'warn' | 'error';
|
|
45
48
|
/** Environment variables to pass to the server */
|
|
46
49
|
env?: Record<string, string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fixture-types.d.ts","sourceRoot":"","sources":["../../src/fixtures/fixture-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAEhC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAM9E;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8FAA8F;IAC9F,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,SAAS,CAAC,EAAE,KAAK,GAAG,iBAAiB,CAAC;IACtC;;;;;OAKG;IACH,IAAI,CAAC,EAAE;QACL,IAAI,CAAC,EAAE,QAAQ,GAAG,cAAc,GAAG,OAAO,GAAG,QAAQ,GAAG,aAAa,CAAC;QACtE,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;KAC3B,CAAC;IACF;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB
|
|
1
|
+
{"version":3,"file":"fixture-types.d.ts","sourceRoot":"","sources":["../../src/fixtures/fixture-types.ts"],"names":[],"mappings":"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"}
|
package/fixtures/index.js
CHANGED
|
@@ -3009,6 +3009,7 @@ var ProgressCollector = class {
|
|
|
3009
3009
|
|
|
3010
3010
|
// libs/testing/src/server/test-server.ts
|
|
3011
3011
|
var import_child_process = require("child_process");
|
|
3012
|
+
var import_net2 = require("net");
|
|
3012
3013
|
var import_utils = require("@frontmcp/utils");
|
|
3013
3014
|
|
|
3014
3015
|
// libs/testing/src/errors/index.ts
|
|
@@ -3237,6 +3238,7 @@ async function releasePort(port) {
|
|
|
3237
3238
|
}
|
|
3238
3239
|
|
|
3239
3240
|
// libs/testing/src/server/test-server.ts
|
|
3241
|
+
var SERVER_EXIT_TIMEOUT_MS = 12e3;
|
|
3240
3242
|
var DEBUG_SERVER = process.env["DEBUG_SERVER"] === "1" || process.env["DEBUG"] === "1";
|
|
3241
3243
|
var TestServer = class _TestServer {
|
|
3242
3244
|
process = null;
|
|
@@ -3392,9 +3394,12 @@ var TestServer = class _TestServer {
|
|
|
3392
3394
|
async stopProcess() {
|
|
3393
3395
|
if (this.process) {
|
|
3394
3396
|
this.log("Stopping server...");
|
|
3397
|
+
const serverPid = this._info.pid !== this._info.shellPid ? this._info.pid : void 0;
|
|
3395
3398
|
if (this.process.exitCode !== null || this.process.signalCode !== null) {
|
|
3396
3399
|
this.log(`Server already exited (code: ${this.process.exitCode}, signal: ${this.process.signalCode})`);
|
|
3397
3400
|
this.process = null;
|
|
3401
|
+
if (serverPid !== void 0) signalIfRunning(serverPid, "SIGTERM");
|
|
3402
|
+
await this.waitForServerGone(serverPid);
|
|
3398
3403
|
return;
|
|
3399
3404
|
}
|
|
3400
3405
|
const pid = this.process.pid;
|
|
@@ -3432,9 +3437,26 @@ var TestServer = class _TestServer {
|
|
|
3432
3437
|
await exitPromise;
|
|
3433
3438
|
clearTimeout(killTimeout);
|
|
3434
3439
|
this.process = null;
|
|
3440
|
+
await this.waitForServerGone(serverPid);
|
|
3435
3441
|
this.log("Server stopped");
|
|
3436
3442
|
}
|
|
3437
3443
|
}
|
|
3444
|
+
/**
|
|
3445
|
+
* Wait until the server process has exited and its port refuses connections. A server that
|
|
3446
|
+
* drains on SIGTERM can keep listening after the shell it was started through has exited.
|
|
3447
|
+
*/
|
|
3448
|
+
async waitForServerGone(serverPid) {
|
|
3449
|
+
const deadline = Date.now() + SERVER_EXIT_TIMEOUT_MS;
|
|
3450
|
+
while (Date.now() < deadline) {
|
|
3451
|
+
const serverRunning = serverPid !== void 0 && pidIsAlive(serverPid);
|
|
3452
|
+
if (!serverRunning && !await acceptsConnections(this._info.port)) return;
|
|
3453
|
+
await sleep2(100);
|
|
3454
|
+
}
|
|
3455
|
+
if (serverPid !== void 0 && pidIsAlive(serverPid)) {
|
|
3456
|
+
this.log("Force killing server process after timeout...");
|
|
3457
|
+
signalIfRunning(serverPid, "SIGKILL");
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3438
3460
|
/**
|
|
3439
3461
|
* Wait for server to be ready
|
|
3440
3462
|
*/
|
|
@@ -3654,6 +3676,23 @@ TIP: Set DEBUG_SERVER=1 or DEBUG=1 environment variable for verbose output`
|
|
|
3654
3676
|
function sleep2(ms) {
|
|
3655
3677
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3656
3678
|
}
|
|
3679
|
+
function signalIfRunning(pid, signal) {
|
|
3680
|
+
try {
|
|
3681
|
+
process.kill(pid, signal);
|
|
3682
|
+
} catch (error) {
|
|
3683
|
+
if (error.code !== "ESRCH") throw error;
|
|
3684
|
+
}
|
|
3685
|
+
}
|
|
3686
|
+
function acceptsConnections(port) {
|
|
3687
|
+
return new Promise((resolve) => {
|
|
3688
|
+
const socket = (0, import_net2.connect)(port, "127.0.0.1");
|
|
3689
|
+
socket.once("connect", () => {
|
|
3690
|
+
socket.destroy();
|
|
3691
|
+
resolve(true);
|
|
3692
|
+
});
|
|
3693
|
+
socket.once("error", () => resolve(false));
|
|
3694
|
+
});
|
|
3695
|
+
}
|
|
3657
3696
|
function findListeningPid(port) {
|
|
3658
3697
|
if (process.platform === "win32") return Promise.resolve(void 0);
|
|
3659
3698
|
return new Promise((resolve) => {
|
|
@@ -3851,6 +3890,7 @@ function serverKey(config) {
|
|
|
3851
3890
|
}
|
|
3852
3891
|
function serverEnv(config) {
|
|
3853
3892
|
const extra = {};
|
|
3893
|
+
if (config.logLevel) extra["FRONTMCP_LOG_LEVEL"] = config.logLevel;
|
|
3854
3894
|
if (config.auth?.mode) extra["FRONTMCP_TEST_AUTH_MODE"] = config.auth.mode;
|
|
3855
3895
|
if (config.auth?.type) extra["FRONTMCP_TEST_AUTH_TYPE"] = config.auth.type;
|
|
3856
3896
|
if (Object.keys(extra).length === 0 && !config.env) return void 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-fixture.d.ts","sourceRoot":"","sources":["../../src/fixtures/test-fixture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAMH,OAAO,KAAK,EAIV,YAAY,EAGZ,gBAAgB,EACjB,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"test-fixture.d.ts","sourceRoot":"","sources":["../../src/fixtures/test-fixture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAMH,OAAO,KAAK,EAIV,YAAY,EAGZ,gBAAgB,EACjB,MAAM,iBAAiB,CAAC;AAyTzB;;;GAGG;AACH,iBAAe,kBAAkB,IAAI,OAAO,CAAC,YAAY,CAAC,CAEzD;AAED;;GAEG;AACH,iBAAe,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC,CAExD;AAED;;;;GAIG;AACH,iBAAe,mBAAmB,CAAC,QAAQ,EAAE,YAAY,EAAE,UAAU,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA2B5F;AAED;;GAEG;AACH,iBAAe,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAErD;AA2YD,QAAA,MAAM,IAAI,EAAuB,gBAAgB,CAAC;AAsBlD,OAAO,EAAE,IAAI,EAAE,CAAC;AAGhB,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,CAAC"}
|
package/index.js
CHANGED
|
@@ -4684,6 +4684,7 @@ var MockCimdServer = class {
|
|
|
4684
4684
|
|
|
4685
4685
|
// libs/testing/src/server/test-server.ts
|
|
4686
4686
|
var import_child_process = require("child_process");
|
|
4687
|
+
var import_net2 = require("net");
|
|
4687
4688
|
var import_utils2 = require("@frontmcp/utils");
|
|
4688
4689
|
|
|
4689
4690
|
// libs/testing/src/errors/index.ts
|
|
@@ -4948,6 +4949,7 @@ async function releasePort(port) {
|
|
|
4948
4949
|
}
|
|
4949
4950
|
|
|
4950
4951
|
// libs/testing/src/server/test-server.ts
|
|
4952
|
+
var SERVER_EXIT_TIMEOUT_MS = 12e3;
|
|
4951
4953
|
var DEBUG_SERVER = process.env["DEBUG_SERVER"] === "1" || process.env["DEBUG"] === "1";
|
|
4952
4954
|
var TestServer = class _TestServer {
|
|
4953
4955
|
process = null;
|
|
@@ -5103,9 +5105,12 @@ var TestServer = class _TestServer {
|
|
|
5103
5105
|
async stopProcess() {
|
|
5104
5106
|
if (this.process) {
|
|
5105
5107
|
this.log("Stopping server...");
|
|
5108
|
+
const serverPid = this._info.pid !== this._info.shellPid ? this._info.pid : void 0;
|
|
5106
5109
|
if (this.process.exitCode !== null || this.process.signalCode !== null) {
|
|
5107
5110
|
this.log(`Server already exited (code: ${this.process.exitCode}, signal: ${this.process.signalCode})`);
|
|
5108
5111
|
this.process = null;
|
|
5112
|
+
if (serverPid !== void 0) signalIfRunning(serverPid, "SIGTERM");
|
|
5113
|
+
await this.waitForServerGone(serverPid);
|
|
5109
5114
|
return;
|
|
5110
5115
|
}
|
|
5111
5116
|
const pid = this.process.pid;
|
|
@@ -5143,9 +5148,26 @@ var TestServer = class _TestServer {
|
|
|
5143
5148
|
await exitPromise;
|
|
5144
5149
|
clearTimeout(killTimeout);
|
|
5145
5150
|
this.process = null;
|
|
5151
|
+
await this.waitForServerGone(serverPid);
|
|
5146
5152
|
this.log("Server stopped");
|
|
5147
5153
|
}
|
|
5148
5154
|
}
|
|
5155
|
+
/**
|
|
5156
|
+
* Wait until the server process has exited and its port refuses connections. A server that
|
|
5157
|
+
* drains on SIGTERM can keep listening after the shell it was started through has exited.
|
|
5158
|
+
*/
|
|
5159
|
+
async waitForServerGone(serverPid) {
|
|
5160
|
+
const deadline = Date.now() + SERVER_EXIT_TIMEOUT_MS;
|
|
5161
|
+
while (Date.now() < deadline) {
|
|
5162
|
+
const serverRunning = serverPid !== void 0 && pidIsAlive(serverPid);
|
|
5163
|
+
if (!serverRunning && !await acceptsConnections(this._info.port)) return;
|
|
5164
|
+
await sleep2(100);
|
|
5165
|
+
}
|
|
5166
|
+
if (serverPid !== void 0 && pidIsAlive(serverPid)) {
|
|
5167
|
+
this.log("Force killing server process after timeout...");
|
|
5168
|
+
signalIfRunning(serverPid, "SIGKILL");
|
|
5169
|
+
}
|
|
5170
|
+
}
|
|
5149
5171
|
/**
|
|
5150
5172
|
* Wait for server to be ready
|
|
5151
5173
|
*/
|
|
@@ -5365,6 +5387,23 @@ TIP: Set DEBUG_SERVER=1 or DEBUG=1 environment variable for verbose output`
|
|
|
5365
5387
|
function sleep2(ms) {
|
|
5366
5388
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
5367
5389
|
}
|
|
5390
|
+
function signalIfRunning(pid, signal) {
|
|
5391
|
+
try {
|
|
5392
|
+
process.kill(pid, signal);
|
|
5393
|
+
} catch (error) {
|
|
5394
|
+
if (error.code !== "ESRCH") throw error;
|
|
5395
|
+
}
|
|
5396
|
+
}
|
|
5397
|
+
function acceptsConnections(port) {
|
|
5398
|
+
return new Promise((resolve) => {
|
|
5399
|
+
const socket = (0, import_net2.connect)(port, "127.0.0.1");
|
|
5400
|
+
socket.once("connect", () => {
|
|
5401
|
+
socket.destroy();
|
|
5402
|
+
resolve(true);
|
|
5403
|
+
});
|
|
5404
|
+
socket.once("error", () => resolve(false));
|
|
5405
|
+
});
|
|
5406
|
+
}
|
|
5368
5407
|
function findListeningPid(port) {
|
|
5369
5408
|
if (process.platform === "win32") return Promise.resolve(void 0);
|
|
5370
5409
|
return new Promise((resolve) => {
|
|
@@ -5727,6 +5766,7 @@ function serverKey(config) {
|
|
|
5727
5766
|
}
|
|
5728
5767
|
function serverEnv(config) {
|
|
5729
5768
|
const extra = {};
|
|
5769
|
+
if (config.logLevel) extra["FRONTMCP_LOG_LEVEL"] = config.logLevel;
|
|
5730
5770
|
if (config.auth?.mode) extra["FRONTMCP_TEST_AUTH_MODE"] = config.auth.mode;
|
|
5731
5771
|
if (config.auth?.type) extra["FRONTMCP_TEST_AUTH_TYPE"] = config.auth.type;
|
|
5732
5772
|
if (Object.keys(extra).length === 0 && !config.env) return void 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/testing",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.3",
|
|
4
4
|
"description": "E2E testing framework for FrontMCP servers - MCP client, auth mocks, Playwright integration",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"homepage": "https://docs.agentfront.dev",
|
|
@@ -87,9 +87,9 @@
|
|
|
87
87
|
"./esm": null
|
|
88
88
|
},
|
|
89
89
|
"peerDependencies": {
|
|
90
|
-
"@frontmcp/lazy-zod": "1.9.
|
|
91
|
-
"@frontmcp/sdk": "1.9.
|
|
92
|
-
"@frontmcp/ui": "1.9.
|
|
90
|
+
"@frontmcp/lazy-zod": "1.9.3",
|
|
91
|
+
"@frontmcp/sdk": "1.9.3",
|
|
92
|
+
"@frontmcp/ui": "1.9.3",
|
|
93
93
|
"@jest/globals": "^29.0.0 || ^30.0.0",
|
|
94
94
|
"@playwright/test": "^1.40.0",
|
|
95
95
|
"jest": "^29.0.0 || ^30.0.0"
|
|
@@ -112,8 +112,8 @@
|
|
|
112
112
|
"node": ">=24.0.0"
|
|
113
113
|
},
|
|
114
114
|
"dependencies": {
|
|
115
|
-
"@frontmcp/protocol": "1.9.
|
|
116
|
-
"@frontmcp/utils": "1.9.
|
|
115
|
+
"@frontmcp/protocol": "1.9.3",
|
|
116
|
+
"@frontmcp/utils": "1.9.3",
|
|
117
117
|
"@swc/core": "~1.15.41",
|
|
118
118
|
"@swc/jest": "~0.2.38",
|
|
119
119
|
"jose": "^6.0.11",
|
package/perf/index.js
CHANGED
|
@@ -3805,6 +3805,7 @@ var ProgressCollector = class {
|
|
|
3805
3805
|
|
|
3806
3806
|
// libs/testing/src/server/test-server.ts
|
|
3807
3807
|
var import_child_process = require("child_process");
|
|
3808
|
+
var import_net2 = require("net");
|
|
3808
3809
|
var import_utils = require("@frontmcp/utils");
|
|
3809
3810
|
|
|
3810
3811
|
// libs/testing/src/errors/index.ts
|
|
@@ -4033,6 +4034,7 @@ async function releasePort(port) {
|
|
|
4033
4034
|
}
|
|
4034
4035
|
|
|
4035
4036
|
// libs/testing/src/server/test-server.ts
|
|
4037
|
+
var SERVER_EXIT_TIMEOUT_MS = 12e3;
|
|
4036
4038
|
var DEBUG_SERVER = process.env["DEBUG_SERVER"] === "1" || process.env["DEBUG"] === "1";
|
|
4037
4039
|
var TestServer = class _TestServer {
|
|
4038
4040
|
process = null;
|
|
@@ -4188,9 +4190,12 @@ var TestServer = class _TestServer {
|
|
|
4188
4190
|
async stopProcess() {
|
|
4189
4191
|
if (this.process) {
|
|
4190
4192
|
this.log("Stopping server...");
|
|
4193
|
+
const serverPid = this._info.pid !== this._info.shellPid ? this._info.pid : void 0;
|
|
4191
4194
|
if (this.process.exitCode !== null || this.process.signalCode !== null) {
|
|
4192
4195
|
this.log(`Server already exited (code: ${this.process.exitCode}, signal: ${this.process.signalCode})`);
|
|
4193
4196
|
this.process = null;
|
|
4197
|
+
if (serverPid !== void 0) signalIfRunning(serverPid, "SIGTERM");
|
|
4198
|
+
await this.waitForServerGone(serverPid);
|
|
4194
4199
|
return;
|
|
4195
4200
|
}
|
|
4196
4201
|
const pid = this.process.pid;
|
|
@@ -4228,9 +4233,26 @@ var TestServer = class _TestServer {
|
|
|
4228
4233
|
await exitPromise;
|
|
4229
4234
|
clearTimeout(killTimeout);
|
|
4230
4235
|
this.process = null;
|
|
4236
|
+
await this.waitForServerGone(serverPid);
|
|
4231
4237
|
this.log("Server stopped");
|
|
4232
4238
|
}
|
|
4233
4239
|
}
|
|
4240
|
+
/**
|
|
4241
|
+
* Wait until the server process has exited and its port refuses connections. A server that
|
|
4242
|
+
* drains on SIGTERM can keep listening after the shell it was started through has exited.
|
|
4243
|
+
*/
|
|
4244
|
+
async waitForServerGone(serverPid) {
|
|
4245
|
+
const deadline = Date.now() + SERVER_EXIT_TIMEOUT_MS;
|
|
4246
|
+
while (Date.now() < deadline) {
|
|
4247
|
+
const serverRunning = serverPid !== void 0 && pidIsAlive(serverPid);
|
|
4248
|
+
if (!serverRunning && !await acceptsConnections(this._info.port)) return;
|
|
4249
|
+
await sleep4(100);
|
|
4250
|
+
}
|
|
4251
|
+
if (serverPid !== void 0 && pidIsAlive(serverPid)) {
|
|
4252
|
+
this.log("Force killing server process after timeout...");
|
|
4253
|
+
signalIfRunning(serverPid, "SIGKILL");
|
|
4254
|
+
}
|
|
4255
|
+
}
|
|
4234
4256
|
/**
|
|
4235
4257
|
* Wait for server to be ready
|
|
4236
4258
|
*/
|
|
@@ -4450,6 +4472,23 @@ TIP: Set DEBUG_SERVER=1 or DEBUG=1 environment variable for verbose output`
|
|
|
4450
4472
|
function sleep4(ms) {
|
|
4451
4473
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4452
4474
|
}
|
|
4475
|
+
function signalIfRunning(pid, signal) {
|
|
4476
|
+
try {
|
|
4477
|
+
process.kill(pid, signal);
|
|
4478
|
+
} catch (error) {
|
|
4479
|
+
if (error.code !== "ESRCH") throw error;
|
|
4480
|
+
}
|
|
4481
|
+
}
|
|
4482
|
+
function acceptsConnections(port) {
|
|
4483
|
+
return new Promise((resolve) => {
|
|
4484
|
+
const socket = (0, import_net2.connect)(port, "127.0.0.1");
|
|
4485
|
+
socket.once("connect", () => {
|
|
4486
|
+
socket.destroy();
|
|
4487
|
+
resolve(true);
|
|
4488
|
+
});
|
|
4489
|
+
socket.once("error", () => resolve(false));
|
|
4490
|
+
});
|
|
4491
|
+
}
|
|
4453
4492
|
function findListeningPid(port) {
|
|
4454
4493
|
if (process.platform === "win32") return Promise.resolve(void 0);
|
|
4455
4494
|
return new Promise((resolve) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"port-registry.d.ts","sourceRoot":"","sources":["../../src/server/port-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH;;;;;;GAMG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiElB,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"port-registry.d.ts","sourceRoot":"","sources":["../../src/server/port-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH;;;;;;GAMG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiElB,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,eAAe,CAAC;AA2CtD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAO/C;AAuDD;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAM7E;AAED;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,MAAM,EACf,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC,CAgE7F;AAmDD;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGtD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAWxE;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAMrD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAM/F"}
|
package/server/test-server.d.ts
CHANGED
|
@@ -86,6 +86,11 @@ export declare class TestServer {
|
|
|
86
86
|
*/
|
|
87
87
|
stop(): Promise<void>;
|
|
88
88
|
private stopProcess;
|
|
89
|
+
/**
|
|
90
|
+
* Wait until the server process has exited and its port refuses connections. A server that
|
|
91
|
+
* drains on SIGTERM can keep listening after the shell it was started through has exited.
|
|
92
|
+
*/
|
|
93
|
+
private waitForServerGone;
|
|
89
94
|
/**
|
|
90
95
|
* Wait for server to be ready
|
|
91
96
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-server.d.ts","sourceRoot":"","sources":["../../src/server/test-server.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"test-server.d.ts","sourceRoot":"","sources":["../../src/server/test-server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAoBH,MAAM,WAAW,iBAAiB;IAChC,wEAAwE;IACxE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kCAAkC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,kEAAkE;IAClE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4DAA4D;IAC5D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAMD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsE;IAC9F,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,IAAI,CAAgB;IAC5B,oFAAoF;IACpF,OAAO,CAAC,WAAW,CAAsC;IACzD,2EAA2E;IAC3E,OAAO,CAAC,iBAAiB,CAAsC;IAE/D,OAAO;IAyBP;;OAEG;WACU,KAAK,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC;IA4CnE;;OAEG;WACU,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,OAAO,CAAC,iBAAiB,CAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IA0DpG;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU;IAoB3C;;OAEG;IACH,IAAI,IAAI,IAAI,cAAc,CAEzB;IAED;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAYb,WAAW;IA4DzB;;;OAGG;YACW,iBAAiB;IAa/B;;OAEG;IACG,YAAY,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BnD;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAM9B;;OAEG;IACH,OAAO,IAAI,MAAM,EAAE;IAInB;;OAEG;IACH,SAAS,IAAI,IAAI;YAQH,YAAY;IA+G1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAY1B;;OAEG;YACW,6BAA6B;IAqE3C,OAAO,CAAC,GAAG;CAKZ;AAwMD,OAAO,EACL,WAAW,EACX,cAAc,EACd,eAAe,EACf,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,KAAK,UAAU,GAChB,MAAM,iBAAiB,CAAC"}
|