content-grade 1.0.26 → 1.0.28
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/content-grade.js
CHANGED
|
@@ -91,7 +91,7 @@ function incrementUsage() {
|
|
|
91
91
|
|
|
92
92
|
// Upgrade links — Free → Pro → Business → Team
|
|
93
93
|
const UPGRADE_LINKS = {
|
|
94
|
-
free: 'https://
|
|
94
|
+
free: 'https://content-grade.github.io/Content-Grade/#pricing', // Pro $9/mo — pricing page first
|
|
95
95
|
pro: 'https://buy.stripe.com/bJefZjafO2Tz36Z2W48k80b', // Business $29/mo
|
|
96
96
|
business: 'https://buy.stripe.com/cNiaEZfA8cu9bDv4088k80c', // Team $79/mo
|
|
97
97
|
};
|
package/bin/telemetry.js
CHANGED
|
@@ -58,18 +58,32 @@ export function isOptedOut() {
|
|
|
58
58
|
return cfg?.telemetryEnabled === false;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Return run count bucket label from total lifetime runs.
|
|
63
|
+
* Buckets: 1-5, 6-20, 21-50, 50+
|
|
64
|
+
*/
|
|
65
|
+
export function getRunCountBucket(totalRuns) {
|
|
66
|
+
if (totalRuns <= 5) return '1-5';
|
|
67
|
+
if (totalRuns <= 20) return '6-20';
|
|
68
|
+
if (totalRuns <= 50) return '21-50';
|
|
69
|
+
return '50+';
|
|
70
|
+
}
|
|
71
|
+
|
|
61
72
|
/**
|
|
62
73
|
* Initialise telemetry on CLI startup.
|
|
63
|
-
*
|
|
74
|
+
* Increments total run count and returns { installId, totalRuns, runCountBucket, isNew, optedOut }.
|
|
64
75
|
* isNew=true means this is the first time the CLI has run — show the notice.
|
|
65
76
|
*/
|
|
66
77
|
export function initTelemetry() {
|
|
67
|
-
if (isOptedOut()) return { installId: null, isNew: false, optedOut: true };
|
|
78
|
+
if (isOptedOut()) return { installId: null, totalRuns: 0, runCountBucket: '1-5', isNew: false, optedOut: true };
|
|
68
79
|
|
|
69
80
|
const cfg = loadConfig();
|
|
70
81
|
|
|
71
82
|
if (cfg?.installId) {
|
|
72
|
-
|
|
83
|
+
// Increment lifetime run counter
|
|
84
|
+
const totalRuns = (cfg.totalRuns ?? 0) + 1;
|
|
85
|
+
saveConfig({ ...cfg, totalRuns });
|
|
86
|
+
return { installId: cfg.installId, totalRuns, runCountBucket: getRunCountBucket(totalRuns), isNew: false, optedOut: false };
|
|
73
87
|
}
|
|
74
88
|
|
|
75
89
|
// First run — generate anonymous install ID, enabled by default (opt-out available)
|
|
@@ -79,9 +93,10 @@ export function initTelemetry() {
|
|
|
79
93
|
installId,
|
|
80
94
|
installedAt: new Date().toISOString(),
|
|
81
95
|
telemetryEnabled: true,
|
|
96
|
+
totalRuns: 1,
|
|
82
97
|
});
|
|
83
98
|
|
|
84
|
-
return { installId, isNew: true, optedOut: false };
|
|
99
|
+
return { installId, totalRuns: 1, runCountBucket: '1-5', isNew: true, optedOut: false };
|
|
85
100
|
}
|
|
86
101
|
|
|
87
102
|
/**
|
|
@@ -105,10 +120,12 @@ export function recordEvent(data) {
|
|
|
105
120
|
const installId = cfg?.installId;
|
|
106
121
|
if (!installId) return; // shouldn't happen after initTelemetry, but guard
|
|
107
122
|
|
|
123
|
+
const totalRuns = cfg?.totalRuns ?? 1;
|
|
108
124
|
const event = {
|
|
109
125
|
...data,
|
|
110
126
|
package: 'content-grade',
|
|
111
127
|
installId,
|
|
128
|
+
run_count_bucket: data.run_count_bucket ?? getRunCountBucket(totalRuns),
|
|
112
129
|
timestamp: new Date().toISOString(),
|
|
113
130
|
};
|
|
114
131
|
|
package/dist/landing.html
CHANGED
|
@@ -1447,7 +1447,7 @@
|
|
|
1447
1447
|
<script>
|
|
1448
1448
|
document.addEventListener('DOMContentLoaded', function() {
|
|
1449
1449
|
// Track pricing CTA clicks
|
|
1450
|
-
document.querySelectorAll('a.plan-cta
|
|
1450
|
+
document.querySelectorAll('a.plan-cta').forEach(function(el) {
|
|
1451
1451
|
el.addEventListener('click', function() {
|
|
1452
1452
|
if (window.goatcounter && window.goatcounter.count) {
|
|
1453
1453
|
var tier = el.href.includes('business') ? 'business' : el.href.includes('team') ? 'team' : 'pro';
|
package/dist-server/server/db.js
CHANGED
|
@@ -43,9 +43,9 @@ export function registerAnalyticsRoutes(app) {
|
|
|
43
43
|
const db = getDb();
|
|
44
44
|
db.prepare(`
|
|
45
45
|
INSERT INTO cli_telemetry
|
|
46
|
-
(install_id, event, command, is_pro, duration_ms, success, exit_code, score, content_type, version, platform, node_version)
|
|
47
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
48
|
-
`).run(String(body.install_id).slice(0, 64), String(body.event ?? 'unknown').slice(0, 64), body.command ? String(body.command).slice(0, 64) : null, typeof body.is_pro === 'boolean' ? (body.is_pro ? 1 : 0) : null, typeof body.duration_ms === 'number' ? Math.round(body.duration_ms) : null, typeof body.success === 'boolean' ? (body.success ? 1 : 0) : null, typeof body.exit_code === 'number' ? body.exit_code : null, typeof body.score === 'number' ? body.score : null, body.content_type ? String(body.content_type).slice(0, 64) : null, body.version ? String(body.version).slice(0, 32) : null, body.platform ? String(body.platform).slice(0, 32) : null, body.nodeVersion ? String(body.nodeVersion).slice(0, 32) : null);
|
|
46
|
+
(install_id, event, command, is_pro, duration_ms, success, exit_code, score, content_type, version, platform, node_version, run_count_bucket)
|
|
47
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
48
|
+
`).run(String(body.install_id).slice(0, 64), String(body.event ?? 'unknown').slice(0, 64), body.command ? String(body.command).slice(0, 64) : null, typeof body.is_pro === 'boolean' ? (body.is_pro ? 1 : 0) : null, typeof body.duration_ms === 'number' ? Math.round(body.duration_ms) : null, typeof body.success === 'boolean' ? (body.success ? 1 : 0) : null, typeof body.exit_code === 'number' ? body.exit_code : null, typeof body.score === 'number' ? body.score : null, body.content_type ? String(body.content_type).slice(0, 64) : null, body.version ? String(body.version).slice(0, 32) : null, body.platform ? String(body.platform).slice(0, 32) : null, body.nodeVersion ? String(body.nodeVersion).slice(0, 32) : null, body.run_count_bucket ? String(body.run_count_bucket).slice(0, 10) : null);
|
|
49
49
|
}
|
|
50
50
|
catch {
|
|
51
51
|
// never fail — telemetry is non-critical
|
|
@@ -23,7 +23,7 @@ function freeGateMsg(_what) {
|
|
|
23
23
|
return `Free daily limit reached (${FREE_TIER_LIMIT}/day). Upgrade to Pro for unlimited: ${UPGRADE_URL}`;
|
|
24
24
|
}
|
|
25
25
|
function paidGateMsg(limit) {
|
|
26
|
-
return `Daily limit reached (${limit}/day). Upgrade for more at content-grade.
|
|
26
|
+
return `Daily limit reached (${limit}/day). Upgrade for more at content-grade.github.io/Content-Grade/#pricing. Resets at midnight UTC.`;
|
|
27
27
|
}
|
|
28
28
|
function hashIp(ip) {
|
|
29
29
|
return createHash('sha256').update(ip).digest('hex');
|
package/package.json
CHANGED