feat(cli): add pic docs/dead-letters ls group read mirrors
Two read-only operator surfaces existed server-side but the CLI was app-only:
- `pic dead-letters ls --group <slug>` — mirrors the app listing onto a group's
shared-queue dead-letters (§11.6 D3, `GET /groups/{id}/dead-letters`), via the
existing `require_one_owner`/`OwnerRef` dispatch. List-only (show/replay/
resolve stay app-only, matching the server's operator surface); a group DL row
shows its `collection` and carries no trigger, so it renders its own columns.
- `pic docs ls/get --group <slug>` — a new `Docs` command (`cmds/docs.rs`)
wrapping `GET /groups/{id}/docs[/{collection}/{id}]`, mirroring `pic kv`.
Group-only: per-app docs have no admin read route yet (unlike kv/files), so
there is no `--app` variant — noted for a later pass.
Read-only by design (writes go through the SDK). New client methods +
`GroupDocsListDto`/`GroupDeadLetterDto`. Pinned by a new
`operator_reads_shared_docs_and_group_dead_letters_via_cli` journey
(152/152 pass).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1318,6 +1318,64 @@ impl Client {
|
||||
Ok(wrapped.value)
|
||||
}
|
||||
|
||||
/// §11.6: a group's shared-docs collection (operator read).
|
||||
/// `GET /api/v1/admin/groups/{id_or_slug}/docs?collection=…&limit=…`
|
||||
pub async fn group_docs_list(
|
||||
&self,
|
||||
group: &str,
|
||||
collection: &str,
|
||||
limit: u32,
|
||||
) -> Result<GroupDocsListDto> {
|
||||
let (group, collection) = (seg(group), seg(collection));
|
||||
let resp = self
|
||||
.request(
|
||||
Method::GET,
|
||||
&format!("/api/v1/admin/groups/{group}/docs?collection={collection}&limit={limit}"),
|
||||
)
|
||||
.send()
|
||||
.await?;
|
||||
decode(resp).await
|
||||
}
|
||||
|
||||
/// `GET /api/v1/admin/groups/{id_or_slug}/docs/{collection}/{doc_id}`
|
||||
pub async fn group_docs_get(
|
||||
&self,
|
||||
group: &str,
|
||||
collection: &str,
|
||||
doc_id: &str,
|
||||
) -> Result<Value> {
|
||||
let (group, collection, doc_id) = (seg(group), seg(collection), seg(doc_id));
|
||||
let resp = self
|
||||
.request(
|
||||
Method::GET,
|
||||
&format!("/api/v1/admin/groups/{group}/docs/{collection}/{doc_id}"),
|
||||
)
|
||||
.send()
|
||||
.await?;
|
||||
decode(resp).await
|
||||
}
|
||||
|
||||
/// §11.6 D3: a group's shared-queue dead-letters (operator read; list-only).
|
||||
/// `GET /api/v1/admin/groups/{id_or_slug}/dead-letters?unresolved=…&limit=…`
|
||||
pub async fn group_dead_letters_list(
|
||||
&self,
|
||||
group: &str,
|
||||
unresolved: bool,
|
||||
limit: u32,
|
||||
) -> Result<Vec<GroupDeadLetterDto>> {
|
||||
let group = seg(group);
|
||||
let resp = self
|
||||
.request(
|
||||
Method::GET,
|
||||
&format!(
|
||||
"/api/v1/admin/groups/{group}/dead-letters?unresolved={unresolved}&limit={limit}"
|
||||
),
|
||||
)
|
||||
.send()
|
||||
.await?;
|
||||
decode(resp).await
|
||||
}
|
||||
|
||||
// --- Queues (G2, read-only admin surface) -----------------------------
|
||||
|
||||
/// `GET /api/v1/admin/apps/{id_or_slug}/queues`
|
||||
@@ -2344,6 +2402,37 @@ pub struct KvListPageDto {
|
||||
pub next_cursor: Option<String>,
|
||||
}
|
||||
|
||||
/// One document in a group's shared-docs collection (operator listing). The
|
||||
/// server also sends each doc's `data`, but the `ls` view shows ids only (fetch
|
||||
/// a document's body with `pic docs get`), so it is not deserialized here.
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct GroupDocEntryDto {
|
||||
pub id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct GroupDocsListDto {
|
||||
pub docs: Vec<GroupDocEntryDto>,
|
||||
pub next_cursor: Option<String>,
|
||||
}
|
||||
|
||||
/// One group shared-queue dead-letter (operator listing). Distinct from the
|
||||
/// per-app `DeadLetterDto`: a group DL carries no `app_id`/`trigger_id` and
|
||||
/// includes the `collection` it belonged to; timestamps are RFC3339 strings.
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct GroupDeadLetterDto {
|
||||
pub id: String,
|
||||
pub collection: String,
|
||||
pub source: String,
|
||||
pub op: String,
|
||||
pub attempt_count: u32,
|
||||
pub last_error: String,
|
||||
pub created_at: String,
|
||||
pub resolved_at: Option<String>,
|
||||
#[allow(dead_code)]
|
||||
pub payload: Value,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct KvGetResponse {
|
||||
value: Value,
|
||||
|
||||
Reference in New Issue
Block a user