Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
05ca10d
feat(flags): add framework integration for nuxt
danielroe Aug 26, 2025
02cac21
chore: exclude runtime nuxt entrypoints
danielroe Aug 26, 2025
ca8704c
Merge remote-tracking branch 'origin/main' into feat/nuxt
danielroe Nov 10, 2025
d3417b9
chore: bump nuxt packages
danielroe Nov 10, 2025
6705996
chore: minimise diff
danielroe Nov 10, 2025
f91e792
chore: dedupe lockfile
danielroe Nov 10, 2025
009ac7e
chore: bump some nuxt deps
danielroe Nov 10, 2025
bde2de1
fix(nuxt): move default flags directory to top-level
danielroe Nov 10, 2025
5ef0974
fix(nuxt): ensure web headers are available on client/server
danielroe Nov 10, 2025
64df14c
test: add basic nuxt e2e test suite
danielroe Nov 10, 2025
3f89af4
chore: drop vitest + postinstall step
danielroe Nov 10, 2025
d1536de
chore: add back vitest v1 dep
danielroe Nov 10, 2025
9026ea4
chore: remove --no-ui flag 🤦
danielroe Nov 10, 2025
4ea359e
chore: add nuxt prepare step
danielroe Nov 10, 2025
78416ed
ci: bump playwright test timeout
danielroe Nov 10, 2025
9f7575a
chore: sync playwright versions with rest of project
danielroe Nov 10, 2025
0c01f09
test: pass `executablePath`
danielroe Nov 10, 2025
c0a6fa1
test: allow running playwright locally
danielroe Nov 11, 2025
1139baf
feat: add automatic passing of event in nuxt context (+ nitro if asyn…
danielroe Nov 11, 2025
90a3905
refactor: extract some shared precompute utils
danielroe Nov 13, 2025
911b3c1
feat(nuxt): support precomputed paths
danielroe Nov 13, 2025
7a38236
perf: use lru cache for cached static values
danielroe Nov 13, 2025
76a38f9
chore: import JsonValue from `src`, not root
danielroe Nov 13, 2025
d949c52
fix: don't include lru cache if not prerendering
danielroe Nov 13, 2025
b9a2422
test: improve e2e tests
danielroe Nov 13, 2025
10aa069
test: add `.env`
danielroe Nov 14, 2025
1794ae4
feat: respect precomputed flag values on client-side navigation
danielroe Nov 14, 2025
ccf706d
fix: pass fully resolved path to `isIgnored`
danielroe Nov 14, 2025
afd2d51
test: add tests for overriding flags
danielroe Nov 14, 2025
1c1aff5
test: work with FLAGS_SECRET env variable as well
danielroe Nov 14, 2025
18187fd
test: don't rely on value of secret
danielroe Nov 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ on:
branches: ["*"]
jobs:
test:
timeout-minutes: 5
timeout-minutes: 10
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@
"publint": "0.3.14",
"turbo": "2.3.3",
"typescript": "^5.3.3",
"typescript-eslint": "8.46.1"
"typescript-eslint": "8.46.1",
"unstorage": "1.17.2"
},
"packageManager": "[email protected]",
"engines": {
Expand Down
3 changes: 3 additions & 0 deletions packages/flags/.attw.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"excludeEntrypoints": ["flags/nuxt", "flags/nuxt/runtime"]
}
4 changes: 2 additions & 2 deletions packages/flags/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

# Flags SDK

The feature flags toolkit for Next.js and SvelteKit.
The feature flags toolkit for Next.js, Nuxt, and SvelteKit.

From the creators of Next.js, the Flags SDK is a free open-source library that gives you the tools you need to use feature flags in Next.js and SvelteKit applications.
From the creators of Next.js, the Flags SDK is a free open-source library that gives you the tools you need to use feature flags in Next.js, Nuxt, and SvelteKit applications.

