@shipeasy/openapi 2.2.0 → 2.4.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.
Files changed (52) hide show
  1. package/dist/{chunk-643YSMLU.js → chunk-4QSU744W.js} +183 -1
  2. package/dist/chunk-4QSU744W.js.map +1 -0
  3. package/dist/{chunk-MRW3DJ57.js → chunk-ZPKHTUVV.js} +1238 -335
  4. package/dist/chunk-ZPKHTUVV.js.map +1 -0
  5. package/dist/{client-K0ShmsC7.d.ts → client-WGNXT4xl.d.ts} +5818 -2647
  6. package/dist/client.d.ts +1 -1
  7. package/dist/client.js +51 -1
  8. package/dist/custom.js +4 -4
  9. package/dist/custom.js.map +1 -1
  10. package/dist/index.d.ts +2 -2
  11. package/dist/index.js +52 -2
  12. package/dist/index.js.map +1 -1
  13. package/dist/schemas.d.ts +3538 -534
  14. package/dist/schemas.js +253 -5
  15. package/openapi.json +12914 -7158
  16. package/openapi.yaml +7672 -3742
  17. package/package.json +1 -1
  18. package/spec/components/errors.yaml +33 -1
  19. package/spec/components/schemas/alerts.yaml +138 -0
  20. package/spec/components/schemas/attributes.yaml +53 -3
  21. package/spec/components/schemas/common.yaml +16 -0
  22. package/spec/components/schemas/configs.yaml +58 -0
  23. package/spec/components/schemas/connectors.yaml +5 -1
  24. package/spec/components/schemas/errors-api.yaml +116 -6
  25. package/spec/components/schemas/experiment-api-row.yaml +293 -0
  26. package/spec/components/schemas/experiments.yaml +395 -380
  27. package/spec/components/schemas/gates.yaml +355 -272
  28. package/spec/components/schemas/i18n.yaml +169 -40
  29. package/spec/components/schemas/keys.yaml +2 -1
  30. package/spec/components/schemas/killswitches.yaml +36 -0
  31. package/spec/components/schemas/metrics.yaml +200 -23
  32. package/spec/components/schemas/ops.yaml +918 -29
  33. package/spec/components/schemas/projects.yaml +246 -2
  34. package/spec/components/schemas/universes.yaml +83 -1
  35. package/spec/openapi.yaml +61 -0
  36. package/spec/paths/alert-rules.yaml +1 -0
  37. package/spec/paths/alerts.yaml +184 -0
  38. package/spec/paths/attributes.yaml +23 -5
  39. package/spec/paths/configs.yaml +71 -0
  40. package/spec/paths/errors.yaml +112 -2
  41. package/spec/paths/events.yaml +1 -0
  42. package/spec/paths/experiments.yaml +244 -16
  43. package/spec/paths/gates.yaml +138 -0
  44. package/spec/paths/i18n.yaml +290 -6
  45. package/spec/paths/keys.yaml +1 -0
  46. package/spec/paths/killswitches.yaml +7 -0
  47. package/spec/paths/metrics.yaml +187 -0
  48. package/spec/paths/ops.yaml +410 -0
  49. package/spec/paths/projects.yaml +62 -2
  50. package/spec/paths/universes.yaml +1 -0
  51. package/dist/chunk-643YSMLU.js.map +0 -1
  52. package/dist/chunk-MRW3DJ57.js.map +0 -1
@@ -1,290 +1,327 @@
1
- ListGatesResponse:
1
+ # The single wire shape for a gate row, shared by `ListGatesResponse`
2
+ # (`data[]` items) and `GET /api/admin/gates/{id}`. The app projects every gate
3
+ # through one `toGateApiRow` allow-list at the HTTP boundary, so both endpoints
4
+ # return the SAME object — this schema is that allow-list.
5
+ GateApiRow:
2
6
  type: object
3
7
  properties:
