@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.
@@ -0,0 +1,430 @@
1
+ import { type JsonValue } from "./base.js";
2
+ export declare const configDecisioningContractVersion = "runbound.config.decisioning.v1";
3
+ /**
4
+ * Hard protocol bounds. These are compatibility-bearing rejection thresholds,
5
+ * not deployment defaults, and therefore cannot be raised without a new
6
+ * decisioning contract version and cross-runtime fixtures.
7
+ */
8
+ export declare const configDecisioningLimits: Readonly<{
9
+ maximumActivationSetBytes: number;
10
+ maximumAllocationFieldBytes: 4096;
11
+ maximumAllocationRangesPerRule: 64;
12
+ maximumAttributePathBytes: 256;
13
+ maximumAttributesPerKind: 64;
14
+ maximumAttributesTotal: 256;
15
+ maximumBoundedSetBytes: number;
16
+ maximumBoundedSetItems: 64;
17
+ maximumContextBytes: number;
18
+ maximumContextContractBytes: number;
19
+ maximumContextKinds: 16;
20
+ maximumContextStringBytes: 4096;
21
+ maximumDecisionsPerProgram: 1024;
22
+ maximumEvaluationDetailsBytes: number;
23
+ maximumDependencyNodesPerEvaluation: 128;
24
+ maximumDirectPrerequisites: 16;
25
+ maximumDirectTargetsPerDecision: 128;
26
+ maximumEvaluationSteps: 10000;
27
+ maximumExplicitSegmentMembers: 10000;
28
+ maximumInlineSimulationCases: 1024;
29
+ maximumReferencedCohortUnits: 100000;
30
+ maximumPrerequisiteDepth: 32;
31
+ maximumPrivateArtifactBytes: number;
32
+ maximumProgramClauses: 65536;
33
+ maximumProgramIrBytes: number;
34
+ maximumProgramRules: 16384;
35
+ maximumPublicArtifactBytes: number;
36
+ maximumRemoteRequestBytes: number;
37
+ maximumRemoteResponseBytes: number;
38
+ maximumRuleBooleanDepth: 8;
39
+ maximumRuleClauses: 32;
40
+ maximumRuleClausesPerDecision: 2048;
41
+ maximumRulesPerDecision: 128;
42
+ maximumSegmentSnapshotBytes: number;
43
+ maximumSegmentsPerProgram: 1024;
44
+ maximumTraceBytes: number;
45
+ maximumTraceSteps: 512;
46
+ maximumUnitKeyBytes: 512;
47
+ maximumVariationsPerDecision: 32;
48
+ slotCount: 1000000;
49
+ }>;
50
+ export declare const configDecisioningAdmissionLimits: Readonly<{
51
+ artifactDelivery: Readonly<{
52
+ bindingBurst: 20;
53
+ bindingPerMinute: 120;
54
+ tenantBurst: 200;
55
+ tenantPerMinute: 1200;
56
+ }>;
57
+ remoteEvaluation: Readonly<{
58
+ credentialBurst: 200;
59
+ credentialInFlight: 64;
60
+ credentialPerMinute: 6000;
61
+ tenantBurst: 2000;
62
+ tenantInFlight: 512;
63
+ tenantPerMinute: 60000;
64
+ }>;
65
+ simulation: Readonly<{
66
+ principalInFlight: 2;
67
+ principalPerMinute: 30;
68
+ tenantInFlight: 8;
69
+ tenantPerMinute: 300;
70
+ }>;
71
+ }>;
72
+ /**
73
+ * Inactive/unpriced Phase 3 usage dimensions. Keeping these calculations in
74
+ * the contract prevents admission counters from being mistaken for billable
75
+ * units when later gates activate pricing.
76
+ */
77
+ export declare const configDecisioningCostUnits: Readonly<{
78
+ artifactDelivery(bodyBytes: number, responseHasBody?: boolean): number;
79
+ remoteEvaluation(acceptedDecisions: number): number;
80
+ simulation(decisionContextPairs: number): number;
81
+ }>;
82
+ export declare const configDecisioningPerformanceBudgets: Readonly<{
83
+ artifactLoad: Readonly<{
84
+ p95Ms: 500;
85
+ peakRssGrowthBytes: number;
86
+ }>;
87
+ localBudgetEdge: Readonly<{
88
+ p95Ms: 10;
89
+ p99Ms: 20;
90
+ }>;
91
+ localCommon: Readonly<{
92
+ minimumEvaluationsPerSecond: 25000;
93
+ p95Ms: 0.5;
94
+ p99Ms: 1;
95
+ }>;
96
+ localSoak: Readonly<{
97
+ durationSeconds: 300;
98
+ maximumP95DriftRatio: 0.1;
99
+ postWarmRssGrowthBytes: number;
100
+ minimumEvaluations: 7500000;
101
+ }>;
102
+ remoteBudgetEdge: Readonly<{
103
+ p95Ms: 500;
104
+ p99Ms: 1000;
105
+ }>;
106
+ remoteCold: Readonly<{
107
+ p99Ms: 2000;
108
+ }>;
109
+ remoteWarm: Readonly<{
110
+ p95Ms: 150;
111
+ p99Ms: 500;
112
+ }>;
113
+ retainedBaseline: Readonly<{
114
+ maximumP95Ratio: 1.25;
115
+ minimumThroughputRatio: 0.9;
116
+ }>;
117
+ }>;
118
+ export type ConfigContextSourceClass = "advisoryClientAsserted" | "applicationAsserted" | "authenticatedWorkload" | "runboundRegistered" | "serverEnriched";
119
+ export type ConfigContextSensitivity = "confidential" | "internal" | "public" | "restricted";
120
+ export type ConfigContextRetention = "assignment" | "exposure" | "metric" | "none" | "request";
121
+ export type ConfigContextAttributeType = "boolean" | "finiteNumber" | "ipAddress" | "semanticVersion" | "string" | "stringSet" | "timestamp";
122
+ export type ConfigTargetingOperator = "equals" | "exists" | "greaterThan" | "greaterThanOrEqual" | "inSet" | "ipInCidr" | "intersects" | "lessThan" | "lessThanOrEqual" | "notEquals" | "prefix" | "substring" | "suffix";
123
+ export type ConfigContextAttributeContract = Readonly<{
124
+ allowedOperators: readonly ConfigTargetingOperator[];
125
+ description: string;
126
+ lifecycle: "active" | "deprecated";
127
+ nullable: boolean;
128
+ owner: string;
129
+ path: string;
130
+ publicRuleEligible: boolean;
131
+ required: boolean;
132
+ retention: ConfigContextRetention;
133
+ sensitivity: ConfigContextSensitivity;
134
+ source: ConfigContextSourceClass;
135
+ type: ConfigContextAttributeType;
136
+ }>;
137
+ export type ConfigContextKindContract = Readonly<{
138
+ attributes: readonly ConfigContextAttributeContract[];
139
+ description: string;
140
+ kind: string;
141
+ owner: string;
142
+ required: boolean;
143
+ unitKey: string;
144
+ }>;
145
+ export type ConfigContextContract = Readonly<{
146
+ configId: string;
147
+ contextContractId: string;
148
+ formatVersion: typeof configDecisioningContractVersion;
149
+ kinds: readonly ConfigContextKindContract[];
150
+ projectId: string;
151
+ revision: number;
152
+ tenantId: string;
153
+ }>;
154
+ export type ConfigContextScalar = boolean | number | string;
155
+ export type ConfigContextValue = ConfigContextScalar | null | readonly string[];
156
+ export type ConfigEvaluationEntity = Readonly<{
157
+ attributes: Readonly<Record<string, ConfigContextValue>>;
158
+ key: string;
159
+ kind: string;
160
+ }>;
161
+ export type ConfigEvaluationContext = Readonly<{
162
+ formatVersion: "runbound.config.evaluation-context.v1";
163
+ kinds: readonly ConfigEvaluationEntity[];
164
+ }>;
165
+ export type ConfigAllocationV1Input = Readonly<{
166
+ allocationNamespace: string;
167
+ projectId: string;
168
+ randomizationContextKind: string;
169
+ reassignmentEpoch: number;
170
+ salt: string;
171
+ tenantId: string;
172
+ unitKey: string;
173
+ }>;
174
+ export type ConfigAllocationV1Result = Readonly<{
175
+ bucket: number;
176
+ digest: `sha256:${string}`;
177
+ protocolVersion: 1;
178
+ }>;
179
+ export type ConfigDecisionValueSchema = Readonly<{
180
+ type: "boolean";
181
+ }> | Readonly<{
182
+ type: "number";
183
+ }> | Readonly<{
184
+ type: "string";
185
+ }> | Readonly<{
186
+ type: "enum";
187
+ values: readonly string[];
188
+ }> | Readonly<{
189
+ schemaDigest: string;
190
+ type: "object";
191
+ }>;
192
+ export type ConfigVariation = Readonly<{
193
+ description: string;
194
+ variationId: string;
195
+ value: JsonValue;
196
+ }>;
197
+ export type ConfigPrerequisite = Readonly<{
198
+ decisionId: string;
199
+ variationIds: readonly string[];
200
+ }>;
201
+ export type ConfigDecisionReason = "CACHED" | "DEFAULT" | "DISABLED" | "ERROR" | "SPLIT" | "STATIC" | "STALE" | "TARGETING_MATCH";
202
+ export type ConfigDecisionErrorCode = "FLAG_NOT_FOUND" | "GENERAL" | "INVALID_CONTEXT" | "PARSE_ERROR" | "PROVIDER_FATAL" | "PROVIDER_NOT_READY" | "TARGETING_KEY_MISSING" | "TYPE_MISMATCH";
203
+ export type ConfigDecisionFallback = Readonly<{
204
+ mode: "current";
205
+ }> | Readonly<{
206
+ mode: "failClosed";
207
+ variationId: string;
208
+ }> | Readonly<{
209
+ mode: "lastKnownGood";
210
+ }> | Readonly<{
211
+ mode: "literal";
212
+ variationId: string;
213
+ }>;
214
+ export type ConfigDecisionDefinition = Readonly<{
215
+ decisionId: string;
216
+ delivery: Readonly<{
217
+ allowedAudiences: readonly ConfigAudience[];
218
+ publicRuleApproved: boolean;
219
+ }>;
220
+ description: string;
221
+ disabledVariationId?: string;
222
+ fallthroughVariationId: string;
223
+ fallback: ConfigDecisionFallback;
224
+ openFeaturePrimaryContextKind: string;
225
+ prerequisites: readonly ConfigPrerequisite[];
226
+ targets?: readonly ConfigDecisionTarget[];
227
+ valueSchema: ConfigDecisionValueSchema;
228
+ variations: readonly ConfigVariation[];
229
+ }>;
230
+ export type ConfigDecisionClause = Readonly<{
231
+ contextKind: string;
232
+ expected: ConfigContextValue;
233
+ operator: ConfigTargetingOperator;
234
+ path: string;
235
+ }>;
236
+ export type ConfigDecisionTarget = Readonly<{
237
+ contextKind: string;
238
+ targetId: string;
239
+ unitKey: string;
240
+ variationId: string;
241
+ }>;
242
+ export type ConfigSegmentMembershipExpression = Readonly<{
243
+ segment: Readonly<{
244
+ segmentId: string;
245
+ sourceRevision: string;
246
+ }>;
247
+ }>;
248
+ export type ConfigDecisionExpression = ConfigDecisionClause | ConfigSegmentMembershipExpression | Readonly<{
249
+ all: readonly ConfigDecisionExpression[];
250
+ }> | Readonly<{
251
+ any: readonly ConfigDecisionExpression[];
252
+ }> | Readonly<{
253
+ not: ConfigDecisionExpression;
254
+ }>;
255
+ export type ConfigAllocationRange = Readonly<{
256
+ end: number;
257
+ start: number;
258
+ variationId?: string;
259
+ }>;
260
+ export type ConfigAllocationReservationClass = "experiment" | "holdout" | "rollout";
261
+ export type ConfigRuleAllocation = Readonly<{
262
+ allocationNamespace: string;
263
+ missingRandomizationUnitPolicy: "error" | "fallthrough";
264
+ ranges: readonly ConfigAllocationRange[];
265
+ randomizationContextKind: string;
266
+ reassignmentEpoch: number;
267
+ reassignmentPolicy: "explicitLedger" | "rebucket" | "stickyExpansion";
268
+ reservationClass: ConfigAllocationReservationClass;
269
+ revision: number;
270
+ salt: string;
271
+ }>;
272
+ export type ConfigDecisionRule = Readonly<{
273
+ allocation?: ConfigRuleAllocation;
274
+ condition: ConfigDecisionExpression;
275
+ ruleId: string;
276
+ schedule?: Readonly<{
277
+ endsAt?: string;
278
+ startsAt?: string;
279
+ }>;
280
+ variationId?: string;
281
+ }>;
282
+ export type ConfigDecisionProgram = Readonly<{
283
+ configId: string;
284
+ contextContractDigest: string;
285
+ decisions: readonly ConfigDecisionDefinition[];
286
+ formatVersion: "runbound.config.decision-program.v1";
287
+ programRevisionId: string;
288
+ projectId: string;
289
+ rules: Readonly<Record<string, readonly ConfigDecisionRule[]>>;
290
+ segmentRevisionIds: readonly string[];
291
+ tenantId: string;
292
+ }>;
293
+ export type ConfigDecisionIr = Readonly<{
294
+ canonicalProgramDigest: string;
295
+ configId: string;
296
+ contextContractDigest: string;
297
+ decisions: readonly ConfigDecisionDefinition[];
298
+ formatVersion: "runbound.config.decision-ir.v1";
299
+ projectId: string;
300
+ rules: Readonly<Record<string, readonly ConfigDecisionRule[]>>;
301
+ segmentRevisionDigests: readonly string[];
302
+ }>;
303
+ export type ConfigSegment = Readonly<{
304
+ configId: string;
305
+ description: string;
306
+ environmentId: string;
307
+ projectId: string;
308
+ segmentId: string;
309
+ tenantId: string;
310
+ }>;
311
+ export type ConfigSegmentRevision = Readonly<{
312
+ configId: string;
313
+ exclude: readonly string[];
314
+ expiresAt?: string;
315
+ externalSnapshotDigest?: string;
316
+ include: readonly string[];
317
+ projectId: string;
318
+ revision: number;
319
+ segmentId: string;
320
+ sourceRevision: string;
321
+ }>;
322
+ export type ConfigEvaluationDetails = Readonly<{
323
+ activationSetId: string;
324
+ allocationNamespace?: string;
325
+ artifactFreshness?: "current" | "lastKnownGood";
326
+ artifactDigest: string;
327
+ bucket?: number;
328
+ configReleaseId?: string;
329
+ decisionId: string;
330
+ errorCode?: ConfigDecisionErrorCode;
331
+ evaluationMode?: ConfigAudience;
332
+ exposureToken?: string;
333
+ fallbackSource?: "current" | "default" | "failClosed" | "lastKnownGood";
334
+ matchedId?: string;
335
+ overrideSource?: "assignmentLedger" | "localTest";
336
+ reason: ConfigDecisionReason;
337
+ reassignmentEpoch?: number;
338
+ reservationClass?: ConfigAllocationReservationClass;
339
+ reservationId?: string;
340
+ softwareReleaseId?: string;
341
+ traceDigest: string;
342
+ variationId?: string;
343
+ }>;
344
+ export type ConfigDecisionResult = Readonly<{
345
+ details: ConfigEvaluationDetails;
346
+ value?: JsonValue;
347
+ }>;
348
+ export type ConfigDecisionTraceStep = Readonly<{
349
+ decisionId: string;
350
+ outcome: string;
351
+ step: "allocation" | "context" | "fallthrough" | "override" | "prerequisite" | "reservation" | "rule" | "segment" | "target";
352
+ subjectId?: string;
353
+ /**
354
+ * Which revision of the subject decided. Populated by the `segment` step,
355
+ * where naming the segment alone is not an explanation: the same segment id
356
+ * decides differently across revisions, and a reader reconciling a decision
357
+ * with an audience needs to know which membership answered.
358
+ */
359
+ subjectRevision?: number;
360
+ subjectSourceRevision?: string;
361
+ }>;
362
+ export type ConfigDecisionTrace = Readonly<{
363
+ formatVersion: "runbound.config.decision-trace.v1";
364
+ steps: readonly ConfigDecisionTraceStep[];
365
+ traceDigest: string;
366
+ }>;
367
+ export type ConfigAudience = "edge" | "localPrivate" | "localPublic" | "remote";
368
+ export type ConfigAudienceArtifact = Readonly<{
369
+ audience: ConfigAudience;
370
+ canonicalProgramDigest: string;
371
+ configId: string;
372
+ contextContractDigest: string;
373
+ formatVersion: "runbound.config.audience-artifact.v1";
374
+ ir: ConfigDecisionIr;
375
+ projectId: string;
376
+ projectionDigest: string;
377
+ segmentRevisionDigests: readonly string[];
378
+ }>;
379
+ export type ConfigDecisionArtifactEnvelope = Readonly<{
380
+ artifactDigest: string;
381
+ audience: ConfigAudience;
382
+ envelopeId: string;
383
+ formatVersion: "runbound.config.decision-artifact-envelope.v1";
384
+ keyId: string;
385
+ signature: string;
386
+ signatureAlgorithm: "ECDSA_SHA_256" | "Ed25519";
387
+ tenantId: string;
388
+ }>;
389
+ export type ConfigDecisioningActivationSet = Readonly<{
390
+ activationSetId: string;
391
+ allocationManifestDigest: string;
392
+ appId: string;
393
+ assignmentId: string;
394
+ audience: ConfigAudience;
395
+ audienceArtifactDigest: string;
396
+ baseActivationIds: readonly string[];
397
+ channel: string;
398
+ configId: string;
399
+ consumerRegistrationId: string;
400
+ contextContractDigest: string;
401
+ environmentId: string;
402
+ formatVersion: "runbound.config.targeted-activation-set.v1";
403
+ keyId: string;
404
+ projectId: string;
405
+ sequence: number;
406
+ signature: string;
407
+ signatureAlgorithm: "ECDSA_SHA_256" | "Ed25519";
408
+ softwareReleaseIds: readonly string[];
409
+ tenantId: string;
410
+ }>;
411
+ export declare function isConfigDecisioningSemanticVersion(value: unknown): value is string;
412
+ export declare function isConfigDecisioningTimestamp(value: unknown): value is string;
413
+ export declare function validateConfigContextContract(value: unknown): asserts value is ConfigContextContract;
414
+ export declare function validateConfigEvaluationContext(contract: ConfigContextContract, value: unknown): asserts value is ConfigEvaluationContext;
415
+ /** Owns one immutable contract and validates each independently owned context. */
416
+ export declare function createConfigEvaluationContextPreparer(contract: ConfigContextContract): Readonly<{
417
+ contract: ConfigContextContract;
418
+ prepare: (value: unknown) => Readonly<{
419
+ context: ConfigEvaluationContext;
420
+ canonicalBytes: Uint8Array;
421
+ }>;
422
+ prepareFromEntities: (kinds: ConfigEvaluationContext["kinds"]) => Readonly<{
423
+ context: ConfigEvaluationContext;
424
+ canonicalBytes: Uint8Array;
425
+ }>;
426
+ }>;
427
+ export declare function validateConfigDecisionClauseAgainstContextContract(contract: ConfigContextContract, clause: ConfigDecisionClause): void;
428
+ export declare function configIpAddressMatchesCidr(addressValue: string, cidrValue: string): boolean;
429
+ /** Implements the sole epoch-bound million-slot allocation protocol. */
430
+ export declare function allocateConfigBucketV1(input: ConfigAllocationV1Input): ConfigAllocationV1Result;