fest-gateway 0.5.2 → 0.7.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/README.md +26 -1
- package/dist/cli/claude.js +10 -4
- package/dist/cli/claude.js.map +1 -1
- package/dist/cli/codex.js +8 -4
- package/dist/cli/codex.js.map +1 -1
- package/dist/cli/copilot.js +11 -5
- package/dist/cli/copilot.js.map +1 -1
- package/dist/cli/tags.js +258 -0
- package/dist/cli/tags.js.map +1 -0
- package/dist/server/api/auth.js +6 -5
- package/dist/server/api/auth.js.map +1 -1
- package/dist/server/api/live.js +1 -0
- package/dist/server/api/live.js.map +1 -1
- package/dist/server/api/routes.js +23 -2
- package/dist/server/api/routes.js.map +1 -1
- package/dist/server/auth/posture.js +39 -10
- package/dist/server/auth/posture.js.map +1 -1
- package/dist/server/bin/fest.js +171 -39
- package/dist/server/bin/fest.js.map +1 -1
- package/dist/server/cluster/messages.js +35 -0
- package/dist/server/cluster/messages.js.map +1 -0
- package/dist/server/cluster/primary.js +178 -0
- package/dist/server/cluster/primary.js.map +1 -0
- package/dist/server/cluster/worker.js +82 -0
- package/dist/server/cluster/worker.js.map +1 -0
- package/dist/server/config.js +15 -0
- package/dist/server/config.js.map +1 -1
- package/dist/server/http/server.js +4 -1
- package/dist/server/http/server.js.map +1 -1
- package/dist/server/ingest/sink.js +9 -7
- package/dist/server/ingest/sink.js.map +1 -1
- package/dist/server/log.js +4 -1
- package/dist/server/log.js.map +1 -1
- package/dist/server/pipeline/dispatch.js +1 -0
- package/dist/server/pipeline/dispatch.js.map +1 -1
- package/dist/server/pipeline/passthrough.js +1 -0
- package/dist/server/pipeline/passthrough.js.map +1 -1
- package/dist/server/pipeline/record.js +1 -0
- package/dist/server/pipeline/record.js.map +1 -1
- package/dist/server/store/db.js +42 -4
- package/dist/server/store/db.js.map +1 -1
- package/dist/server/store/migrations/007-tags.sql +94 -0
- package/dist/server/store/queries.js +112 -6
- package/dist/server/store/queries.js.map +1 -1
- package/dist/server/store/seed.js +17 -0
- package/dist/server/store/seed.js.map +1 -1
- package/dist/server/store/write.js +10 -3
- package/dist/server/store/write.js.map +1 -1
- package/dist/server/usage/prices/refresh.js +9 -3
- package/dist/server/usage/prices/refresh.js.map +1 -1
- package/dist/shared/tags.js +155 -0
- package/dist/shared/tags.js.map +1 -0
- package/dist/web/dist/assets/index-AJc39GYv.js +56 -0
- package/dist/web/dist/assets/index-AJc39GYv.js.map +1 -0
- package/dist/web/dist/assets/index-BgK6vcz0.css +2 -0
- package/dist/web/dist/index.html +2 -2
- package/package.json +3 -3
- package/dist/web/dist/assets/index-C7n3_lX2.css +0 -2
- package/dist/web/dist/assets/index-DJb4NfM5.js +0 -56
- package/dist/web/dist/assets/index-DJb4NfM5.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../server/api/auth.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAChF,OAAO,EACL,aAAa,EACb,aAAa,EACb,eAAe,EACf,aAAa,EACb,WAAW,GACZ,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAGhC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,MAAM,cAAc,GAAG,CAAC,GAAG,IAAI,CAAC;AAShC,SAAS,IAAI,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAa,EAAE,QAAgC,EAAE;IAClG,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,eAAe,EAAE,UAAU,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;IACrG,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../server/api/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/server/api/live.js
CHANGED
|
@@ -54,6 +54,7 @@ export function toLiveRow(rec) {
|
|
|
54
54
|
rlClaim: rec.rateLimit?.representativeClaim ?? null,
|
|
55
55
|
clientVersion: rec.clientVersion,
|
|
56
56
|
client: rec.client ?? null,
|
|
57
|
+
tags: rec.tags ?? {},
|
|
57
58
|
pipeline: rec.pipeline,
|
|
58
59
|
routeId: rec.routeId,
|
|
59
60
|
credentialsConsidered: rec.credentialsConsidered,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live.js","sourceRoot":"","sources":["../../../server/api/live.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"live.js","sourceRoot":"","sources":["../../../server/api/live.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
* result arrives as `scope`. Every query takes that scope explicitly, so there
|
|
12
12
|
* is no ambient "current org" a handler could forget to apply.
|
|
13
13
|
*/
|
|
14
|
-
import { listRequests, usageTotals, usageByUser, usageByModel, usageByCredentialOrigin, usageByClient, usageSeries, errorBreakdown, latencySummary, latestQuotaByUser, } from "../store/queries.js";
|
|
14
|
+
import { listRequests, usageTotals, usageByUser, usageByModel, usageByCredentialOrigin, usageByClient, usageSeries, errorBreakdown, latencySummary, latestQuotaByUser, usageByTag, tagValues, } from "../store/queries.js";
|
|
15
|
+
import { isValidTagKey, parseTagFilter } from "../../shared/tags.js";
|
|
15
16
|
import { explainRoutes } from "./routing-view.js";
|
|
16
17
|
import { ADAPTER_TRANSFORMS } from "../adapters/registry.js";
|
|
17
18
|
import { handleLive } from "./live.js";
|
|
@@ -34,7 +35,15 @@ export function parseRange(params, now = Date.now()) {
|
|
|
34
35
|
const toMs = intParam(params, "to") ?? now;
|
|
35
36
|
const fromRaw = intParam(params, "from") ?? toMs - DEFAULT_RANGE_MS;
|
|
36
37
|
const fromMs = Math.max(fromRaw, toMs - MAX_RANGE_MS);
|
|
37
|
-
|
|
38
|
+
const tags = parseTagFilter(params.getAll("tag"));
|
|
39
|
+
return {
|
|
40
|
+
fromMs: Math.min(fromMs, toMs),
|
|
41
|
+
toMs,
|
|
42
|
+
// Only present when filtering, so an unfiltered range is exactly what it
|
|
43
|
+
// was before tags existed. Invalid `tag=` values are dropped by the parser,
|
|
44
|
+
// never bound as-is.
|
|
45
|
+
...(Object.keys(tags).length > 0 ? { tags } : {}),
|
|
46
|
+
};
|
|
38
47
|
}
|
|
39
48
|
function strParam(params, name) {
|
|
40
49
|
const raw = params.get(name);
|
|
@@ -92,10 +101,22 @@ export function handleApi(req, res, path, deps) {
|
|
|
92
101
|
...(params.get("errorsOnly") === "1" ? { errorsOnly: true } : {}),
|
|
93
102
|
...(intParam(params, "before") !== undefined ? { beforeSeq: intParam(params, "before") } : {}),
|
|
94
103
|
...(intParam(params, "limit") !== undefined ? { limit: intParam(params, "limit") } : {}),
|
|
104
|
+
...(range.tags !== undefined ? { tags: range.tags } : {}),
|
|
95
105
|
};
|
|
96
106
|
json(res, 200, listRequests(deps.store, scope, filter));
|
|
97
107
|
return true;
|
|
98
108
|
}
|
|
109
|
+
case "/api/tags": {
|
|
110
|
+
const by = strParam(params, "by")?.trim().toLowerCase();
|
|
111
|
+
const key = by !== undefined && isValidTagKey(by) ? by : null;
|
|
112
|
+
json(res, 200, {
|
|
113
|
+
range,
|
|
114
|
+
keys: tagValues(deps.store, scope, range),
|
|
115
|
+
by: key,
|
|
116
|
+
rows: key === null ? [] : usageByTag(deps.store, scope, range, key),
|
|
117
|
+
});
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
99
120
|
case "/api/users":
|
|
100
121
|
json(res, 200, { range, rows: usageByUser(deps.store, scope, range) });
|
|
101
122
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../server/api/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,EACL,YAAY,EACZ,WAAW,EACX,WAAW,EACX,YAAY,EACZ,uBAAuB,EACvB,aAAa,EACb,WAAW,EACX,cAAc,EACd,cAAc,EACd,iBAAiB,
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../server/api/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,EACL,YAAY,EACZ,WAAW,EACX,WAAW,EACX,YAAY,EACZ,uBAAuB,EACvB,aAAa,EACb,WAAW,EACX,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,SAAS,GACV,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAIrE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAa9C,MAAM,gBAAgB,GAAG,EAAE,GAAG,SAAS,CAAC;AACxC,MAAM,YAAY,GAAG,GAAG,GAAG,UAAU,CAAC;AAEtC,SAAS,QAAQ,CAAC,MAAuB,EAAE,IAAY;IACrD,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IACxD,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACtB,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACxD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,MAAuB,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAClE,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,GAAG,CAAC;IAC3C,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,IAAI,GAAG,gBAAgB,CAAC;IACpE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,GAAG,YAAY,CAAC,CAAC;IACtD,MAAM,IAAI,GAAG,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAClD,OAAO;QACL,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC;QAC9B,IAAI;QACJ,yEAAyE;QACzE,4EAA4E;QAC5E,qBAAqB;QACrB,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAClD,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,MAAuB,EAAE,IAAY;IACrD,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC7B,OAAO,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC;AAC7D,CAAC;AAgBD,SAAS,IAAI,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAa;IAC9D,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACrC,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE;QACpB,cAAc,EAAE,kBAAkB;QAClC,eAAe,EAAE,UAAU;KAC5B,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CACvB,GAAoB,EACpB,GAAmB,EACnB,IAAY,EACZ,IAAa;IAEb,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,KAAK,CAAC,KAAK,KAAK,EAAE,CAAC;QACpC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC,CAAC;QAChD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,mBAAmB,CAAC,CAAC;IACzD,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,CAAC;IAChC,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IAEzB,0EAA0E;IAC1E,yBAAyB;IACzB,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;QACzB,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,eAAe;YAClB,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE;gBACb,KAAK;gBACL,MAAM,EAAE,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;gBAC7C,MAAM,EAAE,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;gBAC7C,kBAAkB,EAAE,uBAAuB,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;gBACrE,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;gBACjD,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;gBACjD,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;aACG,CAAC,CAAC;YAC9B,OAAO,IAAI,CAAC;QAEd,KAAK,eAAe,CAAC,CAAC,CAAC;YACrB,MAAM,MAAM,GAAG;gBACb,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC3F,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC9F,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC,KAAK,SAAS;oBACpD,CAAC,CAAC,EAAE,gBAAgB,EAAE,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAAE;oBAC5D,CAAC,CAAC,EAAE,CAAC;gBACP,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACjE,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC9F,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACxF,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC1D,CAAC;YACF,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAA4B,CAAC,CAAC;YACnF,OAAO,IAAI,CAAC;QACd,CAAC;QAED,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YACxD,MAAM,GAAG,GAAG,EAAE,KAAK,SAAS,IAAI,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YAC9D,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE;gBACb,KAAK;gBACL,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;gBACzC,EAAE,EAAE,GAAG;gBACP,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC;aAC7C,CAAC,CAAC;YAC1B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,KAAK,YAAY;YACf,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,EAA0B,CAAC,CAAC;YAC/F,OAAO,IAAI,CAAC;QAEd,KAAK,aAAa;YAChB,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,EAA2B,CAAC,CAAC;YACjG,OAAO,IAAI,CAAC;QAEd,KAAK,aAAa;YAChB,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE;gBACb,KAAK;gBACL,IAAI,EAAE,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;gBAC9C,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;aACzB,CAAC,CAAC;YAC5B,OAAO,IAAI,CAAC;QAEd,uEAAuE;QACvE,sEAAsE;QACtE,wEAAwE;QACxE,sCAAsC;QACtC,KAAK,cAAc;YACjB,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE;gBACb,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO;gBAC5B,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;gBACtC,SAAS,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBACzD,EAAE,EAAE,CAAC,CAAC,EAAE;oBACR,OAAO,EAAE,CAAC,CAAC,OAAO;oBAClB,OAAO,EAAE,CAAC,CAAC,OAAO;oBAClB,gBAAgB,EAAE,CAAC,CAAC,UAAU,CAAC,MAAM;oBACrC,iBAAiB,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,IAAI;oBAC9D,UAAU,EAAE,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE;iBAChD,CAAC,CAAC;gBACH,oEAAoE;gBACpE,oEAAoE;gBACpE,yCAAyC;gBACzC,MAAM,EAAE,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;oBAClF,EAAE,EAAE,KAAK,CAAC,EAAE;oBACZ,KAAK,EAAE,KAAK,CAAC,KAAK;oBAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;oBACxB,KAAK,EAAE,KAAK,CAAC,KAAK;oBAClB,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,OAAO;oBACP,SAAS;oBACT,OAAO;iBACR,CAAC,CAAC;aACsB,CAAC,CAAC;YAC7B,OAAO,IAAI,CAAC;QAEd,qEAAqE;QACrE,+DAA+D;QAC/D,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC5B,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;gBACnD,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,IAAI,GAAG;gBACX,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACxF,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC/F,CAAC;YACF,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,EAA0B,CAAC,CAAC;YAC3F,OAAO,IAAI,CAAC;QACd,CAAC;QAED,KAAK,YAAY;YACf,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,iBAAiB,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,EAA0B,CAAC,CAAC;YACvF,OAAO,IAAI,CAAC;QAEd;YACE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,qBAAqB,IAAI,EAAE,EAAE,CAAC,CAAC;YACvD,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC"}
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
* impersonate a developer on this gateway.
|
|
26
26
|
*/
|
|
27
27
|
import { classifyCredential, fingerprint } from "../secret/fingerprint.js";
|
|
28
|
+
import { parseTagPairs, parseTags, tagsFromPairs } from "../../shared/tags.js";
|
|
28
29
|
/**
|
|
29
30
|
* Header positions that may hold the *upstream* credential, in preference order.
|
|
30
31
|
*
|
|
@@ -35,8 +36,25 @@ import { classifyCredential, fingerprint } from "../secret/fingerprint.js";
|
|
|
35
36
|
const UPSTREAM_CREDENTIAL_HEADERS = ["authorization", "x-api-key"];
|
|
36
37
|
/** Path prefixes that carry an identity token. `/t/` is the short form. */
|
|
37
38
|
const IDENTITY_PATH_PREFIX = /^\/(?:t|fest)\/([^/?#]+)(\/[^?#]*)?(\?.*|#.*)?$/;
|
|
39
|
+
/** A leading `~…` tag segment, and whatever follows it. */
|
|
40
|
+
const TAG_SEGMENT = /^\/~([^/?#]*)(\/[^?#]*)?(\?.*|#.*)?$/;
|
|
38
41
|
/**
|
|
39
|
-
* Split a
|
|
42
|
+
* Split a `~team=platform,project=fest` tag segment off the front of a path.
|
|
43
|
+
*
|
|
44
|
+
* No upstream API path starts with `~`, so the segment cannot be mistaken for
|
|
45
|
+
* anything the client meant to send upstream; it is removed here so nothing
|
|
46
|
+
* downstream of this module ever sees it. See `shared/tags.ts`.
|
|
47
|
+
*/
|
|
48
|
+
function splitTagSegment(url) {
|
|
49
|
+
const match = TAG_SEGMENT.exec(url);
|
|
50
|
+
if (!match)
|
|
51
|
+
return { tagSegment: null, rest: url };
|
|
52
|
+
const path = match[2] ?? "/";
|
|
53
|
+
return { tagSegment: match[1] ?? "", rest: `${path === "" ? "/" : path}${match[3] ?? ""}` };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Split a leading `/t/<token>` or `/fest/<token>` segment off the request URL,
|
|
57
|
+
* then a `~…` tag segment after it (or first, when there is no token).
|
|
40
58
|
*
|
|
41
59
|
* The query string belongs to the remainder, because Claude Code sends
|
|
42
60
|
* `POST /v1/messages?beta=true` and dropping `?beta=true` changes the upstream
|
|
@@ -45,16 +63,17 @@ const IDENTITY_PATH_PREFIX = /^\/(?:t|fest)\/([^/?#]+)(\/[^?#]*)?(\?.*|#.*)?$/;
|
|
|
45
63
|
* (its first segment is not `t` or `fest`).
|
|
46
64
|
*/
|
|
47
65
|
export function parseIdentityPath(url) {
|
|
66
|
+
let token = null;
|
|
67
|
+
let rest = url;
|
|
48
68
|
const match = IDENTITY_PATH_PREFIX.exec(url);
|
|
49
|
-
if (
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
return { token, remainder: `${path === "" ? "/" : path}${suffix}` };
|
|
69
|
+
if (match && (match[1] ?? "").length > 0) {
|
|
70
|
+
token = match[1];
|
|
71
|
+
// `/t/<tok>` with nothing after it still has to address a path upstream.
|
|
72
|
+
const path = match[2] ?? "/";
|
|
73
|
+
rest = `${path === "" ? "/" : path}${match[3] ?? ""}`;
|
|
74
|
+
}
|
|
75
|
+
const { tagSegment, rest: remainder } = splitTagSegment(rest);
|
|
76
|
+
return { token, remainder, tags: tagSegment === null ? {} : parseTags(tagSegment) };
|
|
58
77
|
}
|
|
59
78
|
/** `Bearer xyz` -> `xyz`; anything else unchanged. */
|
|
60
79
|
function stripBearer(raw) {
|
|
@@ -140,6 +159,16 @@ export function detectInbound(url, headers) {
|
|
|
140
159
|
identity,
|
|
141
160
|
identityToken,
|
|
142
161
|
effectivePath: fromPath.remainder,
|
|
162
|
+
tags: tagsOf(fromPath.tags, headerValue(headers, "x-fest-tags")),
|
|
143
163
|
};
|
|
144
164
|
}
|
|
165
|
+
/**
|
|
166
|
+
* Header tags first, path tags over them: the path is the form the fest CLI
|
|
167
|
+
* hands out, so as with the token it is the deliberate one.
|
|
168
|
+
*/
|
|
169
|
+
function tagsOf(fromPath, header) {
|
|
170
|
+
const headerPairs = header === null ? [] : parseTagPairs(header).filter((p) => p.value !== "");
|
|
171
|
+
const pathPairs = Object.entries(fromPath).map(([key, value]) => ({ key, value }));
|
|
172
|
+
return tagsFromPairs([...headerPairs, ...pathPairs]);
|
|
173
|
+
}
|
|
145
174
|
//# sourceMappingURL=posture.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"posture.js","sourceRoot":"","sources":["../../../server/auth/posture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAuB,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"posture.js","sourceRoot":"","sources":["../../../server/auth/posture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAuB,MAAM,0BAA0B,CAAC;AAChG,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAkB/E;;;;;;GAMG;AACH,MAAM,2BAA2B,GAAsB,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC;AAEtF,2EAA2E;AAC3E,MAAM,oBAAoB,GAAG,iDAAiD,CAAC;AAE/E,2DAA2D;AAC3D,MAAM,WAAW,GAAG,sCAAsC,CAAC;AAE3D;;;;;;GAMG;AACH,SAAS,eAAe,CAAC,GAAW;IAClC,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IACnD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;IAC7B,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC;AAC9F,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAK3C,IAAI,KAAK,GAAkB,IAAI,CAAC;IAChC,IAAI,IAAI,GAAG,GAAG,CAAC;IACf,MAAM,KAAK,GAAG,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC7C,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;QAClB,yEAAyE;QACzE,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;QAC7B,IAAI,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;IACxD,CAAC;IACD,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IAC9D,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;AACtF,CAAC;AAED,sDAAsD;AACtD,SAAS,WAAW,CAAC,GAAW;IAC9B,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IAClD,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AACjD,CAAC;AAED,SAAS,WAAW,CAClB,OAAgE,EAChE,IAAY;IAEZ,sEAAsE;IACtE,6EAA6E;IAC7E,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACnD,IAAI,GAAG,CAAC,WAAW,EAAE,KAAK,IAAI;YAAE,SAAS;QACzC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAC/D,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QACtC,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAC3B,GAAW,EACX,OAAgE;IAEhE,IAAI,kBAAkB,GAA0B,IAAI,CAAC;IACrD;;;;;;;OAOG;IACH,IAAI,mBAAmB,GAAkB,IAAI,CAAC;IAE9C,KAAK,MAAM,IAAI,IAAI,2BAA2B,EAAE,CAAC;QAC/C,MAAM,GAAG,GAAG,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACvC,IAAI,GAAG,KAAK,IAAI;YAAE,SAAS;QAC3B,MAAM,IAAI,GAAG,kBAAkB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC3C,wEAAwE;QACxE,4EAA4E;QAC5E,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO;YAAE,SAAS;QAEpC,IAAI,IAAI,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;YACxC,yEAAyE;YACzE,wEAAwE;YACxE,iCAAiC;YACjC,mBAAmB,KAAK,WAAW,CAAC,GAAG,CAAC,CAAC;YACzC,SAAS;QACX,CAAC;QAED,kBAAkB,GAAG,IAAI,CAAC;QAC1B,MAAM;IACR,CAAC;IAED,MAAM,OAAO,GACX,kBAAkB,EAAE,IAAI,KAAK,8BAA8B,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC;IAEvF,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,UAAU,GAAG,WAAW,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IACxD,iFAAiF;IACjF,wDAAwD;IACxD,EAAE;IACF,8EAA8E;IAC9E,sEAAsE;IACtE,4EAA4E;IAC5E,4EAA4E;IAC5E,aAAa;IACb,MAAM,WAAW,GAAG,UAAU,KAAK,IAAI,IAAI,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/F,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,IAAI,WAAW,IAAI,mBAAmB,CAAC;IAC3E,MAAM,OAAO,GACX,QAAQ,CAAC,KAAK,KAAK,IAAI;QACrB,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,WAAW,KAAK,IAAI;YACpB,CAAC,CAAC,QAAQ;YACV,CAAC,CAAC,mBAAmB,KAAK,IAAI;gBAC5B,CAAC,CAAC,aAAa;gBACf,CAAC,CAAC,MAAM,CAAC;IAEjB,MAAM,QAAQ,GAAa;QACzB,OAAO;QACP,gBAAgB,EAAE,aAAa,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,aAAa,CAAC;KAC7E,CAAC;IAEF,OAAO;QACL,OAAO;QACP,kBAAkB;QAClB,QAAQ;QACR,aAAa;QACb,aAAa,EAAE,QAAQ,CAAC,SAAS;QACjC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;KACjE,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAS,MAAM,CAAC,QAA0C,EAAE,MAAqB;IAC/E,MAAM,WAAW,GAAG,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;IAC/F,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IACnF,OAAO,aAAa,CAAC,CAAC,GAAG,WAAW,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC;AACvD,CAAC"}
|
package/dist/server/bin/fest.js
CHANGED
|
@@ -41,11 +41,15 @@
|
|
|
41
41
|
* `openai` on your OPENAI_API_KEY.
|
|
42
42
|
* fest logout forget the local login
|
|
43
43
|
*/
|
|
44
|
+
import cluster from "node:cluster";
|
|
44
45
|
import { mkdir, rm } from "node:fs/promises";
|
|
45
46
|
import { dirname } from "node:path";
|
|
46
47
|
import { loadConfig, describeConfig } from "../config.js";
|
|
47
48
|
import { createUsageSink } from "../ingest/sink.js";
|
|
48
49
|
import { createLiveBus } from "../ingest/live-bus.js";
|
|
50
|
+
import { runPrimary, ORG_ID_ENV } from "../cluster/primary.js";
|
|
51
|
+
import { createWorkerLink, withWriterStats } from "../cluster/worker.js";
|
|
52
|
+
import { isToWorker } from "../cluster/messages.js";
|
|
49
53
|
import { createServer } from "../http/server.js";
|
|
50
54
|
import { log, setLogLevel } from "../log.js";
|
|
51
55
|
import { openStore, migrate } from "../store/db.js";
|
|
@@ -69,6 +73,7 @@ import { runClaude } from "../../cli/claude.js";
|
|
|
69
73
|
import { runCodex } from "../../cli/codex.js";
|
|
70
74
|
import { runCopilot } from "../../cli/copilot.js";
|
|
71
75
|
import { runLogout } from "../../cli/logout.js";
|
|
76
|
+
import { peelTagFlags, runTags } from "../../cli/tags.js";
|
|
72
77
|
import { readCliConfig } from "../../cli/config.js";
|
|
73
78
|
const out = (s) => void process.stdout.write(s + "\n");
|
|
74
79
|
async function withStore(cfg) {
|
|
@@ -104,12 +109,46 @@ async function loadRoutes(cfg) {
|
|
|
104
109
|
});
|
|
105
110
|
return table;
|
|
106
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* How long an in-flight request may keep the process alive on shutdown.
|
|
114
|
+
*
|
|
115
|
+
* Long enough not to guillotine a developer mid-turn; short enough that
|
|
116
|
+
* `node --watch` feels like a restart rather than a hang.
|
|
117
|
+
*/
|
|
118
|
+
const DRAIN_GRACE_MS = 5_000;
|
|
119
|
+
function banner(cfg, routes) {
|
|
120
|
+
return (`fest: http://${cfg.host}:${cfg.port} -> ${cfg.upstreamBaseUrl}\n` +
|
|
121
|
+
` db: ${cfg.dbPath} identity required: ${cfg.requireIdentity}` +
|
|
122
|
+
(cfg.workers > 1 ? ` workers: ${cfg.workers}` : "") +
|
|
123
|
+
"\n" +
|
|
124
|
+
` retention: requests ${DEFAULT_RETENTION.requestDays}d, rollups ${DEFAULT_RETENTION.rollupDays}d\n` +
|
|
125
|
+
` routing: ${routes.routes.length === 0
|
|
126
|
+
? "none — every request passes through on the caller's own credential"
|
|
127
|
+
: `${routes.routes.length} route(s) via ${cfg.routesPath} (v${routes.version})`}\n` +
|
|
128
|
+
`point Claude Code at it with:\n` +
|
|
129
|
+
` ANTHROPIC_BASE_URL=http://${cfg.host}:${cfg.port}/t/<your-token>\n` +
|
|
130
|
+
`and do NOT set ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN (either disables your subscription)`);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* `fest serve`, in one of three shapes:
|
|
134
|
+
*
|
|
135
|
+
* - single process (`FEST_WORKERS` unset or 1): everything below, in one place.
|
|
136
|
+
* - cluster primary (`FEST_WORKERS` > 1): boot, migrate and the boot-time
|
|
137
|
+
* refusals happen here exactly once, then server/cluster/primary.ts forks the
|
|
138
|
+
* workers and becomes the one metering writer. It never listens itself.
|
|
139
|
+
* - cluster worker: the same `fest serve` command re-run by `cluster.fork()`,
|
|
140
|
+
* which detects that it is a worker and serves HTTP with its usage sent to
|
|
141
|
+
* the primary.
|
|
142
|
+
*/
|
|
107
143
|
async function cmdServe(cfg) {
|
|
144
|
+
if (cluster.isWorker) {
|
|
145
|
+
await serveWorker(cfg);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
// Loaded here even in cluster mode, where only the workers route: a broken
|
|
149
|
+
// table must stop the process before any worker exists, where an operator is
|
|
150
|
+
// watching (see loadRoutes).
|
|
108
151
|
const routes = await loadRoutes(cfg);
|
|
109
|
-
// Edits to routes.json take effect without a restart. `node --watch` only
|
|
110
|
-
// tracks imported .ts files, so without this an edit appeared to do nothing —
|
|
111
|
-
// which reads as "my config is wrong" rather than "it has not been loaded".
|
|
112
|
-
const routeWatcher = cfg.routesPath === null ? null : watchRoutes(cfg.routesPath, routes);
|
|
113
152
|
const store = await withStore(cfg);
|
|
114
153
|
const org = ensureOrg(store);
|
|
115
154
|
/**
|
|
@@ -130,6 +169,19 @@ async function cmdServe(cfg) {
|
|
|
130
169
|
" (in Docker: docker compose run --rm fest admin create you@corp.test)\n" +
|
|
131
170
|
"or bind to loopback (FEST_HOST=127.0.0.1) for a single-developer trial.");
|
|
132
171
|
}
|
|
172
|
+
if (cfg.workers > 1) {
|
|
173
|
+
await runPrimary({
|
|
174
|
+
cfg,
|
|
175
|
+
store,
|
|
176
|
+
orgId: org.id,
|
|
177
|
+
drainGraceMs: DRAIN_GRACE_MS,
|
|
178
|
+
announce: () => {
|
|
179
|
+
log.info("fest listening", describeConfig(cfg));
|
|
180
|
+
out(banner(cfg, routes));
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
133
185
|
// Prices load synchronously from the vendored snapshot before the first
|
|
134
186
|
// request can arrive, so a call is never metered against an empty table. The
|
|
135
187
|
// refresh that follows is best-effort and off the hot path — see
|
|
@@ -159,36 +211,106 @@ async function cmdServe(cfg) {
|
|
|
159
211
|
bus.publish(records);
|
|
160
212
|
},
|
|
161
213
|
});
|
|
214
|
+
startHttp({
|
|
215
|
+
cfg,
|
|
216
|
+
routes,
|
|
217
|
+
store,
|
|
218
|
+
orgId: org.id,
|
|
219
|
+
bus,
|
|
220
|
+
sink,
|
|
221
|
+
touchToken: (id) => lastUsed.touch(id),
|
|
222
|
+
afterSinkClosed: async () => { },
|
|
223
|
+
stop: () => {
|
|
224
|
+
retention.stop();
|
|
225
|
+
priceRefresh.stop();
|
|
226
|
+
lastUsed.stop();
|
|
227
|
+
store.close();
|
|
228
|
+
},
|
|
229
|
+
announce: true,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* A cluster worker: the HTTP server, minus everything that must run once.
|
|
234
|
+
*
|
|
235
|
+
* No migrations (the primary ran them before forking), no retention, no price
|
|
236
|
+
* refresh, no metering writes — see server/cluster/primary.ts for why the
|
|
237
|
+
* writer is elsewhere. Its own store connection serves the dashboard's reads,
|
|
238
|
+
* identity lookups and the low-volume auth writes.
|
|
239
|
+
*/
|
|
240
|
+
async function serveWorker(cfg) {
|
|
241
|
+
const orgId = process.env[ORG_ID_ENV];
|
|
242
|
+
if (orgId === undefined || orgId === "") {
|
|
243
|
+
throw new Error(`cluster worker started without ${ORG_ID_ENV}; it must be forked by fest serve`);
|
|
244
|
+
}
|
|
245
|
+
const routes = await loadRoutes(cfg);
|
|
246
|
+
const store = openStore(cfg.dbPath);
|
|
247
|
+
const pricing = pricingOptionsFromEnv(cfg.dbPath);
|
|
248
|
+
loadPrices(pricing);
|
|
249
|
+
const link = createWorkerLink();
|
|
250
|
+
const bus = createLiveBus();
|
|
251
|
+
// No trail here: the primary keeps the one JSONL file. A throw from send()
|
|
252
|
+
// means the primary is gone, and the sink's requeue holds the batch.
|
|
253
|
+
const local = createUsageSink({ path: null, onBatch: (records) => link.send({ t: "usage", records }) });
|
|
254
|
+
let writerStats = null;
|
|
255
|
+
const sink = withWriterStats(local, () => writerStats, () => link.lost());
|
|
256
|
+
process.on("message", (msg) => {
|
|
257
|
+
if (!isToWorker(msg))
|
|
258
|
+
return;
|
|
259
|
+
if (msg.t === "live")
|
|
260
|
+
bus.publish(msg.records);
|
|
261
|
+
else if (msg.t === "prices")
|
|
262
|
+
loadPrices(pricing);
|
|
263
|
+
else
|
|
264
|
+
writerStats = msg.stats;
|
|
265
|
+
});
|
|
266
|
+
startHttp({
|
|
267
|
+
cfg,
|
|
268
|
+
routes,
|
|
269
|
+
store,
|
|
270
|
+
orgId,
|
|
271
|
+
bus,
|
|
272
|
+
sink,
|
|
273
|
+
touchToken: (id) => link.send({ t: "touch", tokenId: id }),
|
|
274
|
+
// The final flush went out on an asynchronous channel; let it leave before
|
|
275
|
+
// the exit that would otherwise discard it.
|
|
276
|
+
afterSinkClosed: () => link.drained(2_000),
|
|
277
|
+
stop: () => store.close(),
|
|
278
|
+
announce: false,
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
function startHttp(deps) {
|
|
282
|
+
const { cfg, routes, store, bus, sink } = deps;
|
|
283
|
+
// Edits to routes.json take effect without a restart. `node --watch` only
|
|
284
|
+
// tracks imported .ts files, so without this an edit appeared to do nothing —
|
|
285
|
+
// which reads as "my config is wrong" rather than "it has not been loaded".
|
|
286
|
+
const routeWatcher = cfg.routesPath === null ? null : watchRoutes(cfg.routesPath, routes);
|
|
162
287
|
const server = createServer({
|
|
163
288
|
config: cfg,
|
|
164
289
|
sink,
|
|
165
290
|
bus,
|
|
166
291
|
routes: routeWatcher === null ? routes : () => routeWatcher.current(),
|
|
167
|
-
orgId:
|
|
292
|
+
orgId: deps.orgId,
|
|
168
293
|
store,
|
|
169
294
|
resolveIdentity: (raw) => resolveToken(store, raw),
|
|
170
|
-
touchToken:
|
|
295
|
+
touchToken: deps.touchToken,
|
|
171
296
|
});
|
|
172
|
-
/**
|
|
173
|
-
* How long an in-flight request may keep the process alive on shutdown.
|
|
174
|
-
*
|
|
175
|
-
* Long enough not to guillotine a developer mid-turn; short enough that
|
|
176
|
-
* `node --watch` feels like a restart rather than a hang.
|
|
177
|
-
*/
|
|
178
|
-
const DRAIN_GRACE_MS = 5_000;
|
|
179
297
|
let shuttingDown = false;
|
|
180
298
|
const shutdown = (signal) => {
|
|
181
299
|
if (shuttingDown)
|
|
182
300
|
return;
|
|
183
301
|
shuttingDown = true;
|
|
184
302
|
log.info("shutting down", { signal });
|
|
303
|
+
let finished = false;
|
|
185
304
|
const finish = () => {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
305
|
+
if (finished)
|
|
306
|
+
return;
|
|
307
|
+
finished = true;
|
|
308
|
+
void sink
|
|
309
|
+
.close()
|
|
310
|
+
.then(() => deps.afterSinkClosed())
|
|
311
|
+
.then(() => {
|
|
189
312
|
routeWatcher?.stop();
|
|
190
|
-
|
|
191
|
-
store.close();
|
|
313
|
+
deps.stop();
|
|
192
314
|
log.info("drained", { sink: sink.stats() });
|
|
193
315
|
process.exit(0);
|
|
194
316
|
});
|
|
@@ -217,16 +339,10 @@ async function cmdServe(cfg) {
|
|
|
217
339
|
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
218
340
|
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
219
341
|
server.listen(cfg.port, cfg.host, () => {
|
|
342
|
+
if (!deps.announce)
|
|
343
|
+
return;
|
|
220
344
|
log.info("fest listening", describeConfig(cfg));
|
|
221
|
-
out(
|
|
222
|
-
` db: ${cfg.dbPath} identity required: ${cfg.requireIdentity}\n` +
|
|
223
|
-
` retention: requests ${DEFAULT_RETENTION.requestDays}d, rollups ${DEFAULT_RETENTION.rollupDays}d\n` +
|
|
224
|
-
` routing: ${routes.routes.length === 0
|
|
225
|
-
? "none — every request passes through on the caller's own credential"
|
|
226
|
-
: `${routes.routes.length} route(s) via ${cfg.routesPath} (v${routes.version})`}\n` +
|
|
227
|
-
`point Claude Code at it with:\n` +
|
|
228
|
-
` ANTHROPIC_BASE_URL=http://${cfg.host}:${cfg.port}/t/<your-token>\n` +
|
|
229
|
-
`and do NOT set ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN (either disables your subscription)`);
|
|
345
|
+
out(banner(cfg, routes));
|
|
230
346
|
});
|
|
231
347
|
}
|
|
232
348
|
async function cmdToken(cfg, argv) {
|
|
@@ -510,12 +626,19 @@ function printHelp() {
|
|
|
510
626
|
"developer (run on your own machine, no server env needed):\n" +
|
|
511
627
|
" fest login [--provider google|github] [--server <url>]\n" +
|
|
512
628
|
" fest whoami\n" +
|
|
513
|
-
" fest claude [gw] [-- claude args...]
|
|
514
|
-
"
|
|
515
|
-
" fest
|
|
629
|
+
" fest claude [gw] [--tag k=v]... [-- claude args...]\n" +
|
|
630
|
+
" (gw: force org credentials + gateway models)\n" +
|
|
631
|
+
" fest codex [key] [--tag k=v]... [-- codex args...]\n" +
|
|
632
|
+
" (key: force API-key mode over a ChatGPT login)\n" +
|
|
633
|
+
" fest copilot [anthropic|gw|openai] [--tag k=v]... [-- copilot args...]\n" +
|
|
516
634
|
" (Copilot CLI on your Copilot plan; BYOK instead with\n" +
|
|
517
635
|
" anthropic: your ANTHROPIC_API_KEY, gw: gateway routes,\n" +
|
|
518
636
|
" openai: your OPENAI_API_KEY)\n" +
|
|
637
|
+
" fest tags | tags set [-g] k=v [k=v...] | tags unset [-g] k [k...]\n" +
|
|
638
|
+
" (labels on your usage, e.g. team=platform; saved\n" +
|
|
639
|
+
" for this directory and below, -g for everywhere;\n" +
|
|
640
|
+
" project defaults to the git repo name; FEST_TAGS\n" +
|
|
641
|
+
" and --tag override, project= removes)\n" +
|
|
519
642
|
" fest logout");
|
|
520
643
|
}
|
|
521
644
|
async function cmdLogin(argv) {
|
|
@@ -535,10 +658,11 @@ async function cmdLogin(argv) {
|
|
|
535
658
|
* `loadConfig()` is ever called: a laptop has no reason to have any FEST_*
|
|
536
659
|
* server env var set, and these commands must not imply otherwise.
|
|
537
660
|
*/
|
|
538
|
-
const CLIENT_COMMANDS = new Set(["login", "whoami", "claude", "codex", "copilot", "logout"]);
|
|
661
|
+
const CLIENT_COMMANDS = new Set(["login", "whoami", "claude", "codex", "copilot", "tags", "logout"]);
|
|
539
662
|
/**
|
|
540
|
-
* Peel an optional mode word off a client command's args, then
|
|
541
|
-
*
|
|
663
|
+
* Peel an optional mode word off a client command's args, then any leading
|
|
664
|
+
* `--tag k=v` flags, then a conventional leading `--`. Only before `--`:
|
|
665
|
+
* `fest codex -- key` forwards `key`.
|
|
542
666
|
*/
|
|
543
667
|
function modeArgs(argv, modes) {
|
|
544
668
|
let rest = [...argv];
|
|
@@ -547,9 +671,11 @@ function modeArgs(argv, modes) {
|
|
|
547
671
|
mode = rest[0];
|
|
548
672
|
rest = rest.slice(1);
|
|
549
673
|
}
|
|
674
|
+
const peeled = peelTagFlags(rest);
|
|
675
|
+
rest = peeled.rest;
|
|
550
676
|
if (rest[0] === "--")
|
|
551
677
|
rest = rest.slice(1);
|
|
552
|
-
return { mode, rest };
|
|
678
|
+
return { mode, rest, tags: peeled.tags };
|
|
553
679
|
}
|
|
554
680
|
async function main() {
|
|
555
681
|
const argv = process.argv.slice(2);
|
|
@@ -569,25 +695,31 @@ async function main() {
|
|
|
569
695
|
const posture = claudeArgs[0] === "gw" ? "key" : "auto";
|
|
570
696
|
if (posture === "key")
|
|
571
697
|
claudeArgs = claudeArgs.slice(1);
|
|
698
|
+
// Leading `--tag k=v` flags are Fest's; see `cli/tags.ts`.
|
|
699
|
+
const { tags, rest: afterTags } = peelTagFlags(claudeArgs);
|
|
700
|
+
claudeArgs = afterTags;
|
|
572
701
|
// `fest claude -- --resume` and `fest claude --resume` are both fine:
|
|
573
702
|
// apart from `gw` this subcommand defines no flags of its own, so a
|
|
574
703
|
// leading `--` is only ever there by convention and is stripped rather
|
|
575
704
|
// than forwarded.
|
|
576
705
|
if (claudeArgs[0] === "--")
|
|
577
706
|
claudeArgs = claudeArgs.slice(1);
|
|
578
|
-
await runClaude(claudeArgs, posture);
|
|
707
|
+
await runClaude(claudeArgs, posture, tags);
|
|
579
708
|
return;
|
|
580
709
|
}
|
|
581
710
|
case "codex": {
|
|
582
|
-
const { mode, rest } = modeArgs(argv.slice(1), ["key"]);
|
|
583
|
-
await runCodex(rest, mode ?? "auto");
|
|
711
|
+
const { mode, rest, tags } = modeArgs(argv.slice(1), ["key"]);
|
|
712
|
+
await runCodex(rest, mode ?? "auto", tags);
|
|
584
713
|
return;
|
|
585
714
|
}
|
|
586
715
|
case "copilot": {
|
|
587
|
-
const { mode, rest } = modeArgs(argv.slice(1), ["anthropic", "gw", "openai"]);
|
|
588
|
-
await runCopilot(rest, mode ?? "subscription");
|
|
716
|
+
const { mode, rest, tags } = modeArgs(argv.slice(1), ["anthropic", "gw", "openai"]);
|
|
717
|
+
await runCopilot(rest, mode ?? "subscription", tags);
|
|
589
718
|
return;
|
|
590
719
|
}
|
|
720
|
+
case "tags":
|
|
721
|
+
await runTags(argv.slice(1));
|
|
722
|
+
return;
|
|
591
723
|
case "logout":
|
|
592
724
|
await runLogout();
|
|
593
725
|
return;
|