4
- data:
8
+ id:
9
+ type: string
10
+ description: Stable opaque gate id (`gat_…`).
11
+ name:
12
+ type: string
13
+ maxLength: 128
14
+ pattern: ^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$
15
+ description: Stable gate key used by SDKs (`Shipeasy.checkGate(user, '<name>')`). Single segment or `folder.name`. Lowercase letters, digits, `_` or `-`; max 128 chars. Immutable after create — rename = delete + recreate.
16
+ enabled:
17
+ anyOf:
18
+ - type: boolean
19
+ - type: integer
20
+ minimum: 0
21
+ maximum: 1
22
+ description: Master switch. Returned as `1`/`0` from D1; treat truthy as enabled.
23
+ type:
24
+ type: string
25
+ enum:
26
+ - targeting
27
+ - holdout
28
+ description: Gate kind — `targeting` (normal flag) or `holdout` (restricted public % + whitelist).
29
+ rolloutPct:
30
+ type: integer
31
+ minimum: 0
32
+ maximum: 10000
33
+ description: Current rollout in basis points (0–10000).
34
+ rules:
5
35
  type: array
6
36
  items:
7
37
  type: object
8
38
  properties:
9
- id:
10
- type: string
11
- description: Stable opaque gate id (`gat_…`).
12
- name:
39
+ attr:
13
40
  type: string
14
- maxLength: 128
15
- pattern: ^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$
16
- description: Stable gate key used by SDKs (`Shipeasy.checkGate(user, '<name>')`). Single segment or `folder.name`. Lowercase letters, digits, `_` or `-`; max 128 chars. Immutable after create — rename = delete + recreate.
17
- enabled:
18
- anyOf:
19
- - type: boolean
20
- - type: integer
21
- minimum: 0
22
- maximum: 1
23
- description: Master switch. Returned as `1`/`0` from D1; treat truthy as enabled.
24
- rolloutPct:
25
- type: integer
26
- minimum: 0
27
- maximum: 10000
28
- description: Current rollout in basis points (0–10000).
29
- rules:
30
- type: array
31
- items:
32
- type: object
33
- properties:
34
- attr:
35
- type: string
36
- minLength: 1
37
- description: Attribute key on the evaluation context (e.g. `country`, `plan`, `email`). Matched case-sensitively against `Shipeasy.checkGate(user, name)` input.
38
- op:
39
- type: string
40
- enum:
41
- - eq
42
- - neq
43
- - in
44
- - not_in
45
- - gt
46
- - gte
47
- - lt
48
- - lte
49
- - contains
50
- - regex
51
- - semver_gt
52
- - semver_gte
53
- - semver_lt
54
- - semver_lte
55
- - gate_pass
56
- - exp_in
57
- description: "Comparison operator. Equality: `eq`/`neq`. Set membership: `in`/`not_in` (value is an array). Numeric order: `gt`/`gte`/`lt`/`lte`. Semver order: `semver_gt`/`semver_gte`/`semver_lt`/`semver_lte` (value is a dotted version like `4.2.0`). String: `contains` (substring), `regex` (JS-flavour pattern, value is the pattern string). Cross-resource references (evaluated only on the worker hot path, where both KV blobs load): `gate_pass` (`value` is another gate's name — true when that gate passes for the same caller); `exp_in` (`attr` is a running experiment's name, `value` is a group name, `\"$holdout\"`, or `\"$any\"` — true when the caller is in that variant / the universe holdout / any variant)."
58
- value:
59
- description: 'Operand. Shape depends on `op`: scalar for `eq/neq/gt/gte/lt/lte/contains/semver_*`; array of scalars for `in/not_in`; string pattern for `regex`; referenced gate name for `gate_pass`; group name / `"$holdout"` / `"$any"` for `exp_in`.'
60
- required:
61
- - attr
62
- - op
63
- - value
64
- additionalProperties: false
65
- description: Single targeting predicate. A gate's `rules` array is evaluated with AND semantics; use the gatekeeper `stack` for OR / fall-through logic.
66
- salt:
67
- description: Hash salt used for percentage bucketing.
41
+ minLength: 1
42
+ description: Attribute key on the evaluation context (e.g. `country`, `plan`, `email`). Matched case-sensitively against `Shipeasy.checkGate(user, name)` input.
43
+ op:
68
44
  type: string
