@flagsync/nextjs-sdk 0.2.7 → 0.3.0
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/LICENSE +1 -1
- package/README.md +8 -282
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/LICENSE
CHANGED
|
@@ -186,7 +186,7 @@
|
|
|
186
186
|
same "printed page" as the copyright notice for easier
|
|
187
187
|
identification within third-party archives.
|
|
188
188
|
|
|
189
|
-
Copyright
|
|
189
|
+
Copyright 2005 Mike Chabot (FlagSync)
|
|
190
190
|
|
|
191
191
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
192
|
you may not use this file except in compliance with the License.
|
package/README.md
CHANGED
|
@@ -1,288 +1,14 @@
|
|
|
1
|
-
# FlagSync
|
|
1
|
+
# FlagSync SDK for Next.js
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The `@flagsync/nextjs-sdk` integrates into Next.js applications with [Vercel Flags](https://flags-sdk.dev/) for feature management and event tracking—ideal for SSR and static site generation workflows.
|
|
4
4
|
|
|
5
5
|
[](https://badge.fury.io/js/%40flagsync%2Fvercel-flags-sdk)
|
|
6
|
-
[](https://twitter.com/flagsync)
|
|
7
|
-
[](https://www.apache.org/licenses/LICENSE-2.0)
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## Getting Started
|
|
12
|
-
|
|
13
|
-
Refer to the [SDK documentation](https://docs.flagsync.com/sdks/next.js) for more information on how to use this library.
|
|
14
|
-
|
|
15
|
-
### Compatibility
|
|
6
|
+
[](https://twitter.com/flagsync)
|
|
16
7
|
|
|
8
|
+
## Compatibility
|
|
17
9
|
- Requires [Next.js](https://nextjs.org/) 14+
|
|
18
|
-
- Compatible with Node.js 16+ and ES5
|
|
19
|
-
- TypeScript is fully supported
|
|
20
|
-
- **Note:** This SDK is optimized for Next.js App Router. For non-Next.js Node.js apps, use the [FlagSync Node SDK](https://github.com/flagsync/node-client) instead.
|
|
21
|
-
|
|
22
|
-
### Prerequisites
|
|
23
|
-
- Install the SDK: `npm install @flagsync/vercel-flags-sdk flags/next`
|
|
24
|
-
- Set the `FLAGSYNC_SDK_KEY` environment variable in your `.env` file.
|
|
25
|
-
|
|
26
|
-
## Basic Setup
|
|
27
|
-
|
|
28
|
-
FlagSync lets you toggle features and personalize experiences in your Next.js App Router application. Follow these steps to set it up.
|
|
29
|
-
|
|
30
|
-
### Step 1: Create the FlagSync client singleton
|
|
31
|
-
|
|
32
|
-
Initialize the client with your server-side SDK key:
|
|
33
|
-
|
|
34
|
-
```typescript
|
|
35
|
-
// lib/flagsync.ts
|
|
36
|
-
import { createFlagSyncClient } from '@flagsync/vercel-flags-sdk';
|
|
37
|
-
|
|
38
|
-
export const client = createFlagSyncClient({
|
|
39
|
-
sdkKey: process.env.FLAGSYNC_SDK_KEY!,
|
|
40
|
-
});
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
### Step 2: Set up user identification
|
|
44
|
-
|
|
45
|
-
> [!NOTE]
|
|
46
|
-
> Feature flags in FlagSync use user context (e.g. via `identify`) to enable personalized experiences.
|
|
47
|
-
|
|
48
|
-
The `identify` function defines how users are identified (e.g., via cookies, headers, or session data). See [Identify](#identify) for more details.
|
|
49
|
-
|
|
50
|
-
```typescript
|
|
51
|
-
// lib/flagsync.ts
|
|
52
|
-
import {
|
|
53
|
-
createIdentify,
|
|
54
|
-
createFlagSyncClient,
|
|
55
|
-
} from '@flagsync/vercel-flags-sdk';
|
|
56
|
-
|
|
57
|
-
export const identify = createIdentify(({ cookies }) => {
|
|
58
|
-
const userId = cookies.get('user-id')?.value; // Authenticated user ID
|
|
59
|
-
const visitorId = cookies.get('visitor-id')?.value; // Unauthenticated visitor ID
|
|
60
|
-
return {
|
|
61
|
-
key: userId ?? visitorId ?? 'anonymous' // Fallback to 'anonymous'
|
|
62
|
-
};
|
|
63
|
-
});
|
|
64
|
-
```
|
|
65
|
-
> [!CAUTION]
|
|
66
|
-
> While `anonymous` user contexts are supported, always provide a unique identifier (even for unauthenticated users) to ensure consistent flag evaluation.
|
|
67
|
-
>
|
|
68
|
-
> See [Identify](#identify) for more details.
|
|
69
|
-
|
|
70
|
-
### Step 3: Define a feature flag
|
|
71
|
-
|
|
72
|
-
Create a flag definition using the shared `client` and `identify` function:
|
|
73
|
-
|
|
74
|
-
```typescript
|
|
75
|
-
// app/dashboard/flags.ts
|
|
76
|
-
import { flag } from 'flags/next';
|
|
77
|
-
import { client, identify } from '@/lib/flagsync';
|
|
78
|
-
import { createStringFlagAdaptor } from '@flagsync/vercel-flags-sdk';
|
|
79
|
-
|
|
80
|
-
export const dashboardFlag = flag<string>({
|
|
81
|
-
identify, // Links flag to user context
|
|
82
|
-
key: 'dashboardFlag', // Unique flag key
|
|
83
|
-
adapter: createStringFlagAdaptor(client), // Retrieves the flag with type safety
|
|
84
|
-
});
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### Step 4: Use the flag in your app
|
|
88
|
-
|
|
89
|
-
Now you can use `dashboardFlag` in your Server Components:
|
|
90
|
-
|
|
91
|
-
```typescript jsx
|
|
92
|
-
// app/dashboard/page.tsx
|
|
93
|
-
|
|
94
|
-
import { dashboardFlag } from '@/app/dashboard/flags';
|
|
95
|
-
|
|
96
|
-
export default async function DashboardPage() {
|
|
97
|
-
const dashboard = await dashboardFlag();
|
|
98
|
-
|
|
99
|
-
return (
|
|
100
|
-
<div>The value of {dashboardFlag.key} is {dashboard}</div>
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
## Type-Safe Feature Flags
|
|
106
|
-
|
|
107
|
-
FlagSync supports multiple flag types for different use cases. Use the type-specific adapter depending on your flag type:
|
|
108
|
-
|
|
109
|
-
- `createBoolFlagAdaptor`: For boolean flags
|
|
110
|
-
- `createStringFlagAdaptor`: For string flags
|
|
111
|
-
- `createNumberFlagAdaptor`: For numeric flags
|
|
112
|
-
- `createJsonFlagAdaptor`: For JSON object flags
|
|
113
|
-
|
|
114
|
-
```typescript
|
|
115
|
-
// app/<route>/flags.ts
|
|
116
|
-
import { client, identify } from '@/lib/flagsync';
|
|
117
|
-
import {
|
|
118
|
-
createBoolFlagAdaptor,
|
|
119
|
-
createJsonFlagAdaptor,
|
|
120
|
-
createNumberFlagAdaptor,
|
|
121
|
-
createStringFlagAdaptor,
|
|
122
|
-
} from '@flagsync/vercel-flags-sdk';
|
|
123
|
-
import { flag } from '@vercel/flags';
|
|
124
|
-
|
|
125
|
-
// Boolean flag for feature toggles
|
|
126
|
-
export const betaFeatureFlag = flag<boolean>({
|
|
127
|
-
identify,
|
|
128
|
-
key: 'beta-feature-enabled',
|
|
129
|
-
adapter: createBoolFlagAdaptor(client),
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
// String flag for UI variants
|
|
133
|
-
export const heroCtaFlag = flag<string>({
|
|
134
|
-
identify,
|
|
135
|
-
key: 'hero-cta',
|
|
136
|
-
adapter: createStringFlagAdaptor(client),
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
// Number flag for pricing tiers
|
|
140
|
-
export const discountFlag = flag<number>({
|
|
141
|
-
identify,
|
|
142
|
-
key: 'price-discount',
|
|
143
|
-
adapter: createNumberFlagAdaptor(client),
|
|
144
|
-
});
|
|
10
|
+
- Compatible with Node.js 16+ and ES5
|
|
11
|
+
- TypeScript is fully supported
|
|
145
12
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
enabled: boolean;
|
|
149
|
-
limits: { requests: number; storage: number };
|
|
150
|
-
}>({
|
|
151
|
-
identify,
|
|
152
|
-
key: 'feature-config',
|
|
153
|
-
adapter: createJsonFlagAdaptor(client),
|
|
154
|
-
});
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
## Identify
|
|
158
|
-
|
|
159
|
-
The `identify` function links feature flags to user contexts in FlagSync by returning an `FsUserContext` object.
|
|
160
|
-
|
|
161
|
-
```typescript
|
|
162
|
-
type FsUserContext = {
|
|
163
|
-
key: string; // Unique identifier for the user
|
|
164
|
-
attributes?: Record<string, string | number | boolean>; // Optional custom data (used in individual targeting)
|
|
165
|
-
};
|
|
166
|
-
```
|
|
167
|
-
* `key`: A unique ID for the user (required)
|
|
168
|
-
* `attributes`: Optional metadata (e.g., user agent, region, role, department) to personalize flag evaluations.
|
|
169
|
-
|
|
170
|
-
> [!IMPORTANT]
|
|
171
|
-
> User contexts enable personalized flag evaluations via [Individual Targeting](https://docs.flagsync.com/sdks/sdk-concepts/flag-evaluation#does-the-flag-have-any-individual-targeting-rules), and consistent experiences during [Percentage Rollouts](https://docs.flagsync.com/sdks/sdk-concepts/flag-evaluation#does-the-flag-have-a-percentage-rollout).
|
|
172
|
-
|
|
173
|
-
We recommend:
|
|
174
|
-
1. Using a helper function (getFlagSyncUserContext) to build the full context.
|
|
175
|
-
2. Setting cookies in middleware for the key.
|
|
176
|
-
|
|
177
|
-
Here's how:
|
|
178
|
-
|
|
179
|
-
### Step 1: Define a helper function
|
|
180
|
-
|
|
181
|
-
Create a utility to build the user context:
|
|
182
|
-
|
|
183
|
-
```typescript
|
|
184
|
-
// lib/flagsync.user-context.ts
|
|
185
|
-
import type { ReadonlyRequestCookies, ReadonlyHeaders } from 'flags';
|
|
186
|
-
import { dedupe } from 'flags/next';
|
|
187
|
-
import { nanoid } from 'nanoid';
|
|
188
|
-
import type { NextRequest } from 'next/server';
|
|
189
|
-
|
|
190
|
-
const generateId = dedupe(async () => nanoid());
|
|
191
|
-
|
|
192
|
-
export const getFlagSyncUserContext = async (
|
|
193
|
-
cookies: ReadonlyRequestCookies | NextRequest['cookies'],
|
|
194
|
-
headers: ReadonlyHeaders | NextRequest['headers'],
|
|
195
|
-
) => {
|
|
196
|
-
const userId = cookies.get('user-id')?.value; // Authenticated user
|
|
197
|
-
const visitorId = cookies.get('visitor-id')?.value; // Anonymous visitor
|
|
198
|
-
|
|
199
|
-
return {
|
|
200
|
-
key: userId ?? visitorId ?? (await generateId()), // Fallback to new ID
|
|
201
|
-
attributes: {
|
|
202
|
-
userAgent: headers.get('user-agent') || 'unknown', // Browser info
|
|
203
|
-
region: headers.get('x-region-code') || 'default', // Custom header
|
|
204
|
-
},
|
|
205
|
-
};
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
```
|
|
209
|
-
### Step 2: Set up identification
|
|
210
|
-
|
|
211
|
-
Use the helper in `identify`:
|
|
212
|
-
|
|
213
|
-
```typescript
|
|
214
|
-
// lib/flagsync.ts
|
|
215
|
-
import { createIdentify, createFlagSyncClient } from '@flagsync/vercel-flags-sdk';
|
|
216
|
-
import { getFlagSyncUserContext } from '@lib/flagsync.user-context';
|
|
217
|
-
|
|
218
|
-
export const identify = createIdentify(({ cookies, headers }) => {
|
|
219
|
-
return getFlagSyncUserContext(cookies, headers);
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
export const client = createFlagSyncClient({
|
|
223
|
-
sdkKey: process.env.FLAGSYNC_SDK_KEY!,
|
|
224
|
-
});
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
### Step 3: Handle cookies in middleware
|
|
228
|
-
|
|
229
|
-
```typescript
|
|
230
|
-
// middleware.ts
|
|
231
|
-
import { NextRequest, NextResponse } from 'next/server';
|
|
232
|
-
import { nanoid } from 'nanoid';
|
|
233
|
-
|
|
234
|
-
export async function middleware(request: NextRequest) {
|
|
235
|
-
const response = NextResponse.next();
|
|
236
|
-
|
|
237
|
-
// Example: Get userId from a JWT or API call (replace with your logic)
|
|
238
|
-
const jwt = request.cookies.get('jwt')?.value;
|
|
239
|
-
let userId: string | undefined;
|
|
240
|
-
if (jwt) {
|
|
241
|
-
userId = 'user@example.com'; // Stub: e.g., await decodeJwt(jwt).email
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
if (userId) {
|
|
245
|
-
response.cookies.set('user-id', userId, { maxAge: 60 * 60 * 24 * 7 });
|
|
246
|
-
} else {
|
|
247
|
-
const visitorId = request.cookies.get('visitor-id')?.value ?? nanoid();
|
|
248
|
-
response.cookies.set('visitor-id', visitorId, { maxAge: 60 * 60 * 24 * 365 });
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
return response;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
export const config = {
|
|
255
|
-
matcher: [
|
|
256
|
-
/*
|
|
257
|
-
* Match all request paths except for the ones starting with:
|
|
258
|
-
* - api (API routes)
|
|
259
|
-
* - _next/static (static files)
|
|
260
|
-
* - _next/image (image optimization files)
|
|
261
|
-
* - favicon.ico (favicon file)
|
|
262
|
-
*/
|
|
263
|
-
{
|
|
264
|
-
source: '/((?!api|_next/static|_next/image|favicon.ico).*)',
|
|
265
|
-
missing: [
|
|
266
|
-
{ type: 'header', key: 'next-router-prefetch' },
|
|
267
|
-
{ type: 'header', key: 'purpose', value: 'prefetch' },
|
|
268
|
-
],
|
|
269
|
-
},
|
|
270
|
-
],
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
## Next Steps
|
|
276
|
-
|
|
277
|
-
- Configure flags in the [FlagSync dashboard](https://www.flagsync.com/dashboard).
|
|
278
|
-
- Explore the [Docs](https://docs.flagsync.com/) for information on how to use FlagSync.
|
|
279
|
-
|
|
280
|
-
## Environment Variables
|
|
281
|
-
|
|
282
|
-
Required environment variables:
|
|
283
|
-
|
|
284
|
-
- `FLAGSYNC_SDK_KEY`: Your server-side FlagSync SDK key (required)
|
|
285
|
-
|
|
286
|
-
### License
|
|
287
|
-
|
|
288
|
-
[](https://www.apache.org/licenses/LICENSE-2.0)
|
|
13
|
+
## Getting Started
|
|
14
|
+
Refer to the [SDK documentation](https://docs.flagsync.com/sdks-server-side/nextjs) for setup instructions and usage details.
|
package/dist/index.cjs
CHANGED
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/adapter.ts","../src/identify.ts"],"sourcesContent":["export type {\n CustomAttributes,\n CustomAttributeValue,\n FsConfig,\n FsClient,\n LogLevel,\n FsUserContext,\n} from '@flagsync/node-sdk';\n\nexport { SyncType } from '@flagsync/node-sdk';\n\nexport type { JsonObject } from './types';\n\nexport {\n createFlagSyncClient,\n createFlagSyncAdapter,\n createBoolFlagAdaptor,\n createStringFlagAdaptor,\n createJsonFlagAdaptor,\n createNumberFlagAdaptor,\n} from './adapter';\n\nexport { createIdentify } from './identify';\n","import {\n FlagSyncFactory,\n FsClient,\n type FsConfig,\n type FsUserContext,\n} from '@flagsync/node-sdk';\nimport type { Adapter } from '@vercel/flags';\n\nimport { JsonObject } from './types';\n\n/**\n * Creates a FlagSync client instance that can be used across multiple feature flags.\n * This function should be called once to create a singleton client for your application.\n */\nexport function createFlagSyncClient(config: FsConfig): FsClient {\n const instance = FlagSyncFactory({\n ...config,\n metadata: {\n sdkName: '@flagsync/nextjs-sdk',\n sdkVersion: '0.
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/adapter.ts","../src/identify.ts"],"sourcesContent":["export type {\n CustomAttributes,\n CustomAttributeValue,\n FsConfig,\n FsClient,\n LogLevel,\n FsUserContext,\n} from '@flagsync/node-sdk';\n\nexport { SyncType } from '@flagsync/node-sdk';\n\nexport type { JsonObject } from './types';\n\nexport {\n createFlagSyncClient,\n createFlagSyncAdapter,\n createBoolFlagAdaptor,\n createStringFlagAdaptor,\n createJsonFlagAdaptor,\n createNumberFlagAdaptor,\n} from './adapter';\n\nexport { createIdentify } from './identify';\n","import {\n FlagSyncFactory,\n FsClient,\n type FsConfig,\n type FsUserContext,\n} from '@flagsync/node-sdk';\nimport type { Adapter } from '@vercel/flags';\n\nimport { JsonObject } from './types';\n\n/**\n * Creates a FlagSync client instance that can be used across multiple feature flags.\n * This function should be called once to create a singleton client for your application.\n */\nexport function createFlagSyncClient(config: FsConfig): FsClient {\n const instance = FlagSyncFactory({\n ...config,\n metadata: {\n sdkName: '@flagsync/nextjs-sdk',\n sdkVersion: '0.3.0',\n },\n });\n return instance.client();\n}\n\n/**\n * Creates an adapter factory that integrates FlagSync with Vercel's feature flag system.\n * This adapter handles the communication between your application and the FlagSync service.\n */\nexport function createFlagSyncAdapter(client: FsClient) {\n let isReady = false;\n\n /**\n * Ensures the FlagSync client is ready before making any flag decisions.\n * This is called internally before each flag evaluation.\n */\n const ensureReady = async () => {\n if (!isReady) {\n await client.waitForReady();\n isReady = true;\n }\n };\n\n /**\n * Creates a typed adapter instance for a specific flag value type.\n */\n return function flagSyncAdapter<ValueType>(): Adapter<\n ValueType,\n FsUserContext\n > {\n return {\n /**\n * Evaluates a feature flag for a given context and returns its value.\n */\n async decide({ key, entities }) {\n await ensureReady();\n\n const userContext: FsUserContext = {\n key: 'anonymous',\n ...(entities ?? {}),\n };\n\n return client.flag<ValueType>(userContext, key);\n },\n };\n };\n}\n\n/** Creates an adapter for string-typed flags */\nexport const createStringFlagAdaptor = (\n client: FsClient,\n): Adapter<string, FsUserContext> => createFlagSyncAdapter(client)<string>();\n\n/** Creates an adapter for boolean-typed flags */\nexport const createBoolFlagAdaptor = (\n client: FsClient,\n): Adapter<boolean, FsUserContext> => createFlagSyncAdapter(client)<boolean>();\n\n/** Creates an adapter for number-typed flags */\nexport const createNumberFlagAdaptor = (\n client: FsClient,\n): Adapter<number, FsUserContext> => createFlagSyncAdapter(client)<number>();\n\n/** Creates an adapter for JSON object-typed flags */\nexport const createJsonFlagAdaptor = (\n client: FsClient,\n): Adapter<JsonObject, FsUserContext> =>\n createFlagSyncAdapter(client)<JsonObject>();\n","import { FsUserContext } from '@flagsync/node-sdk';\nimport { Identify } from '@vercel/flags';\n\ntype ExtractParams<T> = T extends (params: infer P) => any ? P : never;\n\nexport const createIdentify =\n (\n callback: (\n params: ExtractParams<Identify<FsUserContext>>,\n ) => Promise<FsUserContext> | FsUserContext,\n ): Identify<FsUserContext> =>\n (params) =>\n callback(params);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,IAAAA,mBAAyB;;;ACTzB,sBAKO;AASA,SAAS,qBAAqB,QAA4B;AAC/D,QAAM,eAAW,iCAAgB;AAAA,IAC/B,GAAG;AAAA,IACH,UAAU;AAAA,MACR,SAAS;AAAA,MACT,YAAY;AAAA,IACd;AAAA,EACF,CAAC;AACD,SAAO,SAAS,OAAO;AACzB;AAMO,SAAS,sBAAsB,QAAkB;AACtD,MAAI,UAAU;AAMd,QAAM,cAAc,YAAY;AAC9B,QAAI,CAAC,SAAS;AACZ,YAAM,OAAO,aAAa;AAC1B,gBAAU;AAAA,IACZ;AAAA,EACF;AAKA,SAAO,SAAS,kBAGd;AACA,WAAO;AAAA;AAAA;AAAA;AAAA,MAIL,MAAM,OAAO,EAAE,KAAK,SAAS,GAAG;AAC9B,cAAM,YAAY;AAElB,cAAM,cAA6B;AAAA,UACjC,KAAK;AAAA,UACL,GAAI,YAAY,CAAC;AAAA,QACnB;AAEA,eAAO,OAAO,KAAgB,aAAa,GAAG;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AACF;AAGO,IAAM,0BAA0B,CACrC,WACmC,sBAAsB,MAAM,EAAU;AAGpE,IAAM,wBAAwB,CACnC,WACoC,sBAAsB,MAAM,EAAW;AAGtE,IAAM,0BAA0B,CACrC,WACmC,sBAAsB,MAAM,EAAU;AAGpE,IAAM,wBAAwB,CACnC,WAEA,sBAAsB,MAAM,EAAc;;;AClFrC,IAAM,iBACX,CACE,aAIF,CAAC,WACC,SAAS,MAAM;","names":["import_node_sdk"]}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/adapter.ts","../src/identify.ts"],"sourcesContent":["export type {\n CustomAttributes,\n CustomAttributeValue,\n FsConfig,\n FsClient,\n LogLevel,\n FsUserContext,\n} from '@flagsync/node-sdk';\n\nexport { SyncType } from '@flagsync/node-sdk';\n\nexport type { JsonObject } from './types';\n\nexport {\n createFlagSyncClient,\n createFlagSyncAdapter,\n createBoolFlagAdaptor,\n createStringFlagAdaptor,\n createJsonFlagAdaptor,\n createNumberFlagAdaptor,\n} from './adapter';\n\nexport { createIdentify } from './identify';\n","import {\n FlagSyncFactory,\n FsClient,\n type FsConfig,\n type FsUserContext,\n} from '@flagsync/node-sdk';\nimport type { Adapter } from '@vercel/flags';\n\nimport { JsonObject } from './types';\n\n/**\n * Creates a FlagSync client instance that can be used across multiple feature flags.\n * This function should be called once to create a singleton client for your application.\n */\nexport function createFlagSyncClient(config: FsConfig): FsClient {\n const instance = FlagSyncFactory({\n ...config,\n metadata: {\n sdkName: '@flagsync/nextjs-sdk',\n sdkVersion: '0.
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/adapter.ts","../src/identify.ts"],"sourcesContent":["export type {\n CustomAttributes,\n CustomAttributeValue,\n FsConfig,\n FsClient,\n LogLevel,\n FsUserContext,\n} from '@flagsync/node-sdk';\n\nexport { SyncType } from '@flagsync/node-sdk';\n\nexport type { JsonObject } from './types';\n\nexport {\n createFlagSyncClient,\n createFlagSyncAdapter,\n createBoolFlagAdaptor,\n createStringFlagAdaptor,\n createJsonFlagAdaptor,\n createNumberFlagAdaptor,\n} from './adapter';\n\nexport { createIdentify } from './identify';\n","import {\n FlagSyncFactory,\n FsClient,\n type FsConfig,\n type FsUserContext,\n} from '@flagsync/node-sdk';\nimport type { Adapter } from '@vercel/flags';\n\nimport { JsonObject } from './types';\n\n/**\n * Creates a FlagSync client instance that can be used across multiple feature flags.\n * This function should be called once to create a singleton client for your application.\n */\nexport function createFlagSyncClient(config: FsConfig): FsClient {\n const instance = FlagSyncFactory({\n ...config,\n metadata: {\n sdkName: '@flagsync/nextjs-sdk',\n sdkVersion: '0.3.0',\n },\n });\n return instance.client();\n}\n\n/**\n * Creates an adapter factory that integrates FlagSync with Vercel's feature flag system.\n * This adapter handles the communication between your application and the FlagSync service.\n */\nexport function createFlagSyncAdapter(client: FsClient) {\n let isReady = false;\n\n /**\n * Ensures the FlagSync client is ready before making any flag decisions.\n * This is called internally before each flag evaluation.\n */\n const ensureReady = async () => {\n if (!isReady) {\n await client.waitForReady();\n isReady = true;\n }\n };\n\n /**\n * Creates a typed adapter instance for a specific flag value type.\n */\n return function flagSyncAdapter<ValueType>(): Adapter<\n ValueType,\n FsUserContext\n > {\n return {\n /**\n * Evaluates a feature flag for a given context and returns its value.\n */\n async decide({ key, entities }) {\n await ensureReady();\n\n const userContext: FsUserContext = {\n key: 'anonymous',\n ...(entities ?? {}),\n };\n\n return client.flag<ValueType>(userContext, key);\n },\n };\n };\n}\n\n/** Creates an adapter for string-typed flags */\nexport const createStringFlagAdaptor = (\n client: FsClient,\n): Adapter<string, FsUserContext> => createFlagSyncAdapter(client)<string>();\n\n/** Creates an adapter for boolean-typed flags */\nexport const createBoolFlagAdaptor = (\n client: FsClient,\n): Adapter<boolean, FsUserContext> => createFlagSyncAdapter(client)<boolean>();\n\n/** Creates an adapter for number-typed flags */\nexport const createNumberFlagAdaptor = (\n client: FsClient,\n): Adapter<number, FsUserContext> => createFlagSyncAdapter(client)<number>();\n\n/** Creates an adapter for JSON object-typed flags */\nexport const createJsonFlagAdaptor = (\n client: FsClient,\n): Adapter<JsonObject, FsUserContext> =>\n createFlagSyncAdapter(client)<JsonObject>();\n","import { FsUserContext } from '@flagsync/node-sdk';\nimport { Identify } from '@vercel/flags';\n\ntype ExtractParams<T> = T extends (params: infer P) => any ? P : never;\n\nexport const createIdentify =\n (\n callback: (\n params: ExtractParams<Identify<FsUserContext>>,\n ) => Promise<FsUserContext> | FsUserContext,\n ): Identify<FsUserContext> =>\n (params) =>\n callback(params);\n"],"mappings":";AASA,SAAS,gBAAgB;;;ACTzB;AAAA,EACE;AAAA,OAIK;AASA,SAAS,qBAAqB,QAA4B;AAC/D,QAAM,WAAW,gBAAgB;AAAA,IAC/B,GAAG;AAAA,IACH,UAAU;AAAA,MACR,SAAS;AAAA,MACT,YAAY;AAAA,IACd;AAAA,EACF,CAAC;AACD,SAAO,SAAS,OAAO;AACzB;AAMO,SAAS,sBAAsB,QAAkB;AACtD,MAAI,UAAU;AAMd,QAAM,cAAc,YAAY;AAC9B,QAAI,CAAC,SAAS;AACZ,YAAM,OAAO,aAAa;AAC1B,gBAAU;AAAA,IACZ;AAAA,EACF;AAKA,SAAO,SAAS,kBAGd;AACA,WAAO;AAAA;AAAA;AAAA;AAAA,MAIL,MAAM,OAAO,EAAE,KAAK,SAAS,GAAG;AAC9B,cAAM,YAAY;AAElB,cAAM,cAA6B;AAAA,UACjC,KAAK;AAAA,UACL,GAAI,YAAY,CAAC;AAAA,QACnB;AAEA,eAAO,OAAO,KAAgB,aAAa,GAAG;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AACF;AAGO,IAAM,0BAA0B,CACrC,WACmC,sBAAsB,MAAM,EAAU;AAGpE,IAAM,wBAAwB,CACnC,WACoC,sBAAsB,MAAM,EAAW;AAGtE,IAAM,0BAA0B,CACrC,WACmC,sBAAsB,MAAM,EAAU;AAGpE,IAAM,wBAAwB,CACnC,WAEA,sBAAsB,MAAM,EAAc;;;AClFrC,IAAM,iBACX,CACE,aAIF,CAAC,WACC,SAAS,MAAM;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flagsync/nextjs-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "FlagSync adapter for Vercel's Flags SDK",
|
|
5
5
|
"author": "Mike Chabot",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"@vercel/flags": "^3.1.1"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@flagsync/node-sdk": "^0.
|
|
42
|
+
"@flagsync/node-sdk": "^0.3.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|