@shipeasy/openapi 2.3.0 → 2.5.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 (46) hide show
  1. package/dist/{chunk-PRN4AEAM.js → chunk-DBTSD3W5.js} +1085 -261
  2. package/dist/chunk-DBTSD3W5.js.map +1 -0
  3. package/dist/{chunk-LYNWK55D.js → chunk-RDMD5XQT.js} +171 -1
  4. package/dist/chunk-RDMD5XQT.js.map +1 -0
  5. package/dist/{client-DO5HTb_L.d.ts → client-ObcuFHaV.d.ts} +5605 -2734
  6. package/dist/client.d.ts +1 -1
  7. package/dist/client.js +47 -1
  8. package/dist/custom.d.ts +9 -4
  9. package/dist/custom.js +57 -9
  10. package/dist/custom.js.map +1 -1
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.js +48 -2
  13. package/dist/index.js.map +1 -1
  14. package/dist/schemas.d.ts +3171 -485
  15. package/dist/schemas.js +229 -1
  16. package/openapi.json +13264 -8071
  17. package/openapi.yaml +5108 -1550
  18. package/package.json +1 -1
  19. package/spec/components/errors.yaml +3 -0
  20. package/spec/components/schemas/alerts.yaml +138 -0
  21. package/spec/components/schemas/attributes.yaml +53 -3
  22. package/spec/components/schemas/common.yaml +10 -0
  23. package/spec/components/schemas/configs.yaml +91 -3
  24. package/spec/components/schemas/connectors.yaml +5 -1
  25. package/spec/components/schemas/errors-api.yaml +51 -4
  26. package/spec/components/schemas/experiments.yaml +347 -87
  27. package/spec/components/schemas/gates.yaml +350 -277
  28. package/spec/components/schemas/i18n.yaml +169 -40
  29. package/spec/components/schemas/killswitches.yaml +36 -0
  30. package/spec/components/schemas/metrics.yaml +199 -7
  31. package/spec/components/schemas/ops.yaml +961 -29
  32. package/spec/components/schemas/projects.yaml +129 -3
  33. package/spec/openapi.yaml +58 -0
  34. package/spec/paths/alerts.yaml +184 -0
  35. package/spec/paths/attributes.yaml +23 -5
  36. package/spec/paths/configs.yaml +98 -21
  37. package/spec/paths/errors.yaml +16 -0
  38. package/spec/paths/experiments.yaml +236 -16
  39. package/spec/paths/gates.yaml +137 -0
  40. package/spec/paths/i18n.yaml +290 -6
  41. package/spec/paths/killswitches.yaml +6 -0
  42. package/spec/paths/metrics.yaml +186 -0
  43. package/spec/paths/ops.yaml +382 -0
  44. package/spec/paths/projects.yaml +60 -0
  45. package/dist/chunk-LYNWK55D.js.map +0 -1
  46. package/dist/chunk-PRN4AEAM.js.map +0 -1
@@ -1,296 +1,330 @@
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
- type:
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:
25
44
  type: string
26
45
  enum:
