@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.
@@ -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 { useState, useEffect, createContext, useContext } from "react";
6
- import { useSecrets, SettingsView } from "@sanity/studio-secrets";
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
- key: apiKeyName,
9
- title: "Your secret API key"
8
+ key: apiKeyName,
9
+ title: "Your secret API key"
10
10
  }], Secrets = (props) => {
11
- const $ = c(12), {
12
- secrets,
13
- loading
14
- } = useSecrets(namespace), {
15
- setSecret
16
- } = useGrowthbookContext(), [showSettings, setShowSettings] = useState(!1);
17
- let t0, t1;
18
- if ($[0] !== loading || $[1] !== secrets || $[2] !== setSecret ? (t0 = () => {
19
- if (!loading)
20
- return !secrets && !loading ? (setSecret(void 0), setShowSettings(!0)) : (setSecret(secrets.apiKey), setShowSettings(!1));
21
- }, t1 = [secrets, loading, setSecret], $[0] = loading, $[1] = secrets, $[2] = setSecret, $[3] = t0, $[4] = t1) : (t0 = $[3], t1 = $[4]), useEffect(t0, t1), !showSettings) {
22
- let t22;
23
- return $[5] !== props ? (t22 = props.renderDefault(props), $[5] = props, $[6] = t22) : t22 = $[6], t22;
24
- }
25
- let t2;
26
- $[7] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t2 = /* @__PURE__ */ jsx(SettingsView, { title: "Growthbook secret", namespace, keys: pluginConfigKeys, onClose: () => {
27
- setShowSettings(!1);
28
- } }), $[7] = t2) : t2 = $[7];
29
- let t3;
30
- $[8] !== props ? (t3 = props.renderDefault(props), $[8] = props, $[9] = t3) : t3 = $[9];
31
- let t4;
32
- return $[10] !== t3 ? (t4 = /* @__PURE__ */ jsxs(Fragment, { children: [
33
- t2,
34
- t3
35
- ] }), $[10] = t3, $[11] = t4) : t4 = $[11], t4;
36
- }, GROWTHBOOK_CONFIG_DEFAULT = {
37
- baseUrl: "https://api.growthbook.io/api/v1"
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
- return useContext(GrowthbookContext);
40
+ return useContext(GrowthbookContext);
45
41
  }