69
- title:
70
- anyOf:
71
- - type: string
72
- - type: "null"
73
- description:
74
- anyOf:
75
- - type: string
76
- - type: "null"
77
- folder:
78
- anyOf:
79
- - type: string
80
- - type: "null"
81
- groupName:
82
- description: "Group label (note: `groupName` in response, `group` in request)."
83
- anyOf:
84
- - type: string
85
- - type: "null"
86
- ownerEmail:
87
- description: "Owner email (note: `ownerEmail` in response, `owner_email` in request)."
88
- anyOf:
89
- - type: string
90
- - type: "null"
91
- stack:
92
- anyOf:
93
- - type: array
94
- items:
95
- oneOf:
96
- - type: object
45
+ enum:
46
+ - eq
47
+ - neq
48
+ - in
49
+ - not_in
50
+ - gt
51
+ - gte
52
+ - lt
53
+ - lte
54
+ - contains
55
+ - regex
56
+ - semver_gt
57
+ - semver_gte
58
+ - semver_lt
59
+ - semver_lte
60
+ - gate_pass
61
+ - exp_in
62
+ description: "Comparison operator. Equality: `eq`/`neq`. Set membership: `in`/`not_in` (value is an array). Numeric order: `gt`/`gte`/`lt`/`lte`. Semver order: `semver_gt`/`semver_gte`/`semver_lt`/`semver_lte` (value is a dotted version like `4.2.0`). String: `contains` (substring), `regex` (JS-flavour pattern, value is the pattern string). Cross-resource references (evaluated only on the worker hot path, where both KV blobs load): `gate_pass` (`value` is another gate's name — true when that gate passes for the same caller); `exp_in` (`attr` is a running experiment's name, `value` is a group name, `\"$holdout\"`, or `\"$any\"` — true when the caller is in that variant / the universe holdout / any variant)."
63
+ value:
64
+ description: 'Operand. Shape depends on `op`: scalar for `eq/neq/gt/gte/lt/lte/contains/semver_*`; array of scalars for `in/not_in`; string pattern for `regex`; referenced gate name for `gate_pass`; group name / `"$holdout"` / `"$any"` for `exp_in`.'
65
+ required:
66
+ - attr
67
+ - op
68
+ - value
69
+ additionalProperties: false
70
+ description: Single targeting predicate. A gate's `rules` array is evaluated with AND semantics; use the gatekeeper `stack` for OR / fall-through logic.
71
+ salt:
72
+ description: Hash salt used for percentage bucketing.
73
+ type: string
74
+ title:
75
+ anyOf:
76
+ - type: string
77
+ - type: "null"
78
+ description:
79
+ anyOf:
80
+ - type: string
81
+ - type: "null"
82
+ folder:
83
+ anyOf:
84
+ - type: string
85
+ - type: "null"
86
+ groupName:
87
+ description: "Group label (note: `groupName` in response, `group` in request)."
88
+ anyOf:
89
+ - type: string
90
+ - type: "null"
91
+ ownerEmail:
92
+ description: "Owner email (note: `ownerEmail` in response, `owner_email` in request)."
93
+ anyOf:
94
+ - type: string
95
+ - type: "null"
96
+ stack:
97
+ anyOf:
98
+ - type: array
99
+ items:
100
+ oneOf:
101
+ - type: object
102
+ properties:
103
+ id:
104
+ type: string
105
+ minLength: 1
106
+ description: Client-supplied stable id for the stack entry (used for React keys, audit diffs, and as the default per-condition rollout salt).
107
+ type:
108
+ type: string
109
+ const: condition
110
+ description: Discriminator. `condition` = rule-based predicate sub-gate.
111
+ name:
112
+ description: Human label shown in the dashboard.
113
+ type: string
114
+ fromTemplate:
115
+ description: Id of the project template this entry was seeded from, or `null` if hand-authored.
116
+ anyOf:
117
+ - type: string
118
+ - type: "null"
119
+ pass:
120
+ description: Combinator across `rules`. `all` = AND (default), `any` = OR.
121
+ type: string
122
+ enum:
123
+ - all
124
+ - any
125
+ rules:
126
+ default: []
127
+ description: Predicates evaluated under `pass`. Empty array = match nothing.
128
+ type: array
129
+ items:
130
+ type: object
97
131
  properties:
