원클릭으로
react-sdk-contract
Use when changing packages/react, CaptureFlagProvider, useFeatureFlag, or React SDK tests.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Use when changing packages/react, CaptureFlagProvider, useFeatureFlag, or React SDK tests.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Use when adding, changing, extracting, or reusing client components, including Storybook stories and controls.
Use when adding or changing forms in apps/client.
Use when changing GitHub OAuth, session cookies, SessionGuard, logout, or authenticated API request identity.
Use when adding or changing routes in apps/client.
Use when adding or changing client state, React Query data flow, immutable context values, or Zustand stores.
Use when styling apps/client with Tailwind CSS v4.
| name | react-sdk-contract |
| description | Use when changing packages/react, CaptureFlagProvider, useFeatureFlag, or React SDK tests. |
Generated from ai/registry.json. Do not edit manually.
Canonical skill: ../../../ai/skills/react-sdk-contract.md.
Referenced context:
../../../ai/rules/react-sdk-rules.md../../../ai/rules/sdk-evaluator-rules.md../../../ai/architecture/react-sdk-provider.md../../../ai/architecture/sdk-evaluation-flow.md../../../ai/examples/good-react-sdk-hook.mdThis file is compiled from canonical AI knowledge files. Edit canonical files under ai, then run npm run ai:sync.
ai/skills/react-sdk-contract.mdUse this skill when changing packages/react, CaptureFlagProvider, useFeatureFlag, or React SDK tests.
Preserve the React SDK as a thin provider/hook layer around the JavaScript SDK client and local evaluation context.
ai/rules/react-sdk-rules.mdai/rules/sdk-evaluator-rules.mdai/architecture/react-sdk-provider.mdai/architecture/sdk-evaluation-flow.mdai/examples/good-react-sdk-hook.mdCaptureFlagProvider.packages/react.npm --workspace @capture-flag/react run test after React SDK behavior changes.npm --workspace @capture-flag/react run build after package source changes.ai/rules/react-sdk-rules.mdRules for packages/react, the Capture Flag provider, and useFeatureFlag.
CaptureFlagProvider as the owner of the SDK client and optional default evaluation context.useFeatureFlag(key, fallbackValue, context?) as the public hook shape unless intentionally changing the React SDK contract.getValue when the SDK notifies.useFeatureFlag usable outside CaptureFlagProvider silently.packages/react.ai/rules/sdk-evaluator-rules.mdRules for packages/sdk-js, packages/evaluator, and packages/react.
createClient(options) returns getValue<TValue>(key, fallbackValue, context?), refresh(), close(), and subscribe(listener).fallbackValue distinct from stored config defaultValue.segments and the Evaluation Context.equals and notEquals unless the public contract is explicitly expanded.arrayContains, dateBefore, dateAfter, semverEquals, semverGreaterThan, semverGreaterThanOrEquals, semverLessThan, and semverLessThanOrEquals.YYYY-MM-DD/date-time strings with timezone.MAJOR.MINOR.PATCH, prerelease precedence, and ignored build metadata.${flagKey}:${attributeValue}, UTF-16/JavaScript code units, modulo 10000, and percentage basis points with at most two decimal places.lazy, auto, manual, and offline.cacheTtlMs before refreshing.client.close().getValue and fetch only through refresh().If-None-Match when a cached ETag exists and treat 304 Not Modified as a freshness update without reprocessing JSON.304 Not Modified, request failures, non-OK responses, invalid config, or equivalent config responses.defaultValue.fallbackValue when config is unavailable, invalid, missing, or mismatched.ai/architecture/react-sdk-provider.mdpackages/react wraps the JavaScript SDK for React applications.
CaptureFlagProvider receives an already-created CaptureFlagClient.packages/sdk-js.useFeatureFlag reads the SDK client and provider context from React context.getValue when the SDK notifies.React SDK tests use a fake CaptureFlagClient and assert rendered provider/hook behavior.
ai/architecture/sdk-evaluation-flow.mdSDK evaluation is local. The API only serves config data.
packages/evaluator: pure deterministic evaluation engine.packages/sdk-js: fetches public config, owns cache/polling behavior, and calls the evaluator.packages/react: React provider and useFeatureFlag hook around the JS SDK client.createClient({ baseUrl, sdkKey }).lazy.getValue(key, fallbackValue, context) resolves a config according to the selected SDK mode.evaluate from @capture-flag/evaluator.localStorage cache is browser-only and opt-in through SDK options.cacheTtlMs has expired.getValue; applications call refresh() to fetch.getValue and refreshes in the background on pollIntervalMs.close() stops auto polling timers.If-None-Match when the current cache has an ETag.304 Not Modified updates cache freshness without parsing or replacing config JSON.304, failed refreshes, invalid configs, or equivalent config responses.schemaVersion.Evaluation context stays in the SDK process and is never sent to the public config API.
ai/examples/good-react-sdk-hook.mdSource: packages/react/src/index.tsx (sha256: 573755cf26383171eeeb0b49210ea3d2c0beb1170d729e1838a3b250621843c8)
Source: packages/react/test/index.spec.tsx (sha256: c3c5683bd7f5c00d49f031ac1d41554ac87af9250dd4e8a70981812cdf3215aa)
Why this is canonical:
const effectiveContext = context === undefined ? captureFlag.context : context;
const client = captureFlag.client;
const [state, setState] = useState<FeatureFlagState<TValue>>(() => ({
client,
context: effectiveContext,
fallbackValue,
key,
value: fallbackValue,
}));
useEffect(() => {
let cancelled = false;
let requestVersion = 0;
const requestState = {
client,
context: effectiveContext,
fallbackValue,
key,
};
function requestValue(resetToFallback: boolean) {
const currentRequestVersion = ++requestVersion;
if (resetToFallback) {
setState({ ...requestState, value: fallbackValue });
}
client.getValue(key, fallbackValue, effectiveContext).then(
(nextValue) => {
if (!cancelled && currentRequestVersion === requestVersion) {
setState({ ...requestState, value: nextValue });
}
},
() => {
if (!cancelled && currentRequestVersion === requestVersion) {
setState({ ...requestState, value: fallbackValue });
}
},
);
}
const unsubscribe = client.subscribe(() => requestValue(false));
requestValue(true);
return () => {
cancelled = true;
unsubscribe();
};
}, [client, effectiveContext, fallbackValue, key]);
const stateMatchesCurrentRequest =
state.client === client &&
state.context === effectiveContext &&
Object.is(state.fallbackValue, fallbackValue) &&
state.key === key;
return stateMatchesCurrentRequest ? state.value : fallbackValue;
The cancellation guard prevents updates after dependency changes or unmount, and the request version prevents older async evaluations from overwriting newer config-change evaluations. The request identity check prevents stale render output before the next effect runs.