@shipeasy/openapi 3.0.0 → 3.2.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/dist/{chunk-7T77D5YO.js → chunk-DW33MG4B.js} +148 -6
- package/dist/chunk-DW33MG4B.js.map +1 -0
- package/dist/{chunk-V4ZESAIF.js → chunk-RTN572TI.js} +67 -1
- package/dist/chunk-RTN572TI.js.map +1 -0
- package/dist/{client-DzEqdN5N.d.ts → client-BPVn4hMC.d.ts} +692 -8
- package/dist/client.d.ts +1 -1
- package/dist/client.js +15 -1
- package/dist/custom.js +2 -1
- package/dist/custom.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +16 -2
- package/dist/index.js.map +1 -1
- package/dist/schemas.d.ts +383 -55
- package/dist/schemas.js +67 -1
- package/openapi-sdk.json +1747 -0
- package/openapi.json +1489 -185
- package/openapi.yaml +926 -9
- package/package.json +6 -4
- package/spec/components/responses.yaml +39 -0
- package/spec/components/schemas/gates.yaml +87 -0
- package/spec/components/schemas/keys.yaml +2 -2
- package/spec/components/schemas/killswitches.yaml +64 -0
- package/spec/components/schemas/ops.yaml +206 -22
- package/spec/openapi-sdk.yaml +86 -0
- package/spec/openapi.yaml +18 -0
- package/spec/paths/gates.yaml +282 -0
- package/spec/paths/killswitches.yaml +96 -0
- package/spec/paths/ops.yaml +182 -3
- package/dist/chunk-7T77D5YO.js.map +0 -1
- package/dist/chunk-V4ZESAIF.js.map +0 -1
package/openapi.yaml
CHANGED
|
@@ -877,6 +877,288 @@ paths:
|
|
|
877
877
|
name: activity
|
|
878
878
|
positional:
|
|
879
879
|
- id
|
|
880
|
+
/api/admin/gates/{id}/whitelist:
|
|
881
|
+
get:
|
|
882
|
+
operationId: getGateWhitelist
|
|
883
|
+
summary: Read a gate's whitelist
|
|
884
|
+
description: |-
|
|
885
|
+
Returns the gate's whitelist — the always-first allowlist that admits the listed identities before any targeting rule or percentage rollout is evaluated.
|
|
886
|
+
|
|
887
|
+
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.
|
|
888
|
+
|
|
889
|
+
**Use case:** Check whether an account is already let through before adding it.
|
|
890
|
+
tags:
|
|
891
|
+
- Flags
|
|
892
|
+
parameters:
|
|
893
|
+
- $ref: '#/components/parameters/ProjectId'
|
|
894
|
+
- name: id
|
|
895
|
+
in: path
|
|
896
|
+
required: true
|
|
897
|
+
description: Stable opaque gate id (`gate_…`) or the gate's `name`.
|
|
898
|
+
schema:
|
|
899
|
+
$ref: '#/components/schemas/ResourceId'
|
|
900
|
+
responses:
|
|
901
|
+
'200':
|
|
902
|
+
description: Read a gate's whitelist
|
|
903
|
+
content:
|
|
904
|
+
application/json:
|
|
905
|
+
schema:
|
|
906
|
+
$ref: '#/components/schemas/GateWhitelist'
|
|
907
|
+
example:
|
|
908
|
+
id: gate_01j7w8a1b2c3d4e5f6g7h8i9j0
|
|
909
|
+
name: new_checkout
|
|
910
|
+
attr: email
|
|
911
|
+
entries:
|
|
912
|
+
- alice@acme.dev
|
|
913
|
+
- bob@acme.dev
|
|
914
|
+
'400':
|
|
915
|
+
$ref: '#/components/responses/BadRequest'
|
|
916
|
+
'401':
|
|
917
|
+
$ref: '#/components/responses/Unauthorized'
|
|
918
|
+
'403':
|
|
919
|
+
$ref: '#/components/responses/Forbidden'
|
|
920
|
+
'404':
|
|
921
|
+
$ref: '#/components/responses/NotFound'
|
|
922
|
+
'409':
|
|
923
|
+
$ref: '#/components/responses/Conflict'
|
|
924
|
+
'422':
|
|
925
|
+
$ref: '#/components/responses/UnprocessableEntity'
|
|
926
|
+
x-error-codes:
|
|
927
|
+
- BAD_REQUEST
|
|
928
|
+
- UNAUTHORIZED
|
|
929
|
+
- FORBIDDEN
|
|
930
|
+
- NOT_FOUND
|
|
931
|
+
x-cli:
|
|
932
|
+
name: whitelist
|
|
933
|
+
positional:
|
|
934
|
+
- id
|
|
935
|
+
put:
|
|
936
|
+
operationId: setGateWhitelist
|
|
937
|
+
summary: Replace a gate's whitelist
|
|
938
|
+
description: |-
|
|
939
|
+
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.
|
|
940
|
+
|
|
941
|
+
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.
|
|
942
|
+
|
|
943
|
+
**Use cases**
|
|
944
|
+
|
|
945
|
+
- **Pin an exact list** — `{ "entries": ["alice@acme.dev", "bob@acme.dev"] }`.
|
|
946
|
+
- **Switch to user ids** — `{ "attr": "user_id", "entries": ["usr_123"] }`.
|
|
947
|
+
- **Drop the whitelist** — `{ "entries": [] }`.
|
|
948
|
+
tags:
|
|
949
|
+
- Flags
|
|
950
|
+
parameters:
|
|
951
|
+
- $ref: '#/components/parameters/ProjectId'
|
|
952
|
+
- name: id
|
|
953
|
+
in: path
|
|
954
|
+
required: true
|
|
955
|
+
description: Stable opaque gate id (`gate_…`) or the gate's `name`.
|
|
956
|
+
schema:
|
|
957
|
+
$ref: '#/components/schemas/ResourceId'
|
|
958
|
+
requestBody:
|
|
959
|
+
required: true
|
|
960
|
+
content:
|
|
961
|
+
application/json:
|
|
962
|
+
schema:
|
|
963
|
+
$ref: '#/components/schemas/SetGateWhitelistRequest'
|
|
964
|
+
examples:
|
|
965
|
+
pinList:
|
|
966
|
+
summary: Pin an exact list of emails
|
|
967
|
+
value:
|
|
968
|
+
entries:
|
|
969
|
+
- alice@acme.dev
|
|
970
|
+
- bob@acme.dev
|
|
971
|
+
switchToUserIds:
|
|
972
|
+
summary: Re-key the whitelist onto user ids
|
|
973
|
+
description: Switching `attr` replaces the entries wholesale — the old emails are not translated.
|
|
974
|
+
value:
|
|
975
|
+
attr: user_id
|
|
976
|
+
entries:
|
|
977
|
+
- usr_01j7w8a1b2c3d4e5f6g7h8i9j0
|
|
978
|
+
clear:
|
|
979
|
+
summary: Remove the whitelist
|
|
980
|
+
description: An empty list drops the pinned block from the gate's stack.
|
|
981
|
+
value:
|
|
982
|
+
entries: []
|
|
983
|
+
responses:
|
|
984
|
+
'200':
|
|
985
|
+
description: Replace a gate's whitelist
|
|
986
|
+
content:
|
|
987
|
+
application/json:
|
|
988
|
+
schema:
|
|
989
|
+
$ref: '#/components/schemas/GateWhitelist'
|
|
990
|
+
example:
|
|
991
|
+
id: gate_01j7w8a1b2c3d4e5f6g7h8i9j0
|
|
992
|
+
name: new_checkout
|
|
993
|
+
attr: email
|
|
994
|
+
entries:
|
|
995
|
+
- alice@acme.dev
|
|
996
|
+
- bob@acme.dev
|
|
997
|
+
'400':
|
|
998
|
+
$ref: '#/components/responses/BadRequest'
|
|
999
|
+
'401':
|
|
1000
|
+
$ref: '#/components/responses/Unauthorized'
|
|
1001
|
+
'403':
|
|
1002
|
+
$ref: '#/components/responses/Forbidden'
|
|
1003
|
+
'404':
|
|
1004
|
+
$ref: '#/components/responses/NotFound'
|
|
1005
|
+
'409':
|
|
1006
|
+
$ref: '#/components/responses/Conflict'
|
|
1007
|
+
'422':
|
|
1008
|
+
$ref: '#/components/responses/UnprocessableEntity'
|
|
1009
|
+
x-error-codes:
|
|
1010
|
+
- BAD_REQUEST
|
|
1011
|
+
- UNAUTHORIZED
|
|
1012
|
+
- FORBIDDEN
|
|
1013
|
+
- NOT_FOUND
|
|
1014
|
+
- VALIDATION
|
|
1015
|
+
x-cli:
|
|
1016
|
+
name: whitelist-set
|
|
1017
|
+
positional:
|
|
1018
|
+
- id
|
|
1019
|
+
post:
|
|
1020
|
+
operationId: addToGateWhitelist
|
|
1021
|
+
summary: Add entries to a gate's whitelist
|
|
1022
|
+
description: |-
|
|
1023
|
+
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.
|
|
1024
|
+
|
|
1025
|
+
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.
|
|
1026
|
+
|
|
1027
|
+
**Use case:** Let one more customer into a private beta without reading the current list first.
|
|
1028
|
+
tags:
|
|
1029
|
+
- Flags
|
|
1030
|
+
parameters:
|
|
1031
|
+
- $ref: '#/components/parameters/ProjectId'
|
|
1032
|
+
- name: id
|
|
1033
|
+
in: path
|
|
1034
|
+
required: true
|
|
1035
|
+
description: Stable opaque gate id (`gate_…`) or the gate's `name`.
|
|
1036
|
+
schema:
|
|
1037
|
+
$ref: '#/components/schemas/ResourceId'
|
|
1038
|
+
requestBody:
|
|
1039
|
+
required: true
|
|
1040
|
+
content:
|
|
1041
|
+
application/json:
|
|
1042
|
+
schema:
|
|
1043
|
+
$ref: '#/components/schemas/AddToGateWhitelistRequest'
|
|
1044
|
+
examples:
|
|
1045
|
+
addOne:
|
|
1046
|
+
summary: Admit one more email
|
|
1047
|
+
value:
|
|
1048
|
+
entries:
|
|
1049
|
+
- carol@acme.dev
|
|
1050
|
+
createOnUserIds:
|
|
1051
|
+
summary: Start a whitelist keyed on user ids
|
|
1052
|
+
description: '`attr` is honoured only because this gate has no whitelist yet.'
|
|
1053
|
+
value:
|
|
1054
|
+
attr: user_id
|
|
1055
|
+
entries:
|
|
1056
|
+
- usr_01j7w8a1b2c3d4e5f6g7h8i9j0
|
|
1057
|
+
responses:
|
|
1058
|
+
'200':
|
|
1059
|
+
description: Add entries to a gate's whitelist
|
|
1060
|
+
content:
|
|
1061
|
+
application/json:
|
|
1062
|
+
schema:
|
|
1063
|
+
$ref: '#/components/schemas/GateWhitelist'
|
|
1064
|
+
example:
|
|
1065
|
+
id: gate_01j7w8a1b2c3d4e5f6g7h8i9j0
|
|
1066
|
+
name: new_checkout
|
|
1067
|
+
attr: email
|
|
1068
|
+
entries:
|
|
1069
|
+
- alice@acme.dev
|
|
1070
|
+
- bob@acme.dev
|
|
1071
|
+
- carol@acme.dev
|
|
1072
|
+
'400':
|
|
1073
|
+
$ref: '#/components/responses/BadRequest'
|
|
1074
|
+
'401':
|
|
1075
|
+
$ref: '#/components/responses/Unauthorized'
|
|
1076
|
+
'403':
|
|
1077
|
+
$ref: '#/components/responses/Forbidden'
|
|
1078
|
+
'404':
|
|
1079
|
+
$ref: '#/components/responses/NotFound'
|
|
1080
|
+
'409':
|
|
1081
|
+
$ref: '#/components/responses/Conflict'
|
|
1082
|
+
'422':
|
|
1083
|
+
$ref: '#/components/responses/UnprocessableEntity'
|
|
1084
|
+
x-error-codes:
|
|
1085
|
+
- BAD_REQUEST
|
|
1086
|
+
- UNAUTHORIZED
|
|
1087
|
+
- FORBIDDEN
|
|
1088
|
+
- NOT_FOUND
|
|
1089
|
+
- IMMUTABLE_FIELD
|
|
1090
|
+
- VALIDATION
|
|
1091
|
+
x-cli:
|
|
1092
|
+
name: whitelist-add
|
|
1093
|
+
positional:
|
|
1094
|
+
- id
|
|
1095
|
+
delete:
|
|
1096
|
+
operationId: removeFromGateWhitelist
|
|
1097
|
+
summary: Remove entries from a gate's whitelist
|
|
1098
|
+
description: |-
|
|
1099
|
+
Removes identities from the gate's whitelist. Entries that aren't on the list are skipped, so the call is idempotent.
|
|
1100
|
+
|
|
1101
|
+
Removing the last entry leaves an empty whitelist block in place; to drop the block itself use `PUT` with `entries: []`.
|
|
1102
|
+
|
|
1103
|
+
**Use case:** Revoke one beta tester's access without touching anyone else's.
|
|
1104
|
+
tags:
|
|
1105
|
+
- Flags
|
|
1106
|
+
parameters:
|
|
1107
|
+
- $ref: '#/components/parameters/ProjectId'
|
|
1108
|
+
- name: id
|
|
1109
|
+
in: path
|
|
1110
|
+
required: true
|
|
1111
|
+
description: Stable opaque gate id (`gate_…`) or the gate's `name`.
|
|
1112
|
+
schema:
|
|
1113
|
+
$ref: '#/components/schemas/ResourceId'
|
|
1114
|
+
requestBody:
|
|
1115
|
+
required: true
|
|
1116
|
+
content:
|
|
1117
|
+
application/json:
|
|
1118
|
+
schema:
|
|
1119
|
+
$ref: '#/components/schemas/RemoveFromGateWhitelistRequest'
|
|
1120
|
+
examples:
|
|
1121
|
+
removeOne:
|
|
1122
|
+
summary: Revoke one email
|
|
1123
|
+
value:
|
|
1124
|
+
entries:
|
|
1125
|
+
- carol@acme.dev
|
|
1126
|
+
responses:
|
|
1127
|
+
'200':
|
|
1128
|
+
description: Remove entries from a gate's whitelist
|
|
1129
|
+
content:
|
|
1130
|
+
application/json:
|
|
1131
|
+
schema:
|
|
1132
|
+
$ref: '#/components/schemas/GateWhitelist'
|
|
1133
|
+
example:
|
|
1134
|
+
id: gate_01j7w8a1b2c3d4e5f6g7h8i9j0
|
|
1135
|
+
name: new_checkout
|
|
1136
|
+
attr: email
|
|
1137
|
+
entries:
|
|
1138
|
+
- alice@acme.dev
|
|
1139
|
+
- bob@acme.dev
|
|
1140
|
+
'400':
|
|
1141
|
+
$ref: '#/components/responses/BadRequest'
|
|
1142
|
+
'401':
|
|
1143
|
+
$ref: '#/components/responses/Unauthorized'
|
|
1144
|
+
'403':
|
|
1145
|
+
$ref: '#/components/responses/Forbidden'
|
|
1146
|
+
'404':
|
|
1147
|
+
$ref: '#/components/responses/NotFound'
|
|
1148
|
+
'409':
|
|
1149
|
+
$ref: '#/components/responses/Conflict'
|
|
1150
|
+
'422':
|
|
1151
|
+
$ref: '#/components/responses/UnprocessableEntity'
|
|
1152
|
+
x-error-codes:
|
|
1153
|
+
- BAD_REQUEST
|
|
1154
|
+
- UNAUTHORIZED
|
|
1155
|
+
- FORBIDDEN
|
|
1156
|
+
- NOT_FOUND
|
|
1157
|
+
- VALIDATION
|
|
1158
|
+
x-cli:
|
|
1159
|
+
name: whitelist-remove
|
|
1160
|
+
positional:
|
|
1161
|
+
- id
|
|
880
1162
|
/api/admin/experiments:
|
|
881
1163
|
get:
|
|
882
1164
|
operationId: listExperiments
|
|
@@ -3343,6 +3625,102 @@ paths:
|
|
|
3343
3625
|
name: set-value
|
|
3344
3626
|
positional:
|
|
3345
3627
|
- id
|
|
3628
|
+
/api/admin/killswitches/{id}/toggle:
|
|
3629
|
+
post:
|
|
3630
|
+
operationId: toggleKillswitch
|
|
3631
|
+
summary: Toggle a killswitch or one of its switches
|
|
3632
|
+
description: |-
|
|
3633
|
+
Flips a killswitch on one environment and publishes a new version there. This is the one-call incident verb: it reads the current value, flips it, and publishes, so you don't have to fetch the killswitch first.
|
|
3634
|
+
|
|
3635
|
+
Every body field is optional, which is what makes the call widen cleanly:
|
|
3636
|
+
|
|
3637
|
+
- **Flip the killswitch** — `{}`. Flips the flat `value` on `prod`.
|
|
3638
|
+
- **Flip one sub-switch** — `{ "switchKey": "eu_region" }`. Flips that entry on `prod`, creating it (from `false`) if it isn't in the map yet.
|
|
3639
|
+
- **Set it idempotently** — `{ "switchKey": "eu_region", "value": true }`. Publishes exactly that value, so a retried call can't undo the first one. A `null` `value` means "flip", not "set to null".
|
|
3640
|
+
- **Choose the environment** — add `"env": "staging"`. Omitted, `env` is `prod`.
|
|
3641
|
+
|
|
3642
|
+
The response reports both `previous` and `value`, so a caller that asked for a flip can see what it actually changed.
|
|
3643
|
+
|
|
3644
|
+
Prefer this over `PUT /{id}/value` and `PUT /{id}/switch` unless you specifically need those endpoints' unconditional set semantics.
|
|
3645
|
+
tags:
|
|
3646
|
+
- Killswitch
|
|
3647
|
+
parameters:
|
|
3648
|
+
- $ref: '#/components/parameters/ProjectId'
|
|
3649
|
+
- name: id
|
|
3650
|
+
in: path
|
|
3651
|
+
required: true
|
|
3652
|
+
description: Stable opaque killswitch id (`ksw_…`) or the killswitch's `name`.
|
|
3653
|
+
schema:
|
|
3654
|
+
$ref: '#/components/schemas/ResourceId'
|
|
3655
|
+
requestBody:
|
|
3656
|
+
required: false
|
|
3657
|
+
content:
|
|
3658
|
+
application/json:
|
|
3659
|
+
schema:
|
|
3660
|
+
$ref: '#/components/schemas/ToggleKillswitchRequest'
|
|
3661
|
+
examples:
|
|
3662
|
+
flipOnProd:
|
|
3663
|
+
summary: Flip the killswitch on prod
|
|
3664
|
+
description: No body fields — reads the flat `value` on prod and publishes its opposite.
|
|
3665
|
+
value: {}
|
|
3666
|
+
flipOneSwitch:
|
|
3667
|
+
summary: Flip one sub-switch on prod
|
|
3668
|
+
description: Flips `switches.eu_region` on prod, leaving the flat `value` and every other key alone.
|
|
3669
|
+
value:
|
|
3670
|
+
switchKey: eu_region
|
|
3671
|
+
setOneSwitch:
|
|
3672
|
+
summary: Trip one sub-switch idempotently
|
|
3673
|
+
description: Publishes `switches.eu_region = true` on prod whatever it was before — safe to retry.
|
|
3674
|
+
value:
|
|
3675
|
+
switchKey: eu_region
|
|
3676
|
+
value: true
|
|
3677
|
+
setOneSwitchOnStaging:
|
|
3678
|
+
summary: Trip one sub-switch on a chosen env
|
|
3679
|
+
description: The same idempotent set, published on staging instead of prod.
|
|
3680
|
+
value:
|
|
3681
|
+
switchKey: eu_region
|
|
3682
|
+
value: true
|
|
3683
|
+
env: staging
|
|
3684
|
+
responses:
|
|
3685
|
+
'200':
|
|
3686
|
+
description: Toggle a killswitch or one of its switches
|
|
3687
|
+
content:
|
|
3688
|
+
application/json:
|
|
3689
|
+
schema:
|
|
3690
|
+
$ref: '#/components/schemas/ToggleKillswitchResponse'
|
|
3691
|
+
example:
|
|
3692
|
+
id: ksw_01j7w9d8h2k4m6n8p0q2r4s6t8
|
|
3693
|
+
env: prod
|
|
3694
|
+
switchKey: eu_region
|
|
3695
|
+
previous: false
|
|
3696
|
+
value: true
|
|
3697
|
+
version: 7
|
|
3698
|
+
published:
|
|
3699
|
+
value: false
|
|
3700
|
+
switches:
|
|
3701
|
+
eu_region: true
|
|
3702
|
+
'400':
|
|
3703
|
+
$ref: '#/components/responses/BadRequest'
|
|
3704
|
+
'401':
|
|
3705
|
+
$ref: '#/components/responses/Unauthorized'
|
|
3706
|
+
'403':
|
|
3707
|
+
$ref: '#/components/responses/Forbidden'
|
|
3708
|
+
'404':
|
|
3709
|
+
$ref: '#/components/responses/NotFound'
|
|
3710
|
+
'409':
|
|
3711
|
+
$ref: '#/components/responses/Conflict'
|
|
3712
|
+
'422':
|
|
3713
|
+
$ref: '#/components/responses/UnprocessableEntity'
|
|
3714
|
+
x-error-codes:
|
|
3715
|
+
- BAD_REQUEST
|
|
3716
|
+
- UNAUTHORIZED
|
|
3717
|
+
- FORBIDDEN
|
|
3718
|
+
- NOT_FOUND
|
|
3719
|
+
- VALIDATION
|
|
3720
|
+
x-cli:
|
|
3721
|
+
name: toggle
|
|
3722
|
+
positional:
|
|
3723
|
+
- id
|
|
3346
3724
|
/api/admin/universes:
|
|
3347
3725
|
get:
|
|
3348
3726
|
operationId: listUniverses
|
|
@@ -5078,7 +5456,7 @@ paths:
|
|
|
5078
5456
|
- name: status
|
|
5079
5457
|
in: query
|
|
5080
5458
|
required: false
|
|
5081
|
-
description: Filter by lifecycle status, or `all`. The human-gated holding
|
|
5459
|
+
description: Filter by lifecycle status, or `all`. The human-gated holding state (`pending_approval`) is excluded from `all`/default and returned only when requested as the exact status.
|
|
5082
5460
|
schema:
|
|
5083
5461
|
anyOf:
|
|
5084
5462
|
- $ref: '#/components/schemas/OpsItemStatus'
|
|
@@ -5222,6 +5600,171 @@ paths:
|
|
|
5222
5600
|
summary: File a feature request.
|
|
5223
5601
|
preset:
|
|
5224
5602
|
type: feature_request
|
|
5603
|
+
/ops/bug:
|
|
5604
|
+
post:
|
|
5605
|
+
operationId: createPublicBug
|
|
5606
|
+
summary: File a bug
|
|
5607
|
+
description: |-
|
|
5608
|
+
Files one bug onto a project's queue, awaiting human approval. This is the **public** intake: it authenticates with a *client* SDK key rather than an admin key, so it can be called from a CLI, an installer script, a devtools overlay, or any shipped code — the same places a client key already lives.
|
|
5609
|
+
|
|
5610
|
+
Three gates decide whether a ticket is filed, and nothing else the caller sends can widen them:
|
|
5611
|
+
|
|
5612
|
+
1. the key is a `client` key carrying the `tickets:public_create` scope,
|
|
5613
|
+
2. the key's project has public ticket creation enabled, and
|
|
5614
|
+
3. the item is filed as `pending_approval` — parked out of the work queue until a human promotes it in the dashboard.
|
|
5615
|
+
|
|
5616
|
+
The project is the key's own project; there is no `X-Project-Id` to pass and no way to file into someone else's queue. Repeat submissions of the same title dedupe against the open ticket already tracking it, which returns `200` with `deduped: true` instead of filing again.
|
|
5617
|
+
|
|
5618
|
+
This endpoint is served by the Shipeasy **edge worker** (`api.shipeasy.ai`), not the admin API — see `servers` below.
|
|
5619
|
+
|
|
5620
|
+
**Use case:** `shipeasy setup` fails on a customer's machine and self-reports the failure with the user's consent — `{ "title": "Setup failed at Feature installs", "stepsToReproduce": "…", "actualResult": "…" }`.
|
|
5621
|
+
tags:
|
|
5622
|
+
- Ops
|
|
5623
|
+
servers:
|
|
5624
|
+
- url: https://api.shipeasy.ai
|
|
5625
|
+
description: Shipeasy edge worker (production)
|
|
5626
|
+
- url: http://localhost:8787
|
|
5627
|
+
description: Local `wrangler dev`
|
|
5628
|
+
security:
|
|
5629
|
+
- clientSdkKey: []
|
|
5630
|
+
requestBody:
|
|
5631
|
+
required: true
|
|
5632
|
+
content:
|
|
5633
|
+
application/json:
|
|
5634
|
+
schema:
|
|
5635
|
+
$ref: '#/components/schemas/CreatePublicBugRequest'
|
|
5636
|
+
examples:
|
|
5637
|
+
minimal:
|
|
5638
|
+
summary: Just a title
|
|
5639
|
+
description: Every other field is optional — the queue triages from `open` at default priority.
|
|
5640
|
+
value:
|
|
5641
|
+
title: Checkout button misaligned on mobile
|
|
5642
|
+
full:
|
|
5643
|
+
summary: A full report
|
|
5644
|
+
value:
|
|
5645
|
+
title: Checkout button misaligned on mobile
|
|
5646
|
+
stepsToReproduce: Open the cart on iOS Safari and tap the price row.
|
|
5647
|
+
actualResult: The primary CTA overlaps the price.
|
|
5648
|
+
expectedResult: The CTA sits below the price with clear spacing.
|
|
5649
|
+
priority: high
|
|
5650
|
+
reporterEmail: alice@acme.dev
|
|
5651
|
+
pageUrl: https://acme.dev/cart
|
|
5652
|
+
responses:
|
|
5653
|
+
'200':
|
|
5654
|
+
description: An open ticket already tracks this report; nothing was filed
|
|
5655
|
+
content:
|
|
5656
|
+
application/json:
|
|
5657
|
+
schema:
|
|
5658
|
+
$ref: '#/components/schemas/CreatePublicTicketResponse'
|
|
5659
|
+
example:
|
|
5660
|
+
number: 7
|
|
5661
|
+
deduped: true
|
|
5662
|
+
'201':
|
|
5663
|
+
description: File a bug
|
|
5664
|
+
content:
|
|
5665
|
+
application/json:
|
|
5666
|
+
schema:
|
|
5667
|
+
$ref: '#/components/schemas/CreatePublicTicketResponse'
|
|
5668
|
+
example:
|
|
5669
|
+
id: fb_01j7w8a1b2c3d4e5f6g7h8i9j0
|
|
5670
|
+
number: 7
|
|
5671
|
+
'400':
|
|
5672
|
+
$ref: '#/components/responses/BadRequest'
|
|
5673
|
+
'401':
|
|
5674
|
+
$ref: '#/components/responses/Unauthorized'
|
|
5675
|
+
'403':
|
|
5676
|
+
$ref: '#/components/responses/Forbidden'
|
|
5677
|
+
'413':
|
|
5678
|
+
$ref: '#/components/responses/PayloadTooLarge'
|
|
5679
|
+
'429':
|
|
5680
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
5681
|
+
'503':
|
|
5682
|
+
$ref: '#/components/responses/ServiceUnavailable'
|
|
5683
|
+
x-error-codes:
|
|
5684
|
+
- BAD_REQUEST
|
|
5685
|
+
- UNAUTHORIZED
|
|
5686
|
+
- FORBIDDEN
|
|
5687
|
+
- VALIDATION
|
|
5688
|
+
x-cli:
|
|
5689
|
+
hidden: true
|
|
5690
|
+
/ops/feature-request:
|
|
5691
|
+
post:
|
|
5692
|
+
operationId: createPublicFeatureRequest
|
|
5693
|
+
summary: File a feature request
|
|
5694
|
+
description: |-
|
|
5695
|
+
Files one feature request onto a project's queue, awaiting human approval. The feature-request counterpart to `POST /ops/bug`, with the same three gates: a `client` key carrying `tickets:public_create`, a project that has opted in, and a `pending_approval` state forced server-side.
|
|
5696
|
+
|
|
5697
|
+
The project is the key's own project; there is no `X-Project-Id` to pass. Repeat submissions of the same title dedupe against the open ticket already tracking it, which returns `200` with `deduped: true` instead of filing again.
|
|
5698
|
+
|
|
5699
|
+
This endpoint is served by the Shipeasy **edge worker** (`api.shipeasy.ai`), not the admin API — see `servers` below.
|
|
5700
|
+
|
|
5701
|
+
**Use case:** An in-product "request a feature" form posts what the user asked for — `{ "title": "Dark mode", "useCase": "Reduce eye strain at night" }`.
|
|
5702
|
+
tags:
|
|
5703
|
+
- Ops
|
|
5704
|
+
servers:
|
|
5705
|
+
- url: https://api.shipeasy.ai
|
|
5706
|
+
description: Shipeasy edge worker (production)
|
|
5707
|
+
- url: http://localhost:8787
|
|
5708
|
+
description: Local `wrangler dev`
|
|
5709
|
+
security:
|
|
5710
|
+
- clientSdkKey: []
|
|
5711
|
+
requestBody:
|
|
5712
|
+
required: true
|
|
5713
|
+
content:
|
|
5714
|
+
application/json:
|
|
5715
|
+
schema:
|
|
5716
|
+
$ref: '#/components/schemas/CreatePublicFeatureRequestRequest'
|
|
5717
|
+
examples:
|
|
5718
|
+
minimal:
|
|
5719
|
+
summary: Just a title
|
|
5720
|
+
value:
|
|
5721
|
+
title: Dark mode for the dashboard
|
|
5722
|
+
full:
|
|
5723
|
+
summary: A full request
|
|
5724
|
+
value:
|
|
5725
|
+
title: Dark mode for the dashboard
|
|
5726
|
+
description: Add a theme toggle that persists per user.
|
|
5727
|
+
useCase: Reduce eye strain for users working at night.
|
|
5728
|
+
priority: nice_to_have
|
|
5729
|
+
reporterEmail: alice@acme.dev
|
|
5730
|
+
responses:
|
|
5731
|
+
'200':
|
|
5732
|
+
description: An open ticket already tracks this report; nothing was filed
|
|
5733
|
+
content:
|
|
5734
|
+
application/json:
|
|
5735
|
+
schema:
|
|
5736
|
+
$ref: '#/components/schemas/CreatePublicTicketResponse'
|
|
5737
|
+
example:
|
|
5738
|
+
number: 7
|
|
5739
|
+
deduped: true
|
|
5740
|
+
'201':
|
|
5741
|
+
description: File a feature request
|
|
5742
|
+
content:
|
|
5743
|
+
application/json:
|
|
5744
|
+
schema:
|
|
5745
|
+
$ref: '#/components/schemas/CreatePublicTicketResponse'
|
|
5746
|
+
example:
|
|
5747
|
+
id: fb_01j7w8a1b2c3d4e5f6g7h8i9j0
|
|
5748
|
+
number: 8
|
|
5749
|
+
'400':
|
|
5750
|
+
$ref: '#/components/responses/BadRequest'
|
|
5751
|
+
'401':
|
|
5752
|
+
$ref: '#/components/responses/Unauthorized'
|
|
5753
|
+
'403':
|
|
5754
|
+
$ref: '#/components/responses/Forbidden'
|
|
5755
|
+
'413':
|
|
5756
|
+
$ref: '#/components/responses/PayloadTooLarge'
|
|
5757
|
+
'429':
|
|
5758
|
+
$ref: '#/components/responses/TooManyRequests'
|
|
5759
|
+
'503':
|
|
5760
|
+
$ref: '#/components/responses/ServiceUnavailable'
|
|
5761
|
+
x-error-codes:
|
|
5762
|
+
- BAD_REQUEST
|
|
5763
|
+
- UNAUTHORIZED
|
|
5764
|
+
- FORBIDDEN
|
|
5765
|
+
- VALIDATION
|
|
5766
|
+
x-cli:
|
|
5767
|
+
hidden: true
|
|
5225
5768
|
/api/admin/ops/{handle}:
|
|
5226
5769
|
get:
|
|
5227
5770
|
operationId: getOpsItem
|
|
@@ -9081,6 +9624,16 @@ components:
|
|
|
9081
9624
|
scheme: bearer
|
|
9082
9625
|
bearerFormat: sdk_admin_*
|
|
9083
9626
|
description: 'Pass an admin SDK key as `Authorization: Bearer sdk_admin_…`. Mint via `POST /api/admin/keys` with `type: "admin"`.'
|
|
9627
|
+
clientSdkKey:
|
|
9628
|
+
type: apiKey
|
|
9629
|
+
in: header
|
|
9630
|
+
name: X-SDK-Key
|
|
9631
|
+
description: |-
|
|
9632
|
+
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.
|
|
9633
|
+
|
|
9634
|
+
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.
|
|
9635
|
+
|
|
9636
|
+
The key must additionally carry the `tickets:public_create` scope, and its project must have public ticket creation enabled.
|
|
9084
9637
|
parameters:
|
|
9085
9638
|
ProjectId:
|
|
9086
9639
|
name: X-Project-Id
|
|
@@ -10185,6 +10738,85 @@ components:
|
|
|
10185
10738
|
- createdAt
|
|
10186
10739
|
additionalProperties: false
|
|
10187
10740
|
description: Recent audit rows for one gate, newest first.
|
|
10741
|
+
GateWhitelistAttr:
|
|
10742
|
+
type: string
|
|
10743
|
+
enum:
|
|
10744
|
+
- email
|
|
10745
|
+
- user_id
|
|
10746
|
+
description: Which identity attribute the whitelist matches on. `email` compares the caller's `email`; `user_id` compares the caller's `userID`. A whitelist matches on exactly one of the two at a time.
|
|
10747
|
+
GateWhitelist:
|
|
10748
|
+
type: object
|
|
10749
|
+
properties:
|
|
10750
|
+
id:
|
|
10751
|
+
type: string
|
|
10752
|
+
description: Resolved gate id.
|
|
10753
|
+
name:
|
|
10754
|
+
type: string
|
|
10755
|
+
description: The gate's stable `name`.
|
|
10756
|
+
attr:
|
|
10757
|
+
$ref: '#/components/schemas/GateWhitelistAttr'
|
|
10758
|
+
entries:
|
|
10759
|
+
type: array
|
|
10760
|
+
items:
|
|
10761
|
+
type: string
|
|
10762
|
+
minLength: 1
|
|
10763
|
+
description: The whitelisted identities, in the order they are stored. Deduplicated case-sensitively; an empty array means the gate has no whitelist.
|
|
10764
|
+
required:
|
|
10765
|
+
- id
|
|
10766
|
+
- name
|
|
10767
|
+
- attr
|
|
10768
|
+
- entries
|
|
10769
|
+
additionalProperties: false
|
|
10770
|
+
description: A gate's whitelist — the always-first allowlist that admits the listed identities before any targeting rule or rollout runs. Backed by the pinned `whitelist` entry at the head of the gate's `stack`, so it is the same list the dashboard's Whitelist block edits.
|
|
10771
|
+
SetGateWhitelistRequest:
|
|
10772
|
+
type: object
|
|
10773
|
+
properties:
|
|
10774
|
+
attr:
|
|
10775
|
+
anyOf:
|
|
10776
|
+
- $ref: '#/components/schemas/GateWhitelistAttr'
|
|
10777
|
+
description: Identity attribute to match on. Defaults to the whitelist's current attribute, or `email` when the gate has no whitelist yet.
|
|
10778
|
+
entries:
|
|
10779
|
+
type: array
|
|
10780
|
+
items:
|
|
10781
|
+
type: string
|
|
10782
|
+
minLength: 1
|
|
10783
|
+
description: The complete whitelist after the call. Pass `[]` to remove the whitelist from the gate entirely.
|
|
10784
|
+
required:
|
|
10785
|
+
- entries
|
|
10786
|
+
additionalProperties: false
|
|
10787
|
+
description: Body for `PUT /api/admin/gates/{id}/whitelist`. Replaces the whole list — idempotent, and the only call that can switch `attr` or clear the whitelist.
|
|
10788
|
+
AddToGateWhitelistRequest:
|
|
10789
|
+
type: object
|
|
10790
|
+
properties:
|
|
10791
|
+
attr:
|
|
10792
|
+
anyOf:
|
|
10793
|
+
- $ref: '#/components/schemas/GateWhitelistAttr'
|
|
10794
|
+
description: Identity attribute to match on. Only honoured when the gate has no whitelist yet (this call creates it); passing an attribute that disagrees with an existing whitelist is a 409 rather than a silent re-key of the entries already there.
|
|
10795
|
+
entries:
|
|
10796
|
+
type: array
|
|
10797
|
+
minItems: 1
|
|
10798
|
+
items:
|
|
10799
|
+
type: string
|
|
10800
|
+
minLength: 1
|
|
10801
|
+
description: Identities to admit. Already-listed entries are skipped, so the call is idempotent.
|
|
10802
|
+
required:
|
|
10803
|
+
- entries
|
|
10804
|
+
additionalProperties: false
|
|
10805
|
+
description: Body for `POST /api/admin/gates/{id}/whitelist`. Adds entries to the whitelist, creating it if the gate doesn't have one.
|
|
10806
|
+
RemoveFromGateWhitelistRequest:
|
|
10807
|
+
type: object
|
|
10808
|
+
properties:
|
|
10809
|
+
entries:
|
|
10810
|
+
type: array
|
|
10811
|
+
minItems: 1
|
|
10812
|
+
items:
|
|
10813
|
+
type: string
|
|
10814
|
+
minLength: 1
|
|
10815
|
+
description: Identities to stop admitting. Entries that aren't listed are skipped, so the call is idempotent.
|
|
10816
|
+
required:
|
|
10817
|
+
- entries
|
|
10818
|
+
additionalProperties: false
|
|
10819
|
+
description: 'Body for `DELETE /api/admin/gates/{id}/whitelist`. Removes entries from the whitelist. Removing the last entry leaves an empty whitelist in place — use `PUT` with `entries: []` to drop the block itself.'
|
|
10188
10820
|
ExperimentApiRow:
|
|
10189
10821
|
type: object
|
|
10190
10822
|
properties:
|
|
@@ -12214,6 +12846,70 @@ components:
|
|
|
12214
12846
|
- version
|
|
12215
12847
|
- published
|
|
12216
12848
|
additionalProperties: false
|
|
12849
|
+
ToggleKillswitchRequest:
|
|
12850
|
+
type: object
|
|
12851
|
+
properties:
|
|
12852
|
+
switchKey:
|
|
12853
|
+
anyOf:
|
|
12854
|
+
- type: string
|
|
12855
|
+
maxLength: 64
|
|
12856
|
+
pattern: ^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?$
|
|
12857
|
+
- type: 'null'
|
|
12858
|
+
description: Which target to flip. Omit (or `null`) to flip the killswitch's own flat `value`; name a switch key to flip that nested sub-switch instead, creating the entry if it doesn't exist yet.
|
|
12859
|
+
value:
|
|
12860
|
+
anyOf:
|
|
12861
|
+
- type: boolean
|
|
12862
|
+
- type: 'null'
|
|
12863
|
+
description: The value to publish. Omit (or `null`) to flip whatever is stored now — read-modify-write in one call. Pass an explicit `true`/`false` to make the call idempotent, so a retry can't undo the first attempt.
|
|
12864
|
+
env:
|
|
12865
|
+
anyOf:
|
|
12866
|
+
- $ref: '#/components/schemas/Env'
|
|
12867
|
+
description: Environment to publish on. Defaults to `prod` — the environment an incident response means when it says "kill it".
|
|
12868
|
+
additionalProperties: false
|
|
12869
|
+
description: |-
|
|
12870
|
+
Body for `POST /api/admin/killswitches/{id}/toggle`. Every field is optional, so the four useful calls read as one method with a widening argument list:
|
|
12871
|
+
|
|
12872
|
+
- `{}` — flip the flat value on prod.
|
|
12873
|
+
- `{ "switchKey": "eu_region" }` — flip that sub-switch on prod.
|
|
12874
|
+
- `{ "switchKey": "eu_region", "value": true }` — set that sub-switch on prod, idempotently.
|
|
12875
|
+
- `{ "switchKey": "eu_region", "value": true, "env": "staging" }` — the same, on a chosen env.
|
|
12876
|
+
ToggleKillswitchResponse:
|
|
12877
|
+
type: object
|
|
12878
|
+
properties:
|
|
12879
|
+
id:
|
|
12880
|
+
type: string
|
|
12881
|
+
description: Resolved killswitch id.
|
|
12882
|
+
env:
|
|
12883
|
+
$ref: '#/components/schemas/Env'
|
|
12884
|
+
switchKey:
|
|
12885
|
+
anyOf:
|
|
12886
|
+
- type: string
|
|
12887
|
+
maxLength: 64
|
|
12888
|
+
pattern: ^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?$
|
|
12889
|
+
- type: 'null'
|
|
12890
|
+
description: The sub-switch that was flipped, or `null` when the flat `value` was.
|
|
12891
|
+
previous:
|
|
12892
|
+
type: boolean
|
|
12893
|
+
description: The value that was in effect before this call. Equal to `value` when an idempotent `value` matched what was already stored.
|
|
12894
|
+
value:
|
|
12895
|
+
type: boolean
|
|
12896
|
+
description: The value now in effect on `env`.
|
|
12897
|
+
version:
|
|
12898
|
+
type: integer
|
|
12899
|
+
minimum: -9007199254740991
|
|
12900
|
+
maximum: 9007199254740991
|
|
12901
|
+
description: Newly published version on `env`.
|
|
12902
|
+
published:
|
|
12903
|
+
$ref: '#/components/schemas/KillswitchValue'
|
|
12904
|
+
required:
|
|
12905
|
+
- id
|
|
12906
|
+
- env
|
|
12907
|
+
- switchKey
|
|
12908
|
+
- previous
|
|
12909
|
+
- value
|
|
12910
|
+
- version
|
|
12911
|
+
- published
|
|
12912
|
+
additionalProperties: false
|
|
12217
12913
|
UniverseParam:
|
|
12218
12914
|
type: object
|
|
12219
12915
|
properties:
|
|
@@ -13925,15 +14621,13 @@ components:
|
|
|
13925
14621
|
enum:
|
|
13926
14622
|
- open
|
|
13927
14623
|
- pending_approval
|
|
13928
|
-
- triage
|
|
13929
|
-
- triaged
|
|
13930
14624
|
- investigating_by_ai
|
|
13931
14625
|
- in_progress
|
|
13932
14626
|
- blocked
|
|
13933
14627
|
- ready_for_qa
|
|
13934
14628
|
- resolved
|
|
13935
14629
|
- wont_fix
|
|
13936
|
-
description: 'Lifecycle status of a queue item. The working flow is `open` → `
|
|
14630
|
+
description: 'Lifecycle status of a queue item. The working flow is `open` → `in_progress` → `ready_for_qa` → `resolved` (or `wont_fix`, terminal from any earlier stage). `blocked` marks an item that can''t progress until an external dependency clears — a working state a human sets and clears. `ready_for_qa` is what a developer sets once a fix lands; `resolved` is the QA sign-off, normally flipped in the dashboard after verification — set it directly from code only when the fix has been verified end-to-end. `investigating_by_ai` is a system-owned display state — set when the AI agent (Jarvis) picks an item up to investigate, never chosen by a human — so it is shown but not offered as a manual choice. `pending_approval` is the one human-gated holding state: it parks an item OUT of the work queue until a human promotes it to `open` in the dashboard, so `GET /api/admin/ops` excludes it under `status=all`/default and returns it only when requested as an exact `status`. It covers untriaged inbound that must never be auto-implemented — connector requests filed from a customer''s connectors panel, and questions funnelled in from the "Stuck in onboarding?" assistant — where approving means flipping the status to `open`. Two earlier values were removed in favour of this single gate: `triage` (the onboarding-help bucket, now `pending_approval`) and `triaged` (a redundant "looked at but not started" step, now plain `open`).'
|
|
13937
14631
|
OpsItemPriority:
|
|
13938
14632
|
type: string
|
|
13939
14633
|
enum:
|
|
@@ -13946,16 +14640,15 @@ components:
|
|
|
13946
14640
|
type: string
|
|
13947
14641
|
enum:
|
|
13948
14642
|
- pr_ready
|
|
14643
|
+
- pr_merged
|
|
13949
14644
|
- investigated
|
|
13950
14645
|
- detected
|
|
13951
14646
|
- question
|
|
13952
14647
|
- ready_for_qa
|
|
13953
14648
|
- pending_approval
|
|
13954
|
-
- needs_triage
|
|
13955
14649
|
- working
|
|
13956
|
-
- triaged_low
|
|
13957
14650
|
- backlog
|
|
13958
|
-
description: 'Where automation has taken an item in the investigation lifecycle — the signal the ops cockpit renders as "what AI did" plus the one action expected of the user. It is **written as a side-effect of the actions that already happen**, never authored on its own: linking a PR sets `pr_ready`, moving to `in_progress` sets `working`, `ready_for_qa` sets `ready_for_qa`, a system/assistant reply sets `question`, resolving clears it, and creation seeds `
|
|
14651
|
+
description: 'Where automation has taken an item in the investigation lifecycle — the signal the ops cockpit renders as "what AI did" plus the one action expected of the user. It is **written as a side-effect of the actions that already happen**, never authored on its own: linking a PR sets `pr_ready`, moving to `in_progress` sets `working`, `ready_for_qa` sets `ready_for_qa`, a system/assistant reply sets `question`, resolving clears it, and creation seeds `backlog` or `investigated`/`detected` for auto-filed error/alert tickets. `backlog` is the single "nothing has happened yet" state — how urgent that is reads off `priority`, not off a separate state, and its one action is to hand the item to an agent. `pr_merged` is derived client-side by scanning the linked pull request on GitHub, so it is accepted on write but not currently emitted by the API. Absent on rows filed before the field existed — consumers should treat a missing value as "derive from the other fields".'
|
|
13959
14652
|
OpsBrowserContext:
|
|
13960
14653
|
type: object
|
|
13961
14654
|
properties:
|
|
@@ -14900,6 +15593,191 @@ components:
|
|
|
14900
15593
|
- id
|
|
14901
15594
|
additionalProperties: false
|
|
14902
15595
|
description: Response for `POST /api/admin/ops`.
|
|
15596
|
+
CreatePublicBugRequest:
|
|
15597
|
+
type: object
|
|
15598
|
+
properties:
|
|
15599
|
+
title:
|
|
15600
|
+
type: string
|
|
15601
|
+
minLength: 1
|
|
15602
|
+
maxLength: 200
|
|
15603
|
+
pattern: ^\S(.*\S)?$
|
|
15604
|
+
description: One-line bug title (no leading/trailing whitespace).
|
|
15605
|
+
stepsToReproduce:
|
|
15606
|
+
type: string
|
|
15607
|
+
maxLength: 8000
|
|
15608
|
+
default: ''
|
|
15609
|
+
description: How to reproduce the bug.
|
|
15610
|
+
actualResult:
|
|
15611
|
+
type: string
|
|
15612
|
+
maxLength: 8000
|
|
15613
|
+
default: ''
|
|
15614
|
+
description: What actually happened.
|
|
15615
|
+
expectedResult:
|
|
15616
|
+
type: string
|
|
15617
|
+
maxLength: 8000
|
|
15618
|
+
default: ''
|
|
15619
|
+
description: What was expected instead.
|
|
15620
|
+
priority:
|
|
15621
|
+
anyOf:
|
|
15622
|
+
- $ref: '#/components/schemas/OpsItemPriority'
|
|
15623
|
+
- type: 'null'
|
|
15624
|
+
description: Initial triage priority, or `null`.
|
|
15625
|
+
status:
|
|
15626
|
+
anyOf:
|
|
15627
|
+
- $ref: '#/components/schemas/OpsItemStatus'
|
|
15628
|
+
description: Initial lifecycle status; defaults to `open` when omitted.
|
|
15629
|
+
assigneeId:
|
|
15630
|
+
anyOf:
|
|
15631
|
+
- type: string
|
|
15632
|
+
- type: 'null'
|
|
15633
|
+
description: The `users.id` of the person to assign as owner at creation, or `null`.
|
|
15634
|
+
subscribers:
|
|
15635
|
+
type: array
|
|
15636
|
+
items:
|
|
15637
|
+
type: string
|
|
15638
|
+
format: email
|
|
15639
|
+
default: []
|
|
15640
|
+
description: Emails of teammates to subscribe to this item's Slack pings at creation.
|
|
15641
|
+
tags:
|
|
15642
|
+
type: array
|
|
15643
|
+
items:
|
|
15644
|
+
type: string
|
|
15645
|
+
default: []
|
|
15646
|
+
description: Tag names to attach at creation (get-or-created by name, deduped case-insensitively).
|
|
15647
|
+
reporterEmail:
|
|
15648
|
+
anyOf:
|
|
15649
|
+
- type: string
|
|
15650
|
+
format: email
|
|
15651
|
+
- type: 'null'
|
|
15652
|
+
description: Email of the reporter, or `null`.
|
|
15653
|
+
pageUrl:
|
|
15654
|
+
anyOf:
|
|
15655
|
+
- type: string
|
|
15656
|
+
format: uri
|
|
15657
|
+
- type: 'null'
|
|
15658
|
+
description: URL of the page the bug relates to, or `null`.
|
|
15659
|
+
userAgent:
|
|
15660
|
+
anyOf:
|
|
15661
|
+
- type: string
|
|
15662
|
+
maxLength: 500
|
|
15663
|
+
- type: 'null'
|
|
15664
|
+
description: Reporter's user-agent string, or `null`.
|
|
15665
|
+
viewport:
|
|
15666
|
+
anyOf:
|
|
15667
|
+
- type: string
|
|
15668
|
+
maxLength: 40
|
|
15669
|
+
- type: 'null'
|
|
15670
|
+
description: Reporter's viewport (e.g. `1280x720`), or `null`.
|
|
15671
|
+
context:
|
|
15672
|
+
anyOf:
|
|
15673
|
+
- type: object
|
|
15674
|
+
additionalProperties: {}
|
|
15675
|
+
- type: 'null'
|
|
15676
|
+
description: Arbitrary capture context, or `null`.
|
|
15677
|
+
notify:
|
|
15678
|
+
anyOf:
|
|
15679
|
+
- $ref: '#/components/schemas/NotificationTarget'
|
|
15680
|
+
- type: 'null'
|
|
15681
|
+
description: Where this bug's completion notification lands.
|
|
15682
|
+
required:
|
|
15683
|
+
- title
|
|
15684
|
+
additionalProperties: false
|
|
15685
|
+
description: Body for `POST /ops/bug`. The same bug fields as `CreateBugRequest`, minus the `type` discriminator — the path already says what is being filed.
|
|
15686
|
+
CreatePublicTicketResponse:
|
|
15687
|
+
type: object
|
|
15688
|
+
properties:
|
|
15689
|
+
id:
|
|
15690
|
+
type: string
|
|
15691
|
+
description: The new item's id. Absent on a deduped response — nothing was created, so there is no new id to report.
|
|
15692
|
+
number:
|
|
15693
|
+
type: integer
|
|
15694
|
+
description: Per-project item number. On a deduped response this is the number of the OPEN ticket already tracking the report, which is what a caller should show the user either way.
|
|
15695
|
+
deduped:
|
|
15696
|
+
type: boolean
|
|
15697
|
+
description: '`true` when an open ticket already tracked this report and nothing was filed (HTTP 200). Absent on a fresh file (HTTP 201).'
|
|
15698
|
+
required:
|
|
15699
|
+
- number
|
|
15700
|
+
additionalProperties: false
|
|
15701
|
+
description: 'Response for the public ticket intake. A fresh file returns `201` with `id` + `number`; a repeat of a report already tracked by an open ticket returns `200` with that ticket''s `number` and `deduped: true`.'
|
|
15702
|
+
CreatePublicFeatureRequestRequest:
|
|
15703
|
+
type: object
|
|
15704
|
+
properties:
|
|
15705
|
+
title:
|
|
15706
|
+
type: string
|
|
15707
|
+
minLength: 1
|
|
15708
|
+
maxLength: 200
|
|
15709
|
+
pattern: ^\S(.*\S)?$
|
|
15710
|
+
description: One-line feature-request title (no leading/trailing whitespace).
|
|
15711
|
+
description:
|
|
15712
|
+
type: string
|
|
15713
|
+
maxLength: 8000
|
|
15714
|
+
default: ''
|
|
15715
|
+
description: What the feature is.
|
|
15716
|
+
useCase:
|
|
15717
|
+
type: string
|
|
15718
|
+
maxLength: 8000
|
|
15719
|
+
default: ''
|
|
15720
|
+
description: Why it's needed / the use case.
|
|
15721
|
+
priority:
|
|
15722
|
+
anyOf:
|
|
15723
|
+
- $ref: '#/components/schemas/OpsItemPriority'
|
|
15724
|
+
- type: 'null'
|
|
15725
|
+
description: Initial triage priority, or `null`.
|
|
15726
|
+
status:
|
|
15727
|
+
anyOf:
|
|
15728
|
+
- $ref: '#/components/schemas/OpsItemStatus'
|
|
15729
|
+
description: Initial lifecycle status; defaults to `open` when omitted.
|
|
15730
|
+
assigneeId:
|
|
15731
|
+
anyOf:
|
|
15732
|
+
- type: string
|
|
15733
|
+
- type: 'null'
|
|
15734
|
+
description: The `users.id` of the person to assign as owner at creation, or `null`.
|
|
15735
|
+
subscribers:
|
|
15736
|
+
type: array
|
|
15737
|
+
items:
|
|
15738
|
+
type: string
|
|
15739
|
+
format: email
|
|
15740
|
+
default: []
|
|
15741
|
+
description: Emails of teammates to subscribe to this item's Slack pings at creation.
|
|
15742
|
+
tags:
|
|
15743
|
+
type: array
|
|
15744
|
+
items:
|
|
15745
|
+
type: string
|
|
15746
|
+
default: []
|
|
15747
|
+
description: Tag names to attach at creation (get-or-created by name, deduped case-insensitively).
|
|
15748
|
+
reporterEmail:
|
|
15749
|
+
anyOf:
|
|
15750
|
+
- type: string
|
|
15751
|
+
format: email
|
|
15752
|
+
- type: 'null'
|
|
15753
|
+
description: Email of the reporter, or `null`.
|
|
15754
|
+
pageUrl:
|
|
15755
|
+
anyOf:
|
|
15756
|
+
- type: string
|
|
15757
|
+
format: uri
|
|
15758
|
+
- type: 'null'
|
|
15759
|
+
description: URL of the page the request relates to, or `null`.
|
|
15760
|
+
userAgent:
|
|
15761
|
+
anyOf:
|
|
15762
|
+
- type: string
|
|
15763
|
+
maxLength: 500
|
|
15764
|
+
- type: 'null'
|
|
15765
|
+
description: Reporter's user-agent string, or `null`.
|
|
15766
|
+
context:
|
|
15767
|
+
anyOf:
|
|
15768
|
+
- type: object
|
|
15769
|
+
additionalProperties: {}
|
|
15770
|
+
- type: 'null'
|
|
15771
|
+
description: Arbitrary capture context, or `null`.
|
|
15772
|
+
notify:
|
|
15773
|
+
anyOf:
|
|
15774
|
+
- $ref: '#/components/schemas/NotificationTarget'
|
|
15775
|
+
- type: 'null'
|
|
15776
|
+
description: Where this request's completion notification lands.
|
|
15777
|
+
required:
|
|
15778
|
+
- title
|
|
15779
|
+
additionalProperties: false
|
|
15780
|
+
description: Body for `POST /ops/feature-request`. The same feature-request fields as `CreateFeatureRequestRequest`, minus the `type` discriminator — the path already says what is being filed.
|
|
14903
15781
|
OpsItemAttachment:
|
|
14904
15782
|
type: object
|
|
14905
15783
|
properties:
|
|
@@ -18225,8 +19103,8 @@ components:
|
|
|
18225
19103
|
name:
|
|
18226
19104
|
type: string
|
|
18227
19105
|
minLength: 1
|
|
18228
|
-
maxLength:
|
|
18229
|
-
description: Optional human label. Programmatic (API) mints that omit it get an auto-generated descriptive name; dashboard mints may leave it blank.
|
|
19106
|
+
maxLength: 160
|
|
19107
|
+
description: Optional human label. Programmatic (API) mints that omit it get an auto-generated descriptive name; dashboard mints may leave it blank. The cap is generous because provenance labels are composed, not typed — `shipeasy setup` mints keys named with the stack, package, date, and operator that produced them, which does not fit in a one-line-input budget.
|
|
18230
19108
|
scopes:
|
|
18231
19109
|
type: array
|
|
18232
19110
|
items:
|
|
@@ -18462,6 +19340,45 @@ components:
|
|
|
18462
19340
|
value:
|
|
18463
19341
|
error: The referenced event is still pending review and cannot back a metric yet.
|
|
18464
19342
|
code: EVENT_PENDING
|
|
19343
|
+
PayloadTooLarge:
|
|
19344
|
+
description: The request body exceeded the intake's fixed size cap (16 KB).
|
|
19345
|
+
content:
|
|
19346
|
+
application/json:
|
|
19347
|
+
schema:
|
|
19348
|
+
$ref: '#/components/schemas/Error'
|
|
19349
|
+
examples:
|
|
19350
|
+
BAD_REQUEST:
|
|
19351
|
+
summary: Body too large
|
|
19352
|
+
value:
|
|
19353
|
+
error: Body too large
|
|
19354
|
+
code: BAD_REQUEST
|
|
19355
|
+
TooManyRequests:
|
|
19356
|
+
description: |-
|
|
19357
|
+
The public intake is rate-limited per (project, client IP). Back off and retry;
|
|
19358
|
+
the limit is a burst guard, not a quota, so a modest delay clears it.
|
|
19359
|
+
content:
|
|
19360
|
+
application/json:
|
|
19361
|
+
schema:
|
|
19362
|
+
$ref: '#/components/schemas/Error'
|
|
19363
|
+
examples:
|
|
19364
|
+
BAD_REQUEST:
|
|
19365
|
+
summary: Rate limited
|
|
19366
|
+
value:
|
|
19367
|
+
error: Too many requests
|
|
19368
|
+
code: BAD_REQUEST
|
|
19369
|
+
ServiceUnavailable:
|
|
19370
|
+
description: |-
|
|
19371
|
+
A backing store the endpoint needs is not bound in this environment. Transient
|
|
19372
|
+
and infrastructural — no stable `ErrorCode` is assigned, so `code` is omitted.
|
|
19373
|
+
content:
|
|
19374
|
+
application/json:
|
|
19375
|
+
schema:
|
|
19376
|
+
$ref: '#/components/schemas/Error'
|
|
19377
|
+
examples:
|
|
19378
|
+
UNAVAILABLE:
|
|
19379
|
+
summary: Storage unbound
|
|
19380
|
+
value:
|
|
19381
|
+
error: Unavailable
|
|
18465
19382
|
BadGateway:
|
|
18466
19383
|
description: |-
|
|
18467
19384
|
The request was well-formed and the resource exists, but a downstream provider
|