Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 24 additions & 0 deletions .changeset/bumpy-gifts-peel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
"@vercel/flags-core": minor
"@flags-sdk/vercel": minor
---

Allow specifying entities type when creating clients

You can now create clients while specifying the entities type:

```ts
type Entities = { user: { id: string, name?: string } }
const client = createClient<Entities>('')
client.evaluate('flagKey', undefined, { user: { id: '' } }) // uses Entities type for context
```

You can still narrow the entities type when evaluating flags:

```ts
client.evaluate<{ user: { id: string, name: string } }>(
'flagKey',
false,
{ user: { id: '', name: '' } } // uses custom entities type
)
```
14 changes: 7 additions & 7 deletions packages/adapter-vercel/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ export function createVercelAdapter(
? createClient(sdkKeyOrFlagsClient)
: sdkKeyOrFlagsClient;

return function vercelAdapter<ValueType, EntitiesType>(): Adapter<
return function vercelAdapter<
ValueType,
EntitiesType
> {
EntitiesType extends Record<string, unknown>,
>(): Adapter<ValueType, EntitiesType> {
return {
origin: flagsClient.origin,
config: { reportValue: false },
async decide({ key, entities, headers }): Promise<ValueType> {
async decide({ key, entities }): Promise<ValueType> {
const evaluationResult = await flagsClient.evaluate<
ValueType,
EntitiesType
Expand Down Expand Up @@ -75,10 +75,10 @@ export function resetDefaultVercelAdapter() {
*
*/
// This is initialized lazily to avoid warning when it is not actually used and env vars are missing.
export function vercelAdapter<ValueType, EntitiesType>(): Adapter<
export function vercelAdapter<
ValueType,
EntitiesType
> {
EntitiesType extends Record<string, unknown>,
>(): Adapter<ValueType, EntitiesType> {
if (!defaultVercelAdapter) {
defaultVercelAdapter = createVercelAdapter(flagsClient);
}
Expand Down
6 changes: 3 additions & 3 deletions packages/vercel-flags-core/src/create-raw-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ export function createCreateRawClient(fns: {
evaluate: typeof evaluate;
getDatafile: typeof getDatafile;
}) {
return function createRawClient({
return function createRawClient<Entities = Record<string, unknown>>({
controller,
origin,
}: {
controller: ControllerInterface;
origin?: { provider: string; sdkKey: string };
}): FlagsClient {
}): FlagsClient<Entities> {
const id = idCount++;
controllerInstanceMap.set(id, {
controller,
Expand Down Expand Up @@ -92,7 +92,7 @@ export function createCreateRawClient(fns: {
getFallbackDatafile: (): Promise<BundledDefinitions> => {
return fns.getFallbackDatafile(id);
},
evaluate: async <T = Value, E = Record<string, unknown>>(
evaluate: async <T = Value, E = Entities>(
flagKey: string,
defaultValue?: T,
entities?: E,
Expand Down
10 changes: 5 additions & 5 deletions packages/vercel-flags-core/src/index.make.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@ export function make(
): {
flagsClient: FlagsClient;
resetDefaultFlagsClient: () => void;
createClient: (
createClient: <Entities = Record<string, unknown>>(
sdkKeyOrConnectionString: string,
options?: CreateClientOptions,
) => FlagsClient;
) => FlagsClient<Entities>;
} {
let _defaultFlagsClient: FlagsClient | null = null;

// Insights
// - data source must specify the environment & projectId as sdkKey has that info
// - "reuse" functionality relies on the data source having the data for all envs
function createClient(
function createClient<Entities = Record<string, unknown>>(
sdkKeyOrConnectionString: string,
options?: CreateClientOptions,
): FlagsClient {
): FlagsClient<Entities> {
if (!sdkKeyOrConnectionString)
throw new Error('@vercel/flags-core: Missing sdkKey');

Expand All @@ -51,7 +51,7 @@ export function make(

// sdk key contains the environment
const controller = new Controller({ sdkKey, ...options });
return createRawClient({
return createRawClient<Entities>({
controller,
origin: { provider: 'vercel', sdkKey },
});
Expand Down
4 changes: 2 additions & 2 deletions packages/vercel-flags-core/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ControllerInstance } from './controller-fns';

Check warning on line 1 in packages/vercel-flags-core/src/types.ts

View workflow job for this annotation

GitHub Actions / Biome

lint/correctness/noUnusedImports

This import is unused.

/**
* Options for stream connection behavior
Expand Down Expand Up @@ -120,7 +120,7 @@
/**
* A client for Vercel Flags
*/
export type FlagsClient = {
export type FlagsClient<Entities = Record<string, unknown>> = {
/**
* Origin information for this client (provider and sdkKey)
*/
Expand All @@ -138,7 +138,7 @@
* @param entities
* @returns
*/
evaluate: <T = Value, E = Record<string, unknown>>(
evaluate: <T = Value, E extends Entities = Entities>(
flagKey: string,
defaultValue?: T,
entities?: E,
Expand Down
Loading