@shipeasy/openapi 3.1.0 → 3.3.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 +1 -1
- package/dist/{chunk-V4ZESAIF.js → chunk-75Z4SQOM.js} +141 -1
- package/dist/chunk-75Z4SQOM.js.map +1 -0
- package/dist/{chunk-UV333BIK.js → chunk-ZYK74ZIW.js} +569 -119
- package/dist/chunk-ZYK74ZIW.js.map +1 -0
- package/dist/{client-yqGYju-M.d.ts → client-DAGqRpF1.d.ts} +2209 -401
- package/dist/client.d.ts +1 -1
- package/dist/client.js +33 -1
- package/dist/custom.d.ts +5 -5
- package/dist/custom.js +128 -84
- package/dist/custom.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +34 -2
- package/dist/index.js.map +1 -1
- package/dist/schemas.d.ts +2007 -891
- package/dist/schemas.js +179 -1
- package/openapi-sdk.json +1769 -0
- package/openapi.json +5861 -2597
- package/openapi.yaml +2739 -452
- package/package.json +6 -4
- package/spec/components/responses.yaml +39 -0
- package/spec/components/schemas/alert-rules.yaml +405 -7
- package/spec/components/schemas/alerts.yaml +9 -7
- package/spec/components/schemas/common.yaml +2 -2
- package/spec/components/schemas/connectors.yaml +69 -6
- package/spec/components/schemas/events.yaml +20 -9
- package/spec/components/schemas/gates.yaml +87 -0
- package/spec/components/schemas/keys.yaml +32 -2
- package/spec/components/schemas/killswitches.yaml +64 -0
- package/spec/components/schemas/metrics.yaml +131 -251
- package/spec/components/schemas/ops.yaml +555 -22
- package/spec/components/schemas/projects.yaml +18 -0
- package/spec/components/schemas/tags.yaml +91 -0
- package/spec/openapi-sdk.yaml +86 -0
- package/spec/openapi.yaml +61 -0
- package/spec/paths/alerts.yaml +5 -3
- package/spec/paths/gates.yaml +282 -0
- package/spec/paths/i18n.yaml +2 -1
- package/spec/paths/keys.yaml +79 -0
- package/spec/paths/killswitches.yaml +96 -0
- package/spec/paths/metrics.yaml +26 -17
- package/spec/paths/ops.yaml +566 -10
- package/spec/paths/tags.yaml +270 -0
- package/dist/chunk-UV333BIK.js.map +0 -1
- package/dist/chunk-V4ZESAIF.js.map +0 -1
|
@@ -171,6 +171,12 @@ GetCurrentProjectResponse:
|
|
|
171
171
|
- type: boolean
|
|
172
172
|
- type: number
|
|
173
173
|
description: Whether key-authenticated public ticket creation (`POST /cli/report`) is allowed into this project. Off by default.
|
|
174
|
+
errorAutocloseDays:
|
|
175
|
+
type: integer
|
|
176
|
+
description: Days an `open` tracked error may go unseen before the nightly sweep auto-resolves it. `0` disables auto-close for this project. Ingest reopens a resolved error the moment it recurs, so this never hides a live issue.
|
|
177
|
+
errorTicketMinOccurrences:
|
|
178
|
+
type: integer
|
|
179
|
+
description: Occurrence count a tracked error must cross before an `error` ticket is auto-filed into the ops queue. Customising it requires a paid plan; unentitled projects always run at the platform default of 10.
|
|
174
180
|
stripeSubscriptionId:
|
|
175
181
|
anyOf:
|
|
176
182
|
- type: string
|
|
@@ -250,6 +256,8 @@ GetCurrentProjectResponse:
|
|
|
250
256
|
- moduleUser
|
|
251
257
|
- moduleEvents
|
|
252
258
|
- allowPublicTickets
|
|
259
|
+
- errorAutocloseDays
|
|
260
|
+
- errorTicketMinOccurrences
|
|
253
261
|
- slug
|
|
254
262
|
- logo
|
|
255
263
|
- defaultEnv
|
|
@@ -462,5 +470,15 @@ UpdateProjectRequest:
|
|
|
462
470
|
minimum: 0.0001
|
|
463
471
|
maximum: 0.05
|
|
464
472
|
description: SRM chi-square p-value below which the run is called invalid.
|
|
473
|
+
errorAutocloseDays:
|
|
474
|
+
type: integer
|
|
475
|
+
minimum: 0
|
|
476
|
+
maximum: 365
|
|
477
|
+
description: Days an `open` tracked error may go unseen before the nightly sweep auto-resolves it. `0` disables auto-close for this project.
|
|
478
|
+
errorTicketMinOccurrences:
|
|
479
|
+
type: integer
|
|
480
|
+
minimum: 1
|
|
481
|
+
maximum: 10000
|
|
482
|
+
description: Occurrence count a tracked error must cross before an `error` ticket is auto-filed into the ops queue. Requires a paid plan — the request is rejected with 403 on a plan without the `ops_auto_error_issues` entitlement.
|
|
465
483
|
additionalProperties: false
|
|
466
484
|
description: "Body for `PATCH /api/admin/projects/{id}`. Partial — every field is optional; only supplied fields change. The project id in the path must match the caller's own project."
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
TaggableEntityType:
|
|
2
|
+
type: string
|
|
3
|
+
enum:
|
|
4
|
+
- ops
|
|
5
|
+
- flag
|
|
6
|
+
- config
|
|
7
|
+
- killswitch
|
|
8
|
+
- metric
|
|
9
|
+
- error
|
|
10
|
+
- alert_rule
|
|
11
|
+
- experiment
|
|
12
|
+
description: >-
|
|
13
|
+
The kind of item a tag set hangs off: `ops` (any queue item — bug, feature
|
|
14
|
+
request, error/alert/measure-plan ticket), `flag` (feature gate), `config`
|
|
15
|
+
(dynamic config), `killswitch`, `metric`, `error` (tracked error group),
|
|
16
|
+
`alert_rule`, or `experiment`.
|
|
17
|
+
TagName:
|
|
18
|
+
type: string
|
|
19
|
+
minLength: 1
|
|
20
|
+
maxLength: 64
|
|
21
|
+
description: A tag name. Trimmed; matched case-insensitively against the project's existing tags.
|
|
22
|
+
Tag:
|
|
23
|
+
type: object
|
|
24
|
+
properties:
|
|
25
|
+
id:
|
|
26
|
+
type: string
|
|
27
|
+
description: Stable opaque tag id.
|
|
28
|
+
name:
|
|
29
|
+
type: string
|
|
30
|
+
description: Display name — also the tag's identity, unique case-insensitively within the project.
|
|
31
|
+
required:
|
|
32
|
+
- id
|
|
33
|
+
- name
|
|
34
|
+
additionalProperties: false
|
|
35
|
+
ListTagsResponse:
|
|
36
|
+
type: array
|
|
37
|
+
items:
|
|
38
|
+
$ref: "#/Tag"
|
|
39
|
+
description: The project's tags, sorted by name.
|
|
40
|
+
EntityTagsResponse:
|
|
41
|
+
type: object
|
|
42
|
+
properties:
|
|
43
|
+
entityType:
|
|
44
|
+
$ref: "#/TaggableEntityType"
|
|
45
|
+
entityId:
|
|
46
|
+
type: string
|
|
47
|
+
description: The item's canonical id (the handle you passed, resolved).
|
|
48
|
+
tags:
|
|
49
|
+
type: array
|
|
50
|
+
items:
|
|
51
|
+
type: string
|
|
52
|
+
description: The tag names now attached to the item, sorted by name.
|
|
53
|
+
required:
|
|
54
|
+
- entityType
|
|
55
|
+
- entityId
|
|
56
|
+
- tags
|
|
57
|
+
additionalProperties: false
|
|
58
|
+
SetEntityTagsRequest:
|
|
59
|
+
type: object
|
|
60
|
+
properties:
|
|
61
|
+
tags:
|
|
62
|
+
type: array
|
|
63
|
+
maxItems: 50
|
|
64
|
+
items:
|
|
65
|
+
$ref: "#/TagName"
|
|
66
|
+
description: >-
|
|
67
|
+
The complete tag set the item should carry — tags not listed are
|
|
68
|
+
detached. Names are get-or-created (a new name mints a project tag),
|
|
69
|
+
deduped case-insensitively; `[]` clears every tag.
|
|
70
|
+
required:
|
|
71
|
+
- tags
|
|
72
|
+
additionalProperties: false
|
|
73
|
+
UpdateEntityTagsRequest:
|
|
74
|
+
type: object
|
|
75
|
+
properties:
|
|
76
|
+
add:
|
|
77
|
+
type: array
|
|
78
|
+
maxItems: 50
|
|
79
|
+
items:
|
|
80
|
+
$ref: "#/TagName"
|
|
81
|
+
default: []
|
|
82
|
+
description: Tag names to attach (get-or-created by name, case-insensitive). Already-attached names are a no-op.
|
|
83
|
+
remove:
|
|
84
|
+
type: array
|
|
85
|
+
maxItems: 50
|
|
86
|
+
items:
|
|
87
|
+
$ref: "#/TagName"
|
|
88
|
+
default: []
|
|
89
|
+
description: Tag names to detach (case-insensitive). Names the item doesn't carry are a no-op. A name in both lists is removed.
|
|
90
|
+
additionalProperties: false
|
|
91
|
+
description: Incremental tag edit — pass `add`, `remove`, or both. Every other tag on the item is left as is.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# The SERVER-SDK surface of the admin API — a second root over the same
|
|
2
|
+
# `paths/` and `components/schemas/` tree that `openapi.yaml` bundles.
|
|
3
|
+
#
|
|
4
|
+
# WHY A SECOND ROOT. The CLI and MCP consume the FULL spec (127 operations);
|
|
5
|
+
# the published server SDKs ship a deliberately tiny opt-in `AdminClient`, and
|
|
6
|
+
# vendoring the whole contract into eight repos bloated each generated client
|
|
7
|
+
# into the megabytes for operations nobody called. This file IS that smaller
|
|
8
|
+
# contract, declared rather than derived: `paths` below lists exactly the
|
|
9
|
+
# operations the SDKs expose, and `redocly bundle` pulls in only the schemas
|
|
10
|
+
# those operations transitively reference.
|
|
11
|
+
#
|
|
12
|
+
# WHY IT'S EXACT. Every path listed here is a dedicated, single-purpose route,
|
|
13
|
+
# so a path item never drags in a method the SDK shouldn't have. That is the
|
|
14
|
+
# reason the SDK-facing endpoints were built as their own paths instead of
|
|
15
|
+
# extra query/discriminator modes on the generic CRUD routes.
|
|
16
|
+
#
|
|
17
|
+
# ADDING AN OPERATION is one `$ref` here — then `pnpm gen` in this package and
|
|
18
|
+
# `pnpm sdk:spec:regen` in the monorepo, and commit the regenerated client
|
|
19
|
+
# inside each SDK submodule. A monorepo pre-commit hook blocks any commit that
|
|
20
|
+
# changes this contract while a vendored copy is stale.
|
|
21
|
+
#
|
|
22
|
+
# DELIBERATELY ABSENT, so nobody re-adds them by accident: everything else.
|
|
23
|
+
# Listing, generic CRUD, key minting, projects, connectors, i18n, errors,
|
|
24
|
+
# alerts, metrics, events, experiments, universes, templates, attributes, and
|
|
25
|
+
# the AI-agent working seam (ack / link-pr / investigations) all stay reachable
|
|
26
|
+
# through the CLI and MCP, which read `openapi.yaml`.
|
|
27
|
+
openapi: 3.2.0
|
|
28
|
+
info:
|
|
29
|
+
title: Shipeasy Admin API (server-SDK surface)
|
|
30
|
+
version: 2.0.0
|
|
31
|
+
description: |-
|
|
32
|
+
The slice of the Shipeasy admin API that the published server SDKs expose as their optional `AdminClient`. Authenticate with an admin SDK key (`Authorization: Bearer sdk_admin_…`) and scope every request to a project via the `X-Project-Id` header.
|
|
33
|
+
|
|
34
|
+
Three capabilities, nothing else:
|
|
35
|
+
|
|
36
|
+
- **File a public ticket** — a bug or a feature request onto the project's ops queue.
|
|
37
|
+
- **Toggle a kill switch** — flip the switch itself, or one of its named sub-switches, on one environment.
|
|
38
|
+
- **Manage a flag's whitelist** — read, replace, add to, or remove from the allowlist that admits specific identities ahead of every targeting rule.
|
|
39
|
+
|
|
40
|
+
Everything else in the admin API is reachable through the Shipeasy CLI and MCP server, which speak the complete contract (`openapi.yaml`).
|
|
41
|
+
contact:
|
|
42
|
+
name: Shipeasy
|
|
43
|
+
url: https://shipeasy.ai
|
|
44
|
+
license:
|
|
45
|
+
name: Proprietary
|
|
46
|
+
identifier: LicenseRef-Proprietary
|
|
47
|
+
servers:
|
|
48
|
+
- url: https://shipeasy.ai
|
|
49
|
+
description: Production
|
|
50
|
+
- url: http://localhost:3000
|
|
51
|
+
description: Local Next.js dev server
|
|
52
|
+
security:
|
|
53
|
+
- bearerSdkKey: []
|
|
54
|
+
tags:
|
|
55
|
+
- name: Flags
|
|
56
|
+
description: A feature gate's whitelist — the always-first allowlist that admits named identities before any targeting rule or percentage rollout runs.
|
|
57
|
+
- name: Killswitch
|
|
58
|
+
description: Per-env boolean overrides for incident response. `toggle` reads the current value and publishes its opposite in one call, on the flat value or on one named sub-switch.
|
|
59
|
+
- name: Ops
|
|
60
|
+
description: The public ticket queue — filing a bug or a feature request, which also fires the project's GitHub/Slack connectors.
|
|
61
|
+
paths:
|
|
62
|
+
/ops/bug:
|
|
63
|
+
$ref: ./paths/ops.yaml#/~1ops~1bug
|
|
64
|
+
/ops/feature-request:
|
|
65
|
+
$ref: ./paths/ops.yaml#/~1ops~1feature-request
|
|
66
|
+
/api/admin/killswitches/{id}/toggle:
|
|
67
|
+
$ref: ./paths/killswitches.yaml#/~1api~1admin~1killswitches~1{id}~1toggle
|
|
68
|
+
/api/admin/gates/{id}/whitelist:
|
|
69
|
+
$ref: ./paths/gates.yaml#/~1api~1admin~1gates~1{id}~1whitelist
|
|
70
|
+
components:
|
|
71
|
+
securitySchemes:
|
|
72
|
+
bearerSdkKey:
|
|
73
|
+
type: http
|
|
74
|
+
scheme: bearer
|
|
75
|
+
bearerFormat: sdk_admin_*
|
|
76
|
+
description: 'Pass an admin SDK key as `Authorization: Bearer sdk_admin_…`. Mint via `POST /api/admin/keys` with `type: "admin"`.'
|
|
77
|
+
clientSdkKey:
|
|
78
|
+
type: apiKey
|
|
79
|
+
in: header
|
|
80
|
+
name: X-SDK-Key
|
|
81
|
+
description: |-
|
|
82
|
+
Pass a **client** SDK key as `X-SDK-Key: sdk_client_…`. Used only by the public ticket intake (`POST /ops/bug`, `POST /ops/feature-request`), which is served by the edge worker rather than the admin API.
|
|
83
|
+
|
|
84
|
+
Client keys are designed to be embedded in shipped code — a CLI, an installer, a browser bundle — so presenting one here is safe by construction: it can do nothing but file a rate-limited ticket into its own project, in a state a human must approve. It carries no read access and cannot reach any other operation in this contract.
|
|
85
|
+
|
|
86
|
+
The key must additionally carry the `tickets:public_create` scope, and its project must have public ticket creation enabled.
|
package/spec/openapi.yaml
CHANGED
|
@@ -218,6 +218,24 @@ tags:
|
|
|
218
218
|
the AI-write seam the cockpit's detail panel renders: `list` reads what a
|
|
219
219
|
previous run found, `create` appends a new record, and `update` fills in the
|
|
220
220
|
`working` run record you were handed (findings, PR, confidence) as you work.
|
|
221
|
+
- name: Questions
|
|
222
|
+
parent: Ops
|
|
223
|
+
description: |-
|
|
224
|
+
Structured questions an agent asks the team about a queue item — the
|
|
225
|
+
`AskUserQuestion` shape: a short `header`, the `question`, 2–4 `options`
|
|
226
|
+
(label + description), and `multiSelect` for checkboxes instead of radios.
|
|
227
|
+
Every question also accepts a free-text "Other" answer. Open questions sit
|
|
228
|
+
at the very top of the item's detail panel and mark the row in the queue.
|
|
229
|
+
|
|
230
|
+
**Asking.** `ask` posts 1–4 questions at once. Several agents (or several
|
|
231
|
+
runs) may have questions open on the same item at the same time.
|
|
232
|
+
|
|
233
|
+
**Getting the answer back.** `delivery: resume` (the default for a run
|
|
234
|
+
launched through a trigger connector) re-fires that same agent on the
|
|
235
|
+
item once every question its run asked is answered, continuing the same
|
|
236
|
+
run record with the answers in the prompt. `delivery: poll` (the default
|
|
237
|
+
for a live, connector-less session such as Claude Code in a terminal)
|
|
238
|
+
fires nothing — call `list` until the status reads `completed`.
|
|
221
239
|
- name: Projects
|
|
222
240
|
description: |-
|
|
223
241
|
Projects: the account-level container every other resource is scoped to.
|
|
@@ -260,6 +278,19 @@ tags:
|
|
|
260
278
|
Continue) schedule on their own surface — typically a GitHub Actions
|
|
261
279
|
`schedule:` cron running the platform's headless CLI with the shared
|
|
262
280
|
trigger prompt.
|
|
281
|
+
- name: Tags
|
|
282
|
+
description: |-
|
|
283
|
+
Tags: free-form, project-scoped labels any item can carry — queue items
|
|
284
|
+
(bugs, feature requests, error/alert tickets), flags, configs, kill
|
|
285
|
+
switches, metrics, tracked errors, alert rules, and experiments all share
|
|
286
|
+
one tag roster.
|
|
287
|
+
|
|
288
|
+
**Identity.** A tag is its name, unique case-insensitively per project. A
|
|
289
|
+
tag is born the first time it's attached — there is no separate create.
|
|
290
|
+
|
|
291
|
+
**Addressing.** An item is named by `entityType` + its handle (an ops
|
|
292
|
+
item's number, a resource's name, or any id). `set` replaces the full tag
|
|
293
|
+
set; `update` adds/removes names incrementally.
|
|
263
294
|
- name: Connectors
|
|
264
295
|
description: |-
|
|
265
296
|
Outbound integrations: the per-project destinations feedback + trigger
|
|
@@ -282,6 +313,8 @@ paths:
|
|
|
282
313
|
$ref: ./paths/gates.yaml#/~1api~1admin~1gates~1{id}~1disable
|
|
283
314
|
/api/admin/gates/{id}/activity:
|
|
284
315
|
$ref: ./paths/gates.yaml#/~1api~1admin~1gates~1{id}~1activity
|
|
316
|
+
/api/admin/gates/{id}/whitelist:
|
|
317
|
+
$ref: ./paths/gates.yaml#/~1api~1admin~1gates~1{id}~1whitelist
|
|
285
318
|
/api/admin/experiments:
|
|
286
319
|
$ref: ./paths/experiments.yaml#/~1api~1admin~1experiments
|
|
287
320
|
/api/admin/experiments/{id}:
|
|
@@ -322,6 +355,8 @@ paths:
|
|
|
322
355
|
$ref: ./paths/killswitches.yaml#/~1api~1admin~1killswitches~1{id}~1switch
|
|
323
356
|
/api/admin/killswitches/{id}/value:
|
|
324
357
|
$ref: ./paths/killswitches.yaml#/~1api~1admin~1killswitches~1{id}~1value
|
|
358
|
+
/api/admin/killswitches/{id}/toggle:
|
|
359
|
+
$ref: ./paths/killswitches.yaml#/~1api~1admin~1killswitches~1{id}~1toggle
|
|
325
360
|
/api/admin/universes:
|
|
326
361
|
$ref: ./paths/universes.yaml#/~1api~1admin~1universes
|
|
327
362
|
/api/admin/universes/{id}:
|
|
@@ -352,6 +387,10 @@ paths:
|
|
|
352
387
|
$ref: ./paths/events.yaml#/~1api~1admin~1events~1{id}~1approve
|
|
353
388
|
/api/admin/ops:
|
|
354
389
|
$ref: ./paths/ops.yaml#/~1api~1admin~1ops
|
|
390
|
+
/ops/bug:
|
|
391
|
+
$ref: ./paths/ops.yaml#/~1ops~1bug
|
|
392
|
+
/ops/feature-request:
|
|
393
|
+
$ref: ./paths/ops.yaml#/~1ops~1feature-request
|
|
355
394
|
/api/admin/ops/{handle}:
|
|
356
395
|
$ref: ./paths/ops.yaml#/~1api~1admin~1ops~1{handle}
|
|
357
396
|
/api/admin/ops/{handle}/link-pr:
|
|
@@ -362,6 +401,12 @@ paths:
|
|
|
362
401
|
$ref: ./paths/ops.yaml#/~1api~1admin~1ops~1{handle}~1investigation
|
|
363
402
|
/api/admin/ops/{handle}/investigation/{investigationId}:
|
|
364
403
|
$ref: ./paths/ops.yaml#/~1api~1admin~1ops~1{handle}~1investigation~1{investigationId}
|
|
404
|
+
/api/admin/ops/{handle}/questions:
|
|
405
|
+
$ref: ./paths/ops.yaml#/~1api~1admin~1ops~1{handle}~1questions
|
|
406
|
+
/api/admin/ops/{handle}/questions/{questionId}/answer:
|
|
407
|
+
$ref: ./paths/ops.yaml#/~1api~1admin~1ops~1{handle}~1questions~1{questionId}~1answer
|
|
408
|
+
/api/admin/ops/{handle}/questions/{questionId}/cancel:
|
|
409
|
+
$ref: ./paths/ops.yaml#/~1api~1admin~1ops~1{handle}~1questions~1{questionId}~1cancel
|
|
365
410
|
/api/admin/agent-profiles:
|
|
366
411
|
$ref: ./paths/ops.yaml#/~1api~1admin~1agent-profiles
|
|
367
412
|
/api/admin/ops/{handle}/comments:
|
|
@@ -426,10 +471,16 @@ paths:
|
|
|
426
471
|
$ref: ./paths/connectors.yaml#/~1api~1admin~1connectors~1trigger
|
|
427
472
|
/api/admin/keys:
|
|
428
473
|
$ref: ./paths/keys.yaml#/~1api~1admin~1keys
|
|
474
|
+
/api/admin/keys/{id}:
|
|
475
|
+
$ref: ./paths/keys.yaml#/~1api~1admin~1keys~1{id}
|
|
429
476
|
/api/admin/keys/{id}/revoke:
|
|
430
477
|
$ref: ./paths/keys.yaml#/~1api~1admin~1keys~1{id}~1revoke
|
|
431
478
|
/api/admin/search:
|
|
432
479
|
$ref: ./paths/search.yaml#/~1api~1admin~1search
|
|
480
|
+
/api/admin/tags:
|
|
481
|
+
$ref: ./paths/tags.yaml#/~1api~1admin~1tags
|
|
482
|
+
/api/admin/tags/{entityType}/{entityId}:
|
|
483
|
+
$ref: ./paths/tags.yaml#/~1api~1admin~1tags~1{entityType}~1{entityId}
|
|
433
484
|
components:
|
|
434
485
|
securitySchemes:
|
|
435
486
|
bearerSdkKey:
|
|
@@ -437,3 +488,13 @@ components:
|
|
|
437
488
|
scheme: bearer
|
|
438
489
|
bearerFormat: sdk_admin_*
|
|
439
490
|
description: 'Pass an admin SDK key as `Authorization: Bearer sdk_admin_…`. Mint via `POST /api/admin/keys` with `type: "admin"`.'
|
|
491
|
+
clientSdkKey:
|
|
492
|
+
type: apiKey
|
|
493
|
+
in: header
|
|
494
|
+
name: X-SDK-Key
|
|
495
|
+
description: |-
|
|
496
|
+
Pass a **client** SDK key as `X-SDK-Key: sdk_client_…`. Used only by the public ticket intake (`POST /ops/bug`, `POST /ops/feature-request`), which is served by the edge worker rather than the admin API.
|
|
497
|
+
|
|
498
|
+
Client keys are designed to be embedded in shipped code — a CLI, an installer, a browser bundle — so presenting one here is safe by construction: it can do nothing but file a rate-limited ticket into its own project, in a state a human must approve. It carries no read access and cannot reach any other operation in this contract.
|
|
499
|
+
|
|
500
|
+
The key must additionally carry the `tickets:public_create` scope, and its project must have public ticket creation enabled.
|
package/spec/paths/alerts.yaml
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
description: |-
|
|
6
6
|
Returns the project's FIRED alerts as a **bare JSON array** (no pagination envelope), ordered by `createdAt desc`. Defaults to the currently-firing ones (`status=active`); pass a `status` to widen to resolved/dismissed history or `all`.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
A fired alert is an **instance** of an alert rule, and an instance IS its ops queue item — the same row `/api/admin/ops` returns with `type: "alert"`, viewed through the alert lens. One rule produces many instances over its life and at most one is open at a time: when the condition clears the instance closes, and the next firing is a NEW instance with its own id and history. That is why `severity` reads off the rule (the queue item carries it as `priority`) and why resolving the queue item and clearing the alert are one act, not two rows to keep in step.
|
|
9
|
+
|
|
10
|
+
Instances are opened only by the platform — the UI's killswitch handlers plus the worker's analysis consumer and alerts cron — never filed by hand, so this surface is list + triage (via PATCH), with no create. The rules that *define* metric-threshold alerts live at `/api/admin/alert-rules`.
|
|
9
11
|
|
|
10
12
|
**Use case:** Snapshot what is currently firing for an on-call view or the home Alerts block, or pull `status=all` to audit how a noisy rule has behaved over time.
|
|
11
13
|
tags:
|
|
@@ -89,7 +91,7 @@
|
|
|
89
91
|
description: |-
|
|
90
92
|
Triage writes on one fired alert — the only mutations this surface allows. All body fields are optional (at least one required); only the fields present are changed.
|
|
91
93
|
|
|
92
|
-
- **`status`** — flip between `active` / `resolved` / `dismissed`. `resolved` and `dismissed` stamp `resolvedAt` / `dismissedAt`; `active` re-opens and clears both.
|
|
94
|
+
- **`status`** — flip between `active` / `resolved` / `dismissed`. `resolved` and `dismissed` stamp `resolvedAt` / `dismissedAt`; `active` re-opens and clears both. These write the underlying queue item's own status (`resolved` / `wont_fix` / `open`), so clearing an alert here and resolving it in the ops queue are the same act. A cleared instance is never revived: if the condition fires again it opens a NEW instance with its own id.
|
|
93
95
|
- **`assigneeId`** — the PERSON owner (a `users.id`), or `null` to unassign.
|
|
94
96
|
- **`agent`** — the AGENT owner: a connected trigger connector's id, or the built-in `"jarvis"` (**Enterprise plan only** — `403` otherwise), or `null` to clear. Person and agent halves are independent.
|
|
95
97
|
|
|
@@ -106,7 +108,7 @@
|
|
|
106
108
|
- name: id
|
|
107
109
|
in: path
|
|
108
110
|
required: true
|
|
109
|
-
description: Stable opaque
|
|
111
|
+
description: Stable opaque instance id — the same id as the `alert` ops item this instance is.
|
|
110
112
|
schema:
|
|
111
113
|
$ref: ../components/schemas/common.yaml#/ResourceId
|
|
112
114
|
requestBody:
|
package/spec/paths/gates.yaml
CHANGED
|
@@ -601,3 +601,285 @@
|
|
|
601
601
|
name: activity
|
|
602
602
|
positional:
|
|
603
603
|
- id
|
|
604
|
+
/api/admin/gates/{id}/whitelist:
|
|
605
|
+
get:
|
|
606
|
+
operationId: getGateWhitelist
|
|
607
|
+
summary: Read a gate's whitelist
|
|
608
|
+
description: |-
|
|
609
|
+
Returns the gate's whitelist — the always-first allowlist that admits the listed identities before any targeting rule or percentage rollout is evaluated.
|
|
610
|
+
|
|
611
|
+
A gate with no whitelist returns `entries: []` (and the default `attr`), never a 404 — so a caller can read-then-write without special-casing the empty gate.
|
|
612
|
+
|
|
613
|
+
**Use case:** Check whether an account is already let through before adding it.
|
|
614
|
+
tags:
|
|
615
|
+
- Flags
|
|
616
|
+
parameters:
|
|
617
|
+
- $ref: ../components/parameters.yaml#/ProjectId
|
|
618
|
+
- name: id
|
|
619
|
+
in: path
|
|
620
|
+
required: true
|
|
621
|
+
description: Stable opaque gate id (`gate_…`) or the gate's `name`.
|
|
622
|
+
schema:
|
|
623
|
+
$ref: ../components/schemas/common.yaml#/ResourceId
|
|
624
|
+
responses:
|
|
625
|
+
"200":
|
|
626
|
+
description: Read a gate's whitelist
|
|
627
|
+
content:
|
|
628
|
+
application/json:
|
|
629
|
+
schema:
|
|
630
|
+
$ref: ../components/schemas/gates.yaml#/GetGateWhitelistResponse
|
|
631
|
+
example:
|
|
632
|
+
id: gate_01j7w8a1b2c3d4e5f6g7h8i9j0
|
|
633
|
+
name: new_checkout
|
|
634
|
+
attr: email
|
|
635
|
+
entries:
|
|
636
|
+
- alice@acme.dev
|
|
637
|
+
- bob@acme.dev
|
|
638
|
+
"400":
|
|
639
|
+
$ref: ../components/responses.yaml#/BadRequest
|
|
640
|
+
"401":
|
|
641
|
+
$ref: ../components/responses.yaml#/Unauthorized
|
|
642
|
+
"403":
|
|
643
|
+
$ref: ../components/responses.yaml#/Forbidden
|
|
644
|
+
"404":
|
|
645
|
+
$ref: ../components/responses.yaml#/NotFound
|
|
646
|
+
"409":
|
|
647
|
+
$ref: ../components/responses.yaml#/Conflict
|
|
648
|
+
"422":
|
|
649
|
+
$ref: ../components/responses.yaml#/UnprocessableEntity
|
|
650
|
+
x-error-codes:
|
|
651
|
+
- BAD_REQUEST
|
|
652
|
+
- UNAUTHORIZED
|
|
653
|
+
- FORBIDDEN
|
|
654
|
+
- NOT_FOUND
|
|
655
|
+
x-cli:
|
|
656
|
+
name: whitelist
|
|
657
|
+
positional:
|
|
658
|
+
- id
|
|
659
|
+
put:
|
|
660
|
+
operationId: setGateWhitelist
|
|
661
|
+
summary: Replace a gate's whitelist
|
|
662
|
+
description: |-
|
|
663
|
+
Replaces the gate's whole whitelist with `entries`, creating the block if the gate didn't have one. Idempotent — the same call twice leaves the same list.
|
|
664
|
+
|
|
665
|
+
This is the only whitelist call that can switch `attr` (`email` ⇄ `user_id`) or clear the block: `entries: []` removes the whitelist from the gate entirely.
|
|
666
|
+
|
|
667
|
+
**Use cases**
|
|
668
|
+
|
|
669
|
+
- **Pin an exact list** — `{ "entries": ["alice@acme.dev", "bob@acme.dev"] }`.
|
|
670
|
+
- **Switch to user ids** — `{ "attr": "user_id", "entries": ["usr_123"] }`.
|
|
671
|
+
- **Drop the whitelist** — `{ "entries": [] }`.
|
|
672
|
+
tags:
|
|
673
|
+
- Flags
|
|
674
|
+
parameters:
|
|
675
|
+
- $ref: ../components/parameters.yaml#/ProjectId
|
|
676
|
+
- name: id
|
|
677
|
+
in: path
|
|
678
|
+
required: true
|
|
679
|
+
description: Stable opaque gate id (`gate_…`) or the gate's `name`.
|
|
680
|
+
schema:
|
|
681
|
+
$ref: ../components/schemas/common.yaml#/ResourceId
|
|
682
|
+
requestBody:
|
|
683
|
+
required: true
|
|
684
|
+
content:
|
|
685
|
+
application/json:
|
|
686
|
+
schema:
|
|
687
|
+
$ref: ../components/schemas/gates.yaml#/SetGateWhitelistRequest
|
|
688
|
+
examples:
|
|
689
|
+
pinList:
|
|
690
|
+
summary: Pin an exact list of emails
|
|
691
|
+
value:
|
|
692
|
+
entries:
|
|
693
|
+
- alice@acme.dev
|
|
694
|
+
- bob@acme.dev
|
|
695
|
+
switchToUserIds:
|
|
696
|
+
summary: Re-key the whitelist onto user ids
|
|
697
|
+
description: Switching `attr` replaces the entries wholesale — the old emails are not translated.
|
|
698
|
+
value:
|
|
699
|
+
attr: user_id
|
|
700
|
+
entries:
|
|
701
|
+
- usr_01j7w8a1b2c3d4e5f6g7h8i9j0
|
|
702
|
+
clear:
|
|
703
|
+
summary: Remove the whitelist
|
|
704
|
+
description: An empty list drops the pinned block from the gate's stack.
|
|
705
|
+
value:
|
|
706
|
+
entries: []
|
|
707
|
+
responses:
|
|
708
|
+
"200":
|
|
709
|
+
description: Replace a gate's whitelist
|
|
710
|
+
content:
|
|
711
|
+
application/json:
|
|
712
|
+
schema:
|
|
713
|
+
$ref: ../components/schemas/gates.yaml#/SetGateWhitelistResponse
|
|
714
|
+
example:
|
|
715
|
+
id: gate_01j7w8a1b2c3d4e5f6g7h8i9j0
|
|
716
|
+
name: new_checkout
|
|
717
|
+
attr: email
|
|
718
|
+
entries:
|
|
719
|
+
- alice@acme.dev
|
|
720
|
+
- bob@acme.dev
|
|
721
|
+
"400":
|
|
722
|
+
$ref: ../components/responses.yaml#/BadRequest
|
|
723
|
+
"401":
|
|
724
|
+
$ref: ../components/responses.yaml#/Unauthorized
|
|
725
|
+
"403":
|
|
726
|
+
$ref: ../components/responses.yaml#/Forbidden
|
|
727
|
+
"404":
|
|
728
|
+
$ref: ../components/responses.yaml#/NotFound
|
|
729
|
+
"409":
|
|
730
|
+
$ref: ../components/responses.yaml#/Conflict
|
|
731
|
+
"422":
|
|
732
|
+
$ref: ../components/responses.yaml#/UnprocessableEntity
|
|
733
|
+
x-error-codes:
|
|
734
|
+
- BAD_REQUEST
|
|
735
|
+
- UNAUTHORIZED
|
|
736
|
+
- FORBIDDEN
|
|
737
|
+
- NOT_FOUND
|
|
738
|
+
- VALIDATION
|
|
739
|
+
x-cli:
|
|
740
|
+
name: whitelist-set
|
|
741
|
+
positional:
|
|
742
|
+
- id
|
|
743
|
+
post:
|
|
744
|
+
operationId: addToGateWhitelist
|
|
745
|
+
summary: Add entries to a gate's whitelist
|
|
746
|
+
description: |-
|
|
747
|
+
Adds identities to the gate's whitelist, creating the block if the gate doesn't have one yet. Entries already on the list are skipped, so the call is idempotent and safe to retry.
|
|
748
|
+
|
|
749
|
+
Adding to a gate that already has a whitelist keyed on the other attribute is rejected (409) rather than silently re-keying the entries already there — use `PUT` to switch `attr` deliberately.
|
|
750
|
+
|
|
751
|
+
**Use case:** Let one more customer into a private beta without reading the current list first.
|
|
752
|
+
tags:
|
|
753
|
+
- Flags
|
|
754
|
+
parameters:
|
|
755
|
+
- $ref: ../components/parameters.yaml#/ProjectId
|
|
756
|
+
- name: id
|
|
757
|
+
in: path
|
|
758
|
+
required: true
|
|
759
|
+
description: Stable opaque gate id (`gate_…`) or the gate's `name`.
|
|
760
|
+
schema:
|
|
761
|
+
$ref: ../components/schemas/common.yaml#/ResourceId
|
|
762
|
+
requestBody:
|
|
763
|
+
required: true
|
|
764
|
+
content:
|
|
765
|
+
application/json:
|
|
766
|
+
schema:
|
|
767
|
+
$ref: ../components/schemas/gates.yaml#/AddToGateWhitelistRequest
|
|
768
|
+
examples:
|
|
769
|
+
addOne:
|
|
770
|
+
summary: Admit one more email
|
|
771
|
+
value:
|
|
772
|
+
entries:
|
|
773
|
+
- carol@acme.dev
|
|
774
|
+
createOnUserIds:
|
|
775
|
+
summary: Start a whitelist keyed on user ids
|
|
776
|
+
description: "`attr` is honoured only because this gate has no whitelist yet."
|
|
777
|
+
value:
|
|
778
|
+
attr: user_id
|
|
779
|
+
entries:
|
|
780
|
+
- usr_01j7w8a1b2c3d4e5f6g7h8i9j0
|
|
781
|
+
responses:
|
|
782
|
+
"200":
|
|
783
|
+
description: Add entries to a gate's whitelist
|
|
784
|
+
content:
|
|
785
|
+
application/json:
|
|
786
|
+
schema:
|
|
787
|
+
$ref: ../components/schemas/gates.yaml#/AddToGateWhitelistResponse
|
|
788
|
+
example:
|
|
789
|
+
id: gate_01j7w8a1b2c3d4e5f6g7h8i9j0
|
|
790
|
+
name: new_checkout
|
|
791
|
+
attr: email
|
|
792
|
+
entries:
|
|
793
|
+
- alice@acme.dev
|
|
794
|
+
- bob@acme.dev
|
|
795
|
+
- carol@acme.dev
|
|
796
|
+
"400":
|
|
797
|
+
$ref: ../components/responses.yaml#/BadRequest
|
|
798
|
+
"401":
|
|
799
|
+
$ref: ../components/responses.yaml#/Unauthorized
|
|
800
|
+
"403":
|
|
801
|
+
$ref: ../components/responses.yaml#/Forbidden
|
|
802
|
+
"404":
|
|
803
|
+
$ref: ../components/responses.yaml#/NotFound
|
|
804
|
+
"409":
|
|
805
|
+
$ref: ../components/responses.yaml#/Conflict
|
|
806
|
+
"422":
|
|
807
|
+
$ref: ../components/responses.yaml#/UnprocessableEntity
|
|
808
|
+
x-error-codes:
|
|
809
|
+
- BAD_REQUEST
|
|
810
|
+
- UNAUTHORIZED
|
|
811
|
+
- FORBIDDEN
|
|
812
|
+
- NOT_FOUND
|
|
813
|
+
- IMMUTABLE_FIELD
|
|
814
|
+
- VALIDATION
|
|
815
|
+
x-cli:
|
|
816
|
+
name: whitelist-add
|
|
817
|
+
positional:
|
|
818
|
+
- id
|
|
819
|
+
delete:
|
|
820
|
+
operationId: removeFromGateWhitelist
|
|
821
|
+
summary: Remove entries from a gate's whitelist
|
|
822
|
+
description: |-
|
|
823
|
+
Removes identities from the gate's whitelist. Entries that aren't on the list are skipped, so the call is idempotent.
|
|
824
|
+
|
|
825
|
+
Removing the last entry leaves an empty whitelist block in place; to drop the block itself use `PUT` with `entries: []`.
|
|
826
|
+
|
|
827
|
+
**Use case:** Revoke one beta tester's access without touching anyone else's.
|
|
828
|
+
tags:
|
|
829
|
+
- Flags
|
|
830
|
+
parameters:
|
|
831
|
+
- $ref: ../components/parameters.yaml#/ProjectId
|
|
832
|
+
- name: id
|
|
833
|
+
in: path
|
|
834
|
+
required: true
|
|
835
|
+
description: Stable opaque gate id (`gate_…`) or the gate's `name`.
|
|
836
|
+
schema:
|
|
837
|
+
$ref: ../components/schemas/common.yaml#/ResourceId
|
|
838
|
+
requestBody:
|
|
839
|
+
required: true
|
|
840
|
+
content:
|
|
841
|
+
application/json:
|
|
842
|
+
schema:
|
|
843
|
+
$ref: ../components/schemas/gates.yaml#/RemoveFromGateWhitelistRequest
|
|
844
|
+
examples:
|
|
845
|
+
removeOne:
|
|
846
|
+
summary: Revoke one email
|
|
847
|
+
value:
|
|
848
|
+
entries:
|
|
849
|
+
- carol@acme.dev
|
|
850
|
+
responses:
|
|
851
|
+
"200":
|
|
852
|
+
description: Remove entries from a gate's whitelist
|
|
853
|
+
content:
|
|
854
|
+
application/json:
|
|
855
|
+
schema:
|
|
856
|
+
$ref: ../components/schemas/gates.yaml#/RemoveFromGateWhitelistResponse
|
|
857
|
+
example:
|
|
858
|
+
id: gate_01j7w8a1b2c3d4e5f6g7h8i9j0
|
|
859
|
+
name: new_checkout
|
|
860
|
+
attr: email
|
|
861
|
+
entries:
|
|
862
|
+
- alice@acme.dev
|
|
863
|
+
- bob@acme.dev
|
|
864
|
+
"400":
|
|
865
|
+
$ref: ../components/responses.yaml#/BadRequest
|
|
866
|
+
"401":
|
|
867
|
+
$ref: ../components/responses.yaml#/Unauthorized
|
|
868
|
+
"403":
|
|
869
|
+
$ref: ../components/responses.yaml#/Forbidden
|
|
870
|
+
"404":
|
|
871
|
+
$ref: ../components/responses.yaml#/NotFound
|
|
872
|
+
"409":
|
|
873
|
+
$ref: ../components/responses.yaml#/Conflict
|
|
874
|
+
"422":
|
|
875
|
+
$ref: ../components/responses.yaml#/UnprocessableEntity
|
|
876
|
+
x-error-codes:
|
|
877
|
+
- BAD_REQUEST
|
|
878
|
+
- UNAUTHORIZED
|
|
879
|
+
- FORBIDDEN
|
|
880
|
+
- NOT_FOUND
|
|
881
|
+
- VALIDATION
|
|
882
|
+
x-cli:
|
|
883
|
+
name: whitelist-remove
|
|
884
|
+
positional:
|
|
885
|
+
- id
|
package/spec/paths/i18n.yaml
CHANGED
|
@@ -128,11 +128,12 @@
|
|
|
128
128
|
- name: limit
|
|
129
129
|
in: query
|
|
130
130
|
required: false
|
|
131
|
-
description: Max keys to return (1–500).
|
|
131
|
+
description: Max keys to return (1–500). Defaults to 200.
|
|
132
132
|
schema:
|
|
133
133
|
type: integer
|
|
134
134
|
minimum: 1
|
|
135
135
|
maximum: 500
|
|
136
|
+
default: 200
|
|
136
137
|
- name: offset
|
|
137
138
|
in: query
|
|
138
139
|
required: false
|