@sanity/personalization-plugin 3.0.2 → 3.0.4
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/dist/fieldExperiments.js +498 -0
- package/dist/fieldExperiments.js.map +1 -0
- package/dist/growthbook/index.js +102 -145
- package/dist/growthbook/index.js.map +1 -1
- package/dist/index.js +2 -6
- package/dist/launchDarkly/index.js +88 -119
- package/dist/launchDarkly/index.js.map +1 -1
- package/package.json +8 -8
- package/dist/_chunks-es/fieldExperiments.js +0 -568
- package/dist/_chunks-es/fieldExperiments.js.map +0 -1
- package/dist/index.js.map +0 -1
package/dist/growthbook/index.js
CHANGED
|
@@ -1,156 +1,113 @@
|
|
|
1
|
+
import { n as flattenSchemaType, t as fieldLevelExperiments$1 } from "../fieldExperiments.js";
|
|
1
2
|
import { definePlugin, isObjectInputProps } from "sanity";
|
|
2
|
-
import { flattenSchemaType, fieldLevelExperiments as fieldLevelExperiments$1 } from "../_chunks-es/fieldExperiments.js";
|
|
3
|
-
import { jsxs, Fragment, jsx } from "react/jsx-runtime";
|
|
4
3
|
import { c } from "react/compiler-runtime";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { createContext, useContext, useEffect, useState } from "react";
|
|
5
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { SettingsView, useSecrets } from "@sanity/studio-secrets";
|
|
7
7
|
const namespace = "growthbook", apiKeyName = "apiKey", pluginConfigKeys = [{
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
key: apiKeyName,
|
|
9
|
+
title: "Your secret API key"
|
|
10
10
|
}], Secrets = (props) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}, GrowthbookContext = createContext({
|
|
39
|
-
setSecret: () => {
|
|
40
|
-
},
|
|
41
|
-
secret: void 0
|
|
11
|
+
let $ = c(12), { secrets, loading } = useSecrets(namespace), { setSecret } = useGrowthbookContext(), [showSettings, setShowSettings] = useState(!1), t0, t1;
|
|
12
|
+
if ($[0] !== loading || $[1] !== secrets || $[2] !== setSecret ? (t0 = () => {
|
|
13
|
+
if (!loading) return !secrets && !loading ? (setSecret(void 0), setShowSettings(!0)) : (setSecret(secrets.apiKey), setShowSettings(!1));
|
|
14
|
+
}, t1 = [
|
|
15
|
+
secrets,
|
|
16
|
+
loading,
|
|
17
|
+
setSecret
|
|
18
|
+
], $[0] = loading, $[1] = secrets, $[2] = setSecret, $[3] = t0, $[4] = t1) : (t0 = $[3], t1 = $[4]), useEffect(t0, t1), !showSettings) {
|
|
19
|
+
let t2;
|
|
20
|
+
return $[5] === props ? t2 = $[6] : (t2 = props.renderDefault(props), $[5] = props, $[6] = t2), t2;
|
|
21
|
+
}
|
|
22
|
+
let t2;
|
|
23
|
+
$[7] === Symbol.for("react.memo_cache_sentinel") ? (t2 = /* @__PURE__ */ jsx(SettingsView, {
|
|
24
|
+
title: "Growthbook secret",
|
|
25
|
+
namespace,
|
|
26
|
+
keys: pluginConfigKeys,
|
|
27
|
+
onClose: () => {
|
|
28
|
+
setShowSettings(!1);
|
|
29
|
+
}
|
|
30
|
+
}), $[7] = t2) : t2 = $[7];
|
|
31
|
+
let t3;
|
|
32
|
+
$[8] === props ? t3 = $[9] : (t3 = props.renderDefault(props), $[8] = props, $[9] = t3);
|
|
33
|
+
let t4;
|
|
34
|
+
return $[10] === t3 ? t4 = $[11] : (t4 = /* @__PURE__ */ jsxs(Fragment, { children: [t2, t3] }), $[10] = t3, $[11] = t4), t4;
|
|
35
|
+
}, GROWTHBOOK_CONFIG_DEFAULT = { baseUrl: "https://api.growthbook.io/api/v1" }, GrowthbookContext = createContext({
|
|
36
|
+
setSecret: () => void 0,
|
|
37
|
+
secret: void 0
|
|
42
38
|
});
|
|
43
39
|
function useGrowthbookContext() {
|
|
44
|
-
|
|
40
|
+
return useContext(GrowthbookContext);
|
|
45
41
|
}
|
|
46
42
|
function GrowthbookProvider(props) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return $[5] !== context || $[6] !== t1 ? (t2 = /* @__PURE__ */ jsx(GrowthbookContext.Provider, { value: context, children: t1 }), $[5] = context, $[6] = t1, $[7] = t2) : t2 = $[7], t2;
|
|
43
|
+
let $ = c(8), { growthbookFieldPluginConfig } = props, [secret, setSecret] = useState(), t0;
|
|
44
|
+
$[0] !== growthbookFieldPluginConfig || $[1] !== secret ? (t0 = {
|
|
45
|
+
...growthbookFieldPluginConfig,
|
|
46
|
+
secret,
|
|
47
|
+
setSecret
|
|
48
|
+
}, $[0] = growthbookFieldPluginConfig, $[1] = secret, $[2] = t0) : t0 = $[2];
|
|
49
|
+
let context = t0, t1;
|
|
50
|
+
$[3] === props ? t1 = $[4] : (t1 = /* @__PURE__ */ jsx(Secrets, { ...props }), $[3] = props, $[4] = t1);
|
|
51
|
+
let t2;
|
|
52
|
+
return $[5] !== context || $[6] !== t1 ? (t2 = /* @__PURE__ */ jsx(GrowthbookContext.Provider, {
|
|
53
|
+
value: context,
|
|
54
|
+
children: t1
|
|
55
|
+
}), $[5] = context, $[6] = t1, $[7] = t2) : t2 = $[7], t2;
|
|
61
56
|
}
|
|
62
|
-
const getBooleanConversion = (value) => value === "true" ? "variant" : value === "false" ? "control" : value, getExperiments = async ({
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const variations = [], uniqueValues = /* @__PURE__ */ new Set();
|
|
93
|
-
experiments.forEach((experiment) => {
|
|
94
|
-
experiment?.variations.forEach((variant) => {
|
|
95
|
-
const value2 = convertBooleans ? getBooleanConversion(variant.value) : variant.value;
|
|
96
|
-
uniqueValues.has(value2) || (uniqueValues.add(value2), variations.push({
|
|
97
|
-
id: value2,
|
|
98
|
-
label: value2
|
|
99
|
-
}));
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
const value = {
|
|
103
|
-
id: feature.id,
|
|
104
|
-
label: feature.id,
|
|
105
|
-
variants: variations
|
|
106
|
-
};
|
|
107
|
-
featureExperiments.push(value);
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
return featureExperiments.sort((a, b) => a.id.localeCompare(b.id));
|
|
57
|
+
const getBooleanConversion = (value) => value === "true" ? "variant" : value === "false" ? "control" : value, getExperiments = async ({ client, environment, baseUrl, project, convertBooleans, tags }) => {
|
|
58
|
+
let query = `*[_id == 'secrets.${namespace}'][0].secrets.${apiKeyName}`, secret = await client.fetch(query);
|
|
59
|
+
if (!secret) return [];
|
|
60
|
+
let featureExperiments = [], hasMore = !0, offset = 0, url = new URL(`${baseUrl}/features`);
|
|
61
|
+
for (project && url.searchParams.set("projectId", project); hasMore;) {
|
|
62
|
+
url.searchParams.set("offset", offset.toString());
|
|
63
|
+
let { features, hasMore: responseHasMore, nextOffset } = await (await fetch(url, { headers: { Authorization: `Bearer ${secret}` } })).json();
|
|
64
|
+
hasMore = responseHasMore, offset = nextOffset, features && features.forEach((feature) => {
|
|
65
|
+
if (feature.archived || tags && feature.tags && !feature.tags.some((tag) => tags.includes(tag))) return;
|
|
66
|
+
let experiments = feature.environments[environment]?.rules.filter((experiment) => experiment.type === "experiment-ref" || experiment.type === "experiment");
|
|
67
|
+
if (!experiments) return;
|
|
68
|
+
let variations = [], uniqueValues = /* @__PURE__ */ new Set();
|
|
69
|
+
experiments.forEach((experiment) => {
|
|
70
|
+
experiment?.variations.forEach((variant) => {
|
|
71
|
+
let value = convertBooleans ? getBooleanConversion(variant.value) : variant.value;
|
|
72
|
+
uniqueValues.has(value) || (uniqueValues.add(value), variations.push({
|
|
73
|
+
id: value,
|
|
74
|
+
label: value
|
|
75
|
+
}));
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
let value = {
|
|
79
|
+
id: feature.id,
|
|
80
|
+
label: feature.id,
|
|
81
|
+
variants: variations
|
|
82
|
+
};
|
|
83
|
+
featureExperiments.push(value);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return featureExperiments.sort((a, b) => a.id.localeCompare(b.id));
|
|
111
87
|
}, fieldLevelExperiments = definePlugin((config) => {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
})
|
|
135
|
-
})],
|
|
136
|
-
form: {
|
|
137
|
-
components: {
|
|
138
|
-
input: (props) => {
|
|
139
|
-
if (!(props.id === "root" && isObjectInputProps(props)) || !flattenSchemaType(props.schemaType).map((field) => field.type.name).some((name) => name.startsWith("experiment")))
|
|
140
|
-
return props.renderDefault(props);
|
|
141
|
-
const providerProps = {
|
|
142
|
-
...props,
|
|
143
|
-
growthbookFieldPluginConfig: {
|
|
144
|
-
...pluginConfig
|
|
145
|
-
}
|
|
146
|
-
};
|
|
147
|
-
return GrowthbookProvider(providerProps);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
};
|
|
88
|
+
let pluginConfig = {
|
|
89
|
+
...GROWTHBOOK_CONFIG_DEFAULT,
|
|
90
|
+
...config
|
|
91
|
+
}, { fields, environment, project, convertBooleans, baseUrl, tags } = pluginConfig;
|
|
92
|
+
return {
|
|
93
|
+
name: "sanity-growthbook-personalistaion-plugin-field-level-experiments",
|
|
94
|
+
plugins: [fieldLevelExperiments$1({
|
|
95
|
+
fields,
|
|
96
|
+
experiments: (client) => getExperiments({
|
|
97
|
+
client,
|
|
98
|
+
environment,
|
|
99
|
+
baseUrl,
|
|
100
|
+
project,
|
|
101
|
+
convertBooleans,
|
|
102
|
+
tags
|
|
103
|
+
})
|
|
104
|
+
})],
|
|
105
|
+
form: { components: { input: (props) => !(props.id === "root" && isObjectInputProps(props)) || !flattenSchemaType(props.schemaType).map((field) => field.type.name).some((name) => name.startsWith("experiment")) ? props.renderDefault(props) : GrowthbookProvider({
|
|
106
|
+
...props,
|
|
107
|
+
growthbookFieldPluginConfig: { ...pluginConfig }
|
|
108
|
+
}) } }
|
|
109
|
+
};
|
|
152
110
|
});
|
|
153
|
-
export {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
//# sourceMappingURL=index.js.map
|
|
111
|
+
export { fieldLevelExperiments };
|
|
112
|
+
|
|
113
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
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 type {ObjectInputProps} from 'sanity'\n\nimport {useGrowthbookContext} from './GrowthbookContext'\n\nexport const namespace = 'growthbook'\nexport const apiKeyName = 'apiKey'\n\nconst pluginConfigKeys = [\n {\n key: apiKeyName,\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 // oxlint-disable-next-line react/react-compiler\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 type {ObjectInputProps} from 'sanity'\n\nimport type {GrowthbookContextProps, GrowthbookExperimentFieldPluginConfig} from '../types'\nimport {Secrets} from './Secrets'\n\nexport const GROWTHBOOK_CONFIG_DEFAULT = {\n baseUrl: 'https://api.growthbook.io/api/v1',\n}\n\nconst 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: GrowthbookExperimentFieldPluginConfig\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 type {SanityClient} from 'sanity'\n\nimport type {ExperimentType, GrowthbookFeature, VariantType} from '../types'\nimport {apiKeyName, namespace} from './Components/Secrets'\nimport type {GrowthbookExperimentFieldPluginConfig} 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<GrowthbookExperimentFieldPluginConfig, 'fields' | 'baseUrl'> & {\n client: SanityClient\n baseUrl: string\n}): Promise<ExperimentType[]> => {\n const query = `*[_id == 'secrets.${namespace}'][0].secrets.${apiKeyName}`\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 type {GrowthbookExperimentFieldPluginConfig} from './types'\nimport {getExperiments} from './utils'\n\nexport const fieldLevelExperiments = definePlugin<GrowthbookExperimentFieldPluginConfig>(\n (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)\n"],"names":["namespace","apiKeyName","pluginConfigKeys","key","title","Secrets","props","$","_c","secrets","loading","useSecrets","setSecret","useGrowthbookContext","showSettings","setShowSettings","useState","t0","t1","undefined","apiKey","useEffect","t2","renderDefault","Symbol","for","t3","t4","GROWTHBOOK_CONFIG_DEFAULT","baseUrl","GrowthbookContext","createContext","secret","useContext","GrowthbookProvider","growthbookFieldPluginConfig","context","getBooleanConversion","value","getExperiments","client","environment","project","convertBooleans","tags","query","fetch","featureExperiments","hasMore","offset","url","URL","searchParams","set","toString","response","headers","Authorization","features","responseHasMore","nextOffset","json","forEach","feature","archived","some","tag","includes","experiments","environments","rules","filter","experiment","type","variations","uniqueValues","Set","variant","has","add","push","id","label","variants","sort","a","b","localeCompare","fieldLevelExperiments","definePlugin","config","pluginConfig","fields","name","plugins","baseFieldLevelExperiments","form","components","input","isObjectInputProps","flattenSchemaType","schemaType","map","field","startsWith","providerProps"],"mappings":";;;;;;AAMO,MAAMA,YAAY,cACZC,aAAa,UAEpBC,mBAAmB,CACvB;AAAA,EACEC,KAAKF;AAAAA,EACLG,OAAO;AACT,CAAC,GAGUC,UAAUC,CAAAA,UAAA;AAAA,QAAAC,IAAAC,EAAA,EAAA,GACrB;AAAA,IAAAC;AAAAA,IAAAC;AAAAA,EAAAA,IAA2BC,WAAWX,SAAS,GAC/C;AAAA,IAAAY;AAAAA,EAAAA,IAAoBC,wBACpB,CAAAC,cAAAC,eAAA,IAAwCC,SAAkB,EAAK;AAAC,MAAAC,IAAAC;AAahE,MAbgEX,EAAA,CAAA,MAAAG,WAAAH,SAAAE,WAAAF,EAAA,CAAA,MAAAK,aAEtDK,KAAAA,MAAA;AACR,QAAIP,CAAAA;AACJ,aAAI,CAACD,WAAD,CAAaC,WACfE,UAAUO,MAAS,GAEZJ,gBAAgB,EAAI,MAE7BH,UAAUH,QAAOW,MAAO,GACjBL,gBAAgB,EAAK;AAAA,EAAC,GAC5BG,MAACT,SAASC,SAASE,SAAS,GAACL,OAAAG,SAAAH,OAAAE,SAAAF,OAAAK,WAAAL,OAAAU,IAAAV,OAAAW,OAAAD,KAAAV,EAAA,CAAA,GAAAW,KAAAX,EAAA,CAAA,IAThCc,UAAUJ,IASPC,EAA6B,GAE5B,CAACJ,cAAY;AAAA,QAAAQ;AAAA,WAAAf,SAAAD,SACRgB,MAAAhB,MAAKiB,cAAejB,KAAK,GAACC,OAAAD,OAAAC,OAAAe,OAAAA,MAAAf,EAAA,CAAA,GAA1Be;AAAAA,EAA0B;AAClC,MAAAA;AAAAf,IAAA,CAAA,MAAAiB,uBAAAC,IAAA,2BAAA,KAGGH,yBAAC,cAAA,EACQ,OAAA,qBACItB,WACLE,wBACG,SAAA,MAAA;AACPa,oBAAgB,EAAK;AAAA,EAAC,EAAA,CACvB,GACDR,OAAAe,MAAAA,KAAAf,EAAA,CAAA;AAAA,MAAAmB;AAAAnB,WAAAD,SACDoB,KAAApB,MAAKiB,cAAejB,KAAK,GAACC,OAAAD,OAAAC,OAAAmB,MAAAA,KAAAnB,EAAA,CAAA;AAAA,MAAAoB;AAAA,SAAApB,UAAAmB,MAT7BC,sCACEL,UAAAA;AAAAA,IAAAA;AAAAA,IAQCI;AAAAA,EAAAA,EAAAA,CAA0B,GAC1BnB,QAAAmB,IAAAnB,QAAAoB,MAAAA,KAAApB,EAAA,EAAA,GAVHoB;AAUG,GCxCMC,4BAA4B;AAAA,EACvCC,SAAS;AACX,GAEMC,oBAAoBC,cAAsC;AAAA,EAC9DnB,WAAWA,MAAA;AAAA,EAAA;AAAA,EACXoB,QAAQb;AACV,CAAC;AAEM,SAAAN,uBAAA;AAAA,SACEoB,WAAWH,iBAAiB;AAAC;AAO/B,SAAAI,mBAAA5B,OAAA;AAAA,QAAAC,IAAAC,EAAA,CAAA,GACL;AAAA,IAAA2B;AAAAA,EAAAA,IAAsC7B,OACtC,CAAA0B,QAAApB,SAAA,IAA4BI,SAAAA;AAA8B,MAAAC;AAAAV,IAAA,CAAA,MAAA4B,+BAAA5B,SAAAyB,UAGjDf,KAAA;AAAA,IAAA,GAAIkB;AAAAA,IAA2BH;AAAAA,IAAApB;AAAAA,EAAAA,GAAoBL,OAAA4B,6BAAA5B,OAAAyB,QAAAzB,OAAAU,MAAAA,KAAAV,EAAA,CAAA;AAD5D,QAAA6B,UACSnB;AAER,MAAAC;AAAAX,WAAAD,SAIGY,KAAA,oBAAC,SAAA,EAAO,GAAKZ,OAAK,GAAIC,OAAAD,OAAAC,OAAAW,MAAAA,KAAAX,EAAA,CAAA;AAAA,MAAAe;AAAA,SAAAf,EAAA,CAAA,MAAA6B,WAAA7B,SAAAW,MADxBI,KAAA,oBAAA,kBAAA,UAAA,EAAmCc,OAAAA,SACjClB,UAAAA,GAAAA,CACF,GAA6BX,OAAA6B,SAAA7B,OAAAW,IAAAX,OAAAe,MAAAA,KAAAf,EAAA,CAAA,GAF7Be;AAE6B;AC7BjC,MAAMe,uBAAwBC,CAAAA,UAExBA,UAAU,SACL,YACEA,UAAU,UACZ,YAEFA,OAGIC,iBAAiB,OAAO;AAAA,EACnCC;AAAAA,EACAC;AAAAA,EACAZ;AAAAA,EACAa;AAAAA,EACAC;AAAAA,EACAC;AAIF,MAAiC;AAC/B,QAAMC,QAAQ,qBAAqB7C,SAAS,iBAAiBC,UAAU,IAEjE+B,SAAS,MAAMQ,OAAOM,MAAMD,KAAK;AACvC,MAAI,CAACb,OAAQ,QAAO,CAAA;AAEpB,QAAMe,qBAAuC,CAAA;AAC7C,MAAIC,UAAU,IACVC,SAAS;AACb,QAAMC,MAAM,IAAIC,IAAI,GAAGtB,OAAO,WAAW;AAKzC,OAJIa,WACFQ,IAAIE,aAAaC,IAAI,aAAaX,OAAO,GAGpCM,WAAS;AACdE,QAAIE,aAAaC,IAAI,UAAUJ,OAAOK,UAAU;AAChD,UAAMC,WAAW,MAAMT,MAAMI,KAAK;AAAA,MAChCM,SAAS;AAAA,QACPC,eAAe,UAAUzB,MAAM;AAAA,MAAA;AAAA,IACjC,CACD,GAEK;AAAA,MAAC0B;AAAAA,MAAUV,SAASW;AAAAA,MAAiBC;AAAAA,IAAAA,IAAc,MAAML,SAASM,KAAAA;AAExEb,cAAUW,iBACVV,SAASW,YACJF,YAELA,SAASI,QAASC,CAAAA,YAA+B;AAI/C,UAHIA,QAAQC,YAGRpB,QAAQmB,QAAQnB,QAAQ,CAACmB,QAAQnB,KAAKqB,KAAMC,CAAAA,QAAQtB,KAAKuB,SAASD,GAAG,CAAC;AACxE;AAGF,YAAME,cAAcL,QAAQM,aAAa5B,WAAW,GAAG6B,MAAMC,OAC1DC,CAAAA,eAAeA,WAAWC,SAAS,oBAAoBD,WAAWC,SAAS,YAC9E;AAEA,UAAI,CAACL;AACH;AAGF,YAAMM,aAA4B,CAAA,GAC5BC,mCAAmBC,IAAAA;AAEzBR,kBAAYN,QAASU,CAAAA,eAAe;AAClCA,oBAAYE,WAAWZ,QAASe,CAAAA,YAAY;AAC1C,gBAAMvC,SAAQK,kBAAkBN,qBAAqBwC,QAAQvC,KAAK,IAAIuC,QAAQvC;AACzEqC,uBAAaG,IAAIxC,MAAK,MACzBqC,aAAaI,IAAIzC,MAAK,GACtBoC,WAAWM,KAAK;AAAA,YACdC,IAAI3C;AAAAA,YACJ4C,OAAO5C;AAAAA,UAAAA,CACR;AAAA,QAEL,CAAC;AAAA,MACH,CAAC;AACD,YAAMA,QAAQ;AAAA,QAAC2C,IAAIlB,QAAQkB;AAAAA,QAAIC,OAAOnB,QAAQkB;AAAAA,QAAIE,UAAUT;AAAAA,MAAAA;AAE5D3B,yBAAmBiC,KAAK1C,KAAK;AAAA,IAE/B,CAAC;AAAA,EACH;AAEA,SADiCS,mBAAmBqC,KAAK,CAACC,GAAGC,MAAMD,EAAEJ,GAAGM,cAAcD,EAAEL,EAAE,CAAC;AAE7F,GCrFaO,wBAAwBC,aAClCC,CAAAA,WAAW;AACV,QAAMC,eAAe;AAAA,IAAC,GAAG/D;AAAAA,IAA2B,GAAG8D;AAAAA,EAAAA,GACjD;AAAA,IAACE;AAAAA,IAAQnD;AAAAA,IAAaC;AAAAA,IAASC;AAAAA,IAAiBd;AAAAA,IAASe;AAAAA,EAAAA,IAAQ+C;AACvE,SAAO;AAAA,IACLE,MAAM;AAAA,IACNC,SAAS,CACPC,wBAA0B;AAAA,MACxBH;AAAAA,MACAxB,aAAc5B,YACZD,eAAe;AAAA,QAACC;AAAAA,QAAQC;AAAAA,QAAaZ;AAAAA,QAASa;AAAAA,QAASC;AAAAA,QAAiBC;AAAAA,MAAAA,CAAK;AAAA,IAAA,CAChF,CAAC;AAAA,IAGJoD,MAAM;AAAA,MACJC,YAAY;AAAA,QACVC,OAAQ5F,CAAAA,UAAU;AAahB,cAVI,EAFgBA,MAAM2E,OAAO,UAAUkB,mBAAmB7F,KAAK,MAY/D,CANuB8F,kBAAkB9F,MAAM+F,UAAU,EAAEC,IAC5DC,CAAAA,UAAUA,MAAM9B,KAAKoB,IACxB,EAEyC5B,KAAM4B,CAAAA,SAASA,KAAKW,WAAW,YAAY,CAAC;AAGnF,mBAAOlG,MAAMiB,cAAcjB,KAAK;AAGlC,gBAAMmG,gBAAgB;AAAA,YACpB,GAAGnG;AAAAA,YACH6B,6BAA6B;AAAA,cAC3B,GAAGwD;AAAAA,YAAAA;AAAAA,UACL;AAEF,iBAAOzD,mBAAmBuE,aAAa;AAAA,QACzC;AAAA,MAAA;AAAA,IACF;AAAA,EACF;AAEJ,CACF;"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["SettingsView","useSecrets","useEffect","useState","ObjectInputProps","useGrowthbookContext","namespace","apiKeyName","pluginConfigKeys","key","title","Secrets","props","$","_c","secrets","loading","apiKey","setSecret","showSettings","setShowSettings","t0","t1","undefined","t2","renderDefault","Symbol","for","t3","t4","createContext","useContext","useMemo","useState","ObjectInputProps","GrowthbookContextProps","GrowthbookExperimentFieldPluginConfig","Secrets","GROWTHBOOK_CONFIG_DEFAULT","baseUrl","GrowthbookContext","setSecret","undefined","secret","useGrowthbookContext","GrowthbookProps","growthbookFieldPluginConfig","GrowthbookProvider","props","$","_c","t0","context","t1","t2","SanityClient","ExperimentType","GrowthbookFeature","VariantType","apiKeyName","namespace","GrowthbookExperimentFieldPluginConfig","getBooleanConversion","value","getExperiments","client","environment","baseUrl","project","convertBooleans","tags","Omit","Promise","query","secret","fetch","featureExperiments","hasMore","offset","url","URL","searchParams","set","toString","response","headers","Authorization","features","responseHasMore","nextOffset","json","forEach","feature","archived","undefined","some","tag","includes","experiments","environments","rules","filter","experiment","type","variations","uniqueValues","Set","variant","has","add","push","id","label","variants","sortedFeatureExperiments","sort","a","b","localeCompare","definePlugin","isObjectInputProps","fieldLevelExperiments","baseFieldLevelExperiments","flattenSchemaType","GROWTHBOOK_CONFIG_DEFAULT","GrowthbookProvider","GrowthbookExperimentFieldPluginConfig","getExperiments","config","pluginConfig","fields","environment","project","convertBooleans","baseUrl","tags","name","plugins","experiments","client","form","components","input","props","isRootInput","id","renderDefault","flatFieldTypeNames","schemaType","map","field","type","hasExperiment","some","startsWith","providerProps","growthbookFieldPluginConfig"],"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 type {ObjectInputProps} from 'sanity'\n\nimport {useGrowthbookContext} from './GrowthbookContext'\n\nexport const namespace = 'growthbook'\nexport const apiKeyName = 'apiKey'\n\nconst pluginConfigKeys = [\n {\n key: apiKeyName,\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 // oxlint-disable-next-line react/react-compiler\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 type {ObjectInputProps} from 'sanity'\n\nimport type {GrowthbookContextProps, GrowthbookExperimentFieldPluginConfig} from '../types'\nimport {Secrets} from './Secrets'\n\nexport const GROWTHBOOK_CONFIG_DEFAULT = {\n baseUrl: 'https://api.growthbook.io/api/v1',\n}\n\nconst 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: GrowthbookExperimentFieldPluginConfig\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 type {SanityClient} from 'sanity'\n\nimport type {ExperimentType, GrowthbookFeature, VariantType} from '../types'\nimport {apiKeyName, namespace} from './Components/Secrets'\nimport type {GrowthbookExperimentFieldPluginConfig} 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<GrowthbookExperimentFieldPluginConfig, 'fields' | 'baseUrl'> & {\n client: SanityClient\n baseUrl: string\n}): Promise<ExperimentType[]> => {\n const query = `*[_id == 'secrets.${namespace}'][0].secrets.${apiKeyName}`\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 type {GrowthbookExperimentFieldPluginConfig} from './types'\nimport {getExperiments} from './utils'\n\nexport const fieldLevelExperiments = definePlugin<GrowthbookExperimentFieldPluginConfig>(\n (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)\n"],"mappings":";;;;;;AAMA,MAAaM,YAAY,cACZC,aAAa,UAEpBC,mBAAmB,CACvB;CACEC,KAAKF;CACLG,OAAO;AACT,CAAC,GAGUC,WAAUC,UAAA;CAAA,IAAAC,IAAAC,EAAA,EAAA,GACrB,EAAAC,SAAAC,YAA2Bf,WAAWK,SAAS,GAC/C,EAAAY,cAAoBb,qBAAqB,GACzC,CAAAc,cAAAC,mBAAwCjB,SAAkB,EAAK,GAACkB,IAAAC;CAahE,IAbgET,EAAA,OAAAG,WAAAH,EAAA,OAAAE,WAAAF,EAAA,OAAAK,aAEtDG,WAAA;EACJL,cAMqB,OALrB,CAACD,WAAD,CAAaC,WACfE,UAAUK,KAAAA,CAAS,GAEZH,gBAAgB,EAAI,MAE7BF,UAAUH,QAAOE,MAAO,GACjBG,gBAAgB,EAAK;CAAC,GAC5BE,KAAA;EAACP;EAASC;EAASE;CAAS,GAACL,EAAA,KAAAG,SAAAH,EAAA,KAAAE,SAAAF,EAAA,KAAAK,WAAAL,EAAA,KAAAQ,IAAAR,EAAA,KAAAS,OAAAD,KAAAR,EAAA,IAAAS,KAAAT,EAAA,KAThCX,UAAUmB,IASPC,EAA6B,GAE5B,CAACH,cAAY;EAAA,IAAAK;EACkB,OADlBX,EAAA,OAAAD,QACkBY,KAAAX,EAAA,MAA1BW,KAAAZ,MAAKa,cAAeb,KAAK,GAACC,EAAA,KAAAD,OAAAC,EAAA,KAAAW,KAA1BA;CAA0B;CAClC,IAAAA;CAAA,AAAAX,EAAA,OAAAa,OAAAC,IAAA,2BAAA,KAGGH,KAAA,oBAAC,cAAD;EACS,OAAA;EACIlB;EACLE,MAAAA;EACG,eAAA;GACPY,gBAAgB,EAAK;EAAC;CACvB,CAAA,GACDP,EAAA,KAAAW,MAAAA,KAAAX,EAAA;CAAA,IAAAe;CAAA,AAAAf,EAAA,OAAAD,QACyBgB,KAAAf,EAAA,MAA1Be,KAAAhB,MAAKa,cAAeb,KAAK,GAACC,EAAA,KAAAD,OAAAC,EAAA,KAAAe;CAAA,IAAAC;CAC1B,OAD0BhB,EAAA,QAAAe,KAC1BC,KAAAhB,EAAA,OAVHgB,KAAA,qBAAA,UAAA,EAAA,UAAA,CACEL,IAQCI,EAA0B,EAAA,CAAA,GAC1Bf,EAAA,MAAAe,IAAAf,EAAA,MAAAgB,KAVHA;AAUG,GCxCMS,4BAA4B,EACvCC,SAAS,mCACX,GAEMC,oBAAoBV,cAAsC;CAC9DW,iBAAiBC,KAAAA;CACjBC,QAAQD,KAAAA;AACV,CAAC;AAED,SAAOE,uBAAA;CAAA,OACEb,WAAWS,iBAAiB;AAAC;AAOtC,SAAOO,mBAAAC,OAAA;CAAA,IAAAC,IAAAC,EAAA,CAAA,GACL,EAAAJ,gCAAsCE,OACtC,CAAAL,QAAAF,aAA4BR,SAA6B,GAACkB;CAAA,AAAAF,EAAA,OAAAH,+BAAAG,EAAA,OAAAN,UAGjDQ,KAAA;EAAA,GAAIL;EAA2BH;EAAAF;CAAmB,GAACQ,EAAA,KAAAH,6BAAAG,EAAA,KAAAN,QAAAM,EAAA,KAAAE,MAAAA,KAAAF,EAAA;CAD5D,IAAAG,UACSD,IAERE;CAAA,AAAAJ,EAAA,OAAAD,QAIyBK,KAAAJ,EAAA,MAAtBI,KAAA,oBAAC,SAAD,EAAQ,GAAKL,MAAK,CAAA,GAAIC,EAAA,KAAAD,OAAAC,EAAA,KAAAI;CAAA,IAAAC;CACK,OADLL,EAAA,OAAAG,WAAAH,EAAA,OAAAI,MADxBC,KAAA,oBAAA,kBAAA,UAAA;EAAmCF,OAAAA;YACjCC;CACF,CAAA,GAA6BJ,EAAA,KAAAG,SAAAH,EAAA,KAAAI,IAAAJ,EAAA,KAAAK,MAAAA,KAAAL,EAAA,IAF7BK;AAE6B;AC7BjC,MAAMQ,wBAAwBC,UAExBA,UAAU,SACL,YACEA,UAAU,UACZ,YAEFA,OAGIC,iBAAiB,OAAO,EACnCC,QACAC,aACAC,SACAC,SACAC,iBACAC,WAI+B;CAC/B,IAAMG,QAAQ,qBAAqBb,UAAS,gBAAiBD,cAEvDe,SAAS,MAAMT,OAAOU,MAAMF,KAAK;CACvC,IAAI,CAACC,QAAQ,OAAO,CAAA;CAEpB,IAAME,qBAAuC,CAAA,GACzCC,UAAU,IACVC,SAAS,GACPC,MAAM,IAAIC,IAAI,GAAGb,QAAO,UAAW;CAKzC,KAJIC,WACFW,IAAIE,aAAaC,IAAI,aAAad,OAAO,GAGpCS,UAAS;EACdE,IAAIE,aAAaC,IAAI,UAAUJ,OAAOK,SAAS,CAAC;EAOhD,IAAM,EAACI,UAAUV,SAASW,iBAAiBC,eAAc,OAAML,MANxCT,MAAMI,KAAK,EAChCM,SAAS,EACPC,eAAe,UAAUZ,SAC3B,EACF,CAAC,EAAA,CAEuEgB,KAAK;EAE7Eb,UAAUW,iBACVV,SAASW,YACJF,YAELA,SAASI,SAASC,YAA+B;GAI/C,IAHIA,QAAQC,YAGRvB,QAAQsB,QAAQtB,QAAQ,CAACsB,QAAQtB,KAAKyB,MAAMC,QAAQ1B,KAAK2B,SAASD,GAAG,CAAC,GACxE;GAGF,IAAME,cAAcN,QAAQO,aAAajC,YAAY,EAAEkC,MAAMC,QAC1DC,eAAeA,WAAWC,SAAS,oBAAoBD,WAAWC,SAAS,YAC9E;GAEA,IAAI,CAACL,aACH;GAGF,IAAMM,aAA4B,CAAA,GAC5BC,+BAAe,IAAIC,IAAY;GAErCR,YAAYP,SAASW,eAAe;IAClCA,YAAYE,WAAWb,SAASgB,YAAY;KAC1C,IAAM5C,QAAQM,kBAAkBP,qBAAqB6C,QAAQ5C,KAAK,IAAI4C,QAAQ5C;KAC9E,AAAK0C,aAAaG,IAAI7C,KAAK,MACzB0C,aAAaI,IAAI9C,KAAK,GACtByC,WAAWM,KAAK;MACdC,IAAIhD;MACJiD,OAAOjD;KACT,CAAC;IAEL,CAAC;GACH,CAAC;GACD,IAAMA,QAAQ;IAACgD,IAAInB,QAAQmB;IAAIC,OAAOpB,QAAQmB;IAAIE,UAAUT;GAAU;GAEtE5B,mBAAmBkC,KAAK/C,KAAK;EAE/B,CAAC;CACH;CAEA,OADiCa,mBAAmBuC,MAAMC,GAAGC,MAAMD,EAAEL,GAAGO,cAAcD,EAAEN,EAAE,CACnFG;AACT,GCrFaO,wBAAwBF,cAClCS,WAAW;CACV,IAAMC,eAAe;EAAC,GAAGL;EAA2B,GAAGI;CAAM,GACvD,EAACE,QAAQC,aAAaC,SAASC,iBAAiBC,SAASC,SAAQN;CACvE,OAAO;EACLO,MAAM;EACNC,SAAS,CACPf,wBAA0B;GACxBQ;GACAQ,cAAcC,WACZZ,eAAe;IAACY;IAAQR;IAAaG;IAASF;IAASC;IAAiBE;GAAI,CAAC;EACjF,CAAC,CAAC;EAGJK,MAAM,EACJC,YAAY,EACVC,QAAQC,UAGF,EAFgBA,MAAME,OAAO,UAAUzB,mBAAmBuB,KAAK,MAY/D,CANuBpB,kBAAkBoB,MAAMK,UAAU,CAAC,CAACC,KAC5DC,UAAUA,MAAMC,KAAKf,IAGFW,CAAkB,CAACM,MAAMjB,SAASA,KAAKkB,WAAW,YAAY,CAE/EF,IACIT,MAAMG,cAAcH,KAAK,IAS3BlB,mBAAmB8B;GALxB,GAAGZ;GACHa,6BAA6B,EAC3B,GAAG3B,aACL;EAEwB0B,CAAa,EAE3C,EACF;CACF;AACF,CACF"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
3
|
-
fieldLevelExperiments,
|
|
4
|
-
flattenSchemaType
|
|
5
|
-
};
|
|
6
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
import { n as flattenSchemaType, t as fieldLevelExperiments } from "./fieldExperiments.js";
|
|
2
|
+
export { fieldLevelExperiments, flattenSchemaType };
|
|
@@ -1,131 +1,100 @@
|
|
|
1
|
+
import { n as flattenSchemaType, t as fieldLevelExperiments$1 } from "../fieldExperiments.js";
|
|
1
2
|
import { definePlugin, isObjectInputProps } from "sanity";
|
|
2
|
-
import { flattenSchemaType, fieldLevelExperiments as fieldLevelExperiments$1 } from "../_chunks-es/fieldExperiments.js";
|
|
3
|
-
import { jsxs, Fragment, jsx } from "react/jsx-runtime";
|
|
4
3
|
import { c } from "react/compiler-runtime";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { createContext, useContext, useEffect, useState } from "react";
|
|
5
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { SettingsView, useSecrets } from "@sanity/studio-secrets";
|
|
7
7
|
const namespace = "launchdarkly", pluginConfigKeys = [{
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
key: "apiKey",
|
|
9
|
+
title: "Your secret API key"
|
|
10
10
|
}], Secrets = (props) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
] }), $[10] = t3, $[11] = t4) : t4 = $[11], t4;
|
|
11
|
+
let $ = c(12), { secrets, loading } = useSecrets(namespace), { setSecret } = useLaunchDarklyContext(), [showSettings, setShowSettings] = useState(!1), t0, t1;
|
|
12
|
+
if ($[0] !== loading || $[1] !== secrets || $[2] !== setSecret ? (t0 = () => {
|
|
13
|
+
if (!loading) return !secrets && !loading ? (setSecret(void 0), setShowSettings(!0)) : (setSecret(secrets.apiKey), setShowSettings(!1));
|
|
14
|
+
}, t1 = [
|
|
15
|
+
secrets,
|
|
16
|
+
loading,
|
|
17
|
+
setSecret
|
|
18
|
+
], $[0] = loading, $[1] = secrets, $[2] = setSecret, $[3] = t0, $[4] = t1) : (t0 = $[3], t1 = $[4]), useEffect(t0, t1), !showSettings) {
|
|
19
|
+
let t2;
|
|
20
|
+
return $[5] === props ? t2 = $[6] : (t2 = props.renderDefault(props), $[5] = props, $[6] = t2), t2;
|
|
21
|
+
}
|
|
22
|
+
let t2;
|
|
23
|
+
$[7] === Symbol.for("react.memo_cache_sentinel") ? (t2 = /* @__PURE__ */ jsx(SettingsView, {
|
|
24
|
+
title: `${namespace} api key`,
|
|
25
|
+
namespace,
|
|
26
|
+
keys: pluginConfigKeys,
|
|
27
|
+
onClose: () => {
|
|
28
|
+
setShowSettings(!1);
|
|
29
|
+
}
|
|
30
|
+
}), $[7] = t2) : t2 = $[7];
|
|
31
|
+
let t3;
|
|
32
|
+
$[8] === props ? t3 = $[9] : (t3 = props.renderDefault(props), $[8] = props, $[9] = t3);
|
|
33
|
+
let t4;
|
|
34
|
+
return $[10] === t3 ? t4 = $[11] : (t4 = /* @__PURE__ */ jsxs(Fragment, { children: [t2, t3] }), $[10] = t3, $[11] = t4), t4;
|
|
36
35
|
}, LAUNCHDARKLY_CONFIG_DEFAULT = {}, LaunchDarklyContext = createContext({
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
secret: void 0
|
|
36
|
+
setSecret: () => void 0,
|
|
37
|
+
secret: void 0
|
|
40
38
|
});
|
|
41
39
|
function useLaunchDarklyContext() {
|
|
42
|
-
|
|
40
|
+
return useContext(LaunchDarklyContext);
|
|
43
41
|
}
|
|
44
42
|
function LaunchDarklyProvider(props) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return $[5] !== context || $[6] !== t1 ? (t2 = /* @__PURE__ */ jsx(LaunchDarklyContext.Provider, { value: context, children: t1 }), $[5] = context, $[6] = t1, $[7] = t2) : t2 = $[7], t2;
|
|
43
|
+
let $ = c(8), { launchDarklyFieldPluginConfig } = props, [secret, setSecret] = useState(), t0;
|
|
44
|
+
$[0] !== launchDarklyFieldPluginConfig || $[1] !== secret ? (t0 = {
|
|
45
|
+
...launchDarklyFieldPluginConfig,
|
|
46
|
+
secret,
|
|
47
|
+
setSecret
|
|
48
|
+
}, $[0] = launchDarklyFieldPluginConfig, $[1] = secret, $[2] = t0) : t0 = $[2];
|
|
49
|
+
let context = t0, t1;
|
|
50
|
+
$[3] === props ? t1 = $[4] : (t1 = /* @__PURE__ */ jsx(Secrets, { ...props }), $[3] = props, $[4] = t1);
|
|
51
|
+
let t2;
|
|
52
|
+
return $[5] !== context || $[6] !== t1 ? (t2 = /* @__PURE__ */ jsx(LaunchDarklyContext.Provider, {
|
|
53
|
+
value: context,
|
|
54
|
+
children: t1
|
|
55
|
+
}), $[5] = context, $[6] = t1, $[7] = t2) : t2 = $[7], t2;
|
|
59
56
|
}
|
|
60
|
-
const getExperiments = async ({
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
items
|
|
80
|
-
} = await responseFlags.json(), experiments = items.map((flag) => ({
|
|
81
|
-
id: flag.key,
|
|
82
|
-
label: flag.name,
|
|
83
|
-
variants: flag.variations.map((variation) => ({
|
|
84
|
-
id: variation.value.toString(),
|
|
85
|
-
label: variation.name ?? variation.value.toString()
|
|
86
|
-
}))
|
|
87
|
-
}));
|
|
88
|
-
featureExperiments.push(...experiments), items.length !== limit && (hasMore = !1);
|
|
89
|
-
}
|
|
90
|
-
return featureExperiments;
|
|
57
|
+
const getExperiments = async ({ client, projectKey, tags }) => {
|
|
58
|
+
let secret = await client.fetch("*[_id == 'secrets.launchdarkly'][0].secrets.apiKey");
|
|
59
|
+
if (!secret) return [];
|
|
60
|
+
let url = new URL(`https://app.launchdarkly.com/api/v2/flags/${projectKey}`);
|
|
61
|
+
tags && url.searchParams.set("filter", `tags:${tags.join("+")}`);
|
|
62
|
+
let featureExperiments = [], hasMore = !0;
|
|
63
|
+
for (; hasMore;) {
|
|
64
|
+
url.searchParams.set("offset", "0"), url.searchParams.set("limit", "10");
|
|
65
|
+
let { items } = await (await fetch(url, { headers: { Authorization: secret } })).json(), experiments = items.map((flag) => ({
|
|
66
|
+
id: flag.key,
|
|
67
|
+
label: flag.name,
|
|
68
|
+
variants: flag.variations.map((variation) => ({
|
|
69
|
+
id: variation.value.toString(),
|
|
70
|
+
label: variation.name ?? variation.value.toString()
|
|
71
|
+
}))
|
|
72
|
+
}));
|
|
73
|
+
featureExperiments.push(...experiments), items.length !== 10 && (hasMore = !1);
|
|
74
|
+
}
|
|
75
|
+
return featureExperiments;
|
|
91
76
|
}, fieldLevelExperiments = definePlugin((config) => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
components: {
|
|
113
|
-
input: (props) => {
|
|
114
|
-
if (!(props.id === "root" && isObjectInputProps(props)) || !flattenSchemaType(props.schemaType).map((field) => field.type.name).some((name) => name.startsWith("flag")))
|
|
115
|
-
return props.renderDefault(props);
|
|
116
|
-
const providerProps = {
|
|
117
|
-
...props,
|
|
118
|
-
launchDarklyFieldPluginConfig: {
|
|
119
|
-
...pluginConfig
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
return LaunchDarklyProvider(providerProps);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
};
|
|
77
|
+
let pluginConfig = {
|
|
78
|
+
...LAUNCHDARKLY_CONFIG_DEFAULT,
|
|
79
|
+
...config
|
|
80
|
+
}, { fields, projectKey, tags } = pluginConfig;
|
|
81
|
+
return {
|
|
82
|
+
name: "sanity-growthbook-personalistaion-plugin-field-level-experiments",
|
|
83
|
+
plugins: [fieldLevelExperiments$1({
|
|
84
|
+
fields,
|
|
85
|
+
experiments: (client) => getExperiments({
|
|
86
|
+
client,
|
|
87
|
+
projectKey,
|
|
88
|
+
tags
|
|
89
|
+
}),
|
|
90
|
+
experimentNameOverride: "flag"
|
|
91
|
+
})],
|
|
92
|
+
form: { components: { input: (props) => !(props.id === "root" && isObjectInputProps(props)) || !flattenSchemaType(props.schemaType).map((field) => field.type.name).some((name) => name.startsWith("flag")) ? props.renderDefault(props) : LaunchDarklyProvider({
|
|
93
|
+
...props,
|
|
94
|
+
launchDarklyFieldPluginConfig: { ...pluginConfig }
|
|
95
|
+
}) } }
|
|
96
|
+
};
|
|
127
97
|
});
|
|
128
|
-
export {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
//# sourceMappingURL=index.js.map
|
|
98
|
+
export { fieldLevelExperiments };
|
|
99
|
+
|
|
100
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/launchDarkly/components/Secrets.tsx","../../src/launchDarkly/components/LaunchDarklyContext.tsx","../../src/launchDarkly/utils.ts","../../src/launchDarkly/index.ts"],"sourcesContent":["import {SettingsView, useSecrets} from '@sanity/studio-secrets'\nimport {useEffect, useState} from 'react'\nimport type {ObjectInputProps} from 'sanity'\n\nimport {useLaunchDarklyContext} from './LaunchDarklyContext'\n\nconst namespace = 'launchdarkly'\nconst 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} = useLaunchDarklyContext()\n const [showSettings, setShowSettings] = useState<boolean>(false)\n\n useEffect(() => {\n if (loading) return undefined\n if (!secrets && !loading) {\n setSecret(undefined)\n // oxlint-disable-next-line react/react-compiler\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={`${namespace} api key`}\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 type {ObjectInputProps} from 'sanity'\n\nimport type {LaunchDarklyContextProps, LaunchDarklyFieldLevelConfig} from '../types'\nimport {Secrets} from './Secrets'\n\nexport const LAUNCHDARKLY_CONFIG_DEFAULT = {}\n\nconst LaunchDarklyContext = createContext<LaunchDarklyContextProps>({\n setSecret: () => undefined,\n secret: undefined,\n})\n\nexport function useLaunchDarklyContext() {\n return useContext(LaunchDarklyContext)\n}\n\ntype LaunchDarklyProps = ObjectInputProps & {\n launchDarklyFieldPluginConfig: LaunchDarklyFieldLevelConfig\n}\n\nexport function LaunchDarklyProvider(props: LaunchDarklyProps) {\n const {launchDarklyFieldPluginConfig} = props\n const [secret, setSecret] = useState<string | undefined>()\n\n const context = useMemo(\n () => ({...launchDarklyFieldPluginConfig, secret, setSecret}),\n [launchDarklyFieldPluginConfig, secret, setSecret],\n )\n\n return (\n <LaunchDarklyContext.Provider value={context}>\n <Secrets {...props} />\n </LaunchDarklyContext.Provider>\n )\n}\n","import type {SanityClient} from 'sanity'\n\nimport type {ExperimentType} from '../types'\nimport type {LaunchDarklyFieldLevelConfig, LaunchDarklyFlagItem} from './types'\n\nexport const getExperiments = async ({\n client,\n projectKey,\n tags,\n}: Omit<LaunchDarklyFieldLevelConfig, 'fields'> & {client: SanityClient}): Promise<\n ExperimentType[]\n> => {\n const query = `*[_id == 'secrets.launchdarkly'][0].secrets.apiKey`\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 url = new URL(`https://app.launchdarkly.com/api/v2/flags/${projectKey}`)\n\n if (tags) {\n url.searchParams.set('filter', `tags:${tags.join('+')}`)\n }\n\n const featureExperiments: ExperimentType[] = []\n let hasMore = true\n const offset = 0\n const limit = 10\n\n while (hasMore) {\n url.searchParams.set('offset', offset.toString())\n url.searchParams.set('limit', limit.toString())\n const responseFlags = await fetch(url, {\n headers: {\n Authorization: secret,\n },\n })\n\n const {items} = await responseFlags.json()\n const experiments = items.map((flag: LaunchDarklyFlagItem) => ({\n id: flag.key,\n label: flag.name,\n variants: flag.variations.map((variation) => ({\n id: variation.value.toString(),\n label: variation.name ?? variation.value.toString(),\n })),\n }))\n featureExperiments.push(...experiments)\n if (items.length !== limit) {\n hasMore = false\n }\n }\n\n return featureExperiments\n}\n","import {definePlugin, isObjectInputProps} from 'sanity'\n\nimport {fieldLevelExperiments as baseFieldLevelExperiments} from '../fieldExperiments'\nimport {flattenSchemaType} from '../utils/flattenSchemaType'\nimport {LAUNCHDARKLY_CONFIG_DEFAULT, LaunchDarklyProvider} from './components/LaunchDarklyContext'\nimport type {LaunchDarklyFieldLevelConfig} from './types'\nimport {getExperiments} from './utils'\n\nexport const fieldLevelExperiments = definePlugin<LaunchDarklyFieldLevelConfig>((config) => {\n const pluginConfig = {...LAUNCHDARKLY_CONFIG_DEFAULT, ...config}\n const {fields, projectKey, tags} = pluginConfig\n return {\n name: 'sanity-growthbook-personalistaion-plugin-field-level-experiments',\n plugins: [\n baseFieldLevelExperiments({\n fields,\n experiments: (client) => getExperiments({client, projectKey, tags}),\n experimentNameOverride: 'flag',\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('flag'))\n\n if (!hasExperiment) {\n return props.renderDefault(props)\n }\n\n const providerProps = {\n ...props,\n launchDarklyFieldPluginConfig: {\n ...pluginConfig,\n },\n }\n return LaunchDarklyProvider(providerProps)\n },\n },\n },\n }\n})\n"],"names":["namespace","pluginConfigKeys","key","title","Secrets","props","$","_c","secrets","loading","useSecrets","setSecret","useLaunchDarklyContext","showSettings","setShowSettings","useState","t0","t1","undefined","apiKey","useEffect","t2","renderDefault","for","t3","t4","LAUNCHDARKLY_CONFIG_DEFAULT","LaunchDarklyContext","createContext","secret","useContext","LaunchDarklyProvider","launchDarklyFieldPluginConfig","context","getExperiments","client","projectKey","tags","fetch","url","URL","searchParams","set","join","featureExperiments","hasMore","offset","limit","toString","responseFlags","headers","Authorization","items","json","experiments","map","flag","id","label","name","variants","variations","variation","value","push","length","fieldLevelExperiments","definePlugin","config","pluginConfig","fields","plugins","baseFieldLevelExperiments","experimentNameOverride","form","components","input","isObjectInputProps","flattenSchemaType","schemaType","field","type","some","startsWith","providerProps"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["SettingsView","useSecrets","useEffect","useState","ObjectInputProps","useLaunchDarklyContext","namespace","pluginConfigKeys","key","title","Secrets","props","$","_c","secrets","loading","apiKey","setSecret","showSettings","setShowSettings","t0","t1","undefined","t2","renderDefault","Symbol","for","t3","t4","createContext","useContext","useMemo","useState","ObjectInputProps","LaunchDarklyContextProps","LaunchDarklyFieldLevelConfig","Secrets","LAUNCHDARKLY_CONFIG_DEFAULT","LaunchDarklyContext","setSecret","undefined","secret","useLaunchDarklyContext","LaunchDarklyProps","launchDarklyFieldPluginConfig","LaunchDarklyProvider","props","$","_c","t0","context","t1","t2","SanityClient","ExperimentType","LaunchDarklyFieldLevelConfig","LaunchDarklyFlagItem","getExperiments","client","projectKey","tags","Omit","Promise","query","secret","fetch","url","URL","searchParams","set","join","featureExperiments","hasMore","offset","limit","toString","responseFlags","headers","Authorization","items","json","experiments","map","flag","id","key","label","name","variants","variations","variation","value","push","length","definePlugin","isObjectInputProps","fieldLevelExperiments","baseFieldLevelExperiments","flattenSchemaType","LAUNCHDARKLY_CONFIG_DEFAULT","LaunchDarklyProvider","LaunchDarklyFieldLevelConfig","getExperiments","config","pluginConfig","fields","projectKey","tags","name","plugins","experiments","client","experimentNameOverride","form","components","input","props","isRootInput","id","renderDefault","flatFieldTypeNames","schemaType","map","field","type","hasExperiment","some","startsWith","providerProps","launchDarklyFieldPluginConfig"],"sources":["../../src/launchDarkly/components/Secrets.tsx","../../src/launchDarkly/components/LaunchDarklyContext.tsx","../../src/launchDarkly/utils.ts","../../src/launchDarkly/index.ts"],"sourcesContent":["import {SettingsView, useSecrets} from '@sanity/studio-secrets'\nimport {useEffect, useState} from 'react'\nimport type {ObjectInputProps} from 'sanity'\n\nimport {useLaunchDarklyContext} from './LaunchDarklyContext'\n\nconst namespace = 'launchdarkly'\nconst 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} = useLaunchDarklyContext()\n const [showSettings, setShowSettings] = useState<boolean>(false)\n\n useEffect(() => {\n if (loading) return undefined\n if (!secrets && !loading) {\n setSecret(undefined)\n // oxlint-disable-next-line react/react-compiler\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={`${namespace} api key`}\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 type {ObjectInputProps} from 'sanity'\n\nimport type {LaunchDarklyContextProps, LaunchDarklyFieldLevelConfig} from '../types'\nimport {Secrets} from './Secrets'\n\nexport const LAUNCHDARKLY_CONFIG_DEFAULT = {}\n\nconst LaunchDarklyContext = createContext<LaunchDarklyContextProps>({\n setSecret: () => undefined,\n secret: undefined,\n})\n\nexport function useLaunchDarklyContext() {\n return useContext(LaunchDarklyContext)\n}\n\ntype LaunchDarklyProps = ObjectInputProps & {\n launchDarklyFieldPluginConfig: LaunchDarklyFieldLevelConfig\n}\n\nexport function LaunchDarklyProvider(props: LaunchDarklyProps) {\n const {launchDarklyFieldPluginConfig} = props\n const [secret, setSecret] = useState<string | undefined>()\n\n const context = useMemo(\n () => ({...launchDarklyFieldPluginConfig, secret, setSecret}),\n [launchDarklyFieldPluginConfig, secret, setSecret],\n )\n\n return (\n <LaunchDarklyContext.Provider value={context}>\n <Secrets {...props} />\n </LaunchDarklyContext.Provider>\n )\n}\n","import type {SanityClient} from 'sanity'\n\nimport type {ExperimentType} from '../types'\nimport type {LaunchDarklyFieldLevelConfig, LaunchDarklyFlagItem} from './types'\n\nexport const getExperiments = async ({\n client,\n projectKey,\n tags,\n}: Omit<LaunchDarklyFieldLevelConfig, 'fields'> & {client: SanityClient}): Promise<\n ExperimentType[]\n> => {\n const query = `*[_id == 'secrets.launchdarkly'][0].secrets.apiKey`\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 url = new URL(`https://app.launchdarkly.com/api/v2/flags/${projectKey}`)\n\n if (tags) {\n url.searchParams.set('filter', `tags:${tags.join('+')}`)\n }\n\n const featureExperiments: ExperimentType[] = []\n let hasMore = true\n const offset = 0\n const limit = 10\n\n while (hasMore) {\n url.searchParams.set('offset', offset.toString())\n url.searchParams.set('limit', limit.toString())\n const responseFlags = await fetch(url, {\n headers: {\n Authorization: secret,\n },\n })\n\n const {items} = await responseFlags.json()\n const experiments = items.map((flag: LaunchDarklyFlagItem) => ({\n id: flag.key,\n label: flag.name,\n variants: flag.variations.map((variation) => ({\n id: variation.value.toString(),\n label: variation.name ?? variation.value.toString(),\n })),\n }))\n featureExperiments.push(...experiments)\n if (items.length !== limit) {\n hasMore = false\n }\n }\n\n return featureExperiments\n}\n","import {definePlugin, isObjectInputProps} from 'sanity'\n\nimport {fieldLevelExperiments as baseFieldLevelExperiments} from '../fieldExperiments'\nimport {flattenSchemaType} from '../utils/flattenSchemaType'\nimport {LAUNCHDARKLY_CONFIG_DEFAULT, LaunchDarklyProvider} from './components/LaunchDarklyContext'\nimport type {LaunchDarklyFieldLevelConfig} from './types'\nimport {getExperiments} from './utils'\n\nexport const fieldLevelExperiments = definePlugin<LaunchDarklyFieldLevelConfig>((config) => {\n const pluginConfig = {...LAUNCHDARKLY_CONFIG_DEFAULT, ...config}\n const {fields, projectKey, tags} = pluginConfig\n return {\n name: 'sanity-growthbook-personalistaion-plugin-field-level-experiments',\n plugins: [\n baseFieldLevelExperiments({\n fields,\n experiments: (client) => getExperiments({client, projectKey, tags}),\n experimentNameOverride: 'flag',\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('flag'))\n\n if (!hasExperiment) {\n return props.renderDefault(props)\n }\n\n const providerProps = {\n ...props,\n launchDarklyFieldPluginConfig: {\n ...pluginConfig,\n },\n }\n return LaunchDarklyProvider(providerProps)\n },\n },\n },\n }\n})\n"],"mappings":"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"}
|