@sanity/personalization-plugin 2.5.0 → 3.0.0

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.
Files changed (48) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +570 -144
  3. package/dist/growthbook/index.d.ts +12 -15
  4. package/dist/growthbook/index.d.ts.map +1 -0
  5. package/dist/growthbook/index.js +104 -68
  6. package/dist/growthbook/index.js.map +1 -1
  7. package/dist/index.d.ts +212 -252
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +398 -301
  10. package/dist/index.js.map +1 -1
  11. package/dist/launchDarkly/index.d.ts +9 -12
  12. package/dist/launchDarkly/index.d.ts.map +1 -0
  13. package/dist/launchDarkly/index.js +74 -46
  14. package/dist/launchDarkly/index.js.map +1 -1
  15. package/package.json +35 -77
  16. package/dist/growthbook/index.d.mts +0 -15
  17. package/dist/growthbook/index.mjs +0 -124
  18. package/dist/growthbook/index.mjs.map +0 -1
  19. package/dist/index.d.mts +0 -267
  20. package/dist/index.mjs +0 -472
  21. package/dist/index.mjs.map +0 -1
  22. package/dist/launchDarkly/index.d.mts +0 -12
  23. package/dist/launchDarkly/index.mjs +0 -107
  24. package/dist/launchDarkly/index.mjs.map +0 -1
  25. package/sanity.json +0 -8
  26. package/src/components/Array.tsx +0 -68
  27. package/src/components/ExperimentContext.tsx +0 -65
  28. package/src/components/ExperimentField.tsx +0 -138
  29. package/src/components/ExperimentInput.tsx +0 -75
  30. package/src/components/ExperimentItem.tsx +0 -10
  31. package/src/components/Select.tsx +0 -43
  32. package/src/components/VariantInput.tsx +0 -19
  33. package/src/components/VariantPreview.tsx +0 -75
  34. package/src/fieldExperiments.tsx +0 -266
  35. package/src/growthbook/Components/GrowthbookContext.tsx +0 -38
  36. package/src/growthbook/Components/Secrets.tsx +0 -47
  37. package/src/growthbook/index.ts +0 -54
  38. package/src/growthbook/types.ts +0 -15
  39. package/src/growthbook/utils.ts +0 -94
  40. package/src/index.ts +0 -3
  41. package/src/launchDarkly/components/LaunchDarklyContext.tsx +0 -36
  42. package/src/launchDarkly/components/Secrets.tsx +0 -46
  43. package/src/launchDarkly/index.ts +0 -52
  44. package/src/launchDarkly/types.ts +0 -193
  45. package/src/launchDarkly/utils.ts +0 -54
  46. package/src/types.ts +0 -245
  47. package/src/utils/flattenSchemaType.ts +0 -47
  48. package/v2-incompatible.js +0 -11
