@calltelemetry/cli 0.4.6 → 0.4.8
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/commands/loadtest.d.ts +3 -0
- package/dist/commands/loadtest.d.ts.map +1 -0
- package/dist/commands/loadtest.js +22 -0
- package/dist/commands/loadtest.js.map +1 -0
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/curri-xml.d.ts +21 -0
- package/dist/lib/curri-xml.d.ts.map +1 -0
- package/dist/lib/curri-xml.js +53 -0
- package/dist/lib/curri-xml.js.map +1 -0
- package/dist/lib/loadtest-stats.d.ts +91 -0
- package/dist/lib/loadtest-stats.d.ts.map +1 -0
- package/dist/lib/loadtest-stats.js +23 -0
- package/dist/lib/loadtest-stats.js.map +1 -0
- package/dist/lib/loadtest.d.ts +14 -0
- package/dist/lib/loadtest.d.ts.map +1 -0
- package/dist/lib/loadtest.js +112 -0
- package/dist/lib/loadtest.js.map +1 -0
- package/dist/lib/rpc-scripts.d.ts +2 -0
- package/dist/lib/rpc-scripts.d.ts.map +1 -1
- package/dist/lib/rpc-scripts.js +29 -0
- package/dist/lib/rpc-scripts.js.map +1 -1
- package/dist/ui/components/Sparkline.d.ts +15 -0
- package/dist/ui/components/Sparkline.d.ts.map +1 -0
- package/dist/ui/components/Sparkline.js +21 -0
- package/dist/ui/components/Sparkline.js.map +1 -0
- package/dist/ui/components/index.d.ts +1 -0
- package/dist/ui/components/index.d.ts.map +1 -1
- package/dist/ui/components/index.js +1 -0
- package/dist/ui/components/index.js.map +1 -1
- package/dist/ui/context/MetricsContext.d.ts.map +1 -1
- package/dist/ui/context/MetricsContext.js +4 -2
- package/dist/ui/context/MetricsContext.js.map +1 -1
- package/dist/ui/hooks/index.d.ts +2 -0
- package/dist/ui/hooks/index.d.ts.map +1 -1
- package/dist/ui/hooks/index.js +1 -0
- package/dist/ui/hooks/index.js.map +1 -1
- package/dist/ui/hooks/useLoadTest.d.ts +11 -0
- package/dist/ui/hooks/useLoadTest.d.ts.map +1 -0
- package/dist/ui/hooks/useLoadTest.js +38 -0
- package/dist/ui/hooks/useLoadTest.js.map +1 -0
- package/dist/ui/views/DiagNetworkView.js +61 -54
- package/dist/ui/views/DiagNetworkView.js.map +1 -1
- package/dist/ui/views/LoadTestConfigView.d.ts +31 -0
- package/dist/ui/views/LoadTestConfigView.d.ts.map +1 -0
- package/dist/ui/views/LoadTestConfigView.js +111 -0
- package/dist/ui/views/LoadTestConfigView.js.map +1 -0
- package/dist/ui/views/LoadTestRunView.d.ts +10 -0
- package/dist/ui/views/LoadTestRunView.d.ts.map +1 -0
- package/dist/ui/views/LoadTestRunView.js +71 -0
- package/dist/ui/views/LoadTestRunView.js.map +1 -0
- package/dist/ui/views/LoadTestSummaryView.d.ts +9 -0
- package/dist/ui/views/LoadTestSummaryView.d.ts.map +1 -0
- package/dist/ui/views/LoadTestSummaryView.js +72 -0
- package/dist/ui/views/LoadTestSummaryView.js.map +1 -0
- package/dist/ui/views/LoadTestView.d.ts +8 -0
- package/dist/ui/views/LoadTestView.d.ts.map +1 -0
- package/dist/ui/views/LoadTestView.js +43 -0
- package/dist/ui/views/LoadTestView.js.map +1 -0
- package/dist/ui/views/MainMenu.d.ts.map +1 -1
- package/dist/ui/views/MainMenu.js +90 -21
- package/dist/ui/views/MainMenu.js.map +1 -1
- package/dist/ui/views/StatusView.d.ts.map +1 -1
- package/dist/ui/views/StatusView.js +134 -21
- package/dist/ui/views/StatusView.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadtest.d.ts","sourceRoot":"","sources":["../../src/commands/loadtest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,QAmBvD"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { render } from 'ink';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { LoadTestView } from '../ui/views/LoadTestView.js';
|
|
4
|
+
export function registerLoadtestCommand(program) {
|
|
5
|
+
program
|
|
6
|
+
.command('loadtest')
|
|
7
|
+
.description('CURRI policy load tester with live metrics')
|
|
8
|
+
.option('--policy <name>', 'Policy name (skip selection)')
|
|
9
|
+
.option('--rate <n>', 'Target requests per second')
|
|
10
|
+
.option('--duration <n>', 'Test duration in seconds')
|
|
11
|
+
.option('--connections <n>', 'Number of connections')
|
|
12
|
+
.option('--calling <number>', 'Override calling number')
|
|
13
|
+
.option('--called <number>', 'Override called number')
|
|
14
|
+
.option('--device <name>', 'Override device name')
|
|
15
|
+
.option('--trigger <type>', 'Trigger point type')
|
|
16
|
+
.option('--url <url>', 'CURRI endpoint URL (auto-detected)')
|
|
17
|
+
.action(async (opts) => {
|
|
18
|
+
const { waitUntilExit } = render(React.createElement(LoadTestView, { cliOptions: opts }));
|
|
19
|
+
await waitUntilExit();
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=loadtest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadtest.js","sourceRoot":"","sources":["../../src/commands/loadtest.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,MAAM,UAAU,uBAAuB,CAAC,OAAgB;IACtD,OAAO;SACJ,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CAAC,4CAA4C,CAAC;SACzD,MAAM,CAAC,iBAAiB,EAAE,8BAA8B,CAAC;SACzD,MAAM,CAAC,YAAY,EAAE,4BAA4B,CAAC;SAClD,MAAM,CAAC,gBAAgB,EAAE,0BAA0B,CAAC;SACpD,MAAM,CAAC,mBAAmB,EAAE,uBAAuB,CAAC;SACpD,MAAM,CAAC,oBAAoB,EAAE,yBAAyB,CAAC;SACvD,MAAM,CAAC,mBAAmB,EAAE,wBAAwB,CAAC;SACrD,MAAM,CAAC,iBAAiB,EAAE,sBAAsB,CAAC;SACjD,MAAM,CAAC,kBAAkB,EAAE,oBAAoB,CAAC;SAChD,MAAM,CAAC,aAAa,EAAE,oCAAoC,CAAC;SAC3D,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAC9B,KAAK,CAAC,aAAa,CAAC,YAAY,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CACxD,CAAC;QACF,MAAM,aAAa,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;AACP,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const VERSION = '0.4.
|
|
2
|
+
const VERSION = '0.4.8';
|
|
3
3
|
import { Command } from 'commander';
|
|
4
4
|
import { registerStatusCommand } from './commands/status.js';
|
|
5
5
|
import { registerUpdateCommand } from './commands/update.js';
|
|
@@ -14,6 +14,7 @@ import { registerSecretsCommand } from './commands/secrets.js';
|
|
|
14
14
|
import { registerUsersCommand } from './commands/users.js';
|
|
15
15
|
import { registerServicesCommand } from './commands/services.js';
|
|
16
16
|
import { registerSelfUpdateCommand } from './commands/self-update.js';
|
|
17
|
+
import { registerLoadtestCommand } from './commands/loadtest.js';
|
|
17
18
|
import { LOGO } from './lib/brand.js';
|
|
18
19
|
import { setVerbose, setGlobalLevel } from './lib/log.js';
|
|
19
20
|
import { loadPrefs } from './lib/prefs.js';
|
|
@@ -53,6 +54,7 @@ registerSecretsCommand(program);
|
|
|
53
54
|
registerUsersCommand(program);
|
|
54
55
|
registerServicesCommand(program);
|
|
55
56
|
registerSelfUpdateCommand(program);
|
|
57
|
+
registerLoadtestCommand(program);
|
|
56
58
|
// Interactive menu when `ct` is run with no arguments on a TTY
|
|
57
59
|
// Flags like --debug and --verbose are not commands; only positional args count
|
|
58
60
|
const nonFlagArgs = process.argv.slice(2).filter(a => !a.startsWith('-'));
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,MAAM,OAAO,GAAG,OAAO,CAAC;AAExB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,IAAI,CAAC;KACV,WAAW,CAAC,wCAAwC,CAAC;KACrD,OAAO,CAAC,OAAO,CAAC;KAChB,MAAM,CAAC,eAAe,EAAE,6BAA6B,CAAC;KACtD,MAAM,CAAC,SAAS,EAAE,4BAA4B,CAAC;KAC/C,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,EAAE;IAC7B,wCAAwC;IACxC,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK;QAAE,cAAc,CAAC,OAAO,CAAC,CAAC;SAC7C,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,OAAO;QAAE,UAAU,CAAC,IAAI,CAAC,CAAC;IAClD,qDAAqD;IACrD,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,+BAA+B,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,iEAAiE;IACjE,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;IAC1B,IAAI,KAAK,EAAE,UAAU,EAAE,CAAC;QACtB,kBAAkB,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,iBAAiB,CAAC,OAAO,CAAC,CAAC;AAC3B,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC7B,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,uBAAuB,CAAC,OAAO,CAAC,CAAC;AACjC,yBAAyB,CAAC,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,MAAM,OAAO,GAAG,OAAO,CAAC;AAExB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,IAAI,CAAC;KACV,WAAW,CAAC,wCAAwC,CAAC;KACrD,OAAO,CAAC,OAAO,CAAC;KAChB,MAAM,CAAC,eAAe,EAAE,6BAA6B,CAAC;KACtD,MAAM,CAAC,SAAS,EAAE,4BAA4B,CAAC;KAC/C,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,EAAE;IAC7B,wCAAwC;IACxC,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK;QAAE,cAAc,CAAC,OAAO,CAAC,CAAC;SAC7C,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,OAAO;QAAE,UAAU,CAAC,IAAI,CAAC,CAAC;IAClD,qDAAqD;IACrD,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,+BAA+B,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,iEAAiE;IACjE,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;IAC1B,IAAI,KAAK,EAAE,UAAU,EAAE,CAAC;QACtB,kBAAkB,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,iBAAiB,CAAC,OAAO,CAAC,CAAC;AAC3B,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC7B,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,uBAAuB,CAAC,OAAO,CAAC,CAAC;AACjC,yBAAyB,CAAC,OAAO,CAAC,CAAC;AACnC,uBAAuB,CAAC,OAAO,CAAC,CAAC;AAEjC,+DAA+D;AAC/D,gFAAgF;AAChF,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1E,MAAM,UAAU,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC;AAE1C,IAAI,CAAC,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACxC,oCAAoC;IACpC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACrC,cAAc,CAAC,OAAO,CAAC,CAAC;IAC1B,CAAC;IAED,qCAAqC;IACrC,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;IAC1B,MAAM,QAAQ,GAAG,KAAK,KAAK,IAAI,CAAC;IAEhC,2DAA2D;IAC3D,IAAI,KAAK,EAAE,UAAU,EAAE,CAAC;QACtB,kBAAkB,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED,2EAA2E;IAC3E,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QACtC,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;QACpC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC;QAC5D,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,kCAAkC,CAAC,CAAC;QAC3E,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,gCAAgC,CAAC,CAAC;QAE3E,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,MAAM,CACvC,KAAK,CAAC,aAAa,CAAC,aAAa,EAAE,IAAI,EACrC,KAAK,CAAC,aAAa,CAAC,eAAe,EAAE,IAAI,EACvC,KAAK,CAAC,aAAa,CAAC,QAAQ,EAAE;YAC5B,OAAO,EAAE,OAAO;YAChB,QAAQ;YACR,YAAY,EAAE,CAAC,OAAe,EAAE,EAAE;gBAChC,OAAO,EAAE,CAAC;gBACV,wDAAwD;gBACxD,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACvD,CAAC;YACD,MAAM,EAAE,GAAG,EAAE;gBACX,OAAO,EAAE,CAAC;YACZ,CAAC;SACF,CAAC,CACH,CACF,CACF,CAAC;QAEF,MAAM,aAAa,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;AACL,CAAC;KAAM,CAAC;IACN,OAAO,CAAC,KAAK,EAAE,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** XACML 2.0 XML builder for CURRI load testing. */
|
|
2
|
+
export interface CurriXmlOptions {
|
|
3
|
+
callingNumber: string;
|
|
4
|
+
calledNumber: string;
|
|
5
|
+
deviceName: string;
|
|
6
|
+
triggerType: string;
|
|
7
|
+
}
|
|
8
|
+
/** Generate a random 10-digit US phone number. */
|
|
9
|
+
export declare function randomPhoneNumber(): string;
|
|
10
|
+
/** Generate a random Cisco device MAC name (SEP + 12 hex chars). */
|
|
11
|
+
export declare function randomDeviceName(): string;
|
|
12
|
+
/** Build XACML 2.0 XML for a CURRI policy request. */
|
|
13
|
+
export declare function buildCurriXml(opts: CurriXmlOptions): string;
|
|
14
|
+
/** Build CURRI XML with random or custom values based on config. */
|
|
15
|
+
export declare function buildCurriXmlFromConfig(config: {
|
|
16
|
+
callingNumber: string;
|
|
17
|
+
calledNumber: string;
|
|
18
|
+
deviceName: string;
|
|
19
|
+
triggerType: string;
|
|
20
|
+
}): string;
|
|
21
|
+
//# sourceMappingURL=curri-xml.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"curri-xml.d.ts","sourceRoot":"","sources":["../../src/lib/curri-xml.ts"],"names":[],"mappings":"AAAA,oDAAoD;AAEpD,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,kDAAkD;AAClD,wBAAgB,iBAAiB,IAAI,MAAM,CAK1C;AAED,oEAAoE;AACpE,wBAAgB,gBAAgB,IAAI,MAAM,CAKzC;AAED,sDAAsD;AACtD,wBAAgB,aAAa,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CA4B3D;AAED,oEAAoE;AACpE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE;IAC9C,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,MAAM,CAOT"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** XACML 2.0 XML builder for CURRI load testing. */
|
|
2
|
+
/** Generate a random 10-digit US phone number. */
|
|
3
|
+
export function randomPhoneNumber() {
|
|
4
|
+
const areaCode = 200 + Math.floor(Math.random() * 800); // 200-999
|
|
5
|
+
const exchange = 200 + Math.floor(Math.random() * 800); // 200-999
|
|
6
|
+
const subscriber = Math.floor(Math.random() * 10000);
|
|
7
|
+
return `${areaCode}${exchange}${subscriber.toString().padStart(4, '0')}`;
|
|
8
|
+
}
|
|
9
|
+
/** Generate a random Cisco device MAC name (SEP + 12 hex chars). */
|
|
10
|
+
export function randomDeviceName() {
|
|
11
|
+
const hex = Array.from({ length: 12 }, () => Math.floor(Math.random() * 16).toString(16).toUpperCase()).join('');
|
|
12
|
+
return `SEP${hex}`;
|
|
13
|
+
}
|
|
14
|
+
/** Build XACML 2.0 XML for a CURRI policy request. */
|
|
15
|
+
export function buildCurriXml(opts) {
|
|
16
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
17
|
+
<Request xmlns="urn:oasis:names:tc:xacml:2.0:context:schema:os">
|
|
18
|
+
<Subject SubjectCategory="urn:oasis:names:tc:xacml:1.0:Subject-Category:access-Subject">
|
|
19
|
+
<Attribute AttributeId="urn:Cisco:uc:1.0:callingnumber">
|
|
20
|
+
<AttributeValue>${opts.callingNumber}</AttributeValue>
|
|
21
|
+
</Attribute>
|
|
22
|
+
<Attribute AttributeId="urn:Cisco:uc:1.0:callednumber">
|
|
23
|
+
<AttributeValue>${opts.calledNumber}</AttributeValue>
|
|
24
|
+
</Attribute>
|
|
25
|
+
<Attribute AttributeId="urn:Cisco:uc:1.0:callingdevicename">
|
|
26
|
+
<AttributeValue>${opts.deviceName}</AttributeValue>
|
|
27
|
+
</Attribute>
|
|
28
|
+
<Attribute AttributeId="urn:Cisco:uc:1.0:triggerpointtype">
|
|
29
|
+
<AttributeValue>${opts.triggerType}</AttributeValue>
|
|
30
|
+
</Attribute>
|
|
31
|
+
</Subject>
|
|
32
|
+
<Resource>
|
|
33
|
+
<Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:Resource:Resource-Id">
|
|
34
|
+
<AttributeValue>CISCO:UC:VoiceOrVideoCall</AttributeValue>
|
|
35
|
+
</Attribute>
|
|
36
|
+
</Resource>
|
|
37
|
+
<action>
|
|
38
|
+
<Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-Id">
|
|
39
|
+
<AttributeValue>any</AttributeValue>
|
|
40
|
+
</Attribute>
|
|
41
|
+
</action>
|
|
42
|
+
</Request>`;
|
|
43
|
+
}
|
|
44
|
+
/** Build CURRI XML with random or custom values based on config. */
|
|
45
|
+
export function buildCurriXmlFromConfig(config) {
|
|
46
|
+
return buildCurriXml({
|
|
47
|
+
callingNumber: config.callingNumber === 'random' ? randomPhoneNumber() : config.callingNumber,
|
|
48
|
+
calledNumber: config.calledNumber === 'random' ? randomPhoneNumber() : config.calledNumber,
|
|
49
|
+
deviceName: config.deviceName === 'random' ? randomDeviceName() : config.deviceName,
|
|
50
|
+
triggerType: config.triggerType,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=curri-xml.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"curri-xml.js","sourceRoot":"","sources":["../../src/lib/curri-xml.ts"],"names":[],"mappings":"AAAA,oDAAoD;AASpD,kDAAkD;AAClD,MAAM,UAAU,iBAAiB;IAC/B,MAAM,QAAQ,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,UAAU;IAClE,MAAM,QAAQ,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,UAAU;IAClE,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC;IACrD,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AAC3E,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,gBAAgB;IAC9B,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAC1C,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAC1D,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACX,OAAO,MAAM,GAAG,EAAE,CAAC;AACrB,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,aAAa,CAAC,IAAqB;IACjD,OAAO;;;;wBAIe,IAAI,CAAC,aAAa;;;wBAGlB,IAAI,CAAC,YAAY;;;wBAGjB,IAAI,CAAC,UAAU;;;wBAGf,IAAI,CAAC,WAAW;;;;;;;;;;;;;WAa7B,CAAC;AACZ,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,uBAAuB,CAAC,MAKvC;IACC,OAAO,aAAa,CAAC;QACnB,aAAa,EAAE,MAAM,CAAC,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa;QAC7F,YAAY,EAAE,MAAM,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY;QAC1F,UAAU,EAAE,MAAM,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU;QACnF,WAAW,EAAE,MAAM,CAAC,WAAW;KAChC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/** Types for the CURRI load testing engine. */
|
|
2
|
+
export interface LoadTestConfig {
|
|
3
|
+
/** CURRI endpoint URL (e.g., http://127.0.0.1:4080) */
|
|
4
|
+
url: string;
|
|
5
|
+
/** Policy API key for ?api_key= param */
|
|
6
|
+
apiKey: string;
|
|
7
|
+
/** Policy name for display */
|
|
8
|
+
policyName: string;
|
|
9
|
+
/** Target requests per second */
|
|
10
|
+
rate: number;
|
|
11
|
+
/** Test duration in seconds */
|
|
12
|
+
duration: number;
|
|
13
|
+
/** Number of HTTP connections */
|
|
14
|
+
connections: number;
|
|
15
|
+
/** Override calling number (or 'random') */
|
|
16
|
+
callingNumber: string;
|
|
17
|
+
/** Override called number (or 'random') */
|
|
18
|
+
calledNumber: string;
|
|
19
|
+
/** Override device name (or 'random') */
|
|
20
|
+
deviceName: string;
|
|
21
|
+
/** Trigger point type */
|
|
22
|
+
triggerType: string;
|
|
23
|
+
}
|
|
24
|
+
export interface LoadTestSnapshot {
|
|
25
|
+
/** Elapsed seconds */
|
|
26
|
+
elapsed: number;
|
|
27
|
+
/** Requests completed in this interval */
|
|
28
|
+
requestsInInterval: number;
|
|
29
|
+
/** Cumulative totals */
|
|
30
|
+
totalRequests: number;
|
|
31
|
+
successCount: number;
|
|
32
|
+
errorCount: number;
|
|
33
|
+
timeoutCount: number;
|
|
34
|
+
/** Latency percentiles in ms */
|
|
35
|
+
p50: number;
|
|
36
|
+
p95: number;
|
|
37
|
+
p99: number;
|
|
38
|
+
max: number;
|
|
39
|
+
mean: number;
|
|
40
|
+
/** Rate history for sparkline (last N intervals) */
|
|
41
|
+
rateHistory: number[];
|
|
42
|
+
}
|
|
43
|
+
export interface LoadTestResults {
|
|
44
|
+
config: LoadTestConfig;
|
|
45
|
+
duration: number;
|
|
46
|
+
totalRequests: number;
|
|
47
|
+
successCount: number;
|
|
48
|
+
errorCount: number;
|
|
49
|
+
timeoutCount: number;
|
|
50
|
+
bytesRead: number;
|
|
51
|
+
bytesSent: number;
|
|
52
|
+
latency: {
|
|
53
|
+
p50: number;
|
|
54
|
+
p95: number;
|
|
55
|
+
p99: number;
|
|
56
|
+
p999: number;
|
|
57
|
+
max: number;
|
|
58
|
+
mean: number;
|
|
59
|
+
stddev: number;
|
|
60
|
+
};
|
|
61
|
+
throughput: {
|
|
62
|
+
average: number;
|
|
63
|
+
max: number;
|
|
64
|
+
min: number;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export interface CurriPolicy {
|
|
68
|
+
id: number;
|
|
69
|
+
name: string;
|
|
70
|
+
api_key: string;
|
|
71
|
+
org_id: number;
|
|
72
|
+
org_name: string;
|
|
73
|
+
}
|
|
74
|
+
/** Maximum number of rate samples kept in the sparkline history. */
|
|
75
|
+
export declare const MAX_RATE_HISTORY = 30;
|
|
76
|
+
/** Build a LoadTestSnapshot from autocannon tick data. */
|
|
77
|
+
export declare function buildSnapshot(counter: {
|
|
78
|
+
counter: number;
|
|
79
|
+
bytes: number;
|
|
80
|
+
}, elapsed: number, rateHistory: number[], latencyData: {
|
|
81
|
+
p50: number;
|
|
82
|
+
p95: number;
|
|
83
|
+
p99: number;
|
|
84
|
+
max: number;
|
|
85
|
+
mean: number;
|
|
86
|
+
}, totals: {
|
|
87
|
+
requests: number;
|
|
88
|
+
errors: number;
|
|
89
|
+
timeouts: number;
|
|
90
|
+
}): LoadTestSnapshot;
|
|
91
|
+
//# sourceMappingURL=loadtest-stats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadtest-stats.d.ts","sourceRoot":"","sources":["../../src/lib/loadtest-stats.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAE/C,MAAM,WAAW,cAAc;IAC7B,uDAAuD;IACvD,GAAG,EAAE,MAAM,CAAC;IACZ,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,aAAa,EAAE,MAAM,CAAC;IACtB,2CAA2C;IAC3C,YAAY,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,sBAAsB;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,kBAAkB,EAAE,MAAM,CAAC;IAC3B,wBAAwB;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,gCAAgC;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE;QACP,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,UAAU,EAAE;QACV,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,oEAAoE;AACpE,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC,0DAA0D;AAC1D,wBAAgB,aAAa,CAC3B,OAAO,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAC3C,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EAAE,EACrB,WAAW,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACjF,MAAM,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC7D,gBAAgB,CAkBlB"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Types for the CURRI load testing engine. */
|
|
2
|
+
/** Maximum number of rate samples kept in the sparkline history. */
|
|
3
|
+
export const MAX_RATE_HISTORY = 30;
|
|
4
|
+
/** Build a LoadTestSnapshot from autocannon tick data. */
|
|
5
|
+
export function buildSnapshot(counter, elapsed, rateHistory, latencyData, totals) {
|
|
6
|
+
const requestsInInterval = counter.counter;
|
|
7
|
+
const updatedHistory = [...rateHistory, requestsInInterval].slice(-MAX_RATE_HISTORY);
|
|
8
|
+
return {
|
|
9
|
+
elapsed,
|
|
10
|
+
requestsInInterval,
|
|
11
|
+
totalRequests: totals.requests,
|
|
12
|
+
successCount: totals.requests - totals.errors - totals.timeouts,
|
|
13
|
+
errorCount: totals.errors,
|
|
14
|
+
timeoutCount: totals.timeouts,
|
|
15
|
+
p50: latencyData.p50,
|
|
16
|
+
p95: latencyData.p95,
|
|
17
|
+
p99: latencyData.p99,
|
|
18
|
+
max: latencyData.max,
|
|
19
|
+
mean: latencyData.mean,
|
|
20
|
+
rateHistory: updatedHistory,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=loadtest-stats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadtest-stats.js","sourceRoot":"","sources":["../../src/lib/loadtest-stats.ts"],"names":[],"mappings":"AAAA,+CAA+C;AA8E/C,oEAAoE;AACpE,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAEnC,0DAA0D;AAC1D,MAAM,UAAU,aAAa,CAC3B,OAA2C,EAC3C,OAAe,EACf,WAAqB,EACrB,WAAiF,EACjF,MAA8D;IAE9D,MAAM,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC;IAC3C,MAAM,cAAc,GAAG,CAAC,GAAG,WAAW,EAAE,kBAAkB,CAAC,CAAC,KAAK,CAAC,CAAC,gBAAgB,CAAC,CAAC;IAErF,OAAO;QACL,OAAO;QACP,kBAAkB;QAClB,aAAa,EAAE,MAAM,CAAC,QAAQ;QAC9B,YAAY,EAAE,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,QAAQ;QAC/D,UAAU,EAAE,MAAM,CAAC,MAAM;QACzB,YAAY,EAAE,MAAM,CAAC,QAAQ;QAC7B,GAAG,EAAE,WAAW,CAAC,GAAG;QACpB,GAAG,EAAE,WAAW,CAAC,GAAG;QACpB,GAAG,EAAE,WAAW,CAAC,GAAG;QACpB,GAAG,EAAE,WAAW,CAAC,GAAG;QACpB,IAAI,EAAE,WAAW,CAAC,IAAI;QACtB,WAAW,EAAE,cAAc;KAC5B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** CURRI load test engine wrapping autocannon. */
|
|
2
|
+
import type { LoadTestConfig, LoadTestResults, LoadTestSnapshot } from './loadtest-stats.js';
|
|
3
|
+
export type { LoadTestConfig, LoadTestResults, LoadTestSnapshot } from './loadtest-stats.js';
|
|
4
|
+
/** Default CURRI endpoint URL. */
|
|
5
|
+
export declare const DEFAULT_CURRI_URL = "http://127.0.0.1:4080";
|
|
6
|
+
export interface LoadTestHandle {
|
|
7
|
+
/** Promise that resolves when the test completes. */
|
|
8
|
+
promise: Promise<LoadTestResults>;
|
|
9
|
+
/** Stop the load test early. */
|
|
10
|
+
stop: () => void;
|
|
11
|
+
}
|
|
12
|
+
/** Start a CURRI load test with live progress callbacks. */
|
|
13
|
+
export declare function startLoadTest(config: LoadTestConfig, onProgress: (snapshot: LoadTestSnapshot) => void): LoadTestHandle;
|
|
14
|
+
//# sourceMappingURL=loadtest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadtest.d.ts","sourceRoot":"","sources":["../../src/lib/loadtest.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAIlD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAO7F,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE7F,kCAAkC;AAClC,eAAO,MAAM,iBAAiB,0BAA0B,CAAC;AAEzD,MAAM,WAAW,cAAc;IAC7B,qDAAqD;IACrD,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAClC,gCAAgC;IAChC,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,4DAA4D;AAC5D,wBAAgB,aAAa,CAC3B,MAAM,EAAE,cAAc,EACtB,UAAU,EAAE,CAAC,QAAQ,EAAE,gBAAgB,KAAK,IAAI,GAC/C,cAAc,CA4GhB"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/** CURRI load test engine wrapping autocannon. */
|
|
2
|
+
import { createRequire } from 'module';
|
|
3
|
+
import { buildCurriXmlFromConfig } from './curri-xml.js';
|
|
4
|
+
import { MAX_RATE_HISTORY } from './loadtest-stats.js';
|
|
5
|
+
// autocannon is CJS — use createRequire for ESM compatibility
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
7
|
+
const autocannon = require('autocannon');
|
|
8
|
+
/** Default CURRI endpoint URL. */
|
|
9
|
+
export const DEFAULT_CURRI_URL = 'http://127.0.0.1:4080';
|
|
10
|
+
/** Start a CURRI load test with live progress callbacks. */
|
|
11
|
+
export function startLoadTest(config, onProgress) {
|
|
12
|
+
let elapsed = 0;
|
|
13
|
+
let totalRequests = 0;
|
|
14
|
+
let totalErrors = 0;
|
|
15
|
+
let totalTimeouts = 0;
|
|
16
|
+
const rateHistory = [];
|
|
17
|
+
// Latest latency data from tick events
|
|
18
|
+
let latencyP50 = 0;
|
|
19
|
+
let latencyP95 = 0;
|
|
20
|
+
let latencyP99 = 0;
|
|
21
|
+
let latencyMax = 0;
|
|
22
|
+
let latencyMean = 0;
|
|
23
|
+
const instance = autocannon({
|
|
24
|
+
url: `${config.url}/api/policy?api_key=${config.apiKey}`,
|
|
25
|
+
method: 'POST',
|
|
26
|
+
headers: { 'content-type': 'application/xml' },
|
|
27
|
+
connections: config.connections,
|
|
28
|
+
duration: config.duration,
|
|
29
|
+
overallRate: config.rate,
|
|
30
|
+
timeout: 10,
|
|
31
|
+
setupRequest(req) {
|
|
32
|
+
req.body = buildCurriXmlFromConfig({
|
|
33
|
+
callingNumber: config.callingNumber,
|
|
34
|
+
calledNumber: config.calledNumber,
|
|
35
|
+
deviceName: config.deviceName,
|
|
36
|
+
triggerType: config.triggerType,
|
|
37
|
+
});
|
|
38
|
+
return req;
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
// Suppress autocannon's built-in progress output
|
|
42
|
+
autocannon.track(instance, {
|
|
43
|
+
renderProgressBar: false,
|
|
44
|
+
renderResultsTable: false,
|
|
45
|
+
renderLatencyTable: false,
|
|
46
|
+
});
|
|
47
|
+
// Track individual responses for latency info
|
|
48
|
+
instance.on('response', (_client, statusCode, _resBytes, responseTime) => {
|
|
49
|
+
totalRequests++;
|
|
50
|
+
if (statusCode >= 400)
|
|
51
|
+
totalErrors++;
|
|
52
|
+
// Update rolling latency estimates (rough, tick gives better data)
|
|
53
|
+
void responseTime;
|
|
54
|
+
void statusCode;
|
|
55
|
+
});
|
|
56
|
+
instance.on('tick', (value) => {
|
|
57
|
+
elapsed++;
|
|
58
|
+
const requestsInInterval = value.counter;
|
|
59
|
+
rateHistory.push(requestsInInterval);
|
|
60
|
+
if (rateHistory.length > MAX_RATE_HISTORY)
|
|
61
|
+
rateHistory.shift();
|
|
62
|
+
const snapshot = {
|
|
63
|
+
elapsed,
|
|
64
|
+
requestsInInterval,
|
|
65
|
+
totalRequests,
|
|
66
|
+
successCount: totalRequests - totalErrors - totalTimeouts,
|
|
67
|
+
errorCount: totalErrors,
|
|
68
|
+
timeoutCount: totalTimeouts,
|
|
69
|
+
p50: latencyP50,
|
|
70
|
+
p95: latencyP95,
|
|
71
|
+
p99: latencyP99,
|
|
72
|
+
max: latencyMax,
|
|
73
|
+
mean: latencyMean,
|
|
74
|
+
rateHistory: [...rateHistory],
|
|
75
|
+
};
|
|
76
|
+
onProgress(snapshot);
|
|
77
|
+
});
|
|
78
|
+
const promise = new Promise((resolve, reject) => {
|
|
79
|
+
instance.on('done', (result) => {
|
|
80
|
+
resolve({
|
|
81
|
+
config,
|
|
82
|
+
duration: result.duration,
|
|
83
|
+
totalRequests: result['2xx'] + result['3xx'] + result['4xx'] + result['5xx'] + result['1xx'],
|
|
84
|
+
successCount: result['2xx'] + result['3xx'],
|
|
85
|
+
errorCount: result.errors + result['4xx'] + result['5xx'],
|
|
86
|
+
timeoutCount: result.timeouts,
|
|
87
|
+
bytesRead: result.throughput.totalCount,
|
|
88
|
+
bytesSent: 0, // autocannon doesn't track sent bytes
|
|
89
|
+
latency: {
|
|
90
|
+
p50: result.latency.p50,
|
|
91
|
+
p95: result.latency.p97_5,
|
|
92
|
+
p99: result.latency.p99,
|
|
93
|
+
p999: result.latency.p99_9,
|
|
94
|
+
max: result.latency.max,
|
|
95
|
+
mean: result.latency.mean,
|
|
96
|
+
stddev: result.latency.stddev,
|
|
97
|
+
},
|
|
98
|
+
throughput: {
|
|
99
|
+
average: result.requests.average,
|
|
100
|
+
max: result.requests.max,
|
|
101
|
+
min: result.requests.min,
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
instance.on('error', reject);
|
|
106
|
+
});
|
|
107
|
+
return {
|
|
108
|
+
promise,
|
|
109
|
+
stop: () => instance.stop(),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=loadtest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadtest.js","sourceRoot":"","sources":["../../src/lib/loadtest.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/** RPC: List all CURRI policies for all orgs (for load testing). */
|
|
2
|
+
export declare const CURRI_POLICIES_RPC = "\n alias Cdrcisco.Identity\n alias Cdrcisco.Policies\n\n try do\n orgs = Identity.get_all_orgs()\n\n result = Enum.flat_map(orgs, fn org ->\n Policies.list_policies_by_org(org.id)\n |> Enum.map(fn p ->\n %{\n id: p.id,\n name: p.name,\n api_key: p.api_key,\n org_id: org.id,\n org_name: org.name\n }\n end)\n end)\n\n Jason.encode!(%{policies: result, count: length(result)})\n |> IO.puts()\n rescue\n e ->\n Jason.encode!(%{error: inspect(e), policies: [], count: 0})\n |> IO.puts()\n end\n";
|
|
1
3
|
/** RPC: List all greeting policies for all orgs with rules. */
|
|
2
4
|
export declare const GREETING_POLICIES_RPC = "\n alias Cdrcisco.Identity\n alias Cdrcisco.JtapiGreeting.GreetingPolicies\n\n try do\n orgs = Identity.get_all_orgs()\n\n result = Enum.flat_map(orgs, fn org ->\n policies = GreetingPolicies.list_greeting_policies(org.id,\n preload: [:default_audio_file, rules: [:audio_file]]\n )\n\n Enum.map(policies, fn p ->\n %{\n org_id: org.id,\n org_name: org.name,\n id: p.id,\n name: p.name,\n description: p.description,\n enabled: p.enabled,\n injection_target: p.injection_target,\n injection_mode: p.injection_mode,\n trigger_timing: p.trigger_timing,\n max_duration_seconds: p.max_duration_seconds,\n skip_key: p.skip_key,\n call_direction: p.call_direction,\n default_audio_file: case p.default_audio_file do\n nil -> nil\n f -> %{id: f.id, name: f.name}\n end,\n rules: Enum.map(p.rules || [], fn r ->\n %{\n id: r.id,\n name: r.name,\n priority: r.priority,\n enabled: r.enabled,\n calling_pattern: r.calling_pattern,\n called_pattern: r.called_pattern,\n call_direction: r.call_direction,\n injection_target: r.injection_target,\n injection_mode: r.injection_mode,\n audio_file: case r.audio_file do\n nil -> nil\n f -> %{id: f.id, name: f.name}\n end\n }\n end),\n rules_count: length(p.rules || []),\n inserted_at: p.inserted_at,\n updated_at: p.updated_at\n }\n end)\n end)\n\n Jason.encode!(%{policies: result, count: length(result), collected_at: DateTime.utc_now()})\n |> IO.puts()\n rescue\n e ->\n Jason.encode!(%{error: inspect(e), policies: [], count: 0})\n |> IO.puts()\n end\n";
|
|
3
5
|
/** Generate RPC code for policy history with a time window in minutes. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc-scripts.d.ts","sourceRoot":"","sources":["../../src/lib/rpc-scripts.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,eAAO,MAAM,qBAAqB,s6DA6DjC,CAAC;AAEF,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA6CxD;AAED,eAAO,MAAM,oBAAoB,urDAqDhC,CAAC"}
|
|
1
|
+
{"version":3,"file":"rpc-scripts.d.ts","sourceRoot":"","sources":["../../src/lib/rpc-scripts.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,eAAO,MAAM,kBAAkB,2lBA2B9B,CAAC;AAEF,+DAA+D;AAC/D,eAAO,MAAM,qBAAqB,s6DA6DjC,CAAC;AAEF,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA6CxD;AAED,eAAO,MAAM,oBAAoB,urDAqDhC,CAAC"}
|
package/dist/lib/rpc-scripts.js
CHANGED
|
@@ -1,3 +1,32 @@
|
|
|
1
|
+
/** RPC: List all CURRI policies for all orgs (for load testing). */
|
|
2
|
+
export const CURRI_POLICIES_RPC = `
|
|
3
|
+
alias Cdrcisco.Identity
|
|
4
|
+
alias Cdrcisco.Policies
|
|
5
|
+
|
|
6
|
+
try do
|
|
7
|
+
orgs = Identity.get_all_orgs()
|
|
8
|
+
|
|
9
|
+
result = Enum.flat_map(orgs, fn org ->
|
|
10
|
+
Policies.list_policies_by_org(org.id)
|
|
11
|
+
|> Enum.map(fn p ->
|
|
12
|
+
%{
|
|
13
|
+
id: p.id,
|
|
14
|
+
name: p.name,
|
|
15
|
+
api_key: p.api_key,
|
|
16
|
+
org_id: org.id,
|
|
17
|
+
org_name: org.name
|
|
18
|
+
}
|
|
19
|
+
end)
|
|
20
|
+
end)
|
|
21
|
+
|
|
22
|
+
Jason.encode!(%{policies: result, count: length(result)})
|
|
23
|
+
|> IO.puts()
|
|
24
|
+
rescue
|
|
25
|
+
e ->
|
|
26
|
+
Jason.encode!(%{error: inspect(e), policies: [], count: 0})
|
|
27
|
+
|> IO.puts()
|
|
28
|
+
end
|
|
29
|
+
`;
|
|
1
30
|
/** RPC: List all greeting policies for all orgs with rules. */
|
|
2
31
|
export const GREETING_POLICIES_RPC = `
|
|
3
32
|
alias Cdrcisco.Identity
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc-scripts.js","sourceRoot":"","sources":["../../src/lib/rpc-scripts.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6DpC,CAAC;AAEF,0EAA0E;AAC1E,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,OAAO;;;;;;qDAM4C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BA4BhC,OAAO;;;;;;mFAMgD,OAAO;;;GAGvF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDnC,CAAC"}
|
|
1
|
+
{"version":3,"file":"rpc-scripts.js","sourceRoot":"","sources":["../../src/lib/rpc-scripts.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,MAAM,CAAC,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BjC,CAAC;AAEF,+DAA+D;AAC/D,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6DpC,CAAC;AAEF,0EAA0E;AAC1E,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,OAAO;;;;;;qDAM4C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BA4BhC,OAAO;;;;;;mFAMgD,OAAO;;;GAGvF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDnC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
interface SparklineProps {
|
|
2
|
+
/** Array of numeric values to visualize. */
|
|
3
|
+
data: number[];
|
|
4
|
+
/** Width in characters (pads or truncates data). Default 24. */
|
|
5
|
+
width?: number;
|
|
6
|
+
/** Label shown before the sparkline. */
|
|
7
|
+
label?: string;
|
|
8
|
+
/** Right-side detail text (e.g., "avg 198 req/s"). */
|
|
9
|
+
detail?: string;
|
|
10
|
+
/** Sparkline color. Default 'cyan'. */
|
|
11
|
+
color?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function Sparkline({ data, width, label, detail, color }: SparklineProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=Sparkline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Sparkline.d.ts","sourceRoot":"","sources":["../../../src/ui/components/Sparkline.tsx"],"names":[],"mappings":"AAIA,UAAU,cAAc;IACtB,4CAA4C;IAC5C,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,SAAS,CAAC,EAAE,IAAI,EAAE,KAAU,EAAE,KAAK,EAAE,MAAM,EAAE,KAAc,EAAE,EAAE,cAAc,2CAwB5F"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
const BLOCKS = ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'];
|
|
4
|
+
export function Sparkline({ data, width = 24, label, detail, color = 'cyan' }) {
|
|
5
|
+
// Take last `width` data points, pad with zeros if shorter
|
|
6
|
+
const visible = data.length > width ? data.slice(-width) : data;
|
|
7
|
+
const padded = visible.length < width
|
|
8
|
+
? [...Array(width - visible.length).fill(0), ...visible]
|
|
9
|
+
: visible;
|
|
10
|
+
const min = Math.min(...padded);
|
|
11
|
+
const max = Math.max(...padded);
|
|
12
|
+
const range = max - min;
|
|
13
|
+
const bars = padded.map((v) => {
|
|
14
|
+
if (range === 0)
|
|
15
|
+
return BLOCKS[3]; // uniform data → mid-height
|
|
16
|
+
const idx = Math.round(((v - min) / range) * (BLOCKS.length - 1));
|
|
17
|
+
return BLOCKS[Math.min(idx, BLOCKS.length - 1)];
|
|
18
|
+
}).join('');
|
|
19
|
+
return (_jsxs(Box, { children: [label && _jsx(Text, { bold: true, children: label.padEnd(11) }), _jsx(Text, { color: color, children: bars }), detail && _jsx(Text, { dimColor: true, children: ` ${detail}` })] }));
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=Sparkline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Sparkline.js","sourceRoot":"","sources":["../../../src/ui/components/Sparkline.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAEhC,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAexD,MAAM,UAAU,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,GAAG,MAAM,EAAkB;IAC3F,2DAA2D;IAC3D,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAChE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,KAAK;QACnC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAS,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC;QAChE,CAAC,CAAC,OAAO,CAAC;IAEZ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,GAAG,GAAG,GAAG,CAAC;IAExB,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC5B,IAAI,KAAK,KAAK,CAAC;YAAE,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,4BAA4B;QAC/D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QAClE,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,OAAO,CACL,MAAC,GAAG,eACD,KAAK,IAAI,KAAC,IAAI,IAAC,IAAI,kBAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,GAAQ,EAC9C,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,YAAG,IAAI,GAAQ,EAChC,MAAM,IAAI,KAAC,IAAI,IAAC,QAAQ,kBAAE,KAAK,MAAM,EAAE,GAAQ,IAC5C,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -19,4 +19,5 @@ export { LogLevelBadge } from './LogLevelBadge.js';
|
|
|
19
19
|
export { ErrorBoundary } from './ErrorBoundary.js';
|
|
20
20
|
export { TabBar } from './TabBar.js';
|
|
21
21
|
export type { Tab } from './TabBar.js';
|
|
22
|
+
export { Sparkline } from './Sparkline.js';
|
|
22
23
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -17,4 +17,5 @@ export { MetricsFooter } from './MetricsFooter.js';
|
|
|
17
17
|
export { LogLevelBadge } from './LogLevelBadge.js';
|
|
18
18
|
export { ErrorBoundary } from './ErrorBoundary.js';
|
|
19
19
|
export { TabBar } from './TabBar.js';
|
|
20
|
+
export { Sparkline } from './Sparkline.js';
|
|
20
21
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ui/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ui/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MetricsContext.d.ts","sourceRoot":"","sources":["../../../src/ui/context/MetricsContext.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"MetricsContext.d.ts","sourceRoot":"","sources":["../../../src/ui/context/MetricsContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA6C,MAAM,OAAO,CAAC;AAGlE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAQzD,wBAAgB,eAAe,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,2CAS1E;AAED,wBAAgB,UAAU,IAAI,aAAa,GAAG,SAAS,CAEtD"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { createContext, useContext } from 'react';
|
|
2
|
+
import { createContext, useContext, useMemo } from 'react';
|
|
3
3
|
import { usePolling } from '../hooks/usePolling.js';
|
|
4
4
|
import { getSystemMetrics } from '../../lib/system.js';
|
|
5
5
|
const MetricsContext = createContext({ metrics: undefined });
|
|
6
6
|
export function MetricsProvider({ children }) {
|
|
7
7
|
const { data: metrics } = usePolling(getSystemMetrics, 10_000, true);
|
|
8
|
-
|
|
8
|
+
// Memoize the context value to prevent unnecessary consumer re-renders
|
|
9
|
+
const value = useMemo(() => ({ metrics }), [metrics]);
|
|
10
|
+
return (_jsx(MetricsContext.Provider, { value: value, children: children }));
|
|
9
11
|
}
|
|
10
12
|
export function useMetrics() {
|
|
11
13
|
return useContext(MetricsContext).metrics;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MetricsContext.js","sourceRoot":"","sources":["../../../src/ui/context/MetricsContext.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"MetricsContext.js","sourceRoot":"","sources":["../../../src/ui/context/MetricsContext.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAOvD,MAAM,cAAc,GAAG,aAAa,CAAsB,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;AAElF,MAAM,UAAU,eAAe,CAAC,EAAE,QAAQ,EAAiC;IACzE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,UAAU,CAAgB,gBAAgB,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACpF,uEAAuE;IACvE,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACtD,OAAO,CACL,KAAC,cAAc,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAClC,QAAQ,GACe,CAC3B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,UAAU,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC;AAC5C,CAAC"}
|
package/dist/ui/hooks/index.d.ts
CHANGED
|
@@ -7,4 +7,6 @@ export { usePolling } from "./usePolling.js";
|
|
|
7
7
|
export { useComposeLogs } from "./useComposeLogs.js";
|
|
8
8
|
export { useFinish } from "./useFinish.js";
|
|
9
9
|
export { useLogLevel } from "./useLogLevel.js";
|
|
10
|
+
export { useLoadTest } from "./useLoadTest.js";
|
|
11
|
+
export type { LoadTestPhase } from "./useLoadTest.js";
|
|
10
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/ui/hooks/index.js
CHANGED
|
@@ -5,4 +5,5 @@ export { usePolling } from "./usePolling.js";
|
|
|
5
5
|
export { useComposeLogs } from "./useComposeLogs.js";
|
|
6
6
|
export { useFinish } from "./useFinish.js";
|
|
7
7
|
export { useLogLevel } from "./useLogLevel.js";
|
|
8
|
+
export { useLoadTest } from "./useLoadTest.js";
|
|
8
9
|
//# sourceMappingURL=index.js.map
|