@coralogix/rum-cli 1.0.0

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.
Files changed (59) hide show
  1. package/.eslintignore +1 -0
  2. package/.eslintrc.js +31 -0
  3. package/.github/workflows/npm-publish.yml +41 -0
  4. package/README.md +59 -0
  5. package/api/rum-api.ts +73 -0
  6. package/cli/rum-cli.ts +79 -0
  7. package/cli/utils/traverse-folder.util.ts +33 -0
  8. package/config/config.ts +31 -0
  9. package/config/index.js +7 -0
  10. package/config/index.ts +3 -0
  11. package/dist/api/rum-api.d.ts +2 -0
  12. package/dist/api/rum-api.js +86 -0
  13. package/dist/cli/rum-cli.d.ts +3 -0
  14. package/dist/cli/rum-cli.js +77 -0
  15. package/dist/cli/utils/traverse-folder.util.d.ts +2 -0
  16. package/dist/cli/utils/traverse-folder.util.js +42 -0
  17. package/dist/config/config.d.ts +16 -0
  18. package/dist/config/config.js +16 -0
  19. package/dist/config/index.d.ts +2 -0
  20. package/dist/config/index.js +8 -0
  21. package/dist/model/cli.model.d.ts +1 -0
  22. package/dist/model/cli.model.js +13 -0
  23. package/dist/src/app/proto-models/com/coralogix/rum/v2/audit_log.d.ts +24 -0
  24. package/dist/src/app/proto-models/com/coralogix/rum/v2/audit_log.js +62 -0
  25. package/dist/src/app/proto-models/com/coralogix/rum/v2/chunk.d.ts +43 -0
  26. package/dist/src/app/proto-models/com/coralogix/rum/v2/chunk.js +252 -0
  27. package/dist/src/app/proto-models/com/coralogix/rum/v2/file.d.ts +26 -0
  28. package/dist/src/app/proto-models/com/coralogix/rum/v2/file.js +140 -0
  29. package/dist/src/app/proto-models/com/coralogix/rum/v2/rum_service.d.ts +69 -0
  30. package/dist/src/app/proto-models/com/coralogix/rum/v2/rum_service.js +190 -0
  31. package/dist/src/app/proto-models/com/coralogix/rum/v2/rum_source_map_service.d.ts +66 -0
  32. package/dist/src/app/proto-models/com/coralogix/rum/v2/rum_source_map_service.js +145 -0
  33. package/dist/src/app/proto-models/com/coralogix/rum/v2/source_code_file_mapping.d.ts +54 -0
  34. package/dist/src/app/proto-models/com/coralogix/rum/v2/source_code_file_mapping.js +264 -0
  35. package/dist/src/app/proto-models/google/protobuf/descriptor.d.ts +1140 -0
  36. package/dist/src/app/proto-models/google/protobuf/descriptor.js +3612 -0
  37. package/generate-protos.sh +14 -0
  38. package/meta.yaml +4 -0
  39. package/model/cli.model.ts +9 -0
  40. package/package.json +46 -0
  41. package/prepublish.sh +19 -0
  42. package/protofetch.lock +18 -0
  43. package/protofetch.toml +7 -0
  44. package/protos/com/coralogix/rum/v2/audit_log.proto +13 -0
  45. package/protos/com/coralogix/rum/v2/chunk.proto +18 -0
  46. package/protos/com/coralogix/rum/v2/file.proto +8 -0
  47. package/protos/com/coralogix/rum/v2/rum_service.proto +20 -0
  48. package/protos/com/coralogix/rum/v2/rum_source_map_service.proto +16 -0
  49. package/protos/com/coralogix/rum/v2/source_code_file_mapping.proto +15 -0
  50. package/protoset.bin +0 -0
  51. package/src/app/proto-models/com/coralogix/rum/v2/audit_log.ts +76 -0
  52. package/src/app/proto-models/com/coralogix/rum/v2/chunk.ts +298 -0
  53. package/src/app/proto-models/com/coralogix/rum/v2/file.ts +164 -0
  54. package/src/app/proto-models/com/coralogix/rum/v2/rum_service.ts +223 -0
  55. package/src/app/proto-models/com/coralogix/rum/v2/rum_source_map_service.ts +174 -0
  56. package/src/app/proto-models/com/coralogix/rum/v2/source_code_file_mapping.ts +316 -0
  57. package/src/app/proto-models/google/protobuf/descriptor.ts +4715 -0
  58. package/tsconfig.build.json +6 -0
  59. package/tsconfig.json +25 -0
