@runbound/config-browser 0.0.0-stage → 0.1.0-alpha.1
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/CHANGELOG.md +15 -0
- package/LICENSE +161 -0
- package/README.md +136 -2
- package/THIRD_PARTY_NOTICES.md +30 -0
- package/dist/config-context-client.d.ts +74 -0
- package/dist/config-context-client.js +1 -0
- package/dist/config-context.d.ts +55 -0
- package/dist/config-context.js +1 -0
- package/dist/config-delivery-store.d.ts +73 -0
- package/dist/config-delivery-store.js +1 -0
- package/dist/config-experiment-committed-render.d.ts +57 -0
- package/dist/config-experiment-committed-render.js +1 -0
- package/dist/config-experiment-web-durability.d.ts +85 -0
- package/dist/config-experiment-web-durability.js +1 -0
- package/dist/config-experiment-web-proof.d.ts +22 -0
- package/dist/config-experiment-web-proof.js +1 -0
- package/dist/config-experimentation.d.ts +308 -0
- package/dist/config-experimentation.js +1 -0
- package/dist/config-public-decision.d.ts +67 -0
- package/dist/config-public-decision.js +1 -0
- package/dist/config-refresh.d.ts +69 -0
- package/dist/config-refresh.js +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +1 -0
- package/dist/internal/config-contract/base.d.ts +180 -0
- package/dist/internal/config-contract/core.d.ts +82 -0
- package/dist/internal/config-contract/decisioning.d.ts +430 -0
- package/dist/internal/config-contract/experimentation.d.ts +460 -0
- package/dist/internal/config-contract/schema.d.ts +133 -0
- package/package.json +74 -4
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
import type { ConfigAllocationReservationClass, ConfigRuleAllocation } from "./decisioning.js";
|
|
2
|
+
export declare const configExperimentContractVersion: "runbound.config.experimentation.v1";
|
|
3
|
+
export declare const configExperimentLimits: Readonly<{
|
|
4
|
+
maximumActions: 64;
|
|
5
|
+
maximumArms: 64;
|
|
6
|
+
maximumArtifactBytes: 1048576;
|
|
7
|
+
maximumDiagnostics: 256;
|
|
8
|
+
maximumDimensions: 32;
|
|
9
|
+
maximumFactors: 12;
|
|
10
|
+
maximumFactorialCells: 4096;
|
|
11
|
+
maximumInputPartitions: 10000;
|
|
12
|
+
maximumMetricRevisions: 256;
|
|
13
|
+
maximumProbabilityEntries: 64;
|
|
14
|
+
maximumSwitchbackPeriods: 10000;
|
|
15
|
+
}>;
|
|
16
|
+
export type ConfigExperimentDigest = `sha256:${string}`;
|
|
17
|
+
export type ConfigExperimentLifecycle = "approved" | "archived" | "draft" | "finalized" | "finalizing" | "paused" | "running" | "scheduled" | "stopped" | "validated";
|
|
18
|
+
export type ConfigExperimentEvidenceStrength = "advisory" | "confirmatory" | "exploratory";
|
|
19
|
+
/**
|
|
20
|
+
* Every durable experiment artifact is bound to the same immutable ingress
|
|
21
|
+
* authority. Do not reduce this to a tenant/project/config prefix: the app,
|
|
22
|
+
* environment, and assignment are independently reusable identifiers.
|
|
23
|
+
*/
|
|
24
|
+
export type ConfigExperimentArtifactScope = Readonly<{
|
|
25
|
+
appId: string;
|
|
26
|
+
assignmentId: string;
|
|
27
|
+
configId: string;
|
|
28
|
+
createdAt: string;
|
|
29
|
+
environmentId: string;
|
|
30
|
+
projectId: string;
|
|
31
|
+
tenantId: string;
|
|
32
|
+
}>;
|
|
33
|
+
type ArtifactScope = ConfigExperimentArtifactScope;
|
|
34
|
+
export type ConfigExperimentArm = Readonly<{
|
|
35
|
+
armId: string;
|
|
36
|
+
role: "control" | "treatment";
|
|
37
|
+
treatmentDigest: ConfigExperimentDigest;
|
|
38
|
+
variationIds: readonly string[];
|
|
39
|
+
}>;
|
|
40
|
+
export type ConfigExperimentFactor = Readonly<{
|
|
41
|
+
factorId: string;
|
|
42
|
+
levels: readonly Readonly<{
|
|
43
|
+
levelId: string;
|
|
44
|
+
treatmentDigest: ConfigExperimentDigest;
|
|
45
|
+
}>[];
|
|
46
|
+
}>;
|
|
47
|
+
export type ConfigExperimentFactorialCell = Readonly<{
|
|
48
|
+
cellId: string;
|
|
49
|
+
levels: Readonly<Record<string, string>>;
|
|
50
|
+
treatmentDigest: ConfigExperimentDigest;
|
|
51
|
+
}>;
|
|
52
|
+
export type ConfigExperimentDesign = Readonly<{
|
|
53
|
+
arms: readonly ConfigExperimentArm[];
|
|
54
|
+
designKind: "aa" | "ab" | "abn" | "treatmentBundle";
|
|
55
|
+
}> | Readonly<{
|
|
56
|
+
cells: readonly ConfigExperimentFactorialCell[];
|
|
57
|
+
designKind: "factorialFractional" | "factorialFull";
|
|
58
|
+
factors: readonly ConfigExperimentFactor[];
|
|
59
|
+
interactions: readonly (readonly string[])[];
|
|
60
|
+
}> | Readonly<{
|
|
61
|
+
arms: readonly ConfigExperimentArm[];
|
|
62
|
+
clusterContextKind: string;
|
|
63
|
+
designKind: "cluster";
|
|
64
|
+
}> | Readonly<{
|
|
65
|
+
arms: readonly ConfigExperimentArm[];
|
|
66
|
+
designKind: "switchback";
|
|
67
|
+
periodSeconds: number;
|
|
68
|
+
periods: readonly Readonly<{
|
|
69
|
+
armId: string;
|
|
70
|
+
endsAt: string;
|
|
71
|
+
periodId: string;
|
|
72
|
+
startsAt: string;
|
|
73
|
+
}>[];
|
|
74
|
+
washoutSeconds: number;
|
|
75
|
+
}>;
|
|
76
|
+
export type ConfigExperimentContrast = Readonly<{
|
|
77
|
+
comparisonIds: readonly string[];
|
|
78
|
+
contrastId: string;
|
|
79
|
+
contrastKind: "armDifference" | "factorInteraction" | "factorMainEffect";
|
|
80
|
+
hypothesis: "equivalence" | "nonInferiority" | "superiority";
|
|
81
|
+
metricRevisionIds: readonly string[];
|
|
82
|
+
referenceIds: readonly string[];
|
|
83
|
+
}>;
|
|
84
|
+
export type ConfigExperimentPlanning = Readonly<{
|
|
85
|
+
alpha: number;
|
|
86
|
+
minimumDetectableEffect: number;
|
|
87
|
+
plannedDurationSeconds: number;
|
|
88
|
+
planningMode: "power";
|
|
89
|
+
targetPower: number;
|
|
90
|
+
}> | Readonly<{
|
|
91
|
+
alpha: number;
|
|
92
|
+
plannedDurationSeconds: number;
|
|
93
|
+
planningMode: "precision";
|
|
94
|
+
targetPrecision: number;
|
|
95
|
+
}>;
|
|
96
|
+
export type ConfigExperimentDecisionThresholds = Readonly<{
|
|
97
|
+
maximumCrossoverRate: number;
|
|
98
|
+
maximumMissingRate: number;
|
|
99
|
+
minimumDurationSeconds: number;
|
|
100
|
+
minimumSampleSize: number;
|
|
101
|
+
minimumSrmPValue: number;
|
|
102
|
+
practicalSignificance: number;
|
|
103
|
+
}>;
|
|
104
|
+
export type ConfigExperimentPopulation = Readonly<{
|
|
105
|
+
eligibility: "allEligible" | "segmentIntersection" | "segmentUnion";
|
|
106
|
+
exclusionSegmentRevisionIds: readonly string[];
|
|
107
|
+
inclusionSegmentRevisionIds: readonly string[];
|
|
108
|
+
noncomplianceHandling: "excludeFromModifiedIntentionToTreat" | "retainInPrimary" | "secondaryOnly";
|
|
109
|
+
primaryAnalysisPopulation: "assignmentBasedEligible" | "modifiedIntentionToTreat";
|
|
110
|
+
secondaryAnalysisPopulations: readonly ("asTreated" | "exposureConditioned" | "perProtocol")[];
|
|
111
|
+
}>;
|
|
112
|
+
export type ConfigExperimentMetricAnalysisRule = Readonly<{
|
|
113
|
+
attributionAnchor: "assignment" | "exposure";
|
|
114
|
+
censoringPolicy: "exclude" | "rightCensor" | "zeroFill";
|
|
115
|
+
identityTransitionPolicy: "block" | "freezeAtAssignment" | "resolveAsOfOutcome" | "separateTransitionedPopulation";
|
|
116
|
+
lateDataPolicy: "blockFinalization" | "includeUntilWatermark" | "successorReanalysis";
|
|
117
|
+
maturitySeconds: number;
|
|
118
|
+
metricRevisionId: string;
|
|
119
|
+
missingDataPolicy: "block" | "exclude" | "zeroFill";
|
|
120
|
+
outlierPolicy: "none" | "robust" | "winsorized";
|
|
121
|
+
role: "guardrail" | "invariant" | "primary" | "secondary";
|
|
122
|
+
}>;
|
|
123
|
+
export type ConfigExperimentProtocol = ArtifactScope & Readonly<{
|
|
124
|
+
allowedAutomaticActions: readonly ("pauseForDataQuality" | "pauseForHarm" | "rollbackToControl")[];
|
|
125
|
+
analysisProfileId: string;
|
|
126
|
+
contrasts: readonly ConfigExperimentContrast[];
|
|
127
|
+
decisionThresholds: ConfigExperimentDecisionThresholds;
|
|
128
|
+
decisionQuestion: string;
|
|
129
|
+
formatVersion: "runbound.config.experiment-protocol.v1";
|
|
130
|
+
hypothesis: string;
|
|
131
|
+
intendedAction: string;
|
|
132
|
+
integrityGateIds: readonly string[];
|
|
133
|
+
multiplicity: Readonly<{
|
|
134
|
+
alpha: number;
|
|
135
|
+
familyId: string;
|
|
136
|
+
method: "benjaminiHochberg" | "bonferroni" | "holm" | "none";
|
|
137
|
+
}>;
|
|
138
|
+
owner: string;
|
|
139
|
+
planning: ConfigExperimentPlanning;
|
|
140
|
+
protocolId: string;
|
|
141
|
+
revision: number;
|
|
142
|
+
varianceReduction: "cupac" | "cuped" | "none" | "regressionAdjustment";
|
|
143
|
+
}>;
|
|
144
|
+
export type ConfigExperimentLayer = ArtifactScope & Readonly<{
|
|
145
|
+
allocation: ConfigRuleAllocation;
|
|
146
|
+
interferencePolicy: "mutuallyExclusive" | "orthogonal";
|
|
147
|
+
layerId: string;
|
|
148
|
+
layerRevisionId: string;
|
|
149
|
+
formatVersion: "runbound.config.experiment-layer.v1";
|
|
150
|
+
revision: number;
|
|
151
|
+
scope: "app" | "decisionFamily" | "global";
|
|
152
|
+
}>;
|
|
153
|
+
export type ConfigExperimentHoldout = ArtifactScope & Readonly<{
|
|
154
|
+
allocation: ConfigRuleAllocation;
|
|
155
|
+
contaminationPolicy: "block" | "diagnoseAndExclude";
|
|
156
|
+
controlTreatmentDigest: ConfigExperimentDigest;
|
|
157
|
+
endsAt?: string;
|
|
158
|
+
formatVersion: "runbound.config.experiment-holdout.v1";
|
|
159
|
+
holdoutId: string;
|
|
160
|
+
holdoutRevisionId: string;
|
|
161
|
+
includedDecisionIds: readonly string[];
|
|
162
|
+
metricRevisionIds: readonly string[];
|
|
163
|
+
revision: number;
|
|
164
|
+
scope: "app" | "decision" | "global" | "layer";
|
|
165
|
+
startsAt: string;
|
|
166
|
+
}>;
|
|
167
|
+
export type ConfigExperimentIteration = ArtifactScope & Readonly<{
|
|
168
|
+
allocation: ConfigRuleAllocation;
|
|
169
|
+
analysisUnitContextKind: string;
|
|
170
|
+
compatibleSoftwareReleaseIds: readonly string[];
|
|
171
|
+
design: ConfigExperimentDesign;
|
|
172
|
+
environmentId: string;
|
|
173
|
+
estimand: "intentionToTreat" | "modifiedIntentionToTreat";
|
|
174
|
+
contextContractRevisionId: string;
|
|
175
|
+
exclusionRevisionId: string;
|
|
176
|
+
exposurePolicyRevisionId: string;
|
|
177
|
+
formatVersion: "runbound.config.experiment-iteration.v1";
|
|
178
|
+
holdoutRevisionId?: string;
|
|
179
|
+
iterationId: string;
|
|
180
|
+
layerRevisionId: string;
|
|
181
|
+
metricAnalysisRules: readonly ConfigExperimentMetricAnalysisRule[];
|
|
182
|
+
metricRevisionIds: readonly string[];
|
|
183
|
+
population: ConfigExperimentPopulation;
|
|
184
|
+
protocolDigest: ConfigExperimentDigest;
|
|
185
|
+
protocolId: string;
|
|
186
|
+
randomizationContextKind: string;
|
|
187
|
+
revision: number;
|
|
188
|
+
stoppingPolicy: "anytimeValid" | "bayesian" | "fixedHorizon";
|
|
189
|
+
}>;
|
|
190
|
+
export type ConfigExperimentRun = ArtifactScope & Readonly<{
|
|
191
|
+
assignmentEpoch: number;
|
|
192
|
+
endsAt?: string;
|
|
193
|
+
formatVersion: "runbound.config.experiment-run.v1";
|
|
194
|
+
iterationDigest: ConfigExperimentDigest;
|
|
195
|
+
iterationId: string;
|
|
196
|
+
runId: string;
|
|
197
|
+
startsAt: string;
|
|
198
|
+
state: ConfigExperimentLifecycle;
|
|
199
|
+
}>;
|
|
200
|
+
export type ConfigExperimentMetricKind = "binary" | "composite" | "continuous" | "count" | "funnel" | "quantile" | "rate" | "ratio" | "repeatedWindow" | "retention" | "timeToEvent";
|
|
201
|
+
export type ConfigExperimentMetricDefinition = ArtifactScope & Readonly<{
|
|
202
|
+
aggregationUnitContextKind: string;
|
|
203
|
+
attributionAnchor: "assignment" | "exposure";
|
|
204
|
+
censoringPolicy: "exclude" | "rightCensor" | "zeroFill";
|
|
205
|
+
dimensions: readonly string[];
|
|
206
|
+
direction: "decrease" | "increase" | "invariant";
|
|
207
|
+
formatVersion: "runbound.config.experiment-metric.v1";
|
|
208
|
+
identityColumn: string;
|
|
209
|
+
kind: ConfigExperimentMetricKind;
|
|
210
|
+
maturitySeconds: number;
|
|
211
|
+
metricId: string;
|
|
212
|
+
metricRevisionId: string;
|
|
213
|
+
minimumCohortSize: number;
|
|
214
|
+
minimumMeaningfulChange: number;
|
|
215
|
+
observationWindowSeconds: number;
|
|
216
|
+
outlierPolicy: "none" | "robust" | "winsorized";
|
|
217
|
+
residency: "eu" | "uk" | "us";
|
|
218
|
+
retentionDays: number;
|
|
219
|
+
revision: number;
|
|
220
|
+
sensitivity: "internal" | "public" | "restricted";
|
|
221
|
+
sourceRevision: string;
|
|
222
|
+
sourceType: "hostedEvent" | "warehouse";
|
|
223
|
+
timestampColumn: string;
|
|
224
|
+
valueColumns: readonly string[];
|
|
225
|
+
}>;
|
|
226
|
+
type TransportEvent = ArtifactScope & Readonly<{
|
|
227
|
+
appId: string;
|
|
228
|
+
environmentId: string;
|
|
229
|
+
eventId: string;
|
|
230
|
+
holdoutRevisionId: string | null;
|
|
231
|
+
layerRevisionId: string;
|
|
232
|
+
occurredAt: string;
|
|
233
|
+
producerEpoch: string;
|
|
234
|
+
producerId: string;
|
|
235
|
+
producerSequence: string;
|
|
236
|
+
producerSessionId: string;
|
|
237
|
+
receivedAt: string;
|
|
238
|
+
runId: string;
|
|
239
|
+
}>;
|
|
240
|
+
type ExperimentEventIdentity = Readonly<{
|
|
241
|
+
assignmentEpoch: number;
|
|
242
|
+
assignmentUnitToken: string;
|
|
243
|
+
iterationId: string;
|
|
244
|
+
qaOverride?: Readonly<{
|
|
245
|
+
exclusionPolicy: "excludeFromConfirmatoryAndWinnerSelection";
|
|
246
|
+
overrideId: string;
|
|
247
|
+
}>;
|
|
248
|
+
semanticBoundaryId: string;
|
|
249
|
+
switchbackPeriodId?: string;
|
|
250
|
+
}>;
|
|
251
|
+
export type ConfigExperimentAssignmentEvent = TransportEvent & ExperimentEventIdentity & Readonly<{
|
|
252
|
+
activationSetId: string;
|
|
253
|
+
allocationNamespace: string;
|
|
254
|
+
allocationRevision: number;
|
|
255
|
+
armId: string;
|
|
256
|
+
assignmentReason: "adaptive" | "deterministic" | "fallback" | "imported";
|
|
257
|
+
assignmentReceiptDigest: ConfigExperimentDigest;
|
|
258
|
+
decisionArtifactDigest: ConfigExperimentDigest;
|
|
259
|
+
formatVersion: "runbound.config.experiment-assignment.v1";
|
|
260
|
+
iterationDigest: ConfigExperimentDigest;
|
|
261
|
+
probabilityVector?: readonly Readonly<{
|
|
262
|
+
actionId: string;
|
|
263
|
+
probability: number;
|
|
264
|
+
}>[];
|
|
265
|
+
reservationClass: ConfigAllocationReservationClass;
|
|
266
|
+
selectedProbability: number;
|
|
267
|
+
softwareReleaseId: string;
|
|
268
|
+
stateArtifactDigest?: ConfigExperimentDigest;
|
|
269
|
+
stateRevisionId?: string;
|
|
270
|
+
}>;
|
|
271
|
+
export type ConfigExperimentExposureEvent = TransportEvent & ExperimentEventIdentity & Readonly<{
|
|
272
|
+
activationSetId: string;
|
|
273
|
+
armId: string;
|
|
274
|
+
assignmentReason: "adaptive" | "deterministic" | "fallback" | "imported";
|
|
275
|
+
decisionArtifactDigest: ConfigExperimentDigest;
|
|
276
|
+
evidenceStrength: ConfigExperimentEvidenceStrength;
|
|
277
|
+
exposurePolicyRevisionId: string;
|
|
278
|
+
fallbackPosture: "none" | "offline" | "safeFallback";
|
|
279
|
+
formatVersion: "runbound.config.experiment-exposure.v1";
|
|
280
|
+
iterationDigest: ConfigExperimentDigest;
|
|
281
|
+
occurrenceKind: "committedRender" | "explicitApplication" | "sdkEvaluation" | "serverBoundary";
|
|
282
|
+
occurrenceWindowId?: string;
|
|
283
|
+
probabilityVector?: readonly Readonly<{
|
|
284
|
+
actionId: string;
|
|
285
|
+
probability: number;
|
|
286
|
+
}>[];
|
|
287
|
+
selectedProbability: number;
|
|
288
|
+
softwareReleaseId: string;
|
|
289
|
+
stateArtifactDigest?: ConfigExperimentDigest;
|
|
290
|
+
stateRevisionId?: string;
|
|
291
|
+
}>;
|
|
292
|
+
export type ConfigExperimentObservationEvent = TransportEvent & Readonly<{
|
|
293
|
+
analysisUnitToken: string;
|
|
294
|
+
dimensionValues: Readonly<Record<string, boolean | number | string>>;
|
|
295
|
+
formatVersion: "runbound.config.experiment-observation.v1";
|
|
296
|
+
metricRevisionId: string;
|
|
297
|
+
observationId: string;
|
|
298
|
+
value: boolean | number;
|
|
299
|
+
}>;
|
|
300
|
+
export type ConfigExperimentIdentitySnapshot = ArtifactScope & Readonly<{
|
|
301
|
+
asOf: string;
|
|
302
|
+
cardinality: "manyToOne" | "oneToOne";
|
|
303
|
+
conflictPolicy: "block" | "firstTouch" | "lastTouch" | "timeAsOf";
|
|
304
|
+
correctionOfSnapshotId?: string;
|
|
305
|
+
deletionStateDigest: ConfigExperimentDigest;
|
|
306
|
+
destinationContextKind: string;
|
|
307
|
+
formatVersion: "runbound.config.experiment-identity-snapshot.v1";
|
|
308
|
+
mappingDigest: ConfigExperimentDigest;
|
|
309
|
+
mappingSourceRevision: string;
|
|
310
|
+
snapshotId: string;
|
|
311
|
+
sourceContextKind: string;
|
|
312
|
+
}>;
|
|
313
|
+
export type ConfigExperimentWarehouseManifest = ArtifactScope & Readonly<{
|
|
314
|
+
compiledQueryDigest: ConfigExperimentDigest;
|
|
315
|
+
connectionRevisionId: string;
|
|
316
|
+
deletionStateDigest: ConfigExperimentDigest;
|
|
317
|
+
engine: "athena" | "bigquery" | "databricksSql" | "redshift" | "snowflake";
|
|
318
|
+
engineJobId: string;
|
|
319
|
+
engineVersion: string;
|
|
320
|
+
formatVersion: "runbound.config.experiment-warehouse-manifest.v1";
|
|
321
|
+
inputWatermarks: readonly Readonly<{
|
|
322
|
+
sourceId: string;
|
|
323
|
+
watermark: string;
|
|
324
|
+
}>[];
|
|
325
|
+
manifestId: string;
|
|
326
|
+
mode: "fullSnapshot" | "incremental";
|
|
327
|
+
outputDigest: ConfigExperimentDigest;
|
|
328
|
+
parametersDigest: ConfigExperimentDigest;
|
|
329
|
+
queryPlanDigest: ConfigExperimentDigest;
|
|
330
|
+
scannedBytes: number;
|
|
331
|
+
}>;
|
|
332
|
+
export type ConfigExperimentSealedInput = ArtifactScope & Readonly<{
|
|
333
|
+
analysisEngineDigest: ConfigExperimentDigest;
|
|
334
|
+
assignmentInputDigest: ConfigExperimentDigest;
|
|
335
|
+
deletionStateDigest: ConfigExperimentDigest;
|
|
336
|
+
exclusionRevisionId: string;
|
|
337
|
+
exposureInputDigest: ConfigExperimentDigest;
|
|
338
|
+
formatVersion: "runbound.config.experiment-sealed-input.v1";
|
|
339
|
+
identitySnapshotDigest: ConfigExperimentDigest;
|
|
340
|
+
iterationDigest: ConfigExperimentDigest;
|
|
341
|
+
metricInputDigests: readonly ConfigExperimentDigest[];
|
|
342
|
+
metricRevisionIds: readonly string[];
|
|
343
|
+
partitionDigests: readonly ConfigExperimentDigest[];
|
|
344
|
+
projectionWatermark: string;
|
|
345
|
+
runId: string;
|
|
346
|
+
sealedInputId: string;
|
|
347
|
+
warehouseManifestDigests: readonly ConfigExperimentDigest[];
|
|
348
|
+
}>;
|
|
349
|
+
export type ConfigExperimentDiagnostic = Readonly<{
|
|
350
|
+
blocking: boolean;
|
|
351
|
+
code: string;
|
|
352
|
+
observed: number;
|
|
353
|
+
threshold: number;
|
|
354
|
+
}>;
|
|
355
|
+
export type ConfigExperimentAnalysisResult = ArtifactScope & Readonly<{
|
|
356
|
+
analysisResultId: string;
|
|
357
|
+
diagnostics: readonly ConfigExperimentDiagnostic[];
|
|
358
|
+
effects: readonly Readonly<{
|
|
359
|
+
absolute: number;
|
|
360
|
+
adjusted: boolean;
|
|
361
|
+
contrastId: string;
|
|
362
|
+
intervalLower: number;
|
|
363
|
+
intervalUpper: number;
|
|
364
|
+
metricRevisionId: string;
|
|
365
|
+
practicalThreshold: number;
|
|
366
|
+
relative: number;
|
|
367
|
+
}>[];
|
|
368
|
+
evidenceStrength: ConfigExperimentEvidenceStrength;
|
|
369
|
+
formatVersion: "runbound.config.experiment-analysis-result.v1";
|
|
370
|
+
methodDigest: ConfigExperimentDigest;
|
|
371
|
+
replayability: "replayable" | "sourceDeleted" | "withdrawn";
|
|
372
|
+
runId: string;
|
|
373
|
+
sealedInputDigest: ConfigExperimentDigest;
|
|
374
|
+
status: "blocked" | "complete" | "superseded" | "withdrawn";
|
|
375
|
+
successorResultId?: string;
|
|
376
|
+
}>;
|
|
377
|
+
export type ConfigExperimentRecommendation = ArtifactScope & Readonly<{
|
|
378
|
+
analysisResultDigest: ConfigExperimentDigest;
|
|
379
|
+
compatibleSoftwareReleaseIds: readonly string[];
|
|
380
|
+
formatVersion: "runbound.config.experiment-recommendation.v1";
|
|
381
|
+
recommendedArmId?: string;
|
|
382
|
+
recommendation: "continue" | "inconclusive" | "promote" | "stopForFutility" | "stopForHarm";
|
|
383
|
+
recommendationId: string;
|
|
384
|
+
targetConfigReleaseId?: string;
|
|
385
|
+
}>;
|
|
386
|
+
export type ConfigExperimentAdaptivePolicy = ArtifactScope & Readonly<{
|
|
387
|
+
actions: readonly Readonly<{
|
|
388
|
+
actionId: string;
|
|
389
|
+
treatmentDigest: ConfigExperimentDigest;
|
|
390
|
+
}>[];
|
|
391
|
+
algorithm: "contextualBandit" | "epsilonGreedy" | "thompsonSampling";
|
|
392
|
+
contextSchemaDigest: ConfigExperimentDigest;
|
|
393
|
+
controlReservation: ConfigRuleAllocation;
|
|
394
|
+
expiresAt: string;
|
|
395
|
+
explorationFloor: number;
|
|
396
|
+
fallbackDistribution: readonly Readonly<{
|
|
397
|
+
actionId: string;
|
|
398
|
+
probability: number;
|
|
399
|
+
}>[];
|
|
400
|
+
formatVersion: "runbound.config.experiment-adaptive-policy.v1";
|
|
401
|
+
guardrailMetricRevisionIds: readonly string[];
|
|
402
|
+
maximumProbability: number;
|
|
403
|
+
maximumTrafficChange: number;
|
|
404
|
+
minimumProbability: number;
|
|
405
|
+
objectiveMetricRevisionId: string;
|
|
406
|
+
policyId: string;
|
|
407
|
+
policyRevisionId: string;
|
|
408
|
+
revision: number;
|
|
409
|
+
trainingNamespace: string;
|
|
410
|
+
}>;
|
|
411
|
+
export type ConfigExperimentAdaptiveState = ArtifactScope & Readonly<{
|
|
412
|
+
actionProbabilities: readonly Readonly<{
|
|
413
|
+
actionId: string;
|
|
414
|
+
probability: number;
|
|
415
|
+
}>[];
|
|
416
|
+
compilerDigest: ConfigExperimentDigest;
|
|
417
|
+
expiresAt: string;
|
|
418
|
+
featureSchemaRevisionId: string;
|
|
419
|
+
formatVersion: "runbound.config.experiment-adaptive-state.v1";
|
|
420
|
+
modelDigest: ConfigExperimentDigest;
|
|
421
|
+
policyRevisionId: string;
|
|
422
|
+
predecessorStateRevisionId?: string;
|
|
423
|
+
signature: string;
|
|
424
|
+
signatureAlgorithm: "ECDSA_SHA_256" | "Ed25519";
|
|
425
|
+
stateArtifactDigest: ConfigExperimentDigest;
|
|
426
|
+
stateRevisionId: string;
|
|
427
|
+
trainingInputDigest: ConfigExperimentDigest;
|
|
428
|
+
}>;
|
|
429
|
+
export type ConfigExperimentArtifact = ConfigExperimentAdaptivePolicy | ConfigExperimentAdaptiveState | ConfigExperimentAnalysisResult | ConfigExperimentAssignmentEvent | ConfigExperimentExposureEvent | ConfigExperimentHoldout | ConfigExperimentIdentitySnapshot | ConfigExperimentIteration | ConfigExperimentLayer | ConfigExperimentMetricDefinition | ConfigExperimentObservationEvent | ConfigExperimentProtocol | ConfigExperimentRecommendation | ConfigExperimentRun | ConfigExperimentSealedInput | ConfigExperimentWarehouseManifest;
|
|
430
|
+
export type ConfigExperimentEvidenceEligibility = Readonly<{
|
|
431
|
+
confirmatoryEligible: boolean;
|
|
432
|
+
reason: "eligible" | "qaOverride";
|
|
433
|
+
winnerSelectionEligible: boolean;
|
|
434
|
+
}>;
|
|
435
|
+
export declare function validateConfigExperimentArtifact(value: unknown): asserts value is ConfigExperimentArtifact;
|
|
436
|
+
export declare function configExperimentArtifactDigest(artifact: ConfigExperimentArtifact): ConfigExperimentDigest;
|
|
437
|
+
/**
|
|
438
|
+
* Classifies an assignment or exposure before it can enter a confirmatory
|
|
439
|
+
* projection. QA overrides are always excluded from both analysis and winner
|
|
440
|
+
* selection; the closed policy marker makes that exclusion portable across
|
|
441
|
+
* producers without granting the override any decision authority.
|
|
442
|
+
*/
|
|
443
|
+
export declare function configExperimentEventEvidenceEligibility(event: ConfigExperimentAssignmentEvent | ConfigExperimentExposureEvent): ConfigExperimentEvidenceEligibility;
|
|
444
|
+
export declare const validateConfigExperimentProtocol: (value: unknown) => asserts value is ConfigExperimentProtocol;
|
|
445
|
+
export declare const validateConfigExperimentIteration: (value: unknown) => asserts value is ConfigExperimentIteration;
|
|
446
|
+
export declare const validateConfigExperimentRun: (value: unknown) => asserts value is ConfigExperimentRun;
|
|
447
|
+
export declare const validateConfigExperimentLayer: (value: unknown) => asserts value is ConfigExperimentLayer;
|
|
448
|
+
export declare const validateConfigExperimentHoldout: (value: unknown) => asserts value is ConfigExperimentHoldout;
|
|
449
|
+
export declare const validateConfigExperimentMetricDefinition: (value: unknown) => asserts value is ConfigExperimentMetricDefinition;
|
|
450
|
+
export declare const validateConfigExperimentAssignmentEvent: (value: unknown) => asserts value is ConfigExperimentAssignmentEvent;
|
|
451
|
+
export declare const validateConfigExperimentExposureEvent: (value: unknown) => asserts value is ConfigExperimentExposureEvent;
|
|
452
|
+
export declare const validateConfigExperimentObservationEvent: (value: unknown) => asserts value is ConfigExperimentObservationEvent;
|
|
453
|
+
export declare const validateConfigExperimentIdentitySnapshot: (value: unknown) => asserts value is ConfigExperimentIdentitySnapshot;
|
|
454
|
+
export declare const validateConfigExperimentSealedInput: (value: unknown) => asserts value is ConfigExperimentSealedInput;
|
|
455
|
+
export declare const validateConfigExperimentAnalysisResult: (value: unknown) => asserts value is ConfigExperimentAnalysisResult;
|
|
456
|
+
export declare const validateConfigExperimentRecommendation: (value: unknown) => asserts value is ConfigExperimentRecommendation;
|
|
457
|
+
export declare const validateConfigExperimentWarehouseManifest: (value: unknown) => asserts value is ConfigExperimentWarehouseManifest;
|
|
458
|
+
export declare const validateConfigExperimentAdaptivePolicy: (value: unknown) => asserts value is ConfigExperimentAdaptivePolicy;
|
|
459
|
+
export declare const validateConfigExperimentAdaptiveState: (value: unknown) => asserts value is ConfigExperimentAdaptiveState;
|
|
460
|
+
export {};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { type ConfigJsonSchemaProjection, type JsonValue } from "./base.js";
|
|
2
|
+
export declare const configSchemaFormatVersion: "runbound.config.schema.v1";
|
|
3
|
+
export type ConfigSchemaGovernance = Readonly<{
|
|
4
|
+
compatibility?: "additive" | "breaking" | "stable";
|
|
5
|
+
deprecated?: boolean;
|
|
6
|
+
elementIdProperty?: string;
|
|
7
|
+
exposure?: "private" | "public";
|
|
8
|
+
fallback?: "literal-default" | "none";
|
|
9
|
+
lifecycle?: "live" | "startup";
|
|
10
|
+
localOverride?: boolean;
|
|
11
|
+
ownerIds?: readonly string[];
|
|
12
|
+
replacementFieldId?: string;
|
|
13
|
+
reviewerIds?: readonly string[];
|
|
14
|
+
secretReference?: boolean;
|
|
15
|
+
staleness?: "fail-closed" | "use-last-known-good";
|
|
16
|
+
targeting?: "allowed" | "forbidden";
|
|
17
|
+
valueKind?: "array" | "boolean" | "integer" | "null" | "number" | "object" | "string";
|
|
18
|
+
}>;
|
|
19
|
+
type ConfigSchemaCommon = Readonly<{
|
|
20
|
+
default?: JsonValue;
|
|
21
|
+
description?: string;
|
|
22
|
+
governance?: ConfigSchemaGovernance;
|
|
23
|
+
}>;
|
|
24
|
+
export type ConfigSchemaNode = (ConfigSchemaCommon & Readonly<{
|
|
25
|
+
allowedValues?: readonly boolean[];
|
|
26
|
+
kind: "boolean";
|
|
27
|
+
}>) | (ConfigSchemaCommon & Readonly<{
|
|
28
|
+
kind: "null";
|
|
29
|
+
}>) | (ConfigSchemaCommon & Readonly<{
|
|
30
|
+
allowedValues?: readonly string[];
|
|
31
|
+
format?: "date-time" | "duration" | "email" | "hostname" | "ipv4" | "ipv6" | "uri" | "uuid";
|
|
32
|
+
kind: "string";
|
|
33
|
+
length?: Readonly<{
|
|
34
|
+
max?: number;
|
|
35
|
+
min?: number;
|
|
36
|
+
}>;
|
|
37
|
+
pattern?: string;
|
|
38
|
+
}>) | (ConfigSchemaCommon & Readonly<{
|
|
39
|
+
allowedValues?: readonly number[];
|
|
40
|
+
kind: "number" | "integer";
|
|
41
|
+
range?: Readonly<{
|
|
42
|
+
max?: number;
|
|
43
|
+
min?: number;
|
|
44
|
+
}>;
|
|
45
|
+
}>) | (ConfigSchemaCommon & Readonly<{
|
|
46
|
+
extraFields: Readonly<{
|
|
47
|
+
mode: "forbid";
|
|
48
|
+
}> | Readonly<{
|
|
49
|
+
mode: "map";
|
|
50
|
+
schema: ConfigSchemaNode;
|
|
51
|
+
}>;
|
|
52
|
+
fields: readonly ConfigSchemaField[];
|
|
53
|
+
kind: "object";
|
|
54
|
+
}>) | (ConfigSchemaCommon & Readonly<{
|
|
55
|
+
items: ConfigSchemaNode;
|
|
56
|
+
kind: "array";
|
|
57
|
+
length?: Readonly<{
|
|
58
|
+
max?: number;
|
|
59
|
+
min?: number;
|
|
60
|
+
}>;
|
|
61
|
+
}>) | (ConfigSchemaCommon & Readonly<{
|
|
62
|
+
alternatives: readonly ConfigSchemaNode[];
|
|
63
|
+
kind: "union";
|
|
64
|
+
}>) | (ConfigSchemaCommon & Readonly<{
|
|
65
|
+
kind: "reference";
|
|
66
|
+
name: string;
|
|
67
|
+
}>);
|
|
68
|
+
export type ConfigSchemaField = Readonly<{
|
|
69
|
+
id: string;
|
|
70
|
+
name: string;
|
|
71
|
+
required: boolean;
|
|
72
|
+
schema: ConfigSchemaNode;
|
|
73
|
+
}>;
|
|
74
|
+
export type ConfigSchema = Readonly<{
|
|
75
|
+
definitions?: Readonly<Record<string, ConfigSchemaNode>>;
|
|
76
|
+
formatVersion: typeof configSchemaFormatVersion;
|
|
77
|
+
root: ConfigSchemaNode;
|
|
78
|
+
}>;
|
|
79
|
+
export type ConfigSchemaDiagnostic = Readonly<{
|
|
80
|
+
schemaPath: string;
|
|
81
|
+
code: string;
|
|
82
|
+
jsonSchemaPath?: string;
|
|
83
|
+
message: string;
|
|
84
|
+
}>;
|
|
85
|
+
export declare class ConfigSchemaError extends Error {
|
|
86
|
+
readonly diagnostics: readonly ConfigSchemaDiagnostic[];
|
|
87
|
+
constructor(message: string, diagnostics: readonly ConfigSchemaDiagnostic[]);
|
|
88
|
+
}
|
|
89
|
+
export declare const configSchemaJsonProjectionMapping: Readonly<{
|
|
90
|
+
readonly allowedValues: "enum";
|
|
91
|
+
readonly alternatives: "oneOf";
|
|
92
|
+
readonly compatibility: "x-runbound-compatibility-intent";
|
|
93
|
+
readonly default: "default";
|
|
94
|
+
readonly definitions: "$defs";
|
|
95
|
+
readonly deprecated: "x-runbound-deprecated";
|
|
96
|
+
readonly description: "description";
|
|
97
|
+
readonly elementIdProperty: "x-runbound-element-id-property";
|
|
98
|
+
readonly exposure: "x-runbound-exposure";
|
|
99
|
+
readonly extraFields: "additionalProperties";
|
|
100
|
+
readonly fallback: "x-runbound-fallback";
|
|
101
|
+
readonly fields: "properties";
|
|
102
|
+
readonly format: "format";
|
|
103
|
+
readonly formatVersion: "$schema";
|
|
104
|
+
readonly id: "x-runbound-field-id";
|
|
105
|
+
readonly items: "items";
|
|
106
|
+
readonly kind: "type";
|
|
107
|
+
readonly lengthMax: "maxItems|maxLength";
|
|
108
|
+
readonly lengthMin: "minItems|minLength";
|
|
109
|
+
readonly lifecycle: "x-runbound-lifecycle";
|
|
110
|
+
readonly localOverride: "x-runbound-local-override";
|
|
111
|
+
readonly ownerIds: "x-runbound-owner-principal-ids";
|
|
112
|
+
readonly rangeMax: "maximum";
|
|
113
|
+
readonly rangeMin: "minimum";
|
|
114
|
+
readonly referenceName: "$ref";
|
|
115
|
+
readonly replacementFieldId: "x-runbound-replacement-field-id";
|
|
116
|
+
readonly reviewerIds: "x-runbound-reviewer-principal-ids";
|
|
117
|
+
readonly secretReference: "x-runbound-secret-reference";
|
|
118
|
+
readonly staleness: "x-runbound-staleness";
|
|
119
|
+
readonly targeting: "x-runbound-targeting";
|
|
120
|
+
readonly valueKind: "x-runbound-value-kind";
|
|
121
|
+
}>;
|
|
122
|
+
export declare function parseConfigSchema(value: unknown): ConfigSchema;
|
|
123
|
+
export declare function normalizeConfigSchema(document: ConfigSchema): ConfigSchema;
|
|
124
|
+
export declare function validateConfigSchema(value: unknown): asserts value is ConfigSchema;
|
|
125
|
+
export declare function validateConfigDocument(schema: ConfigSchema, value: unknown): asserts value is JsonValue;
|
|
126
|
+
export declare function materializeDefaults(schema: ConfigSchema, value: JsonValue | undefined): JsonValue;
|
|
127
|
+
export declare function compilePublicProjection(schema: ConfigSchema, value: JsonValue): {
|
|
128
|
+
schema: ConfigSchema;
|
|
129
|
+
value: JsonValue;
|
|
130
|
+
};
|
|
131
|
+
export declare function configSchemaToJsonSchemaProjection(document: ConfigSchema): ConfigJsonSchemaProjection;
|
|
132
|
+
export declare function configJsonSchemaProjectionToSchema(value: ConfigJsonSchemaProjection): ConfigSchema;
|
|
133
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,76 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@runbound/config-browser",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0-alpha.1",
|
|
4
|
+
"description": "Runbound Config for the browser: typed configuration snapshots, subscriptions, pinned sessions, refresh and experiment exposure for any framework or none.",
|
|
5
|
+
"author": "Runbound",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"runbound",
|
|
8
|
+
"config",
|
|
9
|
+
"configuration",
|
|
10
|
+
"feature-flags",
|
|
11
|
+
"browser",
|
|
12
|
+
"experimentation"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://github.com/runbound-io/config/tree/main/sdks/browser#readme",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/runbound-io/config/issues"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/runbound-io/config.git",
|
|
21
|
+
"directory": "sdks/browser"
|
|
22
|
+
},
|
|
23
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public",
|
|
26
|
+
"tag": "alpha"
|
|
27
|
+
},
|
|
28
|
+
"type": "module",
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"!dist/**/*.map",
|
|
32
|
+
"CHANGELOG.md",
|
|
33
|
+
"THIRD_PARTY_NOTICES.md"
|
|
34
|
+
],
|
|
35
|
+
"sideEffects": false,
|
|
36
|
+
"exports": {
|
|
37
|
+
".": {
|
|
38
|
+
"types": "./dist/index.d.ts",
|
|
39
|
+
"import": "./dist/index.js",
|
|
40
|
+
"default": "./dist/index.js"
|
|
41
|
+
},
|
|
42
|
+
"./config-context": {
|
|
43
|
+
"types": "./dist/config-context.d.ts",
|
|
44
|
+
"import": "./dist/config-context.js",
|
|
45
|
+
"default": "./dist/config-context.js"
|
|
46
|
+
},
|
|
47
|
+
"./config-context-client": {
|
|
48
|
+
"types": "./dist/config-context-client.d.ts",
|
|
49
|
+
"import": "./dist/config-context-client.js",
|
|
50
|
+
"default": "./dist/config-context-client.js"
|
|
51
|
+
},
|
|
52
|
+
"./config-delivery-store": {
|
|
53
|
+
"types": "./dist/config-delivery-store.d.ts",
|
|
54
|
+
"import": "./dist/config-delivery-store.js",
|
|
55
|
+
"default": "./dist/config-delivery-store.js"
|
|
56
|
+
},
|
|
57
|
+
"./config-experimentation": {
|
|
58
|
+
"types": "./dist/config-experimentation.d.ts",
|
|
59
|
+
"import": "./dist/config-experimentation.js",
|
|
60
|
+
"default": "./dist/config-experimentation.js"
|
|
61
|
+
},
|
|
62
|
+
"./config-experiment-committed-render": {
|
|
63
|
+
"types": "./dist/config-experiment-committed-render.d.ts",
|
|
64
|
+
"import": "./dist/config-experiment-committed-render.js",
|
|
65
|
+
"default": "./dist/config-experiment-committed-render.js"
|
|
66
|
+
},
|
|
67
|
+
"./config-refresh": {
|
|
68
|
+
"types": "./dist/config-refresh.d.ts",
|
|
69
|
+
"import": "./dist/config-refresh.js",
|
|
70
|
+
"default": "./dist/config-refresh.js"
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"dependencies": {
|
|
74
|
+
"@noble/hashes": "2.2.0"
|
|
75
|
+
}
|
|
76
|
+
}
|