@spotify-confidence/openfeature-server-provider-local 0.10.1 → 0.11.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 CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.11.1](https://github.com/spotify/confidence-resolver/compare/openfeature-provider-js-v0.11.0...openfeature-provider-js-v0.11.1) (2026-03-26)
4
+
5
+
6
+ ### Dependencies
7
+
8
+ * The following workspace dependencies were updated
9
+ * dependencies
10
+ * rust-guest bumped from 0.1.20 to 0.1.21
11
+
12
+ ## [0.11.0](https://github.com/spotify/confidence-resolver/compare/openfeature-provider-js-v0.10.1...openfeature-provider-js-v0.11.0) (2026-03-24)
13
+
14
+
15
+ ### Features
16
+
17
+ * add register_resolve WASM export for SDK-side telemetry ([#354](https://github.com/spotify/confidence-resolver/issues/354)) ([31499bc](https://github.com/spotify/confidence-resolver/commit/31499bc911942ecd751b4a4a702f35ded41e9776))
18
+ * add resolver_version field to TelemetryData ([#346](https://github.com/spotify/confidence-resolver/issues/346)) ([10ab1c6](https://github.com/spotify/confidence-resolver/commit/10ab1c657cb830dc36f433d1dca0af73beecaa27))
19
+ * local prometheus sdk metrics ([#322](https://github.com/spotify/confidence-resolver/issues/322)) ([8b18119](https://github.com/spotify/confidence-resolver/commit/8b18119eae449afbe4a0815e8aab5f82888a8621))
20
+
21
+
22
+ ### Dependencies
23
+
24
+ * The following workspace dependencies were updated
25
+ * dependencies
26
+ * rust-guest bumped from 0.1.19 to 0.1.20
27
+
3
28
  ## [0.10.1](https://github.com/spotify/confidence-resolver/compare/openfeature-provider-js-v0.10.0...openfeature-provider-js-v0.10.1) (2026-03-12)
4
29
 
5
30
 
package/dist/client.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { EvaluationDetails, FlagValue } from "@openfeature/core";
2
2
 
3
3
  //#region src/types.d.ts
4
- type ResolutionReason = "ERROR" | "FLAG_ARCHIVED" | "MATCH" | "NO_SEGMENT_MATCH" | "TARGETING_KEY_ERROR" | "NO_TREATMENT_MATCH" | "UNSPECIFIED";
4
+ type ResolutionReason = "ERROR" | "FLAG_ARCHIVED" | "MATCH" | "NO_SEGMENT_MATCH" | "TARGETING_KEY_ERROR" | "NO_TREATMENT_MATCH" | "MATERIALIZATION_NOT_SUPPORTED" | "UNSPECIFIED";
5
5
  declare enum ErrorCode {
6
6
  PROVIDER_NOT_READY = "PROVIDER_NOT_READY",
7
7
  PROVIDER_FATAL = "PROVIDER_FATAL",
package/dist/client.js CHANGED
@@ -92,6 +92,16 @@ function resolve(bundle, flagKey, defaultValue, logger$1) {
92
92
  shouldApply: false
93
93
  };
94
94
  }
95
+ if (flag.reason === "MATERIALIZATION_NOT_SUPPORTED") {
96
+ logger$1?.warn("Flag '%s' requires materializations but no materialization store is configured. Pass a MaterializationStore implementation or: 'CONFIDENCE_REMOTE_STORE' to createConfidenceServerProvider()", flagName);
97
+ return {
98
+ reason: "ERROR",
99
+ errorCode: ErrorCode.GENERAL,
100
+ errorMessage: `Flag '${flagName}' requires materializations. Configure a materialization store.`,
101
+ value: defaultValue,
102
+ shouldApply: false
103
+ };
104
+ }
95
105
  let value = flag.value;
96
106
  for (let i = 0; i < path.length; i++) {
97
107
  if (value === null || typeof value !== "object" || Array.isArray(value)) return {
Binary file
@@ -82,6 +82,10 @@ declare enum ResolveReason {
82
82
  RESOLVE_REASON_UNRECOGNIZED_TARGETING_RULE = 7,
83
83
  /** RESOLVE_REASON_MATERIALIZATION_NOT_SUPPORTED - The flag could not be resolved because a rule is using materialization */
84
84
  RESOLVE_REASON_MATERIALIZATION_NOT_SUPPORTED = 8,
85
+ /** RESOLVE_REASON_TYPE_MISMATCH - The resolved value type does not match the type requested by the SDK */
86
+ RESOLVE_REASON_TYPE_MISMATCH = 9,
87
+ /** RESOLVE_REASON_FLAG_NOT_FOUND - The flag was not found in the resolve response */
88
+ RESOLVE_REASON_FLAG_NOT_FOUND = 10,
85
89
  UNRECOGNIZED = -1,
86
90
  }
87
91
  declare enum SdkId {
@@ -273,6 +277,10 @@ interface MaterializationRecord {
273
277
  rule: string;
274
278
  variant: string;
275
279
  }
280
+ interface RegisterResolveRequest {
281
+ reason: ResolveReason;
282
+ latencyUs: number;
283
+ }
276
284
  declare const ResolveProcessRequest: MessageFns$2<ResolveProcessRequest>;
277
285
  declare const ResolveProcessRequest_StaticMaterializations: MessageFns$2<ResolveProcessRequest_StaticMaterializations>;
278
286
  declare const ResolveProcessRequest_Resume: MessageFns$2<ResolveProcessRequest_Resume>;
@@ -280,6 +288,7 @@ declare const ResolveProcessResponse: MessageFns$2<ResolveProcessResponse>;
280
288
  declare const ResolveProcessResponse_Resolved: MessageFns$2<ResolveProcessResponse_Resolved>;
281
289
  declare const ResolveProcessResponse_Suspended: MessageFns$2<ResolveProcessResponse_Suspended>;
282
290
  declare const MaterializationRecord: MessageFns$2<MaterializationRecord>;
291
+ declare const RegisterResolveRequest: MessageFns$2<RegisterResolveRequest>;
283
292
  type Builtin$2 = Date | Function | Uint8Array | string | number | boolean | undefined;
284
293
  type DeepPartial$2<T> = T extends Builtin$2 ? T : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial$2<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial$2<U>> : T extends {} ? { [K in keyof T]?: DeepPartial$2<T[K]> } : Partial<T>;
285
294
  type KeysOfUnion$2<T> = T extends T ? keyof T : never;
@@ -316,10 +325,12 @@ interface MessageFns$1<T> {
316
325
  //#region src/LocalResolver.d.ts
317
326
  interface LocalResolver {
318
327
  resolveProcess(request: ResolveProcessRequest): ResolveProcessResponse;
328
+ registerResolve(request: RegisterResolveRequest): void;
319
329
  setResolverState(request: SetResolverStateRequest): void;
320
330
  flushLogs(): Uint8Array;
321
331
  flushAssigned(): Uint8Array;
322
332
  applyFlags(request: ApplyFlagsRequest): void;
333
+ prometheusSnapshot(instance: string): string;
323
334
  }
324
335
  //#endregion
325
336
  //#region src/proto/confidence/flags/resolver/v1/internal_api.d.ts
@@ -429,7 +440,7 @@ interface MaterializationStore {
429
440
  }
430
441
  //#endregion
431
442
  //#region src/types.d.ts
432
- type ResolutionReason = "ERROR" | "FLAG_ARCHIVED" | "MATCH" | "NO_SEGMENT_MATCH" | "TARGETING_KEY_ERROR" | "NO_TREATMENT_MATCH" | "UNSPECIFIED";
443
+ type ResolutionReason = "ERROR" | "FLAG_ARCHIVED" | "MATCH" | "NO_SEGMENT_MATCH" | "TARGETING_KEY_ERROR" | "NO_TREATMENT_MATCH" | "MATERIALIZATION_NOT_SUPPORTED" | "UNSPECIFIED";
433
444
  declare enum ErrorCode {
434
445
  PROVIDER_NOT_READY = "PROVIDER_NOT_READY",
435
446
  PROVIDER_FATAL = "PROVIDER_FATAL",
@@ -462,6 +473,12 @@ interface FlagBundle {
462
473
  //#endregion
463
474
  //#region src/ConfidenceServerProviderLocal.d.ts
464
475
  type FlagBundle$1 = FlagBundle;
476
+ /**
477
+ * Configuration for {@link ConfidenceServerProviderLocal.getPrometheusMetrics}.
478
+ *
479
+ * @experimental This API is subject to change.
480
+ */
481
+ interface SnapshotConfig {}
465
482
  interface ProviderOptions {
466
483
  flagClientSecret: string;
467
484
  initializeTimeout?: number;
@@ -513,6 +530,12 @@ declare class ConfidenceServerProviderLocal implements Provider {
513
530
  /** Resolves with an evaluation of a String flag */
514
531
  resolveStringEvaluation(flagKey: string, defaultValue: string, context: EvaluationContext): Promise<ResolutionDetails<string>>;
515
532
  /**
533
+ * Returns a Prometheus metrics snapshot from the WASM resolver.
534
+ *
535
+ * @experimental This API is subject to change.
536
+ */
537
+ getPrometheusMetrics(_request?: SnapshotConfig): string;
538
+ /**
516
539
  * Applies a previously resolved flag, logging that it was used/exposed.
517
540
  * Call this when a flag value is actually rendered or used in the client.
518
541
  * @param resolveToken - Base64-encoded resolve token from the flag bundle
@@ -530,4 +553,4 @@ declare function createConfidenceServerProvider({
530
553
  ...options
531
554
  }: ProviderOptionsExt): ConfidenceServerProviderLocal;
532
555
  //#endregion
533
- export { type MaterializationStore, ProviderOptionsExt, createConfidenceServerProvider };
556
+ export { type MaterializationStore, ProviderOptionsExt, type SnapshotConfig, createConfidenceServerProvider };
@@ -774,6 +774,8 @@ let ResolveReason = /* @__PURE__ */ function(ResolveReason$1) {
774
774
  ResolveReason$1[ResolveReason$1["RESOLVE_REASON_ERROR"] = 6] = "RESOLVE_REASON_ERROR";
775
775
  ResolveReason$1[ResolveReason$1["RESOLVE_REASON_UNRECOGNIZED_TARGETING_RULE"] = 7] = "RESOLVE_REASON_UNRECOGNIZED_TARGETING_RULE";
776
776
  ResolveReason$1[ResolveReason$1["RESOLVE_REASON_MATERIALIZATION_NOT_SUPPORTED"] = 8] = "RESOLVE_REASON_MATERIALIZATION_NOT_SUPPORTED";
777
+ ResolveReason$1[ResolveReason$1["RESOLVE_REASON_TYPE_MISMATCH"] = 9] = "RESOLVE_REASON_TYPE_MISMATCH";
778
+ ResolveReason$1[ResolveReason$1["RESOLVE_REASON_FLAG_NOT_FOUND"] = 10] = "RESOLVE_REASON_FLAG_NOT_FOUND";
777
779
  ResolveReason$1[ResolveReason$1["UNRECOGNIZED"] = -1] = "UNRECOGNIZED";
778
780
  return ResolveReason$1;
779
781
  }({});
@@ -797,6 +799,10 @@ function resolveReasonFromJSON(object) {
797
799
  case "RESOLVE_REASON_UNRECOGNIZED_TARGETING_RULE": return ResolveReason.RESOLVE_REASON_UNRECOGNIZED_TARGETING_RULE;
798
800
  case 8:
799
801
  case "RESOLVE_REASON_MATERIALIZATION_NOT_SUPPORTED": return ResolveReason.RESOLVE_REASON_MATERIALIZATION_NOT_SUPPORTED;
802
+ case 9:
803
+ case "RESOLVE_REASON_TYPE_MISMATCH": return ResolveReason.RESOLVE_REASON_TYPE_MISMATCH;
804
+ case 10:
805
+ case "RESOLVE_REASON_FLAG_NOT_FOUND": return ResolveReason.RESOLVE_REASON_FLAG_NOT_FOUND;
800
806
  case -1:
801
807
  case "UNRECOGNIZED":
802
808
  default: return ResolveReason.UNRECOGNIZED;
@@ -813,6 +819,8 @@ function resolveReasonToJSON(object) {
813
819
  case ResolveReason.RESOLVE_REASON_ERROR: return "RESOLVE_REASON_ERROR";
814
820
  case ResolveReason.RESOLVE_REASON_UNRECOGNIZED_TARGETING_RULE: return "RESOLVE_REASON_UNRECOGNIZED_TARGETING_RULE";
815
821
  case ResolveReason.RESOLVE_REASON_MATERIALIZATION_NOT_SUPPORTED: return "RESOLVE_REASON_MATERIALIZATION_NOT_SUPPORTED";
822
+ case ResolveReason.RESOLVE_REASON_TYPE_MISMATCH: return "RESOLVE_REASON_TYPE_MISMATCH";
823
+ case ResolveReason.RESOLVE_REASON_FLAG_NOT_FOUND: return "RESOLVE_REASON_FLAG_NOT_FOUND";
816
824
  case ResolveReason.UNRECOGNIZED:
817
825
  default: return "UNRECOGNIZED";
818
826
  }
@@ -1410,7 +1418,7 @@ function isObject(value) {
1410
1418
  function isSet$3(value) {
1411
1419
  return value !== null && value !== void 0;
1412
1420
  }
1413
- const VERSION = "0.10.1";
1421
+ const VERSION = "0.11.1";
1414
1422
  const NOOP_LOG_FN = Object.assign(() => {}, { enabled: false });
1415
1423
  const debugBackend = loadDebug();
1416
1424
  const logger$2 = new class LoggerImpl {
@@ -2550,6 +2558,90 @@ const Response$1 = {
2550
2558
  return message;
2551
2559
  }
2552
2560
  };
2561
+ function createBasePrometheusSnapshotRequest() {
2562
+ return { instance: "" };
2563
+ }
2564
+ const PrometheusSnapshotRequest = {
2565
+ encode(message, writer = new BinaryWriter()) {
2566
+ if (message.instance !== "") writer.uint32(10).string(message.instance);
2567
+ return writer;
2568
+ },
2569
+ decode(input, length) {
2570
+ const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
2571
+ const end = length === void 0 ? reader.len : reader.pos + length;
2572
+ const message = createBasePrometheusSnapshotRequest();
2573
+ while (reader.pos < end) {
2574
+ const tag = reader.uint32();
2575
+ switch (tag >>> 3) {
2576
+ case 1:
2577
+ if (tag !== 10) break;
2578
+ message.instance = reader.string();
2579
+ continue;
2580
+ }
2581
+ if ((tag & 7) === 4 || tag === 0) break;
2582
+ reader.skip(tag & 7);
2583
+ }
2584
+ return message;
2585
+ },
2586
+ fromJSON(object) {
2587
+ return { instance: isSet$1(object.instance) ? globalThis.String(object.instance) : "" };
2588
+ },
2589
+ toJSON(message) {
2590
+ const obj = {};
2591
+ if (message.instance !== "") obj.instance = message.instance;
2592
+ return obj;
2593
+ },
2594
+ create(base) {
2595
+ return PrometheusSnapshotRequest.fromPartial(base ?? {});
2596
+ },
2597
+ fromPartial(object) {
2598
+ const message = createBasePrometheusSnapshotRequest();
2599
+ message.instance = object.instance ?? "";
2600
+ return message;
2601
+ }
2602
+ };
2603
+ function createBasePrometheusSnapshotResponse() {
2604
+ return { text: "" };
2605
+ }
2606
+ const PrometheusSnapshotResponse = {
2607
+ encode(message, writer = new BinaryWriter()) {
2608
+ if (message.text !== "") writer.uint32(10).string(message.text);
2609
+ return writer;
2610
+ },
2611
+ decode(input, length) {
2612
+ const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
2613
+ const end = length === void 0 ? reader.len : reader.pos + length;
2614
+ const message = createBasePrometheusSnapshotResponse();
2615
+ while (reader.pos < end) {
2616
+ const tag = reader.uint32();
2617
+ switch (tag >>> 3) {
2618
+ case 1:
2619
+ if (tag !== 10) break;
2620
+ message.text = reader.string();
2621
+ continue;
2622
+ }
2623
+ if ((tag & 7) === 4 || tag === 0) break;
2624
+ reader.skip(tag & 7);
2625
+ }
2626
+ return message;
2627
+ },
2628
+ fromJSON(object) {
2629
+ return { text: isSet$1(object.text) ? globalThis.String(object.text) : "" };
2630
+ },
2631
+ toJSON(message) {
2632
+ const obj = {};
2633
+ if (message.text !== "") obj.text = message.text;
2634
+ return obj;
2635
+ },
2636
+ create(base) {
2637
+ return PrometheusSnapshotResponse.fromPartial(base ?? {});
2638
+ },
2639
+ fromPartial(object) {
2640
+ const message = createBasePrometheusSnapshotResponse();
2641
+ message.text = object.text ?? "";
2642
+ return message;
2643
+ }
2644
+ };
2553
2645
  function bytesFromBase64$2(b64) {
2554
2646
  if (globalThis.Buffer) return Uint8Array.from(globalThis.Buffer.from(b64, "base64"));
2555
2647
  else {
@@ -2629,6 +2721,16 @@ function resolve(bundle, flagKey, defaultValue, logger$4) {
2629
2721
  shouldApply: false
2630
2722
  };
2631
2723
  }
2724
+ if (flag.reason === "MATERIALIZATION_NOT_SUPPORTED") {
2725
+ logger$4?.warn("Flag '%s' requires materializations but no materialization store is configured. Pass a MaterializationStore implementation or: 'CONFIDENCE_REMOTE_STORE' to createConfidenceServerProvider()", flagName);
2726
+ return {
2727
+ reason: "ERROR",
2728
+ errorCode: ErrorCode.GENERAL,
2729
+ errorMessage: `Flag '${flagName}' requires materializations. Configure a materialization store.`,
2730
+ value: defaultValue,
2731
+ shouldApply: false
2732
+ };
2733
+ }
2632
2734
  let value = flag.value;
2633
2735
  for (let i = 0; i < path.length; i++) {
2634
2736
  if (value === null || typeof value !== "object" || Array.isArray(value)) return {
@@ -2682,6 +2784,7 @@ function convertReason(reason) {
2682
2784
  case ResolveReason.RESOLVE_REASON_TARGETING_KEY_ERROR: return "TARGETING_KEY_ERROR";
2683
2785
  case ResolveReason.RESOLVE_REASON_NO_TREATMENT_MATCH: return "NO_TREATMENT_MATCH";
2684
2786
  case ResolveReason.RESOLVE_REASON_UNRECOGNIZED_TARGETING_RULE: return "ERROR";
2787
+ case ResolveReason.RESOLVE_REASON_MATERIALIZATION_NOT_SUPPORTED: return "MATERIALIZATION_NOT_SUPPORTED";
2685
2788
  default: return "UNSPECIFIED";
2686
2789
  }
2687
2790
  }
@@ -2777,10 +2880,28 @@ var ConfidenceServerProviderLocal = class ConfidenceServerProviderLocal {
2777
2880
  }
2778
2881
  }
2779
2882
  async evaluate(flagKey, defaultValue, context) {
2883
+ const startMs = performance.now();
2780
2884
  try {
2781
2885
  const [flagName] = flagKey.split(".", 1);
2782
2886
  const resolution = await this.resolve(context, [flagName], true);
2783
- return resolve(resolution, flagKey, defaultValue, logger$1);
2887
+ const result = resolve(resolution, flagKey, defaultValue, logger$1);
2888
+ const latencyUs = Math.round((performance.now() - startMs) * 1e3);
2889
+ let reason;
2890
+ if (resolution.errorCode) reason = ResolveReason.RESOLVE_REASON_ERROR;
2891
+ else {
2892
+ const [flagNameForTelemetry] = flagKey.split(".", 1);
2893
+ if (resolution.flags[flagNameForTelemetry]?.reason === "MATERIALIZATION_NOT_SUPPORTED") reason = ResolveReason.RESOLVE_REASON_MATERIALIZATION_NOT_SUPPORTED;
2894
+ else if (result.errorCode === ErrorCode.FLAG_NOT_FOUND) reason = ResolveReason.RESOLVE_REASON_FLAG_NOT_FOUND;
2895
+ else if (result.errorCode === ErrorCode.TYPE_MISMATCH) reason = ResolveReason.RESOLVE_REASON_TYPE_MISMATCH;
2896
+ else reason = reasonStringToEnum(result.reason);
2897
+ }
2898
+ try {
2899
+ this.resolver.registerResolve({
2900
+ reason,
2901
+ latencyUs
2902
+ });
2903
+ } catch {}
2904
+ return result;
2784
2905
  } finally {
2785
2906
  this.flushAssigned();
2786
2907
  }
@@ -2887,6 +3008,9 @@ var ConfidenceServerProviderLocal = class ConfidenceServerProviderLocal {
2887
3008
  resolveStringEvaluation(flagKey, defaultValue, context) {
2888
3009
  return Promise.resolve(this.evaluate(flagKey, defaultValue, context));
2889
3010
  }
3011
+ getPrometheusMetrics(_request) {
3012
+ return this.resolver.prometheusSnapshot("0");
3013
+ }
2890
3014
  applyFlag(resolveToken, flagName) {
2891
3015
  const request = {
2892
3016
  flags: [{
@@ -2904,6 +3028,17 @@ var ConfidenceServerProviderLocal = class ConfidenceServerProviderLocal {
2904
3028
  this.resolver.applyFlags(request);
2905
3029
  }
2906
3030
  };
3031
+ function reasonStringToEnum(reason) {
3032
+ switch (reason) {
3033
+ case "MATCH": return ResolveReason.RESOLVE_REASON_MATCH;
3034
+ case "NO_SEGMENT_MATCH": return ResolveReason.RESOLVE_REASON_NO_SEGMENT_MATCH;
3035
+ case "NO_TREATMENT_MATCH": return ResolveReason.RESOLVE_REASON_NO_TREATMENT_MATCH;
3036
+ case "FLAG_ARCHIVED": return ResolveReason.RESOLVE_REASON_FLAG_ARCHIVED;
3037
+ case "TARGETING_KEY_ERROR": return ResolveReason.RESOLVE_REASON_TARGETING_KEY_ERROR;
3038
+ case "ERROR": return ResolveReason.RESOLVE_REASON_ERROR;
3039
+ default: return ResolveReason.RESOLVE_REASON_UNSPECIFIED;
3040
+ }
3041
+ }
2907
3042
  function createBaseResolveProcessRequest() {
2908
3043
  return {
2909
3044
  deferredMaterializations: void 0,
@@ -3325,6 +3460,61 @@ const MaterializationRecord = {
3325
3460
  return message;
3326
3461
  }
3327
3462
  };
3463
+ function createBaseRegisterResolveRequest() {
3464
+ return {
3465
+ reason: 0,
3466
+ latencyUs: 0
3467
+ };
3468
+ }
3469
+ const RegisterResolveRequest = {
3470
+ encode(message, writer = new BinaryWriter()) {
3471
+ if (message.reason !== 0) writer.uint32(8).int32(message.reason);
3472
+ if (message.latencyUs !== 0) writer.uint32(16).uint32(message.latencyUs);
3473
+ return writer;
3474
+ },
3475
+ decode(input, length) {
3476
+ const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
3477
+ const end = length === void 0 ? reader.len : reader.pos + length;
3478
+ const message = createBaseRegisterResolveRequest();
3479
+ while (reader.pos < end) {
3480
+ const tag = reader.uint32();
3481
+ switch (tag >>> 3) {
3482
+ case 1:
3483
+ if (tag !== 8) break;
3484
+ message.reason = reader.int32();
3485
+ continue;
3486
+ case 2:
3487
+ if (tag !== 16) break;
3488
+ message.latencyUs = reader.uint32();
3489
+ continue;
3490
+ }
3491
+ if ((tag & 7) === 4 || tag === 0) break;
3492
+ reader.skip(tag & 7);
3493
+ }
3494
+ return message;
3495
+ },
3496
+ fromJSON(object) {
3497
+ return {
3498
+ reason: isSet(object.reason) ? resolveReasonFromJSON(object.reason) : 0,
3499
+ latencyUs: isSet(object.latencyUs) ? globalThis.Number(object.latencyUs) : 0
3500
+ };
3501
+ },
3502
+ toJSON(message) {
3503
+ const obj = {};
3504
+ if (message.reason !== 0) obj.reason = resolveReasonToJSON(message.reason);
3505
+ if (message.latencyUs !== 0) obj.latencyUs = Math.round(message.latencyUs);
3506
+ return obj;
3507
+ },
3508
+ create(base) {
3509
+ return RegisterResolveRequest.fromPartial(base ?? {});
3510
+ },
3511
+ fromPartial(object) {
3512
+ const message = createBaseRegisterResolveRequest();
3513
+ message.reason = object.reason ?? 0;
3514
+ message.latencyUs = object.latencyUs ?? 0;
3515
+ return message;
3516
+ }
3517
+ };
3328
3518
  function bytesFromBase64(b64) {
3329
3519
  if (globalThis.Buffer) return Uint8Array.from(globalThis.Buffer.from(b64, "base64"));
3330
3520
  else {
@@ -3352,10 +3542,12 @@ const EXPORT_FN_NAMES = [
3352
3542
  "wasm_msg_alloc",
3353
3543
  "wasm_msg_free",
3354
3544
  "wasm_msg_guest_resolve_flags",
3545
+ "wasm_msg_guest_register_resolve",
3355
3546
  "wasm_msg_guest_set_resolver_state",
3356
3547
  "wasm_msg_guest_bounded_flush_logs",
3357
3548
  "wasm_msg_guest_bounded_flush_assign",
3358
- "wasm_msg_guest_apply_flags"
3549
+ "wasm_msg_guest_apply_flags",
3550
+ "wasm_msg_guest_prometheus_snapshot"
3359
3551
  ];
3360
3552
  function verifyExports(exports) {
3361
3553
  for (const fnName of EXPORT_FN_NAMES) if (typeof exports[fnName] !== "function") throw new Error(`Expected Function export "${fnName}" found ${exports[fnName]}`);
@@ -3382,6 +3574,11 @@ var UnsafeWasmResolver = class {
3382
3574
  const resPtr = this.exports.wasm_msg_guest_resolve_flags(reqPtr);
3383
3575
  return this.consumeResponse(resPtr, ResolveProcessResponse);
3384
3576
  }
3577
+ registerResolve(request) {
3578
+ const reqPtr = this.transferRequest(request, RegisterResolveRequest);
3579
+ const resPtr = this.exports.wasm_msg_guest_register_resolve(reqPtr);
3580
+ this.consumeResponse(resPtr, Void);
3581
+ }
3385
3582
  setResolverState(request) {
3386
3583
  const reqPtr = this.transferRequest(request, SetResolverStateRequest);
3387
3584
  const resPtr = this.exports.wasm_msg_guest_set_resolver_state(reqPtr);
@@ -3404,6 +3601,11 @@ var UnsafeWasmResolver = class {
3404
3601
  const resPtr = this.exports.wasm_msg_guest_apply_flags(reqPtr);
3405
3602
  this.consumeResponse(resPtr, Void);
3406
3603
  }
3604
+ prometheusSnapshot(instance) {
3605
+ const reqPtr = this.transferRequest({ instance }, PrometheusSnapshotRequest);
3606
+ const resPtr = this.exports.wasm_msg_guest_prometheus_snapshot(reqPtr);
3607
+ return this.consumeResponse(resPtr, PrometheusSnapshotResponse).text;
3608
+ }
3407
3609
  transferRequest(value, codec) {
3408
3610
  const data = codec.encode(value).finish();
3409
3611
  return this.transfer({ data }, Request);
@@ -3461,6 +3663,11 @@ var WasmResolver = class {
3461
3663
  throw error$1;
3462
3664
  }
3463
3665
  }
3666
+ registerResolve(request) {
3667
+ try {
3668
+ this.delegate.registerResolve(request);
3669
+ } catch {}
3670
+ }
3464
3671
  setResolverState(request) {
3465
3672
  this.currentState = request;
3466
3673
  try {
@@ -3498,6 +3705,14 @@ var WasmResolver = class {
3498
3705
  throw error$1;
3499
3706
  }
3500
3707
  }
3708
+ prometheusSnapshot(instance) {
3709
+ try {
3710
+ return this.delegate.prometheusSnapshot(instance);
3711
+ } catch (error$1) {
3712
+ logger.error("prometheus snapshot failed:", error$1);
3713
+ return "";
3714
+ }
3715
+ }
3501
3716
  };
3502
3717
  let resolver = null;
3503
3718
  function createConfidenceServerProvider({ wasmUrl,...options }) {
@@ -82,6 +82,10 @@ declare enum ResolveReason {
82
82
  RESOLVE_REASON_UNRECOGNIZED_TARGETING_RULE = 7,
83
83
  /** RESOLVE_REASON_MATERIALIZATION_NOT_SUPPORTED - The flag could not be resolved because a rule is using materialization */
84
84
  RESOLVE_REASON_MATERIALIZATION_NOT_SUPPORTED = 8,
85
+ /** RESOLVE_REASON_TYPE_MISMATCH - The resolved value type does not match the type requested by the SDK */
86
+ RESOLVE_REASON_TYPE_MISMATCH = 9,
87
+ /** RESOLVE_REASON_FLAG_NOT_FOUND - The flag was not found in the resolve response */
88
+ RESOLVE_REASON_FLAG_NOT_FOUND = 10,
85
89
  UNRECOGNIZED = -1,
86
90
  }
87
91
  declare enum SdkId {
@@ -273,6 +277,10 @@ interface MaterializationRecord {
273
277
  rule: string;
274
278
  variant: string;
275
279
  }
280
+ interface RegisterResolveRequest {
281
+ reason: ResolveReason;
282
+ latencyUs: number;
283
+ }
276
284
  declare const ResolveProcessRequest: MessageFns$2<ResolveProcessRequest>;
277
285
  declare const ResolveProcessRequest_StaticMaterializations: MessageFns$2<ResolveProcessRequest_StaticMaterializations>;
278
286
  declare const ResolveProcessRequest_Resume: MessageFns$2<ResolveProcessRequest_Resume>;
@@ -280,6 +288,7 @@ declare const ResolveProcessResponse: MessageFns$2<ResolveProcessResponse>;
280
288
  declare const ResolveProcessResponse_Resolved: MessageFns$2<ResolveProcessResponse_Resolved>;
281
289
  declare const ResolveProcessResponse_Suspended: MessageFns$2<ResolveProcessResponse_Suspended>;
282
290
  declare const MaterializationRecord: MessageFns$2<MaterializationRecord>;
291
+ declare const RegisterResolveRequest: MessageFns$2<RegisterResolveRequest>;
283
292
  type Builtin$2 = Date | Function | Uint8Array | string | number | boolean | undefined;
284
293
  type DeepPartial$2<T> = T extends Builtin$2 ? T : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial$2<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial$2<U>> : T extends {} ? { [K in keyof T]?: DeepPartial$2<T[K]> } : Partial<T>;
285
294
  type KeysOfUnion$2<T> = T extends T ? keyof T : never;
@@ -316,10 +325,12 @@ interface MessageFns$1<T> {
316
325
  //#region src/LocalResolver.d.ts
317
326
  interface LocalResolver {
318
327
  resolveProcess(request: ResolveProcessRequest): ResolveProcessResponse;
328
+ registerResolve(request: RegisterResolveRequest): void;
319
329
  setResolverState(request: SetResolverStateRequest): void;
320
330
  flushLogs(): Uint8Array;
321
331
  flushAssigned(): Uint8Array;
322
332
  applyFlags(request: ApplyFlagsRequest): void;
333
+ prometheusSnapshot(instance: string): string;
323
334
  }
324
335
  //#endregion
325
336
  //#region src/proto/confidence/flags/resolver/v1/internal_api.d.ts
@@ -429,7 +440,7 @@ interface MaterializationStore {
429
440
  }
430
441
  //#endregion
431
442
  //#region src/types.d.ts
432
- type ResolutionReason = "ERROR" | "FLAG_ARCHIVED" | "MATCH" | "NO_SEGMENT_MATCH" | "TARGETING_KEY_ERROR" | "NO_TREATMENT_MATCH" | "UNSPECIFIED";
443
+ type ResolutionReason = "ERROR" | "FLAG_ARCHIVED" | "MATCH" | "NO_SEGMENT_MATCH" | "TARGETING_KEY_ERROR" | "NO_TREATMENT_MATCH" | "MATERIALIZATION_NOT_SUPPORTED" | "UNSPECIFIED";
433
444
  declare enum ErrorCode {
434
445
  PROVIDER_NOT_READY = "PROVIDER_NOT_READY",
435
446
  PROVIDER_FATAL = "PROVIDER_FATAL",
@@ -462,6 +473,12 @@ interface FlagBundle {
462
473
  //#endregion
463
474
  //#region src/ConfidenceServerProviderLocal.d.ts
464
475
  type FlagBundle$1 = FlagBundle;
476
+ /**
477
+ * Configuration for {@link ConfidenceServerProviderLocal.getPrometheusMetrics}.
478
+ *
479
+ * @experimental This API is subject to change.
480
+ */
481
+ interface SnapshotConfig {}
465
482
  interface ProviderOptions {
466
483
  flagClientSecret: string;
467
484
  initializeTimeout?: number;
@@ -513,6 +530,12 @@ declare class ConfidenceServerProviderLocal implements Provider {
513
530
  /** Resolves with an evaluation of a String flag */
514
531
  resolveStringEvaluation(flagKey: string, defaultValue: string, context: EvaluationContext): Promise<ResolutionDetails<string>>;
515
532
  /**
533
+ * Returns a Prometheus metrics snapshot from the WASM resolver.
534
+ *
535
+ * @experimental This API is subject to change.
536
+ */
537
+ getPrometheusMetrics(_request?: SnapshotConfig): string;
538
+ /**
516
539
  * Applies a previously resolved flag, logging that it was used/exposed.
517
540
  * Call this when a flag value is actually rendered or used in the client.
518
541
  * @param resolveToken - Base64-encoded resolve token from the flag bundle
@@ -525,4 +548,4 @@ declare class ConfidenceServerProviderLocal implements Provider {
525
548
  type ProviderOptionsExt = ProviderOptions;
526
549
  declare function createConfidenceServerProvider(options: ProviderOptions): ConfidenceServerProviderLocal;
527
550
  //#endregion
528
- export { type MaterializationStore, ProviderOptionsExt, createConfidenceServerProvider };
551
+ export { type MaterializationStore, ProviderOptionsExt, type SnapshotConfig, createConfidenceServerProvider };