@sanity/personalization-plugin 2.3.0-growthbook.1 → 2.3.0-launch-darkly.2

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.
@@ -0,0 +1,54 @@
1
+ import {SanityClient} from 'sanity'
2
+
3
+ import {ExperimentType} from '../types'
4
+ import {LaunchDarklyFieldLevelConfig, LaunchDarklyFlagItem} from './types'
5
+
6
+ export const getExperiments = async ({
7
+ client,
8
+ projectKey,
9
+ tags,
10
+ }: Omit<LaunchDarklyFieldLevelConfig, 'fields'> & {client: SanityClient}): Promise<
11
+ ExperimentType[]
12
+ > => {
13
+ const query = `*[_id == 'secrets.launchdarkly'][0].secrets.apiKey`
14
+
15
+ const secret = await client.fetch(query) // secret is stored in the content lake using @sanity/studio-secrets
16
+ if (!secret) return []
17
+
18
+ const url = new URL(`https://app.launchdarkly.com/api/v2/flags/${projectKey}`)
19
+
20
+ if (tags) {
21
+ url.searchParams.set('filter', `tags:${tags.join('+')}`)
22
+ }
23
+
24
+ const featureExperiments: ExperimentType[] = []
25
+ let hasMore = true
26
+ const offset = 0
27
+ const limit = 10
28
+
29
+ while (hasMore) {
30
+ url.searchParams.set('offset', offset.toString())
31
+ url.searchParams.set('limit', limit.toString())
32
+ const responseFlags = await fetch(url, {
33
+ headers: {
34
+ Authorization: secret,
35
+ },
36
+ })
37
+
38
+ const {items} = await responseFlags.json()
39
+ const experiments = items.map((flag: LaunchDarklyFlagItem) => ({
40
+ id: flag.key,
41
+ label: flag.name,
42
+ variants: flag.variations.map((variation) => ({
43
+ id: variation.value,
44
+ label: variation.name ?? variation.value,
45
+ })),
46
+ }))
47
+ featureExperiments.push(...experiments)
48
+ if (items.length !== limit) {
49
+ hasMore = false
50
+ }
51
+ }
52
+
53
+ return featureExperiments
54
+ }
package/src/types.ts CHANGED
@@ -20,9 +20,7 @@ export type ExperimentType = {
20
20
 
21
21
  export type FieldPluginConfig = {
22
22
  fields: (string | FieldDefinition)[]
23
- experiments:
24
- | ExperimentType[]
25
- | ((client: SanityClient, secret?: string) => Promise<ExperimentType[]>)
23
+ experiments: ExperimentType[] | ((client: SanityClient) => Promise<ExperimentType[]>)
26
24
  apiVersion?: string
27
25
  experimentNameOverride?: string
28
26
  variantNameOverride?: string
@@ -69,179 +67,3 @@ export type ExperimentGeneric<T> = {
69
67
  | T
70
68
  | undefined
71
69
  }
72
-
73
- export type GrowthbookExperiment = {
74
- id: string
75
- dateCreated: string
76
- dateUpdated: string
77
- name: string
78
- project: string
79
- hypothesis: string
80
- description: string
81
- tags: [string]
82
- owner: string
83
- archived: boolean
84
- status: string
85
- autoRefresh: boolean
86
- hashAttribute: string
87
- fallbackAttribute: string
88
- hashVersion: number
89
- disableStickyBucketing: boolean
90
- bucketVersion: number
91
- minBucketVersion: number
92
- variations: [
93
- {
94
- variationId: string
95
- key: string
96
- name: string
97
- description: string
98
- screenshots: [string]
99
- },
100
- ]
101
- phases: [
102
- {
103
- name: string
104
- dateStarted: string
105
- dateEnded: string
106
- reasonForStopping: string
107
- seed: string
108
- coverage: 0
109
- trafficSplit: [
110
- {
111
- variationId: string
112
- weight: 0
113
- },
114
- ]
115
- namespace: {
116
- namespaceId: string
117
- range: []
118
- }
119
- targetingCondition: string
120
- savedGroupTargeting: [
121
- {
122
- matchType: string
123
- savedGroups: [string]
124
- },
125
- ]
126
- },
127
- ]
128
- settings: {
129
- datasourceId: string
130
- assignmentQueryId: string
131
- experimentId: string
132
- segmentId: string
133
- queryFilter: string
134
- inProgressConversions: string
135
- attributionModel: string
136
- statsEngine: string
137
- regressionAdjustmentEnabled: boolean
138
- goals: [
139
- {
140
- metricId: string
141
- overrides: {
142
- delayHours: 0
143
- windowHours: 0
144
- window: string
145
- winRiskThreshold: 0
146
- loseRiskThreshold: 0
147
- }
148
- },
149
- ]
150
- secondaryMetrics: [
151
- {
152
- metricId: string
153
- overrides: {
154
- delayHours: 0
155
- windowHours: 0
156
- window: string
157
- winRiskThreshold: 0
158
- loseRiskThreshold: 0
159
- }
160
- },
161
- ]
162
- guardrails: [
163
- {
164
- metricId: string
165
- overrides: {
166
- delayHours: 0
167
- windowHours: 0
168
- window: string
169
- winRiskThreshold: 0
170
- loseRiskThreshold: 0
171
- }
172
- },
173
- ]
174
- activationMetric: {
175
- metricId: string
176
- overrides: {
177
- delayHours: 0
178
- windowHours: 0
179
- window: string
180
- winRiskThreshold: 0
181
- loseRiskThreshold: 0
182
- }
183
- }
184
- }
185
- resultSummary: {
186
- status: string
187
- winner: string
188
- conclusions: string
189
- releasedVariationId: string
190
- excludeFromPayload: boolean
191
- }
192
- }
193
-
194
- export type GrowthbookFeature = {
195
- id: string
196
- dateCreated: string
197
- dateUpdated: string
198
- archived: boolean
199
- description: string
200
- owner: string
201
- project: string
202
- valueType: string
203
- defaultValue: string
204
- tags: string[]
205
- environments: {
206
- [key: string]: {
207
- enabled: boolean
208
- defaultValue: string
209
- rules: {
210
- description: string
211
- condition: string
212
- savedGroupTargeting: {matchType: string; savedGroups: string[]}[]
213
- id: string
214
- enabled: boolean
215
- type: string
216
- value: string
217
- variations: {value: string; variationId: string}[]
218
- }[]
219
- definition: string
220
- draft: {
221
- enabled: boolean
222
- defaultValue: string
223
- rules: {
224
- description: string
225
- condition: string
226
- savedGroupTargeting: {matchType: string; savedGroups: string[]}[]
227
- id: string
228
- enabled: boolean
229
- type: string
230
- value: string
231
- variations: {value: string; variationId: string}[]
232
- }[]
233
- definition: string
234
- }
235
- }
236
- }
237
- prerequisites: {
238
- parentId: string
239
- parentCondition: string
240
- }[]
241
- revision: {
242
- version: number
243
- comment: string
244
- date: string
245
- publishedBy: string
246
- }
247
- }
@@ -1,15 +0,0 @@
1
- import {FieldDefinition} from 'sanity'
2
- import {Plugin as Plugin_2} from 'sanity'
3
-
4
- export declare const fieldLevelExperiments: Plugin_2<GrowthbookABConfig>
5
-
6
- declare type GrowthbookABConfig = {
7
- fields: (string | FieldDefinition)[]
8
- environment: string
9
- baseUrl?: string
10
- project?: string
11
- convertBooleans?: boolean
12
- tags?: string[]
13
- }
14
-
15
- export {}
@@ -1,15 +0,0 @@
1
- import {FieldDefinition} from 'sanity'
2
- import {Plugin as Plugin_2} from 'sanity'
3
-
4
- export declare const fieldLevelExperiments: Plugin_2<GrowthbookABConfig>
5
-
6
- declare type GrowthbookABConfig = {
7
- fields: (string | FieldDefinition)[]
8
- environment: string
9
- baseUrl?: string
10
- project?: string
11
- convertBooleans?: boolean
12
- tags?: string[]
13
- }
14
-
15
- export {}
@@ -1,118 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: !0 });
3
- var sanity = require("sanity"), index = require("../index.js"), jsxRuntime = require("react/jsx-runtime"), react = require("react"), studioSecrets = require("@sanity/studio-secrets");
4
- const namespace = "growthbook", pluginConfigKeys = [
5
- {
6
- key: "apiKey",
7
- title: "Your secret API key"
8
- }
9
- ], Secrets = (props) => {
10
- const { secrets, loading } = studioSecrets.useSecrets(namespace), { setSecret } = useGrowthbookContext(), [showSettings, setShowSettings] = react.useState(!1);
11
- return react.useEffect(() => {
12
- if (!loading)
13
- return !secrets && !loading ? (setSecret(void 0), setShowSettings(!0)) : (setSecret(secrets.apiKey), setShowSettings(!1));
14
- }, [secrets, loading, setSecret]), showSettings ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
15
- /* @__PURE__ */ jsxRuntime.jsx(
16
- studioSecrets.SettingsView,
17
- {
18
- title: "Growthbook secret",
19
- namespace,
20
- keys: pluginConfigKeys,
21
- onClose: () => {
22
- setShowSettings(!1);
23
- }
24
- }
25
- ),
26
- props.renderDefault(props)
27
- ] }) : props.renderDefault(props);
28
- }, GROWTHBOOK_CONFIG_DEFAULT = {
29
- baseUrl: "https://api.growthbook.io/api/v1"
30
- }, GrowthbookContext = react.createContext({
31
- setSecret: () => {
32
- },
33
- secret: void 0
34
- });
35
- function useGrowthbookContext() {
36
- return react.useContext(GrowthbookContext);
37
- }
38
- function GrowthbookProvider(props) {
39
- const { growthbookFieldPluginConfig } = props, [secret, setSecret] = react.useState(), context = react.useMemo(
40
- () => ({ ...growthbookFieldPluginConfig, secret, setSecret }),
41
- [growthbookFieldPluginConfig, secret, setSecret]
42
- );
43
- return /* @__PURE__ */ jsxRuntime.jsx(GrowthbookContext.Provider, { value: context, children: /* @__PURE__ */ jsxRuntime.jsx(Secrets, { ...props }) });
44
- }
45
- const getBooleanConversion = (value) => value === "true" ? "variant" : value === "false" ? "control" : value, getExperiments = async ({
46
- client,
47
- environment,
48
- baseUrl,
49
- project,
50
- convertBooleans,
51
- tags
52
- }) => {
53
- const query = `*[_id == 'secrets.${namespace}'][0].secrets.${pluginConfigKeys[0].key}`, secret = await client.fetch(query);
54
- if (!secret) return [];
55
- const featureExperiments = [];
56
- let hasMore = !0, offset = 0;
57
- const url = new URL(`${baseUrl}/features`);
58
- for (project && url.searchParams.set("projectId", project); hasMore; ) {
59
- url.searchParams.set("offset", offset.toString());
60
- const response = await fetch(url, {
61
- headers: {
62
- Authorization: `Bearer ${secret}`
63
- }
64
- }), { features, hasMore: responseHasMore, nextOffset } = await response.json();
65
- hasMore = responseHasMore, offset = nextOffset, features && features.forEach((feature) => {
66
- if (feature.archived || tags && feature.tags && !feature.tags.some((tag) => tags.includes(tag)))
67
- return;
68
- const experiments = feature.environments[environment]?.rules.filter(
69
- (experiment) => experiment.type === "experiment-ref" || experiment.type === "experiment"
70
- );
71
- if (!experiments)
72
- return;
73
- const variations = [], uniqueValues = /* @__PURE__ */ new Set();
74
- experiments.forEach((experiment) => {
75
- experiment?.variations.forEach((variant) => {
76
- const value2 = convertBooleans ? getBooleanConversion(variant.value) : variant.value;
77
- uniqueValues.has(value2) || (uniqueValues.add(value2), variations.push({
78
- id: value2,
79
- label: value2
80
- }));
81
- });
82
- });
83
- const value = { id: feature.id, label: feature.id, variants: variations };
84
- featureExperiments.push(value);
85
- });
86
- }
87
- return featureExperiments.sort((a, b) => a.id.localeCompare(b.id));
88
- }, fieldLevelExperiments = sanity.definePlugin((config) => {
89
- const pluginConfig = { ...GROWTHBOOK_CONFIG_DEFAULT, ...config }, { fields, environment, project, convertBooleans, baseUrl, tags } = pluginConfig;
90
- return {
91
- name: "sanity-growthbook-personalistaion-plugin-field-level-experiments",
92
- plugins: [
93
- index.fieldLevelExperiments({
94
- fields,
95
- experiments: (client) => getExperiments({ client, environment, baseUrl, project, convertBooleans, tags })
96
- })
97
- ],
98
- form: {
99
- components: {
100
- input: (props) => {
101
- if (!(props.id === "root" && sanity.isObjectInputProps(props)) || !index.flattenSchemaType(props.schemaType).map(
102
- (field) => field.type.name
103
- ).some((name) => name.startsWith("experiment")))
104
- return props.renderDefault(props);
105
- const providerProps = {
106
- ...props,
107
- growthbookFieldPluginConfig: {
108
- ...pluginConfig
109
- }
110
- };
111
- return GrowthbookProvider(providerProps);
112
- }
113
- }
114
- }
115
- };
116
- });
117
- exports.fieldLevelExperiments = fieldLevelExperiments;
118
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sources":["../../src/growthbook/Components/Secrets.tsx","../../src/growthbook/Components/GrowthbookContext.tsx","../../src/growthbook/utils.ts","../../src/growthbook/index.ts"],"sourcesContent":["import {SettingsView, useSecrets} from '@sanity/studio-secrets'\nimport {useEffect, useState} from 'react'\nimport {ObjectInputProps} from 'sanity'\n\nimport {useGrowthbookContext} from './GrowthbookContext'\n\nexport const namespace = 'growthbook'\n\nexport const pluginConfigKeys = [\n {\n key: 'apiKey',\n title: 'Your secret API key',\n },\n]\n\nexport const Secrets = (props: ObjectInputProps) => {\n const {secrets, loading} = useSecrets(namespace) as {secrets: {apiKey: string}; loading: boolean}\n const {setSecret} = useGrowthbookContext()\n const [showSettings, setShowSettings] = useState<boolean>(false)\n\n useEffect(() => {\n if (loading) return undefined\n if (!secrets && !loading) {\n setSecret(undefined)\n return setShowSettings(true)\n }\n setSecret(secrets.apiKey)\n return setShowSettings(false)\n }, [secrets, loading, setSecret])\n\n if (!showSettings) {\n return props.renderDefault(props)\n }\n return (\n <>\n <SettingsView\n title={'Growthbook secret'}\n namespace={namespace}\n keys={pluginConfigKeys}\n onClose={() => {\n setShowSettings(false)\n }}\n />\n {props.renderDefault(props)}\n </>\n )\n}\n","import {createContext, useContext, useMemo, useState} from 'react'\nimport {ObjectInputProps} from 'sanity'\n\nimport {GrowthbookABConfig, GrowthbookContextProps} from '../types'\nimport {Secrets} from './Secrets'\n\nexport const GROWTHBOOK_CONFIG_DEFAULT = {\n baseUrl: 'https://api.growthbook.io/api/v1',\n}\n\nexport const GrowthbookContext = createContext<GrowthbookContextProps>({\n setSecret: () => undefined,\n secret: undefined,\n})\n\nexport function useGrowthbookContext() {\n return useContext(GrowthbookContext)\n}\n\ntype GrowthbookProps = ObjectInputProps & {\n growthbookFieldPluginConfig: GrowthbookABConfig\n}\n\nexport function GrowthbookProvider(props: GrowthbookProps) {\n const {growthbookFieldPluginConfig} = props\n const [secret, setSecret] = useState<string | undefined>()\n\n const context = useMemo(\n () => ({...growthbookFieldPluginConfig, secret, setSecret}),\n [growthbookFieldPluginConfig, secret, setSecret],\n )\n\n return (\n <GrowthbookContext.Provider value={context}>\n <Secrets {...props} />\n </GrowthbookContext.Provider>\n )\n}\n","import {SanityClient} from 'sanity'\n\nimport {ExperimentType, GrowthbookFeature, VariantType} from '../types'\nimport {namespace, pluginConfigKeys} from './Components/Secrets'\nimport {GrowthbookABConfig} from './types'\n\nconst getBooleanConversion = (value: string) => {\n // control is false\n if (value === 'true') {\n return 'variant'\n } else if (value === 'false') {\n return 'control'\n }\n return value\n}\n\nexport const getExperiments = async ({\n client,\n environment,\n baseUrl,\n project,\n convertBooleans,\n tags,\n}: Omit<GrowthbookABConfig, 'fields' | 'baseUrl'> & {\n client: SanityClient\n baseUrl: string\n}): Promise<ExperimentType[]> => {\n const query = `*[_id == 'secrets.${namespace}'][0].secrets.${pluginConfigKeys[0].key}`\n\n const secret = await client.fetch(query) // secret is stored in the content lake using @sanity/studio-secrets\n if (!secret) return []\n\n const featureExperiments: ExperimentType[] = []\n let hasMore = true\n let offset = 0\n const url = new URL(`${baseUrl}/features`)\n if (project) {\n url.searchParams.set('projectId', project)\n }\n\n while (hasMore) {\n url.searchParams.set('offset', offset.toString())\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${secret}`,\n },\n })\n\n const {features, hasMore: responseHasMore, nextOffset} = await response.json()\n\n hasMore = responseHasMore\n offset = nextOffset\n if (!features) continue\n\n features.forEach((feature: GrowthbookFeature) => {\n if (feature.archived) {\n return undefined\n }\n if (tags && feature.tags && !feature.tags.some((tag) => tags.includes(tag))) {\n return undefined\n }\n\n const experiments = feature.environments[environment]?.rules.filter(\n (experiment) => experiment.type === 'experiment-ref' || experiment.type === 'experiment',\n )\n\n if (!experiments) {\n return undefined\n }\n\n const variations: VariantType[] = []\n const uniqueValues = new Set<string>()\n\n experiments.forEach((experiment) => {\n experiment?.variations.forEach((variant) => {\n const value = convertBooleans ? getBooleanConversion(variant.value) : variant.value\n if (!uniqueValues.has(value)) {\n uniqueValues.add(value)\n variations.push({\n id: value,\n label: value,\n })\n }\n })\n })\n const value = {id: feature.id, label: feature.id, variants: variations}\n\n featureExperiments.push(value)\n return undefined\n })\n }\n const sortedFeatureExperiments = featureExperiments.sort((a, b) => a.id.localeCompare(b.id))\n return sortedFeatureExperiments\n}\n","import {definePlugin, isObjectInputProps} from 'sanity'\n\nimport {fieldLevelExperiments as baseFieldLevelExperiments} from '../fieldExperiments'\nimport {flattenSchemaType} from '../utils/flattenSchemaType'\nimport {GROWTHBOOK_CONFIG_DEFAULT, GrowthbookProvider} from './Components/GrowthbookContext'\nimport {GrowthbookABConfig} from './types'\nimport {getExperiments} from './utils'\n\nexport const fieldLevelExperiments = definePlugin<GrowthbookABConfig>((config) => {\n const pluginConfig = {...GROWTHBOOK_CONFIG_DEFAULT, ...config}\n const {fields, environment, project, convertBooleans, baseUrl, tags} = pluginConfig\n return {\n name: 'sanity-growthbook-personalistaion-plugin-field-level-experiments',\n plugins: [\n baseFieldLevelExperiments({\n fields,\n experiments: (client) =>\n getExperiments({client, environment, baseUrl, project, convertBooleans, tags}),\n }),\n ],\n\n form: {\n components: {\n input: (props) => {\n const isRootInput = props.id === 'root' && isObjectInputProps(props)\n\n if (!isRootInput) {\n return props.renderDefault(props)\n }\n\n const flatFieldTypeNames = flattenSchemaType(props.schemaType).map(\n (field) => field.type.name,\n )\n\n const hasExperiment = flatFieldTypeNames.some((name) => name.startsWith('experiment'))\n\n if (!hasExperiment) {\n return props.renderDefault(props)\n }\n\n const providerProps = {\n ...props,\n growthbookFieldPluginConfig: {\n ...pluginConfig,\n },\n }\n return GrowthbookProvider(providerProps)\n },\n },\n },\n }\n})\n"],"names":["useSecrets","useState","useEffect","jsxs","Fragment","jsx","SettingsView","createContext","useContext","useMemo","value","definePlugin","baseFieldLevelExperiments","isObjectInputProps","flattenSchemaType"],"mappings":"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"}
@@ -1,122 +0,0 @@
1
- import { definePlugin, isObjectInputProps } from "sanity";
2
- import { fieldLevelExperiments as fieldLevelExperiments$1, flattenSchemaType } from "../index.mjs";
3
- import { jsxs, Fragment, jsx } from "react/jsx-runtime";
4
- import { useState, useEffect, createContext, useMemo, useContext } from "react";
5
- import { useSecrets, SettingsView } from "@sanity/studio-secrets";
6
- const namespace = "growthbook", pluginConfigKeys = [
7
- {
8
- key: "apiKey",
9
- title: "Your secret API key"
10
- }
11
- ], Secrets = (props) => {
12
- const { secrets, loading } = useSecrets(namespace), { setSecret } = useGrowthbookContext(), [showSettings, setShowSettings] = useState(!1);
13
- return useEffect(() => {
14
- if (!loading)
15
- return !secrets && !loading ? (setSecret(void 0), setShowSettings(!0)) : (setSecret(secrets.apiKey), setShowSettings(!1));
16
- }, [secrets, loading, setSecret]), showSettings ? /* @__PURE__ */ jsxs(Fragment, { children: [
17
- /* @__PURE__ */ jsx(
18
- SettingsView,
19
- {
20
- title: "Growthbook secret",
21
- namespace,
22
- keys: pluginConfigKeys,
23
- onClose: () => {
24
- setShowSettings(!1);
25
- }
26
- }
27
- ),
28
- props.renderDefault(props)
29
- ] }) : props.renderDefault(props);
30
- }, GROWTHBOOK_CONFIG_DEFAULT = {
31
- baseUrl: "https://api.growthbook.io/api/v1"
32
- }, GrowthbookContext = createContext({
33
- setSecret: () => {
34
- },
35
- secret: void 0
36
- });
37
- function useGrowthbookContext() {
38
- return useContext(GrowthbookContext);
39
- }
40
- function GrowthbookProvider(props) {
41
- const { growthbookFieldPluginConfig } = props, [secret, setSecret] = useState(), context = useMemo(
42
- () => ({ ...growthbookFieldPluginConfig, secret, setSecret }),
43
- [growthbookFieldPluginConfig, secret, setSecret]
44
- );
45
- return /* @__PURE__ */ jsx(GrowthbookContext.Provider, { value: context, children: /* @__PURE__ */ jsx(Secrets, { ...props }) });
46
- }
47
- const getBooleanConversion = (value) => value === "true" ? "variant" : value === "false" ? "control" : value, getExperiments = async ({
48
- client,
49
- environment,
50
- baseUrl,
51
- project,
52
- convertBooleans,
53
- tags
54
- }) => {
55
- const query = `*[_id == 'secrets.${namespace}'][0].secrets.${pluginConfigKeys[0].key}`, secret = await client.fetch(query);
56
- if (!secret) return [];
57
- const featureExperiments = [];
58
- let hasMore = !0, offset = 0;
59
- const url = new URL(`${baseUrl}/features`);
60
- for (project && url.searchParams.set("projectId", project); hasMore; ) {
61
- url.searchParams.set("offset", offset.toString());
62
- const response = await fetch(url, {
63
- headers: {
64
- Authorization: `Bearer ${secret}`
65
- }
66
- }), { features, hasMore: responseHasMore, nextOffset } = await response.json();
67
- hasMore = responseHasMore, offset = nextOffset, features && features.forEach((feature) => {
68
- if (feature.archived || tags && feature.tags && !feature.tags.some((tag) => tags.includes(tag)))
69
- return;
70
- const experiments = feature.environments[environment]?.rules.filter(
71
- (experiment) => experiment.type === "experiment-ref" || experiment.type === "experiment"
72
- );
73
- if (!experiments)
74
- return;
75
- const variations = [], uniqueValues = /* @__PURE__ */ new Set();
76
- experiments.forEach((experiment) => {
77
- experiment?.variations.forEach((variant) => {
78
- const value2 = convertBooleans ? getBooleanConversion(variant.value) : variant.value;
79
- uniqueValues.has(value2) || (uniqueValues.add(value2), variations.push({
80
- id: value2,
81
- label: value2
82
- }));
83
- });
84
- });
85
- const value = { id: feature.id, label: feature.id, variants: variations };
86
- featureExperiments.push(value);
87
- });
88
- }
89
- return featureExperiments.sort((a, b) => a.id.localeCompare(b.id));
90
- }, fieldLevelExperiments = definePlugin((config) => {
91
- const pluginConfig = { ...GROWTHBOOK_CONFIG_DEFAULT, ...config }, { fields, environment, project, convertBooleans, baseUrl, tags } = pluginConfig;
92
- return {
93
- name: "sanity-growthbook-personalistaion-plugin-field-level-experiments",
94
- plugins: [
95
- fieldLevelExperiments$1({
96
- fields,
97
- experiments: (client) => getExperiments({ client, environment, baseUrl, project, convertBooleans, tags })
98
- })
99
- ],
100
- form: {
101
- components: {
102
- input: (props) => {
103
- if (!(props.id === "root" && isObjectInputProps(props)) || !flattenSchemaType(props.schemaType).map(
104
- (field) => field.type.name
105
- ).some((name) => name.startsWith("experiment")))
106
- return props.renderDefault(props);
107
- const providerProps = {
108
- ...props,
109
- growthbookFieldPluginConfig: {
110
- ...pluginConfig
111
- }
112
- };
113
- return GrowthbookProvider(providerProps);
114
- }
115
- }
116
- }
117
- };
118
- });
119
- export {
120
- fieldLevelExperiments
121
- };
122
- //# sourceMappingURL=index.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.mjs","sources":["../../src/growthbook/Components/Secrets.tsx","../../src/growthbook/Components/GrowthbookContext.tsx","../../src/growthbook/utils.ts","../../src/growthbook/index.ts"],"sourcesContent":["import {SettingsView, useSecrets} from '@sanity/studio-secrets'\nimport {useEffect, useState} from 'react'\nimport {ObjectInputProps} from 'sanity'\n\nimport {useGrowthbookContext} from './GrowthbookContext'\n\nexport const namespace = 'growthbook'\n\nexport const pluginConfigKeys = [\n {\n key: 'apiKey',\n title: 'Your secret API key',\n },\n]\n\nexport const Secrets = (props: ObjectInputProps) => {\n const {secrets, loading} = useSecrets(namespace) as {secrets: {apiKey: string}; loading: boolean}\n const {setSecret} = useGrowthbookContext()\n const [showSettings, setShowSettings] = useState<boolean>(false)\n\n useEffect(() => {\n if (loading) return undefined\n if (!secrets && !loading) {\n setSecret(undefined)\n return setShowSettings(true)\n }\n setSecret(secrets.apiKey)\n return setShowSettings(false)\n }, [secrets, loading, setSecret])\n\n if (!showSettings) {\n return props.renderDefault(props)\n }\n return (\n <>\n <SettingsView\n title={'Growthbook secret'}\n namespace={namespace}\n keys={pluginConfigKeys}\n onClose={() => {\n setShowSettings(false)\n }}\n />\n {props.renderDefault(props)}\n </>\n )\n}\n","import {createContext, useContext, useMemo, useState} from 'react'\nimport {ObjectInputProps} from 'sanity'\n\nimport {GrowthbookABConfig, GrowthbookContextProps} from '../types'\nimport {Secrets} from './Secrets'\n\nexport const GROWTHBOOK_CONFIG_DEFAULT = {\n baseUrl: 'https://api.growthbook.io/api/v1',\n}\n\nexport const GrowthbookContext = createContext<GrowthbookContextProps>({\n setSecret: () => undefined,\n secret: undefined,\n})\n\nexport function useGrowthbookContext() {\n return useContext(GrowthbookContext)\n}\n\ntype GrowthbookProps = ObjectInputProps & {\n growthbookFieldPluginConfig: GrowthbookABConfig\n}\n\nexport function GrowthbookProvider(props: GrowthbookProps) {\n const {growthbookFieldPluginConfig} = props\n const [secret, setSecret] = useState<string | undefined>()\n\n const context = useMemo(\n () => ({...growthbookFieldPluginConfig, secret, setSecret}),\n [growthbookFieldPluginConfig, secret, setSecret],\n )\n\n return (\n <GrowthbookContext.Provider value={context}>\n <Secrets {...props} />\n </GrowthbookContext.Provider>\n )\n}\n","import {SanityClient} from 'sanity'\n\nimport {ExperimentType, GrowthbookFeature, VariantType} from '../types'\nimport {namespace, pluginConfigKeys} from './Components/Secrets'\nimport {GrowthbookABConfig} from './types'\n\nconst getBooleanConversion = (value: string) => {\n // control is false\n if (value === 'true') {\n return 'variant'\n } else if (value === 'false') {\n return 'control'\n }\n return value\n}\n\nexport const getExperiments = async ({\n client,\n environment,\n baseUrl,\n project,\n convertBooleans,\n tags,\n}: Omit<GrowthbookABConfig, 'fields' | 'baseUrl'> & {\n client: SanityClient\n baseUrl: string\n}): Promise<ExperimentType[]> => {\n const query = `*[_id == 'secrets.${namespace}'][0].secrets.${pluginConfigKeys[0].key}`\n\n const secret = await client.fetch(query) // secret is stored in the content lake using @sanity/studio-secrets\n if (!secret) return []\n\n const featureExperiments: ExperimentType[] = []\n let hasMore = true\n let offset = 0\n const url = new URL(`${baseUrl}/features`)\n if (project) {\n url.searchParams.set('projectId', project)\n }\n\n while (hasMore) {\n url.searchParams.set('offset', offset.toString())\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${secret}`,\n },\n })\n\n const {features, hasMore: responseHasMore, nextOffset} = await response.json()\n\n hasMore = responseHasMore\n offset = nextOffset\n if (!features) continue\n\n features.forEach((feature: GrowthbookFeature) => {\n if (feature.archived) {\n return undefined\n }\n if (tags && feature.tags && !feature.tags.some((tag) => tags.includes(tag))) {\n return undefined\n }\n\n const experiments = feature.environments[environment]?.rules.filter(\n (experiment) => experiment.type === 'experiment-ref' || experiment.type === 'experiment',\n )\n\n if (!experiments) {\n return undefined\n }\n\n const variations: VariantType[] = []\n const uniqueValues = new Set<string>()\n\n experiments.forEach((experiment) => {\n experiment?.variations.forEach((variant) => {\n const value = convertBooleans ? getBooleanConversion(variant.value) : variant.value\n if (!uniqueValues.has(value)) {\n uniqueValues.add(value)\n variations.push({\n id: value,\n label: value,\n })\n }\n })\n })\n const value = {id: feature.id, label: feature.id, variants: variations}\n\n featureExperiments.push(value)\n return undefined\n })\n }\n const sortedFeatureExperiments = featureExperiments.sort((a, b) => a.id.localeCompare(b.id))\n return sortedFeatureExperiments\n}\n","import {definePlugin, isObjectInputProps} from 'sanity'\n\nimport {fieldLevelExperiments as baseFieldLevelExperiments} from '../fieldExperiments'\nimport {flattenSchemaType} from '../utils/flattenSchemaType'\nimport {GROWTHBOOK_CONFIG_DEFAULT, GrowthbookProvider} from './Components/GrowthbookContext'\nimport {GrowthbookABConfig} from './types'\nimport {getExperiments} from './utils'\n\nexport const fieldLevelExperiments = definePlugin<GrowthbookABConfig>((config) => {\n const pluginConfig = {...GROWTHBOOK_CONFIG_DEFAULT, ...config}\n const {fields, environment, project, convertBooleans, baseUrl, tags} = pluginConfig\n return {\n name: 'sanity-growthbook-personalistaion-plugin-field-level-experiments',\n plugins: [\n baseFieldLevelExperiments({\n fields,\n experiments: (client) =>\n getExperiments({client, environment, baseUrl, project, convertBooleans, tags}),\n }),\n ],\n\n form: {\n components: {\n input: (props) => {\n const isRootInput = props.id === 'root' && isObjectInputProps(props)\n\n if (!isRootInput) {\n return props.renderDefault(props)\n }\n\n const flatFieldTypeNames = flattenSchemaType(props.schemaType).map(\n (field) => field.type.name,\n )\n\n const hasExperiment = flatFieldTypeNames.some((name) => name.startsWith('experiment'))\n\n if (!hasExperiment) {\n return props.renderDefault(props)\n }\n\n const providerProps = {\n ...props,\n growthbookFieldPluginConfig: {\n ...pluginConfig,\n },\n }\n return GrowthbookProvider(providerProps)\n },\n },\n },\n }\n})\n"],"names":["value","baseFieldLevelExperiments"],"mappings":"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"}
@@ -1,38 +0,0 @@
1
- import {createContext, useContext, useMemo, useState} from 'react'
2
- import {ObjectInputProps} from 'sanity'
3
-
4
- import {GrowthbookABConfig, GrowthbookContextProps} from '../types'
5
- import {Secrets} from './Secrets'
6
-
7
- export const GROWTHBOOK_CONFIG_DEFAULT = {
8
- baseUrl: 'https://api.growthbook.io/api/v1',
9
- }
10
-
11
- export const GrowthbookContext = createContext<GrowthbookContextProps>({
12
- setSecret: () => undefined,
13
- secret: undefined,
14
- })
15
-
16
- export function useGrowthbookContext() {
17
- return useContext(GrowthbookContext)
18
- }
19
-
20
- type GrowthbookProps = ObjectInputProps & {
21
- growthbookFieldPluginConfig: GrowthbookABConfig
22
- }
23
-
24
- export function GrowthbookProvider(props: GrowthbookProps) {
25
- const {growthbookFieldPluginConfig} = props
26
- const [secret, setSecret] = useState<string | undefined>()
27
-
28
- const context = useMemo(
29
- () => ({...growthbookFieldPluginConfig, secret, setSecret}),
30
- [growthbookFieldPluginConfig, secret, setSecret],
31
- )
32
-
33
- return (
34
- <GrowthbookContext.Provider value={context}>
35
- <Secrets {...props} />
36
- </GrowthbookContext.Provider>
37
- )
38
- }
@@ -1,15 +0,0 @@
1
- import {FieldDefinition} from 'sanity'
2
-
3
- export type GrowthbookABConfig = {
4
- fields: (string | FieldDefinition)[]
5
- environment: string
6
- baseUrl?: string
7
- project?: string
8
- convertBooleans?: boolean
9
- tags?: string[]
10
- }
11
-
12
- export type GrowthbookContextProps = {
13
- setSecret: (secret: string | undefined) => void
14
- secret: string | undefined
15
- }