appmesh 3.1.6 → 3.1.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/README.md +27 -23
- package/dist/appmesh.esm.js +1 -1
- package/package.json +2 -2
- package/src/appmesh.js +108 -106
- package/src/appmesh_tcp.js +306 -210
- package/src/worker.js +34 -44
- package/dist/894.appmesh.esm.js +0 -1
package/src/appmesh.js
CHANGED
|
@@ -113,9 +113,7 @@ function parseDuration(duration) {
|
|
|
113
113
|
const datePattern = `(${numbers}Y)?(${numbers}M)?(${numbers}W)?(${numbers}D)?`;
|
|
114
114
|
const timePattern = `T(${fractionalNumbers}H)?(${fractionalNumbers}M)?(${fractionalNumbers}S)?`;
|
|
115
115
|
const iso8601 = `P(?:${datePattern}(?:${timePattern})?)`;
|
|
116
|
-
const objMap = [
|
|
117
|
-
"years", "months", "weeks", "days", "hours", "minutes", "seconds",
|
|
118
|
-
];
|
|
116
|
+
const objMap = ["years", "months", "weeks", "days", "hours", "minutes", "seconds"];
|
|
119
117
|
|
|
120
118
|
// Parse duration string
|
|
121
119
|
const matches = duration.replace(/,/g, ".").match(new RegExp(iso8601));
|
|
@@ -252,7 +250,8 @@ async function _lookupGroup(key, value) {
|
|
|
252
250
|
return parts[0] && !isNaN(gid) ? { name: parts[0], gid } : null;
|
|
253
251
|
}
|
|
254
252
|
// macOS: "name: staff" / "gid: 20" lines, and empty output when unknown
|
|
255
|
-
const macResult = spawnSync('dscacheutil', ['-q', 'group', '-a', key, String(value)],
|
|
253
|
+
const macResult = spawnSync('dscacheutil', ['-q', 'group', '-a', key, String(value)],
|
|
254
|
+
{ encoding: 'utf8', timeout: 3000 });
|
|
256
255
|
if (macResult.status !== 0 || !macResult.stdout) return null;
|
|
257
256
|
const lines = macResult.stdout.split('\n');
|
|
258
257
|
const nameLine = lines.find(entry => entry.startsWith('name:'));
|
|
@@ -360,7 +359,8 @@ class AppMeshClient {
|
|
|
360
359
|
* rejectUnauthorized: true
|
|
361
360
|
* };
|
|
362
361
|
*/
|
|
363
|
-
constructor(baseURL = ENV.isNode ? 'https://127.0.0.1:6060' : window.location.origin,
|
|
362
|
+
constructor(baseURL = ENV.isNode ? 'https://127.0.0.1:6060' : window.location.origin,
|
|
363
|
+
sslConfig = null, tokenProvider = null) {
|
|
364
364
|
// Base URL for API requests
|
|
365
365
|
this.baseURL = baseURL;
|
|
366
366
|
|
|
@@ -371,7 +371,7 @@ class AppMeshClient {
|
|
|
371
371
|
// read from it via _getAccessToken()
|
|
372
372
|
this._tokenProvider = null;
|
|
373
373
|
if (tokenProvider) {
|
|
374
|
-
this.
|
|
374
|
+
this.setTokenProvider(tokenProvider);
|
|
375
375
|
}
|
|
376
376
|
|
|
377
377
|
// Configure axios instance
|
|
@@ -411,15 +411,14 @@ class AppMeshClient {
|
|
|
411
411
|
);
|
|
412
412
|
|
|
413
413
|
// Response interceptor
|
|
414
|
-
this._client.interceptors.response.use(
|
|
415
|
-
response => this._handleUnauthorizedRetry(response),
|
|
416
|
-
error => {
|
|
414
|
+
this._client.interceptors.response.use(response => this._handleUnauthorizedRetry(response), error => {
|
|
417
415
|
// Typed SDK errors (e.g. JSON parse failures from transformResponse) pass through unchanged
|
|
418
416
|
if (error instanceof AppMeshError) {
|
|
419
417
|
return Promise.reject(error);
|
|
420
418
|
}
|
|
421
419
|
// Network-level failure (DNS, connection refused, timeout, ...)
|
|
422
|
-
const err = new AppMeshError('Request failed: ' + (error.message || 'Unknown error'),
|
|
420
|
+
const err = new AppMeshError('Request failed: ' + (error.message || 'Unknown error'),
|
|
421
|
+
error.response?.status ?? null, error.response?.data ?? null);
|
|
423
422
|
err.cause = error;
|
|
424
423
|
return Promise.reject(err);
|
|
425
424
|
}
|
|
@@ -432,7 +431,7 @@ class AppMeshClient {
|
|
|
432
431
|
* and `clear()` follow the contract in token_provider.js.
|
|
433
432
|
* @param {Object} provider - Token provider
|
|
434
433
|
*/
|
|
435
|
-
|
|
434
|
+
setTokenProvider(provider) {
|
|
436
435
|
if (!provider || typeof provider.getAccessToken !== 'function') {
|
|
437
436
|
throw new TypeError('tokenProvider must implement async getAccessToken()');
|
|
438
437
|
}
|
|
@@ -440,21 +439,21 @@ class AppMeshClient {
|
|
|
440
439
|
}
|
|
441
440
|
|
|
442
441
|
/** Attach a caller-owned, non-refreshing access token in memory. */
|
|
443
|
-
|
|
442
|
+
setBearerToken(token) {
|
|
444
443
|
if (token === null || token === undefined) {
|
|
445
|
-
this.
|
|
444
|
+
this.clearBearerToken();
|
|
446
445
|
return;
|
|
447
446
|
}
|
|
448
|
-
this.
|
|
447
|
+
this.setTokenProvider(new StaticAccessTokenProvider(token));
|
|
449
448
|
}
|
|
450
449
|
|
|
451
|
-
/** Source-compatible alias for
|
|
452
|
-
|
|
453
|
-
this.
|
|
450
|
+
/** Source-compatible alias for setBearerToken(). */
|
|
451
|
+
setToken(token) {
|
|
452
|
+
this.setBearerToken(token);
|
|
454
453
|
}
|
|
455
454
|
|
|
456
455
|
/** Remove the locally attached bearer without contacting Engine or the authentication service. */
|
|
457
|
-
|
|
456
|
+
clearBearerToken() {
|
|
458
457
|
const provider = this._tokenProvider;
|
|
459
458
|
if (provider && typeof provider.clear === 'function') {
|
|
460
459
|
provider.clear();
|
|
@@ -508,12 +507,12 @@ class AppMeshClient {
|
|
|
508
507
|
}
|
|
509
508
|
|
|
510
509
|
/** Return Engine's public OAuth/OIDC configuration. */
|
|
511
|
-
async
|
|
510
|
+
async getAuthConfig() {
|
|
512
511
|
return (await this._request("get", "/appmesh/auth/config")).data;
|
|
513
512
|
}
|
|
514
513
|
|
|
515
514
|
/** Return the verified principal represented by the current bearer. */
|
|
516
|
-
async
|
|
515
|
+
async getCurrentPrincipal() {
|
|
517
516
|
return (await this._request("get", "/appmesh/principal/self")).data;
|
|
518
517
|
}
|
|
519
518
|
|
|
@@ -521,7 +520,7 @@ class AppMeshClient {
|
|
|
521
520
|
* Get all applications info
|
|
522
521
|
* @returns {Object} All apps info
|
|
523
522
|
*/
|
|
524
|
-
async
|
|
523
|
+
async listApps() {
|
|
525
524
|
const response = await this._request("get", "/appmesh/applications");
|
|
526
525
|
return response.data;
|
|
527
526
|
}
|
|
@@ -531,7 +530,7 @@ class AppMeshClient {
|
|
|
531
530
|
* @param {string} name - App name
|
|
532
531
|
* @returns {Object} App config
|
|
533
532
|
*/
|
|
534
|
-
async
|
|
533
|
+
async getApp(name) {
|
|
535
534
|
const response = await this._request("get", `/appmesh/app/${name}`);
|
|
536
535
|
return response.data;
|
|
537
536
|
}
|
|
@@ -542,7 +541,7 @@ class AppMeshClient {
|
|
|
542
541
|
* @returns {boolean} True if healthy; false only when the daemon's health verdict says unhealthy
|
|
543
542
|
* @throws {AppMeshError} On auth/missing-app/server errors (non-200) or network/transport failure
|
|
544
543
|
*/
|
|
545
|
-
async
|
|
544
|
+
async checkAppHealth(name) {
|
|
546
545
|
const response = await this._request("get", `/appmesh/app/${name}/health`);
|
|
547
546
|
return parseInt(response.data, 10) === 0;
|
|
548
547
|
}
|
|
@@ -579,9 +578,9 @@ class AppMeshClient {
|
|
|
579
578
|
* resource_limit: { cpu_shares: null, memory_mb: null, memory_virt_mb: null },
|
|
580
579
|
* behavior: { exit: "standby", exit_code_actions: { "0": "keepalive" } }
|
|
581
580
|
* };
|
|
582
|
-
* await client.
|
|
581
|
+
* await client.addApp("ping", appConfig);
|
|
583
582
|
*/
|
|
584
|
-
async
|
|
583
|
+
async addApp(name, appJson) {
|
|
585
584
|
const response = await this._request("put", `/appmesh/app/${name}`, appJson);
|
|
586
585
|
return response.data;
|
|
587
586
|
}
|
|
@@ -591,7 +590,7 @@ class AppMeshClient {
|
|
|
591
590
|
* @param {string} name - App name
|
|
592
591
|
* @returns {Promise<boolean>} Success status
|
|
593
592
|
*/
|
|
594
|
-
async
|
|
593
|
+
async deleteApp(name) {
|
|
595
594
|
try {
|
|
596
595
|
const response = await this._request("delete", `/appmesh/app/${name}`);
|
|
597
596
|
return response.status === 200;
|
|
@@ -606,7 +605,7 @@ class AppMeshClient {
|
|
|
606
605
|
* @param {string} name - App name
|
|
607
606
|
* @returns {Promise<boolean>} true on success; failures throw AppMeshError
|
|
608
607
|
*/
|
|
609
|
-
async
|
|
608
|
+
async enableApp(name) {
|
|
610
609
|
await this._request("post", `/appmesh/app/${name}/enable`);
|
|
611
610
|
return true;
|
|
612
611
|
}
|
|
@@ -616,7 +615,7 @@ class AppMeshClient {
|
|
|
616
615
|
* @param {string} name - App name
|
|
617
616
|
* @returns {Promise<boolean>} true on success; failures throw AppMeshError
|
|
618
617
|
*/
|
|
619
|
-
async
|
|
618
|
+
async disableApp(name) {
|
|
620
619
|
await this._request("post", `/appmesh/app/${name}/disable`);
|
|
621
620
|
return true;
|
|
622
621
|
}
|
|
@@ -632,7 +631,8 @@ class AppMeshClient {
|
|
|
632
631
|
* @param {number} [timeout=0] - Server long-poll timeout in seconds
|
|
633
632
|
* @returns {Promise<AppOutput>} Output body, next cursor, and exit code when available
|
|
634
633
|
*/
|
|
635
|
-
async
|
|
634
|
+
async getAppOutput(app_name, stdout_position = 0, stdout_index = 0, stdout_maxsize = 10240,
|
|
635
|
+
process_uuid = "", timeout = 0) {
|
|
636
636
|
const params = {
|
|
637
637
|
stdout_position: stdout_position.toString(),
|
|
638
638
|
stdout_index: stdout_index.toString(),
|
|
@@ -658,7 +658,8 @@ class AppMeshClient {
|
|
|
658
658
|
* @param {number|string} [lifecycle] - Lifecycle time
|
|
659
659
|
* @returns {Promise<number|null>} Exit code parsed from `X-Exit-Code`, or `null` when absent
|
|
660
660
|
*/
|
|
661
|
-
async
|
|
661
|
+
async runAppSync(app, stdoutHandler = defaultOutputHandler, maxTime = CONSTANTS.DEFAULT_RUN_APP_TIMEOUT_SECONDS,
|
|
662
|
+
lifecycle = CONSTANTS.DEFAULT_RUN_APP_LIFECYCLE_SECONDS) {
|
|
662
663
|
const params = {
|
|
663
664
|
timeout: parseDuration(maxTime),
|
|
664
665
|
lifecycle: parseDuration(lifecycle)
|
|
@@ -667,17 +668,15 @@ class AppMeshClient {
|
|
|
667
668
|
const response = await this._request("post", "/appmesh/app/syncrun", app, { params });
|
|
668
669
|
let exitCode = null;
|
|
669
670
|
|
|
671
|
+
if (stdoutHandler) {
|
|
672
|
+
stdoutHandler(response.data, 0);
|
|
673
|
+
}
|
|
670
674
|
if (response.status === 200) {
|
|
671
|
-
if (stdoutHandler) {
|
|
672
|
-
stdoutHandler(response.data, 0);
|
|
673
|
-
}
|
|
674
675
|
// axios lowercases header names; the TCP transport keeps the daemon's exact case
|
|
675
676
|
const exitCodeHeader = _getHeader(response.headers, "X-Exit-Code");
|
|
676
677
|
if (exitCodeHeader) {
|
|
677
678
|
exitCode = parseInt(exitCodeHeader, 10);
|
|
678
679
|
}
|
|
679
|
-
} else if (stdoutHandler) {
|
|
680
|
-
stdoutHandler(response.data, 0);
|
|
681
680
|
}
|
|
682
681
|
|
|
683
682
|
return exitCode;
|
|
@@ -690,7 +689,8 @@ class AppMeshClient {
|
|
|
690
689
|
* @param {string|number} [lifecycle] - Lifecycle time
|
|
691
690
|
* @returns {AppRun} Running app handle that also snapshots the current forwarding host
|
|
692
691
|
*/
|
|
693
|
-
async
|
|
692
|
+
async runAppAsync(app, maxTime = CONSTANTS.DEFAULT_RUN_APP_TIMEOUT_SECONDS,
|
|
693
|
+
lifecycle = CONSTANTS.DEFAULT_RUN_APP_LIFECYCLE_SECONDS) {
|
|
694
694
|
const params = {
|
|
695
695
|
timeout: parseDuration(maxTime),
|
|
696
696
|
lifecycle: parseDuration(lifecycle)
|
|
@@ -709,14 +709,14 @@ class AppMeshClient {
|
|
|
709
709
|
* the SDK also attempts to delete the temporary run app.
|
|
710
710
|
* @throws {AppMeshError} If polling the app output fails.
|
|
711
711
|
*/
|
|
712
|
-
async
|
|
712
|
+
async waitForAsyncRun(run, stdoutHandler = defaultOutputHandler, timeout = 0) {
|
|
713
713
|
if (run) {
|
|
714
714
|
let lastOutputPosition = 0;
|
|
715
715
|
const start = new Date();
|
|
716
716
|
const interval = 1;
|
|
717
717
|
|
|
718
718
|
while (run.procUid.length > 0) {
|
|
719
|
-
const appOut = await this.
|
|
719
|
+
const appOut = await this.getAppOutput(run.appName, lastOutputPosition, 0, 20480, run.procUid, interval);
|
|
720
720
|
if (appOut.output && stdoutHandler) {
|
|
721
721
|
stdoutHandler(appOut.output, lastOutputPosition);
|
|
722
722
|
}
|
|
@@ -727,7 +727,7 @@ class AppMeshClient {
|
|
|
727
727
|
|
|
728
728
|
if (appOut.exitCode !== null) {
|
|
729
729
|
// Process finished
|
|
730
|
-
await this.
|
|
730
|
+
await this.deleteApp(run.appName);
|
|
731
731
|
return appOut.exitCode;
|
|
732
732
|
}
|
|
733
733
|
|
|
@@ -749,7 +749,7 @@ class AppMeshClient {
|
|
|
749
749
|
* @param {number} [timeout=300] - Timeout in seconds
|
|
750
750
|
* @returns {Promise<string>} Response from app
|
|
751
751
|
*/
|
|
752
|
-
async
|
|
752
|
+
async runTask(appName, data, timeout = 300) {
|
|
753
753
|
if (timeout <= 0) {
|
|
754
754
|
timeout = 300;
|
|
755
755
|
}
|
|
@@ -764,13 +764,16 @@ class AppMeshClient {
|
|
|
764
764
|
* @param {string} appName - App name
|
|
765
765
|
* @returns {Promise<boolean>} true on success; failures throw AppMeshError
|
|
766
766
|
*/
|
|
767
|
-
async
|
|
767
|
+
async cancelTask(appName) {
|
|
768
768
|
await this._request("delete", `/appmesh/app/${appName}/task`);
|
|
769
769
|
return true;
|
|
770
770
|
}
|
|
771
771
|
|
|
772
772
|
/**
|
|
773
|
-
* Download a remote file.
|
|
773
|
+
* Download a remote file.
|
|
774
|
+
*
|
|
775
|
+
* Plain-HTTP transport: GET answers the file bytes; the agent proxy serves
|
|
776
|
+
* the same route from local disk.
|
|
774
777
|
*
|
|
775
778
|
* - **Node.js**: `localFile` is a filesystem path — the response body is written to it,
|
|
776
779
|
* and when `applyAttrs` is true the returned mode and best-effort owner/group metadata
|
|
@@ -785,7 +788,7 @@ class AppMeshClient {
|
|
|
785
788
|
* @param {boolean} [applyAttrs=false] - Node.js only: apply returned mode and best-effort
|
|
786
789
|
* owner/group metadata on non-Windows platforms
|
|
787
790
|
*/
|
|
788
|
-
async
|
|
791
|
+
async downloadFile(filePath, localFile = null, applyAttrs = false) {
|
|
789
792
|
if (!localFile) localFile = filePath.split(/[\\/]/).pop();
|
|
790
793
|
const headers = { [CONSTANTS.HTTP_HEADER_KEY_X_FILE_PATH]: encodeURIComponent(filePath) };
|
|
791
794
|
const response = await this._request("get", "/appmesh/file/download", null, {
|
|
@@ -795,6 +798,13 @@ class AppMeshClient {
|
|
|
795
798
|
}
|
|
796
799
|
});
|
|
797
800
|
|
|
801
|
+
// A JSON reply without Content-Disposition is a legacy placeholder, not content.
|
|
802
|
+
if (response.status === 200 && !response.headers?.["content-disposition"] &&
|
|
803
|
+
String(response.headers?.["content-type"] ?? "").toLowerCase().includes("json")) {
|
|
804
|
+
throw new AppMeshError(
|
|
805
|
+
`File download is not supported by this server surface: ${filePath}`, response.status, response.data);
|
|
806
|
+
}
|
|
807
|
+
|
|
798
808
|
if (response.status !== 200) {
|
|
799
809
|
throw new AppMeshError(`Failed to download file: ${filePath}`, response.status, response.data);
|
|
800
810
|
}
|
|
@@ -846,12 +856,16 @@ class AppMeshClient {
|
|
|
846
856
|
|
|
847
857
|
/**
|
|
848
858
|
* Upload a file to the remote server.
|
|
859
|
+
*
|
|
860
|
+
* Plain-HTTP transport: POST streams the raw file bytes as the body; the
|
|
861
|
+
* agent proxy accepts the same route.
|
|
862
|
+
*
|
|
849
863
|
* @param {string|File} localFile - Local file path/object
|
|
850
864
|
* @param {string} [filePath=null] - Remote target path; defaults to the basename of localFile
|
|
851
865
|
* @param {boolean} [applyAttrs=false] - In Node.js, send local permission bits plus
|
|
852
866
|
* user/group (names when resolvable locally, numeric ids otherwise)
|
|
853
867
|
*/
|
|
854
|
-
async
|
|
868
|
+
async uploadFile(localFile, filePath = null, applyAttrs = false) {
|
|
855
869
|
if (!filePath) {
|
|
856
870
|
// Node.js passes a path string; browser passes a File (use its name)
|
|
857
871
|
const sourceName = typeof localFile === 'string' ? localFile : localFile && localFile.name;
|
|
@@ -861,73 +875,55 @@ class AppMeshClient {
|
|
|
861
875
|
filePath = sourceName.split(/[\\/]/).pop();
|
|
862
876
|
}
|
|
863
877
|
const headers = { [CONSTANTS.HTTP_HEADER_KEY_X_FILE_PATH]: encodeURIComponent(filePath) };
|
|
864
|
-
let
|
|
878
|
+
let body;
|
|
865
879
|
|
|
866
880
|
if (ENV.isNode) {
|
|
867
|
-
// Node.js environment
|
|
868
|
-
const FormData = (await import('form-data')).default;
|
|
869
881
|
const fs = await import('fs');
|
|
870
|
-
formData = new FormData();
|
|
871
|
-
|
|
872
|
-
const filename = filePath.split('/').pop();
|
|
873
|
-
formData.append("filename", filename);
|
|
874
|
-
|
|
875
882
|
const stat = fs.statSync(localFile);
|
|
876
|
-
if (stat.size < 10 * 1024 * 1024) {
|
|
877
|
-
// For files < 10MB, use buffer
|
|
878
|
-
const fileBuffer = fs.readFileSync(localFile);
|
|
879
|
-
formData.append("file", fileBuffer, { filename: localFile.split('/').pop() });
|
|
880
|
-
} else {
|
|
881
|
-
// Stream for larger files
|
|
882
|
-
formData.append("file", fs.createReadStream(localFile));
|
|
883
|
-
}
|
|
884
883
|
|
|
885
|
-
// Add file attributes
|
|
886
884
|
if (applyAttrs) {
|
|
887
885
|
headers["X-File-Mode"] = (stat.mode & 0o777).toString(); // Only permission bits
|
|
888
|
-
// Send user/group names when resolvable; the daemon also accepts
|
|
889
|
-
// all-digit values (os::chown -> getUidByName numeric fallback, and
|
|
890
|
-
// the Go agent's ApplyFileAttributes), so fall back to numeric ids.
|
|
891
886
|
const username = await _resolveUserName(stat.uid);
|
|
892
887
|
const groupName = await _resolveGroupName(stat.gid);
|
|
893
888
|
headers["X-File-User"] = username || String(stat.uid);
|
|
894
889
|
headers["X-File-Group"] = groupName || String(stat.gid);
|
|
895
890
|
}
|
|
896
891
|
|
|
897
|
-
//
|
|
898
|
-
|
|
892
|
+
// Stream larger files; buffer small ones.
|
|
893
|
+
body = stat.size < 10 * 1024 * 1024 ? fs.readFileSync(localFile) : fs.createReadStream(localFile);
|
|
899
894
|
} else {
|
|
900
895
|
// Browser environment
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
// Get filename
|
|
904
|
-
let filename;
|
|
905
|
-
if (localFile instanceof File) {
|
|
906
|
-
filename = localFile.name;
|
|
907
|
-
} else if (localFile instanceof Blob) {
|
|
908
|
-
filename = filePath.split('/').pop();
|
|
896
|
+
if (localFile instanceof File || localFile instanceof Blob) {
|
|
897
|
+
body = localFile;
|
|
909
898
|
} else {
|
|
910
899
|
throw new AppMeshError('In browser, localFile must be File or Blob');
|
|
911
900
|
}
|
|
912
|
-
|
|
913
|
-
formData.append("filename", filename);
|
|
914
|
-
formData.append("file", localFile);
|
|
915
901
|
}
|
|
916
902
|
|
|
917
|
-
await this._request("post", "/appmesh/file/upload",
|
|
903
|
+
const response = await this._request("post", "/appmesh/file/upload", body, {
|
|
918
904
|
headers,
|
|
919
905
|
config: {
|
|
920
906
|
maxBodyLength: Infinity,
|
|
921
907
|
maxContentLength: Infinity
|
|
922
908
|
}
|
|
923
909
|
});
|
|
910
|
+
if (response.status !== 200 && response.status !== 201) {
|
|
911
|
+
throw new AppMeshError(`Failed to upload file: ${filePath}`, response.status, response.data);
|
|
912
|
+
}
|
|
913
|
+
// A 200 JSON status reply means a legacy daemon stored nothing.
|
|
914
|
+
const contentType = String(response.headers?.["content-type"] ?? "").toLowerCase();
|
|
915
|
+
if (response.status === 200 && contentType.includes("json") &&
|
|
916
|
+
response.data && typeof response.data === "object" && "message" in response.data) {
|
|
917
|
+
throw new AppMeshError(
|
|
918
|
+
`File upload is not supported by this server surface: ${filePath}`, response.status, response.data);
|
|
919
|
+
}
|
|
924
920
|
}
|
|
925
921
|
|
|
926
922
|
/**
|
|
927
923
|
* Get host resource usage
|
|
928
924
|
* @returns {Object} Resource stats
|
|
929
925
|
*/
|
|
930
|
-
async
|
|
926
|
+
async getHostResources() {
|
|
931
927
|
const response = await this._request("get", "/appmesh/resources");
|
|
932
928
|
return response.data;
|
|
933
929
|
}
|
|
@@ -936,7 +932,7 @@ class AppMeshClient {
|
|
|
936
932
|
* Get current configuration
|
|
937
933
|
* @returns {Promise<Object>} Config JSON
|
|
938
934
|
*/
|
|
939
|
-
async
|
|
935
|
+
async getConfig() {
|
|
940
936
|
const response = await this._request("get", "/appmesh/config");
|
|
941
937
|
return response.data;
|
|
942
938
|
}
|
|
@@ -946,7 +942,7 @@ class AppMeshClient {
|
|
|
946
942
|
* @param {Object} config - Partial config document to POST to `/appmesh/config`
|
|
947
943
|
* @returns {Object} Updated config
|
|
948
944
|
*/
|
|
949
|
-
async
|
|
945
|
+
async setConfig(config) {
|
|
950
946
|
const response = await this._request("post", "/appmesh/config", config);
|
|
951
947
|
return response.data;
|
|
952
948
|
}
|
|
@@ -956,8 +952,8 @@ class AppMeshClient {
|
|
|
956
952
|
* @param {string} [level="DEBUG"] - Log level
|
|
957
953
|
* @returns {string} Updated level
|
|
958
954
|
*/
|
|
959
|
-
async
|
|
960
|
-
const response = await this.
|
|
955
|
+
async setLogLevel(level = "DEBUG") {
|
|
956
|
+
const response = await this.setConfig({ BaseConfig: { LogLevel: level } });
|
|
961
957
|
return response.BaseConfig.LogLevel;
|
|
962
958
|
}
|
|
963
959
|
|
|
@@ -967,7 +963,7 @@ class AppMeshClient {
|
|
|
967
963
|
* @param {string} labelValue - Label value
|
|
968
964
|
* @returns {Promise<boolean>} true on success; failures throw AppMeshError
|
|
969
965
|
*/
|
|
970
|
-
async
|
|
966
|
+
async addLabel(labelName, labelValue) {
|
|
971
967
|
await this._request("put", `/appmesh/label/${labelName}`, null, { params: { value: labelValue } });
|
|
972
968
|
return true;
|
|
973
969
|
}
|
|
@@ -978,7 +974,7 @@ class AppMeshClient {
|
|
|
978
974
|
* @param {string} labelName - Label name
|
|
979
975
|
* @returns {Promise<boolean>} true on success; failures throw AppMeshError
|
|
980
976
|
*/
|
|
981
|
-
async
|
|
977
|
+
async deleteLabel(labelName) {
|
|
982
978
|
await this._request("delete", `/appmesh/label/${labelName}`);
|
|
983
979
|
return true;
|
|
984
980
|
}
|
|
@@ -988,59 +984,59 @@ class AppMeshClient {
|
|
|
988
984
|
* Get all server labels
|
|
989
985
|
* @returns {Promise<Object>} All labels
|
|
990
986
|
*/
|
|
991
|
-
async
|
|
987
|
+
async listLabels() {
|
|
992
988
|
const response = await this._request("get", "/appmesh/labels");
|
|
993
989
|
return response.data;
|
|
994
990
|
}
|
|
995
991
|
|
|
996
992
|
|
|
997
993
|
/** List Engine authorization overlays keyed by immutable principal ID. */
|
|
998
|
-
async
|
|
994
|
+
async listPrincipals() {
|
|
999
995
|
return (await this._request("get", "/appmesh/principals")).data;
|
|
1000
996
|
}
|
|
1001
997
|
|
|
1002
998
|
/** Update an Engine authorization overlay; never mutate IdP account data. */
|
|
1003
|
-
async
|
|
999
|
+
async updatePrincipal(principalId, policy) {
|
|
1004
1000
|
await this._request("post", `/appmesh/principal/${encodeURIComponent(principalId)}`, policy);
|
|
1005
1001
|
return true;
|
|
1006
1002
|
}
|
|
1007
1003
|
|
|
1008
1004
|
/** Delete only an Engine authorization overlay. */
|
|
1009
|
-
async
|
|
1005
|
+
async deletePrincipal(principalId) {
|
|
1010
1006
|
await this._request("delete", `/appmesh/principal/${encodeURIComponent(principalId)}`);
|
|
1011
1007
|
return true;
|
|
1012
1008
|
}
|
|
1013
1009
|
|
|
1014
1010
|
/** Safe compatibility alias returning a Principal, not an IdP user. */
|
|
1015
|
-
async
|
|
1016
|
-
return this.
|
|
1011
|
+
async getCurrentUser() {
|
|
1012
|
+
return this.getCurrentPrincipal();
|
|
1017
1013
|
}
|
|
1018
1014
|
|
|
1019
1015
|
/**
|
|
1020
1016
|
* Get available permissions
|
|
1021
1017
|
* @returns {Object[]} Permission list
|
|
1022
1018
|
*/
|
|
1023
|
-
async
|
|
1019
|
+
async listPermissions() {
|
|
1024
1020
|
const response = await this._request("get", "/appmesh/permissions");
|
|
1025
1021
|
return response.data;
|
|
1026
1022
|
}
|
|
1027
1023
|
|
|
1028
1024
|
/** Get effective permissions for the current verified principal. */
|
|
1029
|
-
async
|
|
1025
|
+
async getPrincipalPermissions() {
|
|
1030
1026
|
const response = await this._request("get", "/appmesh/principal/self/permissions");
|
|
1031
1027
|
return response.data;
|
|
1032
1028
|
}
|
|
1033
1029
|
|
|
1034
|
-
/** Safe compatibility alias for
|
|
1035
|
-
async
|
|
1036
|
-
return this.
|
|
1030
|
+
/** Safe compatibility alias for getPrincipalPermissions(). */
|
|
1031
|
+
async getUserPermissions() {
|
|
1032
|
+
return this.getPrincipalPermissions();
|
|
1037
1033
|
}
|
|
1038
1034
|
|
|
1039
1035
|
/**
|
|
1040
1036
|
* Get all roles and permissions
|
|
1041
1037
|
* @returns {Object[]} Role array
|
|
1042
1038
|
*/
|
|
1043
|
-
async
|
|
1039
|
+
async listRoles() {
|
|
1044
1040
|
const response = await this._request("get", "/appmesh/roles");
|
|
1045
1041
|
return response.data;
|
|
1046
1042
|
}
|
|
@@ -1051,7 +1047,7 @@ class AppMeshClient {
|
|
|
1051
1047
|
* @param {Object} rolePermissionJson - Permission IDs
|
|
1052
1048
|
* @returns {Promise<boolean>} true on success; failures throw AppMeshError
|
|
1053
1049
|
*/
|
|
1054
|
-
async
|
|
1050
|
+
async updateRole(roleName, rolePermissionJson) {
|
|
1055
1051
|
await this._request("post", `/appmesh/role/${roleName}`, rolePermissionJson);
|
|
1056
1052
|
return true;
|
|
1057
1053
|
}
|
|
@@ -1061,7 +1057,7 @@ class AppMeshClient {
|
|
|
1061
1057
|
* @param {string} roleName - Role name
|
|
1062
1058
|
* @returns {Promise<boolean>} true on success; failures throw AppMeshError
|
|
1063
1059
|
*/
|
|
1064
|
-
async
|
|
1060
|
+
async deleteRole(roleName) {
|
|
1065
1061
|
await this._request("delete", `/appmesh/role/${roleName}`);
|
|
1066
1062
|
return true;
|
|
1067
1063
|
}
|
|
@@ -1070,7 +1066,7 @@ class AppMeshClient {
|
|
|
1070
1066
|
* Get raw Prometheus metrics text from the server.
|
|
1071
1067
|
* @returns {Promise<string>} Metrics text
|
|
1072
1068
|
*/
|
|
1073
|
-
async
|
|
1069
|
+
async getMetrics() {
|
|
1074
1070
|
const response = await this._request("get", "/appmesh/metrics", null, {
|
|
1075
1071
|
config: { responseType: "text" }
|
|
1076
1072
|
});
|
|
@@ -1082,7 +1078,8 @@ class AppMeshClient {
|
|
|
1082
1078
|
* @throws {AppMeshError} Always — use AppMeshClientTCP for event subscriptions.
|
|
1083
1079
|
*/
|
|
1084
1080
|
async subscribe() {
|
|
1085
|
-
throw new AppMeshError("subscribe requires the TCP client (AppMeshClientTCP, imported from 'appmesh/tcp');
|
|
1081
|
+
throw new AppMeshError("subscribe requires the TCP client (AppMeshClientTCP, imported from 'appmesh/tcp'); " +
|
|
1082
|
+
"the HTTP client does not support event subscriptions");
|
|
1086
1083
|
}
|
|
1087
1084
|
|
|
1088
1085
|
/**
|
|
@@ -1090,7 +1087,8 @@ class AppMeshClient {
|
|
|
1090
1087
|
* @throws {AppMeshError} Always — use AppMeshClientTCP for event subscriptions.
|
|
1091
1088
|
*/
|
|
1092
1089
|
async unsubscribe() {
|
|
1093
|
-
throw new AppMeshError("unsubscribe requires the TCP client (AppMeshClientTCP, imported from 'appmesh/tcp');
|
|
1090
|
+
throw new AppMeshError("unsubscribe requires the TCP client (AppMeshClientTCP, imported from 'appmesh/tcp'); " +
|
|
1091
|
+
"the HTTP client does not support event subscriptions");
|
|
1094
1092
|
}
|
|
1095
1093
|
|
|
1096
1094
|
/**
|
|
@@ -1297,7 +1295,7 @@ class AppRun {
|
|
|
1297
1295
|
* @param {function} callback - Function to execute within the forward host context
|
|
1298
1296
|
* @returns {Promise<*>} Result of the callback function
|
|
1299
1297
|
*/
|
|
1300
|
-
async
|
|
1298
|
+
async withForwardingHost(callback) {
|
|
1301
1299
|
const originalValue = this._client.forwardingHost;
|
|
1302
1300
|
this._client.forwardingHost = this._forwardingHost;
|
|
1303
1301
|
try {
|
|
@@ -1314,14 +1312,18 @@ class AppRun {
|
|
|
1314
1312
|
* @returns {Promise<number|null>} Return exit code if process finished, return null for timeout or exception
|
|
1315
1313
|
*/
|
|
1316
1314
|
async wait(stdoutHandler = defaultOutputHandler, timeout = 0) {
|
|
1317
|
-
return this.
|
|
1318
|
-
this._client.
|
|
1315
|
+
return this.withForwardingHost(() =>
|
|
1316
|
+
this._client.waitForAsyncRun(this, stdoutHandler, timeout)
|
|
1319
1317
|
);
|
|
1320
1318
|
}
|
|
1321
1319
|
}
|
|
1322
1320
|
|
|
1323
1321
|
// Export the main classes
|
|
1324
|
-
export {
|
|
1322
|
+
export {
|
|
1323
|
+
AppMeshClient, AppOutput, AppRun, AppMeshError, AppRemovedError, TransportDisconnectedError,
|
|
1324
|
+
DEFAULT_CA_FILE, StaticAccessTokenProvider, RefreshTokenProvider
|
|
1325
|
+
};
|
|
1325
1326
|
// Exported for the TCP client (Node.js only); not part of the browser-facing API
|
|
1326
1327
|
export { _resolveUid, _resolveGid, _resolveUserName, _resolveGroupName };
|
|
1327
1328
|
export default AppMeshClient;
|
|
1329
|
+
|