@grafana-experiments/sdk 0.0.0 → 0.1.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.
@@ -0,0 +1,35 @@
1
+ import { E as ExperimentsOptions, e as Experiments, f as EventDefinition, R as ReportOptions, A as Assignment, M as MeasurementContext } from './types-M9Kqiiqw.cjs';
2
+ export { g as AllocationUnit, h as AnalyticsReporter, i as AssignmentMetadata, D as Diagnostic, d as EventManifest, c as Experiment, a as ExperimentConfig, b as ExperimentDefinition, j as ExperimentState, F as FaroEventType, J as Journey, P as Properties, V as Variant } from './types-M9Kqiiqw.cjs';
3
+ import { BrowserConfig } from '@grafana/faro-web-sdk';
4
+ import { TrackingEventDetails } from '@openfeature/web-sdk';
5
+
6
+ declare function createExperiments(options: ExperimentsOptions): Experiments;
7
+
8
+ declare function defineEvent<const T extends EventDefinition>(definition: T): T;
9
+ type Value<T> = T extends {
10
+ type: 'number';
11
+ } ? number : T extends {
12
+ type: 'boolean';
13
+ } ? boolean : string;
14
+ type EventProperties<T extends EventDefinition> = {
15
+ [K in keyof T['properties'] as T['properties'][K] extends {
16
+ required: true;
17
+ } ? K : never]: Value<T['properties'][K]>;
18
+ } & {
19
+ [K in keyof T['properties'] as T['properties'][K] extends {
20
+ required: true;
21
+ } ? never : K]?: Value<T['properties'][K]>;
22
+ };
23
+ declare function createTypedReporter<T extends Record<string, EventDefinition>>(sdk: Experiments, definitions: T): <K extends keyof T & string>(name: K, properties: EventProperties<T[K]>, options?: ReportOptions) => void;
24
+
25
+ /** Install before Faro initialization; bind getAssignments to the SDK when it exists. */
26
+ declare function createExperimentEnricher(options: {
27
+ getAssignments: () => readonly Assignment[];
28
+ isEnabled?: () => boolean;
29
+ beforeSend?: BrowserConfig['beforeSend'];
30
+ }): NonNullable<BrowserConfig['beforeSend']>;
31
+
32
+ /** Explicitly opt in to sharing captured attribution with the flag provider. */
33
+ declare function toOpenFeatureTrackingDetails(context: MeasurementContext): TrackingEventDetails;
34
+
35
+ export { Assignment, EventDefinition, Experiments, ExperimentsOptions, MeasurementContext, ReportOptions, createExperimentEnricher, createExperiments, createTypedReporter, defineEvent, toOpenFeatureTrackingDetails };
@@ -0,0 +1,35 @@
1
+ import { E as ExperimentsOptions, e as Experiments, f as EventDefinition, R as ReportOptions, A as Assignment, M as MeasurementContext } from './types-M9Kqiiqw.js';
2
+ export { g as AllocationUnit, h as AnalyticsReporter, i as AssignmentMetadata, D as Diagnostic, d as EventManifest, c as Experiment, a as ExperimentConfig, b as ExperimentDefinition, j as ExperimentState, F as FaroEventType, J as Journey, P as Properties, V as Variant } from './types-M9Kqiiqw.js';
3
+ import { BrowserConfig } from '@grafana/faro-web-sdk';
4
+ import { TrackingEventDetails } from '@openfeature/web-sdk';
5
+
6
+ declare function createExperiments(options: ExperimentsOptions): Experiments;
7
+
8
+ declare function defineEvent<const T extends EventDefinition>(definition: T): T;
9
+ type Value<T> = T extends {
10
+ type: 'number';
11
+ } ? number : T extends {
12
+ type: 'boolean';
13
+ } ? boolean : string;
14
+ type EventProperties<T extends EventDefinition> = {
15
+ [K in keyof T['properties'] as T['properties'][K] extends {
16
+ required: true;
17
+ } ? K : never]: Value<T['properties'][K]>;
18
+ } & {
19
+ [K in keyof T['properties'] as T['properties'][K] extends {
20
+ required: true;
21
+ } ? never : K]?: Value<T['properties'][K]>;
22
+ };
23
+ declare function createTypedReporter<T extends Record<string, EventDefinition>>(sdk: Experiments, definitions: T): <K extends keyof T & string>(name: K, properties: EventProperties<T[K]>, options?: ReportOptions) => void;
24
+
25
+ /** Install before Faro initialization; bind getAssignments to the SDK when it exists. */
26
+ declare function createExperimentEnricher(options: {
27
+ getAssignments: () => readonly Assignment[];
28
+ isEnabled?: () => boolean;
29
+ beforeSend?: BrowserConfig['beforeSend'];
30
+ }): NonNullable<BrowserConfig['beforeSend']>;
31
+
32
+ /** Explicitly opt in to sharing captured attribution with the flag provider. */
33
+ declare function toOpenFeatureTrackingDetails(context: MeasurementContext): TrackingEventDetails;
34
+
35
+ export { Assignment, EventDefinition, Experiments, ExperimentsOptions, MeasurementContext, ReportOptions, createExperimentEnricher, createExperiments, createTypedReporter, defineEvent, toOpenFeatureTrackingDetails };
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ import {
2
+ createExperimentEnricher,
3
+ createExperiments,
4
+ createTypedReporter,
5
+ defineEvent
6
+ } from "./chunk-W7444I4G.js";
7
+
8
+ // src/tracking.ts
9
+ function toOpenFeatureTrackingDetails(context) {
10
+ return {
11
+ event_id: context.event_id,
12
+ telemetry_schema_version: context.telemetry_schema_version,
13
+ experiments: context.experiments.map(
14
+ (assignment) => Object.fromEntries(Object.entries(assignment).filter(([, value]) => value !== void 0))
15
+ ),
16
+ ...context.event_schema_version !== void 0 ? { event_schema_version: context.event_schema_version } : {},
17
+ ...context.journey_id !== void 0 ? { journey_id: context.journey_id } : {}
18
+ };
19
+ }
20
+ export {
21
+ createExperimentEnricher,
22
+ createExperiments,
23
+ createTypedReporter,
24
+ defineEvent,
25
+ toOpenFeatureTrackingDetails
26
+ };
package/dist/react.cjs ADDED
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/react.tsx
21
+ var react_exports = {};
22
+ __export(react_exports, {
23
+ ExperimentsProvider: () => ExperimentsProvider,
24
+ useExperiment: () => useExperiment,
25
+ useExperiments: () => useExperiments
26
+ });
27
+ module.exports = __toCommonJS(react_exports);
28
+ var import_react = require("react");
29
+ var import_jsx_runtime = require("react/jsx-runtime");
30
+ var Context = (0, import_react.createContext)(null);
31
+ var serverSnapshot = () => ({ status: "inactive" });
32
+ var INACTIVE = serverSnapshot();
33
+ function ExperimentsProvider({
34
+ experiments,
35
+ children
36
+ }) {
37
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Context.Provider, { value: experiments, children });
38
+ }
39
+ function useExperiments() {
40
+ const experiments = (0, import_react.useContext)(Context);
41
+ if (!experiments) {
42
+ throw new Error("useExperiments requires ExperimentsProvider");
43
+ }
44
+ return experiments;
45
+ }
46
+ function useExperiment(experiment, eligible = true, entryId) {
47
+ const state = (0, import_react.useSyncExternalStore)(experiment.subscribe, experiment.getSnapshot, () => INACTIVE);
48
+ (0, import_react.useEffect)(() => {
49
+ if (!eligible) {
50
+ return;
51
+ }
52
+ const controller = new AbortController();
53
+ void experiment.activate({ signal: controller.signal, entryId });
54
+ return () => controller.abort();
55
+ }, [experiment, eligible, entryId, state.status === "inactive"]);
56
+ return state;
57
+ }
58
+ // Annotate the CommonJS export names for ESM import in node:
59
+ 0 && (module.exports = {
60
+ ExperimentsProvider,
61
+ useExperiment,
62
+ useExperiments
63
+ });
@@ -0,0 +1,14 @@
1
+ import { e as Experiments, a as ExperimentConfig, c as Experiment, j as ExperimentState } from './types-M9Kqiiqw.cjs';
2
+ import * as react from 'react';
3
+ import { ReactNode } from 'react';
4
+ import '@grafana/faro-web-sdk';
5
+ import '@openfeature/web-sdk';
6
+
7
+ declare function ExperimentsProvider({ experiments, children, }: {
8
+ experiments: Experiments;
9
+ children: ReactNode;
10
+ }): react.JSX.Element;
11
+ declare function useExperiments(): Experiments;
12
+ declare function useExperiment<T extends ExperimentConfig>(experiment: Experiment<T>, eligible?: boolean, entryId?: string): ExperimentState<T>;
13
+
14
+ export { ExperimentsProvider, useExperiment, useExperiments };
@@ -0,0 +1,14 @@
1
+ import { e as Experiments, a as ExperimentConfig, c as Experiment, j as ExperimentState } from './types-M9Kqiiqw.js';
2
+ import * as react from 'react';
3
+ import { ReactNode } from 'react';
4
+ import '@grafana/faro-web-sdk';
5
+ import '@openfeature/web-sdk';
6
+
7
+ declare function ExperimentsProvider({ experiments, children, }: {
8
+ experiments: Experiments;
9
+ children: ReactNode;
10
+ }): react.JSX.Element;
11
+ declare function useExperiments(): Experiments;
12
+ declare function useExperiment<T extends ExperimentConfig>(experiment: Experiment<T>, eligible?: boolean, entryId?: string): ExperimentState<T>;
13
+
14
+ export { ExperimentsProvider, useExperiment, useExperiments };
package/dist/react.js ADDED
@@ -0,0 +1,36 @@
1
+ // src/react.tsx
2
+ import { createContext, useContext, useEffect, useSyncExternalStore } from "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+ var Context = createContext(null);
5
+ var serverSnapshot = () => ({ status: "inactive" });
6
+ var INACTIVE = serverSnapshot();
7
+ function ExperimentsProvider({
8
+ experiments,
9
+ children
10
+ }) {
11
+ return /* @__PURE__ */ jsx(Context.Provider, { value: experiments, children });
12
+ }
13
+ function useExperiments() {
14
+ const experiments = useContext(Context);
15
+ if (!experiments) {
16
+ throw new Error("useExperiments requires ExperimentsProvider");
17
+ }
18
+ return experiments;
19
+ }
20
+ function useExperiment(experiment, eligible = true, entryId) {
21
+ const state = useSyncExternalStore(experiment.subscribe, experiment.getSnapshot, () => INACTIVE);
22
+ useEffect(() => {
23
+ if (!eligible) {
24
+ return;
25
+ }
26
+ const controller = new AbortController();
27
+ void experiment.activate({ signal: controller.signal, entryId });
28
+ return () => controller.abort();
29
+ }, [experiment, eligible, entryId, state.status === "inactive"]);
30
+ return state;
31
+ }
32
+ export {
33
+ ExperimentsProvider,
34
+ useExperiment,
35
+ useExperiments
36
+ };
@@ -0,0 +1,171 @@
1
+ import { Faro, BrowserConfig } from '@grafana/faro-web-sdk';
2
+ import { Client, TrackingEventDetails } from '@openfeature/web-sdk';
3
+
4
+ type Variant = 'control' | 'treatment' | 'excluded';
5
+ type Properties = Record<string, unknown>;
6
+ type AnalyticsReporter = (name: string, properties: Properties) => void | Promise<void>;
7
+ type FaroEventType = 'custom-event' | 'user-action';
8
+ interface ReportOptions {
9
+ faro?: {
10
+ type: FaroEventType;
11
+ };
12
+ }
13
+ interface ExperimentConfig {
14
+ variant: Variant;
15
+ }
16
+ interface ExperimentDefinition<T extends ExperimentConfig = ExperimentConfig> {
17
+ id: string;
18
+ flagKey: string;
19
+ group?: string;
20
+ metadata?: AssignmentMetadata;
21
+ mapAssignment?: (evaluation: {
22
+ value: unknown;
23
+ variant?: string;
24
+ flagMetadata?: Record<string, unknown>;
25
+ reason?: string;
26
+ }) => AssignmentMetadata;
27
+ flag: {
28
+ type: 'boolean';
29
+ } | {
30
+ type: 'object';
31
+ validate: (value: unknown) => value is T;
32
+ };
33
+ }
34
+ interface Assignment {
35
+ experiment_id: string;
36
+ experiment_revision?: string;
37
+ allocation_unit_type?: AllocationUnit['type'];
38
+ allocation_unit_id?: string;
39
+ assignment_source?: 'provider' | 'host' | 'unknown';
40
+ population?: AssignmentMetadata['population'];
41
+ activated_at?: string;
42
+ experiment_group: string;
43
+ flag_key: string;
44
+ variant: 'control' | 'treatment';
45
+ session_id: string;
46
+ exposure_id: string;
47
+ }
48
+ type ExperimentState<T extends ExperimentConfig = ExperimentConfig> = {
49
+ status: 'inactive';
50
+ } | {
51
+ status: 'unavailable';
52
+ reason: 'disabled' | 'no-session' | 'provider' | 'evaluation' | 'invalid-value' | 'disposed';
53
+ } | {
54
+ status: 'excluded';
55
+ variant: 'excluded';
56
+ config?: Readonly<T>;
57
+ } | {
58
+ status: 'active';
59
+ variant: 'control' | 'treatment';
60
+ assignment: Readonly<Assignment>;
61
+ config?: Readonly<T>;
62
+ };
63
+ interface Experiment<T extends ExperimentConfig = ExperimentConfig> {
64
+ readonly id: string;
65
+ activate: (options?: {
66
+ signal?: AbortSignal;
67
+ entryId?: string;
68
+ }) => Promise<ExperimentState<T>>;
69
+ getSnapshot: () => ExperimentState<T>;
70
+ subscribe: (listener: () => void) => () => void;
71
+ }
72
+ /** Attribution captured once for an outcome, independent of destination serialization. */
73
+ interface MeasurementContext {
74
+ readonly event_id: string;
75
+ readonly experiments: readonly Readonly<Assignment>[];
76
+ readonly telemetry_schema_version: 2;
77
+ readonly event_schema_version?: number;
78
+ readonly journey_id?: string;
79
+ }
80
+ interface ExperimentsOptions {
81
+ /** Stable application identifier; namespaces session storage and exposure identities. */
82
+ scope: string;
83
+ client: Client;
84
+ /** Optional existing analytics destination. Omit for Faro-only reporting. */
85
+ reportAnalytics?: AnalyticsReporter;
86
+ faro: {
87
+ instance: Faro;
88
+ config?: never;
89
+ } | {
90
+ config: BrowserConfig;
91
+ instance?: never;
92
+ };
93
+ getSessionId?: () => string | undefined;
94
+ contextKey?: string;
95
+ /** Gate both destinations and activation; the host owns consent. */
96
+ isEnabled?: () => boolean;
97
+ events?: Record<string, FaroEventType>;
98
+ eventDefinitions?: Record<string, EventDefinition>;
99
+ onDiagnostic?: (diagnostic: Diagnostic) => void;
100
+ enrichFaro?: boolean;
101
+ transformFaroProperties?: (name: string, properties: Properties) => Properties | null;
102
+ reportExposure?: (assignment: Readonly<Assignment>) => void | Promise<void>;
103
+ /**
104
+ * Opt-in: also send outcome events to the OpenFeature Tracking API, for providers that attribute goals themselves. Return the details to send, or
105
+ * null to skip. Receives isolated original properties and captured attribution; return only fields to share. Providers without `track` no-op.
106
+ */
107
+ openFeatureTracking?: (name: string, properties: Properties, context: MeasurementContext) => TrackingEventDetails | null | undefined;
108
+ /**
109
+ * Record `feature_flag.result.value` on exposures when the provider supplies no variant, as the
110
+ * OpenTelemetry convention requires. Disable when flag values are sensitive or large. Default true.
111
+ */
112
+ recordFlagValue?: boolean;
113
+ onError?: (error: unknown) => void;
114
+ readinessTimeoutMs?: number;
115
+ storage?: Pick<Storage, 'getItem' | 'setItem' | 'removeItem'> | null;
116
+ }
117
+ interface Experiments {
118
+ readonly ready: Promise<void>;
119
+ defineExperiment: <T extends ExperimentConfig = ExperimentConfig>(definition: ExperimentDefinition<T>) => Experiment<T>;
120
+ reportAnalytics: (name: string, properties?: Properties, options?: ReportOptions) => void;
121
+ /** Call when a host-provided session ID or consent changes. Faro session changes are observed automatically. */
122
+ refreshSession: () => void;
123
+ /** Supply a stable, non-secret identity/tenant context key before activating in a new context. */
124
+ resetContext: (contextKey: string) => void;
125
+ beginJourney: () => Journey;
126
+ getEventManifest: () => EventManifest;
127
+ getDiagnostics: () => readonly Diagnostic[];
128
+ subscribeDiagnostics: (listener: (diagnostic: Diagnostic) => void) => () => void;
129
+ /** Attribution snapshot for an opt-in Faro enrichment hook. Never activates experiments. */
130
+ getActiveAssignments: () => readonly Assignment[];
131
+ dispose: () => void;
132
+ }
133
+ interface AllocationUnit {
134
+ type: 'stack' | 'organization' | 'user' | 'session';
135
+ id: string;
136
+ }
137
+ interface AssignmentMetadata {
138
+ revision?: string;
139
+ allocationUnit?: AllocationUnit;
140
+ population?: 'randomized' | 'test' | 'targeted';
141
+ }
142
+ interface Diagnostic {
143
+ sequence: number;
144
+ timestamp: string;
145
+ code: string;
146
+ experimentId?: string;
147
+ eventName?: string;
148
+ detail?: string;
149
+ }
150
+ type PropertyType = 'string' | 'number' | 'boolean';
151
+ interface EventDefinition {
152
+ version: number;
153
+ description?: string;
154
+ properties: Record<string, {
155
+ type: PropertyType;
156
+ required?: boolean;
157
+ }>;
158
+ }
159
+ interface EventManifest {
160
+ schemaVersion: 2;
161
+ scope: string;
162
+ events: Record<string, EventDefinition>;
163
+ }
164
+ interface Journey {
165
+ readonly id: string;
166
+ getTelemetryContext: () => Record<string, string>;
167
+ reportAnalytics(name: string, properties?: Properties, options?: ReportOptions): void;
168
+ end(): void;
169
+ }
170
+
171
+ export type { Assignment as A, Diagnostic as D, ExperimentsOptions as E, FaroEventType as F, Journey as J, MeasurementContext as M, Properties as P, ReportOptions as R, Variant as V, ExperimentConfig as a, ExperimentDefinition as b, Experiment as c, EventManifest as d, Experiments as e, EventDefinition as f, AllocationUnit as g, AnalyticsReporter as h, AssignmentMetadata as i, ExperimentState as j };
@@ -0,0 +1,171 @@
1
+ import { Faro, BrowserConfig } from '@grafana/faro-web-sdk';
2
+ import { Client, TrackingEventDetails } from '@openfeature/web-sdk';
3
+
4
+ type Variant = 'control' | 'treatment' | 'excluded';
5
+ type Properties = Record<string, unknown>;
6
+ type AnalyticsReporter = (name: string, properties: Properties) => void | Promise<void>;
7
+ type FaroEventType = 'custom-event' | 'user-action';
8
+ interface ReportOptions {
9
+ faro?: {
10
+ type: FaroEventType;
11
+ };
12
+ }
13
+ interface ExperimentConfig {
14
+ variant: Variant;
15
+ }
16
+ interface ExperimentDefinition<T extends ExperimentConfig = ExperimentConfig> {
17
+ id: string;
18
+ flagKey: string;
19
+ group?: string;
20
+ metadata?: AssignmentMetadata;
21
+ mapAssignment?: (evaluation: {
22
+ value: unknown;
23
+ variant?: string;
24
+ flagMetadata?: Record<string, unknown>;
25
+ reason?: string;
26
+ }) => AssignmentMetadata;
27
+ flag: {
28
+ type: 'boolean';
29
+ } | {
30
+ type: 'object';
31
+ validate: (value: unknown) => value is T;
32
+ };
33
+ }
34
+ interface Assignment {
35
+ experiment_id: string;
36
+ experiment_revision?: string;
37
+ allocation_unit_type?: AllocationUnit['type'];
38
+ allocation_unit_id?: string;
39
+ assignment_source?: 'provider' | 'host' | 'unknown';
40
+ population?: AssignmentMetadata['population'];
41
+ activated_at?: string;
42
+ experiment_group: string;
43
+ flag_key: string;
44
+ variant: 'control' | 'treatment';
45
+ session_id: string;
46
+ exposure_id: string;
47
+ }
48
+ type ExperimentState<T extends ExperimentConfig = ExperimentConfig> = {
49
+ status: 'inactive';
50
+ } | {
51
+ status: 'unavailable';
52
+ reason: 'disabled' | 'no-session' | 'provider' | 'evaluation' | 'invalid-value' | 'disposed';
53
+ } | {
54
+ status: 'excluded';
55
+ variant: 'excluded';
56
+ config?: Readonly<T>;
57
+ } | {
58
+ status: 'active';
59
+ variant: 'control' | 'treatment';
60
+ assignment: Readonly<Assignment>;
61
+ config?: Readonly<T>;
62
+ };
63
+ interface Experiment<T extends ExperimentConfig = ExperimentConfig> {
64
+ readonly id: string;
65
+ activate: (options?: {
66
+ signal?: AbortSignal;
67
+ entryId?: string;
68
+ }) => Promise<ExperimentState<T>>;
69
+ getSnapshot: () => ExperimentState<T>;
70
+ subscribe: (listener: () => void) => () => void;
71
+ }
72
+ /** Attribution captured once for an outcome, independent of destination serialization. */
73
+ interface MeasurementContext {
74
+ readonly event_id: string;
75
+ readonly experiments: readonly Readonly<Assignment>[];
76
+ readonly telemetry_schema_version: 2;
77
+ readonly event_schema_version?: number;
78
+ readonly journey_id?: string;
79
+ }
80
+ interface ExperimentsOptions {
81
+ /** Stable application identifier; namespaces session storage and exposure identities. */
82
+ scope: string;
83
+ client: Client;
84
+ /** Optional existing analytics destination. Omit for Faro-only reporting. */
85
+ reportAnalytics?: AnalyticsReporter;
86
+ faro: {
87
+ instance: Faro;
88
+ config?: never;
89
+ } | {
90
+ config: BrowserConfig;
91
+ instance?: never;
92
+ };
93
+ getSessionId?: () => string | undefined;
94
+ contextKey?: string;
95
+ /** Gate both destinations and activation; the host owns consent. */
96
+ isEnabled?: () => boolean;
97
+ events?: Record<string, FaroEventType>;
98
+ eventDefinitions?: Record<string, EventDefinition>;
99
+ onDiagnostic?: (diagnostic: Diagnostic) => void;
100
+ enrichFaro?: boolean;
101
+ transformFaroProperties?: (name: string, properties: Properties) => Properties | null;
102
+ reportExposure?: (assignment: Readonly<Assignment>) => void | Promise<void>;
103
+ /**
104
+ * Opt-in: also send outcome events to the OpenFeature Tracking API, for providers that attribute goals themselves. Return the details to send, or
105
+ * null to skip. Receives isolated original properties and captured attribution; return only fields to share. Providers without `track` no-op.
106
+ */
107
+ openFeatureTracking?: (name: string, properties: Properties, context: MeasurementContext) => TrackingEventDetails | null | undefined;
108
+ /**
109
+ * Record `feature_flag.result.value` on exposures when the provider supplies no variant, as the
110
+ * OpenTelemetry convention requires. Disable when flag values are sensitive or large. Default true.
111
+ */
112
+ recordFlagValue?: boolean;
113
+ onError?: (error: unknown) => void;
114
+ readinessTimeoutMs?: number;
115
+ storage?: Pick<Storage, 'getItem' | 'setItem' | 'removeItem'> | null;
116
+ }
117
+ interface Experiments {
118
+ readonly ready: Promise<void>;
119
+ defineExperiment: <T extends ExperimentConfig = ExperimentConfig>(definition: ExperimentDefinition<T>) => Experiment<T>;
120
+ reportAnalytics: (name: string, properties?: Properties, options?: ReportOptions) => void;
121
+ /** Call when a host-provided session ID or consent changes. Faro session changes are observed automatically. */
122
+ refreshSession: () => void;
123
+ /** Supply a stable, non-secret identity/tenant context key before activating in a new context. */
124
+ resetContext: (contextKey: string) => void;
125
+ beginJourney: () => Journey;
126
+ getEventManifest: () => EventManifest;
127
+ getDiagnostics: () => readonly Diagnostic[];
128
+ subscribeDiagnostics: (listener: (diagnostic: Diagnostic) => void) => () => void;
129
+ /** Attribution snapshot for an opt-in Faro enrichment hook. Never activates experiments. */
130
+ getActiveAssignments: () => readonly Assignment[];
131
+ dispose: () => void;
132
+ }
133
+ interface AllocationUnit {
134
+ type: 'stack' | 'organization' | 'user' | 'session';
135
+ id: string;
136
+ }
137
+ interface AssignmentMetadata {
138
+ revision?: string;
139
+ allocationUnit?: AllocationUnit;
140
+ population?: 'randomized' | 'test' | 'targeted';
141
+ }
142
+ interface Diagnostic {
143
+ sequence: number;
144
+ timestamp: string;
145
+ code: string;
146
+ experimentId?: string;
147
+ eventName?: string;
148
+ detail?: string;
149
+ }
150
+ type PropertyType = 'string' | 'number' | 'boolean';
151
+ interface EventDefinition {
152
+ version: number;
153
+ description?: string;
154
+ properties: Record<string, {
155
+ type: PropertyType;
156
+ required?: boolean;
157
+ }>;
158
+ }
159
+ interface EventManifest {
160
+ schemaVersion: 2;
161
+ scope: string;
162
+ events: Record<string, EventDefinition>;
163
+ }
164
+ interface Journey {
165
+ readonly id: string;
166
+ getTelemetryContext: () => Record<string, string>;
167
+ reportAnalytics(name: string, properties?: Properties, options?: ReportOptions): void;
168
+ end(): void;
169
+ }
170
+
171
+ export type { Assignment as A, Diagnostic as D, ExperimentsOptions as E, FaroEventType as F, Journey as J, MeasurementContext as M, Properties as P, ReportOptions as R, Variant as V, ExperimentConfig as a, ExperimentDefinition as b, Experiment as c, EventManifest as d, Experiments as e, EventDefinition as f, AllocationUnit as g, AnalyticsReporter as h, AssignmentMetadata as i, ExperimentState as j };
package/package.json CHANGED
@@ -1 +1,73 @@
1
- {"name":"@grafana-experiments/sdk","version":"0.0.0","license":"Apache-2.0","description":"Bootstrap placeholder for trusted publishing; use a later release."}
1
+ {
2
+ "name": "@grafana-experiments/sdk",
3
+ "version": "0.1.0",
4
+ "description": "Explicit experiment activation and analytics reporting with OpenFeature and Grafana Faro",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "files": [
9
+ "dist",
10
+ "README.md",
11
+ "LICENSE",
12
+ "RELEASING.md"
13
+ ],
14
+ "exports": {
15
+ ".": {
16
+ "import": {
17
+ "types": "./dist/index.d.ts",
18
+ "default": "./dist/index.js"
19
+ },
20
+ "require": {
21
+ "types": "./dist/index.d.cts",
22
+ "default": "./dist/index.cjs"
23
+ }
24
+ },
25
+ "./grafana": {
26
+ "import": {
27
+ "types": "./dist/grafana.d.ts",
28
+ "default": "./dist/grafana.js"
29
+ },
30
+ "require": {
31
+ "types": "./dist/grafana.d.cts",
32
+ "default": "./dist/grafana.cjs"
33
+ }
34
+ },
35
+ "./react": {
36
+ "import": {
37
+ "types": "./dist/react.d.ts",
38
+ "default": "./dist/react.js"
39
+ },
40
+ "require": {
41
+ "types": "./dist/react.d.cts",
42
+ "default": "./dist/react.cjs"
43
+ }
44
+ }
45
+ },
46
+ "engines": {
47
+ "node": ">=22"
48
+ },
49
+ "peerDependencies": {
50
+ "@grafana/faro-web-sdk": ">=2.12.0 <2.13.0",
51
+ "@grafana/runtime": ">=13.2.2 <14",
52
+ "@openfeature/web-sdk": ">=1.9.0 <2",
53
+ "react": "^18.3.0 || ^19.0.0"
54
+ },
55
+ "peerDependenciesMeta": {
56
+ "@grafana/runtime": {
57
+ "optional": true
58
+ },
59
+ "react": {
60
+ "optional": true
61
+ }
62
+ },
63
+ "publishConfig": {
64
+ "access": "public",
65
+ "registry": "https://registry.npmjs.org"
66
+ },
67
+ "repository": {
68
+ "type": "git",
69
+ "url": "git+https://github.com/grafana/grafana-experiments-app.git",
70
+ "directory": "packages/grafana-experiments"
71
+ },
72
+ "gitHead": "ba9348e954f7dc3beddba187e56916139bb76790"
73
+ }