@contractspec/lib.feature-flags 1.57.0 → 1.59.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/browser/contracts/index.js +636 -0
- package/dist/browser/docs/feature-flags.docblock.js +71 -0
- package/dist/browser/docs/index.js +71 -0
- package/dist/browser/entities/index.js +306 -0
- package/dist/browser/evaluation/index.js +223 -0
- package/dist/browser/events.js +296 -0
- package/dist/browser/feature-flags.capability.js +28 -0
- package/dist/browser/feature-flags.feature.js +55 -0
- package/dist/browser/index.js +1583 -0
- package/dist/contracts/index.d.ts +944 -950
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js +635 -906
- package/dist/docs/feature-flags.docblock.d.ts +2 -1
- package/dist/docs/feature-flags.docblock.d.ts.map +1 -0
- package/dist/docs/feature-flags.docblock.js +18 -22
- package/dist/docs/index.d.ts +2 -1
- package/dist/docs/index.d.ts.map +1 -0
- package/dist/docs/index.js +72 -1
- package/dist/entities/index.d.ts +159 -164
- package/dist/entities/index.d.ts.map +1 -1
- package/dist/entities/index.js +297 -315
- package/dist/evaluation/index.d.ts +119 -122
- package/dist/evaluation/index.d.ts.map +1 -1
- package/dist/evaluation/index.js +215 -212
- package/dist/events.d.ts +480 -486
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +272 -511
- package/dist/feature-flags.capability.d.ts +2 -7
- package/dist/feature-flags.capability.d.ts.map +1 -1
- package/dist/feature-flags.capability.js +29 -25
- package/dist/feature-flags.feature.d.ts +1 -6
- package/dist/feature-flags.feature.d.ts.map +1 -1
- package/dist/feature-flags.feature.js +54 -146
- package/dist/index.d.ts +7 -6
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1584 -8
- package/dist/node/contracts/index.js +636 -0
- package/dist/node/docs/feature-flags.docblock.js +71 -0
- package/dist/node/docs/index.js +71 -0
- package/dist/node/entities/index.js +306 -0
- package/dist/node/evaluation/index.js +223 -0
- package/dist/node/events.js +296 -0
- package/dist/node/feature-flags.capability.js +28 -0
- package/dist/node/feature-flags.feature.js +55 -0
- package/dist/node/index.js +1583 -0
- package/package.json +117 -30
- package/dist/contracts/index.js.map +0 -1
- package/dist/docs/feature-flags.docblock.js.map +0 -1
- package/dist/entities/index.js.map +0 -1
- package/dist/evaluation/index.js.map +0 -1
- package/dist/events.js.map +0 -1
- package/dist/feature-flags.capability.js.map +0 -1
- package/dist/feature-flags.feature.js.map +0 -1
package/dist/contracts/index.js
CHANGED
|
@@ -1,908 +1,637 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/contracts/index.ts
|
|
1
3
|
import { ScalarTypeEnum, defineSchemaModel } from "@contractspec/lib.schema";
|
|
2
4
|
import { defineCommand, defineQuery } from "@contractspec/lib.contracts";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
when: "Flag key is invalid"
|
|
637
|
-
} }
|
|
638
|
-
},
|
|
639
|
-
policy: { auth: "user" }
|
|
640
|
-
});
|
|
641
|
-
/**
|
|
642
|
-
* List feature flags.
|
|
643
|
-
*/
|
|
644
|
-
const ListFlagsContract = defineQuery({
|
|
645
|
-
meta: {
|
|
646
|
-
key: "flag.list",
|
|
647
|
-
version: "1.0.0",
|
|
648
|
-
stability: "stable",
|
|
649
|
-
owners: [...OWNERS],
|
|
650
|
-
tags: ["feature-flags", "list"],
|
|
651
|
-
description: "List all feature flags.",
|
|
652
|
-
goal: "View all configured flags.",
|
|
653
|
-
context: "Admin dashboard."
|
|
654
|
-
},
|
|
655
|
-
io: {
|
|
656
|
-
input: ListFlagsInput,
|
|
657
|
-
output: ListFlagsOutput
|
|
658
|
-
},
|
|
659
|
-
policy: { auth: "admin" }
|
|
660
|
-
});
|
|
661
|
-
/**
|
|
662
|
-
* Evaluate a feature flag.
|
|
663
|
-
*/
|
|
664
|
-
const EvaluateFlagContract = defineQuery({
|
|
665
|
-
meta: {
|
|
666
|
-
key: "flag.evaluate",
|
|
667
|
-
version: "1.0.0",
|
|
668
|
-
stability: "stable",
|
|
669
|
-
owners: [...OWNERS],
|
|
670
|
-
tags: ["feature-flags", "evaluate"],
|
|
671
|
-
description: "Evaluate a feature flag for a given context.",
|
|
672
|
-
goal: "Determine if a feature should be enabled.",
|
|
673
|
-
context: "Called at runtime to check feature availability."
|
|
674
|
-
},
|
|
675
|
-
io: {
|
|
676
|
-
input: EvaluateFlagInput,
|
|
677
|
-
output: EvaluationResultModel,
|
|
678
|
-
errors: { FLAG_NOT_FOUND: {
|
|
679
|
-
description: "Flag does not exist",
|
|
680
|
-
http: 404,
|
|
681
|
-
gqlCode: "FLAG_NOT_FOUND",
|
|
682
|
-
when: "Flag key is invalid"
|
|
683
|
-
} }
|
|
684
|
-
},
|
|
685
|
-
policy: { auth: "anonymous" }
|
|
686
|
-
});
|
|
687
|
-
/**
|
|
688
|
-
* Create a targeting rule.
|
|
689
|
-
*/
|
|
690
|
-
const CreateRuleContract = defineCommand({
|
|
691
|
-
meta: {
|
|
692
|
-
key: "flag.rule.create",
|
|
693
|
-
version: "1.0.0",
|
|
694
|
-
stability: "stable",
|
|
695
|
-
owners: [...OWNERS],
|
|
696
|
-
tags: [
|
|
697
|
-
"feature-flags",
|
|
698
|
-
"rule",
|
|
699
|
-
"create"
|
|
700
|
-
],
|
|
701
|
-
description: "Create a targeting rule for a flag.",
|
|
702
|
-
goal: "Add conditional targeting to a flag.",
|
|
703
|
-
context: "Called when setting up targeting."
|
|
704
|
-
},
|
|
705
|
-
io: {
|
|
706
|
-
input: CreateRuleInput,
|
|
707
|
-
output: TargetingRuleModel,
|
|
708
|
-
errors: {
|
|
709
|
-
FLAG_NOT_FOUND: {
|
|
710
|
-
description: "Flag does not exist",
|
|
711
|
-
http: 404,
|
|
712
|
-
gqlCode: "FLAG_NOT_FOUND",
|
|
713
|
-
when: "Flag ID is invalid"
|
|
714
|
-
},
|
|
715
|
-
INVALID_OPERATOR: {
|
|
716
|
-
description: "Invalid operator",
|
|
717
|
-
http: 400,
|
|
718
|
-
gqlCode: "INVALID_OPERATOR",
|
|
719
|
-
when: "Operator is not supported"
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
},
|
|
723
|
-
policy: { auth: "admin" }
|
|
724
|
-
});
|
|
725
|
-
/**
|
|
726
|
-
* Delete a targeting rule.
|
|
727
|
-
*/
|
|
728
|
-
const DeleteRuleContract = defineCommand({
|
|
729
|
-
meta: {
|
|
730
|
-
key: "flag.rule.delete",
|
|
731
|
-
version: "1.0.0",
|
|
732
|
-
stability: "stable",
|
|
733
|
-
owners: [...OWNERS],
|
|
734
|
-
tags: [
|
|
735
|
-
"feature-flags",
|
|
736
|
-
"rule",
|
|
737
|
-
"delete"
|
|
738
|
-
],
|
|
739
|
-
description: "Delete a targeting rule.",
|
|
740
|
-
goal: "Remove a targeting rule from a flag.",
|
|
741
|
-
context: "Called when removing targeting conditions."
|
|
742
|
-
},
|
|
743
|
-
io: {
|
|
744
|
-
input: DeleteRuleInput,
|
|
745
|
-
output: SuccessOutput,
|
|
746
|
-
errors: { RULE_NOT_FOUND: {
|
|
747
|
-
description: "Rule does not exist",
|
|
748
|
-
http: 404,
|
|
749
|
-
gqlCode: "RULE_NOT_FOUND",
|
|
750
|
-
when: "Rule ID is invalid"
|
|
751
|
-
} }
|
|
752
|
-
},
|
|
753
|
-
policy: { auth: "admin" }
|
|
754
|
-
});
|
|
755
|
-
/**
|
|
756
|
-
* Create an experiment.
|
|
757
|
-
*/
|
|
758
|
-
const CreateExperimentContract = defineCommand({
|
|
759
|
-
meta: {
|
|
760
|
-
key: "experiment.create",
|
|
761
|
-
version: "1.0.0",
|
|
762
|
-
stability: "stable",
|
|
763
|
-
owners: [...OWNERS],
|
|
764
|
-
tags: [
|
|
765
|
-
"feature-flags",
|
|
766
|
-
"experiment",
|
|
767
|
-
"create"
|
|
768
|
-
],
|
|
769
|
-
description: "Create an A/B test experiment.",
|
|
770
|
-
goal: "Set up an experiment with variants.",
|
|
771
|
-
context: "Called when setting up A/B testing."
|
|
772
|
-
},
|
|
773
|
-
io: {
|
|
774
|
-
input: CreateExperimentInput,
|
|
775
|
-
output: ExperimentModel,
|
|
776
|
-
errors: {
|
|
777
|
-
FLAG_NOT_FOUND: {
|
|
778
|
-
description: "Flag does not exist",
|
|
779
|
-
http: 404,
|
|
780
|
-
gqlCode: "FLAG_NOT_FOUND",
|
|
781
|
-
when: "Flag ID is invalid"
|
|
782
|
-
},
|
|
783
|
-
EXPERIMENT_KEY_EXISTS: {
|
|
784
|
-
description: "Experiment key already exists",
|
|
785
|
-
http: 409,
|
|
786
|
-
gqlCode: "EXPERIMENT_KEY_EXISTS",
|
|
787
|
-
when: "An experiment with this key already exists"
|
|
788
|
-
},
|
|
789
|
-
INVALID_VARIANTS: {
|
|
790
|
-
description: "Invalid variant configuration",
|
|
791
|
-
http: 400,
|
|
792
|
-
gqlCode: "INVALID_VARIANTS",
|
|
793
|
-
when: "Variant percentages must sum to 100"
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
},
|
|
797
|
-
policy: { auth: "admin" }
|
|
798
|
-
});
|
|
799
|
-
/**
|
|
800
|
-
* Start an experiment.
|
|
801
|
-
*/
|
|
802
|
-
const StartExperimentContract = defineCommand({
|
|
803
|
-
meta: {
|
|
804
|
-
key: "experiment.start",
|
|
805
|
-
version: "1.0.0",
|
|
806
|
-
stability: "stable",
|
|
807
|
-
owners: [...OWNERS],
|
|
808
|
-
tags: [
|
|
809
|
-
"feature-flags",
|
|
810
|
-
"experiment",
|
|
811
|
-
"start"
|
|
812
|
-
],
|
|
813
|
-
description: "Start an experiment.",
|
|
814
|
-
goal: "Begin collecting data for an experiment.",
|
|
815
|
-
context: "Called when ready to run an A/B test."
|
|
816
|
-
},
|
|
817
|
-
io: {
|
|
818
|
-
input: StartExperimentInput,
|
|
819
|
-
output: ExperimentModel,
|
|
820
|
-
errors: {
|
|
821
|
-
EXPERIMENT_NOT_FOUND: {
|
|
822
|
-
description: "Experiment does not exist",
|
|
823
|
-
http: 404,
|
|
824
|
-
gqlCode: "EXPERIMENT_NOT_FOUND",
|
|
825
|
-
when: "Experiment ID is invalid"
|
|
826
|
-
},
|
|
827
|
-
EXPERIMENT_ALREADY_RUNNING: {
|
|
828
|
-
description: "Experiment is already running",
|
|
829
|
-
http: 409,
|
|
830
|
-
gqlCode: "EXPERIMENT_ALREADY_RUNNING",
|
|
831
|
-
when: "Cannot start an experiment that is already running"
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
},
|
|
835
|
-
policy: { auth: "admin" }
|
|
836
|
-
});
|
|
837
|
-
/**
|
|
838
|
-
* Stop an experiment.
|
|
839
|
-
*/
|
|
840
|
-
const StopExperimentContract = defineCommand({
|
|
841
|
-
meta: {
|
|
842
|
-
key: "experiment.stop",
|
|
843
|
-
version: "1.0.0",
|
|
844
|
-
stability: "stable",
|
|
845
|
-
owners: [...OWNERS],
|
|
846
|
-
tags: [
|
|
847
|
-
"feature-flags",
|
|
848
|
-
"experiment",
|
|
849
|
-
"stop"
|
|
850
|
-
],
|
|
851
|
-
description: "Stop an experiment.",
|
|
852
|
-
goal: "End an experiment and optionally declare a winner.",
|
|
853
|
-
context: "Called when concluding an A/B test."
|
|
854
|
-
},
|
|
855
|
-
io: {
|
|
856
|
-
input: StopExperimentInput,
|
|
857
|
-
output: ExperimentModel,
|
|
858
|
-
errors: {
|
|
859
|
-
EXPERIMENT_NOT_FOUND: {
|
|
860
|
-
description: "Experiment does not exist",
|
|
861
|
-
http: 404,
|
|
862
|
-
gqlCode: "EXPERIMENT_NOT_FOUND",
|
|
863
|
-
when: "Experiment ID is invalid"
|
|
864
|
-
},
|
|
865
|
-
EXPERIMENT_NOT_RUNNING: {
|
|
866
|
-
description: "Experiment is not running",
|
|
867
|
-
http: 409,
|
|
868
|
-
gqlCode: "EXPERIMENT_NOT_RUNNING",
|
|
869
|
-
when: "Cannot stop an experiment that is not running"
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
},
|
|
873
|
-
policy: { auth: "admin" }
|
|
874
|
-
});
|
|
875
|
-
/**
|
|
876
|
-
* Get an experiment.
|
|
877
|
-
*/
|
|
878
|
-
const GetExperimentContract = defineQuery({
|
|
879
|
-
meta: {
|
|
880
|
-
key: "experiment.get",
|
|
881
|
-
version: "1.0.0",
|
|
882
|
-
stability: "stable",
|
|
883
|
-
owners: [...OWNERS],
|
|
884
|
-
tags: [
|
|
885
|
-
"feature-flags",
|
|
886
|
-
"experiment",
|
|
887
|
-
"get"
|
|
888
|
-
],
|
|
889
|
-
description: "Get experiment details.",
|
|
890
|
-
goal: "View experiment configuration and results.",
|
|
891
|
-
context: "Called to inspect experiment status."
|
|
892
|
-
},
|
|
893
|
-
io: {
|
|
894
|
-
input: GetExperimentInput,
|
|
895
|
-
output: ExperimentModel,
|
|
896
|
-
errors: { EXPERIMENT_NOT_FOUND: {
|
|
897
|
-
description: "Experiment does not exist",
|
|
898
|
-
http: 404,
|
|
899
|
-
gqlCode: "EXPERIMENT_NOT_FOUND",
|
|
900
|
-
when: "Experiment ID is invalid"
|
|
901
|
-
} }
|
|
902
|
-
},
|
|
903
|
-
policy: { auth: "user" }
|
|
904
|
-
});
|
|
905
|
-
|
|
906
|
-
//#endregion
|
|
907
|
-
export { CreateExperimentContract, CreateFlagContract, CreateRuleContract, DeleteFlagContract, DeleteRuleContract, EvaluateFlagContract, EvaluationResultModel, ExperimentModel, FeatureFlagModel, GetExperimentContract, GetFlagContract, ListFlagsContract, StartExperimentContract, StopExperimentContract, TargetingRuleModel, ToggleFlagContract, UpdateFlagContract };
|
|
908
|
-
//# sourceMappingURL=index.js.map
|
|
5
|
+
var OWNERS = ["platform.feature-flags"];
|
|
6
|
+
var FeatureFlagModel = defineSchemaModel({
|
|
7
|
+
name: "FeatureFlag",
|
|
8
|
+
description: "Represents a feature flag",
|
|
9
|
+
fields: {
|
|
10
|
+
id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
11
|
+
key: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
12
|
+
name: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
13
|
+
description: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
14
|
+
status: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
15
|
+
defaultValue: { type: ScalarTypeEnum.Boolean(), isOptional: false },
|
|
16
|
+
variants: { type: ScalarTypeEnum.JSON(), isOptional: true },
|
|
17
|
+
orgId: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
18
|
+
tags: { type: ScalarTypeEnum.JSON(), isOptional: true },
|
|
19
|
+
createdAt: { type: ScalarTypeEnum.DateTime(), isOptional: false },
|
|
20
|
+
updatedAt: { type: ScalarTypeEnum.DateTime(), isOptional: false }
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
var TargetingRuleModel = defineSchemaModel({
|
|
24
|
+
name: "TargetingRule",
|
|
25
|
+
description: "Represents a targeting rule",
|
|
26
|
+
fields: {
|
|
27
|
+
id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
28
|
+
flagId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
29
|
+
name: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
30
|
+
priority: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
|
|
31
|
+
enabled: { type: ScalarTypeEnum.Boolean(), isOptional: false },
|
|
32
|
+
attribute: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
33
|
+
operator: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
34
|
+
value: { type: ScalarTypeEnum.JSON(), isOptional: false },
|
|
35
|
+
rolloutPercentage: {
|
|
36
|
+
type: ScalarTypeEnum.Int_unsecure(),
|
|
37
|
+
isOptional: true
|
|
38
|
+
},
|
|
39
|
+
serveValue: { type: ScalarTypeEnum.Boolean(), isOptional: true },
|
|
40
|
+
serveVariant: { type: ScalarTypeEnum.String_unsecure(), isOptional: true }
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
var ExperimentModel = defineSchemaModel({
|
|
44
|
+
name: "Experiment",
|
|
45
|
+
description: "Represents an experiment",
|
|
46
|
+
fields: {
|
|
47
|
+
id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
48
|
+
key: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
49
|
+
name: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
50
|
+
description: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
51
|
+
hypothesis: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
52
|
+
flagId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
53
|
+
status: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
54
|
+
variants: { type: ScalarTypeEnum.JSON(), isOptional: false },
|
|
55
|
+
metrics: { type: ScalarTypeEnum.JSON(), isOptional: true },
|
|
56
|
+
audiencePercentage: {
|
|
57
|
+
type: ScalarTypeEnum.Int_unsecure(),
|
|
58
|
+
isOptional: false
|
|
59
|
+
},
|
|
60
|
+
startedAt: { type: ScalarTypeEnum.DateTime(), isOptional: true },
|
|
61
|
+
endedAt: { type: ScalarTypeEnum.DateTime(), isOptional: true },
|
|
62
|
+
winningVariant: {
|
|
63
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
64
|
+
isOptional: true
|
|
65
|
+
},
|
|
66
|
+
results: { type: ScalarTypeEnum.JSON(), isOptional: true },
|
|
67
|
+
createdAt: { type: ScalarTypeEnum.DateTime(), isOptional: false }
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
var EvaluationResultModel = defineSchemaModel({
|
|
71
|
+
name: "EvaluationResult",
|
|
72
|
+
description: "Result of flag evaluation",
|
|
73
|
+
fields: {
|
|
74
|
+
enabled: { type: ScalarTypeEnum.Boolean(), isOptional: false },
|
|
75
|
+
variant: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
76
|
+
reason: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
77
|
+
ruleId: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
78
|
+
experimentId: { type: ScalarTypeEnum.String_unsecure(), isOptional: true }
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
var CreateFlagInput = defineSchemaModel({
|
|
82
|
+
name: "CreateFlagInput",
|
|
83
|
+
description: "Input for creating a feature flag",
|
|
84
|
+
fields: {
|
|
85
|
+
key: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
86
|
+
name: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
87
|
+
description: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
88
|
+
defaultValue: { type: ScalarTypeEnum.Boolean(), isOptional: true },
|
|
89
|
+
variants: { type: ScalarTypeEnum.JSON(), isOptional: true },
|
|
90
|
+
orgId: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
91
|
+
tags: { type: ScalarTypeEnum.JSON(), isOptional: true }
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
var UpdateFlagInput = defineSchemaModel({
|
|
95
|
+
name: "UpdateFlagInput",
|
|
96
|
+
description: "Input for updating a feature flag",
|
|
97
|
+
fields: {
|
|
98
|
+
flagId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
99
|
+
name: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
100
|
+
description: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
101
|
+
defaultValue: { type: ScalarTypeEnum.Boolean(), isOptional: true },
|
|
102
|
+
variants: { type: ScalarTypeEnum.JSON(), isOptional: true },
|
|
103
|
+
tags: { type: ScalarTypeEnum.JSON(), isOptional: true }
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
var DeleteFlagInput = defineSchemaModel({
|
|
107
|
+
name: "DeleteFlagInput",
|
|
108
|
+
description: "Input for deleting a feature flag",
|
|
109
|
+
fields: {
|
|
110
|
+
flagId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false }
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
var ToggleFlagInput = defineSchemaModel({
|
|
114
|
+
name: "ToggleFlagInput",
|
|
115
|
+
description: "Input for toggling a feature flag",
|
|
116
|
+
fields: {
|
|
117
|
+
flagId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
118
|
+
status: { type: ScalarTypeEnum.String_unsecure(), isOptional: false }
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
var GetFlagInput = defineSchemaModel({
|
|
122
|
+
name: "GetFlagInput",
|
|
123
|
+
description: "Input for getting a feature flag",
|
|
124
|
+
fields: {
|
|
125
|
+
key: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
126
|
+
orgId: { type: ScalarTypeEnum.String_unsecure(), isOptional: true }
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
var ListFlagsInput = defineSchemaModel({
|
|
130
|
+
name: "ListFlagsInput",
|
|
131
|
+
description: "Input for listing feature flags",
|
|
132
|
+
fields: {
|
|
133
|
+
orgId: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
134
|
+
status: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
135
|
+
tags: { type: ScalarTypeEnum.JSON(), isOptional: true },
|
|
136
|
+
limit: { type: ScalarTypeEnum.Int_unsecure(), isOptional: true },
|
|
137
|
+
offset: { type: ScalarTypeEnum.Int_unsecure(), isOptional: true }
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
var ListFlagsOutput = defineSchemaModel({
|
|
141
|
+
name: "ListFlagsOutput",
|
|
142
|
+
description: "Output for listing feature flags",
|
|
143
|
+
fields: {
|
|
144
|
+
flags: { type: FeatureFlagModel, isArray: true, isOptional: false },
|
|
145
|
+
total: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false }
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
var EvaluateFlagInput = defineSchemaModel({
|
|
149
|
+
name: "EvaluateFlagInput",
|
|
150
|
+
description: "Input for evaluating a feature flag",
|
|
151
|
+
fields: {
|
|
152
|
+
key: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
153
|
+
context: { type: ScalarTypeEnum.JSON(), isOptional: false }
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
var CreateRuleInput = defineSchemaModel({
|
|
157
|
+
name: "CreateRuleInput",
|
|
158
|
+
description: "Input for creating a targeting rule",
|
|
159
|
+
fields: {
|
|
160
|
+
flagId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
161
|
+
name: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
162
|
+
priority: { type: ScalarTypeEnum.Int_unsecure(), isOptional: true },
|
|
163
|
+
attribute: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
164
|
+
operator: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
165
|
+
value: { type: ScalarTypeEnum.JSON(), isOptional: false },
|
|
166
|
+
rolloutPercentage: {
|
|
167
|
+
type: ScalarTypeEnum.Int_unsecure(),
|
|
168
|
+
isOptional: true
|
|
169
|
+
},
|
|
170
|
+
serveValue: { type: ScalarTypeEnum.Boolean(), isOptional: true },
|
|
171
|
+
serveVariant: { type: ScalarTypeEnum.String_unsecure(), isOptional: true }
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
var DeleteRuleInput = defineSchemaModel({
|
|
175
|
+
name: "DeleteRuleInput",
|
|
176
|
+
description: "Input for deleting a targeting rule",
|
|
177
|
+
fields: {
|
|
178
|
+
ruleId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false }
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
var CreateExperimentInput = defineSchemaModel({
|
|
182
|
+
name: "CreateExperimentInput",
|
|
183
|
+
description: "Input for creating an experiment",
|
|
184
|
+
fields: {
|
|
185
|
+
key: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
186
|
+
name: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
187
|
+
description: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
188
|
+
hypothesis: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
189
|
+
flagId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
190
|
+
variants: { type: ScalarTypeEnum.JSON(), isOptional: false },
|
|
191
|
+
metrics: { type: ScalarTypeEnum.JSON(), isOptional: true },
|
|
192
|
+
audiencePercentage: {
|
|
193
|
+
type: ScalarTypeEnum.Int_unsecure(),
|
|
194
|
+
isOptional: true
|
|
195
|
+
},
|
|
196
|
+
scheduledStartAt: { type: ScalarTypeEnum.DateTime(), isOptional: true },
|
|
197
|
+
scheduledEndAt: { type: ScalarTypeEnum.DateTime(), isOptional: true },
|
|
198
|
+
orgId: { type: ScalarTypeEnum.String_unsecure(), isOptional: true }
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
var StartExperimentInput = defineSchemaModel({
|
|
202
|
+
name: "StartExperimentInput",
|
|
203
|
+
description: "Input for starting an experiment",
|
|
204
|
+
fields: {
|
|
205
|
+
experimentId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false }
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
var StopExperimentInput = defineSchemaModel({
|
|
209
|
+
name: "StopExperimentInput",
|
|
210
|
+
description: "Input for stopping an experiment",
|
|
211
|
+
fields: {
|
|
212
|
+
experimentId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
213
|
+
reason: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
214
|
+
winningVariant: {
|
|
215
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
216
|
+
isOptional: true
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
var GetExperimentInput = defineSchemaModel({
|
|
221
|
+
name: "GetExperimentInput",
|
|
222
|
+
description: "Input for getting an experiment",
|
|
223
|
+
fields: {
|
|
224
|
+
experimentId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false }
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
var SuccessOutput = defineSchemaModel({
|
|
228
|
+
name: "SuccessOutput",
|
|
229
|
+
description: "Generic success output",
|
|
230
|
+
fields: {
|
|
231
|
+
success: { type: ScalarTypeEnum.Boolean(), isOptional: false }
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
var CreateFlagContract = defineCommand({
|
|
235
|
+
meta: {
|
|
236
|
+
key: "flag.create",
|
|
237
|
+
version: "1.0.0",
|
|
238
|
+
stability: "stable",
|
|
239
|
+
owners: [...OWNERS],
|
|
240
|
+
tags: ["feature-flags", "create"],
|
|
241
|
+
description: "Create a new feature flag.",
|
|
242
|
+
goal: "Define a new feature flag for toggling features.",
|
|
243
|
+
context: "Called when setting up a new feature flag."
|
|
244
|
+
},
|
|
245
|
+
io: {
|
|
246
|
+
input: CreateFlagInput,
|
|
247
|
+
output: FeatureFlagModel,
|
|
248
|
+
errors: {
|
|
249
|
+
KEY_ALREADY_EXISTS: {
|
|
250
|
+
description: "Flag key already exists",
|
|
251
|
+
http: 409,
|
|
252
|
+
gqlCode: "FLAG_KEY_EXISTS",
|
|
253
|
+
when: "A flag with this key already exists"
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
policy: {
|
|
258
|
+
auth: "admin"
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
var UpdateFlagContract = defineCommand({
|
|
262
|
+
meta: {
|
|
263
|
+
key: "flag.update",
|
|
264
|
+
version: "1.0.0",
|
|
265
|
+
stability: "stable",
|
|
266
|
+
owners: [...OWNERS],
|
|
267
|
+
tags: ["feature-flags", "update"],
|
|
268
|
+
description: "Update an existing feature flag.",
|
|
269
|
+
goal: "Modify flag configuration.",
|
|
270
|
+
context: "Called when adjusting flag settings."
|
|
271
|
+
},
|
|
272
|
+
io: {
|
|
273
|
+
input: UpdateFlagInput,
|
|
274
|
+
output: FeatureFlagModel,
|
|
275
|
+
errors: {
|
|
276
|
+
FLAG_NOT_FOUND: {
|
|
277
|
+
description: "Flag does not exist",
|
|
278
|
+
http: 404,
|
|
279
|
+
gqlCode: "FLAG_NOT_FOUND",
|
|
280
|
+
when: "Flag ID is invalid"
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
policy: {
|
|
285
|
+
auth: "admin"
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
var DeleteFlagContract = defineCommand({
|
|
289
|
+
meta: {
|
|
290
|
+
key: "flag.delete",
|
|
291
|
+
version: "1.0.0",
|
|
292
|
+
stability: "stable",
|
|
293
|
+
owners: [...OWNERS],
|
|
294
|
+
tags: ["feature-flags", "delete"],
|
|
295
|
+
description: "Delete a feature flag.",
|
|
296
|
+
goal: "Remove a feature flag and all its rules.",
|
|
297
|
+
context: "Called when a flag is no longer needed."
|
|
298
|
+
},
|
|
299
|
+
io: {
|
|
300
|
+
input: DeleteFlagInput,
|
|
301
|
+
output: SuccessOutput,
|
|
302
|
+
errors: {
|
|
303
|
+
FLAG_NOT_FOUND: {
|
|
304
|
+
description: "Flag does not exist",
|
|
305
|
+
http: 404,
|
|
306
|
+
gqlCode: "FLAG_NOT_FOUND",
|
|
307
|
+
when: "Flag ID is invalid"
|
|
308
|
+
},
|
|
309
|
+
FLAG_HAS_ACTIVE_EXPERIMENT: {
|
|
310
|
+
description: "Flag has an active experiment",
|
|
311
|
+
http: 409,
|
|
312
|
+
gqlCode: "FLAG_HAS_ACTIVE_EXPERIMENT",
|
|
313
|
+
when: "Cannot delete flag with running experiment"
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
policy: {
|
|
318
|
+
auth: "admin"
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
var ToggleFlagContract = defineCommand({
|
|
322
|
+
meta: {
|
|
323
|
+
key: "flag.toggle",
|
|
324
|
+
version: "1.0.0",
|
|
325
|
+
stability: "stable",
|
|
326
|
+
owners: [...OWNERS],
|
|
327
|
+
tags: ["feature-flags", "toggle"],
|
|
328
|
+
description: "Toggle a feature flag status.",
|
|
329
|
+
goal: "Quickly enable or disable a feature.",
|
|
330
|
+
context: "Called when turning a feature on or off."
|
|
331
|
+
},
|
|
332
|
+
io: {
|
|
333
|
+
input: ToggleFlagInput,
|
|
334
|
+
output: FeatureFlagModel,
|
|
335
|
+
errors: {
|
|
336
|
+
FLAG_NOT_FOUND: {
|
|
337
|
+
description: "Flag does not exist",
|
|
338
|
+
http: 404,
|
|
339
|
+
gqlCode: "FLAG_NOT_FOUND",
|
|
340
|
+
when: "Flag ID is invalid"
|
|
341
|
+
},
|
|
342
|
+
INVALID_STATUS: {
|
|
343
|
+
description: "Invalid status value",
|
|
344
|
+
http: 400,
|
|
345
|
+
gqlCode: "INVALID_STATUS",
|
|
346
|
+
when: "Status must be OFF, ON, or GRADUAL"
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
policy: {
|
|
351
|
+
auth: "admin"
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
var GetFlagContract = defineQuery({
|
|
355
|
+
meta: {
|
|
356
|
+
key: "flag.get",
|
|
357
|
+
version: "1.0.0",
|
|
358
|
+
stability: "stable",
|
|
359
|
+
owners: [...OWNERS],
|
|
360
|
+
tags: ["feature-flags", "get"],
|
|
361
|
+
description: "Get a feature flag by key.",
|
|
362
|
+
goal: "Retrieve flag configuration.",
|
|
363
|
+
context: "Called to inspect flag details."
|
|
364
|
+
},
|
|
365
|
+
io: {
|
|
366
|
+
input: GetFlagInput,
|
|
367
|
+
output: FeatureFlagModel,
|
|
368
|
+
errors: {
|
|
369
|
+
FLAG_NOT_FOUND: {
|
|
370
|
+
description: "Flag does not exist",
|
|
371
|
+
http: 404,
|
|
372
|
+
gqlCode: "FLAG_NOT_FOUND",
|
|
373
|
+
when: "Flag key is invalid"
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
},
|
|
377
|
+
policy: {
|
|
378
|
+
auth: "user"
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
var ListFlagsContract = defineQuery({
|
|
382
|
+
meta: {
|
|
383
|
+
key: "flag.list",
|
|
384
|
+
version: "1.0.0",
|
|
385
|
+
stability: "stable",
|
|
386
|
+
owners: [...OWNERS],
|
|
387
|
+
tags: ["feature-flags", "list"],
|
|
388
|
+
description: "List all feature flags.",
|
|
389
|
+
goal: "View all configured flags.",
|
|
390
|
+
context: "Admin dashboard."
|
|
391
|
+
},
|
|
392
|
+
io: {
|
|
393
|
+
input: ListFlagsInput,
|
|
394
|
+
output: ListFlagsOutput
|
|
395
|
+
},
|
|
396
|
+
policy: {
|
|
397
|
+
auth: "admin"
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
var EvaluateFlagContract = defineQuery({
|
|
401
|
+
meta: {
|
|
402
|
+
key: "flag.evaluate",
|
|
403
|
+
version: "1.0.0",
|
|
404
|
+
stability: "stable",
|
|
405
|
+
owners: [...OWNERS],
|
|
406
|
+
tags: ["feature-flags", "evaluate"],
|
|
407
|
+
description: "Evaluate a feature flag for a given context.",
|
|
408
|
+
goal: "Determine if a feature should be enabled.",
|
|
409
|
+
context: "Called at runtime to check feature availability."
|
|
410
|
+
},
|
|
411
|
+
io: {
|
|
412
|
+
input: EvaluateFlagInput,
|
|
413
|
+
output: EvaluationResultModel,
|
|
414
|
+
errors: {
|
|
415
|
+
FLAG_NOT_FOUND: {
|
|
416
|
+
description: "Flag does not exist",
|
|
417
|
+
http: 404,
|
|
418
|
+
gqlCode: "FLAG_NOT_FOUND",
|
|
419
|
+
when: "Flag key is invalid"
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
},
|
|
423
|
+
policy: {
|
|
424
|
+
auth: "anonymous"
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
var CreateRuleContract = defineCommand({
|
|
428
|
+
meta: {
|
|
429
|
+
key: "flag.rule.create",
|
|
430
|
+
version: "1.0.0",
|
|
431
|
+
stability: "stable",
|
|
432
|
+
owners: [...OWNERS],
|
|
433
|
+
tags: ["feature-flags", "rule", "create"],
|
|
434
|
+
description: "Create a targeting rule for a flag.",
|
|
435
|
+
goal: "Add conditional targeting to a flag.",
|
|
436
|
+
context: "Called when setting up targeting."
|
|
437
|
+
},
|
|
438
|
+
io: {
|
|
439
|
+
input: CreateRuleInput,
|
|
440
|
+
output: TargetingRuleModel,
|
|
441
|
+
errors: {
|
|
442
|
+
FLAG_NOT_FOUND: {
|
|
443
|
+
description: "Flag does not exist",
|
|
444
|
+
http: 404,
|
|
445
|
+
gqlCode: "FLAG_NOT_FOUND",
|
|
446
|
+
when: "Flag ID is invalid"
|
|
447
|
+
},
|
|
448
|
+
INVALID_OPERATOR: {
|
|
449
|
+
description: "Invalid operator",
|
|
450
|
+
http: 400,
|
|
451
|
+
gqlCode: "INVALID_OPERATOR",
|
|
452
|
+
when: "Operator is not supported"
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
},
|
|
456
|
+
policy: {
|
|
457
|
+
auth: "admin"
|
|
458
|
+
}
|
|
459
|
+
});
|
|
460
|
+
var DeleteRuleContract = defineCommand({
|
|
461
|
+
meta: {
|
|
462
|
+
key: "flag.rule.delete",
|
|
463
|
+
version: "1.0.0",
|
|
464
|
+
stability: "stable",
|
|
465
|
+
owners: [...OWNERS],
|
|
466
|
+
tags: ["feature-flags", "rule", "delete"],
|
|
467
|
+
description: "Delete a targeting rule.",
|
|
468
|
+
goal: "Remove a targeting rule from a flag.",
|
|
469
|
+
context: "Called when removing targeting conditions."
|
|
470
|
+
},
|
|
471
|
+
io: {
|
|
472
|
+
input: DeleteRuleInput,
|
|
473
|
+
output: SuccessOutput,
|
|
474
|
+
errors: {
|
|
475
|
+
RULE_NOT_FOUND: {
|
|
476
|
+
description: "Rule does not exist",
|
|
477
|
+
http: 404,
|
|
478
|
+
gqlCode: "RULE_NOT_FOUND",
|
|
479
|
+
when: "Rule ID is invalid"
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
},
|
|
483
|
+
policy: {
|
|
484
|
+
auth: "admin"
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
var CreateExperimentContract = defineCommand({
|
|
488
|
+
meta: {
|
|
489
|
+
key: "experiment.create",
|
|
490
|
+
version: "1.0.0",
|
|
491
|
+
stability: "stable",
|
|
492
|
+
owners: [...OWNERS],
|
|
493
|
+
tags: ["feature-flags", "experiment", "create"],
|
|
494
|
+
description: "Create an A/B test experiment.",
|
|
495
|
+
goal: "Set up an experiment with variants.",
|
|
496
|
+
context: "Called when setting up A/B testing."
|
|
497
|
+
},
|
|
498
|
+
io: {
|
|
499
|
+
input: CreateExperimentInput,
|
|
500
|
+
output: ExperimentModel,
|
|
501
|
+
errors: {
|
|
502
|
+
FLAG_NOT_FOUND: {
|
|
503
|
+
description: "Flag does not exist",
|
|
504
|
+
http: 404,
|
|
505
|
+
gqlCode: "FLAG_NOT_FOUND",
|
|
506
|
+
when: "Flag ID is invalid"
|
|
507
|
+
},
|
|
508
|
+
EXPERIMENT_KEY_EXISTS: {
|
|
509
|
+
description: "Experiment key already exists",
|
|
510
|
+
http: 409,
|
|
511
|
+
gqlCode: "EXPERIMENT_KEY_EXISTS",
|
|
512
|
+
when: "An experiment with this key already exists"
|
|
513
|
+
},
|
|
514
|
+
INVALID_VARIANTS: {
|
|
515
|
+
description: "Invalid variant configuration",
|
|
516
|
+
http: 400,
|
|
517
|
+
gqlCode: "INVALID_VARIANTS",
|
|
518
|
+
when: "Variant percentages must sum to 100"
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
},
|
|
522
|
+
policy: {
|
|
523
|
+
auth: "admin"
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
var StartExperimentContract = defineCommand({
|
|
527
|
+
meta: {
|
|
528
|
+
key: "experiment.start",
|
|
529
|
+
version: "1.0.0",
|
|
530
|
+
stability: "stable",
|
|
531
|
+
owners: [...OWNERS],
|
|
532
|
+
tags: ["feature-flags", "experiment", "start"],
|
|
533
|
+
description: "Start an experiment.",
|
|
534
|
+
goal: "Begin collecting data for an experiment.",
|
|
535
|
+
context: "Called when ready to run an A/B test."
|
|
536
|
+
},
|
|
537
|
+
io: {
|
|
538
|
+
input: StartExperimentInput,
|
|
539
|
+
output: ExperimentModel,
|
|
540
|
+
errors: {
|
|
541
|
+
EXPERIMENT_NOT_FOUND: {
|
|
542
|
+
description: "Experiment does not exist",
|
|
543
|
+
http: 404,
|
|
544
|
+
gqlCode: "EXPERIMENT_NOT_FOUND",
|
|
545
|
+
when: "Experiment ID is invalid"
|
|
546
|
+
},
|
|
547
|
+
EXPERIMENT_ALREADY_RUNNING: {
|
|
548
|
+
description: "Experiment is already running",
|
|
549
|
+
http: 409,
|
|
550
|
+
gqlCode: "EXPERIMENT_ALREADY_RUNNING",
|
|
551
|
+
when: "Cannot start an experiment that is already running"
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
},
|
|
555
|
+
policy: {
|
|
556
|
+
auth: "admin"
|
|
557
|
+
}
|
|
558
|
+
});
|
|
559
|
+
var StopExperimentContract = defineCommand({
|
|
560
|
+
meta: {
|
|
561
|
+
key: "experiment.stop",
|
|
562
|
+
version: "1.0.0",
|
|
563
|
+
stability: "stable",
|
|
564
|
+
owners: [...OWNERS],
|
|
565
|
+
tags: ["feature-flags", "experiment", "stop"],
|
|
566
|
+
description: "Stop an experiment.",
|
|
567
|
+
goal: "End an experiment and optionally declare a winner.",
|
|
568
|
+
context: "Called when concluding an A/B test."
|
|
569
|
+
},
|
|
570
|
+
io: {
|
|
571
|
+
input: StopExperimentInput,
|
|
572
|
+
output: ExperimentModel,
|
|
573
|
+
errors: {
|
|
574
|
+
EXPERIMENT_NOT_FOUND: {
|
|
575
|
+
description: "Experiment does not exist",
|
|
576
|
+
http: 404,
|
|
577
|
+
gqlCode: "EXPERIMENT_NOT_FOUND",
|
|
578
|
+
when: "Experiment ID is invalid"
|
|
579
|
+
},
|
|
580
|
+
EXPERIMENT_NOT_RUNNING: {
|
|
581
|
+
description: "Experiment is not running",
|
|
582
|
+
http: 409,
|
|
583
|
+
gqlCode: "EXPERIMENT_NOT_RUNNING",
|
|
584
|
+
when: "Cannot stop an experiment that is not running"
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
},
|
|
588
|
+
policy: {
|
|
589
|
+
auth: "admin"
|
|
590
|
+
}
|
|
591
|
+
});
|
|
592
|
+
var GetExperimentContract = defineQuery({
|
|
593
|
+
meta: {
|
|
594
|
+
key: "experiment.get",
|
|
595
|
+
version: "1.0.0",
|
|
596
|
+
stability: "stable",
|
|
597
|
+
owners: [...OWNERS],
|
|
598
|
+
tags: ["feature-flags", "experiment", "get"],
|
|
599
|
+
description: "Get experiment details.",
|
|
600
|
+
goal: "View experiment configuration and results.",
|
|
601
|
+
context: "Called to inspect experiment status."
|
|
602
|
+
},
|
|
603
|
+
io: {
|
|
604
|
+
input: GetExperimentInput,
|
|
605
|
+
output: ExperimentModel,
|
|
606
|
+
errors: {
|
|
607
|
+
EXPERIMENT_NOT_FOUND: {
|
|
608
|
+
description: "Experiment does not exist",
|
|
609
|
+
http: 404,
|
|
610
|
+
gqlCode: "EXPERIMENT_NOT_FOUND",
|
|
611
|
+
when: "Experiment ID is invalid"
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
},
|
|
615
|
+
policy: {
|
|
616
|
+
auth: "user"
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
export {
|
|
620
|
+
UpdateFlagContract,
|
|
621
|
+
ToggleFlagContract,
|
|
622
|
+
TargetingRuleModel,
|
|
623
|
+
StopExperimentContract,
|
|
624
|
+
StartExperimentContract,
|
|
625
|
+
ListFlagsContract,
|
|
626
|
+
GetFlagContract,
|
|
627
|
+
GetExperimentContract,
|
|
628
|
+
FeatureFlagModel,
|
|
629
|
+
ExperimentModel,
|
|
630
|
+
EvaluationResultModel,
|
|
631
|
+
EvaluateFlagContract,
|
|
632
|
+
DeleteRuleContract,
|
|
633
|
+
DeleteFlagContract,
|
|
634
|
+
CreateRuleContract,
|
|
635
|
+
CreateFlagContract,
|
|
636
|
+
CreateExperimentContract
|
|
637
|
+
};
|