coderifts 1.7.0 → 1.8.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.
- package/bin/coderifts.js +75 -0
- package/dist/cli.js +498 -48
- package/package.json +4 -2
- package/scripts/postinstall.js +53 -0
package/bin/coderifts.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
const { program } = require('commander');
|
|
6
|
+
const pkg = require('../package.json');
|
|
7
|
+
|
|
8
|
+
program
|
|
9
|
+
.name('coderifts')
|
|
10
|
+
.description('Detect breaking API changes between OpenAPI specs')
|
|
11
|
+
.version(pkg.version, '-v, --version');
|
|
12
|
+
|
|
13
|
+
// ── diff command ──
|
|
14
|
+
program
|
|
15
|
+
.command('diff <old-spec> <new-spec>')
|
|
16
|
+
.description('Compare two OpenAPI specs and report breaking changes')
|
|
17
|
+
.option('-f, --format <format>', 'Output format: terminal (default), json, markdown', 'terminal')
|
|
18
|
+
.option('--ci', 'CI mode — exit with code 1 if breaking changes exceed threshold')
|
|
19
|
+
.option('--threshold <number>', 'Risk score threshold for CI mode (0-100)', '50')
|
|
20
|
+
.option('--cloud', 'Use the CodeRifts cloud API instead of local analysis')
|
|
21
|
+
.option('-c, --config <path>', 'Path to .coderifts.yml config file')
|
|
22
|
+
.option('--no-normalize', 'Skip spec normalization (raw diff mode)')
|
|
23
|
+
.action(async (oldSpec, newSpec, options) => {
|
|
24
|
+
const { diff } = require('../src/commands/diff');
|
|
25
|
+
await diff(oldSpec, newSpec, options);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// ── init command ──
|
|
29
|
+
program
|
|
30
|
+
.command('init [template]')
|
|
31
|
+
.description('Generate a .coderifts.yml from a policy template (startup, growth, fintech, public-api, microservices)')
|
|
32
|
+
.action(async (template) => {
|
|
33
|
+
const { init } = require('../src/commands/init');
|
|
34
|
+
await init(template);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// ── login command ──
|
|
38
|
+
program
|
|
39
|
+
.command('login')
|
|
40
|
+
.description('Save your API key for cloud features')
|
|
41
|
+
.action(async () => {
|
|
42
|
+
const { login } = require('../src/commands/login');
|
|
43
|
+
await login();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// ── hook command group ──
|
|
47
|
+
const hookCmd = program
|
|
48
|
+
.command('hook')
|
|
49
|
+
.description('Manage the CodeRifts pre-push Git hook');
|
|
50
|
+
|
|
51
|
+
hookCmd
|
|
52
|
+
.command('install')
|
|
53
|
+
.description('Install the CodeRifts pre-push hook in the current Git repo')
|
|
54
|
+
.action(() => {
|
|
55
|
+
const { install } = require('../src/commands/hook');
|
|
56
|
+
install();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
hookCmd
|
|
60
|
+
.command('uninstall')
|
|
61
|
+
.description('Remove the CodeRifts pre-push hook from the current Git repo')
|
|
62
|
+
.action(() => {
|
|
63
|
+
const { uninstall } = require('../src/commands/hook');
|
|
64
|
+
uninstall();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
hookCmd
|
|
68
|
+
.command('status')
|
|
69
|
+
.description('Show whether the CodeRifts pre-push hook is installed and configured')
|
|
70
|
+
.action(() => {
|
|
71
|
+
const { status } = require('../src/commands/hook');
|
|
72
|
+
status();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
program.parse();
|
package/dist/cli.js
CHANGED
|
@@ -3003,7 +3003,7 @@ var require_package = __commonJS({
|
|
|
3003
3003
|
"package.json"(exports2, module2) {
|
|
3004
3004
|
module2.exports = {
|
|
3005
3005
|
name: "coderifts",
|
|
3006
|
-
version: "1.
|
|
3006
|
+
version: "1.8.0",
|
|
3007
3007
|
description: "Detect breaking API changes from the command line. Works locally or with the CodeRifts cloud API.",
|
|
3008
3008
|
author: "CodeRifts <hello@coderifts.com>",
|
|
3009
3009
|
license: "MIT",
|
|
@@ -3013,6 +3013,8 @@ var require_package = __commonJS({
|
|
|
3013
3013
|
main: "dist/cli.js",
|
|
3014
3014
|
files: [
|
|
3015
3015
|
"dist/",
|
|
3016
|
+
"bin/",
|
|
3017
|
+
"scripts/",
|
|
3016
3018
|
"README.md"
|
|
3017
3019
|
],
|
|
3018
3020
|
keywords: [
|
|
@@ -3056,7 +3058,7 @@ var require_package = __commonJS({
|
|
|
3056
3058
|
"json-schema-ref-parser": "npm:@apidevtools/json-schema-ref-parser@^11.7.3"
|
|
3057
3059
|
},
|
|
3058
3060
|
devDependencies: {
|
|
3059
|
-
esbuild: "^0.27.
|
|
3061
|
+
esbuild: "^0.27.4"
|
|
3060
3062
|
}
|
|
3061
3063
|
};
|
|
3062
3064
|
}
|
|
@@ -61464,14 +61466,438 @@ var require_proxy_from_env = __commonJS({
|
|
|
61464
61466
|
}
|
|
61465
61467
|
});
|
|
61466
61468
|
|
|
61467
|
-
// node_modules/
|
|
61469
|
+
// ../../node_modules/ms/index.js
|
|
61470
|
+
var require_ms = __commonJS({
|
|
61471
|
+
"../../node_modules/ms/index.js"(exports2, module2) {
|
|
61472
|
+
var s = 1e3;
|
|
61473
|
+
var m = s * 60;
|
|
61474
|
+
var h = m * 60;
|
|
61475
|
+
var d = h * 24;
|
|
61476
|
+
var y = d * 365.25;
|
|
61477
|
+
module2.exports = function(val, options) {
|
|
61478
|
+
options = options || {};
|
|
61479
|
+
var type = typeof val;
|
|
61480
|
+
if (type === "string" && val.length > 0) {
|
|
61481
|
+
return parse(val);
|
|
61482
|
+
} else if (type === "number" && isNaN(val) === false) {
|
|
61483
|
+
return options.long ? fmtLong(val) : fmtShort(val);
|
|
61484
|
+
}
|
|
61485
|
+
throw new Error(
|
|
61486
|
+
"val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
|
|
61487
|
+
);
|
|
61488
|
+
};
|
|
61489
|
+
function parse(str) {
|
|
61490
|
+
str = String(str);
|
|
61491
|
+
if (str.length > 100) {
|
|
61492
|
+
return;
|
|
61493
|
+
}
|
|
61494
|
+
var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(
|
|
61495
|
+
str
|
|
61496
|
+
);
|
|
61497
|
+
if (!match) {
|
|
61498
|
+
return;
|
|
61499
|
+
}
|
|
61500
|
+
var n = parseFloat(match[1]);
|
|
61501
|
+
var type = (match[2] || "ms").toLowerCase();
|
|
61502
|
+
switch (type) {
|
|
61503
|
+
case "years":
|
|
61504
|
+
case "year":
|
|
61505
|
+
case "yrs":
|
|
61506
|
+
case "yr":
|
|
61507
|
+
case "y":
|
|
61508
|
+
return n * y;
|
|
61509
|
+
case "days":
|
|
61510
|
+
case "day":
|
|
61511
|
+
case "d":
|
|
61512
|
+
return n * d;
|
|
61513
|
+
case "hours":
|
|
61514
|
+
case "hour":
|
|
61515
|
+
case "hrs":
|
|
61516
|
+
case "hr":
|
|
61517
|
+
case "h":
|
|
61518
|
+
return n * h;
|
|
61519
|
+
case "minutes":
|
|
61520
|
+
case "minute":
|
|
61521
|
+
case "mins":
|
|
61522
|
+
case "min":
|
|
61523
|
+
case "m":
|
|
61524
|
+
return n * m;
|
|
61525
|
+
case "seconds":
|
|
61526
|
+
case "second":
|
|
61527
|
+
case "secs":
|
|
61528
|
+
case "sec":
|
|
61529
|
+
case "s":
|
|
61530
|
+
return n * s;
|
|
61531
|
+
case "milliseconds":
|
|
61532
|
+
case "millisecond":
|
|
61533
|
+
case "msecs":
|
|
61534
|
+
case "msec":
|
|
61535
|
+
case "ms":
|
|
61536
|
+
return n;
|
|
61537
|
+
default:
|
|
61538
|
+
return void 0;
|
|
61539
|
+
}
|
|
61540
|
+
}
|
|
61541
|
+
function fmtShort(ms) {
|
|
61542
|
+
if (ms >= d) {
|
|
61543
|
+
return Math.round(ms / d) + "d";
|
|
61544
|
+
}
|
|
61545
|
+
if (ms >= h) {
|
|
61546
|
+
return Math.round(ms / h) + "h";
|
|
61547
|
+
}
|
|
61548
|
+
if (ms >= m) {
|
|
61549
|
+
return Math.round(ms / m) + "m";
|
|
61550
|
+
}
|
|
61551
|
+
if (ms >= s) {
|
|
61552
|
+
return Math.round(ms / s) + "s";
|
|
61553
|
+
}
|
|
61554
|
+
return ms + "ms";
|
|
61555
|
+
}
|
|
61556
|
+
function fmtLong(ms) {
|
|
61557
|
+
return plural(ms, d, "day") || plural(ms, h, "hour") || plural(ms, m, "minute") || plural(ms, s, "second") || ms + " ms";
|
|
61558
|
+
}
|
|
61559
|
+
function plural(ms, n, name) {
|
|
61560
|
+
if (ms < n) {
|
|
61561
|
+
return;
|
|
61562
|
+
}
|
|
61563
|
+
if (ms < n * 1.5) {
|
|
61564
|
+
return Math.floor(ms / n) + " " + name;
|
|
61565
|
+
}
|
|
61566
|
+
return Math.ceil(ms / n) + " " + name + "s";
|
|
61567
|
+
}
|
|
61568
|
+
}
|
|
61569
|
+
});
|
|
61570
|
+
|
|
61571
|
+
// ../../node_modules/debug/src/debug.js
|
|
61468
61572
|
var require_debug2 = __commonJS({
|
|
61573
|
+
"../../node_modules/debug/src/debug.js"(exports2, module2) {
|
|
61574
|
+
exports2 = module2.exports = createDebug.debug = createDebug["default"] = createDebug;
|
|
61575
|
+
exports2.coerce = coerce;
|
|
61576
|
+
exports2.disable = disable;
|
|
61577
|
+
exports2.enable = enable;
|
|
61578
|
+
exports2.enabled = enabled;
|
|
61579
|
+
exports2.humanize = require_ms();
|
|
61580
|
+
exports2.names = [];
|
|
61581
|
+
exports2.skips = [];
|
|
61582
|
+
exports2.formatters = {};
|
|
61583
|
+
var prevTime;
|
|
61584
|
+
function selectColor(namespace) {
|
|
61585
|
+
var hash = 0, i;
|
|
61586
|
+
for (i in namespace) {
|
|
61587
|
+
hash = (hash << 5) - hash + namespace.charCodeAt(i);
|
|
61588
|
+
hash |= 0;
|
|
61589
|
+
}
|
|
61590
|
+
return exports2.colors[Math.abs(hash) % exports2.colors.length];
|
|
61591
|
+
}
|
|
61592
|
+
function createDebug(namespace) {
|
|
61593
|
+
function debug() {
|
|
61594
|
+
if (!debug.enabled) return;
|
|
61595
|
+
var self2 = debug;
|
|
61596
|
+
var curr = +/* @__PURE__ */ new Date();
|
|
61597
|
+
var ms = curr - (prevTime || curr);
|
|
61598
|
+
self2.diff = ms;
|
|
61599
|
+
self2.prev = prevTime;
|
|
61600
|
+
self2.curr = curr;
|
|
61601
|
+
prevTime = curr;
|
|
61602
|
+
var args = new Array(arguments.length);
|
|
61603
|
+
for (var i = 0; i < args.length; i++) {
|
|
61604
|
+
args[i] = arguments[i];
|
|
61605
|
+
}
|
|
61606
|
+
args[0] = exports2.coerce(args[0]);
|
|
61607
|
+
if ("string" !== typeof args[0]) {
|
|
61608
|
+
args.unshift("%O");
|
|
61609
|
+
}
|
|
61610
|
+
var index = 0;
|
|
61611
|
+
args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) {
|
|
61612
|
+
if (match === "%%") return match;
|
|
61613
|
+
index++;
|
|
61614
|
+
var formatter = exports2.formatters[format];
|
|
61615
|
+
if ("function" === typeof formatter) {
|
|
61616
|
+
var val = args[index];
|
|
61617
|
+
match = formatter.call(self2, val);
|
|
61618
|
+
args.splice(index, 1);
|
|
61619
|
+
index--;
|
|
61620
|
+
}
|
|
61621
|
+
return match;
|
|
61622
|
+
});
|
|
61623
|
+
exports2.formatArgs.call(self2, args);
|
|
61624
|
+
var logFn = debug.log || exports2.log || console.log.bind(console);
|
|
61625
|
+
logFn.apply(self2, args);
|
|
61626
|
+
}
|
|
61627
|
+
debug.namespace = namespace;
|
|
61628
|
+
debug.enabled = exports2.enabled(namespace);
|
|
61629
|
+
debug.useColors = exports2.useColors();
|
|
61630
|
+
debug.color = selectColor(namespace);
|
|
61631
|
+
if ("function" === typeof exports2.init) {
|
|
61632
|
+
exports2.init(debug);
|
|
61633
|
+
}
|
|
61634
|
+
return debug;
|
|
61635
|
+
}
|
|
61636
|
+
function enable(namespaces) {
|
|
61637
|
+
exports2.save(namespaces);
|
|
61638
|
+
exports2.names = [];
|
|
61639
|
+
exports2.skips = [];
|
|
61640
|
+
var split = (typeof namespaces === "string" ? namespaces : "").split(/[\s,]+/);
|
|
61641
|
+
var len = split.length;
|
|
61642
|
+
for (var i = 0; i < len; i++) {
|
|
61643
|
+
if (!split[i]) continue;
|
|
61644
|
+
namespaces = split[i].replace(/\*/g, ".*?");
|
|
61645
|
+
if (namespaces[0] === "-") {
|
|
61646
|
+
exports2.skips.push(new RegExp("^" + namespaces.substr(1) + "$"));
|
|
61647
|
+
} else {
|
|
61648
|
+
exports2.names.push(new RegExp("^" + namespaces + "$"));
|
|
61649
|
+
}
|
|
61650
|
+
}
|
|
61651
|
+
}
|
|
61652
|
+
function disable() {
|
|
61653
|
+
exports2.enable("");
|
|
61654
|
+
}
|
|
61655
|
+
function enabled(name) {
|
|
61656
|
+
var i, len;
|
|
61657
|
+
for (i = 0, len = exports2.skips.length; i < len; i++) {
|
|
61658
|
+
if (exports2.skips[i].test(name)) {
|
|
61659
|
+
return false;
|
|
61660
|
+
}
|
|
61661
|
+
}
|
|
61662
|
+
for (i = 0, len = exports2.names.length; i < len; i++) {
|
|
61663
|
+
if (exports2.names[i].test(name)) {
|
|
61664
|
+
return true;
|
|
61665
|
+
}
|
|
61666
|
+
}
|
|
61667
|
+
return false;
|
|
61668
|
+
}
|
|
61669
|
+
function coerce(val) {
|
|
61670
|
+
if (val instanceof Error) return val.stack || val.message;
|
|
61671
|
+
return val;
|
|
61672
|
+
}
|
|
61673
|
+
}
|
|
61674
|
+
});
|
|
61675
|
+
|
|
61676
|
+
// ../../node_modules/debug/src/browser.js
|
|
61677
|
+
var require_browser = __commonJS({
|
|
61678
|
+
"../../node_modules/debug/src/browser.js"(exports2, module2) {
|
|
61679
|
+
exports2 = module2.exports = require_debug2();
|
|
61680
|
+
exports2.log = log;
|
|
61681
|
+
exports2.formatArgs = formatArgs;
|
|
61682
|
+
exports2.save = save;
|
|
61683
|
+
exports2.load = load;
|
|
61684
|
+
exports2.useColors = useColors;
|
|
61685
|
+
exports2.storage = "undefined" != typeof chrome && "undefined" != typeof chrome.storage ? chrome.storage.local : localstorage();
|
|
61686
|
+
exports2.colors = [
|
|
61687
|
+
"lightseagreen",
|
|
61688
|
+
"forestgreen",
|
|
61689
|
+
"goldenrod",
|
|
61690
|
+
"dodgerblue",
|
|
61691
|
+
"darkorchid",
|
|
61692
|
+
"crimson"
|
|
61693
|
+
];
|
|
61694
|
+
function useColors() {
|
|
61695
|
+
if (typeof window !== "undefined" && window.process && window.process.type === "renderer") {
|
|
61696
|
+
return true;
|
|
61697
|
+
}
|
|
61698
|
+
return typeof document !== "undefined" && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance || // is firebug? http://stackoverflow.com/a/398120/376773
|
|
61699
|
+
typeof window !== "undefined" && window.console && (window.console.firebug || window.console.exception && window.console.table) || // is firefox >= v31?
|
|
61700
|
+
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
|
|
61701
|
+
typeof navigator !== "undefined" && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31 || // double check webkit in userAgent just in case we are in a worker
|
|
61702
|
+
typeof navigator !== "undefined" && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/);
|
|
61703
|
+
}
|
|
61704
|
+
exports2.formatters.j = function(v) {
|
|
61705
|
+
try {
|
|
61706
|
+
return JSON.stringify(v);
|
|
61707
|
+
} catch (err) {
|
|
61708
|
+
return "[UnexpectedJSONParseError]: " + err.message;
|
|
61709
|
+
}
|
|
61710
|
+
};
|
|
61711
|
+
function formatArgs(args) {
|
|
61712
|
+
var useColors2 = this.useColors;
|
|
61713
|
+
args[0] = (useColors2 ? "%c" : "") + this.namespace + (useColors2 ? " %c" : " ") + args[0] + (useColors2 ? "%c " : " ") + "+" + exports2.humanize(this.diff);
|
|
61714
|
+
if (!useColors2) return;
|
|
61715
|
+
var c = "color: " + this.color;
|
|
61716
|
+
args.splice(1, 0, c, "color: inherit");
|
|
61717
|
+
var index = 0;
|
|
61718
|
+
var lastC = 0;
|
|
61719
|
+
args[0].replace(/%[a-zA-Z%]/g, function(match) {
|
|
61720
|
+
if ("%%" === match) return;
|
|
61721
|
+
index++;
|
|
61722
|
+
if ("%c" === match) {
|
|
61723
|
+
lastC = index;
|
|
61724
|
+
}
|
|
61725
|
+
});
|
|
61726
|
+
args.splice(lastC, 0, c);
|
|
61727
|
+
}
|
|
61728
|
+
function log() {
|
|
61729
|
+
return "object" === typeof console && console.log && Function.prototype.apply.call(console.log, console, arguments);
|
|
61730
|
+
}
|
|
61731
|
+
function save(namespaces) {
|
|
61732
|
+
try {
|
|
61733
|
+
if (null == namespaces) {
|
|
61734
|
+
exports2.storage.removeItem("debug");
|
|
61735
|
+
} else {
|
|
61736
|
+
exports2.storage.debug = namespaces;
|
|
61737
|
+
}
|
|
61738
|
+
} catch (e) {
|
|
61739
|
+
}
|
|
61740
|
+
}
|
|
61741
|
+
function load() {
|
|
61742
|
+
var r;
|
|
61743
|
+
try {
|
|
61744
|
+
r = exports2.storage.debug;
|
|
61745
|
+
} catch (e) {
|
|
61746
|
+
}
|
|
61747
|
+
if (!r && typeof process !== "undefined" && "env" in process) {
|
|
61748
|
+
r = process.env.DEBUG;
|
|
61749
|
+
}
|
|
61750
|
+
return r;
|
|
61751
|
+
}
|
|
61752
|
+
exports2.enable(load());
|
|
61753
|
+
function localstorage() {
|
|
61754
|
+
try {
|
|
61755
|
+
return window.localStorage;
|
|
61756
|
+
} catch (e) {
|
|
61757
|
+
}
|
|
61758
|
+
}
|
|
61759
|
+
}
|
|
61760
|
+
});
|
|
61761
|
+
|
|
61762
|
+
// ../../node_modules/debug/src/node.js
|
|
61763
|
+
var require_node2 = __commonJS({
|
|
61764
|
+
"../../node_modules/debug/src/node.js"(exports2, module2) {
|
|
61765
|
+
var tty = require("tty");
|
|
61766
|
+
var util = require("util");
|
|
61767
|
+
exports2 = module2.exports = require_debug2();
|
|
61768
|
+
exports2.init = init;
|
|
61769
|
+
exports2.log = log;
|
|
61770
|
+
exports2.formatArgs = formatArgs;
|
|
61771
|
+
exports2.save = save;
|
|
61772
|
+
exports2.load = load;
|
|
61773
|
+
exports2.useColors = useColors;
|
|
61774
|
+
exports2.colors = [6, 2, 3, 4, 5, 1];
|
|
61775
|
+
exports2.inspectOpts = Object.keys(process.env).filter(function(key) {
|
|
61776
|
+
return /^debug_/i.test(key);
|
|
61777
|
+
}).reduce(function(obj, key) {
|
|
61778
|
+
var prop = key.substring(6).toLowerCase().replace(/_([a-z])/g, function(_, k) {
|
|
61779
|
+
return k.toUpperCase();
|
|
61780
|
+
});
|
|
61781
|
+
var val = process.env[key];
|
|
61782
|
+
if (/^(yes|on|true|enabled)$/i.test(val)) val = true;
|
|
61783
|
+
else if (/^(no|off|false|disabled)$/i.test(val)) val = false;
|
|
61784
|
+
else if (val === "null") val = null;
|
|
61785
|
+
else val = Number(val);
|
|
61786
|
+
obj[prop] = val;
|
|
61787
|
+
return obj;
|
|
61788
|
+
}, {});
|
|
61789
|
+
var fd = parseInt(process.env.DEBUG_FD, 10) || 2;
|
|
61790
|
+
if (1 !== fd && 2 !== fd) {
|
|
61791
|
+
util.deprecate(function() {
|
|
61792
|
+
}, "except for stderr(2) and stdout(1), any other usage of DEBUG_FD is deprecated. Override debug.log if you want to use a different log function (https://git.io/debug_fd)")();
|
|
61793
|
+
}
|
|
61794
|
+
var stream = 1 === fd ? process.stdout : 2 === fd ? process.stderr : createWritableStdioStream(fd);
|
|
61795
|
+
function useColors() {
|
|
61796
|
+
return "colors" in exports2.inspectOpts ? Boolean(exports2.inspectOpts.colors) : tty.isatty(fd);
|
|
61797
|
+
}
|
|
61798
|
+
exports2.formatters.o = function(v) {
|
|
61799
|
+
this.inspectOpts.colors = this.useColors;
|
|
61800
|
+
return util.inspect(v, this.inspectOpts).split("\n").map(function(str) {
|
|
61801
|
+
return str.trim();
|
|
61802
|
+
}).join(" ");
|
|
61803
|
+
};
|
|
61804
|
+
exports2.formatters.O = function(v) {
|
|
61805
|
+
this.inspectOpts.colors = this.useColors;
|
|
61806
|
+
return util.inspect(v, this.inspectOpts);
|
|
61807
|
+
};
|
|
61808
|
+
function formatArgs(args) {
|
|
61809
|
+
var name = this.namespace;
|
|
61810
|
+
var useColors2 = this.useColors;
|
|
61811
|
+
if (useColors2) {
|
|
61812
|
+
var c = this.color;
|
|
61813
|
+
var prefix = " \x1B[3" + c + ";1m" + name + " \x1B[0m";
|
|
61814
|
+
args[0] = prefix + args[0].split("\n").join("\n" + prefix);
|
|
61815
|
+
args.push("\x1B[3" + c + "m+" + exports2.humanize(this.diff) + "\x1B[0m");
|
|
61816
|
+
} else {
|
|
61817
|
+
args[0] = (/* @__PURE__ */ new Date()).toUTCString() + " " + name + " " + args[0];
|
|
61818
|
+
}
|
|
61819
|
+
}
|
|
61820
|
+
function log() {
|
|
61821
|
+
return stream.write(util.format.apply(util, arguments) + "\n");
|
|
61822
|
+
}
|
|
61823
|
+
function save(namespaces) {
|
|
61824
|
+
if (null == namespaces) {
|
|
61825
|
+
delete process.env.DEBUG;
|
|
61826
|
+
} else {
|
|
61827
|
+
process.env.DEBUG = namespaces;
|
|
61828
|
+
}
|
|
61829
|
+
}
|
|
61830
|
+
function load() {
|
|
61831
|
+
return process.env.DEBUG;
|
|
61832
|
+
}
|
|
61833
|
+
function createWritableStdioStream(fd2) {
|
|
61834
|
+
var stream2;
|
|
61835
|
+
var tty_wrap = process.binding("tty_wrap");
|
|
61836
|
+
switch (tty_wrap.guessHandleType(fd2)) {
|
|
61837
|
+
case "TTY":
|
|
61838
|
+
stream2 = new tty.WriteStream(fd2);
|
|
61839
|
+
stream2._type = "tty";
|
|
61840
|
+
if (stream2._handle && stream2._handle.unref) {
|
|
61841
|
+
stream2._handle.unref();
|
|
61842
|
+
}
|
|
61843
|
+
break;
|
|
61844
|
+
case "FILE":
|
|
61845
|
+
var fs = require("fs");
|
|
61846
|
+
stream2 = new fs.SyncWriteStream(fd2, { autoClose: false });
|
|
61847
|
+
stream2._type = "fs";
|
|
61848
|
+
break;
|
|
61849
|
+
case "PIPE":
|
|
61850
|
+
case "TCP":
|
|
61851
|
+
var net = require("net");
|
|
61852
|
+
stream2 = new net.Socket({
|
|
61853
|
+
fd: fd2,
|
|
61854
|
+
readable: false,
|
|
61855
|
+
writable: true
|
|
61856
|
+
});
|
|
61857
|
+
stream2.readable = false;
|
|
61858
|
+
stream2.read = null;
|
|
61859
|
+
stream2._type = "pipe";
|
|
61860
|
+
if (stream2._handle && stream2._handle.unref) {
|
|
61861
|
+
stream2._handle.unref();
|
|
61862
|
+
}
|
|
61863
|
+
break;
|
|
61864
|
+
default:
|
|
61865
|
+
throw new Error("Implement me. Unknown stream file type!");
|
|
61866
|
+
}
|
|
61867
|
+
stream2.fd = fd2;
|
|
61868
|
+
stream2._isStdio = true;
|
|
61869
|
+
return stream2;
|
|
61870
|
+
}
|
|
61871
|
+
function init(debug) {
|
|
61872
|
+
debug.inspectOpts = {};
|
|
61873
|
+
var keys = Object.keys(exports2.inspectOpts);
|
|
61874
|
+
for (var i = 0; i < keys.length; i++) {
|
|
61875
|
+
debug.inspectOpts[keys[i]] = exports2.inspectOpts[keys[i]];
|
|
61876
|
+
}
|
|
61877
|
+
}
|
|
61878
|
+
exports2.enable(load());
|
|
61879
|
+
}
|
|
61880
|
+
});
|
|
61881
|
+
|
|
61882
|
+
// ../../node_modules/debug/src/index.js
|
|
61883
|
+
var require_src = __commonJS({
|
|
61884
|
+
"../../node_modules/debug/src/index.js"(exports2, module2) {
|
|
61885
|
+
if (typeof process !== "undefined" && process.type === "renderer") {
|
|
61886
|
+
module2.exports = require_browser();
|
|
61887
|
+
} else {
|
|
61888
|
+
module2.exports = require_node2();
|
|
61889
|
+
}
|
|
61890
|
+
}
|
|
61891
|
+
});
|
|
61892
|
+
|
|
61893
|
+
// node_modules/follow-redirects/debug.js
|
|
61894
|
+
var require_debug3 = __commonJS({
|
|
61469
61895
|
"node_modules/follow-redirects/debug.js"(exports2, module2) {
|
|
61470
61896
|
var debug;
|
|
61471
61897
|
module2.exports = function() {
|
|
61472
61898
|
if (!debug) {
|
|
61473
61899
|
try {
|
|
61474
|
-
debug =
|
|
61900
|
+
debug = require_src()("follow-redirects");
|
|
61475
61901
|
} catch (error) {
|
|
61476
61902
|
}
|
|
61477
61903
|
if (typeof debug !== "function") {
|
|
@@ -61493,7 +61919,7 @@ var require_follow_redirects = __commonJS({
|
|
|
61493
61919
|
var https = require("https");
|
|
61494
61920
|
var Writable = require("stream").Writable;
|
|
61495
61921
|
var assert = require("assert");
|
|
61496
|
-
var debug =
|
|
61922
|
+
var debug = require_debug3();
|
|
61497
61923
|
(function detectUnsupportedEnvironment() {
|
|
61498
61924
|
var looksLikeNode = typeof process !== "undefined";
|
|
61499
61925
|
var looksLikeBrowser = typeof window !== "undefined" && typeof document !== "undefined";
|
|
@@ -81783,7 +82209,7 @@ var require_password = __commonJS({
|
|
|
81783
82209
|
});
|
|
81784
82210
|
|
|
81785
82211
|
// node_modules/chardet/lib/fs/node.js
|
|
81786
|
-
var
|
|
82212
|
+
var require_node3 = __commonJS({
|
|
81787
82213
|
"node_modules/chardet/lib/fs/node.js"(exports2, module2) {
|
|
81788
82214
|
"use strict";
|
|
81789
82215
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
@@ -87285,7 +87711,7 @@ var require_lib6 = __commonJS({
|
|
|
87285
87711
|
};
|
|
87286
87712
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
87287
87713
|
exports2.detectFileSync = exports2.detectFile = exports2.analyse = exports2.detect = void 0;
|
|
87288
|
-
var node_1 = __importDefault(
|
|
87714
|
+
var node_1 = __importDefault(require_node3());
|
|
87289
87715
|
var ascii_1 = __importDefault(require_ascii());
|
|
87290
87716
|
var utf8_1 = __importDefault(require_utf8());
|
|
87291
87717
|
var unicode = __importStar(require_unicode());
|
|
@@ -91638,56 +92064,80 @@ var require_hook = __commonJS({
|
|
|
91638
92064
|
var HOOK_MARKER = "# CodeRifts pre-push hook";
|
|
91639
92065
|
var PRE_PUSH_SCRIPT = `#!/bin/sh
|
|
91640
92066
|
${HOOK_MARKER}
|
|
91641
|
-
# Checks API spec changes before pushing
|
|
92067
|
+
# Checks API spec changes before pushing.
|
|
92068
|
+
# The pre-push hook receives lines on stdin:
|
|
92069
|
+
# <local ref> <local sha> <remote ref> <remote sha>
|
|
91642
92070
|
|
|
91643
92071
|
CODERIFTS_API_KEY=$(git config coderifts.apiKey)
|
|
91644
92072
|
SPEC_PATH=$(git config coderifts.specPath || echo "api/openapi.yaml")
|
|
92073
|
+
ZERO="0000000000000000000000000000000000000000"
|
|
91645
92074
|
|
|
91646
92075
|
if [ -z "$CODERIFTS_API_KEY" ]; then
|
|
91647
92076
|
echo "CodeRifts: No API key configured. Run: git config coderifts.apiKey <your-key>"
|
|
91648
92077
|
exit 0 # Don't block if not configured
|
|
91649
92078
|
fi
|
|
91650
92079
|
|
|
91651
|
-
#
|
|
91652
|
-
|
|
91653
|
-
|
|
91654
|
-
|
|
91655
|
-
|
|
91656
|
-
|
|
91657
|
-
|
|
91658
|
-
|
|
91659
|
-
|
|
91660
|
-
|
|
91661
|
-
|
|
91662
|
-
|
|
91663
|
-
|
|
91664
|
-
|
|
91665
|
-
|
|
91666
|
-
|
|
91667
|
-
|
|
91668
|
-
|
|
91669
|
-
|
|
91670
|
-
|
|
91671
|
-
|
|
91672
|
-
|
|
91673
|
-
|
|
91674
|
-
|
|
91675
|
-
|
|
91676
|
-
|
|
91677
|
-
|
|
91678
|
-
|
|
91679
|
-
|
|
91680
|
-
|
|
91681
|
-
|
|
91682
|
-
|
|
91683
|
-
echo ""
|
|
91684
|
-
|
|
91685
|
-
|
|
91686
|
-
|
|
91687
|
-
|
|
91688
|
-
|
|
91689
|
-
|
|
91690
|
-
|
|
92080
|
+
# Read stdin lines provided by git pre-push
|
|
92081
|
+
while read LOCAL_REF LOCAL_SHA REMOTE_REF REMOTE_SHA; do
|
|
92082
|
+
# Skip delete pushes
|
|
92083
|
+
if [ "$LOCAL_SHA" = "$ZERO" ]; then
|
|
92084
|
+
continue
|
|
92085
|
+
fi
|
|
92086
|
+
|
|
92087
|
+
# Get the spec at the local (about-to-be-pushed) commit
|
|
92088
|
+
HEAD_SPEC=$(git show "$LOCAL_SHA:$SPEC_PATH" 2>/dev/null)
|
|
92089
|
+
if [ -z "$HEAD_SPEC" ]; then
|
|
92090
|
+
continue # Spec doesn't exist in local commit, skip
|
|
92091
|
+
fi
|
|
92092
|
+
|
|
92093
|
+
# Get the spec at the remote (already-pushed) commit
|
|
92094
|
+
if [ "$REMOTE_SHA" = "$ZERO" ]; then
|
|
92095
|
+
# New branch \u2014 no remote baseline, use empty spec
|
|
92096
|
+
BASE_SPEC=""
|
|
92097
|
+
else
|
|
92098
|
+
BASE_SPEC=$(git show "$REMOTE_SHA:$SPEC_PATH" 2>/dev/null || echo "")
|
|
92099
|
+
fi
|
|
92100
|
+
|
|
92101
|
+
# If base is empty (new spec or new branch), allow
|
|
92102
|
+
if [ -z "$BASE_SPEC" ]; then
|
|
92103
|
+
echo "CodeRifts: New spec detected, allowing push."
|
|
92104
|
+
continue
|
|
92105
|
+
fi
|
|
92106
|
+
|
|
92107
|
+
# If specs are identical, nothing to check
|
|
92108
|
+
if [ "$BASE_SPEC" = "$HEAD_SPEC" ]; then
|
|
92109
|
+
continue
|
|
92110
|
+
fi
|
|
92111
|
+
|
|
92112
|
+
echo "CodeRifts: Checking API spec changes..."
|
|
92113
|
+
|
|
92114
|
+
RESULT=$(curl -s -X POST https://app.coderifts.com/api/v1/diff \\
|
|
92115
|
+
-H "Authorization: Bearer $CODERIFTS_API_KEY" \\
|
|
92116
|
+
-H "Content-Type: application/json" \\
|
|
92117
|
+
-d "{\\"before\\": $(echo "$BASE_SPEC" | python3 -c 'import sys,json; print(json.dumps(sys.stdin.read()))'), \\"after\\": $(echo "$HEAD_SPEC" | python3 -c 'import sys,json; print(json.dumps(sys.stdin.read()))')}")
|
|
92118
|
+
|
|
92119
|
+
DECISION=$(echo $RESULT | python3 -c "import sys,json; print(json.load(sys.stdin).get('omega_decision','ALLOW'))" 2>/dev/null)
|
|
92120
|
+
OMEGA=$(echo $RESULT | python3 -c "import sys,json; print(json.load(sys.stdin).get('omega_api',0))" 2>/dev/null)
|
|
92121
|
+
BREAKING=$(echo $RESULT | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d.get('breaking_changes',[])))" 2>/dev/null)
|
|
92122
|
+
|
|
92123
|
+
if [ "$DECISION" = "BLOCK" ]; then
|
|
92124
|
+
echo ""
|
|
92125
|
+
echo "========================================"
|
|
92126
|
+
echo " CodeRifts: PUSH BLOCKED"
|
|
92127
|
+
echo "========================================"
|
|
92128
|
+
echo " Risk score: $OMEGA/100"
|
|
92129
|
+
echo " Breaking changes: $BREAKING"
|
|
92130
|
+
echo " Decision: BLOCK"
|
|
92131
|
+
echo "========================================"
|
|
92132
|
+
echo ""
|
|
92133
|
+
echo "Fix breaking changes or use --no-verify to bypass."
|
|
92134
|
+
exit 1
|
|
92135
|
+
fi
|
|
92136
|
+
|
|
92137
|
+
if [ "$DECISION" = "REQUIRE_APPROVAL" ] || [ "$DECISION" = "WARN" ]; then
|
|
92138
|
+
echo "CodeRifts: WARNING \u2014 $DECISION \u2014 Risk: $OMEGA/100, Breaking: $BREAKING"
|
|
92139
|
+
fi
|
|
92140
|
+
done
|
|
91691
92141
|
|
|
91692
92142
|
exit 0
|
|
91693
92143
|
`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coderifts",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "Detect breaking API changes from the command line. Works locally or with the CodeRifts cloud API.",
|
|
5
5
|
"author": "CodeRifts <hello@coderifts.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
"main": "dist/cli.js",
|
|
11
11
|
"files": [
|
|
12
12
|
"dist/",
|
|
13
|
+
"bin/",
|
|
14
|
+
"scripts/",
|
|
13
15
|
"README.md"
|
|
14
16
|
],
|
|
15
17
|
"keywords": [
|
|
@@ -53,6 +55,6 @@
|
|
|
53
55
|
"json-schema-ref-parser": "npm:@apidevtools/json-schema-ref-parser@^11.7.3"
|
|
54
56
|
},
|
|
55
57
|
"devDependencies": {
|
|
56
|
-
"esbuild": "^0.27.
|
|
58
|
+
"esbuild": "^0.27.4"
|
|
57
59
|
}
|
|
58
60
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Postinstall patch: z-schema v8+ exports { default: ZSchema } instead of ZSchema directly.
|
|
4
|
+
* This patches @apidevtools/swagger-parser to handle both export styles.
|
|
5
|
+
*/
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
|
|
9
|
+
try {
|
|
10
|
+
const schemaPath = require.resolve('@apidevtools/swagger-parser/lib/validators/schema.js');
|
|
11
|
+
let content = fs.readFileSync(schemaPath, 'utf8');
|
|
12
|
+
|
|
13
|
+
let patched = false;
|
|
14
|
+
if (!content.includes('_ZSchema')) {
|
|
15
|
+
content = content.replace(
|
|
16
|
+
'const ZSchema = require("z-schema");',
|
|
17
|
+
'const _ZSchema = require("z-schema"); const ZSchema = _ZSchema.default || _ZSchema;'
|
|
18
|
+
);
|
|
19
|
+
patched = true;
|
|
20
|
+
}
|
|
21
|
+
// z-schema v10+ requires ZSchema.create() instead of new ZSchema()
|
|
22
|
+
if (content.includes('new ZSchema(') && !content.includes('ZSchema.create')) {
|
|
23
|
+
content = content.replace(
|
|
24
|
+
/return new ZSchema\(/g,
|
|
25
|
+
'return (typeof ZSchema.create === "function" ? ZSchema.create : (opts) => new ZSchema(opts))('
|
|
26
|
+
);
|
|
27
|
+
patched = true;
|
|
28
|
+
}
|
|
29
|
+
if (patched) {
|
|
30
|
+
fs.writeFileSync(schemaPath, content);
|
|
31
|
+
console.log('postinstall: patched z-schema import/constructor in swagger-parser');
|
|
32
|
+
}
|
|
33
|
+
} catch (err) {
|
|
34
|
+
console.log('postinstall: skipping z-schema patch:', err.message);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Patch 2: json-schema-ref-parser v11+ exports { default: $RefParser } instead of $RefParser directly
|
|
38
|
+
// json-schema-diff uses `new RefParser()` which breaks with the new export style
|
|
39
|
+
try {
|
|
40
|
+
const derefPath = require.resolve('json-schema-diff/dist/json-schema-diff/diff-schemas/dereference-schema.js');
|
|
41
|
+
let content2 = fs.readFileSync(derefPath, 'utf8');
|
|
42
|
+
|
|
43
|
+
if (!content2.includes('_RefParser')) {
|
|
44
|
+
content2 = content2.replace(
|
|
45
|
+
'const RefParser = require("json-schema-ref-parser");',
|
|
46
|
+
'const _RefParser = require("json-schema-ref-parser"); const RefParser = _RefParser.default || _RefParser;'
|
|
47
|
+
);
|
|
48
|
+
fs.writeFileSync(derefPath, content2);
|
|
49
|
+
console.log('postinstall: patched json-schema-ref-parser import in json-schema-diff');
|
|
50
|
+
}
|
|
51
|
+
} catch (err) {
|
|
52
|
+
console.log('postinstall: skipping ref-parser patch:', err.message);
|
|
53
|
+
}
|