46
42
  function GrowthbookProvider(props) {
47
- const $ = c(8), {
48
- growthbookFieldPluginConfig
49
- } = props, [secret, setSecret] = useState();
50
- let t0;
51
- $[0] !== growthbookFieldPluginConfig || $[1] !== secret ? (t0 = {
52
- ...growthbookFieldPluginConfig,
53
- secret,
54
- setSecret
55
- }, $[0] = growthbookFieldPluginConfig, $[1] = secret, $[2] = t0) : t0 = $[2];
56
- const context = t0;
57
- let t1;
58
- $[3] !== props ? (t1 = /* @__PURE__ */ jsx(Secrets, { ...props }), $[3] = props, $[4] = t1) : t1 = $[4];
59
- let t2;
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
- client,
64
- environment,
65
- baseUrl,
66
- project,
67
- convertBooleans,
68
- tags
69
- }) => {
70
- const query = `*[_id == 'secrets.${namespace}'][0].secrets.${apiKeyName}`, secret = await client.fetch(query);
71
- if (!secret) return [];
72
- const featureExperiments = [];
73
- let hasMore = !0, offset = 0;
74
- const url = new URL(`${baseUrl}/features`);
75
- for (project && url.searchParams.set("projectId", project); hasMore; ) {
76
- url.searchParams.set("offset", offset.toString());
77
- const response = await fetch(url, {
78
- headers: {
79
- Authorization: `Bearer ${secret}`
80
- }
81
- }), {
82
- features,
83
- hasMore: responseHasMore,
84
- nextOffset
85
- } = await response.json();
86
- hasMore = responseHasMore, offset = nextOffset, features && features.forEach((feature) => {
87
- if (feature.archived || tags && feature.tags && !feature.tags.some((tag) => tags.includes(tag)))
88
- return;
89
- const experiments = feature.environments[environment]?.rules.filter((experiment) => experiment.type === "experiment-ref" || experiment.type === "experiment");
90
- if (!experiments)
91
- return;
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
- const pluginConfig = {
113
- ...GROWTHBOOK_CONFIG_DEFAULT,
114
- ...config
115
- }, {
116
- fields,
117
- environment,
118
- project,
119
- convertBooleans,
120
- baseUrl,
121
- tags
122
- } = pluginConfig;
123
- return {
124
- name: "sanity-growthbook-personalistaion-plugin-field-level-experiments",
125
- plugins: [fieldLevelExperiments$1({
126
- fields,
127
- experiments: (client) => getExperiments({
128
- client,
129
- environment,
130
- baseUrl,
131
- project,
132
- convertBooleans,
133
- tags
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
- fieldLevelExperiments
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":"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"}
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":"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"}
package/dist/index.js CHANGED
@@ -1,6 +1,2 @@
1
- import { fieldLevelExperiments, flattenSchemaType } from "./_chunks-es/fieldExperiments.js";
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 { useState, useEffect, createContext, useContext } from "react";
6
- import { useSecrets, SettingsView } from "@sanity/studio-secrets";
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
- key: "apiKey",
9
- title: "Your secret API key"
8
+ key: "apiKey",
9
+ title: "Your secret API key"
10
10
  }], Secrets = (props) => {
11
- const $ = c(12), {
12
- secrets,
13
- loading
14
- } = useSecrets(namespace), {
15
- setSecret
16
- } = useLaunchDarklyContext(), [showSettings, setShowSettings] = useState(!1);
17
- let t0, t1;
18
- if ($[0] !== loading || $[1] !== secrets || $[2] !== setSecret ? (t0 = () => {
19
- if (!loading)
20
- return !secrets && !loading ? (setSecret(void 0), setShowSettings(!0)) : (setSecret(secrets.apiKey), setShowSettings(!1));
21
- }, t1 = [secrets, loading, setSecret], $[0] = loading, $[1] = secrets, $[2] = setSecret, $[3] = t0, $[4] = t1) : (t0 = $[3], t1 = $[4]), useEffect(t0, t1), !showSettings) {
22
- let t22;
23
- return $[5] !== props ? (t22 = props.renderDefault(props), $[5] = props, $[6] = t22) : t22 = $[6], t22;
24
- }
25
- let t2;
26
- $[7] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t2 = /* @__PURE__ */ jsx(SettingsView, { title: `${namespace} api key`, namespace, keys: pluginConfigKeys, onClose: () => {
27
- setShowSettings(!1);
28
- } }), $[7] = t2) : t2 = $[7];
29
- let t3;
30
- $[8] !== props ? (t3 = props.renderDefault(props), $[8] = props, $[9] = t3) : t3 = $[9];
31
- let t4;
32
- return $[10] !== t3 ? (t4 = /* @__PURE__ */ jsxs(Fragment, { children: [
33
- t2,
34
- t3
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
- setSecret: () => {
38
- },
39
- secret: void 0
36
+ setSecret: () => void 0,
37
+ secret: void 0
40
38
  });
41
39
  function useLaunchDarklyContext() {
42
- return useContext(LaunchDarklyContext);
40
+ return useContext(LaunchDarklyContext);
43
41
  }
44
42
  function LaunchDarklyProvider(props) {
45
- const $ = c(8), {
46
- launchDarklyFieldPluginConfig
47
- } = props, [secret, setSecret] = useState();
48
- let t0;
49
- $[0] !== launchDarklyFieldPluginConfig || $[1] !== secret ? (t0 = {
50
- ...launchDarklyFieldPluginConfig,
51
- secret,
52
- setSecret
53
- }, $[0] = launchDarklyFieldPluginConfig, $[1] = secret, $[2] = t0) : t0 = $[2];
54
- const context = t0;
55
- let t1;
56
- $[3] !== props ? (t1 = /* @__PURE__ */ jsx(Secrets, { ...props }), $[3] = props, $[4] = t1) : t1 = $[4];
57
- let t2;
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
- client,
62
- projectKey,
63
- tags
64
- }) => {
65
- const secret = await client.fetch("*[_id == 'secrets.launchdarkly'][0].secrets.apiKey");
66
- if (!secret) return [];
67
- const url = new URL(`https://app.launchdarkly.com/api/v2/flags/${projectKey}`);
68
- tags && url.searchParams.set("filter", `tags:${tags.join("+")}`);
69
- const featureExperiments = [];
70
- let hasMore = !0;
71
- const offset = 0, limit = 10;
72
- for (; hasMore; ) {
73
- url.searchParams.set("offset", offset.toString()), url.searchParams.set("limit", limit.toString());
74
- const responseFlags = await fetch(url, {
75
- headers: {
76
- Authorization: secret
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
- const pluginConfig = {
93
- ...LAUNCHDARKLY_CONFIG_DEFAULT,
94
- ...config
95
- }, {
96
- fields,
97
- projectKey,
98
- tags
99
- } = pluginConfig;
100
- return {
101
- name: "sanity-growthbook-personalistaion-plugin-field-level-experiments",
102
- plugins: [fieldLevelExperiments$1({
103
- fields,
104
- experiments: (client) => getExperiments({
105
- client,
106
- projectKey,
107
- tags
108
- }),
109
- experimentNameOverride: "flag"
110
- })],
111
- form: {
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
- fieldLevelExperiments
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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"}