27
- - targeting
28
- - holdout
29
- description: Gate kind — `targeting` (normal flag) or `holdout` (restricted public % + whitelist).
30
- rolloutPct:
31
- type: integer
32
- minimum: 0
33
- maximum: 10000
34
- description: Current rollout in basis points (0–10000).
35
- rules:
36
- type: array
37
- items:
38
- type: object
39
- properties:
40
- attr:
41
- type: string
42
- minLength: 1
43
- description: Attribute key on the evaluation context (e.g. `country`, `plan`, `email`). Matched case-sensitively against `Shipeasy.checkGate(user, name)` input.
44
- op:
45
- type: string
46
- enum:
47
- - eq
48
- - neq
49
- - in
50
- - not_in
51
- - gt
52
- - gte
53
- - lt
54
- - lte
55
- - contains
56
- - regex
57
- - semver_gt
58
- - semver_gte
59
- - semver_lt
60
- - semver_lte
61
- - gate_pass
62
- - exp_in
63
- 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)."
64
- value:
65
- 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`.'
66
- required:
67
- - attr
68
- - op
69
- - value
70
- additionalProperties: false
71
- description: Single targeting predicate. A gate's `rules` array is evaluated with AND semantics; use the gatekeeper `stack` for OR / fall-through logic.
72
- salt:
73
- description: Hash salt used for percentage bucketing.
74
- type: string
75
- title:
76
- anyOf:
77
- - type: string
78
- - type: "null"
79
- description:
80
- anyOf:
81
- - type: string
82
- - type: "null"
83
- folder:
84
- anyOf:
85
- - type: string
86
- - type: "null"
87
- groupName:
88
- description: "Group label (note: `groupName` in response, `group` in request)."
89
- anyOf:
90
- - type: string
91
- - type: "null"
92
- ownerEmail:
93
- description: "Owner email (note: `ownerEmail` in response, `owner_email` in request)."
94
- anyOf:
95
- - type: string
96
- - type: "null"
97
- stack:
98
- anyOf:
99
- - type: array
100
- items:
101
- oneOf:
102
- - type: object
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
103
131
  properties:
104
- id:
132
+ attr:
105
133
  type: string
106
134
  minLength: 1
107
- description: Client-supplied stable id for the stack entry (used for React keys, audit diffs, and as the default per-condition rollout salt).
108
- type:
109
- type: string
110
- const: condition
111
- description: Discriminator. `condition` = rule-based predicate sub-gate.
112
- name:
113
- description: Human label shown in the dashboard.
114
- type: string
115
- fromTemplate:
116
- description: Id of the project template this entry was seeded from, or `null` if hand-authored.
117
- anyOf:
118
- - type: string
119
- - type: "null"
120
- pass:
121
- 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:
122
137
  type: string
123
138
  enum:
124
- - all
125
- - any
126
- rules:
127
- default: []
128
- description: Predicates evaluated under `pass`. Empty array = match nothing.
129
- type: array
130
- items:
131
- type: object
132
- properties:
133
- attr:
134
- type: string
135
- minLength: 1
136
- description: Attribute key on the evaluation context (e.g. `country`, `plan`, `email`). Matched case-sensitively against `Shipeasy.checkGate(user, name)` input.
137
- op:
138
- type: string
139
- enum:
140
- - eq
141
- - neq
142
- - in
143
- - not_in
144
- - gt
145
- - gte
146
- - lt
147
- - lte
148
- - contains
149
- - regex
150
- - semver_gt
151
- - semver_gte
152
- - semver_lt
153
- - semver_lte
154
- - gate_pass
155
- - exp_in
156
- 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)."
157
- value:
158
- 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`.'
159
- required:
160
- - attr
161
- - op
162
- - value
163
- additionalProperties: false
164
- description: Single targeting predicate. A gate's `rules` array is evaluated with AND semantics; use the gatekeeper `stack` for OR / fall-through logic.
165
- rolloutPct:
166
- 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).
167
- type: integer
168
- minimum: 0
169
- maximum: 10000
170
- bucketBy:
171
- description: Attribute used to hash the caller into the per-condition bucket. Default `userID`.
172
- type: string
173
- salt:
174
- description: Per-condition hash salt. Defaults to the entry `id`, then the gate salt.
175
- type: string
176
- ramp:
177
- type: object
178
- properties:
179
- from:
180
- type: integer
181
- minimum: 0
182
- maximum: 10000
183
- description: Start of the ramp in basis points (0–10000).
184
- to:
185
- type: integer
186
- minimum: 0
187
- maximum: 10000
188
- description: End of the ramp in basis points (0–10000).
189
- startAt:
190
- type: integer
191
- minimum: 0
192
- maximum: 9007199254740991
193
- description: Ramp start, epoch milliseconds (UTC).
194
- durationMs:
195
- type: integer
196
- exclusiveMinimum: 0
197
- maximum: 9007199254740991
198
- description: Ramp length in milliseconds.
199
- required:
200
- - from
201
- - to
202
- - startAt
203
- - durationMs
204
- additionalProperties: false
205
- 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.
206
- locked:
207
- description: If `true`, dashboard hides edit controls (e.g. the trailing public-floor entry).
208
- type: boolean
209
- required:
210
- - id
211
- - type
212
- additionalProperties: false
213
- 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.
214
- - type: object
215
- properties:
216
- id:
217
- type: string
218
- minLength: 1
219
- description: Client-supplied stable id for the stack entry.
220
- type:
221
- type: string
222
- const: rollout
223
- description: Discriminator. `rollout` = percentage-bucket sub-gate.
224
- name:
225
- description: Human label shown in the dashboard.
226
- type: string
227
- fromTemplate:
228
- description: Source template id, or `null`.
229
- anyOf:
230
- - type: string
231
- - type: "null"
232
- rolloutPct:
233
- type: integer
234
- minimum: 0
235
- maximum: 10000
236
- description: Bucket size in basis points (0–10000 = 0%–100%). `5000` = 50%, `100` = 1%, allows sub-1% precision.
237
- bucketBy:
238
- description: Attribute used to hash the caller into a bucket. Defaults to `user.userID`. Use e.g. `accountID` to bucket whole accounts together.
239
- type: string
240
- salt:
241
- description: Per-entry hash salt. Defaults to the gate's salt. Set explicitly to keep two rollouts independent or correlated across gates.
242
- type: string
243
- ramp:
244
- type: object
245
- properties:
246
- from:
247
- type: integer
248
- minimum: 0
249
- maximum: 10000
250
- description: Start of the ramp in basis points (0–10000).
251
- to:
252
- type: integer
253
- minimum: 0
254
- maximum: 10000
255
- description: End of the ramp in basis points (0–10000).
256
- startAt:
257
- type: integer
258
- minimum: 0
259
- maximum: 9007199254740991
260
- description: Ramp start, epoch milliseconds (UTC).
261
- durationMs:
262
- type: integer
263
- exclusiveMinimum: 0
264
- maximum: 9007199254740991
265
- description: Ramp length in milliseconds.
266
- required:
267
- - from
268
- - to
269
- - startAt
270
- - durationMs
271
- additionalProperties: false
272
- 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.
273
- locked:
274
- description: If `true`, dashboard hides edit controls.
275
- 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`.'
276
158
  required:
277
- - id
278
- - type
279
- - rolloutPct
159
+ - attr
160
+ - op
161
+ - value
280
162
  additionalProperties: false
281
- 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).
282
- 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.
283
- - type: "null"
284
- updatedAt:
285
- type: string
286
- description: ISO-8601 timestamp of last mutation.
287
- required:
288
- - id
289
- - name
290
- - enabled
291
- - rolloutPct
292
- - updatedAt
293
- 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
+ whitelist:
209
+ description: Cosmetic marker. When `true`, the dashboard renders this condition as the pinned, always-first "whitelist" allowlist block (a direct `email`/`user_id` `in […]` list) rather than a numbered targeting step. Purely presentational — ignored by evaluation, which treats the entry as an ordinary condition.
210
+ type: boolean
211
+ required:
212
+ - id
213
+ - type
214
+ additionalProperties: false
215
+ 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.
216
+ - type: object
217
+ properties:
218
+ id:
219
+ type: string
220
+ minLength: 1
221
+ description: Client-supplied stable id for the stack entry.
222
+ type:
223
+ type: string
224
+ const: rollout
225
+ description: Discriminator. `rollout` = percentage-bucket sub-gate.
226
+ name:
227
+ description: Human label shown in the dashboard.
228
+ type: string
229
+ fromTemplate:
230
+ description: Source template id, or `null`.
231
+ anyOf:
232
+ - type: string
233
+ - type: "null"
234
+ rolloutPct:
235
+ type: integer
236
+ minimum: 0
237
+ maximum: 10000
238
+ description: Bucket size in basis points (0–10000 = 0%–100%). `5000` = 50%, `100` = 1%, allows sub-1% precision.
239
+ bucketBy:
240
+ description: Attribute used to hash the caller into a bucket. Defaults to `user.userID`. Use e.g. `accountID` to bucket whole accounts together.
241
+ type: string
242
+ salt:
243
+ description: Per-entry hash salt. Defaults to the gate's salt. Set explicitly to keep two rollouts independent or correlated across gates.
244
+ type: string
245
+ ramp:
246
+ type: object
247
+ properties:
248
+ from:
249
+ type: integer
250
+ minimum: 0
251
+ maximum: 10000
252
+ description: Start of the ramp in basis points (0–10000).
253
+ to:
254
+ type: integer
255
+ minimum: 0
256
+ maximum: 10000
257
+ description: End of the ramp in basis points (0–10000).
258
+ startAt:
259
+ type: integer
260
+ minimum: 0
261
+ maximum: 9007199254740991
262
+ description: Ramp start, epoch milliseconds (UTC).
263
+ durationMs:
264
+ type: integer
265
+ exclusiveMinimum: 0
266
+ maximum: 9007199254740991
267
+ description: Ramp length in milliseconds.
268
+ required:
269
+ - from
270
+ - to
271
+ - startAt
272
+ - durationMs
273
+ additionalProperties: false
274
+ 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.
275
+ locked:
276
+ description: If `true`, dashboard hides edit controls.
277
+ type: boolean
278
+ required:
279
+ - id
280
+ - type
281
+ - rolloutPct
282
+ additionalProperties: false
283
+ 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).
284
+ 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.
285
+ - type: "null"
286
+ updatedAt:
287
+ type: string
288
+ description: ISO-8601 timestamp of last mutation.
289
+ creatorEmail:
290
+ description: Resolved email of the user who created the gate (`created_by` → `users.email`), or `null` when the creator is unknown.
291
+ anyOf:
292
+ - type: string
293
+ - type: "null"
294
+ updaterEmail:
295
+ description: Resolved email of the user who last edited the gate (`updated_by` → `users.email`), or `null` when the last editor is unknown.
296
+ anyOf:
297
+ - type: string
298
+ - type: "null"
299
+ version:
300
+ type: integer
301
+ minimum: 1
302
+ maximum: 9007199254740991
303
+ description: Monotonic edit counter — starts at 1 on create (D1 `NOT NULL DEFAULT 1`) and increments on every `PATCH /api/admin/gates/{id}`.
304
+ createdAt:
305
+ description: ISO-8601 creation timestamp, or `null` on legacy rows created before the column existed.
306
+ anyOf:
307
+ - type: string
308
+ - type: "null"
309
+ required:
310
+ - id
311
+ - name
312
+ - enabled
313
+ - rolloutPct
314
+ - updatedAt
315
+ - creatorEmail
316
+ - updaterEmail
317
+ - version
318
+ - createdAt
319
+ additionalProperties: false
320
+ description: The single wire shape for a gate row, shared by `ListGatesResponse` (`data[]` items) and `GET /api/admin/gates/{id}`.
321
+ ListGatesResponse:
322
+ type: object
323
+ properties:
324
+ data:
325
+ type: array
326
+ items:
327
+ $ref: "#/GateApiRow"
294
328
  next_cursor:
295
329
  anyOf:
296
330
  - type: string
@@ -486,6 +520,9 @@ CreateGateRequest:
486
520
  locked:
487
521
  description: If `true`, dashboard hides edit controls (e.g. the trailing public-floor entry).
488
522
  type: boolean
523
+ whitelist:
524
+ description: Cosmetic marker. When `true`, the dashboard renders this condition as the pinned, always-first "whitelist" allowlist block (a direct `email`/`user_id` `in […]` list) rather than a numbered targeting step. Purely presentational — ignored by evaluation, which treats the entry as an ordinary condition.
525
+ type: boolean
489
526
  required:
490
527
  - id
491
528
  - type
@@ -771,6 +808,9 @@ UpdateGateRequest:
771
808
  locked:
772
809
  description: If `true`, dashboard hides edit controls (e.g. the trailing public-floor entry).
773
810
  type: boolean
811
+ whitelist:
812
+ description: Cosmetic marker. When `true`, the dashboard renders this condition as the pinned, always-first "whitelist" allowlist block (a direct `email`/`user_id` `in […]` list) rather than a numbered targeting step. Purely presentational — ignored by evaluation, which treats the entry as an ordinary condition.
813
+ type: boolean
774
814
  required:
775
815
  - id
776
816
  - type
@@ -907,3 +947,36 @@ DisableGateResponse:
907
947
  - id
908
948
  - enabled
909
949
  additionalProperties: false
950
+ GetGateResponse:
951
+ $ref: "#/GateApiRow"
952
+ ListGateActivityResponse:
953
+ type: array
954
+ items:
955
+ type: object
956
+ properties:
957
+ id:
958
+ type: string
959
+ action:
960
+ type: string
961
+ description: Audit action (e.g. `gate.create`, `gate.update`, `gate.enable`, `gate.disable`, `gate.delete`).
962
+ actorEmail:
963
+ type: string
964
+ actorType:
965
+ type: string
966
+ enum:
967
+ - user
968
+ - cli
969
+ - system
970
+ payload: {}
971
+ createdAt:
972
+ type: string
973
+ description: ISO-8601 timestamp.
974
+ required:
975
+ - id
976
+ - action
977
+ - actorEmail
978
+ - actorType
979
+ - payload
980
+ - createdAt
981
+ additionalProperties: false
982
+ description: Recent audit rows for one gate, newest first.