@@ -1,12 +1,9 @@
1
- import {FieldDefinition} from 'sanity'
2
- import {Plugin as Plugin_2} from 'sanity'
3
-
4
- export declare const fieldLevelExperiments: Plugin_2<LaunchDarklyFieldLevelConfig>
5
-
6
- declare type LaunchDarklyFieldLevelConfig = {
7
- fields: (string | FieldDefinition)[]
8
- projectKey: string
9
- tags?: string[]
10
- }
11
-
12
- export {}
1
+ import { FieldDefinition } from "sanity";
2
+ type LaunchDarklyFieldLevelConfig = {
3
+ fields: (string | FieldDefinition)[];
4
+ projectKey: string;
5
+ tags?: string[];
6
+ };
7
+ declare const fieldLevelExperiments: import("sanity").Plugin<LaunchDarklyFieldLevelConfig>;
8
+ export { fieldLevelExperiments };
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/launchDarkly/types.ts","../../src/launchDarkly/index.ts"],"mappings":";KAEY,4BAAA;EACV,MAAA,YAAkB,eAAe;EACjC,UAAA;EACA,IAAA;AAAA;AAAA,cCGW,qBAAA,mBAAqB,MAAA,CAAA,4BAAA"}
@@ -1,44 +1,61 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: !0 });
3
- var sanity = require("sanity"), index = require("../index.js"), jsxRuntime = require("react/jsx-runtime"), react = require("react"), studioSecrets = require("@sanity/studio-secrets");
4
- const namespace = "launchdarkly", pluginConfigKeys = [
5
- {
6
- key: "apiKey",
7
- title: "Your secret API key"
8
- }
9
- ], Secrets = (props) => {
10
- const { secrets, loading } = studioSecrets.useSecrets(namespace), { setSecret } = useLaunchDarklyContext(), [showSettings, setShowSettings] = react.useState(!1);
11
- return react.useEffect(() => {
1
+ import { definePlugin, isObjectInputProps } from "sanity";
2
+ import { flattenSchemaType, fieldLevelExperiments as fieldLevelExperiments$1 } from "../index.js";
3
+ import { jsxs, Fragment, jsx } from "react/jsx-runtime";
4
+ import { c } from "react/compiler-runtime";
5
+ import { useState, useEffect, createContext, useContext } from "react";
6
+ import { useSecrets, SettingsView } from "@sanity/studio-secrets";
7
+ const namespace = "launchdarkly", pluginConfigKeys = [{
8
+ key: "apiKey",
9
+ title: "Your secret API key"
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 = () => {
12
19
  if (!loading)
13
20
  return !secrets && !loading ? (setSecret(void 0), setShowSettings(!0)) : (setSecret(secrets.apiKey), setShowSettings(!1));
14
- }, [secrets, loading, setSecret]), showSettings ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
15
- /* @__PURE__ */ jsxRuntime.jsx(
16
- studioSecrets.SettingsView,
17
- {
18
- title: `${namespace} api key`,
19
- namespace,
20
- keys: pluginConfigKeys,
21
- onClose: () => {
22
- setShowSettings(!1);
23
- }
24
- }
25
- ),
26
- props.renderDefault(props)
27
- ] }) : props.renderDefault(props);
28
- }, LAUNCHDARKLY_CONFIG_DEFAULT = {}, LaunchDarklyContext = react.createContext({
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;
36
+ }, LAUNCHDARKLY_CONFIG_DEFAULT = {}, LaunchDarklyContext = createContext({
29
37
  setSecret: () => {
30
38
  },
31
39
  secret: void 0
32
40
  });
33
41
  function useLaunchDarklyContext() {
34
- return react.useContext(LaunchDarklyContext);
42
+ return useContext(LaunchDarklyContext);
35
43
  }
36
44
  function LaunchDarklyProvider(props) {
37
- const { launchDarklyFieldPluginConfig } = props, [secret, setSecret] = react.useState(), context = react.useMemo(
38
- () => ({ ...launchDarklyFieldPluginConfig, secret, setSecret }),
39
- [launchDarklyFieldPluginConfig, secret, setSecret]
40
- );
41
- return /* @__PURE__ */ jsxRuntime.jsx(LaunchDarklyContext.Provider, { value: context, children: /* @__PURE__ */ jsxRuntime.jsx(Secrets, { ...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;
42
59
  }
43
60
  const getExperiments = async ({
44
61
  client,
@@ -58,7 +75,9 @@ const getExperiments = async ({
58
75
  headers: {
59
76
  Authorization: secret
60
77
  }
61
- }), { items } = await responseFlags.json(), experiments = items.map((flag) => ({
78
+ }), {
79
+ items
80
+ } = await responseFlags.json(), experiments = items.map((flag) => ({
62
81
  id: flag.key,
63
82
  label: flag.name,
64
83
  variants: flag.variations.map((variation) => ({
@@ -69,23 +88,30 @@ const getExperiments = async ({
69
88
  featureExperiments.push(...experiments), items.length !== limit && (hasMore = !1);
70
89
  }
71
90
  return featureExperiments;
72
- }, fieldLevelExperiments = sanity.definePlugin((config) => {
73
- const pluginConfig = { ...LAUNCHDARKLY_CONFIG_DEFAULT, ...config }, { fields, projectKey, tags } = pluginConfig;
91
+ }, fieldLevelExperiments = definePlugin((config) => {
92
+ const pluginConfig = {
93
+ ...LAUNCHDARKLY_CONFIG_DEFAULT,
94
+ ...config
95
+ }, {
96
+ fields,
97
+ projectKey,
98
+ tags
99
+ } = pluginConfig;
74
100
  return {
75
101
  name: "sanity-growthbook-personalistaion-plugin-field-level-experiments",
76
- plugins: [
77
- index.fieldLevelExperiments({
78
- fields,
79
- experiments: (client) => getExperiments({ client, projectKey, tags }),
80
- experimentNameOverride: "flag"
81
- })
82
- ],
102
+ plugins: [fieldLevelExperiments$1({
103
+ fields,
104
+ experiments: (client) => getExperiments({
105
+ client,
106
+ projectKey,
107
+ tags
108
+ }),
109
+ experimentNameOverride: "flag"
110
+ })],
83
111
  form: {
84
112
  components: {
85
113
  input: (props) => {
86
- if (!(props.id === "root" && sanity.isObjectInputProps(props)) || !index.flattenSchemaType(props.schemaType).map(
87
- (field) => field.type.name
88
- ).some((name) => name.startsWith("flag")))
114
+ if (!(props.id === "root" && isObjectInputProps(props)) || !flattenSchemaType(props.schemaType).map((field) => field.type.name).some((name) => name.startsWith("flag")))
89
115
  return props.renderDefault(props);
90
116
  const providerProps = {
91
117
  ...props,
@@ -99,5 +125,7 @@ const getExperiments = async ({
99
125
  }
100
126
  };
101
127
  });
102
- exports.fieldLevelExperiments = fieldLevelExperiments;
128
+ export {
129
+ fieldLevelExperiments
130
+ };
103
131
  //# 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 {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 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 {ObjectInputProps} from 'sanity'\n\nimport {LaunchDarklyContextProps, LaunchDarklyFieldLevelConfig} from '../types'\nimport {Secrets} from './Secrets'\n\nexport const LAUNCHDARKLY_CONFIG_DEFAULT = {}\n\nexport const 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 {SanityClient} from 'sanity'\n\nimport {ExperimentType} from '../types'\nimport {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 {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":["useSecrets","useState","useEffect","jsxs","Fragment","jsx","SettingsView","createContext","useContext","useMemo","definePlugin","baseFieldLevelExperiments","isObjectInputProps","flattenSchemaType"],"mappings":"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"}
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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"}
package/package.json CHANGED
@@ -1,104 +1,62 @@
1
1
  {
2
2
  "name": "@sanity/personalization-plugin",
3
- "version": "2.5.0",
3
+ "version": "3.0.0",
4
4
  "description": "Plugin to help with personalization, a/b testing when using Sanity",
5
5
  "keywords": [
6
6
  "sanity",
7
7
  "sanity-plugin"
8
8
  ],
9
- "homepage": "https://github.com/sanity-io/sanity-plugin-personalization#readme",
9
+ "homepage": "https://github.com/sanity-io/plugins/tree/main/plugins/@sanity/personalization-plugin#readme",
10
10
  "bugs": {
11
- "url": "https://github.com/sanity-io/sanity-plugin-personalization/issues"
11
+ "url": "https://github.com/sanity-io/plugins/issues"
12
12
  },
13
+ "license": "MIT",
14
+ "author": "Sanity.io <hello@sanity.io>",
13
15
  "repository": {
14
16
  "type": "git",
15
- "url": "git@github.com:sanity-io/sanity-plugin-personalization.git"
16
- },
17
- "license": "MIT",
18
- "author": "Sanity <hello@sanity.io>",
19
- "sideEffects": false,
20
- "type": "commonjs",
21
- "exports": {
22
- ".": {
23
- "source": "./src/index.ts",
24
- "import": "./dist/index.mjs",
25
- "default": "./dist/index.js"
26
- },
27
- "./launchDarkly": {
28
- "source": "./src/launchDarkly/index.ts",
29
- "import": "./dist/launchDarkly/index.mjs",
30
- "default": "./dist/launchDarkly/index.js"
31
- },
32
- "./growthbook": {
33
- "source": "./src/growthbook/index.ts",
34
- "import": "./dist/growthbook/index.mjs",
35
- "default": "./dist/growthbook/index.js"
36
- },
37
- "./package.json": "./package.json"
17
+ "url": "git+ssh://git@github.com/sanity-io/plugins.git",
18
+ "directory": "plugins/@sanity/personalization-plugin"
38
19
  },
39
- "main": "./dist/index.js",
40
- "types": "./dist/index.d.ts",
41
20
  "files": [
42
- "dist",
43
- "sanity.json",
44
- "src",
45
- "v2-incompatible.js"
21
+ "dist"
46
22
  ],
47
- "scripts": {
48
- "build": "plugin-kit verify-package --silent && pkg-utils build --strict --check --clean",
49
- "format": "prettier --write --cache --ignore-unknown .",
50
- "link-watch": "plugin-kit link-watch",
51
- "lint": "eslint . --fix",
52
- "prepublishOnly": "npm run build",
53
- "watch": "pkg-utils watch --strict",
54
- "prepare": "husky"
23
+ "type": "module",
24
+ "types": "./dist/index.d.ts",
25
+ "exports": {
26
+ ".": "./dist/index.js",
27
+ "./launchDarkly": "./dist/launchDarkly/index.js",
28
+ "./growthbook": "./dist/growthbook/index.js",
29
+ "./package.json": "./package.json"
55
30
  },
56
31
  "dependencies": {
57
- "@sanity/incompatible-plugin": "^1.0.5",
58
- "@sanity/studio-secrets": "^3.0.2",
59
- "@sanity/ui": "^2.16.12",
32
+ "@sanity/icons": "^3.7.4",
33
+ "@sanity/ui": "^3.2.0",
60
34
  "@sanity/uuid": "^3.0.2",
61
35
  "fast-deep-equal": "^3.1.3",
62
36
  "react-icons": "^5.5.0",
63
- "suspend-react": "^0.1.3"
37
+ "suspend-react": "^0.1.3",
38
+ "@sanity/studio-secrets": "4.0.5"
64
39
  },
65
40
  "devDependencies": {
66
- "@commitlint/cli": "^19.8.1",
67
- "@commitlint/config-conventional": "^19.8.1",
68
- "@sanity/pkg-utils": "^6.13.4",
69
- "@sanity/plugin-kit": "^4.0.19",
70
- "@sanity/semantic-release-preset": "^5.0.0",
71
- "@types/react": "^18.3.23",
72
- "@typescript-eslint/eslint-plugin": "^8.39.1",
73
- "@typescript-eslint/parser": "^8.39.1",
74
- "eslint": "^8.57.1",
75
- "eslint-config-prettier": "^9.1.2",
76
- "eslint-config-sanity": "^7.1.4",
77
- "eslint-plugin-prettier": "^5.5.4",
78
- "eslint-plugin-react": "^7.37.5",
79
- "eslint-plugin-react-hooks": "^5.2.0",
80
- "husky": "^9.1.7",
81
- "lint-staged": "^15.2.10",
82
- "prettier": "^3.6.2",
83
- "prettier-plugin-packagejson": "^2.5.19",
84
- "react": "^19.2.3",
85
- "react-dom": "^19.2.3",
86
- "sanity": "^5.0.1",
87
- "semantic-release": "^24.2.7",
88
- "styled-components": "^6.1.19",
89
- "typescript": "^5.9.2"
41
+ "@sanity/pkg-utils": "^10.5.7",
42
+ "@types/react": "^19.2.17",
43
+ "@types/react-dom": "^19.2.3",
44
+ "babel-plugin-react-compiler": "^1.0.0",
45
+ "react": "^19.2.7",
46
+ "react-dom": "^19.2.7",
47
+ "sanity": "^6.1.0",
48
+ "@repo/package.config": "0.0.0",
49
+ "@repo/tsconfig": "0.0.0"
90
50
  },
91
51
  "peerDependencies": {
92
- "react": "^18 || ^19",
93
- "sanity": "^3 || ^4.0.0-0 || ^5.0.0"
52
+ "react": "^19.2",
53
+ "react-dom": "^19.2",
54
+ "sanity": "^5 || ^6.0.0-0"
94
55
  },
95
56
  "engines": {
96
- "node": ">=18"
97
- },
98
- "resolutions": {
99
- "conventional-changelog-conventionalcommits": ">= 8.0.0"
57
+ "node": ">=20.19 <22 || >=22.12"
100
58
  },
101
- "publishConfig": {
102
- "access": "public"
59
+ "scripts": {
60
+ "build": "pkg build --strict --check --clean"
103
61
  }
104
- }
62
+ }
@@ -1,15 +0,0 @@
1
- import {FieldDefinition} from 'sanity'
2
- import {Plugin as Plugin_2} from 'sanity'
3
-
4
- export declare const fieldLevelExperiments: Plugin_2<GrowthbookExperimentFieldPluginConfig>
5
-
6
- declare type GrowthbookExperimentFieldPluginConfig = {
7
- fields: (string | FieldDefinition)[]
8
- environment: string
9
- baseUrl?: string
10
- project?: string
11
- convertBooleans?: boolean
12
- tags?: string[]
13
- }
14
-
15
- export {}
@@ -1,124 +0,0 @@
1
- import { definePlugin, isObjectInputProps } from "sanity";
2
- import { fieldLevelExperiments as fieldLevelExperiments$1, flattenSchemaType } from "../index.mjs";
3
- import { jsxs, Fragment, jsx } from "react/jsx-runtime";
4
- import { useState, useEffect, createContext, useMemo, useContext } from "react";
5
- import { useSecrets, SettingsView } from "@sanity/studio-secrets";
6
- const namespace = "growthbook", pluginConfigKeys = [
7
- {
8
- key: "apiKey",
9
- title: "Your secret API key"
10
- }
11
- ], Secrets = (props) => {
12
- const { secrets, loading } = useSecrets(namespace), { setSecret } = useGrowthbookContext(), [showSettings, setShowSettings] = useState(!1);
13
- return useEffect(() => {
14
- if (!loading)
15
- return !secrets && !loading ? (setSecret(void 0), setShowSettings(!0)) : (setSecret(secrets.apiKey), setShowSettings(!1));
16
- }, [secrets, loading, setSecret]), showSettings ? /* @__PURE__ */ jsxs(Fragment, { children: [
17
- /* @__PURE__ */ jsx(
18
- SettingsView,
19
- {
20
- title: "Growthbook secret",
21
- namespace,
22
- keys: pluginConfigKeys,
23
- onClose: () => {
24
- setShowSettings(!1);
25
- }
26
- }
27
- ),
28
- props.renderDefault(props)
29
- ] }) : props.renderDefault(props);
30
- }, GROWTHBOOK_CONFIG_DEFAULT = {
31
- baseUrl: "https://api.growthbook.io/api/v1"
32
- }, GrowthbookContext = createContext({
33
- setSecret: () => {
34
- },
35
- secret: void 0
36
- });
37
- function useGrowthbookContext() {
38
- return useContext(GrowthbookContext);
39
- }
40
- function GrowthbookProvider(props) {
41
- const { growthbookFieldPluginConfig } = props, [secret, setSecret] = useState(), context = useMemo(
42
- () => ({ ...growthbookFieldPluginConfig, secret, setSecret }),
43
- [growthbookFieldPluginConfig, secret, setSecret]
44
- );
45
- return /* @__PURE__ */ jsx(GrowthbookContext.Provider, { value: context, children: /* @__PURE__ */ jsx(Secrets, { ...props }) });
46
- }
47
- const getBooleanConversion = (value) => value === "true" ? "variant" : value === "false" ? "control" : value, getExperiments = async ({
48
- client,
49
- environment,
50
- baseUrl,
51
- project,
52
- convertBooleans,
53
- tags
54
- }) => {
55
- const query = `*[_id == 'secrets.${namespace}'][0].secrets.${pluginConfigKeys[0].key}`, secret = await client.fetch(query);
56
- if (!secret) return [];
57
- const featureExperiments = [];
58
- let hasMore = !0, offset = 0;
59
- const url = new URL(`${baseUrl}/features`);
60
- for (project && url.searchParams.set("projectId", project); hasMore; ) {
61
- url.searchParams.set("offset", offset.toString());
62
- const response = await fetch(url, {
63
- headers: {
64
- Authorization: `Bearer ${secret}`
65
- }
66
- }), { features, hasMore: responseHasMore, nextOffset } = await response.json();
67
- hasMore = responseHasMore, offset = nextOffset, features && features.forEach((feature) => {
68
- if (feature.archived || tags && feature.tags && !feature.tags.some((tag) => tags.includes(tag)))
69
- return;
70
- const experiments = feature.environments[environment]?.rules.filter(
71
- (experiment) => experiment.type === "experiment-ref" || experiment.type === "experiment"
72
- );
73
- if (!experiments)
74
- return;
75
- const variations = [], uniqueValues = /* @__PURE__ */ new Set();
76
- experiments.forEach((experiment) => {
77
- experiment?.variations.forEach((variant) => {
78
- const value2 = convertBooleans ? getBooleanConversion(variant.value) : variant.value;
79
- uniqueValues.has(value2) || (uniqueValues.add(value2), variations.push({
80
- id: value2,
81
- label: value2
82
- }));
83
- });
84
- });
85
- const value = { id: feature.id, label: feature.id, variants: variations };
86
- featureExperiments.push(value);
87
- });
88
- }
89
- return featureExperiments.sort((a, b) => a.id.localeCompare(b.id));
90
- }, fieldLevelExperiments = definePlugin(
91
- (config) => {
92
- const pluginConfig = { ...GROWTHBOOK_CONFIG_DEFAULT, ...config }, { fields, environment, project, convertBooleans, baseUrl, tags } = pluginConfig;
93
- return {
94
- name: "sanity-growthbook-personalistaion-plugin-field-level-experiments",
95
- plugins: [
96
- fieldLevelExperiments$1({
97
- fields,
98
- experiments: (client) => getExperiments({ client, environment, baseUrl, project, convertBooleans, tags })
99
- })
100
- ],
101
- form: {
102
- components: {
103
- input: (props) => {
104
- if (!(props.id === "root" && isObjectInputProps(props)) || !flattenSchemaType(props.schemaType).map(
105
- (field) => field.type.name
106
- ).some((name) => name.startsWith("experiment")))
107
- return props.renderDefault(props);
108
- const providerProps = {
109
- ...props,
110
- growthbookFieldPluginConfig: {
111
- ...pluginConfig
112
- }
113
- };
114
- return GrowthbookProvider(providerProps);
115
- }
116
- }
117
- }
118
- };
119
- }
120
- );
121
- export {
122
- fieldLevelExperiments
123
- };
124
- //# sourceMappingURL=index.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.mjs","sources":["../../src/growthbook/Components/Secrets.tsx","../../src/growthbook/Components/GrowthbookContext.tsx","../../src/growthbook/utils.ts","../../src/growthbook/index.ts"],"sourcesContent":["import {SettingsView, useSecrets} from '@sanity/studio-secrets'\nimport {useEffect, useState} from 'react'\nimport {ObjectInputProps} from 'sanity'\n\nimport {useGrowthbookContext} from './GrowthbookContext'\n\nexport const namespace = 'growthbook'\n\nexport const pluginConfigKeys = [\n {\n key: 'apiKey',\n title: 'Your secret API key',\n },\n]\n\nexport const Secrets = (props: ObjectInputProps) => {\n const {secrets, loading} = useSecrets(namespace) as {secrets: {apiKey: string}; loading: boolean}\n const {setSecret} = useGrowthbookContext()\n const [showSettings, setShowSettings] = useState<boolean>(false)\n\n useEffect(() => {\n if (loading) return undefined\n if (!secrets && !loading) {\n setSecret(undefined)\n return setShowSettings(true)\n }\n setSecret(secrets.apiKey)\n return setShowSettings(false)\n }, [secrets, loading, setSecret])\n\n if (!showSettings) {\n return props.renderDefault(props)\n }\n return (\n <>\n <SettingsView\n title={'Growthbook secret'}\n namespace={namespace}\n keys={pluginConfigKeys}\n onClose={() => {\n setShowSettings(false)\n }}\n />\n {props.renderDefault(props)}\n </>\n )\n}\n","import {createContext, useContext, useMemo, useState} from 'react'\nimport {ObjectInputProps} from 'sanity'\n\nimport {GrowthbookContextProps, GrowthbookExperimentFieldPluginConfig} from '../types'\nimport {Secrets} from './Secrets'\n\nexport const GROWTHBOOK_CONFIG_DEFAULT = {\n baseUrl: 'https://api.growthbook.io/api/v1',\n}\n\nexport const GrowthbookContext = createContext<GrowthbookContextProps>({\n setSecret: () => undefined,\n secret: undefined,\n})\n\nexport function useGrowthbookContext() {\n return useContext(GrowthbookContext)\n}\n\ntype GrowthbookProps = ObjectInputProps & {\n growthbookFieldPluginConfig: 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 {SanityClient} from 'sanity'\n\nimport {ExperimentType, GrowthbookFeature, VariantType} from '../types'\nimport {namespace, pluginConfigKeys} from './Components/Secrets'\nimport {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.${pluginConfigKeys[0].key}`\n\n const secret = await client.fetch(query) // secret is stored in the content lake using @sanity/studio-secrets\n if (!secret) return []\n\n const featureExperiments: ExperimentType[] = []\n let hasMore = true\n let offset = 0\n const url = new URL(`${baseUrl}/features`)\n if (project) {\n url.searchParams.set('projectId', project)\n }\n\n while (hasMore) {\n url.searchParams.set('offset', offset.toString())\n const response = await fetch(url, {\n headers: {\n Authorization: `Bearer ${secret}`,\n },\n })\n\n const {features, hasMore: responseHasMore, nextOffset} = await response.json()\n\n hasMore = responseHasMore\n offset = nextOffset\n if (!features) continue\n\n features.forEach((feature: GrowthbookFeature) => {\n if (feature.archived) {\n return undefined\n }\n if (tags && feature.tags && !feature.tags.some((tag) => tags.includes(tag))) {\n return undefined\n }\n\n const experiments = feature.environments[environment]?.rules.filter(\n (experiment) => experiment.type === 'experiment-ref' || experiment.type === 'experiment',\n )\n\n if (!experiments) {\n return undefined\n }\n\n const variations: VariantType[] = []\n const uniqueValues = new Set<string>()\n\n experiments.forEach((experiment) => {\n experiment?.variations.forEach((variant) => {\n const value = convertBooleans ? getBooleanConversion(variant.value) : variant.value\n if (!uniqueValues.has(value)) {\n uniqueValues.add(value)\n variations.push({\n id: value,\n label: value,\n })\n }\n })\n })\n const value = {id: feature.id, label: feature.id, variants: variations}\n\n featureExperiments.push(value)\n return undefined\n })\n }\n const sortedFeatureExperiments = featureExperiments.sort((a, b) => a.id.localeCompare(b.id))\n return sortedFeatureExperiments\n}\n","import {definePlugin, isObjectInputProps} from 'sanity'\n\nimport {fieldLevelExperiments as baseFieldLevelExperiments} from '../fieldExperiments'\nimport {flattenSchemaType} from '../utils/flattenSchemaType'\nimport {GROWTHBOOK_CONFIG_DEFAULT, GrowthbookProvider} from './Components/GrowthbookContext'\nimport {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":["value","baseFieldLevelExperiments"],"mappings":"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"}