@coframe/sdk 1.1.22 → 1.1.24

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/README.md CHANGED
@@ -65,6 +65,12 @@ only has to forward `<ingestUrl>/*` to `https://ingest.app.coframe.com/ingest/v2
65
65
  with the path unchanged. Both overrides are optional and retain the compiled
66
66
  Coframe endpoints when omitted.
67
67
 
68
+ Configuring either `projectUrl` or `ingestUrl` makes CMAB experiments use
69
+ deterministic local assignment without calling the Edge assignment API.
70
+ Configure both overrides when the browser must avoid the SDK-compiled Coframe
71
+ project and ingest endpoints entirely. Debug tools remain controlled by
72
+ `enableDebug`.
73
+
68
74
  ### URL controls
69
75
 
70
76
  The npm entry uses the same browser URL controls as the script-tag and Edge
@@ -130,6 +136,148 @@ const projectData = serverData?.project
130
136
 
131
137
  Pass `projectData` into `<CoframeProvider>` to avoid the extra client-side project fetch and personalize on first paint.
132
138
 
139
+ ## Feature flags and remote config
140
+
141
+ Browser Feature Flags use the existing public `projectId` and receive only
142
+ flags marked **Public**. `selector` is optional; use `names` for
143
+ individual flag keys and `groups` to evaluate every flag assigned to a page or
144
+ business area.
145
+
146
+ ```ts
147
+ import { setUserToken } from '@coframe/sdk'
148
+ import {
149
+ featureFlags,
150
+ getFeatureFlag,
151
+ getFeatureFlagPayload,
152
+ isFeatureEnabled,
153
+ onFeatureFlags,
154
+ } from '@coframe/sdk/feature-flags'
155
+
156
+ setUserToken('customer-123')
157
+
158
+ await featureFlags.init({
159
+ projectId: 'your-project-id',
160
+ selector: {
161
+ names: ['checkout-redesign'],
162
+ groups: ['homepage_campaigns'],
163
+ },
164
+ })
165
+
166
+ onFeatureFlags(() => {
167
+ if (isFeatureEnabled('checkout-redesign')) {
168
+ showNewCheckout()
169
+ }
170
+
171
+ const content = getFeatureFlagPayload('homepage-content')
172
+ const checkoutVariant = getFeatureFlag('checkout-layout')
173
+ })
174
+ ```
175
+
176
+ Feature Flags are a separate browser entry point and do not increase or initialize
177
+ the main SDK bundle. When both clients are used, Feature Flags reuse the latest
178
+ `setUserToken()` command from Coframe's shared command queue and follow later
179
+ identity changes automatically.
180
+
181
+ Loading does not delay Coframe page modification. Synchronous getters return
182
+ `undefined` until a cached or fresh evaluation is available. The browser client
183
+ always keeps the latest successful response in memory. Before consent, no
184
+ Feature Flag result or evaluation context is persisted. After consent, the
185
+ client also caches the response in `localStorage` for five minutes and keys it
186
+ with an opaque SHA-256 fingerprint derived from the user token and evaluation
187
+ context. It can fall back to that persistent cache if Edge is temporarily
188
+ unavailable. Call `reloadFeatureFlags()` to request fresh evaluations
189
+ explicitly.
190
+
191
+ Payloads support any JSON value up to 32 KB. A payload is returned only when its
192
+ flag is enabled. Remote Config uses the same transport and payload API and
193
+ returns the same payload to all users while active:
194
+
195
+ ```ts
196
+ import { getRemoteConfig } from '@coframe/sdk/feature-flags'
197
+
198
+ const navigation = getRemoteConfig('navigation-config')
199
+ ```
200
+
201
+ Multivariate flags return a stable variant key from `getFeatureFlag()`. Their
202
+ weights divide users into deterministic buckets, and each variant can carry an
203
+ independent optional payload. `isFeatureEnabled()` remains a boolean
204
+ convenience and returns `true` whenever a variant is assigned:
205
+
206
+ ```ts
207
+ import {
208
+ getFeatureFlag,
209
+ getFeatureFlagPayload,
210
+ isFeatureEnabled,
211
+ } from '@coframe/sdk/feature-flags'
212
+
213
+ const variant = getFeatureFlag('checkout-layout')
214
+ const config = getFeatureFlagPayload('checkout-layout')
215
+ const enabled = isFeatureEnabled('checkout-layout')
216
+ ```
217
+
218
+ React apps can read evaluated values from the existing provider:
219
+
220
+ ```tsx
221
+ import {
222
+ useFeatureFlag,
223
+ useFeatureFlagEnabled,
224
+ useFeatureFlagPayload,
225
+ useFeatureFlagVariantKey,
226
+ } from '@coframe/sdk/react'
227
+
228
+ function Checkout() {
229
+ const enabled = useFeatureFlag('checkout-redesign')
230
+ const payload = useFeatureFlagPayload('checkout-redesign')
231
+
232
+ if (enabled === undefined) return <CheckoutSkeleton />
233
+ return enabled ? <NewCheckout config={payload} /> : <OldCheckout />
234
+ }
235
+
236
+ function CheckoutLayout() {
237
+ const variant = useFeatureFlagVariantKey('checkout-layout')
238
+ const enabled = useFeatureFlagEnabled('checkout-layout')
239
+ const payload = useFeatureFlagPayload('checkout-layout')
240
+ return <Checkout variant={variant} enabled={enabled} config={payload} />
241
+ }
242
+ ```
243
+
244
+ For server and edge runtimes, use a secret Feature Flags Server API key. It is
245
+ project-scoped, can read **Private** flags, and must never be included in a
246
+ browser bundle or a `NEXT_PUBLIC_*` environment variable. Each single-key
247
+ helper sends a key-filtered request and fails closed unless a `defaultValue` is
248
+ supplied. Browser and server helpers both call `/api/v1/flags`; server helpers
249
+ include the API key as a Bearer credential so the response may include both
250
+ **Public** and **Private** flags:
251
+
252
+ ```ts
253
+ import {
254
+ evaluateFlags,
255
+ getFeatureFlag,
256
+ getRemoteConfig,
257
+ isFeatureEnabled,
258
+ } from '@coframe/sdk/server'
259
+
260
+ const options = {
261
+ projectId: 'your-project-id',
262
+ apiKey: process.env.COFRAME_FEATURE_FLAGS_SERVER_KEY!,
263
+ userToken: user.id,
264
+ currentUrl: request.url,
265
+ userContext: { plan: user.plan },
266
+ }
267
+
268
+ const checkoutFlags = await evaluateFlags({
269
+ ...options,
270
+ selector: { groups: ['cart_checkout'] },
271
+ })
272
+
273
+ const enabled = await isFeatureEnabled('checkout-redesign', {
274
+ ...options,
275
+ defaultValue: false,
276
+ })
277
+ const variant = await getFeatureFlag('checkout-layout', options)
278
+ const content = await getRemoteConfig('homepage-content', options)
279
+ ```
280
+
133
281
  ## Common React usage
134
282
 
135
283
  ### Read variants in components
@@ -253,9 +401,21 @@ Modern resolution modes handle package subpath exports more reliably.
253
401
  - `onTreatmentApplied(...)`
254
402
  - `onLog(...)`
255
403
 
404
+ ### `@coframe/sdk/feature-flags`
405
+
406
+ - `featureFlags.init(options)`
407
+ - `featureFlags.setUserToken(userToken)` / `featureFlags.reset()`
408
+ - `featureFlags.getUserToken()`
409
+ - `getFeatureFlag(key)` / `isFeatureEnabled(key)`
410
+ - `getFeatureFlagPayload(key)` / `getRemoteConfig(key)`
411
+ - `onFeatureFlags(callback)` / `reloadFeatureFlags()`
412
+
256
413
  ### `@coframe/sdk/server`
257
414
 
258
415
  - `getProjectData(options)`
416
+ - `evaluateFlags(options)`
417
+ - `getFeatureFlag(key, options)` / `isFeatureEnabled(key, options)`
418
+ - `getFeatureFlagPayload(key, options)` / `getRemoteConfig(key, options)`
259
419
 
260
420
  Returns a payload that may include:
261
421
 
@@ -269,3 +429,6 @@ Returns a payload that may include:
269
429
  - `useCoframeTreatments()`
270
430
  - `useCoframeTreatment(experimentId)`
271
431
  - `useCoframeVariant(experimentId)`
432
+ - `useFeatureFlag(key)` / `useFeatureFlagVariantKey(key)`
433
+ - `useFeatureFlagEnabled(key)`
434
+ - `useFeatureFlagResult(key)` / `useFeatureFlagPayload(key)`