@ops-ai/react-router-toggly 1.2.1 → 1.5.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 +33 -0
- package/dist/client.cjs +106 -14
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +5 -2
- package/dist/client.d.ts +5 -2
- package/dist/client.js +108 -16
- package/dist/client.js.map +1 -1
- package/dist/server.cjs +50 -4
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +1 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +42 -4
- package/dist/server.js.map +1 -1
- package/dist/telemetry/grpc.cjs +1 -1
- package/dist/telemetry/grpc.cjs.map +1 -1
- package/dist/telemetry/grpc.js +1 -1
- package/dist/telemetry/grpc.js.map +1 -1
- package/package.json +4 -3
- package/proto/usage.proto +3 -0
package/dist/client.d.cts
CHANGED
|
@@ -3,6 +3,8 @@ import { EvaluatedDefinitions, TogglyEntityContext } from '@ops-ai/toggly-hooks-
|
|
|
3
3
|
export { TogglyEntityContext, normalizeEntityContext, registerContext } from '@ops-ai/toggly-hooks-types';
|
|
4
4
|
import * as react from 'react';
|
|
5
5
|
import { ReactNode, ReactElement } from 'react';
|
|
6
|
+
import { FeatureUsageScope } from '@ops-ai/toggly-client-telemetry';
|
|
7
|
+
export { FeatureUsageScope } from '@ops-ai/toggly-client-telemetry';
|
|
6
8
|
|
|
7
9
|
interface UsageSender {
|
|
8
10
|
sendStats(request: Record<string, unknown>): Promise<unknown>;
|
|
@@ -267,6 +269,7 @@ declare const TOGGLY_LOADER_KEY: "__toggly";
|
|
|
267
269
|
|
|
268
270
|
interface FrontendTelemetry {
|
|
269
271
|
recordUsage(featureKey: string, variant?: string): void;
|
|
272
|
+
use: <T>(featureKey: string, fn: (scope: FeatureUsageScope) => Promise<T>, variant?: string) => Promise<T>;
|
|
270
273
|
recordView(featureKey: string, variant?: string): void;
|
|
271
274
|
incrementCounter(metricKey: string, value?: number): void;
|
|
272
275
|
setGauge(metricKey: string, value: number): void;
|
|
@@ -569,8 +572,8 @@ declare function FeatureGate({ featureKeys, requirement, negate, children, conte
|
|
|
569
572
|
/**
|
|
570
573
|
* React Router-specific utilities for Toggly
|
|
571
574
|
*/
|
|
572
|
-
type SerializeFrom<T> = T;
|
|
573
575
|
|
|
576
|
+
type SerializeFrom<T> = T;
|
|
574
577
|
/**
|
|
575
578
|
* Props for RouterTogglyProvider
|
|
576
579
|
*/
|
|
@@ -593,7 +596,7 @@ interface RouterTogglyProviderProps extends Omit<TogglyProviderProps, 'serverCon
|
|
|
593
596
|
* );
|
|
594
597
|
* }
|
|
595
598
|
*/
|
|
596
|
-
declare function RouterTogglyProvider({ children, routeId, fallbackContext, config, ...props }: RouterTogglyProviderProps): ReactElement;
|
|
599
|
+
declare function RouterTogglyProvider({ children, routeId, fallbackContext, config, ...props }: Readonly<RouterTogglyProviderProps>): ReactElement;
|
|
597
600
|
/**
|
|
598
601
|
* Hook to get Toggly context from loader data
|
|
599
602
|
*/
|
package/dist/client.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { EvaluatedDefinitions, TogglyEntityContext } from '@ops-ai/toggly-hooks-
|
|
|
3
3
|
export { TogglyEntityContext, normalizeEntityContext, registerContext } from '@ops-ai/toggly-hooks-types';
|
|
4
4
|
import * as react from 'react';
|
|
5
5
|
import { ReactNode, ReactElement } from 'react';
|
|
6
|
+
import { FeatureUsageScope } from '@ops-ai/toggly-client-telemetry';
|
|
7
|
+
export { FeatureUsageScope } from '@ops-ai/toggly-client-telemetry';
|
|
6
8
|
|
|
7
9
|
interface UsageSender {
|
|
8
10
|
sendStats(request: Record<string, unknown>): Promise<unknown>;
|
|
@@ -267,6 +269,7 @@ declare const TOGGLY_LOADER_KEY: "__toggly";
|
|
|
267
269
|
|
|
268
270
|
interface FrontendTelemetry {
|
|
269
271
|
recordUsage(featureKey: string, variant?: string): void;
|
|
272
|
+
use: <T>(featureKey: string, fn: (scope: FeatureUsageScope) => Promise<T>, variant?: string) => Promise<T>;
|
|
270
273
|
recordView(featureKey: string, variant?: string): void;
|
|
271
274
|
incrementCounter(metricKey: string, value?: number): void;
|
|
272
275
|
setGauge(metricKey: string, value: number): void;
|
|
@@ -569,8 +572,8 @@ declare function FeatureGate({ featureKeys, requirement, negate, children, conte
|
|
|
569
572
|
/**
|
|
570
573
|
* React Router-specific utilities for Toggly
|
|
571
574
|
*/
|
|
572
|
-
type SerializeFrom<T> = T;
|
|
573
575
|
|
|
576
|
+
type SerializeFrom<T> = T;
|
|
574
577
|
/**
|
|
575
578
|
* Props for RouterTogglyProvider
|
|
576
579
|
*/
|
|
@@ -593,7 +596,7 @@ interface RouterTogglyProviderProps extends Omit<TogglyProviderProps, 'serverCon
|
|
|
593
596
|
* );
|
|
594
597
|
* }
|
|
595
598
|
*/
|
|
596
|
-
declare function RouterTogglyProvider({ children, routeId, fallbackContext, config, ...props }: RouterTogglyProviderProps): ReactElement;
|
|
599
|
+
declare function RouterTogglyProvider({ children, routeId, fallbackContext, config, ...props }: Readonly<RouterTogglyProviderProps>): ReactElement;
|
|
597
600
|
/**
|
|
598
601
|
* Hook to get Toggly context from loader data
|
|
599
602
|
*/
|
package/dist/client.js
CHANGED
|
@@ -3,11 +3,11 @@ export { normalizeEntityContext, registerContext } from '@ops-ai/toggly-hooks-ty
|
|
|
3
3
|
import '@ops-ai/toggly-eval';
|
|
4
4
|
import { asVariantDefsRecord, unwrapDefsPayload } from '@ops-ai/toggly-signed-defs';
|
|
5
5
|
import { createContext, useRef, useMemo, useState, useEffect, useCallback, useContext, useLayoutEffect } from 'react';
|
|
6
|
-
import { createTelemetryReporter } from '@ops-ai/toggly-client-telemetry';
|
|
6
|
+
import { runFeatureUsageScope, createTelemetryReporter } from '@ops-ai/toggly-client-telemetry';
|
|
7
7
|
import { attachBrowserLifecycle } from '@ops-ai/toggly-client-telemetry/browser';
|
|
8
8
|
import { buildFlagGateIndex, applyLocalGate } from '@ops-ai/toggly-local-gates';
|
|
9
9
|
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
10
|
-
import {
|
|
10
|
+
import { useInRouterContext, useLoaderData, useRouteLoaderData } from 'react-router';
|
|
11
11
|
|
|
12
12
|
// src/core/index.ts
|
|
13
13
|
|
|
@@ -185,6 +185,7 @@ function createBrowserTelemetry(config) {
|
|
|
185
185
|
}
|
|
186
186
|
};
|
|
187
187
|
const getReporter = () => {
|
|
188
|
+
if (disposed) return void 0;
|
|
188
189
|
if (!reporter) {
|
|
189
190
|
reporter = createTelemetryReporter({
|
|
190
191
|
appKey: config.appKey,
|
|
@@ -206,6 +207,7 @@ function createBrowserTelemetry(config) {
|
|
|
206
207
|
};
|
|
207
208
|
function replay(entry) {
|
|
208
209
|
const target = getReporter();
|
|
210
|
+
if (!target) return;
|
|
209
211
|
target.setContext(entry.context);
|
|
210
212
|
if (entry.kind === "feature") {
|
|
211
213
|
const methods = ["recordCheck", "recordUsage", "recordView"];
|
|
@@ -273,6 +275,28 @@ function createBrowserTelemetry(config) {
|
|
|
273
275
|
}
|
|
274
276
|
const api = {
|
|
275
277
|
recordUsage: (key, variant = "enabled") => feature(key, variant, 1),
|
|
278
|
+
use: (key, fn, variant = "enabled") => {
|
|
279
|
+
if (!usage || disposed) {
|
|
280
|
+
return runFeatureUsageScope(
|
|
281
|
+
{ recordAttempt: () => {
|
|
282
|
+
}, recordSuccessDuration: () => {
|
|
283
|
+
}, recordFailure: () => {
|
|
284
|
+
} },
|
|
285
|
+
fn
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
const target = getReporter();
|
|
289
|
+
if (!target) {
|
|
290
|
+
return runFeatureUsageScope(
|
|
291
|
+
{ recordAttempt: () => {
|
|
292
|
+
}, recordSuccessDuration: () => {
|
|
293
|
+
}, recordFailure: () => {
|
|
294
|
+
} },
|
|
295
|
+
fn
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
return target.use(key, fn, variant);
|
|
299
|
+
},
|
|
276
300
|
recordView: (key, variant = "enabled") => feature(key, variant, 2),
|
|
277
301
|
incrementCounter: (key, value = 1) => event({ partition, context, key, kind: "counter", values: [value] }),
|
|
278
302
|
setGauge: (key, value) => event({ partition, context, key, kind: "gauge", values: [value] }),
|
|
@@ -292,7 +316,10 @@ function createBrowserTelemetry(config) {
|
|
|
292
316
|
if (disposed || !usage) return () => {
|
|
293
317
|
};
|
|
294
318
|
if (active) {
|
|
295
|
-
const
|
|
319
|
+
const target = getReporter();
|
|
320
|
+
if (!target) return () => {
|
|
321
|
+
};
|
|
322
|
+
const record = target.captureCheck();
|
|
296
323
|
return (key, result) => record(key, checkVariantLabel(result));
|
|
297
324
|
}
|
|
298
325
|
const attribution = context;
|
|
@@ -319,7 +346,7 @@ function createBrowserTelemetry(config) {
|
|
|
319
346
|
|
|
320
347
|
// src/client/sdk-identity.ts
|
|
321
348
|
var SDK_ID = "react-router";
|
|
322
|
-
var SDK_VERSION = "1.
|
|
349
|
+
var SDK_VERSION = "1.5.0";
|
|
323
350
|
function appendSdkQueryParams(params) {
|
|
324
351
|
params.set("sdk", SDK_ID);
|
|
325
352
|
params.set("sdkVersion", SDK_VERSION);
|
|
@@ -1052,32 +1079,97 @@ function FeatureGate({
|
|
|
1052
1079
|
const enabled = useFeatureGate(featureKeys, requirement, negate, context, contextKind);
|
|
1053
1080
|
return enabled ? /* @__PURE__ */ jsx(Fragment, { children }) : null;
|
|
1054
1081
|
}
|
|
1055
|
-
function
|
|
1082
|
+
function resolveServerContext(data, fallbackContext) {
|
|
1083
|
+
const serverContext = data?.[TOGGLY_LOADER_KEY];
|
|
1084
|
+
return serverContext ?? fallbackContext;
|
|
1085
|
+
}
|
|
1086
|
+
function buildMergedConfig(config, serverContext) {
|
|
1087
|
+
return config ?? (serverContext ? {
|
|
1088
|
+
appKey: serverContext.appKey,
|
|
1089
|
+
environment: serverContext.environment
|
|
1090
|
+
} : void 0);
|
|
1091
|
+
}
|
|
1092
|
+
function RouterTogglyProviderInner({
|
|
1093
|
+
children,
|
|
1094
|
+
serverContext,
|
|
1095
|
+
config,
|
|
1096
|
+
...props
|
|
1097
|
+
}) {
|
|
1098
|
+
const mergedConfig = buildMergedConfig(config, serverContext);
|
|
1099
|
+
return /* @__PURE__ */ jsx(TogglyProvider, { serverContext, config: mergedConfig, ...props, children });
|
|
1100
|
+
}
|
|
1101
|
+
function RouterTogglyProviderWithData({
|
|
1102
|
+
children,
|
|
1103
|
+
data,
|
|
1104
|
+
fallbackContext,
|
|
1105
|
+
config,
|
|
1106
|
+
...props
|
|
1107
|
+
}) {
|
|
1108
|
+
const serverContext = resolveServerContext(data, fallbackContext);
|
|
1109
|
+
return /* @__PURE__ */ jsx(RouterTogglyProviderInner, { serverContext, config, ...props, children });
|
|
1110
|
+
}
|
|
1111
|
+
function RouterTogglyProviderFromRoute({
|
|
1056
1112
|
children,
|
|
1057
1113
|
routeId,
|
|
1058
1114
|
fallbackContext,
|
|
1059
1115
|
config,
|
|
1060
1116
|
...props
|
|
1061
1117
|
}) {
|
|
1062
|
-
const routeData = useRouteLoaderData(routeId
|
|
1118
|
+
const routeData = useRouteLoaderData(routeId);
|
|
1119
|
+
return /* @__PURE__ */ jsx(
|
|
1120
|
+
RouterTogglyProviderWithData,
|
|
1121
|
+
{
|
|
1122
|
+
data: routeData,
|
|
1123
|
+
fallbackContext,
|
|
1124
|
+
config,
|
|
1125
|
+
...props,
|
|
1126
|
+
children
|
|
1127
|
+
}
|
|
1128
|
+
);
|
|
1129
|
+
}
|
|
1130
|
+
function RouterTogglyProviderFromLoader({
|
|
1131
|
+
children,
|
|
1132
|
+
fallbackContext,
|
|
1133
|
+
config,
|
|
1134
|
+
...props
|
|
1135
|
+
}) {
|
|
1063
1136
|
const loaderData = useLoaderData();
|
|
1064
|
-
const data = routeId ? routeData : loaderData;
|
|
1065
|
-
const serverContext = data?.[TOGGLY_LOADER_KEY];
|
|
1066
|
-
const resolvedServerContext = serverContext ?? fallbackContext;
|
|
1067
|
-
const mergedConfig = config ?? (resolvedServerContext ? {
|
|
1068
|
-
appKey: resolvedServerContext.appKey,
|
|
1069
|
-
environment: resolvedServerContext.environment
|
|
1070
|
-
} : void 0);
|
|
1071
1137
|
return /* @__PURE__ */ jsx(
|
|
1072
|
-
|
|
1138
|
+
RouterTogglyProviderWithData,
|
|
1073
1139
|
{
|
|
1074
|
-
|
|
1075
|
-
|
|
1140
|
+
data: loaderData,
|
|
1141
|
+
fallbackContext,
|
|
1142
|
+
config,
|
|
1076
1143
|
...props,
|
|
1077
1144
|
children
|
|
1078
1145
|
}
|
|
1079
1146
|
);
|
|
1080
1147
|
}
|
|
1148
|
+
function RouterTogglyProviderStatic({
|
|
1149
|
+
children,
|
|
1150
|
+
fallbackContext,
|
|
1151
|
+
config,
|
|
1152
|
+
...props
|
|
1153
|
+
}) {
|
|
1154
|
+
const serverContext = fallbackContext ?? getWindowTogglyData();
|
|
1155
|
+
return /* @__PURE__ */ jsx(RouterTogglyProviderInner, { serverContext, config, ...props, children });
|
|
1156
|
+
}
|
|
1157
|
+
function RouterTogglyProvider({
|
|
1158
|
+
children,
|
|
1159
|
+
routeId,
|
|
1160
|
+
fallbackContext,
|
|
1161
|
+
config,
|
|
1162
|
+
...props
|
|
1163
|
+
}) {
|
|
1164
|
+
const inRouter = useInRouterContext();
|
|
1165
|
+
if (routeId && inRouter) {
|
|
1166
|
+
return /* @__PURE__ */ jsx(RouterTogglyProviderFromRoute, { routeId, fallbackContext, config, ...props, children });
|
|
1167
|
+
}
|
|
1168
|
+
if (inRouter) {
|
|
1169
|
+
return /* @__PURE__ */ jsx(RouterTogglyProviderFromLoader, { fallbackContext, config, ...props, children });
|
|
1170
|
+
}
|
|
1171
|
+
return /* @__PURE__ */ jsx(RouterTogglyProviderStatic, { fallbackContext, config, ...props, children });
|
|
1172
|
+
}
|
|
1081
1173
|
function useTogglyLoaderData() {
|
|
1082
1174
|
const loaderData = useLoaderData();
|
|
1083
1175
|
return {
|