aweshare 0.5.6 → 0.5.7
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.ai.md +2 -2
- package/README.md +17 -3
- package/apps/agent/dist/doctor.js +52 -16
- package/apps/agent/dist/doctor.js.map +1 -1
- package/apps/agent/dist/table.d.ts +19 -2
- package/apps/agent/dist/table.js +28 -3
- package/apps/agent/dist/table.js.map +1 -1
- package/apps/consumer/dist/table.d.ts +17 -2
- package/apps/consumer/dist/table.js +18 -3
- package/apps/consumer/dist/table.js.map +1 -1
- package/apps/hub/dist/admin.d.ts +2 -0
- package/apps/hub/dist/admin.js +33 -1
- package/apps/hub/dist/admin.js.map +1 -1
- package/apps/hub/dist/cli.js +54 -15
- package/apps/hub/dist/cli.js.map +1 -1
- package/apps/hub/dist/config.d.ts +6 -1
- package/apps/hub/dist/config.js +42 -1
- package/apps/hub/dist/config.js.map +1 -1
- package/apps/hub/dist/consumer.d.ts +34 -3
- package/apps/hub/dist/consumer.js +99 -7
- package/apps/hub/dist/consumer.js.map +1 -1
- package/apps/hub/dist/db.d.ts +29 -1
- package/apps/hub/dist/db.js +70 -6
- package/apps/hub/dist/db.js.map +1 -1
- package/apps/hub/dist/meter.d.ts +6 -1
- package/apps/hub/dist/meter.js +14 -0
- package/apps/hub/dist/meter.js.map +1 -1
- package/apps/hub/dist/server.js +4 -2
- package/apps/hub/dist/server.js.map +1 -1
- package/apps/hub/dist/table.d.ts +20 -3
- package/apps/hub/dist/table.js +35 -10
- package/apps/hub/dist/table.js.map +1 -1
- package/package.json +1 -1
- package/packages/protocol/dist/index.d.ts +1 -0
- package/packages/protocol/dist/index.js +1 -0
- package/packages/protocol/dist/index.js.map +1 -1
- package/packages/protocol/dist/models.d.ts +23 -0
- package/packages/protocol/dist/models.js +72 -0
- package/packages/protocol/dist/models.js.map +1 -0
package/README.ai.md
CHANGED
|
@@ -245,7 +245,7 @@ After setup:
|
|
|
245
245
|
```bash
|
|
246
246
|
aweshare producer doctor # full diagnosis, ordered to find the first failing link
|
|
247
247
|
aweshare producer list # registered offerings, live status, caps, occupancy, config drift
|
|
248
|
-
aweshare hub status
|
|
248
|
+
aweshare hub status [--all] # offering health + capacity; --all adds rosters
|
|
249
249
|
aweshare hub list usage # who used how much, aggregated per consumer × model
|
|
250
250
|
aweshare self-update --check # installed vs npm latest
|
|
251
251
|
```
|
|
@@ -270,7 +270,7 @@ aweshare producer doctor [--status] # diagnosis (with --status: instant, no net
|
|
|
270
270
|
aweshare producer list [--json] # this producer's offerings + drift
|
|
271
271
|
aweshare producer usage [...] # who used this producer's models
|
|
272
272
|
aweshare consumer list --hub URL --token asc_... # hub catalog view
|
|
273
|
-
aweshare hub status
|
|
273
|
+
aweshare hub status [--all] # capacity + offering health; --all adds rosters
|
|
274
274
|
aweshare hub list invites [--reveal|--token] # invite ledger / codes / minted tokens
|
|
275
275
|
aweshare hub limits NAME # bare call views current overrides
|
|
276
276
|
aweshare hub list usage [--details] [--group-by consumer|alias] [--since 7d]
|
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<a href="https://ko-fi.com/mugpeng"><img src="https://img.shields.io/badge/Ko--fi-Buy%20me%20a%20coffee-FF5E5B?style=flat-square&logo=ko-fi&logoColor=white" alt="Ko-fi"></a>
|
|
15
15
|
</p>
|
|
16
16
|
<p>
|
|
17
|
-
<a href="https://github.com/wehuman01/aweshare-source/releases"><img src="https://img.shields.io/badge/version-0.5.
|
|
17
|
+
<a href="https://github.com/wehuman01/aweshare-source/releases"><img src="https://img.shields.io/badge/version-0.5.7-7C3AED?style=flat-square" alt="Version"></a>
|
|
18
18
|
<a href="https://github.com/wehuman01/aweshare"><img src="https://img.shields.io/badge/node-%E2%89%A522-0EA5E9?style=flat-square" alt="Node"></a>
|
|
19
19
|
<a href="https://github.com/wehuman01/aweshare/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-proprietary-E34F26?style=flat-square" alt="License"></a>
|
|
20
20
|
<a href="https://www.npmjs.com/package/aweshare"><img src="https://img.shields.io/badge/npm-aweshare-7C3AED?style=flat-square" alt="npm package"></a>
|
|
@@ -185,6 +185,16 @@ curl https://hub.example.com/v1/chat/completions \
|
|
|
185
185
|
|
|
186
186
|
## Consumer tool configuration
|
|
187
187
|
|
|
188
|
+
**Match the protocol to the tool first** — an alias speaks exactly one wire protocol and the hub never translates. Base URLs come in exactly two shapes: both OpenAI wires (`openai-chat` / `openai-responses`) point at `…/v1`, `anthropic` uses the bare hub address. The PROTOCOL column of `consumer list` / `GET /v1/catalog` shows these labels:
|
|
189
|
+
|
|
190
|
+
| PROTOCOL | Endpoint | base_url | Who can use it |
|
|
191
|
+
| --- | --- | --- | --- |
|
|
192
|
+
| `anthropic` | `/v1/messages` | `https://hub.example.com` | Claude Code, the Anthropic SDK |
|
|
193
|
+
| `openai-chat` | `/v1/chat/completions` | `https://hub.example.com/v1` | any OpenAI-compatible tool/SDK — opencode, zcode and other coding agents usually dial this |
|
|
194
|
+
| `openai-responses` | `/v1/responses` | `https://hub.example.com/v1` | Codex CLI (default `wire_api`), opencode, Cline (OpenAI Native) — not Codex-only |
|
|
195
|
+
|
|
196
|
+
A client may speak several wires (opencode speaks both OpenAI ones); pointing a chat-completions tool at an `openai-responses` alias (or vice versa) is a 404 (`unknown model alias … (no … offering under this alias)`).
|
|
197
|
+
|
|
188
198
|
**OpenAI SDK / any OpenAI-compatible tool**
|
|
189
199
|
|
|
190
200
|
```ts
|
|
@@ -310,7 +320,7 @@ Honest limits: token-based caps count what upstreams report — Ollama streams r
|
|
|
310
320
|
|
|
311
321
|
Error semantics: `401` invalid key · `401 TOKEN_REVOKED` suspended token (ask the operator to restore it) · `403 HUB_FULL` producer capacity reached · `404` unknown alias · `400 PROTOCOL_MISMATCH` protocol/alias mismatch · `429` rate limit, TPM or producer concurrency cap (`PRODUCER_MAX_USERS` = distinct-consumer cap; `QUOTA_EXCEEDED` = lifetime or daily token budget hit) · `502` upstream/tunnel failure (upstream 4xx/5xx passes through verbatim) · `503` producer offline / backend degraded · `504` timeout. Errors carry `{error:{code,message,requestId}}`; the requestId spans both sides' logs.
|
|
312
322
|
|
|
313
|
-
Usage metering: one row per request (alias,
|
|
323
|
+
Usage metering: one row per request (alias, declared upstream model, response-reported model when available, status, duration, byte counts, best-effort token counts), **zero content stored**. `aweshare hub list usage` (and `aweshare producer usage` on a producer's machine, scoped to its own models) answers "who used how much" by default: server-side aggregation on the hub's SQLite, one row per consumer × model — a person's rows stay together, busiest person and busiest model first — with request/error counts, best-effort token totals, an explicit unknown-token count (streaming backends that report no counts) and mean duration. The window defaults to 7 days and is printed with the table (`--since 30m\|12h\|7d\|…\|all`); `--group-by consumer` rolls up to per-person totals, `--group-by alias` to per-model totals. `--details` switches to the per-request log (`GET /admin/v1/usage`; admin sees everything, producers and consumers their own slice, rows carry the consumer/producer names).
|
|
314
324
|
|
|
315
325
|
## Command reference
|
|
316
326
|
|
|
@@ -325,10 +335,11 @@ Both sides at a glance — details in the sections above.
|
|
|
325
335
|
| `aweshare hub produce [--host H] [--port N]` | run the hub with its own models attached — same as `serve`; the `[[backends]]`/`[[offerings]]` sections of `config.produce.toml` become `hub/…` offerings served in-process (keys in the data dir's secrets.json; edits hot-reload) |
|
|
326
336
|
| `aweshare hub invite [--role producer\|consumer] [--name NAME] [--count N] [--expires-in D\|none]` | mint one-time invite codes (`asi_…`, printed once, expire after 7 d by default; re-view with `list invites --reveal`); `--expires-in` also bounds the lifetime of the token it mints — an expired key fails auth with 401 `TOKEN_EXPIRED` (`none` = code and identity never expire; identities minted before this change never expire); producer codes: bound (`--name`) or unbound (name + email at redeem, `--count` batches); consumer codes: always bound to one name |
|
|
327
337
|
| `aweshare hub list invites [--reveal] [--token] [--json]` | the invite ledger: every code, the identity it minted and its lifecycle (pending/used/suspended/revoked/expired; a redeemed code shows `expired` once its identity's expiry passes); `--reveal` re-shows the codes, `--token` the minted tokens with last seen |
|
|
328
|
-
| `aweshare hub status` | the hub's live state: producer slots,
|
|
338
|
+
| `aweshare hub status [--all]` | the hub's live state: producer slots, offerings counted per deduplicated alias (several protocols → one verdict, the worst), a per-alias table — the same columns as `consumer list` and `producer list`, worst status first — with live occupancy (`IN USE n/max`) and today's remaining daily tokens, and a last-5m requests/ok-rate/errors line from the usage summary (hub-admission 429s are not metered); identities appear as counts — `--all` prints the full producer/consumer rosters |
|
|
329
339
|
| `aweshare hub limits NAME [--rps N] [--burst N] [--max-concurrent N] [--tpm N] [--max-total-tokens N] [--clear] [--json]` | show, merge or clear one consumer's limit overrides (unset keys keep the hub-wide defaults) |
|
|
330
340
|
| `aweshare hub list usage [--details] [--consumer NAME] [--producer NAME] [--alias ns/model] [--group-by consumer-alias\|consumer\|alias] [--since 7d\|all] [--limit N] [--json]` | who used how much (default): aggregate per consumer × model, a person's rows together, busiest first — requests, errors, rate, best-effort token totals, unknown-token count, mean duration; window defaults to 7d and is printed with the table · `--details`: per-request log, newest first, zero content stored, each row naming its consumer |
|
|
331
341
|
| `aweshare hub revoke --id N` · `aweshare hub restore --id N` | kill an invite / undo — a redeemed code suspends the producer it minted, restore revives both |
|
|
342
|
+
| `aweshare hub offering block ALIAS` · `aweshare hub offering restore ALIAS` | the per-alias scalpel between doing nothing and revoking a whole producer: block one offering (every protocol row of the alias) — new requests get 503 `OFFERING_BLOCKED`, status shows `blocked`, the producer's other offerings keep serving. Manual blocks survive re-registers; auto blocks (model mismatch, see `autoBlockModelMismatch`) clear once the producer re-declares a different `upstreamModel` |
|
|
332
343
|
|
|
333
344
|
Token issuance runs through invites (both roles). `limits` and `list usage` are thin wrappers over the admin REST API (`/admin/v1/*`, see Endpoints and errors) — curl works too.
|
|
334
345
|
|
|
@@ -377,10 +388,13 @@ The hub reads `config.toml` from its data dir (`~/.aweshare-hub/config.toml`; Do
|
|
|
377
388
|
| `AWESHARE_INVITE_REDEEM_PER_MIN` | 10 | redeem entry global insurance budget (valid-format attempts shared by every origin) |
|
|
378
389
|
| `AWESHARE_INVITE_REDEEM_PER_IP_MIN` | 5 | redeem entry per-origin-IP bucket (`CF-Connecting-IP` behind a tunnel/proxy) — one visitor cannot monopolize admission; both keys reload via SIGHUP |
|
|
379
390
|
| `AWESHARE_MAX_PRODUCERS` | 10 | max active producers — token issuance (admin API), invite redeem and restore refuse with `403 HUB_FULL` when full |
|
|
391
|
+
| `AWESHARE_AUTO_BLOCK_MODEL_MISMATCH` | false | auto-block an offering after 2 consecutive successful responses report a different model than declared. Off by default: mismatches are logged once (flip) and visible in `hub status` / `consumer list` / `list usage --details` either way — the hub is report-only until the operator opts in. An auto block clears when the producer re-declares a different `upstreamModel`; an explicit manual `offering block` takes precedence and always persists; reloads via SIGHUP |
|
|
380
392
|
| `AWESHARE_NO_UPDATE_CHECK` | unset | set to `1` to disable the passive update reminder |
|
|
381
393
|
|
|
382
394
|
Health: agent heartbeats every 15s, silent 45s = dead; backends with 2 consecutive AUTH/QUOTA failures auto-degrade (alias shows `degraded`, dispatch stops), 30s probes recover. A new connection with the same producer token replaces the old one (latest-wins).
|
|
383
395
|
|
|
396
|
+
Model honesty: an offering's `upstreamModel` is the producer's claim — the hub compares it with the bounded model id reported by each successful response (`model` / `message.model` / `response.model`). This is consistency evidence, not proof of the model's underlying weights: a producer or upstream router can still rewrite that metadata. The observation rides the existing usage meter, never rewrites the relayed response, and is scoped to the same alias, protocol and current declaration. It appears in the `OBSERVED MODEL` column, `list usage --details`, and `/v1/catalog` as `observedModel`, `observedAt`, `modelMatch` and the backward-compatible `modelVerified`. Comparison is token-aware: exact ids and explicit date/revision suffixes are affirmative; vendor prefixes are tolerated; adjacent variants such as `gpt-4`/`gpt-4o` and `gpt-4o`/`gpt-4o-mini` mismatch; a less-specific response is marked `?`/`insufficient`, not verified. Handling is tiered: default **report-only**, manual `hub offering block ALIAS` or whole-producer `hub revoke`, and opt-in auto-block after 2 consecutive mismatches. Manual blocks override automatic ones. `producer doctor` probes every distinct configured model and reports the response-named id with the same evidence boundary.
|
|
397
|
+
|
|
384
398
|
Updating a npm install: `aweshare self-update` (asks before installing; `--check` only shows versions). The CLI also reminds you at most once a day when a newer npm release exists.
|
|
385
399
|
|
|
386
400
|
Updating a Docker deployment: `docker compose pull && docker compose up -d`. State lives in the `./data` volume; producers redial automatically after the restart, and consumers see 503 only during the brief restart window.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { classifyStatus, codexNetworkHint, fetchUpstream, probeBody, probeTarget, readCodexCredentials, } from '../../../packages/producer-core/dist/index.js';
|
|
2
|
+
import { compareModels, selfReportedModel } from '../../../packages/protocol/dist/index.js';
|
|
2
3
|
import { ConfigError, loadAgentConfig, } from './config.js';
|
|
3
4
|
import { formatLogLine, isProducerAlive, logFileOf, readPid, tailLog, uptimeOf } from './daemon.js';
|
|
4
5
|
import { assertWireCompatible, fetchOfferings, probeHub } from './hub.js';
|
|
@@ -139,8 +140,10 @@ async function checkBackend(backend, offerings, apiKey) {
|
|
|
139
140
|
detail: `anthropic-style baseUrl must not include /v1 (the agent appends it), got ${backend.baseUrl}`,
|
|
140
141
|
});
|
|
141
142
|
}
|
|
142
|
-
const
|
|
143
|
-
|
|
143
|
+
const models = [
|
|
144
|
+
...new Set(offerings.filter((o) => o.backend === backend.id).map((o) => o.upstreamModel)),
|
|
145
|
+
];
|
|
146
|
+
if (models.length === 0) {
|
|
144
147
|
checks.push({ name: label, ok: true, detail: 'no offerings — probe skipped' });
|
|
145
148
|
return checks;
|
|
146
149
|
}
|
|
@@ -172,21 +175,55 @@ async function checkBackend(backend, offerings, apiKey) {
|
|
|
172
175
|
}
|
|
173
176
|
const resolved = { ...backend, apiKey };
|
|
174
177
|
const { url, headers } = probeTarget(resolved);
|
|
178
|
+
for (const model of models) {
|
|
179
|
+
checks.push(await probeModel(models.length === 1 ? `${label} probe` : `${label} probe '${model}'`, model, backend, resolved, url, headers));
|
|
180
|
+
}
|
|
181
|
+
return checks;
|
|
182
|
+
}
|
|
183
|
+
/** Probe every distinct model on a backend. A healthy first model says
|
|
184
|
+
* nothing about the other ids routed through the same upstream. */
|
|
185
|
+
async function probeModel(name, model, backend, resolved, url, headers) {
|
|
175
186
|
try {
|
|
176
187
|
const started = Date.now();
|
|
177
188
|
const res = await fetchUpstream(resolved, url, {
|
|
178
189
|
method: 'POST',
|
|
179
190
|
headers,
|
|
180
|
-
body: JSON.stringify(probeBody(
|
|
191
|
+
body: JSON.stringify(probeBody(model, backend.protocol, backend.login !== undefined)),
|
|
181
192
|
signal: AbortSignal.timeout(30_000),
|
|
182
193
|
});
|
|
183
194
|
const reason = classifyStatus(res.status);
|
|
184
195
|
if (reason === null) {
|
|
185
|
-
|
|
186
|
-
|
|
196
|
+
// Response metadata is consistency evidence, not proof of the model's
|
|
197
|
+
// underlying weights.
|
|
198
|
+
let served = null;
|
|
199
|
+
try {
|
|
200
|
+
served = selfReportedModel(JSON.parse(await res.text()));
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
served = null; // non-JSON body: nothing self-reported to audit
|
|
204
|
+
}
|
|
205
|
+
if (served !== null) {
|
|
206
|
+
const comparison = compareModels(model, served);
|
|
207
|
+
if (comparison === 'mismatch') {
|
|
208
|
+
return {
|
|
209
|
+
name,
|
|
210
|
+
ok: false,
|
|
211
|
+
detail: `model '${model}' -> ${res.status}, but the response reports '${served}' — check the backend/proxy for model substitution`,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
if (comparison === 'insufficient') {
|
|
215
|
+
return {
|
|
216
|
+
name,
|
|
217
|
+
ok: false,
|
|
218
|
+
detail: `model '${model}' -> ${res.status}, but the response only reports '${served}' — not specific enough to verify the declaration`,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
name,
|
|
187
224
|
ok: true,
|
|
188
|
-
detail: `model '${
|
|
189
|
-
}
|
|
225
|
+
detail: `model '${model}' -> ${res.status} (${Date.now() - started}ms${served ? `, response reported '${served}'` : ''})`,
|
|
226
|
+
};
|
|
190
227
|
}
|
|
191
228
|
else {
|
|
192
229
|
const hint = reason === 'AUTH'
|
|
@@ -196,21 +233,20 @@ async function checkBackend(backend, offerings, apiKey) {
|
|
|
196
233
|
: reason === 'QUOTA'
|
|
197
234
|
? 'upstream balance or rate limit exhausted'
|
|
198
235
|
: 'check that upstreamModel is a real model id on the backend (full `ollama list` tag)';
|
|
199
|
-
|
|
200
|
-
|
|
236
|
+
await res.arrayBuffer().catch(() => undefined);
|
|
237
|
+
return {
|
|
238
|
+
name,
|
|
201
239
|
ok: false,
|
|
202
|
-
detail: `model '${
|
|
203
|
-
}
|
|
240
|
+
detail: `model '${model}' -> ${res.status} (${reason}): ${hint}`,
|
|
241
|
+
};
|
|
204
242
|
}
|
|
205
|
-
await res.arrayBuffer().catch(() => undefined);
|
|
206
243
|
}
|
|
207
244
|
catch (err) {
|
|
208
|
-
|
|
209
|
-
name
|
|
245
|
+
return {
|
|
246
|
+
name,
|
|
210
247
|
ok: false,
|
|
211
248
|
detail: `probe to ${url} failed: ${err instanceof Error ? err.message : err}${codexNetworkHint(resolved)}. Check local network and whether the service is running (inside Docker, 127.0.0.1 is the container itself)`,
|
|
212
|
-
}
|
|
249
|
+
};
|
|
213
250
|
}
|
|
214
|
-
return checks;
|
|
215
251
|
}
|
|
216
252
|
//# sourceMappingURL=doctor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ModelComparison } from 'aweshare-protocol';
|
|
1
2
|
/** Left-aligned columns with two-space gutters. */
|
|
2
3
|
export declare function formatTable(headers: string[], rows: string[][]): string;
|
|
3
4
|
/** '2026-08-01T10:00:00.123Z' → '2026-08-01 10:00Z' (UTC, minute precision). */
|
|
@@ -6,10 +7,16 @@ export declare function fmtTime(iso: string | null | undefined): string;
|
|
|
6
7
|
export interface OfferingRow {
|
|
7
8
|
alias: string;
|
|
8
9
|
/** Owning producer's name; current hubs always send it. Rendered only in
|
|
9
|
-
*
|
|
10
|
+
* the hub-wide view (`producer list --all`). */
|
|
10
11
|
producer?: string;
|
|
11
12
|
protocol: string;
|
|
12
13
|
status: string;
|
|
14
|
+
/** The model id reported in successful responses — consistency evidence
|
|
15
|
+
* for upstreamModel, not proof of underlying weights. Undefined on hubs
|
|
16
|
+
* that predate the audit, null before the first self-naming response. */
|
|
17
|
+
observedModel?: string | null;
|
|
18
|
+
modelVerified?: boolean | null;
|
|
19
|
+
modelMatch?: ModelComparison | null;
|
|
13
20
|
maxConcurrencyPerUser: number;
|
|
14
21
|
maxConcurrentUsers: number;
|
|
15
22
|
/** Distinct consumers with a request in flight right now (snapshot at list
|
|
@@ -19,6 +26,11 @@ export interface OfferingRow {
|
|
|
19
26
|
dailyTokens: number;
|
|
20
27
|
usedDailyTokens: number;
|
|
21
28
|
}
|
|
29
|
+
/** The OBSERVED MODEL cell — kept verbatim in apps/hub/src/table.ts and
|
|
30
|
+
* apps/consumer/src/table.ts with the shared headers: the observed id,
|
|
31
|
+
* '✗'-marked when it disagrees with the declaration, '-' when nothing was
|
|
32
|
+
* observed. */
|
|
33
|
+
export declare function observedCell(observedModel: string | null | undefined, modelVerified: boolean | null | undefined, modelMatch?: ModelComparison | null): string;
|
|
22
34
|
export interface ProducerStatusInput {
|
|
23
35
|
instance: string;
|
|
24
36
|
hubUrl: string;
|
|
@@ -30,7 +42,9 @@ export interface ProducerStatusInput {
|
|
|
30
42
|
/** Compact local overview; config secrets are deliberately never included. */
|
|
31
43
|
export declare function renderProducerStatus(input: ProducerStatusInput): string;
|
|
32
44
|
/** The offering table `producer list` renders — same column spec as the hub
|
|
33
|
-
* status and consumer list tables (locked together by a cross-CLI test).
|
|
45
|
+
* status and consumer list tables (locked together by a cross-CLI test).
|
|
46
|
+
* OBSERVED MODEL is what the upstream itself served: a '✗' marks a
|
|
47
|
+
* declaration that doesn't hold. */
|
|
34
48
|
export declare function renderOfferings(rows: OfferingRow[], opts?: {
|
|
35
49
|
producer?: boolean;
|
|
36
50
|
}): string;
|
|
@@ -47,6 +61,9 @@ export interface UsageRow {
|
|
|
47
61
|
producer_id: number;
|
|
48
62
|
alias: string;
|
|
49
63
|
upstream_model: string;
|
|
64
|
+
/** Model id the upstream named about itself; NULL when it named none.
|
|
65
|
+
* Absent on hubs that predate the model audit. */
|
|
66
|
+
observed_model?: string | null;
|
|
50
67
|
protocol: string;
|
|
51
68
|
streaming: number;
|
|
52
69
|
status: number | null;
|
package/apps/agent/dist/table.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Aligned-column tables for list output; `--json` keeps the raw API shape.
|
|
2
|
-
import { protocolLabel } from '../../../packages/protocol/dist/index.js';
|
|
2
|
+
import { compareModels, protocolLabel } from '../../../packages/protocol/dist/index.js';
|
|
3
3
|
/** Left-aligned columns with two-space gutters. */
|
|
4
4
|
export function formatTable(headers, rows) {
|
|
5
5
|
const widths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => r[i]?.length ?? 0)));
|
|
@@ -13,6 +13,17 @@ export function formatTable(headers, rows) {
|
|
|
13
13
|
export function fmtTime(iso) {
|
|
14
14
|
return iso ? `${iso.slice(0, 16).replace('T', ' ')}Z` : '-';
|
|
15
15
|
}
|
|
16
|
+
/** The OBSERVED MODEL cell — kept verbatim in apps/hub/src/table.ts and
|
|
17
|
+
* apps/consumer/src/table.ts with the shared headers: the observed id,
|
|
18
|
+
* '✗'-marked when it disagrees with the declaration, '-' when nothing was
|
|
19
|
+
* observed. */
|
|
20
|
+
export function observedCell(observedModel, modelVerified, modelMatch) {
|
|
21
|
+
if (observedModel === undefined || observedModel === null)
|
|
22
|
+
return '-';
|
|
23
|
+
if (modelMatch === 'mismatch' || modelVerified === false)
|
|
24
|
+
return `${observedModel} ✗`;
|
|
25
|
+
return modelMatch === 'insufficient' ? `${observedModel} ?` : observedModel;
|
|
26
|
+
}
|
|
16
27
|
/** Compact local overview; config secrets are deliberately never included. */
|
|
17
28
|
export function renderProducerStatus(input) {
|
|
18
29
|
const countOfferings = (status) => input.offerings.filter((o) => o.status === status).length;
|
|
@@ -31,7 +42,9 @@ export function renderProducerStatus(input) {
|
|
|
31
42
|
].join('\n');
|
|
32
43
|
}
|
|
33
44
|
/** The offering table `producer list` renders — same column spec as the hub
|
|
34
|
-
* status and consumer list tables (locked together by a cross-CLI test).
|
|
45
|
+
* status and consumer list tables (locked together by a cross-CLI test).
|
|
46
|
+
* OBSERVED MODEL is what the upstream itself served: a '✗' marks a
|
|
47
|
+
* declaration that doesn't hold. */
|
|
35
48
|
export function renderOfferings(rows, opts = {}) {
|
|
36
49
|
if (rows.length === 0)
|
|
37
50
|
return 'no offerings registered on this hub yet';
|
|
@@ -46,6 +59,7 @@ export function renderOfferings(rows, opts = {}) {
|
|
|
46
59
|
return formatTable([
|
|
47
60
|
...(opts.producer ? ['PRODUCER'] : []),
|
|
48
61
|
'ALIAS',
|
|
62
|
+
'OBSERVED MODEL',
|
|
49
63
|
'PROTOCOL',
|
|
50
64
|
'STATUS',
|
|
51
65
|
'MAX USERS',
|
|
@@ -59,6 +73,7 @@ export function renderOfferings(rows, opts = {}) {
|
|
|
59
73
|
return [
|
|
60
74
|
...(opts.producer ? [join((r) => r.producer ?? '-')] : []),
|
|
61
75
|
first?.alias ?? '',
|
|
76
|
+
join((r) => observedCell(r.observedModel, r.modelVerified, r.modelMatch)),
|
|
62
77
|
join((r) => protocolLabel(r.protocol), ', '),
|
|
63
78
|
join((r) => r.status),
|
|
64
79
|
join((r) => String(r.maxConcurrentUsers)),
|
|
@@ -86,6 +101,16 @@ export function driftSummary(configAliases, hubAliases) {
|
|
|
86
101
|
parts.push(`hub-only (config changed? run 'aweshare producer reload'): ${stale.join(', ')}`);
|
|
87
102
|
return parts.length > 0 ? parts.join('\n') : null;
|
|
88
103
|
}
|
|
104
|
+
/** The usage MODEL cell: the declaration, with the observed id appended when
|
|
105
|
+
* it disagrees (`glm-4.6≠step-2-16k`) — per-request evidence in one glance. */
|
|
106
|
+
function modelCell(r) {
|
|
107
|
+
if (r.observed_model == null)
|
|
108
|
+
return r.upstream_model;
|
|
109
|
+
const match = compareModels(r.upstream_model, r.observed_model);
|
|
110
|
+
if (match === 'mismatch')
|
|
111
|
+
return `${r.upstream_model}≠${r.observed_model}`;
|
|
112
|
+
return match === 'insufficient' ? `${r.upstream_model}?${r.observed_model}` : r.upstream_model;
|
|
113
|
+
}
|
|
89
114
|
/** Newest-first usage log. Token counts are best-effort — NULL (e.g. Ollama
|
|
90
115
|
* streams) renders as '-'. */
|
|
91
116
|
export function renderUsage(rows, consumerName) {
|
|
@@ -95,7 +120,7 @@ export function renderUsage(rows, consumerName) {
|
|
|
95
120
|
fmtTime(r.at),
|
|
96
121
|
consumerName(r.consumer_id),
|
|
97
122
|
r.alias,
|
|
98
|
-
r
|
|
123
|
+
modelCell(r),
|
|
99
124
|
r.error_code ? `${r.status ?? '-'} ${r.error_code}` : String(r.status ?? '-'),
|
|
100
125
|
`${r.duration_ms}ms`,
|
|
101
126
|
r.prompt_tokens === null && r.completion_tokens === null
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table.js","sourceRoot":"","sources":["../src/table.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"table.js","sourceRoot":"","sources":["../src/table.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ModelComparison } from 'aweshare-protocol';
|
|
1
2
|
/** Left-aligned columns with two-space gutters. */
|
|
2
3
|
export declare function formatTable(headers: string[], rows: string[][]): string;
|
|
3
4
|
export interface CatalogRow {
|
|
@@ -5,6 +6,13 @@ export interface CatalogRow {
|
|
|
5
6
|
alias: string;
|
|
6
7
|
protocol: string;
|
|
7
8
|
status: string;
|
|
9
|
+
/** The model id reported in successful responses — consistency evidence
|
|
10
|
+
* for the producer's declaration, not proof of underlying model weights.
|
|
11
|
+
* Undefined on hubs that predate the audit, null before the first
|
|
12
|
+
* self-naming response. */
|
|
13
|
+
observedModel?: string | null;
|
|
14
|
+
modelVerified?: boolean | null;
|
|
15
|
+
modelMatch?: ModelComparison | null;
|
|
8
16
|
/** Concurrent-requests cap per consumer; pre-v0.4.3 hubs don't report it. */
|
|
9
17
|
maxConcurrencyPerUser?: number;
|
|
10
18
|
maxConcurrentUsers: number;
|
|
@@ -18,8 +26,15 @@ export interface CatalogRow {
|
|
|
18
26
|
}
|
|
19
27
|
/** `consumer list` hides offline offerings by default — they can't be called,
|
|
20
28
|
* so they're noise when picking a model; `--all` lists everything. Degraded
|
|
21
|
-
* stays visible: the upstream is briefly failing but the producer is up.
|
|
29
|
+
* stays visible: the upstream is briefly failing but the producer is up.
|
|
30
|
+
* Blocked offerings are hidden like offline ones — the operator closed them. */
|
|
22
31
|
export declare function filterCatalog(rows: CatalogRow[], all: boolean): CatalogRow[];
|
|
32
|
+
/** The OBSERVED MODEL cell — kept verbatim in apps/hub/src/table.ts and
|
|
33
|
+
* apps/agent/src/table.ts with the shared headers: the observed id, '✗'-marked
|
|
34
|
+
* when it disagrees with the declaration, '-' when nothing was observed. */
|
|
35
|
+
export declare function observedCell(observedModel: string | null | undefined, modelVerified: boolean | null | undefined, modelMatch?: ModelComparison | null): string;
|
|
23
36
|
/** The offering table every CLI renders — same column spec as hub status and
|
|
24
|
-
* producer list (locked together by a cross-CLI test in apps/hub/test).
|
|
37
|
+
* producer list (locked together by a cross-CLI test in apps/hub/test).
|
|
38
|
+
* OBSERVED MODEL is what the upstream itself served: a '✗' marks a
|
|
39
|
+
* declaration that doesn't hold. */
|
|
25
40
|
export declare function renderCatalog(rows: CatalogRow[]): string;
|
|
@@ -11,9 +11,20 @@ export function formatTable(headers, rows) {
|
|
|
11
11
|
}
|
|
12
12
|
/** `consumer list` hides offline offerings by default — they can't be called,
|
|
13
13
|
* so they're noise when picking a model; `--all` lists everything. Degraded
|
|
14
|
-
* stays visible: the upstream is briefly failing but the producer is up.
|
|
14
|
+
* stays visible: the upstream is briefly failing but the producer is up.
|
|
15
|
+
* Blocked offerings are hidden like offline ones — the operator closed them. */
|
|
15
16
|
export function filterCatalog(rows, all) {
|
|
16
|
-
return all ? rows : rows.filter((r) => r.status !== 'offline');
|
|
17
|
+
return all ? rows : rows.filter((r) => r.status !== 'offline' && r.status !== 'blocked');
|
|
18
|
+
}
|
|
19
|
+
/** The OBSERVED MODEL cell — kept verbatim in apps/hub/src/table.ts and
|
|
20
|
+
* apps/agent/src/table.ts with the shared headers: the observed id, '✗'-marked
|
|
21
|
+
* when it disagrees with the declaration, '-' when nothing was observed. */
|
|
22
|
+
export function observedCell(observedModel, modelVerified, modelMatch) {
|
|
23
|
+
if (observedModel === undefined || observedModel === null)
|
|
24
|
+
return '-';
|
|
25
|
+
if (modelMatch === 'mismatch' || modelVerified === false)
|
|
26
|
+
return `${observedModel} ✗`;
|
|
27
|
+
return modelMatch === 'insufficient' ? `${observedModel} ?` : observedModel;
|
|
17
28
|
}
|
|
18
29
|
/** One alias may speak several protocols (one hub row each); the table shows
|
|
19
30
|
* one line per alias with the protocols joined. Other columns join differing
|
|
@@ -33,6 +44,7 @@ function mergeByAlias(rows) {
|
|
|
33
44
|
return [
|
|
34
45
|
first?.producer ?? '',
|
|
35
46
|
first?.alias ?? '',
|
|
47
|
+
join((r) => observedCell(r.observedModel, r.modelVerified, r.modelMatch)),
|
|
36
48
|
join((r) => protocolLabel(r.protocol), ', '),
|
|
37
49
|
join((r) => r.status),
|
|
38
50
|
join((r) => String(r.maxConcurrentUsers)),
|
|
@@ -44,13 +56,16 @@ function mergeByAlias(rows) {
|
|
|
44
56
|
});
|
|
45
57
|
}
|
|
46
58
|
/** The offering table every CLI renders — same column spec as hub status and
|
|
47
|
-
* producer list (locked together by a cross-CLI test in apps/hub/test).
|
|
59
|
+
* producer list (locked together by a cross-CLI test in apps/hub/test).
|
|
60
|
+
* OBSERVED MODEL is what the upstream itself served: a '✗' marks a
|
|
61
|
+
* declaration that doesn't hold. */
|
|
48
62
|
export function renderCatalog(rows) {
|
|
49
63
|
if (rows.length === 0)
|
|
50
64
|
return 'no offerings on this hub yet';
|
|
51
65
|
return formatTable([
|
|
52
66
|
'PRODUCER',
|
|
53
67
|
'ALIAS',
|
|
68
|
+
'OBSERVED MODEL',
|
|
54
69
|
'PROTOCOL',
|
|
55
70
|
'STATUS',
|
|
56
71
|
'MAX USERS',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table.js","sourceRoot":"","sources":["../src/table.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,OAAO,
|
|
1
|
+
{"version":3,"file":"table.js","sourceRoot":"","sources":["../src/table.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,OAAO,EAAwB,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEvE,mDAAmD;AACnD,MAAM,UAAU,WAAW,CAAC,OAAiB,EAAE,IAAgB;IAC7D,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;IAC/F,MAAM,IAAI,GAAG,CAAC,KAAe,EAAU,EAAE,CACvC,KAAK;SACF,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;SACvC,IAAI,CAAC,IAAI,CAAC;SACV,OAAO,EAAE,CAAA;IACd,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACtD,CAAC;AA0BD;;;gFAGgF;AAChF,MAAM,UAAU,aAAa,CAAC,IAAkB,EAAE,GAAY;IAC5D,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAA;AAC1F,CAAC;AAED;;4EAE4E;AAC5E,MAAM,UAAU,YAAY,CAC1B,aAAwC,EACxC,aAAyC,EACzC,UAAmC;IAEnC,IAAI,aAAa,KAAK,SAAS,IAAI,aAAa,KAAK,IAAI;QAAE,OAAO,GAAG,CAAA;IACrE,IAAI,UAAU,KAAK,UAAU,IAAI,aAAa,KAAK,KAAK;QAAE,OAAO,GAAG,aAAa,IAAI,CAAA;IACrF,OAAO,UAAU,KAAK,cAAc,CAAC,CAAC,CAAC,GAAG,aAAa,IAAI,CAAC,CAAC,CAAC,aAAa,CAAA;AAC7E,CAAC;AAED;;;oDAGoD;AACpD,SAAS,YAAY,CAAC,IAAkB;IACtC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAwB,CAAA;IAC9C,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,KAAK,EAAE,CAAA;QAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAA;QAClC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACd,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IACvB,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;QACrB,MAAM,IAAI,GAAG,CAAC,IAA+B,EAAE,GAAG,GAAG,GAAG,EAAU,EAAE,CAClE,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACxC,OAAO;YACL,KAAK,EAAE,QAAQ,IAAI,EAAE;YACrB,KAAK,EAAE,KAAK,IAAI,EAAE;YAClB,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC;YACzE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC;YAC5C,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;YACrB,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC;YACzC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,kBAAkB,EAAE,CAAC,CAAC;YAC7F,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,qBAAqB,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC;YAC5F,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;YAChE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CACT,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,eAAe,CAAC,CAAC,CACnF;SACF,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;;oCAGoC;AACpC,MAAM,UAAU,aAAa,CAAC,IAAkB;IAC9C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,8BAA8B,CAAA;IAC5D,OAAO,WAAW,CAChB;QACE,UAAU;QACV,OAAO;QACP,gBAAgB;QAChB,UAAU;QACV,QAAQ;QACR,WAAW;QACX,QAAQ;QACR,UAAU;QACV,cAAc;QACd,WAAW;KACZ,EACD,YAAY,CAAC,IAAI,CAAC,CACnB,CAAA;AACH,CAAC"}
|
package/apps/hub/dist/admin.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type Database from 'better-sqlite3';
|
|
2
2
|
import type { Logger } from 'pino';
|
|
3
3
|
import type { AuthContext } from './auth.js';
|
|
4
|
+
import { type ModelWatch } from './consumer.js';
|
|
4
5
|
import { type Router } from './http.js';
|
|
5
6
|
import type { AliasSlots, AliasUsers } from './limiter.js';
|
|
6
7
|
import type { LocalProducer } from './local.js';
|
|
@@ -15,6 +16,7 @@ export interface AdminDeps {
|
|
|
15
16
|
* view reports in-flight occupancy from it. */
|
|
16
17
|
slots: AliasSlots;
|
|
17
18
|
users: AliasUsers;
|
|
19
|
+
watch: Pick<ModelWatch, 'reset'>;
|
|
18
20
|
}
|
|
19
21
|
/** Audit and governance: rosters, usage, per-consumer limits. Admission is
|
|
20
22
|
* invite-only — see invites.ts; every identity therefore carries an invite
|
package/apps/hub/dist/admin.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { roleForToken } from '../../../packages/protocol/dist/index.js';
|
|
2
2
|
import { requireAdmin, requireConsumer, requireProducer } from './auth.js';
|
|
3
3
|
import { offeringView, serializeOffering } from './consumer.js';
|
|
4
|
-
import { getConsumerByName, getProducerByName, LOCAL_PRODUCER_ID, listOfferings, listTokens, queryUsage, setConsumerConfig, summarizeUsage, } from './db.js';
|
|
4
|
+
import { blockOffering, getConsumerByName, getProducerByName, LOCAL_PRODUCER_ID, listOfferings, listOfferingsByAlias, listTokens, queryUsage, restoreOffering, setConsumerConfig, summarizeUsage, } from './db.js';
|
|
5
5
|
import { extractCredential, HttpError, readJson, sendJson } from './http.js';
|
|
6
6
|
import { parseLimits, safeParseLimits } from './limits.js';
|
|
7
7
|
/** Audit and governance: rosters, usage, per-consumer limits. Admission is
|
|
@@ -29,6 +29,18 @@ export function registerAdminRoutes(router, deps) {
|
|
|
29
29
|
throw new HttpError(404, 'ALIAS_NOT_FOUND', `unknown producer: ${name}`);
|
|
30
30
|
return producer.id;
|
|
31
31
|
};
|
|
32
|
+
/** ?alias=ns/model for the block/restore endpoints — required, and it must
|
|
33
|
+
* name a registered offering (0 protocol rows = unknown alias). */
|
|
34
|
+
const offeringAliasFromQuery = (query) => {
|
|
35
|
+
const alias = query.get('alias');
|
|
36
|
+
if (!alias) {
|
|
37
|
+
throw new HttpError(400, 'ALIAS_REQUIRED', 'query parameter alias is required (ns/model)');
|
|
38
|
+
}
|
|
39
|
+
if (listOfferingsByAlias(db, alias).length === 0) {
|
|
40
|
+
throw new HttpError(404, 'ALIAS_NOT_FOUND', `unknown offering alias: ${alias}`);
|
|
41
|
+
}
|
|
42
|
+
return alias;
|
|
43
|
+
};
|
|
32
44
|
router.add('GET', '/admin/v1/tokens', (ctx) => {
|
|
33
45
|
requireAdmin(ctx.req, auth);
|
|
34
46
|
const { producers, consumers } = listTokens(db);
|
|
@@ -60,6 +72,26 @@ export function registerAdminRoutes(router, deps) {
|
|
|
60
72
|
requireAdmin(ctx.req, auth);
|
|
61
73
|
sendJson(ctx.res, 200, offeringsPayload(deps));
|
|
62
74
|
});
|
|
75
|
+
// The per-alias scalpel between "do nothing" and revoking the whole
|
|
76
|
+
// producer: block one offering (every protocol row of the alias) and its
|
|
77
|
+
// requests fail with 503 OFFERING_BLOCKED while the producer's honest
|
|
78
|
+
// offerings keep serving. Reversible. The alias rides the query string —
|
|
79
|
+
// it contains a '/', which path params can't carry.
|
|
80
|
+
router.add('POST', '/admin/v1/offerings/block', (ctx) => {
|
|
81
|
+
requireAdmin(ctx.req, auth);
|
|
82
|
+
const alias = offeringAliasFromQuery(ctx.query);
|
|
83
|
+
const rows = blockOffering(db, alias, 'manual');
|
|
84
|
+
deps.log.info({ alias, rows }, 'offering blocked (operator)');
|
|
85
|
+
sendJson(ctx.res, 200, { alias, blocked: true, offerings: rows });
|
|
86
|
+
});
|
|
87
|
+
router.add('POST', '/admin/v1/offerings/restore', (ctx) => {
|
|
88
|
+
requireAdmin(ctx.req, auth);
|
|
89
|
+
const alias = offeringAliasFromQuery(ctx.query);
|
|
90
|
+
const rows = restoreOffering(db, alias);
|
|
91
|
+
deps.watch.reset(alias);
|
|
92
|
+
deps.log.info({ alias, rows }, 'offering restored (operator)');
|
|
93
|
+
sendJson(ctx.res, 200, { alias, blocked: false, offerings: rows });
|
|
94
|
+
});
|
|
63
95
|
// Detail log and aggregate summary share the same slice semantics: admin
|
|
64
96
|
// sees everything, a producer key its own registrations, a consumer key its
|
|
65
97
|
// own requests. Rows carry joined consumer/producer names so callers never
|