98
- id:
132
+ attr:
99
133
  type: string
100
134
  minLength: 1
101
- description: Client-supplied stable id for the stack entry (used for React keys, audit diffs, and as the default per-condition rollout salt).
102
- type:
103
- type: string
104
- const: condition
105
- description: Discriminator. `condition` = rule-based predicate sub-gate.
106
- name:
107
- description: Human label shown in the dashboard.
108
- type: string
109
- fromTemplate:
110
- description: Id of the project template this entry was seeded from, or `null` if hand-authored.
111
- anyOf:
112
- - type: string
113
- - type: "null"
114
- pass:
115
- description: Combinator across `rules`. `all` = AND (default), `any` = OR.
135
+ description: Attribute key on the evaluation context (e.g. `country`, `plan`, `email`). Matched case-sensitively against `Shipeasy.checkGate(user, name)` input.
136
+ op:
116
137
  type: string
117
138
  enum:
118
- - all
119
- - any
120
- rules:
121
- default: []
122
- description: Predicates evaluated under `pass`. Empty array = match nothing.
123
- type: array
124
- items:
125
- type: object
126
- properties:
127
- attr:
128
- type: string
129
- minLength: 1
130
- description: Attribute key on the evaluation context (e.g. `country`, `plan`, `email`). Matched case-sensitively against `Shipeasy.checkGate(user, name)` input.
131
- op:
132
- type: string
133
- enum:
134
- - eq
135
- - neq
136
- - in
137
- - not_in
138
- - gt
139
- - gte
140
- - lt
141
- - lte
142
- - contains
143
- - regex
144
- - semver_gt
145
- - semver_gte
146
- - semver_lt
147
- - semver_lte
148
- - gate_pass
149
- - exp_in
150
- description: "Comparison operator. Equality: `eq`/`neq`. Set membership: `in`/`not_in` (value is an array). Numeric order: `gt`/`gte`/`lt`/`lte`. Semver order: `semver_gt`/`semver_gte`/`semver_lt`/`semver_lte` (value is a dotted version like `4.2.0`). String: `contains` (substring), `regex` (JS-flavour pattern, value is the pattern string). Cross-resource references (evaluated only on the worker hot path, where both KV blobs load): `gate_pass` (`value` is another gate's name — true when that gate passes for the same caller); `exp_in` (`attr` is a running experiment's name, `value` is a group name, `\"$holdout\"`, or `\"$any\"` — true when the caller is in that variant / the universe holdout / any variant)."
151
- value:
152
- description: 'Operand. Shape depends on `op`: scalar for `eq/neq/gt/gte/lt/lte/contains/semver_*`; array of scalars for `in/not_in`; string pattern for `regex`; referenced gate name for `gate_pass`; group name / `"$holdout"` / `"$any"` for `exp_in`.'
153
- required:
154
- - attr
155
- - op
156
- - value
157
- additionalProperties: false
158
- description: Single targeting predicate. A gate's `rules` array is evaluated with AND semantics; use the gatekeeper `stack` for OR / fall-through logic.
159
- rolloutPct:
160
- description: Per-condition rollout in basis points. After the rules match, the caller is bucketed at this %; in-bucket → gate `true`, otherwise fall through to the next entry. Absent ⇒ 10000 (100%, every matching caller passes).
161
- type: integer
162
- minimum: 0
163
- maximum: 10000
164
- bucketBy:
165
- description: Attribute used to hash the caller into the per-condition bucket. Default `userID`.
166
- type: string
167
- salt:
168
- description: Per-condition hash salt. Defaults to the entry `id`, then the gate salt.
169
- type: string
170
- ramp:
171
- type: object
172
- properties:
173
- from:
174
- type: integer
175
- minimum: 0
176
- maximum: 10000
177
- description: Start of the ramp in basis points (0–10000).
178
- to:
179
- type: integer
180
- minimum: 0
181
- maximum: 10000
182
- description: End of the ramp in basis points (0–10000).
183
- startAt:
184
- type: integer
185
- minimum: 0
186
- maximum: 9007199254740991
187
- description: Ramp start, epoch milliseconds (UTC).
188
- durationMs:
189
- type: integer
190
- exclusiveMinimum: 0
191
- maximum: 9007199254740991
192
- description: Ramp length in milliseconds.
193
- required:
194
- - from
195
- - to
196
- - startAt
197
- - durationMs
198
- additionalProperties: false
199
- description: Linear rollout ramp. The effective rollout % interpolates `from`→`to` over `[startAt, startAt+durationMs]`, clamped outside that window, evaluated against the wall-clock at eval time. Overrides the entry's static `rolloutPct` while present.
200
- locked:
201
- description: If `true`, dashboard hides edit controls (e.g. the trailing public-floor entry).
202
- type: boolean
203
- required:
204
- - id
205
- - type
206
- additionalProperties: false
207
- description: Rule-based sub-gate. When the rules match and the caller falls in the per-condition rollout bucket, evaluation short-circuits and the gate returns `true`; otherwise it falls through to the next entry.
208
- - type: object
209
- properties:
210
- id:
211
- type: string
212
- minLength: 1
213
- description: Client-supplied stable id for the stack entry.
214
- type:
215
- type: string
216
- const: rollout
217
- description: Discriminator. `rollout` = percentage-bucket sub-gate.
218
- name:
219
- description: Human label shown in the dashboard.
220
- type: string
221
- fromTemplate:
222
- description: Source template id, or `null`.
223
- anyOf:
224
- - type: string
225
- - type: "null"
226
- rolloutPct:
227
- type: integer
228
- minimum: 0
229
- maximum: 10000
230
- description: Bucket size in basis points (0–10000 = 0%–100%). `5000` = 50%, `100` = 1%, allows sub-1% precision.
231
- bucketBy:
232
- description: Attribute used to hash the caller into a bucket. Defaults to `user.userID`. Use e.g. `accountID` to bucket whole accounts together.
233
- type: string
234
- salt:
235
- description: Per-entry hash salt. Defaults to the gate's salt. Set explicitly to keep two rollouts independent or correlated across gates.
236
- type: string
237
- ramp:
238
- type: object
239
- properties:
240
- from:
241
- type: integer
242
- minimum: 0
243
- maximum: 10000
244
- description: Start of the ramp in basis points (0–10000).
245
- to:
246
- type: integer
247
- minimum: 0
248
- maximum: 10000
249
- description: End of the ramp in basis points (0–10000).
250
- startAt:
251
- type: integer
252
- minimum: 0
253
- maximum: 9007199254740991
254
- description: Ramp start, epoch milliseconds (UTC).
255
- durationMs:
256
- type: integer
257
- exclusiveMinimum: 0
258
- maximum: 9007199254740991
259
- description: Ramp length in milliseconds.
260
- required:
261
- - from
262
- - to
263
- - startAt
264
- - durationMs
265
- additionalProperties: false
266
- description: Linear rollout ramp. The effective rollout % interpolates `from`→`to` over `[startAt, startAt+durationMs]`, clamped outside that window, evaluated against the wall-clock at eval time. Overrides the entry's static `rolloutPct` while present.
267
- locked:
268
- description: If `true`, dashboard hides edit controls.
269
- type: boolean
139
+ - eq
140
+ - neq
141
+ - in
142
+ - not_in
143
+ - gt
144
+ - gte
145
+ - lt
146
+ - lte
147
+ - contains
148
+ - regex
149
+ - semver_gt
150
+ - semver_gte
151
+ - semver_lt
152
+ - semver_lte
153
+ - gate_pass
154
+ - exp_in
155
+ description: "Comparison operator. Equality: `eq`/`neq`. Set membership: `in`/`not_in` (value is an array). Numeric order: `gt`/`gte`/`lt`/`lte`. Semver order: `semver_gt`/`semver_gte`/`semver_lt`/`semver_lte` (value is a dotted version like `4.2.0`). String: `contains` (substring), `regex` (JS-flavour pattern, value is the pattern string). Cross-resource references (evaluated only on the worker hot path, where both KV blobs load): `gate_pass` (`value` is another gate's name — true when that gate passes for the same caller); `exp_in` (`attr` is a running experiment's name, `value` is a group name, `\"$holdout\"`, or `\"$any\"` — true when the caller is in that variant / the universe holdout / any variant)."
156
+ value:
157
+ description: 'Operand. Shape depends on `op`: scalar for `eq/neq/gt/gte/lt/lte/contains/semver_*`; array of scalars for `in/not_in`; string pattern for `regex`; referenced gate name for `gate_pass`; group name / `"$holdout"` / `"$any"` for `exp_in`.'
270
158
  required:
