@flags-sdk/vercel 0.1.8 → 1.0.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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @flags-sdk/vercel
2
2
 
3
+ ## 1.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - c71729b: See http://vercel.com/docs/flags/vercel-flags for more information.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [795dfd4]
12
+ - Updated dependencies [c71729b]
13
+ - flags@4.0.3
14
+ - @vercel/flags-core@1.0.0
15
+
3
16
  ## 0.1.8
4
17
 
5
18
  ### Patch Changes
package/README.md CHANGED
@@ -1 +1,28 @@
1
1
  # `@flags-sdk/vercel`
2
+
3
+ The [Vercel adapter](https://flags-sdk.dev/providers/vercel) for the [Flags SDK](https://flags-sdk.dev/) connects your feature flags to [Vercel Flags](https://vercel.com/docs/flags/vercel-flags), the feature flag platform built into Vercel. Manage flags, define targeting rules, roll out gradually, and run experiments directly from the Vercel Dashboard.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm i flags @flags-sdk/vercel @vercel/flags-core
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```ts
14
+ import { flag } from 'flags/next';
15
+ import { vercelAdapter } from '@flags-sdk/vercel';
16
+
17
+ export const exampleFlag = flag({
18
+ key: 'example-flag',
19
+ adapter: vercelAdapter(),
20
+ });
21
+ ```
22
+
23
+ ## Documentation
24
+
25
+ - [Getting Started with Vercel Flags](https://vercel.com/docs/flags/vercel-flags/quickstart)
26
+ - [Vercel Flags](https://vercel.com/docs/flags/vercel-flags)
27
+ - [@flags-sdk/vercel](https://flags-sdk.dev/providers/vercel)
28
+ - [Flags SDK](https://flags-sdk.dev/)
package/dist/index.cjs CHANGED
@@ -3,27 +3,15 @@
3
3
 
4
4
 
5
5
 
6
-
7
6
  var _flagscore = require('@vercel/flags-core');
8
- function createVercelAdapter(connectionStringOrFlagsClient) {
9
- const flagsClient = typeof connectionStringOrFlagsClient === "string" ? _flagscore.createClientFromConnectionString.call(void 0, connectionStringOrFlagsClient) : connectionStringOrFlagsClient;
7
+ function createVercelAdapter(sdkKeyOrFlagsClient) {
8
+ const flagsClient2 = typeof sdkKeyOrFlagsClient === "string" ? _flagscore.createClient.call(void 0, sdkKeyOrFlagsClient) : sdkKeyOrFlagsClient;
10
9
  return function vercelAdapter2() {
11
10
  return {
12
- origin: {
13
- provider: "vercel",
14
- projectId: flagsClient.dataSource.projectId,
15
- env: flagsClient.environment
16
- },
11
+ origin: flagsClient2.origin,
17
12
  config: { reportValue: false },
18
13
  async decide({ key, entities, headers }) {
19
- const evaluationResultPromise = _flagscore.store.run(headers, async () => {
20
- return flagsClient.evaluate(
21
- key,
22
- void 0,
23
- entities
24
- );
25
- });
26
- const evaluationResult = await evaluationResultPromise;
14
+ const evaluationResult = await flagsClient2.evaluate(key, void 0, entities);
27
15
  if (evaluationResult.value === void 0) {
28
16
  throw new Error(
29
17
  evaluationResult.reason === _flagscore.Reason.ERROR && evaluationResult.errorMessage ? `flags: Could not evaluate flag "${key}". ${evaluationResult.errorMessage}` : `flags: Could not evaluate flag "${key}"`
@@ -40,13 +28,64 @@ function resetDefaultVercelAdapter() {
40
28
  }
41
29
  function vercelAdapter() {
42
30
  if (!defaultVercelAdapter) {
43
- defaultVercelAdapter = createVercelAdapter(_flagscore.getDefaultFlagsClient.call(void 0, ));
31
+ defaultVercelAdapter = createVercelAdapter(_flagscore.flagsClient);
44
32
  }
45
33
  return defaultVercelAdapter();
46
34
  }
35
+ var flagsClients = /* @__PURE__ */ new Map();
36
+ function getOrCreateClient(sdkKey) {
37
+ let client = flagsClients.get(sdkKey);
38
+ if (!client) {
39
+ client = _flagscore.createClient.call(void 0, sdkKey);
40
+ flagsClients.set(sdkKey, client);
41
+ }
42
+ return client;
43
+ }
44
+ function isVercelOrigin(origin) {
45
+ return typeof origin === "object" && origin !== null && "provider" in origin && origin.provider === "vercel" && "sdkKey" in origin && typeof origin.sdkKey === "string";
46
+ }
47
+ async function getProviderData(flags) {
48
+ const flagDefs = Object.values(flags).filter((i) => !Array.isArray(i));
49
+ const sdkKeys = /* @__PURE__ */ new Set();
50
+ for (const d of flagDefs) {
51
+ if (isVercelOrigin(d.origin)) {
52
+ sdkKeys.add(d.origin.sdkKey);
53
+ }
54
+ }
55
+ const projectIdBySdkKey = /* @__PURE__ */ new Map();
56
+ await Promise.all(
57
+ Array.from(sdkKeys).map(async (sdkKey) => {
58
+ const client = getOrCreateClient(sdkKey);
59
+ try {
60
+ const fallback = await client.getFallbackDatafile();
61
+ projectIdBySdkKey.set(sdkKey, fallback.projectId);
62
+ } catch (e) {
63
+ const datafile = await client.getDatafile();
64
+ projectIdBySdkKey.set(sdkKey, datafile.projectId);
65
+ }
66
+ })
67
+ );
68
+ const definitions = flagDefs.reduce((acc, d) => {
69
+ if (!isVercelOrigin(d.origin)) return acc;
70
+ const projectId = projectIdBySdkKey.get(d.origin.sdkKey);
71
+ acc[d.key] = {
72
+ options: d.options,
73
+ origin: {
74
+ provider: "vercel",
75
+ projectId
76
+ },
77
+ description: d.description,
78
+ defaultValue: d.defaultValue,
79
+ declaredInCode: true
80
+ };
81
+ return acc;
82
+ }, {});
83
+ return { definitions, hints: [] };
84
+ }
85
+
47
86
 
48
87
 
49
88
 
50
89
 
51
- exports.createVercelAdapter = createVercelAdapter; exports.resetDefaultVercelAdapter = resetDefaultVercelAdapter; exports.vercelAdapter = vercelAdapter;
90
+ exports.createVercelAdapter = createVercelAdapter; exports.getProviderData = getProviderData; exports.resetDefaultVercelAdapter = resetDefaultVercelAdapter; exports.vercelAdapter = vercelAdapter;
52
91
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["vercelAdapter"],"mappings":";AAAA;AAAA,EACE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAWA,SAAS,oBAEd,+BACA;AACA,QAAM,cACJ,OAAO,kCAAkC,WACrC,iCAAiC,6BAA6B,IAC9D;AAEN,SAAO,SAASA,iBAGd;AACA,WAAO;AAAA,MACL,QAAQ;AAAA,QACN,UAAU;AAAA,QACV,WAAW,YAAY,WAAW;AAAA,QAClC,KAAK,YAAY;AAAA,MACnB;AAAA,MACA,QAAQ,EAAE,aAAa,MAAM;AAAA,MAC7B,MAAM,OAAO,EAAE,KAAK,UAAU,QAAQ,GAAuB;AAC3D,cAAM,0BAA0B,MAAM,IAAI,SAAS,YAAY;AAC7D,iBAAO,YAAY;AAAA,YACjB;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF,CAAC;AAED,cAAM,mBAAmB,MAAM;AAC/B,YAAI,iBAAiB,UAAU,QAAW;AAExC,gBAAM,IAAI;AAAA,YACR,iBAAiB,WAAW,OAAO,SACjC,iBAAiB,eACf,mCAAmC,GAAG,MAAM,iBAAiB,YAAY,KACzE,mCAAmC,GAAG;AAAA,UAC5C;AAAA,QACF;AAIA,eAAO,iBAAiB;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAI;AAKG,SAAS,4BAA4B;AAC1C,yBAAuB;AACzB;AAOO,SAAS,gBAGd;AACA,MAAI,CAAC,sBAAsB;AACzB,2BAAuB,oBAAoB,sBAAsB,CAAC;AAAA,EACpE;AAEA,SAAO,qBAA8C;AACvD","sourcesContent":["import {\n createClientFromConnectionString,\n type FlagsClient,\n getDefaultFlagsClient,\n Reason,\n store,\n} from '@vercel/flags-core';\nimport type { Adapter, FlagDeclaration } from 'flags';\n\nexport type VercelAdapterDeclaration<ValueType, EntitiesType> = Omit<\n FlagDeclaration<ValueType, EntitiesType>,\n 'decide' | 'origin'\n>;\n\n/**\n * Allows creating a custom Vercel adapter for feature flags\n */\nexport function createVercelAdapter(\n // usually a connection string, but can also be a pre-configured FlagsClient\n connectionStringOrFlagsClient: string | FlagsClient,\n) {\n const flagsClient =\n typeof connectionStringOrFlagsClient === 'string'\n ? createClientFromConnectionString(connectionStringOrFlagsClient)\n : connectionStringOrFlagsClient;\n\n return function vercelAdapter<ValueType, EntitiesType>(): Adapter<\n ValueType,\n EntitiesType\n > {\n return {\n origin: {\n provider: 'vercel',\n projectId: flagsClient.dataSource.projectId,\n env: flagsClient.environment,\n },\n config: { reportValue: false },\n async decide({ key, entities, headers }): Promise<ValueType> {\n const evaluationResultPromise = store.run(headers, async () => {\n return flagsClient.evaluate<ValueType, EntitiesType>(\n key,\n undefined,\n entities,\n );\n });\n\n const evaluationResult = await evaluationResultPromise;\n if (evaluationResult.value === undefined) {\n // if there was no defaultValue we need to throw\n throw new Error(\n evaluationResult.reason === Reason.ERROR &&\n evaluationResult.errorMessage\n ? `flags: Could not evaluate flag \"${key}\". ${evaluationResult.errorMessage}`\n : `flags: Could not evaluate flag \"${key}\"`,\n );\n }\n\n // runs when the flag evaluates successfully or\n // when there was an error but the defaultValue was set\n return evaluationResult.value;\n },\n };\n };\n}\n\nlet defaultVercelAdapter: ReturnType<typeof createVercelAdapter> | undefined;\n\n/**\n * Internal function for testing purposes\n */\nexport function resetDefaultVercelAdapter() {\n defaultVercelAdapter = undefined;\n}\n\n/**\n * A default Vercel adapter for feature flags\n *\n */\n// This is initialized lazily to avoid warning when it is not actually used and env vars are missing.\nexport function vercelAdapter<ValueType, EntitiesType>(): Adapter<\n ValueType,\n EntitiesType\n> {\n if (!defaultVercelAdapter) {\n defaultVercelAdapter = createVercelAdapter(getDefaultFlagsClient());\n }\n\n return defaultVercelAdapter<ValueType, EntitiesType>();\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/work/flags/flags/packages/adapter-vercel/dist/index.cjs","../src/index.ts"],"names":["flagsClient","vercelAdapter"],"mappings":"AAAA;ACAA;AACE;AAEA;AACA;AAAA,+CACK;AAkBA,SAAS,mBAAA,CAEd,mBAAA,EACA;AACA,EAAA,MAAMA,aAAAA,EACJ,OAAO,oBAAA,IAAwB,SAAA,EAC3B,qCAAA,mBAAgC,EAAA,EAChC,mBAAA;AAEN,EAAA,OAAO,SAASC,cAAAA,CAAAA,EAGd;AACA,IAAA,OAAO;AAAA,MACL,MAAA,EAAQD,YAAAA,CAAY,MAAA;AAAA,MACpB,MAAA,EAAQ,EAAE,WAAA,EAAa,MAAM,CAAA;AAAA,MAC7B,MAAM,MAAA,CAAO,EAAE,GAAA,EAAK,QAAA,EAAU,QAAQ,CAAA,EAAuB;AAC3D,QAAA,MAAM,iBAAA,EAAmB,MAAMA,YAAAA,CAAY,QAAA,CAGzC,GAAA,EAAK,KAAA,CAAA,EAAW,QAAQ,CAAA;AAE1B,QAAA,GAAA,CAAI,gBAAA,CAAiB,MAAA,IAAU,KAAA,CAAA,EAAW;AAExC,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,gBAAA,CAAiB,OAAA,IAAW,iBAAA,CAAO,MAAA,GACjC,gBAAA,CAAiB,aAAA,EACf,CAAA,gCAAA,EAAmC,GAAG,CAAA,GAAA,EAAM,gBAAA,CAAiB,YAAY,CAAA,EAAA;AAE/E,UAAA;AACF,QAAA;AAIwB,QAAA;AAC1B,MAAA;AACF,IAAA;AACF,EAAA;AACF;AAEI;AAKwC;AACnB,EAAA;AACzB;AAUE;AAC2B,EAAA;AAC6B,IAAA;AACxD,EAAA;AAEqD,EAAA;AACvD;AAEkD;AAEM;AAClB,EAAA;AACvB,EAAA;AACiB,IAAA;AACG,IAAA;AACjC,EAAA;AACO,EAAA;AACT;AAIoD;AAOM,EAAA;AAE1D;AAQyB;AAGyC,EAAA;AAGhC,EAAA;AACN,EAAA;AACM,IAAA;AACD,MAAA;AAC7B,IAAA;AACF,EAAA;AAEkD,EAAA;AACpC,EAAA;AAC8B,IAAA;AACD,MAAA;AACnC,MAAA;AACgD,QAAA;AACF,QAAA;AAC1C,MAAA;AACoC,QAAA;AACM,QAAA;AAClD,MAAA;AACD,IAAA;AACH,EAAA;AAEqE,EAAA;AAC7B,IAAA;AAEiB,IAAA;AAC1C,IAAA;AACA,MAAA;AACH,MAAA;AACI,QAAA;AACV,QAAA;AACF,MAAA;AACe,MAAA;AACC,MAAA;AACA,MAAA;AAClB,IAAA;AAEO,IAAA;AACJ,EAAA;AAE2B,EAAA;AAClC;ADhFkK;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/flags/flags/packages/adapter-vercel/dist/index.cjs","sourcesContent":[null,"import {\n createClient,\n type FlagsClient,\n flagsClient,\n Reason,\n} from '@vercel/flags-core';\nimport type {\n Adapter,\n FlagDeclaration,\n FlagDefinitionsType,\n FlagDefinitionType,\n ProviderData,\n} from 'flags';\nimport type { KeyedFlagDefinitionType } from 'flags/next';\n\nexport type VercelAdapterDeclaration<ValueType, EntitiesType> = Omit<\n FlagDeclaration<ValueType, EntitiesType>,\n 'decide' | 'origin'\n>;\n\n/**\n * Allows creating a custom Vercel adapter for feature flags\n */\nexport function createVercelAdapter(\n // usually a connection string, but can also be a pre-configured FlagsClient\n sdkKeyOrFlagsClient: string | FlagsClient,\n) {\n const flagsClient =\n typeof sdkKeyOrFlagsClient === 'string'\n ? createClient(sdkKeyOrFlagsClient)\n : sdkKeyOrFlagsClient;\n\n return function vercelAdapter<ValueType, EntitiesType>(): Adapter<\n ValueType,\n EntitiesType\n > {\n return {\n origin: flagsClient.origin,\n config: { reportValue: false },\n async decide({ key, entities, headers }): Promise<ValueType> {\n const evaluationResult = await flagsClient.evaluate<\n ValueType,\n EntitiesType\n >(key, undefined, entities);\n\n if (evaluationResult.value === undefined) {\n // if there was no defaultValue we need to throw\n throw new Error(\n evaluationResult.reason === Reason.ERROR &&\n evaluationResult.errorMessage\n ? `flags: Could not evaluate flag \"${key}\". ${evaluationResult.errorMessage}`\n : `flags: Could not evaluate flag \"${key}\"`,\n );\n }\n\n // runs when the flag evaluates successfully or\n // when there was an error but the defaultValue was set\n return evaluationResult.value;\n },\n };\n };\n}\n\nlet defaultVercelAdapter: ReturnType<typeof createVercelAdapter> | undefined;\n\n/**\n * Internal function for testing purposes\n */\nexport function resetDefaultVercelAdapter() {\n defaultVercelAdapter = undefined;\n}\n\n/**\n * A default Vercel adapter for feature flags\n *\n */\n// This is initialized lazily to avoid warning when it is not actually used and env vars are missing.\nexport function vercelAdapter<ValueType, EntitiesType>(): Adapter<\n ValueType,\n EntitiesType\n> {\n if (!defaultVercelAdapter) {\n defaultVercelAdapter = createVercelAdapter(flagsClient);\n }\n\n return defaultVercelAdapter<ValueType, EntitiesType>();\n}\n\nconst flagsClients = new Map<string, FlagsClient>();\n\nfunction getOrCreateClient(sdkKey: string): FlagsClient {\n let client = flagsClients.get(sdkKey);\n if (!client) {\n client = createClient(sdkKey);\n flagsClients.set(sdkKey, client);\n }\n return client;\n}\n\nfunction isVercelOrigin(\n origin: unknown,\n): origin is { provider: 'vercel'; sdkKey: string } {\n return (\n typeof origin === 'object' &&\n origin !== null &&\n 'provider' in origin &&\n (origin as Record<string, unknown>).provider === 'vercel' &&\n 'sdkKey' in origin &&\n typeof (origin as Record<string, unknown>).sdkKey === 'string'\n );\n}\n\nexport async function getProviderData(\n flags: Record<\n string,\n // accept an unknown array\n KeyedFlagDefinitionType | readonly unknown[]\n >,\n): Promise<ProviderData> {\n const flagDefs = Object.values(flags)\n // filter out precomputed arrays\n .filter((i): i is KeyedFlagDefinitionType => !Array.isArray(i));\n\n // Collect unique sdkKeys and resolve their projectIds\n const sdkKeys = new Set<string>();\n for (const d of flagDefs) {\n if (isVercelOrigin(d.origin)) {\n sdkKeys.add(d.origin.sdkKey);\n }\n }\n\n const projectIdBySdkKey = new Map<string, string>();\n await Promise.all(\n Array.from(sdkKeys).map(async (sdkKey) => {\n const client = getOrCreateClient(sdkKey);\n try {\n const fallback = await client.getFallbackDatafile();\n projectIdBySdkKey.set(sdkKey, fallback.projectId);\n } catch {\n const datafile = await client.getDatafile();\n projectIdBySdkKey.set(sdkKey, datafile.projectId);\n }\n }),\n );\n\n const definitions = flagDefs.reduce<FlagDefinitionsType>((acc, d) => {\n if (!isVercelOrigin(d.origin)) return acc;\n\n const projectId = projectIdBySdkKey.get(d.origin.sdkKey)!;\n acc[d.key] = {\n options: d.options,\n origin: {\n provider: 'vercel',\n projectId,\n },\n description: d.description,\n defaultValue: d.defaultValue,\n declaredInCode: true,\n } satisfies FlagDefinitionType;\n\n return acc;\n }, {});\n\n return { definitions, hints: [] };\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -1,11 +1,12 @@
1
1
  import { FlagsClient } from '@vercel/flags-core';
2
- import { FlagDeclaration, Adapter } from 'flags';
2
+ import { FlagDeclaration, Adapter, ProviderData } from 'flags';
3
+ import { KeyedFlagDefinitionType } from 'flags/next';
3
4
 
4
5
  type VercelAdapterDeclaration<ValueType, EntitiesType> = Omit<FlagDeclaration<ValueType, EntitiesType>, 'decide' | 'origin'>;
5
6
  /**
6
7
  * Allows creating a custom Vercel adapter for feature flags
7
8
  */
8
- declare function createVercelAdapter(connectionStringOrFlagsClient: string | FlagsClient): <ValueType, EntitiesType>() => Adapter<ValueType, EntitiesType>;
9
+ declare function createVercelAdapter(sdkKeyOrFlagsClient: string | FlagsClient): <ValueType, EntitiesType>() => Adapter<ValueType, EntitiesType>;
9
10
  /**
10
11
  * Internal function for testing purposes
11
12
  */
@@ -15,5 +16,6 @@ declare function resetDefaultVercelAdapter(): void;
15
16
  *
16
17
  */
17
18
  declare function vercelAdapter<ValueType, EntitiesType>(): Adapter<ValueType, EntitiesType>;
19
+ declare function getProviderData(flags: Record<string, KeyedFlagDefinitionType | readonly unknown[]>): Promise<ProviderData>;
18
20
 
19
- export { type VercelAdapterDeclaration, createVercelAdapter, resetDefaultVercelAdapter, vercelAdapter };
21
+ export { type VercelAdapterDeclaration, createVercelAdapter, getProviderData, resetDefaultVercelAdapter, vercelAdapter };
package/dist/index.d.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  import { FlagsClient } from '@vercel/flags-core';
2
- import { FlagDeclaration, Adapter } from 'flags';
2
+ import { FlagDeclaration, Adapter, ProviderData } from 'flags';
3
+ import { KeyedFlagDefinitionType } from 'flags/next';
3
4
 
4
5
  type VercelAdapterDeclaration<ValueType, EntitiesType> = Omit<FlagDeclaration<ValueType, EntitiesType>, 'decide' | 'origin'>;
5
6
  /**
6
7
  * Allows creating a custom Vercel adapter for feature flags
7
8
  */
8
- declare function createVercelAdapter(connectionStringOrFlagsClient: string | FlagsClient): <ValueType, EntitiesType>() => Adapter<ValueType, EntitiesType>;
9
+ declare function createVercelAdapter(sdkKeyOrFlagsClient: string | FlagsClient): <ValueType, EntitiesType>() => Adapter<ValueType, EntitiesType>;
9
10
  /**
10
11
  * Internal function for testing purposes
11
12
  */
@@ -15,5 +16,6 @@ declare function resetDefaultVercelAdapter(): void;
15
16
  *
16
17
  */
17
18
  declare function vercelAdapter<ValueType, EntitiesType>(): Adapter<ValueType, EntitiesType>;
19
+ declare function getProviderData(flags: Record<string, KeyedFlagDefinitionType | readonly unknown[]>): Promise<ProviderData>;
18
20
 
19
- export { type VercelAdapterDeclaration, createVercelAdapter, resetDefaultVercelAdapter, vercelAdapter };
21
+ export { type VercelAdapterDeclaration, createVercelAdapter, getProviderData, resetDefaultVercelAdapter, vercelAdapter };
package/dist/index.js CHANGED
@@ -1,29 +1,17 @@
1
1
  // src/index.ts
2
2
  import {
3
- createClientFromConnectionString,
4
- getDefaultFlagsClient,
5
- Reason,
6
- store
3
+ createClient,
4
+ flagsClient,
5
+ Reason
7
6
  } from "@vercel/flags-core";
8
- function createVercelAdapter(connectionStringOrFlagsClient) {
9
- const flagsClient = typeof connectionStringOrFlagsClient === "string" ? createClientFromConnectionString(connectionStringOrFlagsClient) : connectionStringOrFlagsClient;
7
+ function createVercelAdapter(sdkKeyOrFlagsClient) {
8
+ const flagsClient2 = typeof sdkKeyOrFlagsClient === "string" ? createClient(sdkKeyOrFlagsClient) : sdkKeyOrFlagsClient;
10
9
  return function vercelAdapter2() {
11
10
  return {
12
- origin: {
13
- provider: "vercel",
14
- projectId: flagsClient.dataSource.projectId,
15
- env: flagsClient.environment
16
- },
11
+ origin: flagsClient2.origin,
17
12
  config: { reportValue: false },
18
13
  async decide({ key, entities, headers }) {
19
- const evaluationResultPromise = store.run(headers, async () => {
20
- return flagsClient.evaluate(
21
- key,
22
- void 0,
23
- entities
24
- );
25
- });
26
- const evaluationResult = await evaluationResultPromise;
14
+ const evaluationResult = await flagsClient2.evaluate(key, void 0, entities);
27
15
  if (evaluationResult.value === void 0) {
28
16
  throw new Error(
29
17
  evaluationResult.reason === Reason.ERROR && evaluationResult.errorMessage ? `flags: Could not evaluate flag "${key}". ${evaluationResult.errorMessage}` : `flags: Could not evaluate flag "${key}"`
@@ -40,12 +28,63 @@ function resetDefaultVercelAdapter() {
40
28
  }
41
29
  function vercelAdapter() {
42
30
  if (!defaultVercelAdapter) {
43
- defaultVercelAdapter = createVercelAdapter(getDefaultFlagsClient());
31
+ defaultVercelAdapter = createVercelAdapter(flagsClient);
44
32
  }
45
33
  return defaultVercelAdapter();
46
34
  }
35
+ var flagsClients = /* @__PURE__ */ new Map();
36
+ function getOrCreateClient(sdkKey) {
37
+ let client = flagsClients.get(sdkKey);
38
+ if (!client) {
39
+ client = createClient(sdkKey);
40
+ flagsClients.set(sdkKey, client);
41
+ }
42
+ return client;
43
+ }
44
+ function isVercelOrigin(origin) {
45
+ return typeof origin === "object" && origin !== null && "provider" in origin && origin.provider === "vercel" && "sdkKey" in origin && typeof origin.sdkKey === "string";
46
+ }
47
+ async function getProviderData(flags) {
48
+ const flagDefs = Object.values(flags).filter((i) => !Array.isArray(i));
49
+ const sdkKeys = /* @__PURE__ */ new Set();
50
+ for (const d of flagDefs) {
51
+ if (isVercelOrigin(d.origin)) {
52
+ sdkKeys.add(d.origin.sdkKey);
53
+ }
54
+ }
55
+ const projectIdBySdkKey = /* @__PURE__ */ new Map();
56
+ await Promise.all(
57
+ Array.from(sdkKeys).map(async (sdkKey) => {
58
+ const client = getOrCreateClient(sdkKey);
59
+ try {
60
+ const fallback = await client.getFallbackDatafile();
61
+ projectIdBySdkKey.set(sdkKey, fallback.projectId);
62
+ } catch {
63
+ const datafile = await client.getDatafile();
64
+ projectIdBySdkKey.set(sdkKey, datafile.projectId);
65
+ }
66
+ })
67
+ );
68
+ const definitions = flagDefs.reduce((acc, d) => {
69
+ if (!isVercelOrigin(d.origin)) return acc;
70
+ const projectId = projectIdBySdkKey.get(d.origin.sdkKey);
71
+ acc[d.key] = {
72
+ options: d.options,
73
+ origin: {
74
+ provider: "vercel",
75
+ projectId
76
+ },
77
+ description: d.description,
78
+ defaultValue: d.defaultValue,
79
+ declaredInCode: true
80
+ };
81
+ return acc;
82
+ }, {});
83
+ return { definitions, hints: [] };
84
+ }
47
85
  export {
48
86
  createVercelAdapter,
87
+ getProviderData,
49
88
  resetDefaultVercelAdapter,
50
89
  vercelAdapter
51
90
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\n createClientFromConnectionString,\n type FlagsClient,\n getDefaultFlagsClient,\n Reason,\n store,\n} from '@vercel/flags-core';\nimport type { Adapter, FlagDeclaration } from 'flags';\n\nexport type VercelAdapterDeclaration<ValueType, EntitiesType> = Omit<\n FlagDeclaration<ValueType, EntitiesType>,\n 'decide' | 'origin'\n>;\n\n/**\n * Allows creating a custom Vercel adapter for feature flags\n */\nexport function createVercelAdapter(\n // usually a connection string, but can also be a pre-configured FlagsClient\n connectionStringOrFlagsClient: string | FlagsClient,\n) {\n const flagsClient =\n typeof connectionStringOrFlagsClient === 'string'\n ? createClientFromConnectionString(connectionStringOrFlagsClient)\n : connectionStringOrFlagsClient;\n\n return function vercelAdapter<ValueType, EntitiesType>(): Adapter<\n ValueType,\n EntitiesType\n > {\n return {\n origin: {\n provider: 'vercel',\n projectId: flagsClient.dataSource.projectId,\n env: flagsClient.environment,\n },\n config: { reportValue: false },\n async decide({ key, entities, headers }): Promise<ValueType> {\n const evaluationResultPromise = store.run(headers, async () => {\n return flagsClient.evaluate<ValueType, EntitiesType>(\n key,\n undefined,\n entities,\n );\n });\n\n const evaluationResult = await evaluationResultPromise;\n if (evaluationResult.value === undefined) {\n // if there was no defaultValue we need to throw\n throw new Error(\n evaluationResult.reason === Reason.ERROR &&\n evaluationResult.errorMessage\n ? `flags: Could not evaluate flag \"${key}\". ${evaluationResult.errorMessage}`\n : `flags: Could not evaluate flag \"${key}\"`,\n );\n }\n\n // runs when the flag evaluates successfully or\n // when there was an error but the defaultValue was set\n return evaluationResult.value;\n },\n };\n };\n}\n\nlet defaultVercelAdapter: ReturnType<typeof createVercelAdapter> | undefined;\n\n/**\n * Internal function for testing purposes\n */\nexport function resetDefaultVercelAdapter() {\n defaultVercelAdapter = undefined;\n}\n\n/**\n * A default Vercel adapter for feature flags\n *\n */\n// This is initialized lazily to avoid warning when it is not actually used and env vars are missing.\nexport function vercelAdapter<ValueType, EntitiesType>(): Adapter<\n ValueType,\n EntitiesType\n> {\n if (!defaultVercelAdapter) {\n defaultVercelAdapter = createVercelAdapter(getDefaultFlagsClient());\n }\n\n return defaultVercelAdapter<ValueType, EntitiesType>();\n}\n"],"mappings":";AAAA;AAAA,EACE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAWA,SAAS,oBAEd,+BACA;AACA,QAAM,cACJ,OAAO,kCAAkC,WACrC,iCAAiC,6BAA6B,IAC9D;AAEN,SAAO,SAASA,iBAGd;AACA,WAAO;AAAA,MACL,QAAQ;AAAA,QACN,UAAU;AAAA,QACV,WAAW,YAAY,WAAW;AAAA,QAClC,KAAK,YAAY;AAAA,MACnB;AAAA,MACA,QAAQ,EAAE,aAAa,MAAM;AAAA,MAC7B,MAAM,OAAO,EAAE,KAAK,UAAU,QAAQ,GAAuB;AAC3D,cAAM,0BAA0B,MAAM,IAAI,SAAS,YAAY;AAC7D,iBAAO,YAAY;AAAA,YACjB;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF,CAAC;AAED,cAAM,mBAAmB,MAAM;AAC/B,YAAI,iBAAiB,UAAU,QAAW;AAExC,gBAAM,IAAI;AAAA,YACR,iBAAiB,WAAW,OAAO,SACjC,iBAAiB,eACf,mCAAmC,GAAG,MAAM,iBAAiB,YAAY,KACzE,mCAAmC,GAAG;AAAA,UAC5C;AAAA,QACF;AAIA,eAAO,iBAAiB;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAI;AAKG,SAAS,4BAA4B;AAC1C,yBAAuB;AACzB;AAOO,SAAS,gBAGd;AACA,MAAI,CAAC,sBAAsB;AACzB,2BAAuB,oBAAoB,sBAAsB,CAAC;AAAA,EACpE;AAEA,SAAO,qBAA8C;AACvD;","names":["vercelAdapter"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\n createClient,\n type FlagsClient,\n flagsClient,\n Reason,\n} from '@vercel/flags-core';\nimport type {\n Adapter,\n FlagDeclaration,\n FlagDefinitionsType,\n FlagDefinitionType,\n ProviderData,\n} from 'flags';\nimport type { KeyedFlagDefinitionType } from 'flags/next';\n\nexport type VercelAdapterDeclaration<ValueType, EntitiesType> = Omit<\n FlagDeclaration<ValueType, EntitiesType>,\n 'decide' | 'origin'\n>;\n\n/**\n * Allows creating a custom Vercel adapter for feature flags\n */\nexport function createVercelAdapter(\n // usually a connection string, but can also be a pre-configured FlagsClient\n sdkKeyOrFlagsClient: string | FlagsClient,\n) {\n const flagsClient =\n typeof sdkKeyOrFlagsClient === 'string'\n ? createClient(sdkKeyOrFlagsClient)\n : sdkKeyOrFlagsClient;\n\n return function vercelAdapter<ValueType, EntitiesType>(): Adapter<\n ValueType,\n EntitiesType\n > {\n return {\n origin: flagsClient.origin,\n config: { reportValue: false },\n async decide({ key, entities, headers }): Promise<ValueType> {\n const evaluationResult = await flagsClient.evaluate<\n ValueType,\n EntitiesType\n >(key, undefined, entities);\n\n if (evaluationResult.value === undefined) {\n // if there was no defaultValue we need to throw\n throw new Error(\n evaluationResult.reason === Reason.ERROR &&\n evaluationResult.errorMessage\n ? `flags: Could not evaluate flag \"${key}\". ${evaluationResult.errorMessage}`\n : `flags: Could not evaluate flag \"${key}\"`,\n );\n }\n\n // runs when the flag evaluates successfully or\n // when there was an error but the defaultValue was set\n return evaluationResult.value;\n },\n };\n };\n}\n\nlet defaultVercelAdapter: ReturnType<typeof createVercelAdapter> | undefined;\n\n/**\n * Internal function for testing purposes\n */\nexport function resetDefaultVercelAdapter() {\n defaultVercelAdapter = undefined;\n}\n\n/**\n * A default Vercel adapter for feature flags\n *\n */\n// This is initialized lazily to avoid warning when it is not actually used and env vars are missing.\nexport function vercelAdapter<ValueType, EntitiesType>(): Adapter<\n ValueType,\n EntitiesType\n> {\n if (!defaultVercelAdapter) {\n defaultVercelAdapter = createVercelAdapter(flagsClient);\n }\n\n return defaultVercelAdapter<ValueType, EntitiesType>();\n}\n\nconst flagsClients = new Map<string, FlagsClient>();\n\nfunction getOrCreateClient(sdkKey: string): FlagsClient {\n let client = flagsClients.get(sdkKey);\n if (!client) {\n client = createClient(sdkKey);\n flagsClients.set(sdkKey, client);\n }\n return client;\n}\n\nfunction isVercelOrigin(\n origin: unknown,\n): origin is { provider: 'vercel'; sdkKey: string } {\n return (\n typeof origin === 'object' &&\n origin !== null &&\n 'provider' in origin &&\n (origin as Record<string, unknown>).provider === 'vercel' &&\n 'sdkKey' in origin &&\n typeof (origin as Record<string, unknown>).sdkKey === 'string'\n );\n}\n\nexport async function getProviderData(\n flags: Record<\n string,\n // accept an unknown array\n KeyedFlagDefinitionType | readonly unknown[]\n >,\n): Promise<ProviderData> {\n const flagDefs = Object.values(flags)\n // filter out precomputed arrays\n .filter((i): i is KeyedFlagDefinitionType => !Array.isArray(i));\n\n // Collect unique sdkKeys and resolve their projectIds\n const sdkKeys = new Set<string>();\n for (const d of flagDefs) {\n if (isVercelOrigin(d.origin)) {\n sdkKeys.add(d.origin.sdkKey);\n }\n }\n\n const projectIdBySdkKey = new Map<string, string>();\n await Promise.all(\n Array.from(sdkKeys).map(async (sdkKey) => {\n const client = getOrCreateClient(sdkKey);\n try {\n const fallback = await client.getFallbackDatafile();\n projectIdBySdkKey.set(sdkKey, fallback.projectId);\n } catch {\n const datafile = await client.getDatafile();\n projectIdBySdkKey.set(sdkKey, datafile.projectId);\n }\n }),\n );\n\n const definitions = flagDefs.reduce<FlagDefinitionsType>((acc, d) => {\n if (!isVercelOrigin(d.origin)) return acc;\n\n const projectId = projectIdBySdkKey.get(d.origin.sdkKey)!;\n acc[d.key] = {\n options: d.options,\n origin: {\n provider: 'vercel',\n projectId,\n },\n description: d.description,\n defaultValue: d.defaultValue,\n declaredInCode: true,\n } satisfies FlagDefinitionType;\n\n return acc;\n }, {});\n\n return { definitions, hints: [] };\n}\n"],"mappings":";AAAA;AAAA,EACE;AAAA,EAEA;AAAA,EACA;AAAA,OACK;AAkBA,SAAS,oBAEd,qBACA;AACA,QAAMA,eACJ,OAAO,wBAAwB,WAC3B,aAAa,mBAAmB,IAChC;AAEN,SAAO,SAASC,iBAGd;AACA,WAAO;AAAA,MACL,QAAQD,aAAY;AAAA,MACpB,QAAQ,EAAE,aAAa,MAAM;AAAA,MAC7B,MAAM,OAAO,EAAE,KAAK,UAAU,QAAQ,GAAuB;AAC3D,cAAM,mBAAmB,MAAMA,aAAY,SAGzC,KAAK,QAAW,QAAQ;AAE1B,YAAI,iBAAiB,UAAU,QAAW;AAExC,gBAAM,IAAI;AAAA,YACR,iBAAiB,WAAW,OAAO,SACjC,iBAAiB,eACf,mCAAmC,GAAG,MAAM,iBAAiB,YAAY,KACzE,mCAAmC,GAAG;AAAA,UAC5C;AAAA,QACF;AAIA,eAAO,iBAAiB;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAI;AAKG,SAAS,4BAA4B;AAC1C,yBAAuB;AACzB;AAOO,SAAS,gBAGd;AACA,MAAI,CAAC,sBAAsB;AACzB,2BAAuB,oBAAoB,WAAW;AAAA,EACxD;AAEA,SAAO,qBAA8C;AACvD;AAEA,IAAM,eAAe,oBAAI,IAAyB;AAElD,SAAS,kBAAkB,QAA6B;AACtD,MAAI,SAAS,aAAa,IAAI,MAAM;AACpC,MAAI,CAAC,QAAQ;AACX,aAAS,aAAa,MAAM;AAC5B,iBAAa,IAAI,QAAQ,MAAM;AAAA,EACjC;AACA,SAAO;AACT;AAEA,SAAS,eACP,QACkD;AAClD,SACE,OAAO,WAAW,YAClB,WAAW,QACX,cAAc,UACb,OAAmC,aAAa,YACjD,YAAY,UACZ,OAAQ,OAAmC,WAAW;AAE1D;AAEA,eAAsB,gBACpB,OAKuB;AACvB,QAAM,WAAW,OAAO,OAAO,KAAK,EAEjC,OAAO,CAAC,MAAoC,CAAC,MAAM,QAAQ,CAAC,CAAC;AAGhE,QAAM,UAAU,oBAAI,IAAY;AAChC,aAAW,KAAK,UAAU;AACxB,QAAI,eAAe,EAAE,MAAM,GAAG;AAC5B,cAAQ,IAAI,EAAE,OAAO,MAAM;AAAA,IAC7B;AAAA,EACF;AAEA,QAAM,oBAAoB,oBAAI,IAAoB;AAClD,QAAM,QAAQ;AAAA,IACZ,MAAM,KAAK,OAAO,EAAE,IAAI,OAAO,WAAW;AACxC,YAAM,SAAS,kBAAkB,MAAM;AACvC,UAAI;AACF,cAAM,WAAW,MAAM,OAAO,oBAAoB;AAClD,0BAAkB,IAAI,QAAQ,SAAS,SAAS;AAAA,MAClD,QAAQ;AACN,cAAM,WAAW,MAAM,OAAO,YAAY;AAC1C,0BAAkB,IAAI,QAAQ,SAAS,SAAS;AAAA,MAClD;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,cAAc,SAAS,OAA4B,CAAC,KAAK,MAAM;AACnE,QAAI,CAAC,eAAe,EAAE,MAAM,EAAG,QAAO;AAEtC,UAAM,YAAY,kBAAkB,IAAI,EAAE,OAAO,MAAM;AACvD,QAAI,EAAE,GAAG,IAAI;AAAA,MACX,SAAS,EAAE;AAAA,MACX,QAAQ;AAAA,QACN,UAAU;AAAA,QACV;AAAA,MACF;AAAA,MACA,aAAa,EAAE;AAAA,MACf,cAAc,EAAE;AAAA,MAChB,gBAAgB;AAAA,IAClB;AAEA,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AAEL,SAAO,EAAE,aAAa,OAAO,CAAC,EAAE;AAClC;","names":["flagsClient","vercelAdapter"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flags-sdk/vercel",
3
- "version": "0.1.8",
3
+ "version": "1.0.0",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "license": "MIT",
@@ -26,24 +26,21 @@
26
26
  "dist",
27
27
  "CHANGELOG.md"
28
28
  ],
29
- "dependencies": {
30
- "jose": "5.2.1",
31
- "js-xxhash": "4.0.0",
32
- "@vercel/edge-config": "^1.4.3",
33
- "@vercel/flags-core": "0.1.8"
34
- },
29
+ "dependencies": {},
35
30
  "devDependencies": {
36
31
  "@types/node": "20.11.17",
37
32
  "msw": "2.6.4",
38
- "next": "15.0.3",
39
- "tsup": "8.0.1",
33
+ "next": "16.1.5",
34
+ "tsup": "8.5.1",
40
35
  "typescript": "5.6.3",
41
- "vite": "6.0.3",
42
- "vitest": "2.1.8",
43
- "flags": "4.0.2"
36
+ "vite": "6.4.1",
37
+ "vitest": "2.1.9",
38
+ "@vercel/flags-core": "1.0.0",
39
+ "flags": "4.0.3"
44
40
  },
45
41
  "peerDependencies": {
46
- "flags": "*"
42
+ "flags": "*",
43
+ "@vercel/flags-core": "1.0.0"
47
44
  },
48
45
  "publishConfig": {
49
46
  "access": "public"