package/.eslintignore ADDED
@@ -0,0 +1 @@
1
+ dist
package/.eslintrc.js ADDED
@@ -0,0 +1,31 @@
1
+ module.exports = {
2
+ "root": true,
3
+ "parser": "@typescript-eslint/parser",
4
+ "parserOptions": {
5
+ "project": `./tsconfig.json`
6
+ },
7
+ "plugins": [
8
+ "@typescript-eslint"
9
+ ],
10
+ "extends": [
11
+ "eslint:recommended",
12
+ "plugin:@typescript-eslint/eslint-recommended"
13
+ ],
14
+ "rules": {
15
+ "@typescript-eslint/naming-convention": "error",
16
+ "@typescript-eslint/explicit-module-boundary-types": "error",
17
+ "@typescript-eslint/no-require-imports": "error",
18
+ "@typescript-eslint/prefer-nullish-coalescing": "error",
19
+ "@typescript-eslint/prefer-optional-chain": "error",
20
+ "@typescript-eslint/prefer-string-starts-ends-with": "error",
21
+ "@typescript-eslint/promise-function-async": "error",
22
+ "@typescript-eslint/switch-exhaustiveness-check": "error",
23
+ "@typescript-eslint/type-annotation-spacing": "error",
24
+ "semi": [2, "always"],
25
+ "key-spacing": "error",
26
+ "comma-spacing":["error", {
27
+ "before": false,
28
+ "after": true,
29
+ }]
30
+ }
31
+ };
@@ -0,0 +1,41 @@
1
+ # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
2
+ # For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
3
+
4
+ name: Node.js Package
5
+
6
+ on:
7
+ release:
8
+ types: [created]
9
+
10
+ jobs:
11
+ build:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v3
15
+ - uses: actions/setup-node@v3
16
+ with:
17
+ node-version: 18
18
+ - uses: webfactory/ssh-agent@v0.8.0
19
+ with:
20
+ ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
21
+ - run: npm ci
22
+ - run: npm run proto
23
+ - run: npm run build
24
+ publish-npm:
25
+ needs: build
26
+ runs-on: ubuntu-latest
27
+ steps:
28
+ - uses: actions/checkout@v3
29
+ - uses: actions/setup-node@v3
30
+ with:
31
+ node-version: 18
32
+ registry-url: https://registry.npmjs.org/
33
+ - uses: webfactory/ssh-agent@v0.8.0
34
+ with:
35
+ ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
36
+ - run: npm ci
37
+ - run: npm run proto
38
+ - run: npm run build
39
+ - run: npm publish --access public
40
+ env:
41
+ NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
package/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # Coralogix RUM CLI
2
+
3
+ The Coralogix RUM CLI is a command-line interface tool that simplifies the process of uploading source maps for your applications to the Coralogix RUM service. This CLI tool provides an easy and efficient way to authenticate with the Coralogix API, specify the application and release information, and traverse a folder to upload the relevant source map files.
4
+
5
+ ## Installation
6
+
7
+ To install the Coralogix RUM CLI, follow these steps:
8
+
9
+ 1. Open a terminal or command prompt.
10
+ 2. Run the following command to install the CLI globally: `npm install -g coralogix-rum-cli`
11
+ 3. Once the installation is complete, you can use the CLI by running the `coralogix-rum-cli` command in your terminal.
12
+
13
+ ## Usage
14
+
15
+ The Coralogix RUM CLI supports the following options:
16
+
17
+ - `-k, --private-key <privateKey>`: Private key to authenticate with the Coralogix API.
18
+ - `-a, --application <application>`: Name of the application.
19
+ - `-r, --release-id <releaseId>`: ID of the release.
20
+ - `-f, --folder-path <folderPath>`: Path to the folder containing the source maps.
21
+ - `-e, --env <env>`: Your environment.
22
+ - `-h, --help`: Display help.
23
+
24
+ To use the CLI, execute the following command:
25
+
26
+
27
+ If any of the required arguments are missing, the CLI will display an error message and exit.
28
+
29
+ ## Examples
30
+
31
+ Here are some examples of how to use the Coralogix RUM CLI:
32
+
33
+ 1. Upload source maps:
34
+
35
+ - `coralogix-rum-cli -k <privateKey> -a <application> -r <releaseId> -f <folderPath> -e <env>`
36
+
37
+ 2. Display help:
38
+
39
+ - `coralogix-rum-cli -- --help`
40
+
41
+
42
+ Please ensure you provide valid values for the options when using the CLI.
43
+
44
+ ## Available Environments
45
+
46
+ The Coralogix RUM CLI supports the following environments:
47
+
48
+ - AP1
49
+ - AP2
50
+ - STAGING
51
+ - PRODUCTION
52
+ - EU2
53
+ - US1
54
+
55
+ Please use the appropriate environment value when specifying the `-e, --env` option.
56
+
57
+ ## License
58
+
59
+ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
package/api/rum-api.ts ADDED
@@ -0,0 +1,73 @@
1
+ import {Client, createChannel, createClient, Metadata} from 'nice-grpc';
2
+ import {envToDomain} from "../model/cli.model";
3
+ import * as pako from 'pako';
4
+ import config from "../config/config";
5
+ import {RED_COLOR} from "../cli/rum-cli";
6
+ import {FileMetadata} from "../src/app/proto-models/com/coralogix/rum/v2/file";
7
+ import {
8
+ RumSourceMapServiceDefinition,
9
+ UploadSourceMapsRequest
10
+ } from "../src/app/proto-models/com/coralogix/rum/v2/rum_source_map_service";
11
+
12
+
13
+ export const uploadSourceMaps = async (request: UploadSourceMapsRequest, env: string, privateKey: string): Promise<void> => {
14
+
15
+ const {maxMessageSize, keepaliveTimeMs, keepaliveTimeoutMs} = config.rumApi;
16
+
17
+ try {
18
+
19
+ const channel = createChannel(envToDomain[env], undefined, {
20
+ "grpc.max_receive_message_length": maxMessageSize,
21
+ "grpc.max_send_message_length": maxMessageSize,
22
+ 'grpc.keepalive_time_ms': keepaliveTimeMs,
23
+ 'grpc.keepalive_timeout_ms': keepaliveTimeoutMs,
24
+ });
25
+
26
+ const client: Client<typeof RumSourceMapServiceDefinition> = createClient(RumSourceMapServiceDefinition, channel);
27
+
28
+ const {files, releaseId, application} = request;
29
+
30
+ const compressedFiles: FileMetadata[] = await Promise.all(
31
+ files.map(async (file: FileMetadata) => {
32
+ const compressedChunks = compressFileContentChunks(file.content);
33
+
34
+ const size = compressedChunks.length;
35
+
36
+ return {chunkName: file.chunkName, size, content: compressedChunks};
37
+ })
38
+ );
39
+
40
+ const metadata = new Metadata();
41
+
42
+ metadata.set('Authorization', `Bearer ${privateKey}`);
43
+
44
+ await client.uploadSourceMaps({files: compressedFiles, releaseId, application}, {metadata});
45
+
46
+ } catch (error) {
47
+ throw error;
48
+ }
49
+ };
50
+
51
+
52
+ const compressFileContentChunks = (fileContent: Uint8Array): Uint8Array => {
53
+ const {chunkSize} = config.rumApi; // 512 KB chunk size
54
+ const deflate = new pako.Deflate();
55
+ const totalChunks = Math.ceil(fileContent.length / chunkSize);
56
+
57
+ for (let i = 0; i < totalChunks; i++) {
58
+ const start = i * chunkSize;
59
+ const end = start + chunkSize;
60
+ const chunk = fileContent.subarray(start, end);
61
+
62
+ const isLastChunk = i === totalChunks - 1;
63
+
64
+ deflate.push(chunk, isLastChunk);
65
+ }
66
+
67
+ const {err, msg, result} = deflate;
68
+
69
+ if (err) console.error(RED_COLOR, msg);
70
+
71
+ return result;
72
+ }
73
+
package/cli/rum-cli.ts ADDED
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env node
2
+ import {Command} from 'commander';
3
+ import {uploadSourceMaps} from "../api/rum-api";
4
+ import {traverseFolder} from "./utils/traverse-folder.util";
5
+ import {envToDomain} from "../model/cli.model";
6
+ import {UploadSourceMapsRequest} from "../src/app/proto-models/com/coralogix/rum/v2/rum_source_map_service";
7
+
8
+ export const GREEN_COLOR = '\x1b[32m%s\x1b[0m';
9
+ export const RED_COLOR = '\x1b[31m%s\x1b[0m';
10
+
11
+ const validateEnvironment = (env: string): string => {
12
+ const validEnvironments = Object.keys(envToDomain).join(', ');
13
+
14
+ if (!(env in envToDomain)) {
15
+ const errorMessage = `❌ Invalid environment: ${env}. Possible values are: ${validEnvironments}`;
16
+ console.error(RED_COLOR, errorMessage);
17
+ process.exit(1);
18
+ }
19
+
20
+ return env;
21
+ }
22
+
23
+ const program = new Command();
24
+
25
+ program
26
+ .option('-k, --private-key <privateKey>', 'Private key to authenticate with the API')
27
+ .option('-a, --application <application>', 'Name of the application')
28
+ .option('-r, --release-id <releaseId>', 'ID of the release')
29
+ .option('-f, --folder-path <folderPath>', 'Path to the folder containing the source maps')
30
+ .option('-e, --env <env>', 'Your environment', validateEnvironment)
31
+ .option('-h, --help', 'Display help')
32
+
33
+ program.parse(process.argv);
34
+
35
+ const {privateKey, application, releaseId, folderPath, env} = program.opts();
36
+
37
+ if (process.argv.includes('--help')) {
38
+ program.outputHelp();
39
+ process.exit(0);
40
+ }
41
+
42
+ (async () => {
43
+ try {
44
+ const missingArgs = [];
45
+
46
+ if (!privateKey) missingArgs.push('private-key');
47
+
48
+ if (!application) missingArgs.push('application');
49
+
50
+ if (!releaseId) missingArgs.push('release-id');
51
+
52
+ if (!folderPath) missingArgs.push('folder-path');
53
+
54
+ if (!env) missingArgs.push('env');
55
+
56
+ if (missingArgs.length > 0) {
57
+ const missingArgsList = missingArgs.map(arg => `- ${arg}`).join('\n');
58
+ const errorMessage = `❌ Missing required arguments:\n${missingArgsList}\nPlease provide the necessary options`;
59
+ console.error(RED_COLOR, errorMessage);
60
+ process.exit(1);
61
+ }
62
+
63
+ const request = UploadSourceMapsRequest.create();
64
+
65
+ request.application = application;
66
+ request.releaseId = releaseId;
67
+
68
+ await traverseFolder(folderPath, request);
69
+
70
+ await uploadSourceMaps(request, env, privateKey);
71
+
72
+ console.log(GREEN_COLOR, '✅ Source maps uploaded successfully!');
73
+ console.log(GREEN_COLOR, `✅ Total chunk files processed: ${request.files.length}`);
74
+ console.log(GREEN_COLOR, '✅ Processing complete.');
75
+ } catch (error) {
76
+ console.error(RED_COLOR, '❌ An error occurred:');
77
+ console.error(RED_COLOR, error);
78
+ }
79
+ })();
@@ -0,0 +1,33 @@
1
+ import {Dirent, promises as fsPromises} from "fs";
2
+ import path from "path";
3
+ import {FileMetadata} from "../../src/app/proto-models/com/coralogix/rum/v2/file";
4
+ import {UploadSourceMapsRequest} from "../../src/app/proto-models/com/coralogix/rum/v2/rum_source_map_service";
5
+
6
+ const {readdir, stat, readFile} = fsPromises;
7
+
8
+ export const traverseFolder = async (folderPath: string, request: UploadSourceMapsRequest): Promise<void> => {
9
+ const stack: string[] = [folderPath];
10
+
11
+ while (stack.length) {
12
+ const currentPath = stack.pop();
13
+ const entries: Dirent[] = await readdir(currentPath!, {withFileTypes: true});
14
+
15
+ await Promise.all(entries.map(async (file: Dirent) => {
16
+ const {name} = file;
17
+ const entryPath = path.join(currentPath as string, name);
18
+ const isDotMapFile = file.isFile() && name.endsWith('.js.map');
19
+
20
+ if (file.isDirectory()) stack.push(entryPath);
21
+
22
+ else if (isDotMapFile) request.files.push(await getFileMetadata(entryPath));
23
+ }));
24
+ }
25
+ }
26
+
27
+ const getFileMetadata = async (filePath: string): Promise<FileMetadata> => {
28
+ const {size} = await stat(filePath);
29
+ const {name} = path.parse(filePath);
30
+ const content = await readFile(filePath);
31
+
32
+ return {chunkName: name, size, content};
33
+ }
@@ -0,0 +1,31 @@
1
+ export interface LoggerConfig {
2
+ maxLogSize: number;
3
+ logLevel: string;
4
+ }
5
+
6
+ export interface rumApiConfig {
7
+ maxMessageSize: number,
8
+ keepaliveTimeMs: number
9
+ keepaliveTimeoutMs: number
10
+ chunkSize: number,
11
+ }
12
+
13
+ export interface Config {
14
+ logger: LoggerConfig;
15
+ rumApi: rumApiConfig;
16
+ }
17
+
18
+ const config: Config = {
19
+ logger: {
20
+ maxLogSize: 10000,
21
+ logLevel: 'debug',
22
+ },
23
+ rumApi: {
24
+ maxMessageSize: 400000 * 1024,
25
+ keepaliveTimeMs: 120000,
26
+ keepaliveTimeoutMs: 120000,
27
+ chunkSize: 512 * 1024 // 512 KB chunk size
28
+ }
29
+ };
30
+
31
+ export default config;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ exports.__esModule = true;
6
+ var config_1 = __importDefault(require("./config"));
7
+ exports["default"] = config_1["default"];
@@ -0,0 +1,3 @@
1
+ import config from './config';
2
+
3
+ export default config;
@@ -0,0 +1,2 @@
1
+ import { UploadSourceMapsRequest } from "../src/app/proto-models/com/coralogix/rum/v2/rum_source_map_service";
2
+ export declare const uploadSourceMaps: (request: UploadSourceMapsRequest, env: string, privateKey: string) => Promise<void>;
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ var __importDefault = (this && this.__importDefault) || function (mod) {
35
+ return (mod && mod.__esModule) ? mod : { "default": mod };
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.uploadSourceMaps = void 0;
39
+ const nice_grpc_1 = require("nice-grpc");
40
+ const cli_model_1 = require("../model/cli.model");
41
+ const pako = __importStar(require("pako"));
42
+ const config_1 = __importDefault(require("../config/config"));
43
+ const rum_cli_1 = require("../cli/rum-cli");
44
+ const rum_source_map_service_1 = require("../src/app/proto-models/com/coralogix/rum/v2/rum_source_map_service");
45
+ const uploadSourceMaps = (request, env, privateKey) => __awaiter(void 0, void 0, void 0, function* () {
46
+ const { maxMessageSize, keepaliveTimeMs, keepaliveTimeoutMs } = config_1.default.rumApi;
47
+ try {
48
+ const channel = (0, nice_grpc_1.createChannel)(cli_model_1.envToDomain[env], undefined, {
49
+ "grpc.max_receive_message_length": maxMessageSize,
50
+ "grpc.max_send_message_length": maxMessageSize,
51
+ 'grpc.keepalive_time_ms': keepaliveTimeMs,
52
+ 'grpc.keepalive_timeout_ms': keepaliveTimeoutMs,
53
+ });
54
+ const client = (0, nice_grpc_1.createClient)(rum_source_map_service_1.RumSourceMapServiceDefinition, channel);
55
+ const { files, releaseId, application } = request;
56
+ const compressedFiles = yield Promise.all(files.map((file) => __awaiter(void 0, void 0, void 0, function* () {
57
+ const compressedChunks = compressFileContentChunks(file.content);
58
+ const size = compressedChunks.length;
59
+ return { chunkName: file.chunkName, size, content: compressedChunks };
60
+ })));
61
+ const metadata = new nice_grpc_1.Metadata();
62
+ metadata.set('Authorization', `Bearer ${privateKey}`);
63
+ yield client.uploadSourceMaps({ files: compressedFiles, releaseId, application }, { metadata });
64
+ }
65
+ catch (error) {
66
+ throw error;
67
+ }
68
+ });
69
+ exports.uploadSourceMaps = uploadSourceMaps;
70
+ const compressFileContentChunks = (fileContent) => {
71
+ const { chunkSize } = config_1.default.rumApi; // 512 KB chunk size
72
+ const deflate = new pako.Deflate();
73
+ const totalChunks = Math.ceil(fileContent.length / chunkSize);
74
+ for (let i = 0; i < totalChunks; i++) {
75
+ const start = i * chunkSize;
76
+ const end = start + chunkSize;
77
+ const chunk = fileContent.subarray(start, end);
78
+ const isLastChunk = i === totalChunks - 1;
79
+ deflate.push(chunk, isLastChunk);
80
+ }
81
+ const { err, msg, result } = deflate;
82
+ if (err)
83
+ console.error(rum_cli_1.RED_COLOR, msg);
84
+ return result;
85
+ };
86
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVtLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL2FwaS9ydW0tYXBpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEseUNBQXdFO0FBQ3hFLGtEQUErQztBQUMvQywyQ0FBNkI7QUFDN0IsOERBQXNDO0FBQ3RDLDRDQUF5QztBQUV6QyxnSEFHNkU7QUFHdEUsTUFBTSxnQkFBZ0IsR0FBRyxDQUFPLE9BQWdDLEVBQUUsR0FBVyxFQUFFLFVBQWtCLEVBQWlCLEVBQUU7SUFFdkgsTUFBTSxFQUFDLGNBQWMsRUFBRSxlQUFlLEVBQUUsa0JBQWtCLEVBQUMsR0FBRyxnQkFBTSxDQUFDLE1BQU0sQ0FBQztJQUU1RSxJQUFJO1FBRUEsTUFBTSxPQUFPLEdBQUcsSUFBQSx5QkFBYSxFQUFDLHVCQUFXLENBQUMsR0FBRyxDQUFDLEVBQUUsU0FBUyxFQUFFO1lBQ3ZELGlDQUFpQyxFQUFFLGNBQWM7WUFDakQsOEJBQThCLEVBQUUsY0FBYztZQUM5Qyx3QkFBd0IsRUFBRSxlQUFlO1lBQ3pDLDJCQUEyQixFQUFFLGtCQUFrQjtTQUNsRCxDQUFDLENBQUM7UUFFSCxNQUFNLE1BQU0sR0FBaUQsSUFBQSx3QkFBWSxFQUFDLHNEQUE2QixFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBRWxILE1BQU0sRUFBQyxLQUFLLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBQyxHQUFHLE9BQU8sQ0FBQztRQUVoRCxNQUFNLGVBQWUsR0FBbUIsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUNyRCxLQUFLLENBQUMsR0FBRyxDQUFDLENBQU8sSUFBa0IsRUFBRSxFQUFFO1lBQ25DLE1BQU0sZ0JBQWdCLEdBQUcseUJBQXlCLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBRWpFLE1BQU0sSUFBSSxHQUFHLGdCQUFnQixDQUFDLE1BQU0sQ0FBQztZQUVyQyxPQUFPLEVBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxTQUFTLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBQyxDQUFDO1FBQ3hFLENBQUMsQ0FBQSxDQUFDLENBQ0wsQ0FBQztRQUVGLE1BQU0sUUFBUSxHQUFHLElBQUksb0JBQVEsRUFBRSxDQUFDO1FBRWhDLFFBQVEsQ0FBQyxHQUFHLENBQUMsZUFBZSxFQUFFLFVBQVUsVUFBVSxFQUFFLENBQUMsQ0FBQztRQUV0RCxNQUFNLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFDLEtBQUssRUFBRSxlQUFlLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBQyxFQUFFLEVBQUMsUUFBUSxFQUFDLENBQUMsQ0FBQztLQUUvRjtJQUFDLE9BQU8sS0FBSyxFQUFFO1FBQ1osTUFBTSxLQUFLLENBQUM7S0FDZjtBQUNMLENBQUMsQ0FBQSxDQUFDO0FBcENXLFFBQUEsZ0JBQWdCLG9CQW9DM0I7QUFHRixNQUFNLHlCQUF5QixHQUFHLENBQUMsV0FBdUIsRUFBYyxFQUFFO0lBQ3RFLE1BQU0sRUFBQyxTQUFTLEVBQUMsR0FBRyxnQkFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLG9CQUFvQjtJQUN2RCxNQUFNLE9BQU8sR0FBRyxJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUNuQyxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLEdBQUcsU0FBUyxDQUFDLENBQUM7SUFFOUQsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFdBQVcsRUFBRSxDQUFDLEVBQUUsRUFBRTtRQUNsQyxNQUFNLEtBQUssR0FBRyxDQUFDLEdBQUcsU0FBUyxDQUFDO1FBQzVCLE1BQU0sR0FBRyxHQUFHLEtBQUssR0FBRyxTQUFTLENBQUM7UUFDOUIsTUFBTSxLQUFLLEdBQUcsV0FBVyxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFFL0MsTUFBTSxXQUFXLEdBQUcsQ0FBQyxLQUFLLFdBQVcsR0FBRyxDQUFDLENBQUM7UUFFMUMsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsV0FBVyxDQUFDLENBQUM7S0FDcEM7SUFFRCxNQUFNLEVBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxNQUFNLEVBQUMsR0FBRyxPQUFPLENBQUM7SUFFbkMsSUFBSSxHQUFHO1FBQUUsT0FBTyxDQUFDLEtBQUssQ0FBQyxtQkFBUyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBRXZDLE9BQU8sTUFBTSxDQUFDO0FBQ2xCLENBQUMsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7Q2xpZW50LCBjcmVhdGVDaGFubmVsLCBjcmVhdGVDbGllbnQsIE1ldGFkYXRhfSBmcm9tICduaWNlLWdycGMnO1xuaW1wb3J0IHtlbnZUb0RvbWFpbn0gZnJvbSBcIi4uL21vZGVsL2NsaS5tb2RlbFwiO1xuaW1wb3J0ICogYXMgcGFrbyBmcm9tICdwYWtvJztcbmltcG9ydCBjb25maWcgZnJvbSBcIi4uL2NvbmZpZy9jb25maWdcIjtcbmltcG9ydCB7UkVEX0NPTE9SfSBmcm9tIFwiLi4vY2xpL3J1bS1jbGlcIjtcbmltcG9ydCB7RmlsZU1ldGFkYXRhfSBmcm9tIFwiLi4vc3JjL2FwcC9wcm90by1tb2RlbHMvY29tL2NvcmFsb2dpeC9ydW0vdjIvZmlsZVwiO1xuaW1wb3J0IHtcbiAgICBSdW1Tb3VyY2VNYXBTZXJ2aWNlRGVmaW5pdGlvbixcbiAgICBVcGxvYWRTb3VyY2VNYXBzUmVxdWVzdFxufSBmcm9tIFwiLi4vc3JjL2FwcC9wcm90by1tb2RlbHMvY29tL2NvcmFsb2dpeC9ydW0vdjIvcnVtX3NvdXJjZV9tYXBfc2VydmljZVwiO1xuXG5cbmV4cG9ydCBjb25zdCB1cGxvYWRTb3VyY2VNYXBzID0gYXN5bmMgKHJlcXVlc3Q6IFVwbG9hZFNvdXJjZU1hcHNSZXF1ZXN0LCBlbnY6IHN0cmluZywgcHJpdmF0ZUtleTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiA9PiB7XG5cbiAgICBjb25zdCB7bWF4TWVzc2FnZVNpemUsIGtlZXBhbGl2ZVRpbWVNcywga2VlcGFsaXZlVGltZW91dE1zfSA9IGNvbmZpZy5ydW1BcGk7XG5cbiAgICB0cnkge1xuXG4gICAgICAgIGNvbnN0IGNoYW5uZWwgPSBjcmVhdGVDaGFubmVsKGVudlRvRG9tYWluW2Vudl0sIHVuZGVmaW5lZCwge1xuICAgICAgICAgICAgXCJncnBjLm1heF9yZWNlaXZlX21lc3NhZ2VfbGVuZ3RoXCI6IG1heE1lc3NhZ2VTaXplLFxuICAgICAgICAgICAgXCJncnBjLm1heF9zZW5kX21lc3NhZ2VfbGVuZ3RoXCI6IG1heE1lc3NhZ2VTaXplLFxuICAgICAgICAgICAgJ2dycGMua2VlcGFsaXZlX3RpbWVfbXMnOiBrZWVwYWxpdmVUaW1lTXMsXG4gICAgICAgICAgICAnZ3JwYy5rZWVwYWxpdmVfdGltZW91dF9tcyc6IGtlZXBhbGl2ZVRpbWVvdXRNcyxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgY29uc3QgY2xpZW50OiBDbGllbnQ8dHlwZW9mIFJ1bVNvdXJjZU1hcFNlcnZpY2VEZWZpbml0aW9uPiA9IGNyZWF0ZUNsaWVudChSdW1Tb3VyY2VNYXBTZXJ2aWNlRGVmaW5pdGlvbiwgY2hhbm5lbCk7XG5cbiAgICAgICAgY29uc3Qge2ZpbGVzLCByZWxlYXNlSWQsIGFwcGxpY2F0aW9ufSA9IHJlcXVlc3Q7XG5cbiAgICAgICAgY29uc3QgY29tcHJlc3NlZEZpbGVzOiBGaWxlTWV0YWRhdGFbXSA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICAgICAgZmlsZXMubWFwKGFzeW5jIChmaWxlOiBGaWxlTWV0YWRhdGEpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBjb21wcmVzc2VkQ2h1bmtzID0gY29tcHJlc3NGaWxlQ29udGVudENodW5rcyhmaWxlLmNvbnRlbnQpO1xuXG4gICAgICAgICAgICAgICAgY29uc3Qgc2l6ZSA9IGNvbXByZXNzZWRDaHVua3MubGVuZ3RoO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHtjaHVua05hbWU6IGZpbGUuY2h1bmtOYW1lLCBzaXplLCBjb250ZW50OiBjb21wcmVzc2VkQ2h1bmtzfTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICk7XG5cbiAgICAgICAgY29uc3QgbWV0YWRhdGEgPSBuZXcgTWV0YWRhdGEoKTtcblxuICAgICAgICBtZXRhZGF0YS5zZXQoJ0F1dGhvcml6YXRpb24nLCBgQmVhcmVyICR7cHJpdmF0ZUtleX1gKTtcblxuICAgICAgICBhd2FpdCBjbGllbnQudXBsb2FkU291cmNlTWFwcyh7ZmlsZXM6IGNvbXByZXNzZWRGaWxlcywgcmVsZWFzZUlkLCBhcHBsaWNhdGlvbn0sIHttZXRhZGF0YX0pO1xuXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxufTtcblxuXG5jb25zdCBjb21wcmVzc0ZpbGVDb250ZW50Q2h1bmtzID0gKGZpbGVDb250ZW50OiBVaW50OEFycmF5KTogVWludDhBcnJheSA9PiB7XG4gICAgY29uc3Qge2NodW5rU2l6ZX0gPSBjb25maWcucnVtQXBpOyAvLyA1MTIgS0IgY2h1bmsgc2l6ZVxuICAgIGNvbnN0IGRlZmxhdGUgPSBuZXcgcGFrby5EZWZsYXRlKCk7XG4gICAgY29uc3QgdG90YWxDaHVua3MgPSBNYXRoLmNlaWwoZmlsZUNvbnRlbnQubGVuZ3RoIC8gY2h1bmtTaXplKTtcblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdG90YWxDaHVua3M7IGkrKykge1xuICAgICAgICBjb25zdCBzdGFydCA9IGkgKiBjaHVua1NpemU7XG4gICAgICAgIGNvbnN0IGVuZCA9IHN0YXJ0ICsgY2h1bmtTaXplO1xuICAgICAgICBjb25zdCBjaHVuayA9IGZpbGVDb250ZW50LnN1YmFycmF5KHN0YXJ0LCBlbmQpO1xuXG4gICAgICAgIGNvbnN0IGlzTGFzdENodW5rID0gaSA9PT0gdG90YWxDaHVua3MgLSAxO1xuXG4gICAgICAgIGRlZmxhdGUucHVzaChjaHVuaywgaXNMYXN0Q2h1bmspO1xuICAgIH1cblxuICAgIGNvbnN0IHtlcnIsIG1zZywgcmVzdWx0fSA9IGRlZmxhdGU7XG5cbiAgICBpZiAoZXJyKSBjb25zb2xlLmVycm9yKFJFRF9DT0xPUiwgbXNnKTtcblxuICAgIHJldHVybiByZXN1bHQ7XG59XG5cbiJdfQ==
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export declare const GREEN_COLOR = "\u001B[32m%s\u001B[0m";
3
+ export declare const RED_COLOR = "\u001B[31m%s\u001B[0m";
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
4
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5
+ return new (P || (P = Promise))(function (resolve, reject) {
6
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
7
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
8
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
9
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
10
+ });
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.RED_COLOR = exports.GREEN_COLOR = void 0;
14
+ const commander_1 = require("commander");
15
+ const rum_api_1 = require("../api/rum-api");
16
+ const traverse_folder_util_1 = require("./utils/traverse-folder.util");
17
+ const cli_model_1 = require("../model/cli.model");
18
+ const rum_source_map_service_1 = require("../src/app/proto-models/com/coralogix/rum/v2/rum_source_map_service");
19
+ exports.GREEN_COLOR = '\x1b[32m%s\x1b[0m';
20
+ exports.RED_COLOR = '\x1b[31m%s\x1b[0m';
21
+ const validateEnvironment = (env) => {
22
+ const validEnvironments = Object.keys(cli_model_1.envToDomain).join(', ');
23
+ if (!(env in cli_model_1.envToDomain)) {
24
+ const errorMessage = `❌ Invalid environment: ${env}. Possible values are: ${validEnvironments}`;
25
+ console.error(exports.RED_COLOR, errorMessage);
26
+ process.exit(1);
27
+ }
28
+ return env;
29
+ };
30
+ const program = new commander_1.Command();
31
+ program
32
+ .option('-k, --private-key <privateKey>', 'Private key to authenticate with the API')
33
+ .option('-a, --application <application>', 'Name of the application')
34
+ .option('-r, --release-id <releaseId>', 'ID of the release')
35
+ .option('-f, --folder-path <folderPath>', 'Path to the folder containing the source maps')
36
+ .option('-e, --env <env>', 'Your environment', validateEnvironment)
37
+ .option('-h, --help', 'Display help');
38
+ program.parse(process.argv);
39
+ const { privateKey, application, releaseId, folderPath, env } = program.opts();
40
+ if (process.argv.includes('--help')) {
41
+ program.outputHelp();
42
+ process.exit(0);
43
+ }
44
+ (() => __awaiter(void 0, void 0, void 0, function* () {
45
+ try {
46
+ const missingArgs = [];
47
+ if (!privateKey)
48
+ missingArgs.push('private-key');
49
+ if (!application)
50
+ missingArgs.push('application');
51
+ if (!releaseId)
52
+ missingArgs.push('release-id');
53
+ if (!folderPath)
54
+ missingArgs.push('folder-path');
55
+ if (!env)
56
+ missingArgs.push('env');
57
+ if (missingArgs.length > 0) {
58
+ const missingArgsList = missingArgs.map(arg => `- ${arg}`).join('\n');
59
+ const errorMessage = `❌ Missing required arguments:\n${missingArgsList}\nPlease provide the necessary options`;
60
+ console.error(exports.RED_COLOR, errorMessage);
61
+ process.exit(1);
62
+ }
63
+ const request = rum_source_map_service_1.UploadSourceMapsRequest.create();
64
+ request.application = application;
65
+ request.releaseId = releaseId;
66
+ yield (0, traverse_folder_util_1.traverseFolder)(folderPath, request);
67
+ yield (0, rum_api_1.uploadSourceMaps)(request, env, privateKey);
68
+ console.log(exports.GREEN_COLOR, '✅ Source maps uploaded successfully!');
69
+ console.log(exports.GREEN_COLOR, `✅ Total chunk files processed: ${request.files.length}`);
70
+ console.log(exports.GREEN_COLOR, '✅ Processing complete.');
71
+ }
72
+ catch (error) {
73
+ console.error(exports.RED_COLOR, '❌ An error occurred:');
74
+ console.error(exports.RED_COLOR, error);
75
+ }
76
+ }))();
77
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVtLWNsaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL2NsaS9ydW0tY2xpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7QUFDQSx5Q0FBa0M7QUFDbEMsNENBQWdEO0FBQ2hELHVFQUE0RDtBQUM1RCxrREFBK0M7QUFDL0MsZ0hBQTRHO0FBRS9GLFFBQUEsV0FBVyxHQUFHLG1CQUFtQixDQUFDO0FBQ2xDLFFBQUEsU0FBUyxHQUFHLG1CQUFtQixDQUFDO0FBRTdDLE1BQU0sbUJBQW1CLEdBQUcsQ0FBQyxHQUFXLEVBQVUsRUFBRTtJQUNoRCxNQUFNLGlCQUFpQixHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsdUJBQVcsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUU5RCxJQUFJLENBQUMsQ0FBQyxHQUFHLElBQUksdUJBQVcsQ0FBQyxFQUFFO1FBQ3ZCLE1BQU0sWUFBWSxHQUFHLDBCQUEwQixHQUFHLDBCQUEwQixpQkFBaUIsRUFBRSxDQUFDO1FBQ2hHLE9BQU8sQ0FBQyxLQUFLLENBQUMsaUJBQVMsRUFBRSxZQUFZLENBQUMsQ0FBQztRQUN2QyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0tBQ25CO0lBRUQsT0FBTyxHQUFHLENBQUM7QUFDZixDQUFDLENBQUE7QUFFRCxNQUFNLE9BQU8sR0FBRyxJQUFJLG1CQUFPLEVBQUUsQ0FBQztBQUU5QixPQUFPO0tBQ0YsTUFBTSxDQUFDLGdDQUFnQyxFQUFFLDBDQUEwQyxDQUFDO0tBQ3BGLE1BQU0sQ0FBQyxpQ0FBaUMsRUFBRSx5QkFBeUIsQ0FBQztLQUNwRSxNQUFNLENBQUMsOEJBQThCLEVBQUUsbUJBQW1CLENBQUM7S0FDM0QsTUFBTSxDQUFDLGdDQUFnQyxFQUFFLCtDQUErQyxDQUFDO0tBQ3pGLE1BQU0sQ0FBQyxpQkFBaUIsRUFBRSxrQkFBa0IsRUFBRSxtQkFBbUIsQ0FBQztLQUNsRSxNQUFNLENBQUMsWUFBWSxFQUFFLGNBQWMsQ0FBQyxDQUFBO0FBRXpDLE9BQU8sQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO0FBRTVCLE1BQU0sRUFBQyxVQUFVLEVBQUUsV0FBVyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsR0FBRyxFQUFDLEdBQUcsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDO0FBRTdFLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLEVBQUU7SUFDakMsT0FBTyxDQUFDLFVBQVUsRUFBRSxDQUFDO0lBQ3JCLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7Q0FDbkI7QUFFRCxDQUFDLEdBQVMsRUFBRTtJQUNSLElBQUk7UUFDQSxNQUFNLFdBQVcsR0FBRyxFQUFFLENBQUM7UUFFdkIsSUFBSSxDQUFDLFVBQVU7WUFBRSxXQUFXLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBRWpELElBQUksQ0FBQyxXQUFXO1lBQUUsV0FBVyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUVsRCxJQUFJLENBQUMsU0FBUztZQUFFLFdBQVcsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7UUFFL0MsSUFBSSxDQUFDLFVBQVU7WUFBRSxXQUFXLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBRWpELElBQUksQ0FBQyxHQUFHO1lBQUUsV0FBVyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUVsQyxJQUFJLFdBQVcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1lBQ3hCLE1BQU0sZUFBZSxHQUFHLFdBQVcsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3RFLE1BQU0sWUFBWSxHQUFHLGtDQUFrQyxlQUFlLHdDQUF3QyxDQUFDO1lBQy9HLE9BQU8sQ0FBQyxLQUFLLENBQUMsaUJBQVMsRUFBRSxZQUFZLENBQUMsQ0FBQztZQUN2QyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1NBQ25CO1FBRUQsTUFBTSxPQUFPLEdBQUcsZ0RBQXVCLENBQUMsTUFBTSxFQUFFLENBQUM7UUFFakQsT0FBTyxDQUFDLFdBQVcsR0FBRyxXQUFXLENBQUM7UUFDbEMsT0FBTyxDQUFDLFNBQVMsR0FBRyxTQUFTLENBQUM7UUFFOUIsTUFBTSxJQUFBLHFDQUFjLEVBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBRTFDLE1BQU0sSUFBQSwwQkFBZ0IsRUFBQyxPQUFPLEVBQUUsR0FBRyxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBRWpELE9BQU8sQ0FBQyxHQUFHLENBQUMsbUJBQVcsRUFBRSxzQ0FBc0MsQ0FBQyxDQUFDO1FBQ2pFLE9BQU8sQ0FBQyxHQUFHLENBQUMsbUJBQVcsRUFBRSxrQ0FBa0MsT0FBTyxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO1FBQ25GLE9BQU8sQ0FBQyxHQUFHLENBQUMsbUJBQVcsRUFBRSx3QkFBd0IsQ0FBQyxDQUFDO0tBQ3REO0lBQUMsT0FBTyxLQUFLLEVBQUU7UUFDWixPQUFPLENBQUMsS0FBSyxDQUFDLGlCQUFTLEVBQUUsc0JBQXNCLENBQUMsQ0FBQztRQUNqRCxPQUFPLENBQUMsS0FBSyxDQUFDLGlCQUFTLEVBQUUsS0FBSyxDQUFDLENBQUM7S0FDbkM7QUFDTCxDQUFDLENBQUEsQ0FBQyxFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIjIS91c3IvYmluL2VudiBub2RlXG5pbXBvcnQge0NvbW1hbmR9IGZyb20gJ2NvbW1hbmRlcic7XG5pbXBvcnQge3VwbG9hZFNvdXJjZU1hcHN9IGZyb20gXCIuLi9hcGkvcnVtLWFwaVwiO1xuaW1wb3J0IHt0cmF2ZXJzZUZvbGRlcn0gZnJvbSBcIi4vdXRpbHMvdHJhdmVyc2UtZm9sZGVyLnV0aWxcIjtcbmltcG9ydCB7ZW52VG9Eb21haW59IGZyb20gXCIuLi9tb2RlbC9jbGkubW9kZWxcIjtcbmltcG9ydCB7VXBsb2FkU291cmNlTWFwc1JlcXVlc3R9IGZyb20gXCIuLi9zcmMvYXBwL3Byb3RvLW1vZGVscy9jb20vY29yYWxvZ2l4L3J1bS92Mi9ydW1fc291cmNlX21hcF9zZXJ2aWNlXCI7XG5cbmV4cG9ydCBjb25zdCBHUkVFTl9DT0xPUiA9ICdcXHgxYlszMm0lc1xceDFiWzBtJztcbmV4cG9ydCBjb25zdCBSRURfQ09MT1IgPSAnXFx4MWJbMzFtJXNcXHgxYlswbSc7XG5cbmNvbnN0IHZhbGlkYXRlRW52aXJvbm1lbnQgPSAoZW52OiBzdHJpbmcpOiBzdHJpbmcgPT4ge1xuICAgIGNvbnN0IHZhbGlkRW52aXJvbm1lbnRzID0gT2JqZWN0LmtleXMoZW52VG9Eb21haW4pLmpvaW4oJywgJyk7XG5cbiAgICBpZiAoIShlbnYgaW4gZW52VG9Eb21haW4pKSB7XG4gICAgICAgIGNvbnN0IGVycm9yTWVzc2FnZSA9IGDinYwgSW52YWxpZCBlbnZpcm9ubWVudDogJHtlbnZ9LiBQb3NzaWJsZSB2YWx1ZXMgYXJlOiAke3ZhbGlkRW52aXJvbm1lbnRzfWA7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoUkVEX0NPTE9SLCBlcnJvck1lc3NhZ2UpO1xuICAgICAgICBwcm9jZXNzLmV4aXQoMSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGVudjtcbn1cblxuY29uc3QgcHJvZ3JhbSA9IG5ldyBDb21tYW5kKCk7XG5cbnByb2dyYW1cbiAgICAub3B0aW9uKCctaywgLS1wcml2YXRlLWtleSA8cHJpdmF0ZUtleT4nLCAnUHJpdmF0ZSBrZXkgdG8gYXV0aGVudGljYXRlIHdpdGggdGhlIEFQSScpXG4gICAgLm9wdGlvbignLWEsIC0tYXBwbGljYXRpb24gPGFwcGxpY2F0aW9uPicsICdOYW1lIG9mIHRoZSBhcHBsaWNhdGlvbicpXG4gICAgLm9wdGlvbignLXIsIC0tcmVsZWFzZS1pZCA8cmVsZWFzZUlkPicsICdJRCBvZiB0aGUgcmVsZWFzZScpXG4gICAgLm9wdGlvbignLWYsIC0tZm9sZGVyLXBhdGggPGZvbGRlclBhdGg+JywgJ1BhdGggdG8gdGhlIGZvbGRlciBjb250YWluaW5nIHRoZSBzb3VyY2UgbWFwcycpXG4gICAgLm9wdGlvbignLWUsIC0tZW52IDxlbnY+JywgJ1lvdXIgZW52aXJvbm1lbnQnLCB2YWxpZGF0ZUVudmlyb25tZW50KVxuICAgIC5vcHRpb24oJy1oLCAtLWhlbHAnLCAnRGlzcGxheSBoZWxwJylcblxucHJvZ3JhbS5wYXJzZShwcm9jZXNzLmFyZ3YpO1xuXG5jb25zdCB7cHJpdmF0ZUtleSwgYXBwbGljYXRpb24sIHJlbGVhc2VJZCwgZm9sZGVyUGF0aCwgZW52fSA9IHByb2dyYW0ub3B0cygpO1xuXG5pZiAocHJvY2Vzcy5hcmd2LmluY2x1ZGVzKCctLWhlbHAnKSkge1xuICAgIHByb2dyYW0ub3V0cHV0SGVscCgpO1xuICAgIHByb2Nlc3MuZXhpdCgwKTtcbn1cblxuKGFzeW5jICgpID0+IHtcbiAgICB0cnkge1xuICAgICAgICBjb25zdCBtaXNzaW5nQXJncyA9IFtdO1xuXG4gICAgICAgIGlmICghcHJpdmF0ZUtleSkgbWlzc2luZ0FyZ3MucHVzaCgncHJpdmF0ZS1rZXknKTtcblxuICAgICAgICBpZiAoIWFwcGxpY2F0aW9uKSBtaXNzaW5nQXJncy5wdXNoKCdhcHBsaWNhdGlvbicpO1xuXG4gICAgICAgIGlmICghcmVsZWFzZUlkKSBtaXNzaW5nQXJncy5wdXNoKCdyZWxlYXNlLWlkJyk7XG5cbiAgICAgICAgaWYgKCFmb2xkZXJQYXRoKSBtaXNzaW5nQXJncy5wdXNoKCdmb2xkZXItcGF0aCcpO1xuXG4gICAgICAgIGlmICghZW52KSBtaXNzaW5nQXJncy5wdXNoKCdlbnYnKTtcblxuICAgICAgICBpZiAobWlzc2luZ0FyZ3MubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgY29uc3QgbWlzc2luZ0FyZ3NMaXN0ID0gbWlzc2luZ0FyZ3MubWFwKGFyZyA9PiBgLSAke2FyZ31gKS5qb2luKCdcXG4nKTtcbiAgICAgICAgICAgIGNvbnN0IGVycm9yTWVzc2FnZSA9IGDinYwgTWlzc2luZyByZXF1aXJlZCBhcmd1bWVudHM6XFxuJHttaXNzaW5nQXJnc0xpc3R9XFxuUGxlYXNlIHByb3ZpZGUgdGhlIG5lY2Vzc2FyeSBvcHRpb25zYDtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoUkVEX0NPTE9SLCBlcnJvck1lc3NhZ2UpO1xuICAgICAgICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcmVxdWVzdCA9IFVwbG9hZFNvdXJjZU1hcHNSZXF1ZXN0LmNyZWF0ZSgpO1xuXG4gICAgICAgIHJlcXVlc3QuYXBwbGljYXRpb24gPSBhcHBsaWNhdGlvbjtcbiAgICAgICAgcmVxdWVzdC5yZWxlYXNlSWQgPSByZWxlYXNlSWQ7XG5cbiAgICAgICAgYXdhaXQgdHJhdmVyc2VGb2xkZXIoZm9sZGVyUGF0aCwgcmVxdWVzdCk7XG5cbiAgICAgICAgYXdhaXQgdXBsb2FkU291cmNlTWFwcyhyZXF1ZXN0LCBlbnYsIHByaXZhdGVLZXkpO1xuXG4gICAgICAgIGNvbnNvbGUubG9nKEdSRUVOX0NPTE9SLCAn4pyFIFNvdXJjZSBtYXBzIHVwbG9hZGVkIHN1Y2Nlc3NmdWxseSEnKTtcbiAgICAgICAgY29uc29sZS5sb2coR1JFRU5fQ09MT1IsIGDinIUgVG90YWwgY2h1bmsgZmlsZXMgcHJvY2Vzc2VkOiAke3JlcXVlc3QuZmlsZXMubGVuZ3RofWApO1xuICAgICAgICBjb25zb2xlLmxvZyhHUkVFTl9DT0xPUiwgJ+KchSBQcm9jZXNzaW5nIGNvbXBsZXRlLicpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoUkVEX0NPTE9SLCAn4p2MIEFuIGVycm9yIG9jY3VycmVkOicpO1xuICAgICAgICBjb25zb2xlLmVycm9yKFJFRF9DT0xPUiwgZXJyb3IpO1xuICAgIH1cbn0pKCk7XG4iXX0=
@@ -0,0 +1,2 @@
1
+ import { UploadSourceMapsRequest } from "../../src/app/proto-models/com/coralogix/rum/v2/rum_source_map_service";
2
+ export declare const traverseFolder: (folderPath: string, request: UploadSourceMapsRequest) => Promise<void>;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.traverseFolder = void 0;
16
+ const fs_1 = require("fs");
17
+ const path_1 = __importDefault(require("path"));
18
+ const { readdir, stat, readFile } = fs_1.promises;
19
+ const traverseFolder = (folderPath, request) => __awaiter(void 0, void 0, void 0, function* () {
20
+ const stack = [folderPath];
21
+ while (stack.length) {
22
+ const currentPath = stack.pop();
23
+ const entries = yield readdir(currentPath, { withFileTypes: true });
24
+ yield Promise.all(entries.map((file) => __awaiter(void 0, void 0, void 0, function* () {
25
+ const { name } = file;
26
+ const entryPath = path_1.default.join(currentPath, name);
27
+ const isDotMapFile = file.isFile() && name.endsWith('.js.map');
28
+ if (file.isDirectory())
29
+ stack.push(entryPath);
30
+ else if (isDotMapFile)
31
+ request.files.push(yield getFileMetadata(entryPath));
32
+ })));
33
+ }
34
+ });
35
+ exports.traverseFolder = traverseFolder;
36
+ const getFileMetadata = (filePath) => __awaiter(void 0, void 0, void 0, function* () {
37
+ const { size } = yield stat(filePath);
38
+ const { name } = path_1.default.parse(filePath);
39
+ const content = yield readFile(filePath);
40
+ return { chunkName: name, size, content };
41
+ });
42
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhdmVyc2UtZm9sZGVyLnV0aWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9jbGkvdXRpbHMvdHJhdmVyc2UtZm9sZGVyLnV0aWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsMkJBQWtEO0FBQ2xELGdEQUF3QjtBQUl4QixNQUFNLEVBQUMsT0FBTyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUMsR0FBRyxhQUFVLENBQUM7QUFFdEMsTUFBTSxjQUFjLEdBQUcsQ0FBTyxVQUFrQixFQUFFLE9BQWdDLEVBQWlCLEVBQUU7SUFDeEcsTUFBTSxLQUFLLEdBQWEsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUVyQyxPQUFPLEtBQUssQ0FBQyxNQUFNLEVBQUU7UUFDakIsTUFBTSxXQUFXLEdBQUcsS0FBSyxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQ2hDLE1BQU0sT0FBTyxHQUFhLE1BQU0sT0FBTyxDQUFDLFdBQVksRUFBRSxFQUFDLGFBQWEsRUFBRSxJQUFJLEVBQUMsQ0FBQyxDQUFDO1FBRTdFLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQU8sSUFBWSxFQUFFLEVBQUU7WUFDakQsTUFBTSxFQUFDLElBQUksRUFBQyxHQUFHLElBQUksQ0FBQztZQUNwQixNQUFNLFNBQVMsR0FBRyxjQUFJLENBQUMsSUFBSSxDQUFDLFdBQXFCLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFDekQsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLENBQUM7WUFFL0QsSUFBSSxJQUFJLENBQUMsV0FBVyxFQUFFO2dCQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7aUJBRXpDLElBQUksWUFBWTtnQkFBRSxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLGVBQWUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO1FBQ2hGLENBQUMsQ0FBQSxDQUFDLENBQUMsQ0FBQztLQUNQO0FBQ0wsQ0FBQyxDQUFBLENBQUE7QUFqQlksUUFBQSxjQUFjLGtCQWlCMUI7QUFFRCxNQUFNLGVBQWUsR0FBRyxDQUFPLFFBQWdCLEVBQXlCLEVBQUU7SUFDdEUsTUFBTSxFQUFDLElBQUksRUFBQyxHQUFHLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ3BDLE1BQU0sRUFBQyxJQUFJLEVBQUMsR0FBRyxjQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ3BDLE1BQU0sT0FBTyxHQUFHLE1BQU0sUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBRXpDLE9BQU8sRUFBQyxTQUFTLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUMsQ0FBQztBQUM1QyxDQUFDLENBQUEsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7RGlyZW50LCBwcm9taXNlcyBhcyBmc1Byb21pc2VzfSBmcm9tIFwiZnNcIjtcbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCI7XG5pbXBvcnQge0ZpbGVNZXRhZGF0YX0gZnJvbSBcIi4uLy4uL3NyYy9hcHAvcHJvdG8tbW9kZWxzL2NvbS9jb3JhbG9naXgvcnVtL3YyL2ZpbGVcIjtcbmltcG9ydCB7VXBsb2FkU291cmNlTWFwc1JlcXVlc3R9IGZyb20gXCIuLi8uLi9zcmMvYXBwL3Byb3RvLW1vZGVscy9jb20vY29yYWxvZ2l4L3J1bS92Mi9ydW1fc291cmNlX21hcF9zZXJ2aWNlXCI7XG5cbmNvbnN0IHtyZWFkZGlyLCBzdGF0LCByZWFkRmlsZX0gPSBmc1Byb21pc2VzO1xuXG5leHBvcnQgY29uc3QgdHJhdmVyc2VGb2xkZXIgPSBhc3luYyAoZm9sZGVyUGF0aDogc3RyaW5nLCByZXF1ZXN0OiBVcGxvYWRTb3VyY2VNYXBzUmVxdWVzdCk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgIGNvbnN0IHN0YWNrOiBzdHJpbmdbXSA9IFtmb2xkZXJQYXRoXTtcblxuICAgIHdoaWxlIChzdGFjay5sZW5ndGgpIHtcbiAgICAgICAgY29uc3QgY3VycmVudFBhdGggPSBzdGFjay5wb3AoKTtcbiAgICAgICAgY29uc3QgZW50cmllczogRGlyZW50W10gPSBhd2FpdCByZWFkZGlyKGN1cnJlbnRQYXRoISwge3dpdGhGaWxlVHlwZXM6IHRydWV9KTtcblxuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChlbnRyaWVzLm1hcChhc3luYyAoZmlsZTogRGlyZW50KSA9PiB7XG4gICAgICAgICAgICBjb25zdCB7bmFtZX0gPSBmaWxlO1xuICAgICAgICAgICAgY29uc3QgZW50cnlQYXRoID0gcGF0aC5qb2luKGN1cnJlbnRQYXRoIGFzIHN0cmluZywgbmFtZSk7XG4gICAgICAgICAgICBjb25zdCBpc0RvdE1hcEZpbGUgPSBmaWxlLmlzRmlsZSgpICYmIG5hbWUuZW5kc1dpdGgoJy5qcy5tYXAnKTtcblxuICAgICAgICAgICAgaWYgKGZpbGUuaXNEaXJlY3RvcnkoKSkgc3RhY2sucHVzaChlbnRyeVBhdGgpO1xuXG4gICAgICAgICAgICBlbHNlIGlmIChpc0RvdE1hcEZpbGUpIHJlcXVlc3QuZmlsZXMucHVzaChhd2FpdCBnZXRGaWxlTWV0YWRhdGEoZW50cnlQYXRoKSk7XG4gICAgICAgIH0pKTtcbiAgICB9XG59XG5cbmNvbnN0IGdldEZpbGVNZXRhZGF0YSA9IGFzeW5jIChmaWxlUGF0aDogc3RyaW5nKTogUHJvbWlzZTxGaWxlTWV0YWRhdGE+ID0+IHtcbiAgICBjb25zdCB7c2l6ZX0gPSBhd2FpdCBzdGF0KGZpbGVQYXRoKTtcbiAgICBjb25zdCB7bmFtZX0gPSBwYXRoLnBhcnNlKGZpbGVQYXRoKTtcbiAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgcmVhZEZpbGUoZmlsZVBhdGgpO1xuXG4gICAgcmV0dXJuIHtjaHVua05hbWU6IG5hbWUsIHNpemUsIGNvbnRlbnR9O1xufVxuIl19
@@ -0,0 +1,16 @@
1
+ export interface LoggerConfig {
2
+ maxLogSize: number;
3
+ logLevel: string;
4
+ }
5
+ export interface rumApiConfig {
6
+ maxMessageSize: number;
7
+ keepaliveTimeMs: number;
8
+ keepaliveTimeoutMs: number;
9
+ chunkSize: number;
10
+ }
11
+ export interface Config {
12
+ logger: LoggerConfig;
13
+ rumApi: rumApiConfig;
14
+ }
15
+ declare const config: Config;
16
+ export default config;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const config = {
4
+ logger: {
5
+ maxLogSize: 10000,
6
+ logLevel: 'debug',
7
+ },
8
+ rumApi: {
9
+ maxMessageSize: 400000 * 1024,
10
+ keepaliveTimeMs: 120000,
11
+ keepaliveTimeoutMs: 120000,
12
+ chunkSize: 512 * 1024 // 512 KB chunk size
13
+ }
14
+ };
15
+ exports.default = config;
16
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vY29uZmlnL2NvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQWlCQSxNQUFNLE1BQU0sR0FBVztJQUNuQixNQUFNLEVBQUU7UUFDSixVQUFVLEVBQUUsS0FBSztRQUNqQixRQUFRLEVBQUUsT0FBTztLQUNwQjtJQUNELE1BQU0sRUFBRTtRQUNKLGNBQWMsRUFBRSxNQUFNLEdBQUcsSUFBSTtRQUM3QixlQUFlLEVBQUUsTUFBTTtRQUN2QixrQkFBa0IsRUFBRSxNQUFNO1FBQzFCLFNBQVMsRUFBRSxHQUFHLEdBQUcsSUFBSSxDQUFDLG9CQUFvQjtLQUM3QztDQUNKLENBQUM7QUFFRixrQkFBZSxNQUFNLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgaW50ZXJmYWNlIExvZ2dlckNvbmZpZyB7XG4gICAgbWF4TG9nU2l6ZTogbnVtYmVyO1xuICAgIGxvZ0xldmVsOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgcnVtQXBpQ29uZmlnIHtcbiAgICBtYXhNZXNzYWdlU2l6ZTogbnVtYmVyLFxuICAgIGtlZXBhbGl2ZVRpbWVNczogbnVtYmVyXG4gICAga2VlcGFsaXZlVGltZW91dE1zOiBudW1iZXJcbiAgICBjaHVua1NpemU6IG51bWJlcixcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDb25maWcge1xuICAgIGxvZ2dlcjogTG9nZ2VyQ29uZmlnO1xuICAgIHJ1bUFwaTogcnVtQXBpQ29uZmlnO1xufVxuXG5jb25zdCBjb25maWc6IENvbmZpZyA9IHtcbiAgICBsb2dnZXI6IHtcbiAgICAgICAgbWF4TG9nU2l6ZTogMTAwMDAsXG4gICAgICAgIGxvZ0xldmVsOiAnZGVidWcnLFxuICAgIH0sXG4gICAgcnVtQXBpOiB7XG4gICAgICAgIG1heE1lc3NhZ2VTaXplOiA0MDAwMDAgKiAxMDI0LFxuICAgICAgICBrZWVwYWxpdmVUaW1lTXM6IDEyMDAwMCxcbiAgICAgICAga2VlcGFsaXZlVGltZW91dE1zOiAxMjAwMDAsXG4gICAgICAgIGNodW5rU2l6ZTogNTEyICogMTAyNCAvLyA1MTIgS0IgY2h1bmsgc2l6ZVxuICAgIH1cbn07XG5cbmV4cG9ydCBkZWZhdWx0IGNvbmZpZztcbiJdfQ==