- Works with any flag provider, custom setups or no flag provider at all
- Compatible with App Router, Pages Router, and Edge Middleware
Expand Down
25 changes: 22 additions & 3 deletions packages/flags/package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
{
"name": "flags",
"version": "4.0.2",
"description": "Flags SDK by Vercel - The feature flags toolkit for Next.js and SvelteKit",
"description": "Flags SDK by Vercel - The feature flags toolkit for Next.js, Nuxt and SvelteKit",
"keywords": [
"feature flags",
"Next.js",
"Nuxt",
"react",
"vue",
"toolbar",
"overrides",
"SvelteKit"
Expand All @@ -30,6 +32,8 @@
"import": "./dist/next.js",
"require": "./dist/next.cjs"
},
"./nuxt": "./dist/nuxt.js",
"./nuxt/runtime": "./dist/nuxt/runtime/index.js",
"./analytics": {
"import": "./dist/analytics.js",
"require": "./dist/analytics.cjs"
Expand All @@ -54,6 +58,12 @@
"dist/next.d.ts",
"dist/next.d.cts"
],
"nuxt": [
"dist/nuxt.d.ts"
],
"nuxt/runtime": [
"dist/nuxt/runtime.d.ts"
],
"react": [
"dist/react.d.ts",
"dist/react.d.cts"
Expand All @@ -79,25 +89,31 @@
},
"dependencies": {
"@edge-runtime/cookies": "^5.0.2",
"jose": "^5.2.1"
"exsolve": "^1.0.8",
"jose": "^5.2.1",
"std-env": "^3.10.0"
},
"devDependencies": {
"@arethetypeswrong/cli": "0.17.3",
"@nuxt/test-utils": "3.20.1",
"@types/node": "20.11.17",
"@types/react": "18.2.55",
"@vitejs/plugin-react": "4.2.1",
"h3": "1.15.4",
"msw": "2.6.4",
"next": "15.1.4",
"nuxt": "4.2.1",
"react": "canary",
"tsup": "8.0.1",
"typescript": "5.6.3",
"vite": "5.1.1",
"vite": "7.2.2",
"vitest": "1.4.0"
},
"peerDependencies": {
"@opentelemetry/api": "^1.7.0",
"@sveltejs/kit": "*",
"next": "*",
"nuxt": ">=3.0.0",
"react": "*",
"react-dom": "*"
},
Expand All @@ -111,6 +127,9 @@
"next": {
"optional": true
},
"nuxt": {
"optional": true
},
"react": {
"optional": true
},
Expand Down
10 changes: 5 additions & 5 deletions packages/flags/src/lib/serialization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@ function splitUint8Array(
/**
* Common subset of the flag type used in here
*/
type Flag = {
export type CommonFlag<T = any> = {
key: string;
options?: FlagOption<any>[];
options?: FlagOption<T>[];
};

export async function deserialize(
code: string,
flags: readonly Flag[],
flags: readonly CommonFlag[],
secret: string,
): Promise<Record<string, JsonValue>> {
// TODO what happens when verification fails?
Expand Down Expand Up @@ -151,8 +151,8 @@ function joinUint8Arrays(array1: Uint8Array, array2: Uint8Array): Uint8Array {
return combined;
}
export async function serialize(
flagSet: Record<Flag['key'], JsonValue>,
flags: readonly Flag[],
flagSet: Record<CommonFlag['key'], JsonValue>,
flags: readonly CommonFlag[],
secret: string,
) {
const unlistedValues: JsonValue[] = [];
Expand Down
9 changes: 2 additions & 7 deletions packages/flags/src/next/precompute.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { JsonValue } from '..';
import * as s from '../lib/serialization';
import { cartesianIterator, combineFlags } from '../shared';
import type { Flag } from './types';

type FlagsArray = readonly Flag<any, any>[];
Expand Down Expand Up @@ -40,7 +41,7 @@ export async function precompute<T extends FlagsArray>(
* @returns - A record where the keys are flag keys and the values are flag values.
*/
export function combine(flags: FlagsArray, values: ValuesArray) {
return Object.fromEntries(flags.map((flag, i) => [flag.key, values[i]]));
return combineFlags(flags, values);
}

/**
Expand Down Expand Up @@ -150,12 +151,6 @@ export async function getPrecomputed<T extends JsonValue>(
}
}

// see https://stackoverflow.com/a/44344803
function* cartesianIterator<T>(items: T[][]): Generator<T[]> {
const remainder = items.length > 1 ? cartesianIterator(items.slice(1)) : [[]];
for (const r of remainder) for (const h of items.at(0)!) yield [h, ...r];
}

/**
* Generates all permutations given a list of feature flags based on the options declared on each flag.
* @param flags - The list of feature flags
Expand Down
20 changes: 20 additions & 0 deletions packages/flags/src/nuxt/implementation.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
declare module '#flags-implementation' {
import type { H3Event } from 'h3';
import type { Identify, JsonValue } from 'flags';

export function getState<ValueType>(
key: string,
event?: H3Event,
): { value: ValueType };
export function getStore<T>(event?: H3Event): T;

export function getEvent(): H3Event | undefined;

export interface FlagStore {
event: H3Event;
secret: string;
params: Record<string, string | string[]>;
usedFlags: Record<string, Promise<JsonValue>>;
identifiers: Map<Identify<unknown>, ReturnType<Identify<unknown>>>;
}
}
Loading
Loading