@keplog/cli 0.2.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 (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +495 -0
  3. package/bin/keplog +2 -0
  4. package/dist/commands/delete.d.ts +3 -0
  5. package/dist/commands/delete.d.ts.map +1 -0
  6. package/dist/commands/delete.js +158 -0
  7. package/dist/commands/delete.js.map +1 -0
  8. package/dist/commands/init.d.ts +3 -0
  9. package/dist/commands/init.d.ts.map +1 -0
  10. package/dist/commands/init.js +131 -0
  11. package/dist/commands/init.js.map +1 -0
  12. package/dist/commands/issues.d.ts +3 -0
  13. package/dist/commands/issues.d.ts.map +1 -0
  14. package/dist/commands/issues.js +543 -0
  15. package/dist/commands/issues.js.map +1 -0
  16. package/dist/commands/list.d.ts +3 -0
  17. package/dist/commands/list.d.ts.map +1 -0
  18. package/dist/commands/list.js +104 -0
  19. package/dist/commands/list.js.map +1 -0
  20. package/dist/commands/releases.d.ts +3 -0
  21. package/dist/commands/releases.d.ts.map +1 -0
  22. package/dist/commands/releases.js +100 -0
  23. package/dist/commands/releases.js.map +1 -0
  24. package/dist/commands/upload.d.ts +3 -0
  25. package/dist/commands/upload.d.ts.map +1 -0
  26. package/dist/commands/upload.js +76 -0
  27. package/dist/commands/upload.js.map +1 -0
  28. package/dist/index.d.ts +3 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +28 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/lib/config.d.ts +57 -0
  33. package/dist/lib/config.d.ts.map +1 -0
  34. package/dist/lib/config.js +155 -0
  35. package/dist/lib/config.js.map +1 -0
  36. package/dist/lib/uploader.d.ts +11 -0
  37. package/dist/lib/uploader.d.ts.map +1 -0
  38. package/dist/lib/uploader.js +171 -0
  39. package/dist/lib/uploader.js.map +1 -0
  40. package/jest.config.js +16 -0
  41. package/package.json +58 -0
  42. package/src/commands/delete.ts +186 -0
  43. package/src/commands/init.ts +137 -0
  44. package/src/commands/issues.ts +695 -0
  45. package/src/commands/list.ts +124 -0
  46. package/src/commands/releases.ts +122 -0
  47. package/src/commands/upload.ts +76 -0
  48. package/src/index.ts +31 -0
  49. package/src/lib/config.ts +138 -0
  50. package/src/lib/uploader.ts +168 -0
  51. package/tests/README.md +380 -0
  52. package/tests/config.test.ts +397 -0
  53. package/tests/uploader.test.ts +524 -0
  54. package/tsconfig.json +20 -0
@@ -0,0 +1,171 @@
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 () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.uploadSourceMaps = uploadSourceMaps;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const glob_1 = require("glob");
43
+ const form_data_1 = __importDefault(require("form-data"));
44
+ const axios_1 = __importDefault(require("axios"));
45
+ const chalk_1 = __importDefault(require("chalk"));
46
+ const ora_1 = __importDefault(require("ora"));
47
+ async function uploadSourceMaps(options) {
48
+ const { release, filePatterns, projectId, apiKey, apiUrl, verbose } = options;
49
+ console.log(chalk_1.default.bold.cyan('\nšŸ“¦ Keplog Source Map Uploader\n'));
50
+ console.log(chalk_1.default.gray(`Release: ${release}`));
51
+ console.log(chalk_1.default.gray(`Project ID: ${projectId}`));
52
+ console.log(chalk_1.default.gray(`API URL: ${apiUrl}\n`));
53
+ // Find all matching files
54
+ const spinner = (0, ora_1.default)('Finding source map files...').start();
55
+ const allFiles = [];
56
+ for (const pattern of filePatterns) {
57
+ try {
58
+ const matches = await (0, glob_1.glob)(pattern, { nodir: true });
59
+ if (verbose) {
60
+ spinner.info(`Pattern "${pattern}" matched ${matches.length} file(s)`);
61
+ }
62
+ allFiles.push(...matches);
63
+ }
64
+ catch (error) {
65
+ spinner.fail(`Invalid glob pattern: ${pattern}`);
66
+ throw error;
67
+ }
68
+ }
69
+ // Remove duplicates
70
+ const uniqueFiles = [...new Set(allFiles)];
71
+ if (uniqueFiles.length === 0) {
72
+ spinner.fail('No source map files found');
73
+ console.log(chalk_1.default.yellow('\nāš ļø No files matched the specified patterns'));
74
+ console.log(chalk_1.default.gray('\nTip: Make sure your patterns are correct:'));
75
+ console.log(chalk_1.default.gray(' --files="dist/**/*.map"'));
76
+ console.log(chalk_1.default.gray(' --files="build/*.map"'));
77
+ process.exit(1);
78
+ }
79
+ spinner.succeed(`Found ${uniqueFiles.length} source map file(s)`);
80
+ // Filter only .map files
81
+ const mapFiles = uniqueFiles.filter(file => file.endsWith('.map'));
82
+ if (mapFiles.length === 0) {
83
+ console.log(chalk_1.default.yellow('\nāš ļø No .map files found'));
84
+ process.exit(1);
85
+ }
86
+ if (mapFiles.length !== uniqueFiles.length) {
87
+ console.log(chalk_1.default.yellow(`\nāš ļø Skipped ${uniqueFiles.length - mapFiles.length} non-.map file(s)`));
88
+ }
89
+ // Display files to upload
90
+ if (verbose) {
91
+ console.log(chalk_1.default.cyan('\nšŸ“ Files to upload:'));
92
+ mapFiles.forEach((file, index) => {
93
+ const stats = fs.statSync(file);
94
+ const size = formatFileSize(stats.size);
95
+ console.log(chalk_1.default.gray(` ${index + 1}. ${file} (${size})`));
96
+ });
97
+ console.log();
98
+ }
99
+ // Create form data
100
+ const uploadSpinner = (0, ora_1.default)(`Uploading ${mapFiles.length} file(s) to Keplog...`).start();
101
+ try {
102
+ const formData = new form_data_1.default();
103
+ formData.append('release', release);
104
+ // Add all files
105
+ for (const filePath of mapFiles) {
106
+ const fileName = path.basename(filePath);
107
+ const fileStream = fs.createReadStream(filePath);
108
+ formData.append('files', fileStream, fileName);
109
+ }
110
+ // Upload to API
111
+ const url = `${apiUrl}/api/v1/cli/projects/${projectId}/sourcemaps`;
112
+ const response = await axios_1.default.post(url, formData, {
113
+ headers: {
114
+ 'X-API-Key': apiKey,
115
+ ...formData.getHeaders(),
116
+ },
117
+ maxContentLength: Infinity,
118
+ maxBodyLength: Infinity,
119
+ });
120
+ const data = response.data;
121
+ uploadSpinner.succeed('Upload complete!');
122
+ // Display results
123
+ console.log(chalk_1.default.bold.green('\nāœ… Upload Complete!\n'));
124
+ console.log(chalk_1.default.gray(`Release: ${data.release}`));
125
+ console.log(chalk_1.default.gray(`Uploaded: ${data.count} file(s)\n`));
126
+ if (data.uploaded && data.uploaded.length > 0) {
127
+ console.log(chalk_1.default.cyan('šŸ“ Successfully uploaded:'));
128
+ data.uploaded.forEach(filename => {
129
+ console.log(chalk_1.default.green(` āœ“ ${filename}`));
130
+ });
131
+ }
132
+ if (data.errors && data.errors.length > 0) {
133
+ console.log(chalk_1.default.yellow('\nāš ļø Errors:'));
134
+ data.errors.forEach(error => {
135
+ console.log(chalk_1.default.red(` āœ— ${error}`));
136
+ });
137
+ process.exit(1);
138
+ }
139
+ console.log(chalk_1.default.cyan(`\nšŸ’” Source maps will be used automatically when processing errors for release ${data.release}\n`));
140
+ }
141
+ catch (error) {
142
+ uploadSpinner.fail('Upload failed');
143
+ if (axios_1.default.isAxiosError(error)) {
144
+ if (error.code === 'ENOTFOUND') {
145
+ throw new Error(`Could not connect to ${apiUrl}. Please check your internet connection.`);
146
+ }
147
+ else if (error.code === 'ECONNREFUSED') {
148
+ throw new Error(`Connection refused to ${apiUrl}. Please check the API URL.`);
149
+ }
150
+ else if (error.response) {
151
+ // Server responded with error
152
+ const data = error.response.data;
153
+ throw new Error(data.error || `HTTP ${error.response.status}: ${error.response.statusText}`);
154
+ }
155
+ else if (error.request) {
156
+ // Request made but no response
157
+ throw new Error(`No response from server. Please check your internet connection.`);
158
+ }
159
+ }
160
+ throw error;
161
+ }
162
+ }
163
+ function formatFileSize(bytes) {
164
+ if (bytes === 0)
165
+ return '0 B';
166
+ const k = 1024;
167
+ const sizes = ['B', 'KB', 'MB', 'GB'];
168
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
169
+ return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
170
+ }
171
+ //# sourceMappingURL=uploader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uploader.js","sourceRoot":"","sources":["../../src/lib/uploader.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,4CAsIC;AA/JD,uCAAyB;AACzB,2CAA6B;AAC7B,+BAA4B;AAC5B,0DAAiC;AACjC,kDAA0B;AAC1B,kDAA0B;AAC1B,8CAAsB;AAmBf,KAAK,UAAU,gBAAgB,CAAC,OAAsB;IAC3D,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAE9E,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,YAAY,OAAO,EAAE,CAAC,CAAC,CAAC;IAC/C,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,eAAe,SAAS,EAAE,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,YAAY,MAAM,IAAI,CAAC,CAAC,CAAC;IAEhD,0BAA0B;IAC1B,MAAM,OAAO,GAAG,IAAA,aAAG,EAAC,6BAA6B,CAAC,CAAC,KAAK,EAAE,CAAC;IAC3D,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,IAAA,WAAI,EAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACrD,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,IAAI,CAAC,YAAY,OAAO,aAAa,OAAO,CAAC,MAAM,UAAU,CAAC,CAAC;YACzE,CAAC;YACD,QAAQ,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,yBAAyB,OAAO,EAAE,CAAC,CAAC;YACjD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,oBAAoB;IACpB,MAAM,WAAW,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IAE3C,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,+CAA+C,CAAC,CAAC,CAAC;QAC3E,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC,CAAC;QACvE,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC,CAAC;QACrD,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAC;QACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,OAAO,CAAC,SAAS,WAAW,CAAC,MAAM,qBAAqB,CAAC,CAAC;IAElE,yBAAyB;IACzB,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAEnE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,2BAA2B,CAAC,CAAC,CAAC;QACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,KAAK,WAAW,CAAC,MAAM,EAAE,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,iBAAiB,WAAW,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,mBAAmB,CAAC,CAAC,CAAC;IACtG,CAAC;IAED,0BAA0B;IAC1B,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC;QACjD,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YAC/B,MAAM,KAAK,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAChC,MAAM,IAAI,GAAG,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACxC,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,KAAK,KAAK,GAAG,CAAC,KAAK,IAAI,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,EAAE,CAAC;IAChB,CAAC;IAED,mBAAmB;IACnB,MAAM,aAAa,GAAG,IAAA,aAAG,EAAC,aAAa,QAAQ,CAAC,MAAM,uBAAuB,CAAC,CAAC,KAAK,EAAE,CAAC;IAEvF,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,mBAAQ,EAAE,CAAC;QAChC,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAEpC,gBAAgB;QAChB,KAAK,MAAM,QAAQ,IAAI,QAAQ,EAAE,CAAC;YAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACzC,MAAM,UAAU,GAAG,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YACjD,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;QACjD,CAAC;QAED,gBAAgB;QAChB,MAAM,GAAG,GAAG,GAAG,MAAM,wBAAwB,SAAS,aAAa,CAAC;QAEpE,MAAM,QAAQ,GAAG,MAAM,eAAK,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE;YAC/C,OAAO,EAAE;gBACP,WAAW,EAAE,MAAM;gBACnB,GAAG,QAAQ,CAAC,UAAU,EAAE;aACzB;YACD,gBAAgB,EAAE,QAAQ;YAC1B,aAAa,EAAE,QAAQ;SACxB,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAsB,CAAC;QAE7C,aAAa,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;QAE1C,kBAAkB;QAClB,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC,CAAC;QACxD,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,KAAK,YAAY,CAAC,CAAC,CAAC;QAE7D,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9C,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC,CAAC;YACrD,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAC/B,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,QAAQ,QAAQ,EAAE,CAAC,CAAC,CAAC;YAC/C,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1C,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC;YAC3C,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;gBAC1B,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC;YAC1C,CAAC,CAAC,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,kFAAkF,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC;IAE9H,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAEpC,IAAI,eAAK,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBAC/B,MAAM,IAAI,KAAK,CAAC,wBAAwB,MAAM,0CAA0C,CAAC,CAAC;YAC5F,CAAC;iBAAM,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;gBACzC,MAAM,IAAI,KAAK,CAAC,yBAAyB,MAAM,6BAA6B,CAAC,CAAC;YAChF,CAAC;iBAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBAC1B,8BAA8B;gBAC9B,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACjC,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,QAAQ,KAAK,CAAC,QAAQ,CAAC,MAAM,KAAK,KAAK,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;YAC/F,CAAC;iBAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBACzB,+BAA+B;gBAC/B,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;YACrF,CAAC;QACH,CAAC;QAED,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9B,MAAM,CAAC,GAAG,IAAI,CAAC;IACf,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACtC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAC9D,CAAC"}
package/jest.config.js ADDED
@@ -0,0 +1,16 @@
1
+ module.exports = {
2
+ preset: 'ts-jest',
3
+ testEnvironment: 'node',
4
+ roots: ['<rootDir>/src', '<rootDir>/tests'],
5
+ testMatch: ['**/__tests__/**/*.ts', '**/*.test.ts', '**/*.spec.ts'],
6
+ moduleFileExtensions: ['ts', 'js', 'json'],
7
+ collectCoverageFrom: [
8
+ 'src/**/*.ts',
9
+ '!src/**/*.d.ts',
10
+ '!src/index.ts', // Main entry point, tested via integration
11
+ ],
12
+ coverageDirectory: 'coverage',
13
+ coverageReporters: ['text', 'lcov', 'html'],
14
+ verbose: true,
15
+ testTimeout: 10000,
16
+ };
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@keplog/cli",
3
+ "version": "0.2.0",
4
+ "description": "Official Keplog CLI for uploading source maps and managing projects",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "keplog": "./bin/keplog"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "dev": "tsc --watch",
12
+ "prepublishOnly": "npm run build",
13
+ "test": "jest",
14
+ "test:watch": "jest --watch",
15
+ "test:coverage": "jest --coverage",
16
+ "test:verbose": "jest --verbose"
17
+ },
18
+ "keywords": [
19
+ "keplog",
20
+ "error-tracking",
21
+ "source-maps",
22
+ "cli",
23
+ "monitoring"
24
+ ],
25
+ "author": "Keplog Team",
26
+ "license": "MIT",
27
+ "engines": {
28
+ "node": ">=16.0.0"
29
+ },
30
+ "dependencies": {
31
+ "axios": "^1.6.5",
32
+ "chalk": "^4.1.2",
33
+ "commander": "^11.1.0",
34
+ "dotenv": "^16.3.1",
35
+ "form-data": "^4.0.0",
36
+ "glob": "^10.3.10",
37
+ "ora": "^5.4.1",
38
+ "prompts": "^2.4.2"
39
+ },
40
+ "devDependencies": {
41
+ "@types/form-data": "^2.2.1",
42
+ "@types/jest": "^30.0.0",
43
+ "@types/node": "^20.10.5",
44
+ "@types/prompts": "^2.4.9",
45
+ "axios-mock-adapter": "^2.1.0",
46
+ "jest": "^30.2.0",
47
+ "ts-jest": "^29.4.6",
48
+ "typescript": "^5.3.3"
49
+ },
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "https://github.com/keplog/keplog-cli.git"
53
+ },
54
+ "bugs": {
55
+ "url": "https://github.com/keplog/keplog-cli/issues"
56
+ },
57
+ "homepage": "https://keplog.com"
58
+ }
@@ -0,0 +1,186 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import prompts from 'prompts';
5
+ import { ConfigManager } from '../lib/config.js';
6
+
7
+ interface SourceMap {
8
+ Filename: string;
9
+ Size: number;
10
+ UploadedAt: string;
11
+ }
12
+
13
+ interface ListResponse {
14
+ source_maps: SourceMap[];
15
+ release: string;
16
+ count: number;
17
+ }
18
+
19
+ export const deleteCommand = new Command('delete')
20
+ .description('Delete source maps for a specific release')
21
+ .option('-r, --release <version>', 'Release version')
22
+ .option('-f, --file <filename>', 'Specific file to delete (optional - omit to delete all)')
23
+ .option('-y, --yes', 'Skip confirmation prompt')
24
+ .option('-p, --project-id <id>', 'Project ID (overrides config)')
25
+ .option('-k, --api-key <key>', 'API key (overrides config)')
26
+ .option('-u, --api-url <url>', 'API URL (overrides config)')
27
+ .action(async (options) => {
28
+ try {
29
+ // Read config from file (priority: local > global > env)
30
+ const config = ConfigManager.getConfig();
31
+
32
+ const release = options.release || process.env.KEPLOG_RELEASE;
33
+ const filename = options.file;
34
+ const skipConfirm = options.yes || false;
35
+ const projectId = options.projectId || config.projectId;
36
+ const apiKey = options.apiKey || config.apiKey;
37
+ const apiUrl = options.apiUrl || config.apiUrl || 'https://api.keplog.com';
38
+
39
+ // Validate required parameters
40
+ if (!projectId) {
41
+ console.error(chalk.red('\nāœ— Error: Project ID is required\n'));
42
+ console.log('Options:');
43
+ console.log(' 1. Run: keplog init (recommended)');
44
+ console.log(' 2. Use flag: --project-id=<your-project-id>');
45
+ console.log(' 3. Set env: KEPLOG_PROJECT_ID=<your-project-id>\n');
46
+ process.exit(1);
47
+ }
48
+
49
+ if (!apiKey) {
50
+ console.error(chalk.red('\nāœ— Error: API key is required\n'));
51
+ console.log('Options:');
52
+ console.log(' 1. Run: keplog init (recommended)');
53
+ console.log(' 2. Use flag: --api-key=<your-api-key>');
54
+ console.log(' 3. Set env: KEPLOG_API_KEY=<your-api-key>\n');
55
+ process.exit(1);
56
+ }
57
+
58
+ if (!release) {
59
+ console.error(chalk.red('\nāœ— Error: Release version is required\n'));
60
+ console.log('Options:');
61
+ console.log(' 1. Use flag: --release=v1.0.0');
62
+ console.log(' 2. Set env: KEPLOG_RELEASE=v1.0.0\n');
63
+ process.exit(1);
64
+ }
65
+
66
+ console.log(chalk.bold.red('\nšŸ—‘ļø Keplog Source Maps - Delete\n'));
67
+ console.log(`Release: ${chalk.yellow(release)}`);
68
+ console.log(`Project ID: ${chalk.gray(projectId)}`);
69
+
70
+ if (filename) {
71
+ console.log(`File: ${chalk.yellow(filename)}\n`);
72
+ } else {
73
+ console.log(chalk.yellow('Target: All source maps for this release\n'));
74
+ }
75
+
76
+ // If deleting all files, fetch and show the list first
77
+ let filesToDelete: string[] = [];
78
+ if (!filename) {
79
+ const spinner = ora('Fetching source maps...').start();
80
+
81
+ const listUrl = `${apiUrl}/api/v1/cli/projects/${projectId}/sourcemaps?release=${encodeURIComponent(release)}`;
82
+ const listResponse = await fetch(listUrl, {
83
+ method: 'GET',
84
+ headers: {
85
+ 'X-API-Key': apiKey,
86
+ },
87
+ });
88
+
89
+ if (!listResponse.ok) {
90
+ const error = await listResponse.json() as any;
91
+ spinner.fail(chalk.red('Failed to fetch source maps'));
92
+ console.error(chalk.red(`\nāœ— Error: ${error.error || 'Unknown error'}\n`));
93
+ process.exit(1);
94
+ }
95
+
96
+ const data = await listResponse.json() as ListResponse;
97
+ spinner.succeed(`Found ${data.count} source map${data.count !== 1 ? 's' : ''}`);
98
+
99
+ if (data.count === 0) {
100
+ console.log(chalk.yellow('\nNo source maps found for this release.\n'));
101
+ return;
102
+ }
103
+
104
+ filesToDelete = data.source_maps.map(f => f.Filename);
105
+
106
+ console.log(chalk.gray('\nFiles to be deleted:'));
107
+ for (const file of data.source_maps) {
108
+ console.log(` ${chalk.red('āœ—')} ${file.Filename}`);
109
+ }
110
+ console.log('');
111
+ } else {
112
+ filesToDelete = [filename];
113
+ }
114
+
115
+ // Confirmation prompt (unless --yes flag is used)
116
+ if (!skipConfirm) {
117
+ const message = filename
118
+ ? `Are you sure you want to delete ${chalk.yellow(filename)} from release ${chalk.yellow(release)}?`
119
+ : `Are you sure you want to delete ${chalk.red.bold('ALL')} ${filesToDelete.length} source maps from release ${chalk.yellow(release)}?`;
120
+
121
+ const response = await prompts({
122
+ type: 'confirm',
123
+ name: 'confirmed',
124
+ message,
125
+ initial: false,
126
+ });
127
+
128
+ if (!response.confirmed) {
129
+ console.log(chalk.gray('\nDeletion cancelled.\n'));
130
+ return;
131
+ }
132
+ }
133
+
134
+ // Delete files
135
+ let deletedCount = 0;
136
+ let failedCount = 0;
137
+ const errors: string[] = [];
138
+
139
+ console.log(chalk.gray('\nDeleting source maps...\n'));
140
+
141
+ for (const file of filesToDelete) {
142
+ const spinner = ora(`Deleting ${file}...`).start();
143
+
144
+ try {
145
+ const deleteUrl = `${apiUrl}/api/v1/cli/projects/${projectId}/sourcemaps/${encodeURIComponent(file)}?release=${encodeURIComponent(release)}`;
146
+ const response = await fetch(deleteUrl, {
147
+ method: 'DELETE',
148
+ headers: {
149
+ 'X-API-Key': apiKey,
150
+ },
151
+ });
152
+
153
+ if (!response.ok) {
154
+ const error = await response.json() as any;
155
+ throw new Error(error.error || 'Unknown error');
156
+ }
157
+
158
+ spinner.succeed(chalk.green(`Deleted ${file}`));
159
+ deletedCount++;
160
+ } catch (error: any) {
161
+ spinner.fail(chalk.red(`Failed to delete ${file}`));
162
+ errors.push(`${file}: ${error.message}`);
163
+ failedCount++;
164
+ }
165
+ }
166
+
167
+ // Summary
168
+ console.log(chalk.bold('\nāœ… Deletion Complete!\n'));
169
+ console.log(`Release: ${chalk.yellow(release)}`);
170
+ console.log(`Deleted: ${chalk.green(deletedCount)} file${deletedCount !== 1 ? 's' : ''}`);
171
+
172
+ if (failedCount > 0) {
173
+ console.log(`Failed: ${chalk.red(failedCount)} file${failedCount !== 1 ? 's' : ''}\n`);
174
+ console.log(chalk.red.bold('āš ļø Errors:'));
175
+ for (const error of errors) {
176
+ console.log(` ${chalk.red('āœ—')} ${error}`);
177
+ }
178
+ }
179
+
180
+ console.log('');
181
+
182
+ } catch (error: any) {
183
+ console.error(chalk.red(`\nāœ— Error: ${error.message}\n`));
184
+ process.exit(1);
185
+ }
186
+ });
@@ -0,0 +1,137 @@
1
+ import { Command } from 'commander';
2
+ import prompts from 'prompts';
3
+ import chalk from 'chalk';
4
+ import { ConfigManager } from '../lib/config';
5
+
6
+ export const initCommand = new Command('init')
7
+ .description('Initialize Keplog configuration for the current project')
8
+ .option('-g, --global', 'Save configuration globally (in ~/.keplogrc)')
9
+ .option('-f, --force', 'Overwrite existing configuration')
10
+ .action(async (options) => {
11
+ try {
12
+ const isGlobal = options.global || false;
13
+ const force = options.force || false;
14
+
15
+ console.log(chalk.bold.cyan('\nšŸš€ Keplog CLI Configuration\n'));
16
+
17
+ // Check if config already exists
18
+ const hasLocal = ConfigManager.hasLocalConfig();
19
+ const hasGlobal = ConfigManager.hasGlobalConfig();
20
+
21
+ if (!force) {
22
+ if (isGlobal && hasGlobal) {
23
+ console.log(chalk.yellow('āš ļø Global configuration already exists at ~/.keplogrc'));
24
+ const { overwrite } = await prompts({
25
+ type: 'confirm',
26
+ name: 'overwrite',
27
+ message: 'Do you want to overwrite it?',
28
+ initial: false,
29
+ });
30
+
31
+ if (!overwrite) {
32
+ console.log(chalk.gray('\nConfiguration cancelled.'));
33
+ return;
34
+ }
35
+ } else if (!isGlobal && hasLocal) {
36
+ const configPath = ConfigManager.getLocalConfigPath();
37
+ console.log(chalk.yellow(`āš ļø Configuration already exists at ${configPath}`));
38
+ const { overwrite } = await prompts({
39
+ type: 'confirm',
40
+ name: 'overwrite',
41
+ message: 'Do you want to overwrite it?',
42
+ initial: false,
43
+ });
44
+
45
+ if (!overwrite) {
46
+ console.log(chalk.gray('\nConfiguration cancelled.'));
47
+ return;
48
+ }
49
+ }
50
+ }
51
+
52
+ // Read existing config (if any)
53
+ const existingConfig = ConfigManager.readConfig();
54
+
55
+ // Interactive prompts
56
+ console.log(chalk.gray('Get your credentials from: Project Settings → General → Project Credentials\n'));
57
+
58
+ const responses = await prompts([
59
+ {
60
+ type: 'text',
61
+ name: 'projectId',
62
+ message: 'Project ID:',
63
+ initial: existingConfig.projectId || '',
64
+ validate: (value: string) => value.trim().length > 0 || 'Project ID is required',
65
+ },
66
+ {
67
+ type: 'password',
68
+ name: 'apiKey',
69
+ message: 'API Key:',
70
+ initial: existingConfig.apiKey || '',
71
+ validate: (value: string) => value.trim().length > 0 || 'API Key is required',
72
+ },
73
+ {
74
+ type: 'text',
75
+ name: 'apiUrl',
76
+ message: 'API URL (optional):',
77
+ initial: existingConfig.apiUrl || 'https://api.keplog.com',
78
+ },
79
+ {
80
+ type: 'text',
81
+ name: 'projectName',
82
+ message: 'Project name (optional):',
83
+ initial: existingConfig.projectName || '',
84
+ },
85
+ ]);
86
+
87
+ // Check if user cancelled
88
+ if (!responses.projectId || !responses.apiKey) {
89
+ console.log(chalk.gray('\nConfiguration cancelled.'));
90
+ return;
91
+ }
92
+
93
+ // Prepare config
94
+ const config = {
95
+ projectId: responses.projectId.trim(),
96
+ apiKey: responses.apiKey.trim(),
97
+ apiUrl: responses.apiUrl?.trim() || 'https://api.keplog.com',
98
+ projectName: responses.projectName?.trim() || undefined,
99
+ };
100
+
101
+ // Save config
102
+ if (isGlobal) {
103
+ ConfigManager.writeGlobalConfig(config);
104
+ console.log(chalk.green('\nāœ… Configuration saved globally to ~/.keplogrc'));
105
+ } else {
106
+ ConfigManager.writeLocalConfig(config);
107
+ console.log(chalk.green('\nāœ… Configuration saved to .keplog.json'));
108
+ console.log(chalk.gray('\nTip: Add .keplog.json to .gitignore to keep credentials secret'));
109
+ }
110
+
111
+ // Display saved config
112
+ console.log(chalk.cyan('\nšŸ“ Saved configuration:'));
113
+ console.log(chalk.gray(` Project ID: ${config.projectId}`));
114
+ console.log(chalk.gray(` API Key: ${'*'.repeat(Math.min(config.apiKey.length, 20))}...`));
115
+ console.log(chalk.gray(` API URL: ${config.apiUrl}`));
116
+ if (config.projectName) {
117
+ console.log(chalk.gray(` Project Name: ${config.projectName}`));
118
+ }
119
+
120
+ console.log(chalk.cyan('\nšŸ’” Next steps:'));
121
+ console.log(chalk.gray(' 1. Upload source maps: keplog upload --release=v1.0.0 --files="dist/**/*.map"'));
122
+ console.log(chalk.gray(' 2. View help: keplog upload --help'));
123
+ console.log();
124
+
125
+ } catch (error: any) {
126
+ if (error.message === 'canceled') {
127
+ console.log(chalk.gray('\n\nConfiguration cancelled.'));
128
+ process.exit(0);
129
+ }
130
+
131
+ console.error(chalk.red(`\nāŒ Error: ${error.message}`));
132
+ if (error.stack && process.env.DEBUG) {
133
+ console.error(chalk.gray(error.stack));
134
+ }
135
+ process.exit(1);
136
+ }
137
+ });