Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

flag

Package Overview
Dependencies
Maintainers
1
Versions
34
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

flag - npm Package Compare versions

Comparing version 5.0.0-alpha.0 to 5.0.0

dist/index.d.ts

2

package.json
{
"name": "flag",
"version": "5.0.0-alpha.0",
"version": "5.0.0",
"description": "Strictly typed feature flagging for React",

@@ -5,0 +5,0 @@ "main": "dist/index.js",

# Flag
:caution: v5 is a work in progress and is not yet published. :caution:
This library aims to offer a best-in-class interface for working with feature flags in TypeScript-based React applications.

@@ -38,12 +36,12 @@

### FlagBackendProvider
### `FlagBackendProvider`
_Returned as part of `createFlags<T>()`._
This React component provides a `Backend<T>` (see below) as a data source for `Flag` and `useFlag`.
This React component provides a `Backend<T>` ([see below](https://github.com/garbles/flag/tree/master/packages/flag#backends)) as a data source for `Flag` and `useFlag`.
| Props | Type | Required | Description |
| ---------- | ------------------ | -------- | ---------------------- |
| `backend` | `Types.Backend<T>` | `true` | All pre-computed flags |
| `children` | `ReactNode` | `true` | React children |
| Props | Type | Required | Description |
| ---------- | ------------------ | -------- | ------------------------- |
| `backend` | `Types.Backend<T>` | `true` | The data source for flags |
| `children` | `ReactNode` | `true` | React children |

@@ -53,4 +51,6 @@ ```tsx

import React from "react";
import ReactDOM from "react-dom";
import { NullBackend } from "flag";
import { MyApplication } from "./app";
import { App } from "./app";
import { FlagBackendProvider } from "./flags";

@@ -60,12 +60,12 @@

const instance = (
const root = ReactDOM.createRoot(document.querySelector("#app"));
root.render(
<FlagBackendProvider backend={backend}>
<MyApplication />
<App />
</FlagBackendProvider>
);
React.render(instance, document.querySelector("#app"));
```
### useFlag
### `useFlag`

@@ -98,3 +98,3 @@ _Returned as part of `createFlags<T>()`._

### Flag
### `Flag`

@@ -123,6 +123,208 @@ _Returned as part of `createFlags<T>()`._

`FlagBackendProvider` requires that you pass a `Backend<T>` which is responsible for retreiving flags to your application.
`flag` bundles with several useful backends, but you can also roll your own.
### `StaticBackend<T>`
Accepts a JSON object that matches the partial shape of your flags. It can be nested, but shouldn't use arrays.
```tsx
import React from "react";
import ReactDOM from "react-dom";
import { StaticBackend } from "flag";
import { FlagBackendProvider, MyFlags } from "./flags";
import { App } from "./app";
const backend = new StaticBackend<MyFlags>({
features: {
useMyCoolNewThing: false,
},
config: {
apiUrl: "https://example.com",
},
cool: 100,
dude: 200,
coolAndDude: 300,
largeCoolAndDude: 600,
});
const root = ReactDOM.createRoot(document.querySelector("#app"));
root.render(
<FlagBackendProvider backend={backend}>
<App />
</FlagBackendProvider>
);
```
If a partial object is provided and a requested key is missing, it will fallback to the provided default. That is,
```tsx
const backend = new StaticBackend<MyFlags>({
features: {},
});
// ...
const SomeScreen = () => {
const newThing = useFlag("features.useMyCoolNewThing", true);
// => will always be `true`
// ...
};
```
### `ComputedBackend<T>`
Similar to `StaticBackend` but if a function is used as a value, it will pass in the object `T` as an
argument. (Yes, this means you can end up with a stack overflow if you're not careful.) Useful when you need to have composite flags outside of the React render loop.
```tsx
import React from "react";
import ReactDOM from "react-dom";
import { ComputedBackend } from "flag";
import { FlagBackendProvider, MyFlags } from "./flags";
import { App } from "./app";
const backend = new ComputedBackend<MyFlags>({
features: {
useMyCoolNewThing: false,
},
config: {
apiUrl: "https://example.com",
},
cool: 100,
dude: 200,
coolAndDude: (flags) => flags.cool + flags.dude,
largeCoolAndDude: (flags) => flags.coolAndDude * 2,
});
const root = ReactDOM.createRoot(document.querySelector("#app"));
root.render(
<FlagBackendProvider backend={backend}>
<App />
</FlagBackendProvider>
);
```
### `AlwaysBackend`
Given a partial mapping of `{ boolean: boolean; string: string; number: number; }` will always yield the mapping value for a given type. If a type is missing from the mapping, it will fallback to the default value given to `useFlag`. Useful for testing.
```tsx
import React from "react";
import ReactDOM from "react-dom";
import { AlwaysBackend } from "flag";
import { FlagBackendProvider } from "./flags";
import { App } from "./app";
const backend = new AlwaysBackend({
boolean: false,
string: "some string",
number: 1000,
});
const root = ReactDOM.createRoot(document.querySelector("#app"));
root.render(
<FlagBackendProvider backend={backend}>
<App />
</FlagBackendProvider>
);
```
### `NullBackend`
A backend that always returns the default value. Useful for testing.
```tsx
import React from "react";
import ReactDOM from "react-dom";
import { NullBackend } from "flag";
import { FlagBackendProvider } from "./flags";
import { App } from "./app";
const backend = new NullBackend();
const root = ReactDOM.createRoot(document.querySelector("#app"));
root.render(
<FlagBackendProvider backend={backend}>
<App />
</FlagBackendProvider>
);
```
### Rolling your own with `AbstractBackend<T>`
You can roll your own backend by extending a class off of `AbstractBackend<T>`. You need only implement the `getSnapshot()` (and optionally `getServerSnapshot()`) method.
```tsx
import { AbstractBackend, Types } from "flag";
/**
* `F` is the shape of your flags.
*/
export class MyBackend<F> extends AbstractBackend<F> {
/**
* `KP` is a valid key path (as an array).
* `T` is the type of value associated the key path.
*/
getSnapshot<KP extends Types.KeyPath<F>, T extends Types.GetValueFromKeyPath<F, KP>>(keyPath: KP, defaultValue: T): T {
/**
* `getSnapshot` must return `T`.
*/
return defaultValue;
}
/**
* OPTIONAL: you can override `getServerSnapshot` if you need different behavior for server rendering.
* Defaults to `getSnapshot`.
*/
override getServerSnapshot<KP extends Types.KeyPath<F>, T extends Types.GetValueFromKeyPath<F, KP>>(keyPath: KP, defaultValue: T): T {
/**
* Do something different than `getSnapshot`
*/
return defaultValue;
}
}
```
If you want your backend to work with React Suspense, you can create an [async ref object](https://github.com/garbles/flag/tree/master/packages/async-ref) by calling `this.createAsyncRef()` and using it in `getSnapshot()`.
```tsx
import { AbstractBackend, Types } from "flag";
export class MyBackend<F> extends AbstractBackend<F> {
#data: Types.AsyncMutableRefObject<T>;
constructor() {
this.#data = this.createAsyncRef();
fetch("/api-with-data")
.then((res) => res.json())
.then((data) => {
this.#data.current = data;
});
}
getSnapshot<KP extends Types.KeyPath<F>, T extends Types.GetValueFromKeyPath<F, KP>>(keyPath: KP, defaultValue: T): T {
/**
* Throws a promise if a current value has not yet been assigned.
*/
const data = this.#data.current;
return someGetterFn(data, keyPath);
}
}
```
## Setting NODE_ENV
While in development, you should be sure to set `process.env.NODE_ENV` to `"development"` for useful warnings when possible. Tool kits like Remix, Next and CRA do this automatically for you.
## License
MPL-2.0
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc