@sanity/personalization-plugin 2.1.0 → 2.2.0-growthbook.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/index.d.mts +205 -1
- package/dist/index.d.ts +205 -1
- package/dist/index.js +131 -29
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +133 -30
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
- package/src/components/ExperimentContext.tsx +8 -5
- package/src/components/ExperimentField.tsx +56 -32
- package/src/components/ExperimentInput.tsx +2 -2
- package/src/components/Secrets.tsx +47 -0
- package/src/fieldExperiments.tsx +1 -0
- package/src/growthbookFieldExperiments.tsx +51 -0
- package/src/index.ts +1 -0
- package/src/types.ts +182 -1
- package/src/utils/growthbook.ts +78 -0
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: !0 });
|
|
3
|
-
var jsxRuntime = require("react/jsx-runtime"), sanity = require("sanity"), ui = require("@sanity/ui"), uuid = require("@sanity/uuid"), react = require("react"), equal = require("fast-deep-equal"), suspendReact = require("suspend-react"), gi = require("react-icons/gi");
|
|
3
|
+
var jsxRuntime = require("react/jsx-runtime"), sanity = require("sanity"), ui = require("@sanity/ui"), uuid = require("@sanity/uuid"), react = require("react"), equal = require("fast-deep-equal"), suspendReact = require("suspend-react"), gi = require("react-icons/gi"), studioSecrets = require("@sanity/studio-secrets");
|
|
4
4
|
function _interopDefaultCompat(e) {
|
|
5
5
|
return e && typeof e == "object" && "default" in e ? e : { default: e };
|
|
6
6
|
}
|
|
@@ -15,20 +15,23 @@ const CONFIG_DEFAULT = {
|
|
|
15
15
|
experimentId: "experimentId"
|
|
16
16
|
}, ExperimentContext = react.createContext({
|
|
17
17
|
...CONFIG_DEFAULT,
|
|
18
|
-
experiments: []
|
|
18
|
+
experiments: [],
|
|
19
|
+
setSecret: () => {
|
|
20
|
+
},
|
|
21
|
+
secret: void 0
|
|
19
22
|
});
|
|
20
23
|
function useExperimentContext() {
|
|
21
24
|
return react.useContext(ExperimentContext);
|
|
22
25
|
}
|
|
23
26
|
function ExperimentProvider(props) {
|
|
24
|
-
const { experimentFieldPluginConfig } = props, client = sanity.useClient({ apiVersion: experimentFieldPluginConfig.apiVersion }), workspace = sanity.useWorkspace(), experiments = Array.isArray(experimentFieldPluginConfig.experiments) ? experimentFieldPluginConfig.experiments : suspendReact.suspend(
|
|
27
|
+
const { experimentFieldPluginConfig } = props, [secret, setSecret] = react.useState(), client = sanity.useClient({ apiVersion: experimentFieldPluginConfig.apiVersion }), workspace = sanity.useWorkspace(), experiments = Array.isArray(experimentFieldPluginConfig.experiments) ? experimentFieldPluginConfig.experiments : suspendReact.suspend(
|
|
25
28
|
// eslint-disable-next-line require-await
|
|
26
|
-
async () => typeof experimentFieldPluginConfig.experiments == "function" ? experimentFieldPluginConfig.experiments(client) : experimentFieldPluginConfig.experiments,
|
|
27
|
-
[workspace],
|
|
29
|
+
async () => typeof experimentFieldPluginConfig.experiments == "function" ? experimentFieldPluginConfig.experiments(client, secret) : experimentFieldPluginConfig.experiments,
|
|
30
|
+
[workspace, secret],
|
|
28
31
|
{ equal: equal__default.default }
|
|
29
32
|
), context = react.useMemo(
|
|
30
|
-
() => ({ ...experimentFieldPluginConfig, experiments }),
|
|
31
|
-
[experimentFieldPluginConfig, experiments]
|
|
33
|
+
() => ({ ...experimentFieldPluginConfig, experiments, secret, setSecret }),
|
|
34
|
+
[experimentFieldPluginConfig, experiments, secret, setSecret]
|
|
32
35
|
);
|
|
33
36
|
return /* @__PURE__ */ jsxRuntime.jsx(ExperimentContext.Provider, { value: context, children: props.renderDefault(props) });
|
|
34
37
|
}
|
|
@@ -6405,9 +6408,9 @@ const icons = {
|
|
|
6405
6408
|
});
|
|
6406
6409
|
Icon.displayName = "ForwardRef(Icon)";
|
|
6407
6410
|
const useAddExperimentAction = (props) => {
|
|
6408
|
-
const { onChange, experimentNameOverride } = props, handleAddAction = () => {
|
|
6409
|
-
onChange([sanity.set(!
|
|
6410
|
-
};
|
|
6411
|
+
const { onChange, active, experimentNameOverride } = props, handleAddAction = react.useCallback(() => {
|
|
6412
|
+
onChange([sanity.set(!active, ["active"])]);
|
|
6413
|
+
}, [onChange, active]);
|
|
6411
6414
|
return {
|
|
6412
6415
|
title: `Add ${experimentNameOverride}`,
|
|
6413
6416
|
type: "action",
|
|
@@ -6416,13 +6419,10 @@ const useAddExperimentAction = (props) => {
|
|
|
6416
6419
|
renderAsButton: !0
|
|
6417
6420
|
};
|
|
6418
6421
|
}, useRemoveExperimentAction = (props) => {
|
|
6419
|
-
const { onChange, experimentId, experimentNameOverride } = props,
|
|
6420
|
-
const experiment = [experimentId], variants = [
|
|
6421
|
-
|
|
6422
|
-
},
|
|
6423
|
-
const clearEvents = patchClearEvent(), activeEvent = patchActiveFalseEvent();
|
|
6424
|
-
onChange([activeEvent, ...clearEvents]);
|
|
6425
|
-
};
|
|
6422
|
+
const { onChange, active, experimentId, experimentNameOverride, variantNameOverride } = props, handleClearAction = react.useCallback(() => {
|
|
6423
|
+
const activeId = ["active"], experiment = [experimentId], variants = [`${variantNameOverride}s`];
|
|
6424
|
+
onChange([sanity.set(!active, activeId), sanity.unset(experiment), sanity.unset(variants)]);
|
|
6425
|
+
}, [onChange, active, experimentId, variantNameOverride]);
|
|
6426
6426
|
return {
|
|
6427
6427
|
title: `Remove ${experimentNameOverride}`,
|
|
6428
6428
|
type: "action",
|
|
@@ -6430,36 +6430,53 @@ const useAddExperimentAction = (props) => {
|
|
|
6430
6430
|
onAction: handleClearAction,
|
|
6431
6431
|
renderAsButton: !0
|
|
6432
6432
|
};
|
|
6433
|
-
},
|
|
6433
|
+
}, createActions = ({
|
|
6434
6434
|
onChange,
|
|
6435
6435
|
inputId,
|
|
6436
6436
|
active,
|
|
6437
6437
|
experimentNameOverride,
|
|
6438
|
-
experimentId
|
|
6438
|
+
experimentId,
|
|
6439
|
+
variantNameOverride
|
|
6439
6440
|
}) => {
|
|
6440
6441
|
const removeAction = sanity.defineDocumentFieldAction({
|
|
6441
6442
|
name: `Remove ${experimentNameOverride}`,
|
|
6442
6443
|
useAction: (props) => useRemoveExperimentAction({
|
|
6444
|
+
active: !0,
|
|
6443
6445
|
onChange,
|
|
6444
6446
|
experimentNameOverride,
|
|
6445
|
-
experimentId
|
|
6447
|
+
experimentId,
|
|
6448
|
+
variantNameOverride
|
|
6446
6449
|
})
|
|
6447
6450
|
}), addAction = sanity.defineDocumentFieldAction({
|
|
6448
6451
|
name: `Add ${experimentNameOverride}`,
|
|
6449
6452
|
useAction: (props) => useAddExperimentAction({
|
|
6453
|
+
active: !1,
|
|
6450
6454
|
onChange,
|
|
6451
6455
|
experimentNameOverride
|
|
6452
6456
|
})
|
|
6453
6457
|
});
|
|
6454
6458
|
return active ? removeAction : addAction;
|
|
6455
6459
|
}, ExperimentField = (props) => {
|
|
6456
|
-
const { onChange } = props.inputProps, { inputId, experimentNameOverride, experimentId } = props, active = props.value?.active,
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6460
|
+
const { onChange } = props.inputProps, { inputId, experimentNameOverride, experimentId, variantNameOverride } = props, active = props.value?.active, actionProps = react.useMemo(
|
|
6461
|
+
() => ({
|
|
6462
|
+
onChange,
|
|
6463
|
+
inputId,
|
|
6464
|
+
active,
|
|
6465
|
+
experimentNameOverride,
|
|
6466
|
+
experimentId,
|
|
6467
|
+
variantNameOverride
|
|
6468
|
+
}),
|
|
6469
|
+
[onChange, inputId, active, experimentNameOverride, experimentId, variantNameOverride]
|
|
6470
|
+
), memoizedActions = react.useMemo(() => {
|
|
6471
|
+
const oldActions = props.actions || [];
|
|
6472
|
+
return [createActions(actionProps), ...oldActions];
|
|
6473
|
+
}, [actionProps, props.actions]), withActionProps = react.useMemo(
|
|
6474
|
+
() => ({
|
|
6475
|
+
...props,
|
|
6476
|
+
actions: memoizedActions
|
|
6477
|
+
}),
|
|
6478
|
+
[props, memoizedActions]
|
|
6479
|
+
);
|
|
6463
6480
|
return props.renderDefault(withActionProps);
|
|
6464
6481
|
}, Select = (props) => {
|
|
6465
6482
|
const {
|
|
@@ -6491,7 +6508,7 @@ const useAddExperimentAction = (props) => {
|
|
|
6491
6508
|
value: experiment.id
|
|
6492
6509
|
})), ExperimentInput = (props) => {
|
|
6493
6510
|
const { experiments } = useExperimentContext(), id = sanity.useFormValue(["_id"]), aditionalChangePath = react.useMemo(
|
|
6494
|
-
() => [...props.path.slice(0, -1), props.variantNameOverride],
|
|
6511
|
+
() => [...props.path.slice(0, -1), `${props.variantNameOverride}s`],
|
|
6495
6512
|
[props.variantNameOverride, props.path]
|
|
6496
6513
|
), subValues = sanity.useFormValue(aditionalChangePath), { patch } = sanity.useDocumentOperation(id.replace("drafts.", ""), props.schemaType.name), handleChange = react.useCallback(
|
|
6497
6514
|
(event, onChange) => {
|
|
@@ -6579,7 +6596,8 @@ const createExperimentType = ({
|
|
|
6579
6596
|
{
|
|
6580
6597
|
...props,
|
|
6581
6598
|
experimentId,
|
|
6582
|
-
experimentNameOverride
|
|
6599
|
+
experimentNameOverride,
|
|
6600
|
+
variantNameOverride
|
|
6583
6601
|
}
|
|
6584
6602
|
)
|
|
6585
6603
|
},
|
|
@@ -6742,7 +6760,91 @@ const createExperimentType = ({
|
|
|
6742
6760
|
}
|
|
6743
6761
|
}
|
|
6744
6762
|
};
|
|
6763
|
+
}), namespace = "growthbook", pluginConfigKeys = [
|
|
6764
|
+
{
|
|
6765
|
+
key: "apiKey",
|
|
6766
|
+
title: "Your secret API key"
|
|
6767
|
+
}
|
|
6768
|
+
], Secrets = (props) => {
|
|
6769
|
+
const { secrets, loading } = studioSecrets.useSecrets(namespace), { setSecret } = useExperimentContext(), [showSettings, setShowSettings] = react.useState(!1);
|
|
6770
|
+
return react.useEffect(() => {
|
|
6771
|
+
if (!loading)
|
|
6772
|
+
return !secrets && !loading ? (setSecret(void 0), setShowSettings(!0)) : (setSecret(secrets.apiKey), setShowSettings(!1));
|
|
6773
|
+
}, [secrets, loading, setSecret]), showSettings ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
6774
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6775
|
+
studioSecrets.SettingsView,
|
|
6776
|
+
{
|
|
6777
|
+
title: "Growthbook secret",
|
|
6778
|
+
namespace,
|
|
6779
|
+
keys: pluginConfigKeys,
|
|
6780
|
+
onClose: () => {
|
|
6781
|
+
setShowSettings(!1);
|
|
6782
|
+
}
|
|
6783
|
+
}
|
|
6784
|
+
),
|
|
6785
|
+
props.renderDefault(props)
|
|
6786
|
+
] }) : props.renderDefault(props);
|
|
6787
|
+
}, getBooleanConversion = (value) => value === "true" ? "variant" : value === "false" ? "control" : value, getExperiments = async ({
|
|
6788
|
+
client,
|
|
6789
|
+
environment,
|
|
6790
|
+
baseUrl,
|
|
6791
|
+
project,
|
|
6792
|
+
convertBooleans
|
|
6793
|
+
}) => {
|
|
6794
|
+
const secret = await client.fetch("*[_id == 'secrets.growthbook'][0].secrets.apiKey");
|
|
6795
|
+
if (!secret) return [];
|
|
6796
|
+
const featureExperiments = [];
|
|
6797
|
+
let hasMore = !0, offset = 0;
|
|
6798
|
+
const url = new URL(baseUrl ?? "https://api.growthbook.io/api/v1/features");
|
|
6799
|
+
for (project && url.searchParams.set("projectId", project); hasMore; ) {
|
|
6800
|
+
url.searchParams.set("offset", offset.toString());
|
|
6801
|
+
const response = await fetch(url, {
|
|
6802
|
+
headers: {
|
|
6803
|
+
Authorization: `Bearer ${secret}`
|
|
6804
|
+
}
|
|
6805
|
+
}), { features, hasMore: responseHasMore, nextOffset } = await response.json();
|
|
6806
|
+
hasMore = responseHasMore, offset = nextOffset, features && features.forEach((feature) => {
|
|
6807
|
+
if (feature.archived)
|
|
6808
|
+
return;
|
|
6809
|
+
const experiments = feature.environments[environment]?.rules.filter(
|
|
6810
|
+
(experiment) => experiment.type === "experiment-ref" || experiment.type === "experiment"
|
|
6811
|
+
);
|
|
6812
|
+
if (!experiments)
|
|
6813
|
+
return;
|
|
6814
|
+
const variations = /* @__PURE__ */ new Set();
|
|
6815
|
+
experiments.forEach((experiment) => {
|
|
6816
|
+
experiment?.variations.forEach((variant) => {
|
|
6817
|
+
variations.add({
|
|
6818
|
+
id: convertBooleans ? getBooleanConversion(variant.value) : variant.value,
|
|
6819
|
+
label: convertBooleans ? getBooleanConversion(variant.value) : variant.value
|
|
6820
|
+
});
|
|
6821
|
+
});
|
|
6822
|
+
});
|
|
6823
|
+
const value = { id: feature.id, label: feature.id, variants: [...variations] };
|
|
6824
|
+
featureExperiments.push(value);
|
|
6825
|
+
});
|
|
6826
|
+
}
|
|
6827
|
+
return featureExperiments;
|
|
6828
|
+
}, growthbookFieldLevel = sanity.definePlugin((config) => {
|
|
6829
|
+
const { fields, environment, project, convertBooleans, baseUrl } = config;
|
|
6830
|
+
return {
|
|
6831
|
+
name: "sanity-growthbook-personalistaion-plugin-field-level-experiments",
|
|
6832
|
+
plugins: [
|
|
6833
|
+
fieldLevelExperiments({
|
|
6834
|
+
fields,
|
|
6835
|
+
experiments: (client) => getExperiments({ client, environment, baseUrl, project, convertBooleans })
|
|
6836
|
+
})
|
|
6837
|
+
],
|
|
6838
|
+
form: {
|
|
6839
|
+
components: {
|
|
6840
|
+
input: (props) => !(props.id === "root" && sanity.isObjectInputProps(props)) || !flattenSchemaType(props.schemaType).map(
|
|
6841
|
+
(field) => field.type.name
|
|
6842
|
+
).some((name) => name.startsWith("experiment")) ? props.renderDefault(props) : Secrets(props)
|
|
6843
|
+
}
|
|
6844
|
+
}
|
|
6845
|
+
};
|
|
6745
6846
|
});
|
|
6746
6847
|
exports.fieldLevelExperiments = fieldLevelExperiments;
|
|
6747
6848
|
exports.flattenSchemaType = flattenSchemaType;
|
|
6849
|
+
exports.growthbookFieldLevel = growthbookFieldLevel;
|
|
6748
6850
|
//# sourceMappingURL=index.js.map
|