thumbgate 1.4.0 → 1.4.1
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/.claude-plugin/README.md +25 -0
- package/.claude-plugin/marketplace.json +1 -1
- package/README.md +195 -168
- package/adapters/chatgpt/INSTALL.md +59 -4
- package/bin/cli.js +4 -0
- package/config/github-about.json +1 -1
- package/package.json +9 -5
- package/public/index.html +44 -23
- package/scripts/auto-promote-gates.js +5 -3
- package/scripts/billing-setup.js +109 -0
- package/scripts/build-claude-mcpb.js +71 -5
- package/scripts/distribution-surfaces.js +28 -0
- package/scripts/feedback-to-rules.js +27 -8
- package/scripts/gates-engine.js +51 -7
- package/scripts/hosted-config.js +2 -0
- package/scripts/hybrid-feedback-context.js +26 -16
- package/scripts/operational-summary.js +41 -5
- package/scripts/ralph-loop.js +376 -0
- package/scripts/ralph-mode-ci.js +331 -0
- package/scripts/rotate-stripe-webhook-secret.js +314 -0
- package/src/api/server.js +23 -3
- package/scripts/__pycache__/train_from_feedback.cpython-312.pyc +0 -0
package/src/api/server.js
CHANGED
|
@@ -1020,6 +1020,7 @@ function loadPublicMarketingTemplateHtml(templatePath, runtimeConfig, pageContex
|
|
|
1020
1020
|
'__AUTOMATION_REPORT_URL__': 'https://github.com/IgorGanapolsky/ThumbGate/blob/main/proof/automation/report.json',
|
|
1021
1021
|
'__GTM_PLAN_URL__': 'https://github.com/IgorGanapolsky/ThumbGate/blob/main/docs/GO_TO_MARKET_REVENUE_WEDGE_2026-03.md',
|
|
1022
1022
|
'__GITHUB_URL__': 'https://github.com/IgorGanapolsky/ThumbGate',
|
|
1023
|
+
'__POSTHOG_API_KEY__': runtimeConfig.posthogApiKey || '',
|
|
1023
1024
|
});
|
|
1024
1025
|
}
|
|
1025
1026
|
|
|
@@ -2153,6 +2154,11 @@ function getExpectedApiKey() {
|
|
|
2153
2154
|
return configured;
|
|
2154
2155
|
}
|
|
2155
2156
|
|
|
2157
|
+
function getExpectedOperatorKey() {
|
|
2158
|
+
const key = String(process.env.THUMBGATE_OPERATOR_KEY || '').trim();
|
|
2159
|
+
return key || null;
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2156
2162
|
function isAuthorized(req, expected) {
|
|
2157
2163
|
if (!expected) return true;
|
|
2158
2164
|
const token = extractApiKey(req);
|
|
@@ -2204,6 +2210,19 @@ function isStaticAdminAuthorized(req, expected) {
|
|
|
2204
2210
|
return extractApiKey(req) === expected;
|
|
2205
2211
|
}
|
|
2206
2212
|
|
|
2213
|
+
/**
|
|
2214
|
+
* Billing summary guard: accepts either the static admin key OR the operator key.
|
|
2215
|
+
* The operator key (THUMBGATE_OPERATOR_KEY) allows read-only billing data access
|
|
2216
|
+
* without exposing the full admin key to CLI clients.
|
|
2217
|
+
*/
|
|
2218
|
+
function isBillingSummaryAuthorized(req, expectedAdminKey, expectedOperatorKey) {
|
|
2219
|
+
if (!expectedAdminKey && !expectedOperatorKey) return true;
|
|
2220
|
+
const token = extractApiKey(req);
|
|
2221
|
+
if (expectedAdminKey && token === expectedAdminKey) return true;
|
|
2222
|
+
if (expectedOperatorKey && token === expectedOperatorKey) return true;
|
|
2223
|
+
return false;
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2207
2226
|
function extractTags(input) {
|
|
2208
2227
|
if (Array.isArray(input)) return input;
|
|
2209
2228
|
if (typeof input === 'string') {
|
|
@@ -2318,6 +2337,7 @@ function resolveDocumentImportFilePath(inputPath, options = {}) {
|
|
|
2318
2337
|
|
|
2319
2338
|
function createApiServer() {
|
|
2320
2339
|
const expectedApiKey = getExpectedApiKey();
|
|
2340
|
+
const expectedOperatorKey = getExpectedOperatorKey();
|
|
2321
2341
|
|
|
2322
2342
|
return http.createServer(async (req, res) => {
|
|
2323
2343
|
const parsed = new URL(req.url, 'http://localhost');
|
|
@@ -4540,14 +4560,14 @@ async function addContext(){
|
|
|
4540
4560
|
return;
|
|
4541
4561
|
}
|
|
4542
4562
|
|
|
4543
|
-
// GET /v1/billing/summary — admin
|
|
4563
|
+
// GET /v1/billing/summary — operator billing summary (admin key or operator key)
|
|
4544
4564
|
if (req.method === 'GET' && pathname === '/v1/billing/summary') {
|
|
4545
|
-
if (!
|
|
4565
|
+
if (!isBillingSummaryAuthorized(req, expectedApiKey, expectedOperatorKey)) {
|
|
4546
4566
|
sendProblem(res, {
|
|
4547
4567
|
type: PROBLEM_TYPES.FORBIDDEN,
|
|
4548
4568
|
title: 'Forbidden',
|
|
4549
4569
|
status: 403,
|
|
4550
|
-
detail: 'Admin API key required for this endpoint.',
|
|
4570
|
+
detail: 'Admin or operator API key required for this endpoint.',
|
|
4551
4571
|
});
|
|
4552
4572
|
return;
|
|
4553
4573
|
}
|
|
Binary file
|