@sanity/personalization-plugin 2.1.0-field-names.1 → 2.1.0-growthbook.1

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/src/types.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import {Dispatch, SetStateAction} from 'react'
1
2
  import {
2
3
  ArrayOfObjectsInputProps,
3
4
  FieldDefinition,
@@ -20,36 +21,35 @@ export type ExperimentType = {
20
21
 
21
22
  export type FieldPluginConfig = {
22
23
  fields: (string | FieldDefinition)[]
23
- experiments: ExperimentType[] | ((client: SanityClient) => Promise<ExperimentType[]>)
24
+ experiments:
25
+ | ExperimentType[]
26
+ | ((client: SanityClient, secret?: string) => Promise<ExperimentType[]>)
24
27
  apiVersion?: string
25
- experimentNameOverride?: string
26
- variantNameOverride?: string
27
- variantId?: string
28
- variantArrayName?: string
29
- experimentId?: string
30
28
  }
31
29
 
32
30
  export type VariantPreviewProps = Omit<PreviewProps, 'SchemaType'> & {
33
- [key: string]: string
31
+ experiment: string
32
+ variant: string
34
33
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
35
34
  value: any
36
35
  }
37
36
 
38
37
  export type ExperimentContextProps = Required<FieldPluginConfig> & {
39
38
  experiments: ExperimentType[]
39
+ setSecret: Dispatch<SetStateAction<string | undefined>>
40
+ secret: string | undefined
40
41
  }
41
42
 
42
43
  export type ArrayInputProps = ArrayOfObjectsInputProps & {
43
- variantName: string
44
- variantId: string
45
- experimentId: string
44
+ objectName: string
46
45
  }
47
46
 
48
47
  export type ObjectFieldWithPath = ObjectField<SchemaType> & {path: Path}
49
48
 
50
49
  export type VariantGeneric<T> = {
51
- [key: string]: string | T | undefined
52
50
  _type: string
51
+ variantId?: string
52
+ experimentId?: string
53
53
  value?: T
54
54
  }
55
55
 
@@ -57,13 +57,185 @@ export type ExperimentGeneric<T> = {
57
57
  _type: string
58
58
  default?: T
59
59
  experimentValue?: string
60
- [key: string]:
61
- | Array<
60
+ variants?: Array<
61
+ {
62
+ _key: string
63
+ } & VariantGeneric<T>
64
+ >
65
+ }
66
+
67
+ export type GrowthbookExperiment = {
68
+ id: string
69
+ dateCreated: string
70
+ dateUpdated: string
71
+ name: string
72
+ project: string
73
+ hypothesis: string
74
+ description: string
75
+ tags: [string]
76
+ owner: string
77
+ archived: boolean
78
+ status: string
79
+ autoRefresh: boolean
80
+ hashAttribute: string
81
+ fallbackAttribute: string
82
+ hashVersion: number
83
+ disableStickyBucketing: boolean
84
+ bucketVersion: number
85
+ minBucketVersion: number
86
+ variations: [
87
+ {
88
+ variationId: string
89
+ key: string
90
+ name: string
91
+ description: string
92
+ screenshots: [string]
93
+ },
94
+ ]
95
+ phases: [
96
+ {
97
+ name: string
98
+ dateStarted: string
99
+ dateEnded: string
100
+ reasonForStopping: string
101
+ seed: string
102
+ coverage: 0
103
+ trafficSplit: [
104
+ {
105
+ variationId: string
106
+ weight: 0
107
+ },
108
+ ]
109
+ namespace: {
110
+ namespaceId: string
111
+ range: []
112
+ }
113
+ targetingCondition: string
114
+ savedGroupTargeting: [
62
115
  {
63
- _key: string
64
- } & VariantGeneric<T>
65
- >
66
- | string
67
- | T
68
- | undefined
116
+ matchType: string
117
+ savedGroups: [string]
118
+ },
119
+ ]
120
+ },
121
+ ]
122
+ settings: {
123
+ datasourceId: string
124
+ assignmentQueryId: string
125
+ experimentId: string
126
+ segmentId: string
127
+ queryFilter: string
128
+ inProgressConversions: string
129
+ attributionModel: string
130
+ statsEngine: string
131
+ regressionAdjustmentEnabled: boolean
132
+ goals: [
133
+ {
134
+ metricId: string
135
+ overrides: {
136
+ delayHours: 0
137
+ windowHours: 0
138
+ window: string
139
+ winRiskThreshold: 0
140
+ loseRiskThreshold: 0
141
+ }
142
+ },
143
+ ]
144
+ secondaryMetrics: [
145
+ {
146
+ metricId: string
147
+ overrides: {
148
+ delayHours: 0
149
+ windowHours: 0
150
+ window: string
151
+ winRiskThreshold: 0
152
+ loseRiskThreshold: 0
153
+ }
154
+ },
155
+ ]
156
+ guardrails: [
157
+ {
158
+ metricId: string
159
+ overrides: {
160
+ delayHours: 0
161
+ windowHours: 0
162
+ window: string
163
+ winRiskThreshold: 0
164
+ loseRiskThreshold: 0
165
+ }
166
+ },
167
+ ]
168
+ activationMetric: {
169
+ metricId: string
170
+ overrides: {
171
+ delayHours: 0
172
+ windowHours: 0
173
+ window: string
174
+ winRiskThreshold: 0
175
+ loseRiskThreshold: 0
176
+ }
177
+ }
178
+ }
179
+ resultSummary: {
180
+ status: string
181
+ winner: string
182
+ conclusions: string
183
+ releasedVariationId: string
184
+ excludeFromPayload: boolean
185
+ }
186
+ }
187
+
188
+ export type GrowthbookFeature = {
189
+ id: string
190
+ dateCreated: string
191
+ dateUpdated: string
192
+ archived: boolean
193
+ description: string
194
+ owner: string
195
+ project: string
196
+ valueType: string
197
+ defaultValue: string
198
+ tags: string[]
199
+ environments: {
200
+ [key: string]: {
201
+ enabled: boolean
202
+ defaultValue: string
203
+ rules: {
204
+ description: string
205
+ condition: string
206
+ savedGroupTargeting: {matchType: string; savedGroups: string[]}[]
207
+ id: string
208
+ enabled: boolean
209
+ type: string
210
+ value: string
211
+ variations: {value: string; variationId: string}[]
212
+ }[]
213
+ definition: string
214
+ draft: {
215
+ enabled: boolean
216
+ defaultValue: string
217
+ rules: {
218
+ description: string
219
+ condition: string
220
+ savedGroupTargeting: {matchType: string; savedGroups: string[]}[]
221
+ id: string
222
+ enabled: boolean
223
+ type: string
224
+ value: string
225
+ variations: {value: string; variationId: string}[]
226
+ }[]
227
+ definition: string
228
+ }
229
+ }
230
+ }
231
+ prerequisites: {
232
+ parentId: string
233
+ parentCondition: string
234
+ }[]
235
+ revision: {
236
+ version: number
237
+ comment: string
238
+ date: string
239
+ publishedBy: string
240
+ }
69
241
  }
@@ -0,0 +1,78 @@
1
+ import {SanityClient} from 'sanity'
2
+
3
+ import {GrowthbookABConfig} from '../growthbookFieldExperiments'
4
+ import {ExperimentType, GrowthbookFeature, VariantType} from '../types'
5
+
6
+ const getBooleanConversion = (value: string) => {
7
+ // this way or the other way around?
8
+ if (value === 'true') {
9
+ return 'variant'
10
+ } else if (value === 'false') {
11
+ return 'control'
12
+ }
13
+ return value
14
+ }
15
+
16
+ export const getExperiments = async ({
17
+ client,
18
+ environment,
19
+ baseUrl,
20
+ project,
21
+ convertBooleans,
22
+ }: Omit<GrowthbookABConfig, 'fields'> & {client: SanityClient}): Promise<ExperimentType[]> => {
23
+ const query = `*[_id == 'secrets.growthbook'][0].secrets.apiKey`
24
+
25
+ const secret = await client.fetch(query) // secret is stored in the content lake using @sanity/studio-secrets
26
+ if (!secret) return []
27
+
28
+ const featureExperiments: ExperimentType[] = []
29
+ let hasMore = true
30
+ let offset = 0
31
+ const url = new URL(baseUrl ?? 'https://api.growthbook.io/api/v1/features')
32
+ if (project) {
33
+ url.searchParams.set('projectId', project)
34
+ }
35
+
36
+ while (hasMore) {
37
+ url.searchParams.set('offset', offset.toString())
38
+ const response = await fetch(url, {
39
+ headers: {
40
+ Authorization: `Bearer ${secret}`,
41
+ },
42
+ })
43
+
44
+ const {features, hasMore: responseHasMore, nextOffset} = await response.json()
45
+
46
+ hasMore = responseHasMore
47
+ offset = nextOffset
48
+ if (!features) continue
49
+
50
+ features.forEach((feature: GrowthbookFeature) => {
51
+ if (feature.archived) {
52
+ return undefined
53
+ }
54
+ const experiments = feature.environments[environment]?.rules.filter(
55
+ (experiment) => experiment.type === 'experiment-ref' || experiment.type === 'experiment',
56
+ )
57
+
58
+ if (!experiments) {
59
+ return undefined
60
+ }
61
+
62
+ const variations = new Set<VariantType>()
63
+ experiments.forEach((experiment) => {
64
+ experiment?.variations.forEach((variant) => {
65
+ variations.add({
66
+ id: convertBooleans ? getBooleanConversion(variant.value) : variant.value,
67
+ label: convertBooleans ? getBooleanConversion(variant.value) : variant.value,
68
+ })
69
+ })
70
+ })
71
+ const value = {id: feature.id, label: feature.id, variants: [...variations]}
72
+
73
+ featureExperiments.push(value)
74
+ return undefined
75
+ })
76
+ }
77
+ return featureExperiments
78
+ }