271
- - id
272
- - type
273
- - rolloutPct
159
+ - attr
160
+ - op
161
+ - value
274
162
  additionalProperties: false
275
- description: Percentage-rollout sub-gate. Hashes `bucketBy` (default `userID`) with `salt` and returns `true` for `rolloutPct/10000` fraction of callers (or the ramp's effective % when `ramp` is set).
276
- description: One entry in the ordered gatekeeper stack. Evaluated top-to-bottom; first matching entry decides. Mix `condition` and `rollout` entries to express `internal-only` + `1% beta` + `50% public` in a single gate.
277
- - type: "null"
278
- updatedAt:
279
- type: string
280
- description: ISO-8601 timestamp of last mutation.
281
- required:
282
- - id
283
- - name
284
- - enabled
285
- - rolloutPct
286
- - updatedAt
287
- additionalProperties: false
163
+ description: Single targeting predicate. A gate's `rules` array is evaluated with AND semantics; use the gatekeeper `stack` for OR / fall-through logic.
164
+ rolloutPct:
165
+ description: Per-condition rollout in basis points. After the rules match, the caller is bucketed at this %; in-bucket → gate `true`, otherwise fall through to the next entry. Absent ⇒ 10000 (100%, every matching caller passes).
166
+ type: integer
167
+ minimum: 0
168
+ maximum: 10000
169
+ bucketBy:
170
+ description: Attribute used to hash the caller into the per-condition bucket. Default `userID`.
171
+ type: string
172
+ salt:
173
+ description: Per-condition hash salt. Defaults to the entry `id`, then the gate salt.
174
+ type: string
175
+ ramp:
176
+ type: object
177
+ properties:
178
+ from:
179
+ type: integer
180
+ minimum: 0
181
+ maximum: 10000
182
+ description: Start of the ramp in basis points (0–10000).
183
+ to:
184
+ type: integer
185
+ minimum: 0
186
+ maximum: 10000
187
+ description: End of the ramp in basis points (0–10000).
188
+ startAt:
189
+ type: integer
190
+ minimum: 0
191
+ maximum: 9007199254740991
192
+ description: Ramp start, epoch milliseconds (UTC).
193
+ durationMs:
194
+ type: integer
195
+ exclusiveMinimum: 0
196
+ maximum: 9007199254740991
197
+ description: Ramp length in milliseconds.
198
+ required:
199
+ - from
200
+ - to
201
+ - startAt
202
+ - durationMs
203
+ additionalProperties: false
204
+ description: Linear rollout ramp. The effective rollout % interpolates `from`→`to` over `[startAt, startAt+durationMs]`, clamped outside that window, evaluated against the wall-clock at eval time. Overrides the entry's static `rolloutPct` while present.
205
+ locked:
206
+ description: If `true`, dashboard hides edit controls (e.g. the trailing public-floor entry).
207
+ type: boolean
208
+ required:
209
+ - id
210
+ - type
211
+ additionalProperties: false
212
+ description: Rule-based sub-gate. When the rules match and the caller falls in the per-condition rollout bucket, evaluation short-circuits and the gate returns `true`; otherwise it falls through to the next entry.
213
+ - type: object
214
+ properties:
215
+ id:
216
+ type: string
217
+ minLength: 1
218
+ description: Client-supplied stable id for the stack entry.
219
+ type:
220
+ type: string
221
+ const: rollout
222
+ description: Discriminator. `rollout` = percentage-bucket sub-gate.
223
+ name:
224
+ description: Human label shown in the dashboard.
225
+ type: string
226
+ fromTemplate:
227
+ description: Source template id, or `null`.
228
+ anyOf:
229
+ - type: string
230
+ - type: "null"
231
+ rolloutPct:
232
+ type: integer
233
+ minimum: 0
234
+ maximum: 10000
235
+ description: Bucket size in basis points (0–10000 = 0%–100%). `5000` = 50%, `100` = 1%, allows sub-1% precision.
236
+ bucketBy:
237
+ description: Attribute used to hash the caller into a bucket. Defaults to `user.userID`. Use e.g. `accountID` to bucket whole accounts together.
238
+ type: string
239
+ salt:
240
+ description: Per-entry hash salt. Defaults to the gate's salt. Set explicitly to keep two rollouts independent or correlated across gates.
241
+ type: string
242
+ ramp:
243
+ type: object
244
+ properties:
245
+ from:
246
+ type: integer
247
+ minimum: 0
248
+ maximum: 10000
249
+ description: Start of the ramp in basis points (0–10000).
250
+ to:
251
+ type: integer
252
+ minimum: 0
253
+ maximum: 10000
254
+ description: End of the ramp in basis points (0–10000).
255
+ startAt:
256
+ type: integer
257
+ minimum: 0
258
+ maximum: 9007199254740991
259
+ description: Ramp start, epoch milliseconds (UTC).
260
+ durationMs:
261
+ type: integer
262
+ exclusiveMinimum: 0
263
+ maximum: 9007199254740991
264
+ description: Ramp length in milliseconds.
265
+ required:
266
+ - from
267
+ - to
268
+ - startAt
269
+ - durationMs
270
+ additionalProperties: false
271
+ description: Linear rollout ramp. The effective rollout % interpolates `from`→`to` over `[startAt, startAt+durationMs]`, clamped outside that window, evaluated against the wall-clock at eval time. Overrides the entry's static `rolloutPct` while present.
272
+ locked:
273
+ description: If `true`, dashboard hides edit controls.
274
+ type: boolean
275
+ required:
276
+ - id
277
+ - type
278
+ - rolloutPct
279
+ additionalProperties: false
280
+ description: Percentage-rollout sub-gate. Hashes `bucketBy` (default `userID`) with `salt` and returns `true` for `rolloutPct/10000` fraction of callers (or the ramp's effective % when `ramp` is set).
281
+ description: One entry in the ordered gatekeeper stack. Evaluated top-to-bottom; first matching entry decides. Mix `condition` and `rollout` entries to express `internal-only` + `1% beta` + `50% public` in a single gate.
282
+ - type: "null"
283
+ updatedAt:
284
+ type: string
285
+ description: ISO-8601 timestamp of last mutation.
286
+ creatorEmail:
287
+ description: Resolved email of the user who created the gate (`created_by` → `users.email`), or `null` when the creator is unknown.
288
+ anyOf:
289
+ - type: string
290
+ - type: "null"
291
+ updaterEmail:
292
+ description: Resolved email of the user who last edited the gate (`updated_by` → `users.email`), or `null` when the last editor is unknown.
293
+ anyOf:
294
+ - type: string
295
+ - type: "null"
296
+ version:
297
+ type: integer
298
+ minimum: 1
299
+ maximum: 9007199254740991
300
+ description: Monotonic edit counter — starts at 1 on create (D1 `NOT NULL DEFAULT 1`) and increments on every `PATCH /api/admin/gates/{id}`.
301
+ createdAt:
302
+ description: ISO-8601 creation timestamp, or `null` on legacy rows created before the column existed.
303
+ anyOf:
304
+ - type: string
305
+ - type: "null"
306
+ required:
307
+ - id
308
+ - name
309
+ - enabled
310
+ - rolloutPct
311
+ - updatedAt
312
+ - creatorEmail
313
+ - updaterEmail
314
+ - version
315
+ - createdAt
316
+ additionalProperties: false
317
+ description: The single wire shape for a gate row, shared by `ListGatesResponse` (`data[]` items) and `GET /api/admin/gates/{id}`.
318
+ ListGatesResponse:
319
+ type: object
320
+ properties:
321
+ data:
322
+ type: array
323
+ items:
324
+ $ref: "#/GateApiRow"
288
325
  next_cursor:
289
326
  anyOf:
290
327
  - type: string
@@ -301,6 +338,13 @@ CreateGateRequest:
301
338
  maxLength: 128
302
339
  pattern: ^[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)?$
303
340
  description: Stable gate key used by SDKs (`Shipeasy.checkGate(user, '<name>')`). Single segment or `folder.name`. Lowercase letters, digits, `_` or `-`; max 128 chars. Immutable after create — rename = delete + recreate.
341
+ type:
342
+ default: targeting
343
+ type: string
344
+ enum:
345
+ - targeting
346
+ - holdout
347
+ description: Gate kind. `targeting` (default) is a normal flag with the full builder. `holdout` is a **restricted** flag — only a public rollout % and a whitelist are allowed; attribute rules and a gatekeeper stack are rejected. Used as an experiment's `holdout_gate`.
304
348
  enabled:
305
349
  default: true
306
350
  description: Master switch. Defaults to `true`. Set `false` to create the gate disabled (evaluates to `false` regardless of rules/rollout); flip on via `POST /{id}/enable` or PATCH.
@@ -588,6 +632,12 @@ CreateGateResponse:
588
632
  UpdateGateRequest:
589
633
  type: object
590
634
  properties:
635
+ type:
636
+ type: string
637
+ enum:
638
+ - targeting
639
+ - holdout
640
+ description: Gate kind. Switching to `holdout` requires the gate carry only a public rollout % + whitelist (attribute rules / stack are rejected).
591
641
  rollout_pct:
592
642
  description: New rollout in **basis points** (0–10000 = 0%–100%) — `100` here means **1%**. Use `rollout_percent` (0–100) below for percent. Omit both to leave unchanged.
593
643
  type: integer
@@ -888,3 +938,36 @@ DisableGateResponse:
888
938
  - id
889
939
  - enabled
890
940
  additionalProperties: false
941
+ GetGateResponse:
942
+ $ref: "#/GateApiRow"
943
+ ListGateActivityResponse:
944
+ type: array
945
+ items:
946
+ type: object
947
+ properties:
948
+ id:
949
+ type: string
950
+ action:
951
+ type: string
952
+ description: Audit action (e.g. `gate.create`, `gate.update`, `gate.enable`, `gate.disable`, `gate.delete`).
953
+ actorEmail:
954
+ type: string
955
+ actorType:
956
+ type: string
957
+ enum:
958
+ - user
959
+ - cli
960
+ - system
961
+ payload: {}
962
+ createdAt:
963
+ type: string
964
+ description: ISO-8601 timestamp.
965
+ required:
966
+ - id
967
+ - action
968
+ - actorEmail
969
+ - actorType
970
+ - payload
971
+ - createdAt
972
+ additionalProperties: false
973
+ description: Recent audit rows for one gate, newest first.