Skip to content

Commit 3156c72

Browse files
committed
feat: Create package
0 parents  commit 3156c72

14 files changed

Lines changed: 13080 additions & 0 deletions

.github/workflows/release.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Release
2+
permissions:
3+
contents: write
4+
on:
5+
push:
6+
branches: [main]
7+
8+
jobs:
9+
release:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- name: Checkout
13+
uses: actions/checkout@v4
14+
with:
15+
fetch-depth: 0
16+
17+
- name: Setup Node.js
18+
uses: actions/setup-node@v4
19+
with:
20+
node-version: 'lts/*'
21+
registry-url: 'https://registry.npmjs.org/'
22+
23+
- name: Install dependencies
24+
run: npm ci
25+
26+
- name: Configure npm auth
27+
run: echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
28+
env:
29+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
30+
31+
- name: Build
32+
run: |
33+
npm run typecheck
34+
npm run build
35+
36+
- name: Release
37+
env:
38+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
39+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
40+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
41+
run: npx semantic-release

.gitignore

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
lerna-debug.log*
8+
.pnpm-debug.log*
9+
10+
# Diagnostic reports (https://nodejs.org/api/report.html)
11+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
12+
13+
# Runtime data
14+
pids
15+
*.pid
16+
*.seed
17+
*.pid.lock
18+
19+
# Directory for instrumented libs generated by jscoverage/JSCover
20+
lib-cov
21+
22+
# Coverage directory used by tools like istanbul
23+
coverage
24+
*.lcov
25+
26+
# nyc test coverage
27+
.nyc_output
28+
29+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
30+
.grunt
31+
32+
# Bower dependency directory (https://bower.io/)
33+
bower_components
34+
35+
# node-waf configuration
36+
.lock-wscript
37+
38+
# Compiled binary addons (https://nodejs.org/api/addons.html)
39+
build/Release
40+
41+
# Dependency directories
42+
node_modules/
43+
jspm_packages/
44+
45+
# Snowpack dependency directory (https://snowpack.dev/)
46+
web_modules/
47+
48+
# TypeScript cache
49+
*.tsbuildinfo
50+
51+
# Optional npm cache directory
52+
.npm
53+
54+
# Optional eslint cache
55+
.eslintcache
56+
57+
# Optional stylelint cache
58+
.stylelintcache
59+
60+
# Microbundle cache
61+
.rpt2_cache/
62+
.rts2_cache_cjs/
63+
.rts2_cache_es/
64+
.rts2_cache_umd/
65+
66+
# Optional REPL history
67+
.node_repl_history
68+
69+
# Output of 'npm pack'
70+
*.tgz
71+
72+
# Yarn Integrity file
73+
.yarn-integrity
74+
75+
# dotenv environment variable files
76+
.env
77+
.env.development.local
78+
.env.test.local
79+
.env.production.local
80+
.env.local
81+
82+
# parcel-bundler cache (https://parceljs.org/)
83+
.cache
84+
.parcel-cache
85+
86+
# Next.js build output
87+
.next
88+
out
89+
90+
# Nuxt.js build / generate output
91+
.nuxt
92+
dist
93+
94+
# Gatsby files
95+
.cache/
96+
# Comment in the public line in if your project uses Gatsby and not Next.js
97+
# https://nextjs.org/blog/next-9-1#public-directory-support
98+
# public
99+
100+
# vuepress build output
101+
.vuepress/dist
102+
103+
# vuepress v2.x temp and cache directory
104+
.temp
105+
.cache
106+
107+
# Docusaurus cache and generated files
108+
.docusaurus
109+
110+
# Serverless directories
111+
.serverless/
112+
113+
# FuseBox cache
114+
.fusebox/
115+
116+
# DynamoDB Local files
117+
.dynamodb/
118+
119+
# TernJS port file
120+
.tern-port
121+
122+
# Stores VSCode versions used for testing VSCode extensions
123+
.vscode-test
124+
125+
# yarn v2
126+
.yarn/cache
127+
.yarn/unplugged
128+
.yarn/build-state.yml
129+
.yarn/install-state.gz
130+
.pnp.*
131+
132+
.DS_Store
133+
.idea
134+
out-tsc

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 FlipFlag
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# FlipFlag React
2+
3+
React bindings for **FlipFlag** — feature flags and remote configuration for React and Next.js applications.
4+
5+
Built on top of [`@flipflag/sdk`](https://github.com/flipflag-dev/sdk), this package provides idiomatic React APIs:
6+
**providers, hooks, and safe client-side defaults**.
7+
8+
---
9+
10+
## Features
11+
12+
- React-first API (`Provider`, hooks)
13+
- Works with **React 18+** and **Next.js (App & Pages Router)**
14+
- Safe by default for the browser (public key only)
15+
- Automatic re-rendering on flag updates
16+
- Optional SSR-friendly bootstrapping
17+
- Full TypeScript support
18+
- Zero config required on the client
19+
20+
---
21+
22+
## Installation
23+
24+
```sh
25+
npm install @flipflag/react @flipflag/sdk
26+
# or
27+
yarn add @flipflag/react @flipflag/sdk
28+
```
29+
30+
> `react` and `@flipflag/sdk` are declared as peer dependencies.
31+
32+
---
33+
34+
## Core Concepts
35+
36+
- **`FlipFlagProvider`**
37+
Owns a single `FlipFlag` manager instance and handles lifecycle (`init`, polling, `destroy`).
38+
39+
- **Hooks (`useFlag`, `useFlags`)**
40+
Read feature flags reactively inside components.
41+
42+
- **Client-safe by default**
43+
Designed to run in the browser using a **public key only**.
44+
45+
---
46+
47+
## Quick Start (React)
48+
49+
```tsx
50+
import { FlipFlagProvider, useFlag } from "@flipflag/react";
51+
52+
function NewNavbar() {
53+
const enabled = useFlag("new-navbar", false);
54+
55+
return enabled ? <div>New navbar</div> : <div>Old navbar</div>;
56+
}
57+
58+
export function App() {
59+
return (
60+
<FlipFlagProvider
61+
options={{
62+
publicKey: "YOUR_PUBLIC_KEY",
63+
}}
64+
>
65+
<NewNavbar />
66+
</FlipFlagProvider>
67+
);
68+
}
69+
```
70+
71+
---
72+
73+
## Next.js (App Router)
74+
75+
### `app/providers.tsx`
76+
77+
```tsx
78+
"use client";
79+
80+
import { FlipFlagProvider } from "@flipflag/react";
81+
82+
export function Providers({ children }: { children: React.ReactNode }) {
83+
return (
84+
<FlipFlagProvider
85+
options={{
86+
publicKey: process.env.NEXT_PUBLIC_FLIPFLAG_PUBLIC_KEY!,
87+
ignoreMissingConfig: true
88+
}}
89+
>
90+
{children}
91+
</FlipFlagProvider>
92+
);
93+
}
94+
```
95+
96+
### `app/layout.tsx`
97+
98+
```tsx
99+
import { Providers } from "./providers";
100+
101+
export default function RootLayout({
102+
children,
103+
}: {
104+
children: React.ReactNode;
105+
}) {
106+
return (
107+
<html>
108+
<body>
109+
<Providers>{children}</Providers>
110+
</body>
111+
</html>
112+
);
113+
}
114+
```
115+
116+
---
117+
118+
## Hooks API
119+
120+
### `useFlag(name, fallback?)`
121+
122+
Returns a boolean feature flag value.
123+
124+
```ts
125+
const enabled = useFlag("checkout-v2");
126+
```
127+
128+
With fallback:
129+
130+
```ts
131+
const enabled = useFlag("checkout-v2", false);
132+
```
133+
134+
---
135+
136+
### `useFlags(names, fallback?)`
137+
138+
Read multiple flags at once.
139+
140+
```ts
141+
const flags = useFlags(["checkout-v2", "new-navbar"] as const);
142+
143+
flags["checkout-v2"];
144+
flags["new-navbar"];
145+
```
146+
147+
---
148+
149+
### `useFlipFlagReady()`
150+
151+
Check SDK initialization state.
152+
153+
```ts
154+
const { ready, error } = useFlipFlagReady();
155+
156+
if (!ready) return <Spinner />;
157+
if (error) return <ErrorState />;
158+
```
159+
160+
---
161+
162+
## Provider Options
163+
164+
```ts
165+
export type FlipFlagReactOptions = {
166+
publicKey: string;
167+
privateKey?: string; // ⚠️ server-only
168+
apiUrl?: string;
169+
configPath?: string;
170+
ignoreMissingConfig?: boolean;
171+
refreshIntervalMs?: number; // default: 10_000
172+
initialFlags?: Record<string, boolean>;
173+
};
174+
```
175+
176+
---
177+
178+
## License
179+
180+
MIT License

eslint.config.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import globals from 'globals'
2+
import pluginJs from '@eslint/js'
3+
import tseslint from 'typescript-eslint'
4+
5+
export default [
6+
{ files: ['**/*.{js,mjs,cjs,ts,js,ts}'] },
7+
{ languageOptions: { globals: globals.node } },
8+
pluginJs.configs.recommended,
9+
...tseslint.configs.recommended,
10+
]

0 commit comments

Comments
 (0)